gsmmap: Dump SYSTEM INFORMATION messages while processing
[osmocom-bb.git] / src / target / firmware / rf / trf6151.c
1 /* Driver for RF Transceiver Circuit (TRF6151) */
2
3 /* (C) 2010 by Harald Welte <laforge@gnumonks.org>
4  *
5  * All Rights Reserved
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  */
22
23 #include <stdint.h>
24 #include <stdio.h>
25
26 #include <debug.h>
27 #include <memory.h>
28 #include <keypad.h>
29 #include <osmocom/gsm/gsm_utils.h>
30
31 #include <calypso/tpu.h>
32 #include <calypso/tsp.h>
33 #include <layer1/agc.h>
34 #include <rffe.h>
35
36 #include <rf/trf6151.h>
37
38 /* #define WARN_OUT_OF_SPEC 1 */
39
40 enum trf6151_reg {
41         REG_RX          = 0,    /* RF general settings */
42         REG_PLL         = 1,    /* PLL settings */
43         REG_PWR         = 2,    /* Power on/off functional blocks */
44         REG_CFG         = 3,    /* Transceiver and PA controller settings */
45         REG_TEST1       = 4,
46         REG_TEST2       = 5,
47         REG_TEST3       = 6,
48         REG_TEST4       = 7,
49         _MAX_REG
50 };
51
52 /* REG_RX */
53 #define RX_READ_EN              (1 << 7)
54 #define RX_CAL_MODE             (1 << 8)
55 #define RX_RF_GAIN_HIGH         (3 << 9)
56 #define RX_VGA_GAIN_SHIFT       11
57
58 /* REG_PWR */
59 #define PWR_BANDGAP_SHIFT       3
60 #define PWR_BANDGAP_OFF         (0 << PWR_BANDGAP_SHIFT)
61 #define PWR_BANDGAP_ON_SPEEDUP  (2 << PWR_BANDGAP_SHIFT)
62 #define PWR_BANDGAP_ON          (3 << PWR_BANDGAP_SHIFT)
63 #define PWR_REGUL_ON            (1 << 5)
64 #define PWR_SYNTHE_OFF          (0)
65 #define PWR_SYNTHE_RX_ON        (1 << 9)
66 #define PWR_SYNTHE_TX_ON        (1 << 10)
67 #define PWR_RX_MODE             (1 << 11)
68 #define PWR_TX_MODE             (1 << 13)
69 #define PWR_PACTRL_APC          (1 << 14)
70 #define PWR_PACTRL_APCEN        (1 << 15)
71
72 /* REG_CFG */
73 #define CFG_TX_LOOP_MANU        (1 << 3)
74 #define CFG_PACTLR_IDIOD_30uA   (0 << 4)
75 #define CFG_PACTLR_IDIOD_300uA  (1 << 4)
76 #define CFG_PACTLR_RES_OPEN     (0 << 10)
77 #define CFG_PACTLR_RES_150k     (1 << 10)
78 #define CFG_PACTLR_RES_300k     (2 << 10)
79 #define CFG_PACTLR_CAP_0pF      (0 << 12)
80 #define CFG_PACTLR_CAP_12p5F    (1 << 12)
81 #define CFG_PACTLR_CAP_25pF     (3 << 12)
82 #define CFG_PACTLR_CAP_50pF     (2 << 12)
83 #define CFG_TEMP_SENSOR         (1 << 14)
84 #define CFG_ILOGIC_INIT_DIS     (1 << 15)
85
86 /* FIXME: This must be defined in the RFFE configuration */
87 #define TRF6151_TSP_UID         2
88 #define TRF6151_PACTRL_CFG      (CFG_PACTLR_RES_OPEN|CFG_PACTLR_CAP_0pF|CFG_PACTLR_IDIOD_30uA)
89
90 #define PLL_VAL(a, b)   ((a << 3) | (((b)-64) << 9))
91
92 /* All values in qbits unless otherwise specified */
93 #define TRF6151_LDO_DELAY_TS    6       /* six TDMA frames (at least 25ms) */
94 #define TRF6151_RX_PLL_DELAY    184     /* 170 us */
95 #define TRF6151_TX_PLL_DELAY    260     /* 240 us */
96
97
98 enum trf6151_pwr_unit {
99         TRF1651_PACTLR_APC,
100         TRF6151_PACTRL_APCEN,
101         TRF6151_TRANSMITTER,
102         TRF6151_REGULATORS,
103 };
104
105 enum trf6151_gsm_band {
106         GSM900          = 1,
107         GSM1800         = 2,
108         GSM850_LOW      = 4,
109         GSM850_HIGH     = 5,
110         GSM1900         = 6,
111 };
112
113
114 uint16_t rf_arfcn = 871;        /* TODO: this needs to be private */
115 static uint16_t rf_band;
116
117 static uint8_t trf6151_tsp_uid;
118 static uint8_t trf6151_vga_dbm = 40;
119 static int trf6151_gain_high = 1;
120
121 static uint16_t trf6151_reg_cache[_MAX_REG] = {
122         [REG_RX]        = 0x9E00,
123         [REG_PLL]       = 0x0000,
124         [REG_PWR]       = 0x0000,
125         [REG_CFG]       = 0x2980,
126 };
127
128 /* Write to a TRF6151 register (4 TPU instructions) */
129 static void trf6151_reg_write(uint16_t reg, uint16_t val)
130 {
131         printd("trf6151_reg_write(reg=%u, val=0x%04x)\n", reg, val);
132         /* each TSP write takes 4 TPU instructions */
133         tsp_write(trf6151_tsp_uid, 16, (reg | val));
134         trf6151_reg_cache[reg] = val;
135 }
136
137 /* Frontend gain can be switched high or low (dB) */
138 #define TRF6151_FE_GAIN_LOW     7
139 #define TRF6151_FE_GAIN_HIGH    27
140
141 /* VGA at baseband can be adjusted in this range (dB) */
142 #define TRF6151_VGA_GAIN_MIN    14
143 #define TRF6151_VGA_GAIN_MAX    40
144
145 /* put current set (or computed) gain to register */
146 int trf6151_set_gain_reg(uint8_t dbm, int high)
147 {
148         uint16_t reg = trf6151_reg_cache[REG_RX] & 0x07ff;
149         printd("trf6151_set_gain_reg(%u, %d)\n", dbm, high);
150
151         if (dbm < TRF6151_VGA_GAIN_MIN || dbm > TRF6151_VGA_GAIN_MAX)
152                 return -1;
153
154         /* clear the gain bits first */
155         reg &= ~((0x1F) << RX_VGA_GAIN_SHIFT);
156         /* OR-in the new gain value */
157         reg |= (6 + (dbm-TRF6151_VGA_GAIN_MIN)/2) << RX_VGA_GAIN_SHIFT;
158
159         if (high)
160                 reg |= RX_RF_GAIN_HIGH;
161         else
162                 reg &= ~RX_RF_GAIN_HIGH;
163
164         trf6151_reg_write(REG_RX, reg);
165
166         return 0;
167 }
168
169 int trf6151_set_gain(uint8_t dbm)
170 {
171         int high = 0;
172
173         printd("trf6151_set_gain(%u, %d)\n", dbm);
174         /* If this is negative or less than TRF6151_GAIN_MIN, we are pretty
175          * much lost as we cannot reduce the system inherent gain.  If it is
176          * positive, it corresponds to the gain that we need to configure */
177         if (dbm < TRF6151_FE_GAIN_LOW + TRF6151_VGA_GAIN_MIN) {
178                 printd("AGC Input level overflow\n");
179                 trf6151_vga_dbm = TRF6151_VGA_GAIN_MIN;
180                 trf6151_gain_high = 0;
181                 return 0;
182         } else if (dbm >= TRF6151_FE_GAIN_HIGH + TRF6151_VGA_GAIN_MIN) {
183                 high = 1;
184                 dbm -= TRF6151_FE_GAIN_HIGH;
185         } else
186                 dbm -= TRF6151_FE_GAIN_LOW;
187         if (dbm > TRF6151_VGA_GAIN_MAX)
188                 dbm = TRF6151_VGA_GAIN_MAX;
189
190         /* update the static global variables which are used when programming
191          * the window */
192         trf6151_vga_dbm = dbm;
193         trf6151_gain_high = high;
194
195         return 0;
196 }
197
198 #define SCALE_100KHZ    100
199
200 /* Compute TRF6151 PLL valuese */
201 static void trf6151_pll_rx(uint32_t freq_khz,
202                            uint16_t *pll_config, enum trf6151_gsm_band *band)
203 {
204         const uint32_t p=64, r=65;
205         uint32_t freq_100khz, vco_freq_100khz;
206         uint32_t l, n;
207         uint32_t a, b;
208
209         /* Scale into 100kHz unit (avoid overflow in intermediates) */
210         freq_100khz = freq_khz / SCALE_100KHZ;
211
212         /* L selects hi/lo band */
213         l = (freq_khz > 1350000) ? 2 : 4; /* cut at mid point :) */
214
215         /* VCO frequency */
216         vco_freq_100khz = freq_100khz * l;
217
218         /* vco_freq = 26MHz / R * N  with R=65 and N=B*P+A */
219         n = (vco_freq_100khz * r) / 260;
220         a = n % p;
221         b = n / p;
222
223         *pll_config = PLL_VAL(a, b);
224
225         /* Out-of-spec tuning warning */
226 #ifdef WARN_OUT_OF_SPEC
227         if ((l == 4 && (b < 135 || b > 150)) ||
228             (l == 2 && (b < 141 || b > 155)))
229                 printf("Frequency %u kHz is out of spec\n", (unsigned int)freq_khz);
230 #endif
231
232         /* Select band */
233         if (l==4) {
234                 /* If in the low band, same port for both GSM850/GSM900, so we
235                  * choose the best VCO (VCOMAIN1=3.37GHz, VCOMAIN2=3.8GHz) */
236                 if (vco_freq_100khz < 35850) /* midpoint */
237                         *band = GSM850_LOW;
238                 else
239                         *band = GSM900;
240
241                 /* Out-of-spec freq check */
242 #ifdef WARN_OUT_OF_SPEC
243                 if (!(freq_khz >= 869000 && freq_khz <= 894000) &&
244                     !(freq_khz >= 921000 && freq_khz <= 960000)) /* include GSM-R */
245                         printf("Frequency %u outside normal filter range for selected port\n", (unsigned int)freq_khz);
246 #endif
247         } else {
248                 /* In the high band, different ports for DCS/PCS, so
249                  * take what's best and available */
250                 /* We're stuck to VCOMAIN2=3.8GHz though ... */
251                 uint32_t rx_ports = rffe_get_rx_ports();
252                 uint32_t port;
253
254                 /* Select port */
255                 port = (freq_khz < 1905000) ? (1 << PORT_DCS1800) : (1 << PORT_PCS1900);
256                 port = (port & rx_ports) ? port : rx_ports;
257
258                 /* Select band */
259                 *band = (port & (1 << PORT_DCS1800)) ? GSM1800 : GSM1900;
260
261                 /* Out-of-spec freq check */
262 #ifdef WARN_OUT_OF_SPEC
263                 if ((*band == GSM1800 && (freq_khz < 1805000 || freq_khz > 1880000)) ||
264                     (*band == GSM1900 && (freq_khz < 1930000 || freq_khz > 1990000)))
265                         printf("Frequency %u outside normal filter range for selected port\n", (unsigned int)freq_khz);
266 #endif
267         }
268
269         /* Debug */
270         printd("RX Freq %u kHz => A = %u, B = %u, band = %d, vco_freq = %u kHz\n", freq_khz, a, b, *band, vco_freq_100khz*100);
271
272         /* All done */
273         return;
274 }
275
276 /* Compute TRF6151 PLL TX values */
277 static void trf6151_pll_tx(uint32_t freq_khz,
278                            uint16_t *pll_config, enum trf6151_gsm_band *band)
279 {
280         const uint32_t p=64;
281         uint32_t r, l, m, m_op_l; /* m_op_l = m +/- l depending on mode */
282         uint32_t freq_100khz;
283         uint32_t n, a, b, b_min, b_max;
284
285         /* Scale into 100kHz unit (avoid overflow in intermediates) */
286         freq_100khz = freq_khz / SCALE_100KHZ;
287
288         /* Select band (and PLL mode) */
289         if (freq_khz > 1350000) {
290                 /* High band, so only 1 real PLL mode. band doesn't matter
291                  * that much (or at all) but we still do it :p */
292                 *band = (freq_khz < 1817500) ? GSM1800 : GSM1900;
293                 r = 70;
294                 l = 2;
295                 m = 26;
296                 m_op_l = m + l;
297                 b_min = 133;
298                 b_max = 149;
299         } else {
300                 /* Low band. We have 3 possible PLL modes that output on
301                  * the right port: GSM900, GSM850_HIGH, GSM850_LOW.
302                  *
303                  * The transistion points have been chosen looking at the VCO
304                  * and IF frequencies for various frequencies for theses modes
305                  */
306                 if (freq_khz < 837100) {
307                         /* GSM850_LOW */
308                         *band = GSM850_LOW;
309                         r = 55;
310                         l = 4;
311                         m = 26;
312                         m_op_l = m - l;
313                         b_min = 128;
314                         b_max = 130;
315                 } else if (freq_khz < 850000) {
316                         /* GSM850_HIGH */
317                         *band = GSM850_HIGH;
318                         r = 30;
319                         l = 4;
320                         m = 52;
321                         m_op_l = m - l;
322                         b_min = 65;
323                         b_max = 66;
324                 } else {
325                         /* GSM900 */
326                         *band = GSM900;
327                         r = 35;
328                         l = 4;
329                         m = 52;
330                         m_op_l = m + l;
331                         b_min = 68;
332                         b_max = 71;
333                 }
334         }
335
336         /* vco_freq = f * M * L / (M +- L)                 */
337         /*          = 26MHz / R * N  with R=65 and N=B*P+A */
338         n = (freq_100khz * m * l * r) / (m_op_l * 260);
339         a = n % p;
340         b = n / p;
341
342         *pll_config = PLL_VAL(a, b);
343
344         /* Debug */
345         printd("TX Freq %u kHz => A = %u, B = %u, band = %d\n", freq_khz, a, b, *band);
346
347         /* Out-of-spec tuning warning */
348 #ifdef WARN_OUT_OF_SPEC
349         if (b < b_min || b > b_max)
350                 printf("Frequency %u kHz is out of spec\n", (unsigned int)freq_khz);
351 #endif
352
353         /* All done */
354         return;
355 }
356
357 static inline void trf6151_reset(uint16_t reset_id)
358 {
359         /* pull the nRESET line low */
360         tsp_act_disable(reset_id);
361         tpu_enq_wait(50);
362         /* release nRESET */
363         tsp_act_enable(reset_id);
364 }
365
366 void trf6151_init(uint8_t tsp_uid, uint16_t tsp_reset_id)
367 {
368         trf6151_tsp_uid = tsp_uid;
369
370         /* Configure the TSPEN which is connected to TRF6151 STROBE */
371         tsp_setup(trf6151_tsp_uid, 0, 1, 1);
372
373         trf6151_reset(tsp_reset_id);
374
375         /* configure TRF6151 for operation */
376         trf6151_power(1);
377         trf6151_reg_write(REG_CFG, TRF6151_PACTRL_CFG | CFG_ILOGIC_INIT_DIS);
378
379         /* FIXME: Uplink / Downlink Calibration */
380 }
381
382 void trf6151_power(int on)
383 {
384         if (on) {
385                 trf6151_reg_write(REG_PWR, PWR_REGUL_ON | PWR_BANDGAP_ON);
386                 /* wait until regulators are stable (25ms == 27100 qbits) */
387                 tpu_enq_wait(5000);
388                 tpu_enq_wait(5000);
389                 tpu_enq_wait(5000);
390                 tpu_enq_wait(5000);
391                 tpu_enq_wait(5000);
392                 tpu_enq_wait(2100);
393         } else
394                 trf6151_reg_write(REG_PWR, PWR_BANDGAP_ON);
395 }
396
397 /* Set the operational mode of the TRF6151 chip */
398 void trf6151_set_mode(enum trf6151_mode mode)
399 {
400         uint16_t pwr = (PWR_REGUL_ON | PWR_BANDGAP_ON | (rf_band<<6));
401
402         switch (mode) {
403         case TRF6151_IDLE:
404                 /* should we switch of the RF gain for power saving? */
405                 break;
406         case TRF6151_RX:
407                 pwr |= (PWR_SYNTHE_RX_ON | PWR_RX_MODE);
408                 break;
409         case TRF6151_TX:
410 #if 0
411                 pwr |= (PWR_SYNTHE_TX_ON | PWR_TX_MODE);
412 #else // Dieter: we should turn power control on (for TPU: check timing and order !)
413                 pwr |= (PWR_SYNTHE_TX_ON | PWR_TX_MODE | PWR_PACTRL_APC | PWR_PACTRL_APCEN); // Dieter: TODO
414 #endif
415                 break;
416         }
417         trf6151_reg_write(REG_PWR, pwr);
418 }
419
420 static void trf6151_band_select(enum trf6151_gsm_band band)
421 {
422         uint16_t pwr = trf6151_reg_cache[REG_PWR];
423
424         pwr &= ~(3 << 6);
425         pwr |= (band << 6);
426
427         trf6151_reg_write(REG_PWR, pwr);
428 }
429
430 /* Set ARFCN.  Takes 2 reg_write, i.e. 8 TPU instructions */
431 void trf6151_set_arfcn(uint16_t arfcn, int uplink)
432 {
433         uint32_t freq_khz;
434         uint16_t pll_config;
435         enum trf6151_gsm_band pll_band;
436
437         switch (gsm_arfcn2band(arfcn)) {
438         case GSM_BAND_850:
439         case GSM_BAND_900:
440         case GSM_BAND_1800:
441         case GSM_BAND_1900:
442                 /* Supported */
443                 break;
444         case GSM_BAND_450:
445         case GSM_BAND_480:
446         case GSM_BAND_750:
447         case GSM_BAND_810:
448                 printf("Unsupported band ! YMMV.\n");
449                 break;
450         }
451
452         freq_khz = gsm_arfcn2freq10(arfcn, uplink) * 100;
453         printd("ARFCN %u -> %u kHz\n", arfcn, freq_khz);
454
455         if (uplink == 0)
456                 trf6151_pll_rx(freq_khz, &pll_config, &pll_band);
457         else
458                 trf6151_pll_tx(freq_khz, &pll_config, &pll_band);
459
460         trf6151_band_select(pll_band);
461         trf6151_reg_write(REG_PLL, pll_config);
462
463         rf_band = pll_band;
464         rf_arfcn = arfcn; // TODO: arfcn is referenced at other places
465 }
466
467 void trf6151_calib_dc_offs(void)
468 {
469         uint16_t rx = trf6151_reg_cache[REG_RX];
470
471         /* Set RX CAL Mode bit, it will re-set automatically */
472         trf6151_reg_write(REG_RX, rx | RX_CAL_MODE);
473         /* DC offset calibration can take up to 50us, i.e. 54.16 * 923ns*/
474         tpu_enq_wait(55);
475 }
476
477 uint8_t trf6151_get_gain_reg(void)
478 {
479         uint16_t vga, reg_rx = trf6151_reg_cache[REG_RX];
480         uint8_t gain = 0;
481
482         switch ((reg_rx >> 9) & 3) {
483         case 0:
484                 gain += TRF6151_FE_GAIN_LOW;
485                 break;
486         case 3:
487                 gain += TRF6151_FE_GAIN_HIGH;
488                 break;
489         }
490
491         vga = (reg_rx >> RX_VGA_GAIN_SHIFT) & 0x1f;
492         if (vga < 6)
493                 vga = 6;
494
495         gain += TRF6151_VGA_GAIN_MIN + (vga - 6) * 2;
496
497         return gain;
498 }
499
500 uint8_t trf6151_get_gain(void)
501 {
502         uint8_t gain;
503         
504         gain = trf6151_vga_dbm;
505         if (trf6151_gain_high)
506                 gain += TRF6151_FE_GAIN_HIGH;
507         else
508                 gain += TRF6151_FE_GAIN_LOW;
509
510         return gain;
511 }
512
513 void trf6151_test(uint16_t arfcn)
514 {
515         /* Select ARFCN 871 downlink */
516         trf6151_set_arfcn(arfcn, 0);
517
518         trf6151_set_mode(TRF6151_RX);
519         //trf6151_reg_write(REG_PWR, (PWR_SYNTHE_RX_ON | PWR_RX_MODE | PWR_REGUL_ON | (rf_band<<6) | PWR_BANDGAP_ON));
520         /* Wait for PLL stabilization (170us max) */
521         tpu_enq_wait(TRF6151_RX_PLL_DELAY);
522
523         /* Use DC offset calibration after RX mode has been switched on
524          * (might not be needed) */
525         trf6151_calib_dc_offs();
526
527         tpu_enq_sleep();
528         tpu_enable(1);
529         tpu_wait_idle();
530 }
531
532 void trf6151_tx_test(uint16_t arfcn)
533 {
534         /* Select ARFCN uplink */
535         trf6151_set_arfcn(arfcn, 1);
536
537         trf6151_set_mode(TRF6151_TX);
538         tpu_enq_wait(TRF6151_RX_PLL_DELAY);
539
540         tpu_enq_sleep();
541         tpu_enable(1);
542         tpu_wait_idle();
543 }
544
545 #define TRF6151_REGWR_QBITS     8       /* 4 GSM qbits + 4 TPU instructions */
546 #define TRF6151_RX_TPU_INSTR    4       /* set_gain_reg(1), set_arfcn(2), set_mode(1) */
547
548 /* delay caused by this driver programming the TPU for RX mode */
549 #define TRF6151_RX_TPU_DELAY    (TRF6151_RX_TPU_INSTR * TRF6151_REGWR_QBITS)
550
551 /* prepare a Rx window with the TRF6151 finished at time 'start' (in qbits) */
552 void trf6151_rx_window(int16_t start_qbits, uint16_t arfcn)
553 {
554         int16_t start_pll_qbits;
555
556         /* power up at the right time _before_ the 'start_qbits' point in time */
557         start_pll_qbits = add_mod5000(start_qbits,  -(TRF6151_RX_PLL_DELAY + TRF6151_RX_TPU_DELAY));
558         tpu_enq_at(start_pll_qbits);
559
560         /* Set the AGC and PLL registers */
561         trf6151_set_arfcn(arfcn, 0);
562         trf6151_set_gain_reg(trf6151_vga_dbm, trf6151_gain_high);
563         trf6151_set_mode(TRF6151_RX);
564
565         /* FIXME: power down at the right time again */
566 }
567
568 /* prepare a Tx window with the TRF6151 finished at time 'start' (in qbits) */
569 void trf6151_tx_window(int16_t start_qbits, uint16_t arfcn)
570 {
571 #ifdef CONFIG_TX_ENABLE
572         int16_t start_pll_qbits;
573
574         /* power up at the right time _before_ the 'start_qbits' point in time */
575         start_pll_qbits = add_mod5000(start_qbits,  -(TRF6151_TX_PLL_DELAY + TRF6151_RX_TPU_DELAY));
576         tpu_enq_at(start_pll_qbits);
577
578         trf6151_set_arfcn(arfcn, 1);
579         trf6151_set_mode(TRF6151_TX);
580
581         /* FIXME: power down at the right time again */
582 #endif
583 }
584
585 /* Given the expected input level of exp_inp dBm and the target of target_bb
586  * dBm, configure the RF Frontend with the respective gain */
587 void trf6151_compute_gain(int16_t exp_inp, int16_t target_bb)
588 {
589         /* TRF6151 VGA gain between 14 to 40 dB, plus 20db high/low */
590         int16_t exp_bb, delta;
591
592         /* calculate the dBm8 that we expect at the baseband */
593         exp_bb = exp_inp + system_inherent_gain;
594
595         /* calculate the error that we expect. */
596         delta = target_bb - exp_bb;
597
598         printd("computed gain %d\n", delta);
599         trf6151_set_gain(delta);
600 }
601