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 "rt2870_read_eeprom.h"
20 #include "rt2870_eeprom.h"
21 #include "rt2870_io.h"
22 #include "rt2870_debug.h"
27 void rt2870_read_eeprom(struct rt2870_softc
*sc
)
33 /* read EEPROM version */
35 sc
->eeprom_rev
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_VERSION
);
37 RT2870_DPRINTF(sc
, RT2870_DEBUG_EEPROM
,
38 "%s: EEPROM rev=0x%04x\n",
39 device_get_nameunit(sc
->dev
), sc
->eeprom_rev
);
41 /* read MAC address */
43 rt2870_io_eeprom_read_multi(sc
, RT2870_EEPROM_ADDRESS
,
44 sc
->mac_addr
, IEEE80211_ADDR_LEN
);
46 RT2870_DPRINTF(sc
, RT2870_DEBUG_EEPROM
,
47 "%s: EEPROM mac address=%s\n",
48 device_get_nameunit(sc
->dev
), ether_sprintf(sc
->mac_addr
));
50 /* read RF information */
52 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_ANTENNA
);
55 printf("%s: invalid EEPROM antenna info\n",
56 device_get_nameunit(sc
->dev
));
60 sc
->rf_rev
= (val
>> 8) & 0xf;
61 sc
->ntxpath
= (val
>> 4) & 0xf;
62 sc
->nrxpath
= (val
& 0xf);
65 if ((sc
->mac_rev
!= 0x28830300) && (sc
->nrxpath
> 2))
67 /* only 2 Rx streams for RT2860 series */
72 RT2870_DPRINTF(sc
, RT2870_DEBUG_EEPROM
,
73 "%s: EEPROM RF rev=0x%04x, paths=%dT%dR\n",
74 device_get_nameunit(sc
->dev
), sc
->rf_rev
, sc
->ntxpath
, sc
->nrxpath
);
76 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_NIC_CONFIG
);
78 sc
->hw_radio_cntl
= ((val
& RT2870_EEPROM_HW_RADIO_CNTL
) ? 1 : 0);
79 sc
->tx_agc_cntl
= ((val
& RT2870_EEPROM_TX_AGC_CNTL
) ? 1 : 0);
80 sc
->ext_lna_2ghz
= ((val
& RT2870_EEPROM_EXT_LNA_2GHZ
) ? 1 : 0);
81 sc
->ext_lna_5ghz
= ((val
& RT2870_EEPROM_EXT_LNA_5GHZ
) ? 1 : 0);
83 RT2870_DPRINTF(sc
, RT2870_DEBUG_EEPROM
,
84 "%s: EEPROM NIC config: HW radio cntl=%d, Tx AGC cntl=%d, ext LNA gains=%d/%d\n",
85 device_get_nameunit(sc
->dev
),
86 sc
->hw_radio_cntl
, sc
->tx_agc_cntl
, sc
->ext_lna_2ghz
, sc
->ext_lna_5ghz
);
88 /* read country code */
90 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_COUNTRY
);
92 sc
->country_2ghz
= (val
>> 8) & 0xff;
93 sc
->country_5ghz
= (val
& 0xff);
95 RT2870_DPRINTF(sc
, RT2870_DEBUG_EEPROM
,
96 "%s: EEPROM country code=%d/%d\n",
97 device_get_nameunit(sc
->dev
), sc
->country_2ghz
, sc
->country_5ghz
);
99 /* read RF frequency offset */
101 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_RF_FREQ_OFF
);
103 if ((val
& 0xff) != 0xff)
105 sc
->rf_freq_off
= (val
& 0xff);
109 printf("%s: invalid EEPROM RF freq offset\n",
110 device_get_nameunit(sc
->dev
));
115 RT2870_DPRINTF(sc
, RT2870_DEBUG_EEPROM
,
116 "%s: EEPROM freq offset=0x%02x\n",
117 device_get_nameunit(sc
->dev
), sc
->rf_freq_off
);
119 /* read LEDs operating mode */
121 if (((val
>> 8) & 0xff) != 0xff)
123 sc
->led_cntl
= ((val
>> 8) & 0xff);
124 sc
->led_off
[0] = rt2870_io_eeprom_read(sc
, RT2870_EEPROM_LED1_OFF
);
125 sc
->led_off
[1] = rt2870_io_eeprom_read(sc
, RT2870_EEPROM_LED2_OFF
);
126 sc
->led_off
[2] = rt2870_io_eeprom_read(sc
, RT2870_EEPROM_LED3_OFF
);
130 printf("%s: invalid EEPROM LED settings\n",
131 device_get_nameunit(sc
->dev
));
133 sc
->led_cntl
= RT2870_EEPROM_LED_CNTL_DEFAULT
;
134 sc
->led_off
[0] = RT2870_EEPROM_LED1_OFF_DEFAULT
;
135 sc
->led_off
[1] = RT2870_EEPROM_LED2_OFF_DEFAULT
;
136 sc
->led_off
[2] = RT2870_EEPROM_LED3_OFF_DEFAULT
;
139 RT2870_DPRINTF(sc
, RT2870_DEBUG_EEPROM
,
140 "%s: EEPROM LED cntl=0x%02x, LEDs=0x%04x/0x%04x/0x%04x\n",
141 device_get_nameunit(sc
->dev
), sc
->led_cntl
,
142 sc
->led_off
[0], sc
->led_off
[1], sc
->led_off
[2]);
144 /* read RSSI offsets and LNA gains */
146 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_LNA_GAIN
);
148 sc
->lna_gain
[0] = (val
& 0xff);
149 sc
->lna_gain
[1] = (val
>> 8) & 0xff;
151 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_RSSI_OFF_2GHZ_BASE
);
153 sc
->rssi_off_2ghz
[0] = (val
& 0xff);
154 sc
->rssi_off_2ghz
[1] = (val
>> 8) & 0xff;
156 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_RSSI_OFF_2GHZ_BASE
+ sizeof(uint16_t));
158 sc
->rssi_off_2ghz
[2] = (val
& 0xff);
159 sc
->lna_gain
[2] = (val
>> 8) & 0xff;
161 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_RSSI_OFF_5GHZ_BASE
);
163 sc
->rssi_off_5ghz
[0] = (val
& 0xff);
164 sc
->rssi_off_5ghz
[1] = (val
>> 8) & 0xff;
166 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_RSSI_OFF_5GHZ_BASE
+ sizeof(uint16_t));
168 sc
->rssi_off_5ghz
[2] = (val
& 0xff);
169 sc
->lna_gain
[3] = (val
>> 8) & 0xff;
171 for (i
= 2; i
< RT2870_SOFTC_LNA_GAIN_COUNT
; i
++)
173 if (sc
->lna_gain
[i
] == 0x00 || sc
->lna_gain
[i
] == (int8_t) 0xff)
175 printf("%s: invalid EEPROM LNA gain #%d: 0x%02x\n",
176 device_get_nameunit(sc
->dev
), i
, sc
->lna_gain
[i
]);
178 sc
->lna_gain
[i
] = sc
->lna_gain
[1];
182 RT2870_DPRINTF(sc
, RT2870_DEBUG_EEPROM
,
183 "%s: EEPROM LNA gains=0x%02x/0x%02x/0x%02x/0x%02x\n",
184 device_get_nameunit(sc
->dev
),
185 sc
->lna_gain
[0], sc
->lna_gain
[1], sc
->lna_gain
[2], sc
->lna_gain
[3]);
187 for (i
= 0; i
< RT2870_SOFTC_RSSI_OFF_COUNT
; i
++)
189 if (sc
->rssi_off_2ghz
[i
] < RT2870_EEPROM_RSSI_OFF_MIN
||
190 sc
->rssi_off_2ghz
[i
] > RT2870_EEPROM_RSSI_OFF_MAX
)
192 printf("%s: invalid EEPROM RSSI offset #%d (2GHz): 0x%02x\n",
193 device_get_nameunit(sc
->dev
), i
, sc
->rssi_off_2ghz
[i
]);
195 sc
->rssi_off_2ghz
[i
] = 0;
198 if (sc
->rssi_off_5ghz
[i
] < RT2870_EEPROM_RSSI_OFF_MIN
||
199 sc
->rssi_off_5ghz
[i
] > RT2870_EEPROM_RSSI_OFF_MAX
)
201 printf("%s: invalid EEPROM RSSI offset #%d (5GHz): 0x%02x\n",
202 device_get_nameunit(sc
->dev
), i
, sc
->rssi_off_5ghz
[i
]);
204 sc
->rssi_off_5ghz
[i
] = 0;
208 RT2870_DPRINTF(sc
, RT2870_DEBUG_EEPROM
,
209 "%s: EEPROM RSSI offsets 2GHz=%d/%d/%d\n",
210 device_get_nameunit(sc
->dev
),
211 sc
->rssi_off_2ghz
[0], sc
->rssi_off_2ghz
[1], sc
->rssi_off_2ghz
[2]);
213 RT2870_DPRINTF(sc
, RT2870_DEBUG_EEPROM
,
214 "%s: EEPROM RSSI offsets 5GHz=%d/%d/%d\n",
215 device_get_nameunit(sc
->dev
),
216 sc
->rssi_off_5ghz
[0], sc
->rssi_off_5ghz
[1], sc
->rssi_off_5ghz
[2]);
218 /* read Tx power settings for 2GHz channels */
220 for (i
= 0; i
< 14; i
+= 2)
222 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_TXPOW1_2GHZ_BASE
+ i
/ 2);
224 sc
->txpow1
[i
+ 0] = (int8_t) (val
& 0xff);
225 sc
->txpow1
[i
+ 1] = (int8_t) (val
>> 8);
227 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_TXPOW2_2GHZ_BASE
+ i
/ 2);
229 sc
->txpow2
[i
+ 0] = (int8_t) (val
& 0xff);
230 sc
->txpow2
[i
+ 1] = (int8_t) (val
>> 8);
233 /* read Tx power settings for 5GHz channels */
235 for (; i
< RT2870_SOFTC_TXPOW_COUNT
; i
+= 2)
237 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_TXPOW1_5GHZ_BASE
+ i
/ 2);
239 sc
->txpow1
[i
+ 0] = (int8_t) (val
& 0xff);
240 sc
->txpow1
[i
+ 1] = (int8_t) (val
>> 8);
242 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_TXPOW2_5GHZ_BASE
+ i
/ 2);
244 sc
->txpow2
[i
+ 0] = (int8_t) (val
& 0xff);
245 sc
->txpow2
[i
+ 1] = (int8_t) (val
>> 8);
248 /* fix broken Tx power settings */
250 for (i
= 0; i
< 14; i
++)
252 if (sc
->txpow1
[i
] < RT2870_EEPROM_TXPOW_2GHZ_MIN
||
253 sc
->txpow1
[i
] > RT2870_EEPROM_TXPOW_2GHZ_MAX
)
255 printf("%s: invalid EEPROM Tx power1 #%d (2GHz): 0x%02x\n",
256 device_get_nameunit(sc
->dev
), i
, sc
->txpow1
[i
]);
258 sc
->txpow1
[i
] = RT2870_EEPROM_TXPOW_2GHZ_DEFAULT
;
261 if (sc
->txpow2
[i
] < RT2870_EEPROM_TXPOW_2GHZ_MIN
||
262 sc
->txpow2
[i
] > RT2870_EEPROM_TXPOW_2GHZ_MAX
)
264 printf("%s: invalid EEPROM Tx power2 #%d (2GHz): 0x%02x\n",
265 device_get_nameunit(sc
->dev
), i
, sc
->txpow2
[i
]);
267 sc
->txpow2
[i
] = RT2870_EEPROM_TXPOW_2GHZ_DEFAULT
;
271 for (; i
< RT2870_SOFTC_TXPOW_COUNT
; i
++)
273 if (sc
->txpow1
[i
] < RT2870_EEPROM_TXPOW_5GHZ_MIN
||
274 sc
->txpow1
[i
] > RT2870_EEPROM_TXPOW_5GHZ_MAX
)
276 printf("%s: invalid EEPROM Tx power1 #%d (5GHz): 0x%02x\n",
277 device_get_nameunit(sc
->dev
), i
, sc
->txpow1
[i
]);
279 sc
->txpow1
[i
] = RT2870_EEPROM_TXPOW_5GHZ_DEFAULT
;
282 if (sc
->txpow2
[i
] < RT2870_EEPROM_TXPOW_5GHZ_MIN
||
283 sc
->txpow2
[i
] > RT2870_EEPROM_TXPOW_5GHZ_MAX
)
285 printf("%s: invalid EEPROM Tx power2 #%d (5GHz): 0x%02x\n",
286 device_get_nameunit(sc
->dev
), i
, sc
->txpow2
[i
]);
288 sc
->txpow2
[i
] = RT2870_EEPROM_TXPOW_5GHZ_DEFAULT
;
292 /* read Tx power per rate deltas */
294 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_TXPOW_RATE_DELTA
);
296 sc
->txpow_rate_delta_2ghz
= 0;
297 sc
->txpow_rate_delta_5ghz
= 0;
299 if ((val
& 0xff) != 0xff)
302 sc
->txpow_rate_delta_2ghz
= (val
& 0xf);
305 sc
->txpow_rate_delta_2ghz
= -sc
->txpow_rate_delta_2ghz
;
310 if ((val
& 0xff) != 0xff)
313 sc
->txpow_rate_delta_5ghz
= (val
& 0xf);
316 sc
->txpow_rate_delta_5ghz
= -sc
->txpow_rate_delta_5ghz
;
319 RT2870_DPRINTF(sc
, RT2870_DEBUG_EEPROM
,
320 "%s: EEPROM Tx power per rate deltas=%d(2MHz), %d(5MHz)\n",
321 device_get_nameunit(sc
->dev
),
322 sc
->txpow_rate_delta_2ghz
, sc
->txpow_rate_delta_5ghz
);
324 /* read Tx power per rate */
326 for (i
= 0; i
< RT2870_SOFTC_TXPOW_RATE_COUNT
; i
++)
328 rt2870_io_eeprom_read_multi(sc
, RT2870_EEPROM_TXPOW_RATE_BASE
+ i
* sizeof(uint32_t),
329 &tmp
, sizeof(uint32_t));
331 sc
->txpow_rate_20mhz
[i
] = tmp
;
332 sc
->txpow_rate_40mhz_2ghz
[i
] =
333 rt2870_read_eeprom_txpow_rate_add_delta(tmp
, sc
->txpow_rate_delta_2ghz
);
334 sc
->txpow_rate_40mhz_5ghz
[i
] =
335 rt2870_read_eeprom_txpow_rate_add_delta(tmp
, sc
->txpow_rate_delta_5ghz
);
337 RT2870_DPRINTF(sc
, RT2870_DEBUG_EEPROM
,
338 "%s: EEPROM Tx power per rate #%d=0x%08x(20MHz), 0x%08x(40MHz/2GHz), 0x%08x(40MHz/5GHz)\n",
339 device_get_nameunit(sc
->dev
), i
,
340 sc
->txpow_rate_20mhz
[i
], sc
->txpow_rate_40mhz_2ghz
[i
], sc
->txpow_rate_40mhz_5ghz
[i
]);
344 sc
->tx_agc_cntl_2ghz
= sc
->tx_agc_cntl_5ghz
= 1;
346 /* read factory-calibrated samples for temperature compensation */
348 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_TSSI_2GHZ_BASE
);
350 sc
->tssi_2ghz
[0] = (val
& 0xff); /* [-4] */
351 sc
->tssi_2ghz
[1] = (val
>> 8); /* [-3] */
353 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_TSSI_2GHZ_BASE
+ sizeof(uint16_t));
355 sc
->tssi_2ghz
[2] = (val
& 0xff); /* [-2] */
356 sc
->tssi_2ghz
[3] = (val
>> 8); /* [-1] */
358 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_TSSI_2GHZ_BASE
+ 2 * sizeof(uint16_t));
360 sc
->tssi_2ghz
[4] = (val
& 0xff); /* [0] */
361 sc
->tssi_2ghz
[5] = (val
>> 8); /* [+1] */
363 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_TSSI_2GHZ_BASE
+ 3 * sizeof(uint16_t));
365 sc
->tssi_2ghz
[6] = (val
& 0xff); /* [+2] */
366 sc
->tssi_2ghz
[7] = (val
>> 8); /* [+3] */
368 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_TSSI_2GHZ_BASE
+ 4 * sizeof(uint16_t));
370 sc
->tssi_2ghz
[8] = (val
& 0xff); /* [+4] */
371 sc
->tssi_step_2ghz
= (val
>> 8);
373 if (sc
->tssi_2ghz
[4] == 0xff)
374 sc
->tx_agc_cntl_2ghz
= 0;
376 RT2870_DPRINTF(sc
, RT2870_DEBUG_EEPROM
,
377 "%s: EEPROM TSSI 2GHz: 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, "
378 "0x%02x, 0x%02x, step=%d\n",
379 device_get_nameunit(sc
->dev
),
380 sc
->tssi_2ghz
[0], sc
->tssi_2ghz
[1], sc
->tssi_2ghz
[2],
381 sc
->tssi_2ghz
[3], sc
->tssi_2ghz
[4], sc
->tssi_2ghz
[5],
382 sc
->tssi_2ghz
[6], sc
->tssi_2ghz
[7], sc
->tssi_2ghz
[8],
385 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_TSSI_5GHZ_BASE
);
387 sc
->tssi_5ghz
[0] = (val
& 0xff); /* [-4] */
388 sc
->tssi_5ghz
[1] = (val
>> 8); /* [-3] */
390 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_TSSI_5GHZ_BASE
+ sizeof(uint16_t));
392 sc
->tssi_5ghz
[2] = (val
& 0xff); /* [-2] */
393 sc
->tssi_5ghz
[3] = (val
>> 8); /* [-1] */
395 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_TSSI_5GHZ_BASE
+ 2 * sizeof(uint16_t));
397 sc
->tssi_5ghz
[4] = (val
& 0xff); /* [0] */
398 sc
->tssi_5ghz
[5] = (val
>> 8); /* [+1] */
400 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_TSSI_5GHZ_BASE
+ 3 * sizeof(uint16_t));
402 sc
->tssi_5ghz
[6] = (val
& 0xff); /* [+2] */
403 sc
->tssi_5ghz
[7] = (val
>> 8); /* [+3] */
405 val
= rt2870_io_eeprom_read(sc
, RT2870_EEPROM_TSSI_5GHZ_BASE
+ 4 * sizeof(uint16_t));
407 sc
->tssi_5ghz
[8] = (val
& 0xff); /* [+4] */
408 sc
->tssi_step_5ghz
= (val
>> 8);
410 if (sc
->tssi_5ghz
[4] == 0xff)
411 sc
->tx_agc_cntl_5ghz
= 0;
413 RT2870_DPRINTF(sc
, RT2870_DEBUG_EEPROM
,
414 "%s: EEPROM TSSI 5GHz: 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, "
415 "0x%02x, 0x%02x, step=%d\n",
416 device_get_nameunit(sc
->dev
),
417 sc
->tssi_5ghz
[0], sc
->tssi_5ghz
[1], sc
->tssi_5ghz
[2],
418 sc
->tssi_5ghz
[3], sc
->tssi_5ghz
[4], sc
->tssi_5ghz
[5],
419 sc
->tssi_5ghz
[6], sc
->tssi_5ghz
[7], sc
->tssi_5ghz
[8],
422 /* read default BBP settings */
424 rt2870_io_eeprom_read_multi(sc
, RT2870_EEPROM_BBP_BASE
,
425 sc
->bbp_eeprom
, RT2870_SOFTC_BBP_EEPROM_COUNT
* sizeof(uint16_t));
429 * rt2870_read_eeprom_txpow_rate_add_delta
431 uint32_t rt2870_read_eeprom_txpow_rate_add_delta(uint32_t txpow_rate
,
437 for (i
= 0; i
< 8; i
++)
439 b4
= txpow_rate
& 0xf;
447 txpow_rate
= (txpow_rate
>> 4) | (b4
<< 28);