3 * Copyright (c) 2009-2010 Alexander Egorenkov <egorenar@gmail.com>
4 * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include "rt2860_read_eeprom.h"
20 #include "rt2860_reg.h"
21 #include "rt2860_eeprom.h"
22 #include "rt2860_io.h"
23 #include "rt2860_debug.h"
28 void rt2860_read_eeprom(struct rt2860_softc
*sc
)
34 /* read EEPROM address number */
36 tmp
= rt2860_io_mac_read(sc
, RT2860_REG_EEPROM_CSR
);
39 sc
->eeprom_addr_num
= 6;
40 else if((tmp
& 0x30) == 0x10)
41 sc
->eeprom_addr_num
= 8;
43 sc
->eeprom_addr_num
= 8;
45 /* read EEPROM version */
47 sc
->eeprom_rev
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_VERSION
);
49 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
50 "%s: EEPROM rev=0x%04x\n",
51 device_get_nameunit(sc
->dev
), sc
->eeprom_rev
);
53 /* read MAC address */
55 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_ADDRESS01
);
57 sc
->mac_addr
[0] = (val
& 0xff);
58 sc
->mac_addr
[1] = (val
>> 8);
60 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_ADDRESS23
);
62 sc
->mac_addr
[2] = (val
& 0xff);
63 sc
->mac_addr
[3] = (val
>> 8);
65 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_ADDRESS45
);
67 sc
->mac_addr
[4] = (val
& 0xff);
68 sc
->mac_addr
[5] = (val
>> 8);
70 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
71 "%s: EEPROM mac address=%s\n",
72 device_get_nameunit(sc
->dev
), ether_sprintf(sc
->mac_addr
));
74 /* read RF information */
76 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_ANTENNA
);
79 printf("%s: invalid EEPROM antenna info\n",
80 device_get_nameunit(sc
->dev
));
82 sc
->rf_rev
= RT2860_EEPROM_RF_2820
;
88 sc
->rf_rev
= (val
>> 8) & 0xf;
89 sc
->ntxpath
= (val
>> 4) & 0xf;
90 sc
->nrxpath
= (val
& 0xf);
93 if ((sc
->mac_rev
!= 0x28830300) && (sc
->nrxpath
> 2))
95 /* only 2 Rx streams for RT2860 series */
100 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
101 "%s: EEPROM RF rev=0x%04x, paths=%dT%dR\n",
102 device_get_nameunit(sc
->dev
), sc
->rf_rev
, sc
->ntxpath
, sc
->nrxpath
);
104 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_NIC_CONFIG
);
106 sc
->hw_radio_cntl
= ((val
& RT2860_EEPROM_HW_RADIO_CNTL
) ? 1 : 0);
107 sc
->tx_agc_cntl
= ((val
& RT2860_EEPROM_TX_AGC_CNTL
) ? 1 : 0);
108 sc
->ext_lna_2ghz
= ((val
& RT2860_EEPROM_EXT_LNA_2GHZ
) ? 1 : 0);
109 sc
->ext_lna_5ghz
= ((val
& RT2860_EEPROM_EXT_LNA_5GHZ
) ? 1 : 0);
111 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
112 "%s: EEPROM NIC config: HW radio cntl=%d, Tx AGC cntl=%d, ext LNA gains=%d/%d\n",
113 device_get_nameunit(sc
->dev
),
114 sc
->hw_radio_cntl
, sc
->tx_agc_cntl
, sc
->ext_lna_2ghz
, sc
->ext_lna_5ghz
);
116 /* read country code */
118 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_COUNTRY
);
120 sc
->country_2ghz
= (val
>> 8) & 0xff;
121 sc
->country_5ghz
= (val
& 0xff);
123 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
124 "%s: EEPROM country code=%d/%d\n",
125 device_get_nameunit(sc
->dev
), sc
->country_2ghz
, sc
->country_5ghz
);
127 /* read RF frequency offset */
129 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_RF_FREQ_OFF
);
131 if ((val
& 0xff) != 0xff)
133 sc
->rf_freq_off
= (val
& 0xff);
137 printf("%s: invalid EEPROM RF freq offset\n",
138 device_get_nameunit(sc
->dev
));
143 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
144 "%s: EEPROM freq offset=0x%02x\n",
145 device_get_nameunit(sc
->dev
), sc
->rf_freq_off
);
147 /* read LEDs operating mode */
149 if (((val
>> 8) & 0xff) != 0xff)
151 sc
->led_cntl
= ((val
>> 8) & 0xff);
152 sc
->led_off
[0] = rt2860_io_eeprom_read(sc
, RT2860_EEPROM_LED1_OFF
);
153 sc
->led_off
[1] = rt2860_io_eeprom_read(sc
, RT2860_EEPROM_LED2_OFF
);
154 sc
->led_off
[2] = rt2860_io_eeprom_read(sc
, RT2860_EEPROM_LED3_OFF
);
158 printf("%s: invalid EEPROM LED settings\n",
159 device_get_nameunit(sc
->dev
));
161 sc
->led_cntl
= RT2860_EEPROM_LED_CNTL_DEFAULT
;
162 sc
->led_off
[0] = RT2860_EEPROM_LED1_OFF_DEFAULT
;
163 sc
->led_off
[1] = RT2860_EEPROM_LED2_OFF_DEFAULT
;
164 sc
->led_off
[2] = RT2860_EEPROM_LED3_OFF_DEFAULT
;
167 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
168 "%s: EEPROM LED cntl=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n",
169 device_get_nameunit(sc
->dev
), sc
->led_cntl
,
170 sc
->led_off
[0], sc
->led_off
[1], sc
->led_off
[2]);
172 /* read RSSI offsets and LNA gains */
174 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_LNA_GAIN
);
176 sc
->lna_gain
[0] = (val
& 0xff);
177 sc
->lna_gain
[1] = (val
>> 8) & 0xff;
179 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_RSSI_OFF_2GHZ_BASE
);
181 sc
->rssi_off_2ghz
[0] = (val
& 0xff);
182 sc
->rssi_off_2ghz
[1] = (val
>> 8) & 0xff;
184 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_RSSI_OFF_2GHZ_BASE
+ sizeof(uint16_t));
186 sc
->rssi_off_2ghz
[2] = (val
& 0xff);
187 sc
->lna_gain
[2] = (val
>> 8) & 0xff;
189 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_RSSI_OFF_5GHZ_BASE
);
191 sc
->rssi_off_5ghz
[0] = (val
& 0xff);
192 sc
->rssi_off_5ghz
[1] = (val
>> 8) & 0xff;
194 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_RSSI_OFF_5GHZ_BASE
+ sizeof(uint16_t));
196 sc
->rssi_off_5ghz
[2] = (val
& 0xff);
197 sc
->lna_gain
[3] = (val
>> 8) & 0xff;
199 for (i
= 2; i
< RT2860_SOFTC_LNA_GAIN_COUNT
; i
++)
201 if (sc
->lna_gain
[i
] == 0x00 || sc
->lna_gain
[i
] == 0xff)
203 printf("%s: invalid EEPROM LNA gain #%d: 0x%02x\n",
204 device_get_nameunit(sc
->dev
), i
, sc
->lna_gain
[i
]);
206 sc
->lna_gain
[i
] = sc
->lna_gain
[1];
210 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
211 "%s: EEPROM LNA gains=0x%02x/0x%02x/0x%02x/0x%02x\n",
212 device_get_nameunit(sc
->dev
),
213 sc
->lna_gain
[0], sc
->lna_gain
[1], sc
->lna_gain
[2], sc
->lna_gain
[3]);
215 for (i
= 0; i
< RT2860_SOFTC_RSSI_OFF_COUNT
; i
++)
217 if (sc
->rssi_off_2ghz
[i
] < RT2860_EEPROM_RSSI_OFF_MIN
||
218 sc
->rssi_off_2ghz
[i
] > RT2860_EEPROM_RSSI_OFF_MAX
)
220 printf("%s: invalid EEPROM RSSI offset #%d (2GHz): 0x%02x\n",
221 device_get_nameunit(sc
->dev
), i
, sc
->rssi_off_2ghz
[i
]);
223 sc
->rssi_off_2ghz
[i
] = 0;
226 if (sc
->rssi_off_5ghz
[i
] < RT2860_EEPROM_RSSI_OFF_MIN
||
227 sc
->rssi_off_5ghz
[i
] > RT2860_EEPROM_RSSI_OFF_MAX
)
229 printf("%s: invalid EEPROM RSSI offset #%d (5GHz): 0x%02x\n",
230 device_get_nameunit(sc
->dev
), i
, sc
->rssi_off_5ghz
[i
]);
232 sc
->rssi_off_5ghz
[i
] = 0;
236 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
237 "%s: EEPROM RSSI offsets 2GHz=%d/%d/%d\n",
238 device_get_nameunit(sc
->dev
),
239 sc
->rssi_off_2ghz
[0], sc
->rssi_off_2ghz
[1], sc
->rssi_off_2ghz
[2]);
241 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
242 "%s: EEPROM RSSI offsets 5GHz=%d/%d/%d\n",
243 device_get_nameunit(sc
->dev
),
244 sc
->rssi_off_5ghz
[0], sc
->rssi_off_5ghz
[1], sc
->rssi_off_5ghz
[2]);
246 /* read Tx power settings for 2GHz channels */
248 for (i
= 0; i
< 14; i
+= 2)
250 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TXPOW1_2GHZ_BASE
+ i
/ 2);
252 sc
->txpow1
[i
+ 0] = (int8_t) (val
& 0xff);
253 sc
->txpow1
[i
+ 1] = (int8_t) (val
>> 8);
255 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TXPOW2_2GHZ_BASE
+ i
/ 2);
257 sc
->txpow2
[i
+ 0] = (int8_t) (val
& 0xff);
258 sc
->txpow2
[i
+ 1] = (int8_t) (val
>> 8);
261 /* read Tx power settings for 5GHz channels */
263 for (; i
< RT2860_SOFTC_TXPOW_COUNT
; i
+= 2)
265 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TXPOW1_5GHZ_BASE
+ i
/ 2);
267 sc
->txpow1
[i
+ 0] = (int8_t) (val
& 0xff);
268 sc
->txpow1
[i
+ 1] = (int8_t) (val
>> 8);
270 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TXPOW2_5GHZ_BASE
+ i
/ 2);
272 sc
->txpow2
[i
+ 0] = (int8_t) (val
& 0xff);
273 sc
->txpow2
[i
+ 1] = (int8_t) (val
>> 8);
276 /* fix broken Tx power settings */
278 for (i
= 0; i
< 14; i
++)
280 if (sc
->txpow1
[i
] < RT2860_EEPROM_TXPOW_2GHZ_MIN
||
281 sc
->txpow1
[i
] > RT2860_EEPROM_TXPOW_2GHZ_MAX
)
283 printf("%s: invalid EEPROM Tx power1 #%d (2GHz): 0x%02x\n",
284 device_get_nameunit(sc
->dev
), i
, sc
->txpow1
[i
]);
286 sc
->txpow1
[i
] = RT2860_EEPROM_TXPOW_2GHZ_DEFAULT
;
289 if (sc
->txpow2
[i
] < RT2860_EEPROM_TXPOW_2GHZ_MIN
||
290 sc
->txpow2
[i
] > RT2860_EEPROM_TXPOW_2GHZ_MAX
)
292 printf("%s: invalid EEPROM Tx power2 #%d (2GHz): 0x%02x\n",
293 device_get_nameunit(sc
->dev
), i
, sc
->txpow2
[i
]);
295 sc
->txpow2
[i
] = RT2860_EEPROM_TXPOW_2GHZ_DEFAULT
;
299 for (; i
< RT2860_SOFTC_TXPOW_COUNT
; i
++)
301 if (sc
->txpow1
[i
] < RT2860_EEPROM_TXPOW_5GHZ_MIN
||
302 sc
->txpow1
[i
] > RT2860_EEPROM_TXPOW_5GHZ_MAX
)
304 printf("%s: invalid EEPROM Tx power1 #%d (5GHz): 0x%02x\n",
305 device_get_nameunit(sc
->dev
), i
, sc
->txpow1
[i
]);
307 sc
->txpow1
[i
] = RT2860_EEPROM_TXPOW_5GHZ_DEFAULT
;
310 if (sc
->txpow2
[i
] < RT2860_EEPROM_TXPOW_5GHZ_MIN
||
311 sc
->txpow2
[i
] > RT2860_EEPROM_TXPOW_5GHZ_MAX
)
313 printf("%s: invalid EEPROM Tx power2 #%d (5GHz): 0x%02x\n",
314 device_get_nameunit(sc
->dev
), i
, sc
->txpow2
[i
]);
316 sc
->txpow2
[i
] = RT2860_EEPROM_TXPOW_5GHZ_DEFAULT
;
320 /* read Tx power per rate deltas */
322 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TXPOW_RATE_DELTA
);
324 sc
->txpow_rate_delta_2ghz
= 0;
325 sc
->txpow_rate_delta_5ghz
= 0;
327 if ((val
& 0xff) != 0xff)
330 sc
->txpow_rate_delta_2ghz
= (val
& 0xf);
333 sc
->txpow_rate_delta_2ghz
= -sc
->txpow_rate_delta_2ghz
;
338 if ((val
& 0xff) != 0xff)
341 sc
->txpow_rate_delta_5ghz
= (val
& 0xf);
344 sc
->txpow_rate_delta_5ghz
= -sc
->txpow_rate_delta_5ghz
;
347 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
348 "%s: EEPROM Tx power per rate deltas=%d(2MHz), %d(5MHz)\n",
349 device_get_nameunit(sc
->dev
),
350 sc
->txpow_rate_delta_2ghz
, sc
->txpow_rate_delta_5ghz
);
352 /* read Tx power per rate */
354 for (i
= 0; i
< RT2860_SOFTC_TXPOW_RATE_COUNT
; i
++)
356 rt2860_io_eeprom_read_multi(sc
, RT2860_EEPROM_TXPOW_RATE_BASE
+ i
* sizeof(uint32_t),
357 &tmp
, sizeof(uint32_t));
359 sc
->txpow_rate_20mhz
[i
] = tmp
;
360 sc
->txpow_rate_40mhz_2ghz
[i
] =
361 rt2860_read_eeprom_txpow_rate_add_delta(tmp
, sc
->txpow_rate_delta_2ghz
);
362 sc
->txpow_rate_40mhz_5ghz
[i
] =
363 rt2860_read_eeprom_txpow_rate_add_delta(tmp
, sc
->txpow_rate_delta_5ghz
);
365 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
366 "%s: EEPROM Tx power per rate #%d=0x%08x(20MHz), 0x%08x(40MHz/2GHz), 0x%08x(40MHz/5GHz)\n",
367 device_get_nameunit(sc
->dev
), i
,
368 sc
->txpow_rate_20mhz
[i
], sc
->txpow_rate_40mhz_2ghz
[i
], sc
->txpow_rate_40mhz_5ghz
[i
]);
372 sc
->tx_agc_cntl_2ghz
= sc
->tx_agc_cntl_5ghz
= 1;
374 /* read factory-calibrated samples for temperature compensation */
376 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TSSI_2GHZ_BASE
);
378 sc
->tssi_2ghz
[0] = (val
& 0xff); /* [-4] */
379 sc
->tssi_2ghz
[1] = (val
>> 8); /* [-3] */
381 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TSSI_2GHZ_BASE
+ sizeof(uint16_t));
383 sc
->tssi_2ghz
[2] = (val
& 0xff); /* [-2] */
384 sc
->tssi_2ghz
[3] = (val
>> 8); /* [-1] */
386 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TSSI_2GHZ_BASE
+ 2 * sizeof(uint16_t));
388 sc
->tssi_2ghz
[4] = (val
& 0xff); /* [0] */
389 sc
->tssi_2ghz
[5] = (val
>> 8); /* [+1] */
391 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TSSI_2GHZ_BASE
+ 3 * sizeof(uint16_t));
393 sc
->tssi_2ghz
[6] = (val
& 0xff); /* [+2] */
394 sc
->tssi_2ghz
[7] = (val
>> 8); /* [+3] */
396 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TSSI_2GHZ_BASE
+ 4 * sizeof(uint16_t));
398 sc
->tssi_2ghz
[8] = (val
& 0xff); /* [+4] */
399 sc
->tssi_step_2ghz
= (val
>> 8);
401 if (sc
->tssi_2ghz
[4] == 0xff)
402 sc
->tx_agc_cntl_2ghz
= 0;
404 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
405 "%s: EEPROM TSSI 2GHz: 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, "
406 "0x%02x, 0x%02x, step=%d\n",
407 device_get_nameunit(sc
->dev
),
408 sc
->tssi_2ghz
[0], sc
->tssi_2ghz
[1], sc
->tssi_2ghz
[2],
409 sc
->tssi_2ghz
[3], sc
->tssi_2ghz
[4], sc
->tssi_2ghz
[5],
410 sc
->tssi_2ghz
[6], sc
->tssi_2ghz
[7], sc
->tssi_2ghz
[8],
413 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TSSI_5GHZ_BASE
);
415 sc
->tssi_5ghz
[0] = (val
& 0xff); /* [-4] */
416 sc
->tssi_5ghz
[1] = (val
>> 8); /* [-3] */
418 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TSSI_5GHZ_BASE
+ sizeof(uint16_t));
420 sc
->tssi_5ghz
[2] = (val
& 0xff); /* [-2] */
421 sc
->tssi_5ghz
[3] = (val
>> 8); /* [-1] */
423 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TSSI_5GHZ_BASE
+ 2 * sizeof(uint16_t));
425 sc
->tssi_5ghz
[4] = (val
& 0xff); /* [0] */
426 sc
->tssi_5ghz
[5] = (val
>> 8); /* [+1] */
428 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TSSI_5GHZ_BASE
+ 3 * sizeof(uint16_t));
430 sc
->tssi_5ghz
[6] = (val
& 0xff); /* [+2] */
431 sc
->tssi_5ghz
[7] = (val
>> 8); /* [+3] */
433 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TSSI_5GHZ_BASE
+ 4 * sizeof(uint16_t));
435 sc
->tssi_5ghz
[8] = (val
& 0xff); /* [+4] */
436 sc
->tssi_step_5ghz
= (val
>> 8);
438 if (sc
->tssi_5ghz
[4] == 0xff)
439 sc
->tx_agc_cntl_5ghz
= 0;
441 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
442 "%s: EEPROM TSSI 5GHz: 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, "
443 "0x%02x, 0x%02x, step=%d\n",
444 device_get_nameunit(sc
->dev
),
445 sc
->tssi_5ghz
[0], sc
->tssi_5ghz
[1], sc
->tssi_5ghz
[2],
446 sc
->tssi_5ghz
[3], sc
->tssi_5ghz
[4], sc
->tssi_5ghz
[5],
447 sc
->tssi_5ghz
[6], sc
->tssi_5ghz
[7], sc
->tssi_5ghz
[8],
450 /* read default BBP settings */
452 rt2860_io_eeprom_read_multi(sc
, RT2860_EEPROM_BBP_BASE
,
453 sc
->bbp_eeprom
, RT2860_SOFTC_BBP_EEPROM_COUNT
* sizeof(uint16_t));
455 /* read powersave level */
457 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_POWERSAVE_LEVEL
);
459 sc
->powersave_level
= val
& 0xff;
461 if ((sc
->powersave_level
& 0xff) == 0xff)
462 printf("%s: invalid EEPROM powersave level\n",
463 device_get_nameunit(sc
->dev
));
465 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
466 "%s: EEPROM powersave level=0x%02x\n",
467 device_get_nameunit(sc
->dev
), sc
->powersave_level
);
471 * rt2860_read_eeprom_txpow_rate_add_delta
473 uint32_t rt2860_read_eeprom_txpow_rate_add_delta(uint32_t txpow_rate
,
479 for (i
= 0; i
< 8; i
++)
481 b4
= txpow_rate
& 0xf;
489 txpow_rate
= (txpow_rate
>> 4) | (b4
<< 28);