aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath5k/eeprom.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath5k/eeprom.c')
-rw-r--r--drivers/net/wireless/ath5k/eeprom.c466
1 files changed, 466 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath5k/eeprom.c b/drivers/net/wireless/ath5k/eeprom.c
new file mode 100644
index 000000000000..a883839b6a9f
--- /dev/null
+++ b/drivers/net/wireless/ath5k/eeprom.c
@@ -0,0 +1,466 @@
1/*
2 * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org>
3 * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 *
17 */
18
19/*************************************\
20* EEPROM access functions and helpers *
21\*************************************/
22
23#include "ath5k.h"
24#include "reg.h"
25#include "debug.h"
26#include "base.h"
27
28/*
29 * Read from eeprom
30 */
31static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
32{
33 u32 status, timeout;
34
35 ATH5K_TRACE(ah->ah_sc);
36 /*
37 * Initialize EEPROM access
38 */
39 if (ah->ah_version == AR5K_AR5210) {
40 AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE);
41 (void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset));
42 } else {
43 ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE);
44 AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
45 AR5K_EEPROM_CMD_READ);
46 }
47
48 for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) {
49 status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS);
50 if (status & AR5K_EEPROM_STAT_RDDONE) {
51 if (status & AR5K_EEPROM_STAT_RDERR)
52 return -EIO;
53 *data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) &
54 0xffff);
55 return 0;
56 }
57 udelay(15);
58 }
59
60 return -ETIMEDOUT;
61}
62
63/*
64 * Translate binary channel representation in EEPROM to frequency
65 */
66static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin,
67 unsigned int mode)
68{
69 u16 val;
70
71 if (bin == AR5K_EEPROM_CHANNEL_DIS)
72 return bin;
73
74 if (mode == AR5K_EEPROM_MODE_11A) {
75 if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
76 val = (5 * bin) + 4800;
77 else
78 val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 :
79 (bin * 10) + 5100;
80 } else {
81 if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2)
82 val = bin + 2300;
83 else
84 val = bin + 2400;
85 }
86
87 return val;
88}
89
90/*
91 * Read antenna infos from eeprom
92 */
93static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset,
94 unsigned int mode)
95{
96 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
97 u32 o = *offset;
98 u16 val;
99 int ret, i = 0;
100
101 AR5K_EEPROM_READ(o++, val);
102 ee->ee_switch_settling[mode] = (val >> 8) & 0x7f;
103 ee->ee_ant_tx_rx[mode] = (val >> 2) & 0x3f;
104 ee->ee_ant_control[mode][i] = (val << 4) & 0x3f;
105
106 AR5K_EEPROM_READ(o++, val);
107 ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf;
108 ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f;
109 ee->ee_ant_control[mode][i++] = val & 0x3f;
110
111 AR5K_EEPROM_READ(o++, val);
112 ee->ee_ant_control[mode][i++] = (val >> 10) & 0x3f;
113 ee->ee_ant_control[mode][i++] = (val >> 4) & 0x3f;
114 ee->ee_ant_control[mode][i] = (val << 2) & 0x3f;
115
116 AR5K_EEPROM_READ(o++, val);
117 ee->ee_ant_control[mode][i++] |= (val >> 14) & 0x3;
118 ee->ee_ant_control[mode][i++] = (val >> 8) & 0x3f;
119 ee->ee_ant_control[mode][i++] = (val >> 2) & 0x3f;
120 ee->ee_ant_control[mode][i] = (val << 4) & 0x3f;
121
122 AR5K_EEPROM_READ(o++, val);
123 ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf;
124 ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f;
125 ee->ee_ant_control[mode][i++] = val & 0x3f;
126
127 /* Get antenna modes */
128 ah->ah_antenna[mode][0] =
129 (ee->ee_ant_control[mode][0] << 4) | 0x1;
130 ah->ah_antenna[mode][AR5K_ANT_FIXED_A] =
131 ee->ee_ant_control[mode][1] |
132 (ee->ee_ant_control[mode][2] << 6) |
133 (ee->ee_ant_control[mode][3] << 12) |
134 (ee->ee_ant_control[mode][4] << 18) |
135 (ee->ee_ant_control[mode][5] << 24);
136 ah->ah_antenna[mode][AR5K_ANT_FIXED_B] =
137 ee->ee_ant_control[mode][6] |
138 (ee->ee_ant_control[mode][7] << 6) |
139 (ee->ee_ant_control[mode][8] << 12) |
140 (ee->ee_ant_control[mode][9] << 18) |
141 (ee->ee_ant_control[mode][10] << 24);
142
143 /* return new offset */
144 *offset = o;
145
146 return 0;
147}
148
149/*
150 * Read supported modes from eeprom
151 */
152static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset,
153 unsigned int mode)
154{
155 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
156 u32 o = *offset;
157 u16 val;
158 int ret;
159
160 AR5K_EEPROM_READ(o++, val);
161 ee->ee_tx_end2xlna_enable[mode] = (val >> 8) & 0xff;
162 ee->ee_thr_62[mode] = val & 0xff;
163
164 if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
165 ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28;
166
167 AR5K_EEPROM_READ(o++, val);
168 ee->ee_tx_end2xpa_disable[mode] = (val >> 8) & 0xff;
169 ee->ee_tx_frm2xpa_enable[mode] = val & 0xff;
170
171 AR5K_EEPROM_READ(o++, val);
172 ee->ee_pga_desired_size[mode] = (val >> 8) & 0xff;
173
174 if ((val & 0xff) & 0x80)
175 ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1);
176 else
177 ee->ee_noise_floor_thr[mode] = val & 0xff;
178
179 if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2)
180 ee->ee_noise_floor_thr[mode] =
181 mode == AR5K_EEPROM_MODE_11A ? -54 : -1;
182
183 AR5K_EEPROM_READ(o++, val);
184 ee->ee_xlna_gain[mode] = (val >> 5) & 0xff;
185 ee->ee_x_gain[mode] = (val >> 1) & 0xf;
186 ee->ee_xpd[mode] = val & 0x1;
187
188 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0)
189 ee->ee_fixed_bias[mode] = (val >> 13) & 0x1;
190
191 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) {
192 AR5K_EEPROM_READ(o++, val);
193 ee->ee_false_detect[mode] = (val >> 6) & 0x7f;
194
195 if (mode == AR5K_EEPROM_MODE_11A)
196 ee->ee_xr_power[mode] = val & 0x3f;
197 else {
198 ee->ee_ob[mode][0] = val & 0x7;
199 ee->ee_db[mode][0] = (val >> 3) & 0x7;
200 }
201 }
202
203 if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_4) {
204 ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN;
205 ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA;
206 } else {
207 ee->ee_i_gain[mode] = (val >> 13) & 0x7;
208
209 AR5K_EEPROM_READ(o++, val);
210 ee->ee_i_gain[mode] |= (val << 3) & 0x38;
211
212 if (mode == AR5K_EEPROM_MODE_11G)
213 ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff;
214 }
215
216 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 &&
217 mode == AR5K_EEPROM_MODE_11A) {
218 ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
219 ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
220 }
221
222 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6 &&
223 mode == AR5K_EEPROM_MODE_11G)
224 ee->ee_scaled_cck_delta = (val >> 11) & 0x1f;
225
226 /* return new offset */
227 *offset = o;
228
229 return 0;
230}
231
232/*
233 * Initialize eeprom & capabilities structs
234 */
235int ath5k_eeprom_init(struct ath5k_hw *ah)
236{
237 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
238 unsigned int mode, i;
239 int ret;
240 u32 offset;
241 u16 val;
242
243 /* Initial TX thermal adjustment values */
244 ee->ee_tx_clip = 4;
245 ee->ee_pwd_84 = ee->ee_pwd_90 = 1;
246 ee->ee_gain_select = 1;
247
248 /*
249 * Read values from EEPROM and store them in the capability structure
250 */
251 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic);
252 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect);
253 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain);
254 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version);
255 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header);
256
257 /* Return if we have an old EEPROM */
258 if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
259 return 0;
260
261#ifdef notyet
262 /*
263 * Validate the checksum of the EEPROM date. There are some
264 * devices with invalid EEPROMs.
265 */
266 for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
267 AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
268 cksum ^= val;
269 }
270 if (cksum != AR5K_EEPROM_INFO_CKSUM) {
271 ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum);
272 return -EIO;
273 }
274#endif
275
276 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),
277 ee_ant_gain);
278
279 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
280 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0);
281 AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1);
282 }
283
284 if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) {
285 AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val);
286 ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7;
287 ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7;
288
289 AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val);
290 ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7;
291 ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7;
292 }
293
294 /*
295 * Get conformance test limit values
296 */
297 offset = AR5K_EEPROM_CTL(ah->ah_ee_version);
298 ee->ee_ctls = AR5K_EEPROM_N_CTLS(ah->ah_ee_version);
299
300 for (i = 0; i < ee->ee_ctls; i++) {
301 AR5K_EEPROM_READ(offset++, val);
302 ee->ee_ctl[i] = (val >> 8) & 0xff;
303 ee->ee_ctl[i + 1] = val & 0xff;
304 }
305
306 /*
307 * Get values for 802.11a (5GHz)
308 */
309 mode = AR5K_EEPROM_MODE_11A;
310
311 ee->ee_turbo_max_power[mode] =
312 AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header);
313
314 offset = AR5K_EEPROM_MODES_11A(ah->ah_ee_version);
315
316 ret = ath5k_eeprom_read_ants(ah, &offset, mode);
317 if (ret)
318 return ret;
319
320 AR5K_EEPROM_READ(offset++, val);
321 ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff);
322 ee->ee_ob[mode][3] = (val >> 5) & 0x7;
323 ee->ee_db[mode][3] = (val >> 2) & 0x7;
324 ee->ee_ob[mode][2] = (val << 1) & 0x7;
325
326 AR5K_EEPROM_READ(offset++, val);
327 ee->ee_ob[mode][2] |= (val >> 15) & 0x1;
328 ee->ee_db[mode][2] = (val >> 12) & 0x7;
329 ee->ee_ob[mode][1] = (val >> 9) & 0x7;
330 ee->ee_db[mode][1] = (val >> 6) & 0x7;
331 ee->ee_ob[mode][0] = (val >> 3) & 0x7;
332 ee->ee_db[mode][0] = val & 0x7;
333
334 ret = ath5k_eeprom_read_modes(ah, &offset, mode);
335 if (ret)
336 return ret;
337
338 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) {
339 AR5K_EEPROM_READ(offset++, val);
340 ee->ee_margin_tx_rx[mode] = val & 0x3f;
341 }
342
343 /*
344 * Get values for 802.11b (2.4GHz)
345 */
346 mode = AR5K_EEPROM_MODE_11B;
347 offset = AR5K_EEPROM_MODES_11B(ah->ah_ee_version);
348
349 ret = ath5k_eeprom_read_ants(ah, &offset, mode);
350 if (ret)
351 return ret;
352
353 AR5K_EEPROM_READ(offset++, val);
354 ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff);
355 ee->ee_ob[mode][1] = (val >> 4) & 0x7;
356 ee->ee_db[mode][1] = val & 0x7;
357
358 ret = ath5k_eeprom_read_modes(ah, &offset, mode);
359 if (ret)
360 return ret;
361
362 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
363 AR5K_EEPROM_READ(offset++, val);
364 ee->ee_cal_pier[mode][0] =
365 ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
366 ee->ee_cal_pier[mode][1] =
367 ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
368
369 AR5K_EEPROM_READ(offset++, val);
370 ee->ee_cal_pier[mode][2] =
371 ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
372 }
373
374 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
375 ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
376
377 /*
378 * Get values for 802.11g (2.4GHz)
379 */
380 mode = AR5K_EEPROM_MODE_11G;
381 offset = AR5K_EEPROM_MODES_11G(ah->ah_ee_version);
382
383 ret = ath5k_eeprom_read_ants(ah, &offset, mode);
384 if (ret)
385 return ret;
386
387 AR5K_EEPROM_READ(offset++, val);
388 ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff);
389 ee->ee_ob[mode][1] = (val >> 4) & 0x7;
390 ee->ee_db[mode][1] = val & 0x7;
391
392 ret = ath5k_eeprom_read_modes(ah, &offset, mode);
393 if (ret)
394 return ret;
395
396 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) {
397 AR5K_EEPROM_READ(offset++, val);
398 ee->ee_cal_pier[mode][0] =
399 ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
400 ee->ee_cal_pier[mode][1] =
401 ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode);
402
403 AR5K_EEPROM_READ(offset++, val);
404 ee->ee_turbo_max_power[mode] = val & 0x7f;
405 ee->ee_xr_power[mode] = (val >> 7) & 0x3f;
406
407 AR5K_EEPROM_READ(offset++, val);
408 ee->ee_cal_pier[mode][2] =
409 ath5k_eeprom_bin2freq(ah, val & 0xff, mode);
410
411 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1)
412 ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f;
413
414 AR5K_EEPROM_READ(offset++, val);
415 ee->ee_i_cal[mode] = (val >> 8) & 0x3f;
416 ee->ee_q_cal[mode] = (val >> 3) & 0x1f;
417
418 if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) {
419 AR5K_EEPROM_READ(offset++, val);
420 ee->ee_cck_ofdm_gain_delta = val & 0xff;
421 }
422 }
423
424 /*
425 * Read 5GHz EEPROM channels
426 */
427
428 return 0;
429}
430
431/*
432 * Read the MAC address from eeprom
433 */
434int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
435{
436 u8 mac_d[ETH_ALEN];
437 u32 total, offset;
438 u16 data;
439 int octet, ret;
440
441 memset(mac, 0, ETH_ALEN);
442 memset(mac_d, 0, ETH_ALEN);
443
444 ret = ath5k_hw_eeprom_read(ah, 0x20, &data);
445 if (ret)
446 return ret;
447
448 for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
449 ret = ath5k_hw_eeprom_read(ah, offset, &data);
450 if (ret)
451 return ret;
452
453 total += data;
454 mac_d[octet + 1] = data & 0xff;
455 mac_d[octet] = data >> 8;
456 octet += 2;
457 }
458
459 memcpy(mac, mac_d, ETH_ALEN);
460
461 if (!total || total == 3 * 0xffff)
462 return -EINVAL;
463
464 return 0;
465}
466