bc82946fc718ef3aa841532f2810198603bc9152
[debian/gnuradio] / usrp2 / firmware / lib / db_init.c
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2008,2009 Free Software Foundation, Inc.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19
20 #include <memory_map.h>
21 #include <i2c.h>
22 #include <usrp2_i2c_addr.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <db.h>
26 #include <db_base.h>
27 #include <hal_io.h>
28 #include <nonstdio.h>
29
30
31 struct db_base *tx_dboard;      // the tx daughterboard that's installed
32 struct db_base *rx_dboard;      // the rx daughterboard that's installed
33
34 extern struct db_base db_basic_tx;
35 extern struct db_base db_basic_rx;
36 extern struct db_base db_lf_tx;
37 extern struct db_base db_lf_rx;
38 extern struct db_base db_rfx_400_tx;
39 extern struct db_base db_rfx_400_rx;
40 extern struct db_base db_rfx_900_tx;
41 extern struct db_base db_rfx_900_rx;
42 extern struct db_base db_rfx_1200_tx;
43 extern struct db_base db_rfx_1200_rx;
44 extern struct db_base db_rfx_1800_tx;
45 extern struct db_base db_rfx_1800_rx;
46 extern struct db_base db_rfx_2400_tx;
47 extern struct db_base db_rfx_2400_rx;
48 extern struct db_base db_wbxng_rx;
49 extern struct db_base db_wbxng_tx;
50 extern struct db_base db_tvrx1;
51 extern struct db_base db_tvrx2;
52 extern struct db_base db_tvrx3;
53 extern struct db_base db_dbsrx;
54
55 struct db_base *all_dboards[] = {
56   &db_basic_tx,
57   &db_basic_rx,
58   &db_lf_tx,
59   &db_lf_rx,
60   &db_rfx_400_tx,
61   &db_rfx_400_rx,
62   &db_rfx_900_tx,
63   &db_rfx_900_rx,
64   &db_rfx_1200_tx,
65   &db_rfx_1200_rx,
66   &db_rfx_1800_tx,
67   &db_rfx_1800_rx,
68   &db_rfx_2400_tx,
69   &db_rfx_2400_rx,
70   &db_tvrx1,
71 #if 0
72   &db_tvrx2,
73 #endif
74   &db_tvrx3,
75   &db_dbsrx,
76   0
77 };
78
79
80 typedef enum { UDBE_OK, UDBE_NO_EEPROM, UDBE_INVALID_EEPROM } usrp_dbeeprom_status_t;
81
82 static usrp_dbeeprom_status_t
83 read_raw_dboard_eeprom (unsigned char *buf, int i2c_addr)
84 {
85   if (!eeprom_read (i2c_addr, 0, buf, DB_EEPROM_CLEN))
86     return UDBE_NO_EEPROM;
87
88   if (buf[DB_EEPROM_MAGIC] != DB_EEPROM_MAGIC_VALUE)
89     return UDBE_INVALID_EEPROM;
90
91   int sum = 0;
92   unsigned int i;
93   for (i = 0; i < DB_EEPROM_CLEN; i++)
94     sum += buf[i];
95
96   if ((sum & 0xff) != 0)
97     return UDBE_INVALID_EEPROM;
98
99   return UDBE_OK;
100 }
101
102
103 /*
104  * Return DBID, -1 <none> or -2 <invalid eeprom contents>
105  */
106 int
107 read_dboard_eeprom(int i2c_addr)
108 {
109   unsigned char buf[DB_EEPROM_CLEN];
110
111   usrp_dbeeprom_status_t s = read_raw_dboard_eeprom (buf, i2c_addr);
112
113   //printf("\nread_raw_dboard_eeprom: %d\n", s);
114
115   switch (s){
116   case UDBE_OK:
117     return (buf[DB_EEPROM_ID_MSB] << 8) | buf[DB_EEPROM_ID_LSB];
118
119   case UDBE_NO_EEPROM:
120   default:
121     return -1;
122
123   case UDBE_INVALID_EEPROM:
124     return -2;
125   }
126 }
127
128
129 static struct db_base *
130 lookup_dbid(int dbid)
131 {
132   if (dbid < 0)
133     return 0;
134
135   int i;
136   for (i = 0; all_dboards[i]; i++)
137     if (all_dboards[i]->dbid == dbid)
138       return all_dboards[i];
139
140   return 0;
141 }
142
143 static struct db_base *
144 lookup_dboard(int i2c_addr, struct db_base *default_db, char *msg)
145 {
146   struct db_base *db;
147   int dbid = read_dboard_eeprom(i2c_addr);
148
149   // FIXME removing this printf has the system hang if there are two d'boards
150   // installed.  (I think the problem is in i2c_read/write or the way
151   // I kludge the zero-byte write to set the read address in eeprom_read.)
152   printf("%s dbid: 0x%x\n", msg, dbid);
153
154   if (dbid < 0){        // there was some kind of problem.  Treat as Basic Tx
155     return default_db;
156   }
157   else if ((db = lookup_dbid(dbid)) == 0){
158     printf("No daugherboard code for dbid = 0x%x\n", dbid);
159     return default_db;
160   }
161   return db;
162 }
163
164 void
165 set_atr_regs(int bank, struct db_base *db)
166 {
167   uint32_t      val[4];
168   int           shift;
169   int           mask;
170   int           i;
171
172   val[ATR_IDLE] = db->atr_rxval;
173   val[ATR_RX]   = db->atr_rxval;
174   val[ATR_TX]   = db->atr_txval;
175   val[ATR_FULL] = db->atr_txval;
176
177   if (bank == GPIO_TX_BANK){
178     mask = 0xffff0000;
179     shift = 16;
180   }
181   else {
182     mask = 0x0000ffff;
183     shift = 0;
184   }
185
186   for (i = 0; i < 4; i++){
187     int t = (atr_regs->v[i] & ~mask) | ((val[i] << shift) & mask);
188     //printf("atr_regs[%d] = 0x%x\n", i, t);
189     atr_regs->v[i] = t;
190   }
191 }
192
193 static void
194 set_gpio_mode(int bank, struct db_base *db)
195 {
196   int   i;
197
198   hal_gpio_set_ddr(bank, db->output_enables, 0xffff);
199   set_atr_regs(bank, db);
200
201   for (i = 0; i < 16; i++){
202     if (db->used_pins & (1 << i)){
203       // set to either GPIO_SEL_SW or GPIO_SEL_ATR
204       hal_gpio_set_sel(bank, i, (db->atr_mask & (1 << i)) ? 'a' : 's');
205     }
206   }
207 }
208
209 static int __attribute__((unused))
210 determine_tx_mux_value(struct db_base *db) 
211 {
212   if (db->i_and_q_swapped)
213     return 0x01;
214   else
215     return 0x10;
216 }
217
218 static int
219 determine_rx_mux_value(struct db_base *db)
220 {
221 #define ADC0 0x0
222 #define ADC1 0x1
223 #define ZERO 0x2
224   
225   static int truth_table[8] = {
226     /* swap_iq, uses */
227     /* 0, 0x0 */    (ZERO << 2) | ZERO,         // N/A
228     /* 0, 0x1 */    (ZERO << 2) | ADC0,
229     /* 0, 0x2 */    (ZERO << 2) | ADC1,
230     /* 0, 0x3 */    (ADC1 << 2) | ADC0,
231     /* 1, 0x0 */    (ZERO << 2) | ZERO,         // N/A
232     /* 1, 0x1 */    (ZERO << 2) | ADC0,
233     /* 1, 0x2 */    (ZERO << 2) | ADC1,
234     /* 1, 0x3 */    (ADC0 << 2) | ADC1,
235   };
236
237   int   subdev0_uses;
238   int   subdev1_uses;
239   int   uses;
240
241   if (db->is_quadrature)
242     subdev0_uses = 0x3;         // uses A/D 0 and 1
243   else
244     subdev0_uses = 0x1;         // uses A/D 0 only
245
246   // FIXME second subdev on Basic Rx, LF RX
247   // if subdev2 exists
248   // subdev1_uses = 0x2;
249   subdev1_uses = 0;
250
251   uses = subdev0_uses;
252
253   int swap_iq = db->i_and_q_swapped & 0x1;
254   int index = (swap_iq << 2) | uses;
255
256   return truth_table[index];
257 }
258
259
260 void
261 db_init(void)
262 {
263   int   m;
264
265   tx_dboard = lookup_dboard(I2C_ADDR_TX_A, &db_basic_tx, "Tx");
266   //printf("db_init: tx dbid = 0x%x\n", tx_dboard->dbid);
267   set_gpio_mode(GPIO_TX_BANK, tx_dboard);
268   tx_dboard->init(tx_dboard);
269   m = determine_tx_mux_value(tx_dboard);
270   dsp_tx_regs->tx_mux = m;
271   //printf("tx_mux = 0x%x\n", m);
272   tx_dboard->current_lo_offset = tx_dboard->default_lo_offset;
273
274   rx_dboard = lookup_dboard(I2C_ADDR_RX_A, &db_basic_rx, "Rx");
275   //printf("db_init: rx dbid = 0x%x\n", rx_dboard->dbid);
276   set_gpio_mode(GPIO_RX_BANK, rx_dboard);
277   rx_dboard->init(rx_dboard);
278   m = determine_rx_mux_value(rx_dboard);
279   dsp_rx_regs->rx_mux = m;
280   //printf("rx_mux = 0x%x\n", m);
281   rx_dboard->current_lo_offset = rx_dboard->default_lo_offset;
282 }
283
284 /*!
285  *  Calculate the frequency to use for setting the digital down converter.
286  *
287  *  \param[in] target_freq   desired RF frequency (Hz)
288  *  \param[in] baseband_freq the RF frequency that corresponds to DC in the IF.
289  * 
290  *  \param[out] dxc_freq is the value for the ddc
291  *  \param[out] inverted is true if we're operating in an inverted Nyquist zone.
292 */
293 void
294 calc_dxc_freq(u2_fxpt_freq_t target_freq, u2_fxpt_freq_t baseband_freq,
295               u2_fxpt_freq_t *dxc_freq, bool *inverted)
296 {
297   u2_fxpt_freq_t fs = U2_DOUBLE_TO_FXPT_FREQ(100e6);    // converter sample rate
298   u2_fxpt_freq_t delta = target_freq - baseband_freq;
299
300 #if 0
301   printf("calc_dxc_freq\n");
302   printf("  fs       = "); print_fxpt_freq(fs); newline();
303   printf("  target   = "); print_fxpt_freq(target_freq); newline();
304   printf("  baseband = "); print_fxpt_freq(baseband_freq); newline();
305   printf("  delta    = "); print_fxpt_freq(delta); newline();
306 #endif  
307
308   if (delta >= 0){
309     while (delta > fs)
310       delta -= fs;
311     if (delta <= fs/2){         // non-inverted region
312       *dxc_freq = -delta;
313       *inverted = false;
314     }
315     else {                      // inverted region
316       *dxc_freq = delta - fs;
317       *inverted = true;
318     }
319   }
320   else {
321     while (delta < -fs)
322       delta += fs;
323     if (delta >= -fs/2){        // non-inverted region
324       *dxc_freq = -delta;
325       *inverted = false;
326     }
327     else {                      // inverted region
328       *dxc_freq = delta + fs;
329       *inverted = true;
330     }
331   }
332 }
333
334 bool
335 db_set_lo_offset(struct db_base *db, u2_fxpt_freq_t offset)
336 {
337   db->current_lo_offset = offset;
338   return true;
339 }
340
341 bool
342 db_tune(struct db_base *db, u2_fxpt_freq_t target_freq, struct tune_result *result)
343 {
344   memset(result, 0, sizeof(*result));
345   bool inverted = false;
346   u2_fxpt_freq_t dxc_freq;
347   u2_fxpt_freq_t actual_dxc_freq;
348
349   // Ask the d'board to tune as closely as it can to target_freq+lo_offset
350   bool ok = db->set_freq(db, target_freq+db->current_lo_offset, &result->baseband_freq);
351
352   // Calculate the DDC setting that will downconvert the baseband from the
353   // daughterboard to our target frequency.
354   calc_dxc_freq(target_freq, result->baseband_freq, &dxc_freq, &inverted);
355
356   // If the spectrum is inverted, and the daughterboard doesn't do
357   // quadrature downconversion, we can fix the inversion by flipping the
358   // sign of the dxc_freq...  (This only happens using the basic_rx board)
359   
360   if (db->spectrum_inverted)
361     inverted = !inverted;
362
363   if (inverted && !db->is_quadrature){
364     dxc_freq = -dxc_freq;
365     inverted = !inverted;
366   }
367
368   if (db->is_tx){
369     dxc_freq = -dxc_freq;       // down conversion versus up conversion
370     ok &= db_set_duc_freq(dxc_freq, &actual_dxc_freq);
371   }
372   else {
373     ok &= db_set_ddc_freq(dxc_freq, &actual_dxc_freq);
374   }
375
376   result->dxc_freq = dxc_freq;
377   result->residual_freq = dxc_freq - actual_dxc_freq;
378   result->inverted = inverted;
379   return ok;
380 }
381
382 static int32_t
383 compute_freq_control_word(u2_fxpt_freq_t target_freq, u2_fxpt_freq_t *actual_freq)
384 {
385   // If we were using floating point, we'd calculate
386   //   master = 100e6;
387   //   v = (int) rint(target_freq / master_freq) * pow(2.0, 32.0);
388
389   //printf("compute_freq_control_word\n");
390   //printf("  target_freq = "); print_fxpt_freq(target_freq); newline();
391
392   int32_t master_freq = 100000000;      // 100M
393
394   int32_t v = ((target_freq << 12)) / master_freq;
395   //printf("  fcw = %d\n", v);
396
397   *actual_freq = (v * (int64_t) master_freq) >> 12;
398
399   //printf("  actual = "); print_fxpt_freq(*actual_freq); newline();
400
401   return v;
402 }
403
404
405 bool
406 db_set_ddc_freq(u2_fxpt_freq_t dxc_freq, u2_fxpt_freq_t *actual_dxc_freq)
407 {
408   int32_t v = compute_freq_control_word(dxc_freq, actual_dxc_freq);
409   dsp_rx_regs->freq = v;
410   return true;
411 }
412
413 bool
414 db_set_duc_freq(u2_fxpt_freq_t dxc_freq, u2_fxpt_freq_t *actual_dxc_freq)
415 {
416   int32_t v = compute_freq_control_word(dxc_freq, actual_dxc_freq);
417   dsp_tx_regs->freq = v;
418   return true;
419 }
420
421 bool
422 db_set_gain(struct db_base *db, u2_fxpt_gain_t gain)
423 {
424   return db->set_gain(db, gain);
425 }
426
427 bool
428 db_set_antenna(struct db_base *db, int ant)
429 {
430   if (db->set_antenna == 0) return false;
431   return db->set_antenna(db, ant);
432 }