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 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
94 "%s: EEPROM RF rev=0x%04x, paths=%dT%dR\n",
95 device_get_nameunit(sc
->dev
), sc
->rf_rev
, sc
->ntxpath
, sc
->nrxpath
);
97 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_NIC_CONFIG
);
99 sc
->hw_radio_cntl
= ((val
& RT2860_EEPROM_HW_RADIO_CNTL
) ? 1 : 0);
100 sc
->tx_agc_cntl
= ((val
& RT2860_EEPROM_TX_AGC_CNTL
) ? 1 : 0);
101 sc
->ext_lna_2ghz
= ((val
& RT2860_EEPROM_EXT_LNA_2GHZ
) ? 1 : 0);
102 sc
->ext_lna_5ghz
= ((val
& RT2860_EEPROM_EXT_LNA_5GHZ
) ? 1 : 0);
104 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
105 "%s: EEPROM NIC config: HW radio cntl=%d, Tx AGC cntl=%d, ext LNA gains=%d/%d\n",
106 device_get_nameunit(sc
->dev
),
107 sc
->hw_radio_cntl
, sc
->tx_agc_cntl
, sc
->ext_lna_2ghz
, sc
->ext_lna_5ghz
);
109 /* read country code */
111 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_COUNTRY
);
113 sc
->country_2ghz
= (val
>> 8) & 0xff;
114 sc
->country_5ghz
= (val
& 0xff);
116 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
117 "%s: EEPROM country code=%d/%d\n",
118 device_get_nameunit(sc
->dev
), sc
->country_2ghz
, sc
->country_5ghz
);
120 /* read RF frequency offset */
122 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_RF_FREQ_OFF
);
124 if ((val
& 0xff) != 0xff)
126 sc
->rf_freq_off
= (val
& 0xff);
130 printf("%s: invalid EEPROM RF freq offset\n",
131 device_get_nameunit(sc
->dev
));
136 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
137 "%s: EEPROM freq offset=0x%02x\n",
138 device_get_nameunit(sc
->dev
), sc
->rf_freq_off
);
140 /* read LEDs operating mode */
142 if (((val
>> 8) & 0xff) != 0xff)
144 sc
->led_cntl
= ((val
>> 8) & 0xff);
145 sc
->led_off
[0] = rt2860_io_eeprom_read(sc
, RT2860_EEPROM_LED1_OFF
);
146 sc
->led_off
[1] = rt2860_io_eeprom_read(sc
, RT2860_EEPROM_LED2_OFF
);
147 sc
->led_off
[2] = rt2860_io_eeprom_read(sc
, RT2860_EEPROM_LED3_OFF
);
151 printf("%s: invalid EEPROM LED settings\n",
152 device_get_nameunit(sc
->dev
));
154 sc
->led_cntl
= RT2860_EEPROM_LED_CNTL_DEFAULT
;
155 sc
->led_off
[0] = RT2860_EEPROM_LED1_OFF_DEFAULT
;
156 sc
->led_off
[1] = RT2860_EEPROM_LED2_OFF_DEFAULT
;
157 sc
->led_off
[2] = RT2860_EEPROM_LED3_OFF_DEFAULT
;
160 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
161 "%s: EEPROM LED cntl=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n",
162 device_get_nameunit(sc
->dev
), sc
->led_cntl
,
163 sc
->led_off
[0], sc
->led_off
[1], sc
->led_off
[2]);
165 /* read RSSI offsets and LNA gains */
167 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_LNA_GAIN
);
169 sc
->lna_gain
[0] = (val
& 0xff);
170 sc
->lna_gain
[1] = (val
>> 8) & 0xff;
172 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_RSSI_OFF_2GHZ_BASE
);
174 sc
->rssi_off_2ghz
[0] = (val
& 0xff);
175 sc
->rssi_off_2ghz
[1] = (val
>> 8) & 0xff;
177 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_RSSI_OFF_2GHZ_BASE
+ sizeof(uint16_t));
179 sc
->rssi_off_2ghz
[2] = (val
& 0xff);
180 sc
->lna_gain
[2] = (val
>> 8) & 0xff;
182 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_RSSI_OFF_5GHZ_BASE
);
184 sc
->rssi_off_5ghz
[0] = (val
& 0xff);
185 sc
->rssi_off_5ghz
[1] = (val
>> 8) & 0xff;
187 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_RSSI_OFF_5GHZ_BASE
+ sizeof(uint16_t));
189 sc
->rssi_off_5ghz
[2] = (val
& 0xff);
190 sc
->lna_gain
[3] = (val
>> 8) & 0xff;
192 for (i
= 2; i
< RT2860_SOFTC_LNA_GAIN_COUNT
; i
++)
194 if (sc
->lna_gain
[i
] == 0x00 || sc
->lna_gain
[i
] == (int8_t) 0xff)
196 printf("%s: invalid EEPROM LNA gain #%d: 0x%02x\n",
197 device_get_nameunit(sc
->dev
), i
, sc
->lna_gain
[i
]);
199 sc
->lna_gain
[i
] = sc
->lna_gain
[1];
203 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
204 "%s: EEPROM LNA gains=0x%02x/0x%02x/0x%02x/0x%02x\n",
205 device_get_nameunit(sc
->dev
),
206 sc
->lna_gain
[0], sc
->lna_gain
[1], sc
->lna_gain
[2], sc
->lna_gain
[3]);
208 for (i
= 0; i
< RT2860_SOFTC_RSSI_OFF_COUNT
; i
++)
210 if (sc
->rssi_off_2ghz
[i
] < RT2860_EEPROM_RSSI_OFF_MIN
||
211 sc
->rssi_off_2ghz
[i
] > RT2860_EEPROM_RSSI_OFF_MAX
)
213 printf("%s: invalid EEPROM RSSI offset #%d (2GHz): 0x%02x\n",
214 device_get_nameunit(sc
->dev
), i
, sc
->rssi_off_2ghz
[i
]);
216 sc
->rssi_off_2ghz
[i
] = 0;
219 if (sc
->rssi_off_5ghz
[i
] < RT2860_EEPROM_RSSI_OFF_MIN
||
220 sc
->rssi_off_5ghz
[i
] > RT2860_EEPROM_RSSI_OFF_MAX
)
222 printf("%s: invalid EEPROM RSSI offset #%d (5GHz): 0x%02x\n",
223 device_get_nameunit(sc
->dev
), i
, sc
->rssi_off_5ghz
[i
]);
225 sc
->rssi_off_5ghz
[i
] = 0;
229 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
230 "%s: EEPROM RSSI offsets 2GHz=%d/%d/%d\n",
231 device_get_nameunit(sc
->dev
),
232 sc
->rssi_off_2ghz
[0], sc
->rssi_off_2ghz
[1], sc
->rssi_off_2ghz
[2]);
234 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
235 "%s: EEPROM RSSI offsets 5GHz=%d/%d/%d\n",
236 device_get_nameunit(sc
->dev
),
237 sc
->rssi_off_5ghz
[0], sc
->rssi_off_5ghz
[1], sc
->rssi_off_5ghz
[2]);
239 /* read Tx power settings for 2GHz channels */
241 for (i
= 0; i
< 14; i
+= 2)
243 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TXPOW1_2GHZ_BASE
+ i
/ 2);
245 sc
->txpow1
[i
+ 0] = (int8_t) (val
& 0xff);
246 sc
->txpow1
[i
+ 1] = (int8_t) (val
>> 8);
248 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TXPOW2_2GHZ_BASE
+ i
/ 2);
250 sc
->txpow2
[i
+ 0] = (int8_t) (val
& 0xff);
251 sc
->txpow2
[i
+ 1] = (int8_t) (val
>> 8);
254 /* read Tx power settings for 5GHz channels */
256 for (; i
< RT2860_SOFTC_TXPOW_COUNT
; i
+= 2)
258 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TXPOW1_5GHZ_BASE
+ i
/ 2);
260 sc
->txpow1
[i
+ 0] = (int8_t) (val
& 0xff);
261 sc
->txpow1
[i
+ 1] = (int8_t) (val
>> 8);
263 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TXPOW2_5GHZ_BASE
+ i
/ 2);
265 sc
->txpow2
[i
+ 0] = (int8_t) (val
& 0xff);
266 sc
->txpow2
[i
+ 1] = (int8_t) (val
>> 8);
269 /* fix broken Tx power settings */
271 for (i
= 0; i
< 14; i
++)
273 if (sc
->txpow1
[i
] < RT2860_EEPROM_TXPOW_2GHZ_MIN
||
274 sc
->txpow1
[i
] > RT2860_EEPROM_TXPOW_2GHZ_MAX
)
276 printf("%s: invalid EEPROM Tx power1 #%d (2GHz): 0x%02x\n",
277 device_get_nameunit(sc
->dev
), i
, sc
->txpow1
[i
]);
279 sc
->txpow1
[i
] = RT2860_EEPROM_TXPOW_2GHZ_DEFAULT
;
282 if (sc
->txpow2
[i
] < RT2860_EEPROM_TXPOW_2GHZ_MIN
||
283 sc
->txpow2
[i
] > RT2860_EEPROM_TXPOW_2GHZ_MAX
)
285 printf("%s: invalid EEPROM Tx power2 #%d (2GHz): 0x%02x\n",
286 device_get_nameunit(sc
->dev
), i
, sc
->txpow2
[i
]);
288 sc
->txpow2
[i
] = RT2860_EEPROM_TXPOW_2GHZ_DEFAULT
;
292 for (; i
< RT2860_SOFTC_TXPOW_COUNT
; i
++)
294 if (sc
->txpow1
[i
] < RT2860_EEPROM_TXPOW_5GHZ_MIN
||
295 sc
->txpow1
[i
] > RT2860_EEPROM_TXPOW_5GHZ_MAX
)
297 printf("%s: invalid EEPROM Tx power1 #%d (5GHz): 0x%02x\n",
298 device_get_nameunit(sc
->dev
), i
, sc
->txpow1
[i
]);
300 sc
->txpow1
[i
] = RT2860_EEPROM_TXPOW_5GHZ_DEFAULT
;
303 if (sc
->txpow2
[i
] < RT2860_EEPROM_TXPOW_5GHZ_MIN
||
304 sc
->txpow2
[i
] > RT2860_EEPROM_TXPOW_5GHZ_MAX
)
306 printf("%s: invalid EEPROM Tx power2 #%d (5GHz): 0x%02x\n",
307 device_get_nameunit(sc
->dev
), i
, sc
->txpow2
[i
]);
309 sc
->txpow2
[i
] = RT2860_EEPROM_TXPOW_5GHZ_DEFAULT
;
313 /* read Tx power per rate deltas */
315 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TXPOW_RATE_DELTA
);
317 sc
->txpow_rate_delta_2ghz
= 0;
318 sc
->txpow_rate_delta_5ghz
= 0;
320 if ((val
& 0xff) != 0xff)
323 sc
->txpow_rate_delta_2ghz
= (val
& 0xf);
326 sc
->txpow_rate_delta_2ghz
= -sc
->txpow_rate_delta_2ghz
;
331 if ((val
& 0xff) != 0xff)
334 sc
->txpow_rate_delta_5ghz
= (val
& 0xf);
337 sc
->txpow_rate_delta_5ghz
= -sc
->txpow_rate_delta_5ghz
;
340 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
341 "%s: EEPROM Tx power per rate deltas=%d(2MHz), %d(5MHz)\n",
342 device_get_nameunit(sc
->dev
),
343 sc
->txpow_rate_delta_2ghz
, sc
->txpow_rate_delta_5ghz
);
345 /* read Tx power per rate */
347 for (i
= 0; i
< RT2860_SOFTC_TXPOW_RATE_COUNT
; i
++)
349 rt2860_io_eeprom_read_multi(sc
, RT2860_EEPROM_TXPOW_RATE_BASE
+ i
* sizeof(uint32_t),
350 &tmp
, sizeof(uint32_t));
352 sc
->txpow_rate_20mhz
[i
] = tmp
;
353 sc
->txpow_rate_40mhz_2ghz
[i
] =
354 rt2860_read_eeprom_txpow_rate_add_delta(tmp
, sc
->txpow_rate_delta_2ghz
);
355 sc
->txpow_rate_40mhz_5ghz
[i
] =
356 rt2860_read_eeprom_txpow_rate_add_delta(tmp
, sc
->txpow_rate_delta_5ghz
);
358 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
359 "%s: EEPROM Tx power per rate #%d=0x%08x(20MHz), 0x%08x(40MHz/2GHz), 0x%08x(40MHz/5GHz)\n",
360 device_get_nameunit(sc
->dev
), i
,
361 sc
->txpow_rate_20mhz
[i
], sc
->txpow_rate_40mhz_2ghz
[i
], sc
->txpow_rate_40mhz_5ghz
[i
]);
365 sc
->tx_agc_cntl_2ghz
= sc
->tx_agc_cntl_5ghz
= 1;
367 /* read factory-calibrated samples for temperature compensation */
369 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TSSI_2GHZ_BASE
);
371 sc
->tssi_2ghz
[0] = (val
& 0xff); /* [-4] */
372 sc
->tssi_2ghz
[1] = (val
>> 8); /* [-3] */
374 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TSSI_2GHZ_BASE
+ sizeof(uint16_t));
376 sc
->tssi_2ghz
[2] = (val
& 0xff); /* [-2] */
377 sc
->tssi_2ghz
[3] = (val
>> 8); /* [-1] */
379 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TSSI_2GHZ_BASE
+ 2 * sizeof(uint16_t));
381 sc
->tssi_2ghz
[4] = (val
& 0xff); /* [0] */
382 sc
->tssi_2ghz
[5] = (val
>> 8); /* [+1] */
384 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TSSI_2GHZ_BASE
+ 3 * sizeof(uint16_t));
386 sc
->tssi_2ghz
[6] = (val
& 0xff); /* [+2] */
387 sc
->tssi_2ghz
[7] = (val
>> 8); /* [+3] */
389 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TSSI_2GHZ_BASE
+ 4 * sizeof(uint16_t));
391 sc
->tssi_2ghz
[8] = (val
& 0xff); /* [+4] */
392 sc
->tssi_step_2ghz
= (val
>> 8);
394 if (sc
->tssi_2ghz
[4] == 0xff)
395 sc
->tx_agc_cntl_2ghz
= 0;
397 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
398 "%s: EEPROM TSSI 2GHz: 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, "
399 "0x%02x, 0x%02x, step=%d\n",
400 device_get_nameunit(sc
->dev
),
401 sc
->tssi_2ghz
[0], sc
->tssi_2ghz
[1], sc
->tssi_2ghz
[2],
402 sc
->tssi_2ghz
[3], sc
->tssi_2ghz
[4], sc
->tssi_2ghz
[5],
403 sc
->tssi_2ghz
[6], sc
->tssi_2ghz
[7], sc
->tssi_2ghz
[8],
406 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TSSI_5GHZ_BASE
);
408 sc
->tssi_5ghz
[0] = (val
& 0xff); /* [-4] */
409 sc
->tssi_5ghz
[1] = (val
>> 8); /* [-3] */
411 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TSSI_5GHZ_BASE
+ sizeof(uint16_t));
413 sc
->tssi_5ghz
[2] = (val
& 0xff); /* [-2] */
414 sc
->tssi_5ghz
[3] = (val
>> 8); /* [-1] */
416 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TSSI_5GHZ_BASE
+ 2 * sizeof(uint16_t));
418 sc
->tssi_5ghz
[4] = (val
& 0xff); /* [0] */
419 sc
->tssi_5ghz
[5] = (val
>> 8); /* [+1] */
421 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TSSI_5GHZ_BASE
+ 3 * sizeof(uint16_t));
423 sc
->tssi_5ghz
[6] = (val
& 0xff); /* [+2] */
424 sc
->tssi_5ghz
[7] = (val
>> 8); /* [+3] */
426 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_TSSI_5GHZ_BASE
+ 4 * sizeof(uint16_t));
428 sc
->tssi_5ghz
[8] = (val
& 0xff); /* [+4] */
429 sc
->tssi_step_5ghz
= (val
>> 8);
431 if (sc
->tssi_5ghz
[4] == 0xff)
432 sc
->tx_agc_cntl_5ghz
= 0;
434 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
435 "%s: EEPROM TSSI 5GHz: 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, "
436 "0x%02x, 0x%02x, step=%d\n",
437 device_get_nameunit(sc
->dev
),
438 sc
->tssi_5ghz
[0], sc
->tssi_5ghz
[1], sc
->tssi_5ghz
[2],
439 sc
->tssi_5ghz
[3], sc
->tssi_5ghz
[4], sc
->tssi_5ghz
[5],
440 sc
->tssi_5ghz
[6], sc
->tssi_5ghz
[7], sc
->tssi_5ghz
[8],
443 /* read default BBP settings */
445 rt2860_io_eeprom_read_multi(sc
, RT2860_EEPROM_BBP_BASE
,
446 sc
->bbp_eeprom
, RT2860_SOFTC_BBP_EEPROM_COUNT
* sizeof(uint16_t));
448 /* read powersave level */
450 val
= rt2860_io_eeprom_read(sc
, RT2860_EEPROM_POWERSAVE_LEVEL
);
452 sc
->powersave_level
= val
& 0xff;
454 if ((sc
->powersave_level
& 0xff) == 0xff)
455 printf("%s: invalid EEPROM powersave level\n",
456 device_get_nameunit(sc
->dev
));
458 RT2860_DPRINTF(sc
, RT2860_DEBUG_EEPROM
,
459 "%s: EEPROM powersave level=0x%02x\n",
460 device_get_nameunit(sc
->dev
), sc
->powersave_level
);
464 * rt2860_read_eeprom_txpow_rate_add_delta
466 uint32_t rt2860_read_eeprom_txpow_rate_add_delta(uint32_t txpow_rate
,
472 for (i
= 0; i
< 8; i
++)
474 b4
= txpow_rate
& 0xf;
482 txpow_rate
= (txpow_rate
>> 4) | (b4
<< 28);