diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/eeprom.c')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/eeprom.c | 1769 |
1 files changed, 1769 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c new file mode 100644 index 000000000000..c0fb3b09ba45 --- /dev/null +++ b/drivers/net/wireless/ath/ath5k/eeprom.c | |||
@@ -0,0 +1,1769 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> | ||
3 | * Copyright (c) 2006-2009 Nick Kossifidis <mickflemm@gmail.com> | ||
4 | * Copyright (c) 2008-2009 Felix Fietkau <nbd@openwrt.org> | ||
5 | * | ||
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. | ||
9 | * | ||
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. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | /*************************************\ | ||
21 | * EEPROM access functions and helpers * | ||
22 | \*************************************/ | ||
23 | |||
24 | #include "ath5k.h" | ||
25 | #include "reg.h" | ||
26 | #include "debug.h" | ||
27 | #include "base.h" | ||
28 | |||
29 | /* | ||
30 | * Read from eeprom | ||
31 | */ | ||
32 | static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data) | ||
33 | { | ||
34 | u32 status, timeout; | ||
35 | |||
36 | ATH5K_TRACE(ah->ah_sc); | ||
37 | /* | ||
38 | * Initialize EEPROM access | ||
39 | */ | ||
40 | if (ah->ah_version == AR5K_AR5210) { | ||
41 | AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE); | ||
42 | (void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset)); | ||
43 | } else { | ||
44 | ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE); | ||
45 | AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD, | ||
46 | AR5K_EEPROM_CMD_READ); | ||
47 | } | ||
48 | |||
49 | for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) { | ||
50 | status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS); | ||
51 | if (status & AR5K_EEPROM_STAT_RDDONE) { | ||
52 | if (status & AR5K_EEPROM_STAT_RDERR) | ||
53 | return -EIO; | ||
54 | *data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) & | ||
55 | 0xffff); | ||
56 | return 0; | ||
57 | } | ||
58 | udelay(15); | ||
59 | } | ||
60 | |||
61 | return -ETIMEDOUT; | ||
62 | } | ||
63 | |||
64 | /* | ||
65 | * Translate binary channel representation in EEPROM to frequency | ||
66 | */ | ||
67 | static u16 ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee, u16 bin, | ||
68 | unsigned int mode) | ||
69 | { | ||
70 | u16 val; | ||
71 | |||
72 | if (bin == AR5K_EEPROM_CHANNEL_DIS) | ||
73 | return bin; | ||
74 | |||
75 | if (mode == AR5K_EEPROM_MODE_11A) { | ||
76 | if (ee->ee_version > AR5K_EEPROM_VERSION_3_2) | ||
77 | val = (5 * bin) + 4800; | ||
78 | else | ||
79 | val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 : | ||
80 | (bin * 10) + 5100; | ||
81 | } else { | ||
82 | if (ee->ee_version > AR5K_EEPROM_VERSION_3_2) | ||
83 | val = bin + 2300; | ||
84 | else | ||
85 | val = bin + 2400; | ||
86 | } | ||
87 | |||
88 | return val; | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * Initialize eeprom & capabilities structs | ||
93 | */ | ||
94 | static int | ||
95 | ath5k_eeprom_init_header(struct ath5k_hw *ah) | ||
96 | { | ||
97 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
98 | int ret; | ||
99 | u16 val; | ||
100 | |||
101 | /* | ||
102 | * Read values from EEPROM and store them in the capability structure | ||
103 | */ | ||
104 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic); | ||
105 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect); | ||
106 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain); | ||
107 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version); | ||
108 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header); | ||
109 | |||
110 | /* Return if we have an old EEPROM */ | ||
111 | if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0) | ||
112 | return 0; | ||
113 | |||
114 | #ifdef notyet | ||
115 | /* | ||
116 | * Validate the checksum of the EEPROM date. There are some | ||
117 | * devices with invalid EEPROMs. | ||
118 | */ | ||
119 | for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) { | ||
120 | AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val); | ||
121 | cksum ^= val; | ||
122 | } | ||
123 | if (cksum != AR5K_EEPROM_INFO_CKSUM) { | ||
124 | ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum); | ||
125 | return -EIO; | ||
126 | } | ||
127 | #endif | ||
128 | |||
129 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version), | ||
130 | ee_ant_gain); | ||
131 | |||
132 | if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { | ||
133 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0); | ||
134 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1); | ||
135 | |||
136 | /* XXX: Don't know which versions include these two */ | ||
137 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC2, ee_misc2); | ||
138 | |||
139 | if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) | ||
140 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC3, ee_misc3); | ||
141 | |||
142 | if (ee->ee_version >= AR5K_EEPROM_VERSION_5_0) { | ||
143 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC4, ee_misc4); | ||
144 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC5, ee_misc5); | ||
145 | AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC6, ee_misc6); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) { | ||
150 | AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val); | ||
151 | ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7; | ||
152 | ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7; | ||
153 | |||
154 | AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val); | ||
155 | ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7; | ||
156 | ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7; | ||
157 | } | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | |||
163 | /* | ||
164 | * Read antenna infos from eeprom | ||
165 | */ | ||
166 | static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset, | ||
167 | unsigned int mode) | ||
168 | { | ||
169 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
170 | u32 o = *offset; | ||
171 | u16 val; | ||
172 | int ret, i = 0; | ||
173 | |||
174 | AR5K_EEPROM_READ(o++, val); | ||
175 | ee->ee_switch_settling[mode] = (val >> 8) & 0x7f; | ||
176 | ee->ee_atn_tx_rx[mode] = (val >> 2) & 0x3f; | ||
177 | ee->ee_ant_control[mode][i] = (val << 4) & 0x3f; | ||
178 | |||
179 | AR5K_EEPROM_READ(o++, val); | ||
180 | ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf; | ||
181 | ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f; | ||
182 | ee->ee_ant_control[mode][i++] = val & 0x3f; | ||
183 | |||
184 | AR5K_EEPROM_READ(o++, val); | ||
185 | ee->ee_ant_control[mode][i++] = (val >> 10) & 0x3f; | ||
186 | ee->ee_ant_control[mode][i++] = (val >> 4) & 0x3f; | ||
187 | ee->ee_ant_control[mode][i] = (val << 2) & 0x3f; | ||
188 | |||
189 | AR5K_EEPROM_READ(o++, val); | ||
190 | ee->ee_ant_control[mode][i++] |= (val >> 14) & 0x3; | ||
191 | ee->ee_ant_control[mode][i++] = (val >> 8) & 0x3f; | ||
192 | ee->ee_ant_control[mode][i++] = (val >> 2) & 0x3f; | ||
193 | ee->ee_ant_control[mode][i] = (val << 4) & 0x3f; | ||
194 | |||
195 | AR5K_EEPROM_READ(o++, val); | ||
196 | ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf; | ||
197 | ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f; | ||
198 | ee->ee_ant_control[mode][i++] = val & 0x3f; | ||
199 | |||
200 | /* Get antenna modes */ | ||
201 | ah->ah_antenna[mode][0] = | ||
202 | (ee->ee_ant_control[mode][0] << 4); | ||
203 | ah->ah_antenna[mode][AR5K_ANT_FIXED_A] = | ||
204 | ee->ee_ant_control[mode][1] | | ||
205 | (ee->ee_ant_control[mode][2] << 6) | | ||
206 | (ee->ee_ant_control[mode][3] << 12) | | ||
207 | (ee->ee_ant_control[mode][4] << 18) | | ||
208 | (ee->ee_ant_control[mode][5] << 24); | ||
209 | ah->ah_antenna[mode][AR5K_ANT_FIXED_B] = | ||
210 | ee->ee_ant_control[mode][6] | | ||
211 | (ee->ee_ant_control[mode][7] << 6) | | ||
212 | (ee->ee_ant_control[mode][8] << 12) | | ||
213 | (ee->ee_ant_control[mode][9] << 18) | | ||
214 | (ee->ee_ant_control[mode][10] << 24); | ||
215 | |||
216 | /* return new offset */ | ||
217 | *offset = o; | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | * Read supported modes and some mode-specific calibration data | ||
224 | * from eeprom | ||
225 | */ | ||
226 | static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, | ||
227 | unsigned int mode) | ||
228 | { | ||
229 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
230 | u32 o = *offset; | ||
231 | u16 val; | ||
232 | int ret; | ||
233 | |||
234 | ee->ee_n_piers[mode] = 0; | ||
235 | AR5K_EEPROM_READ(o++, val); | ||
236 | ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); | ||
237 | switch(mode) { | ||
238 | case AR5K_EEPROM_MODE_11A: | ||
239 | ee->ee_ob[mode][3] = (val >> 5) & 0x7; | ||
240 | ee->ee_db[mode][3] = (val >> 2) & 0x7; | ||
241 | ee->ee_ob[mode][2] = (val << 1) & 0x7; | ||
242 | |||
243 | AR5K_EEPROM_READ(o++, val); | ||
244 | ee->ee_ob[mode][2] |= (val >> 15) & 0x1; | ||
245 | ee->ee_db[mode][2] = (val >> 12) & 0x7; | ||
246 | ee->ee_ob[mode][1] = (val >> 9) & 0x7; | ||
247 | ee->ee_db[mode][1] = (val >> 6) & 0x7; | ||
248 | ee->ee_ob[mode][0] = (val >> 3) & 0x7; | ||
249 | ee->ee_db[mode][0] = val & 0x7; | ||
250 | break; | ||
251 | case AR5K_EEPROM_MODE_11G: | ||
252 | case AR5K_EEPROM_MODE_11B: | ||
253 | ee->ee_ob[mode][1] = (val >> 4) & 0x7; | ||
254 | ee->ee_db[mode][1] = val & 0x7; | ||
255 | break; | ||
256 | } | ||
257 | |||
258 | AR5K_EEPROM_READ(o++, val); | ||
259 | ee->ee_tx_end2xlna_enable[mode] = (val >> 8) & 0xff; | ||
260 | ee->ee_thr_62[mode] = val & 0xff; | ||
261 | |||
262 | if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) | ||
263 | ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28; | ||
264 | |||
265 | AR5K_EEPROM_READ(o++, val); | ||
266 | ee->ee_tx_end2xpa_disable[mode] = (val >> 8) & 0xff; | ||
267 | ee->ee_tx_frm2xpa_enable[mode] = val & 0xff; | ||
268 | |||
269 | AR5K_EEPROM_READ(o++, val); | ||
270 | ee->ee_pga_desired_size[mode] = (val >> 8) & 0xff; | ||
271 | |||
272 | if ((val & 0xff) & 0x80) | ||
273 | ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1); | ||
274 | else | ||
275 | ee->ee_noise_floor_thr[mode] = val & 0xff; | ||
276 | |||
277 | if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) | ||
278 | ee->ee_noise_floor_thr[mode] = | ||
279 | mode == AR5K_EEPROM_MODE_11A ? -54 : -1; | ||
280 | |||
281 | AR5K_EEPROM_READ(o++, val); | ||
282 | ee->ee_xlna_gain[mode] = (val >> 5) & 0xff; | ||
283 | ee->ee_x_gain[mode] = (val >> 1) & 0xf; | ||
284 | ee->ee_xpd[mode] = val & 0x1; | ||
285 | |||
286 | if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) | ||
287 | ee->ee_fixed_bias[mode] = (val >> 13) & 0x1; | ||
288 | |||
289 | if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) { | ||
290 | AR5K_EEPROM_READ(o++, val); | ||
291 | ee->ee_false_detect[mode] = (val >> 6) & 0x7f; | ||
292 | |||
293 | if (mode == AR5K_EEPROM_MODE_11A) | ||
294 | ee->ee_xr_power[mode] = val & 0x3f; | ||
295 | else { | ||
296 | ee->ee_ob[mode][0] = val & 0x7; | ||
297 | ee->ee_db[mode][0] = (val >> 3) & 0x7; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_4) { | ||
302 | ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN; | ||
303 | ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA; | ||
304 | } else { | ||
305 | ee->ee_i_gain[mode] = (val >> 13) & 0x7; | ||
306 | |||
307 | AR5K_EEPROM_READ(o++, val); | ||
308 | ee->ee_i_gain[mode] |= (val << 3) & 0x38; | ||
309 | |||
310 | if (mode == AR5K_EEPROM_MODE_11G) { | ||
311 | ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff; | ||
312 | if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6) | ||
313 | ee->ee_scaled_cck_delta = (val >> 11) & 0x1f; | ||
314 | } | ||
315 | } | ||
316 | |||
317 | if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 && | ||
318 | mode == AR5K_EEPROM_MODE_11A) { | ||
319 | ee->ee_i_cal[mode] = (val >> 8) & 0x3f; | ||
320 | ee->ee_q_cal[mode] = (val >> 3) & 0x1f; | ||
321 | } | ||
322 | |||
323 | if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_0) | ||
324 | goto done; | ||
325 | |||
326 | /* Note: >= v5 have bg freq piers on another location | ||
327 | * so these freq piers are ignored for >= v5 (should be 0xff | ||
328 | * anyway) */ | ||
329 | switch(mode) { | ||
330 | case AR5K_EEPROM_MODE_11A: | ||
331 | if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1) | ||
332 | break; | ||
333 | |||
334 | AR5K_EEPROM_READ(o++, val); | ||
335 | ee->ee_margin_tx_rx[mode] = val & 0x3f; | ||
336 | break; | ||
337 | case AR5K_EEPROM_MODE_11B: | ||
338 | AR5K_EEPROM_READ(o++, val); | ||
339 | |||
340 | ee->ee_pwr_cal_b[0].freq = | ||
341 | ath5k_eeprom_bin2freq(ee, val & 0xff, mode); | ||
342 | if (ee->ee_pwr_cal_b[0].freq != AR5K_EEPROM_CHANNEL_DIS) | ||
343 | ee->ee_n_piers[mode]++; | ||
344 | |||
345 | ee->ee_pwr_cal_b[1].freq = | ||
346 | ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode); | ||
347 | if (ee->ee_pwr_cal_b[1].freq != AR5K_EEPROM_CHANNEL_DIS) | ||
348 | ee->ee_n_piers[mode]++; | ||
349 | |||
350 | AR5K_EEPROM_READ(o++, val); | ||
351 | ee->ee_pwr_cal_b[2].freq = | ||
352 | ath5k_eeprom_bin2freq(ee, val & 0xff, mode); | ||
353 | if (ee->ee_pwr_cal_b[2].freq != AR5K_EEPROM_CHANNEL_DIS) | ||
354 | ee->ee_n_piers[mode]++; | ||
355 | |||
356 | if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) | ||
357 | ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; | ||
358 | break; | ||
359 | case AR5K_EEPROM_MODE_11G: | ||
360 | AR5K_EEPROM_READ(o++, val); | ||
361 | |||
362 | ee->ee_pwr_cal_g[0].freq = | ||
363 | ath5k_eeprom_bin2freq(ee, val & 0xff, mode); | ||
364 | if (ee->ee_pwr_cal_g[0].freq != AR5K_EEPROM_CHANNEL_DIS) | ||
365 | ee->ee_n_piers[mode]++; | ||
366 | |||
367 | ee->ee_pwr_cal_g[1].freq = | ||
368 | ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode); | ||
369 | if (ee->ee_pwr_cal_g[1].freq != AR5K_EEPROM_CHANNEL_DIS) | ||
370 | ee->ee_n_piers[mode]++; | ||
371 | |||
372 | AR5K_EEPROM_READ(o++, val); | ||
373 | ee->ee_turbo_max_power[mode] = val & 0x7f; | ||
374 | ee->ee_xr_power[mode] = (val >> 7) & 0x3f; | ||
375 | |||
376 | AR5K_EEPROM_READ(o++, val); | ||
377 | ee->ee_pwr_cal_g[2].freq = | ||
378 | ath5k_eeprom_bin2freq(ee, val & 0xff, mode); | ||
379 | if (ee->ee_pwr_cal_g[2].freq != AR5K_EEPROM_CHANNEL_DIS) | ||
380 | ee->ee_n_piers[mode]++; | ||
381 | |||
382 | if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) | ||
383 | ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; | ||
384 | |||
385 | AR5K_EEPROM_READ(o++, val); | ||
386 | ee->ee_i_cal[mode] = (val >> 8) & 0x3f; | ||
387 | ee->ee_q_cal[mode] = (val >> 3) & 0x1f; | ||
388 | |||
389 | if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) { | ||
390 | AR5K_EEPROM_READ(o++, val); | ||
391 | ee->ee_cck_ofdm_gain_delta = val & 0xff; | ||
392 | } | ||
393 | break; | ||
394 | } | ||
395 | |||
396 | done: | ||
397 | /* return new offset */ | ||
398 | *offset = o; | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | /* | ||
404 | * Read turbo mode information on newer EEPROM versions | ||
405 | */ | ||
406 | static int | ||
407 | ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah, | ||
408 | u32 *offset, unsigned int mode) | ||
409 | { | ||
410 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
411 | u32 o = *offset; | ||
412 | u16 val; | ||
413 | int ret; | ||
414 | |||
415 | if (ee->ee_version < AR5K_EEPROM_VERSION_5_0) | ||
416 | return 0; | ||
417 | |||
418 | switch (mode){ | ||
419 | case AR5K_EEPROM_MODE_11A: | ||
420 | ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f; | ||
421 | |||
422 | ee->ee_atn_tx_rx_turbo[mode] = (val >> 13) & 0x7; | ||
423 | AR5K_EEPROM_READ(o++, val); | ||
424 | ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x7) << 3; | ||
425 | ee->ee_margin_tx_rx_turbo[mode] = (val >> 3) & 0x3f; | ||
426 | |||
427 | ee->ee_adc_desired_size_turbo[mode] = (val >> 9) & 0x7f; | ||
428 | AR5K_EEPROM_READ(o++, val); | ||
429 | ee->ee_adc_desired_size_turbo[mode] |= (val & 0x1) << 7; | ||
430 | ee->ee_pga_desired_size_turbo[mode] = (val >> 1) & 0xff; | ||
431 | |||
432 | if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >=2) | ||
433 | ee->ee_pd_gain_overlap = (val >> 9) & 0xf; | ||
434 | break; | ||
435 | case AR5K_EEPROM_MODE_11G: | ||
436 | ee->ee_switch_settling_turbo[mode] = (val >> 8) & 0x7f; | ||
437 | |||
438 | ee->ee_atn_tx_rx_turbo[mode] = (val >> 15) & 0x7; | ||
439 | AR5K_EEPROM_READ(o++, val); | ||
440 | ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x1f) << 1; | ||
441 | ee->ee_margin_tx_rx_turbo[mode] = (val >> 5) & 0x3f; | ||
442 | |||
443 | ee->ee_adc_desired_size_turbo[mode] = (val >> 11) & 0x7f; | ||
444 | AR5K_EEPROM_READ(o++, val); | ||
445 | ee->ee_adc_desired_size_turbo[mode] |= (val & 0x7) << 5; | ||
446 | ee->ee_pga_desired_size_turbo[mode] = (val >> 3) & 0xff; | ||
447 | break; | ||
448 | } | ||
449 | |||
450 | /* return new offset */ | ||
451 | *offset = o; | ||
452 | |||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | /* Read mode-specific data (except power calibration data) */ | ||
457 | static int | ||
458 | ath5k_eeprom_init_modes(struct ath5k_hw *ah) | ||
459 | { | ||
460 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
461 | u32 mode_offset[3]; | ||
462 | unsigned int mode; | ||
463 | u32 offset; | ||
464 | int ret; | ||
465 | |||
466 | /* | ||
467 | * Get values for all modes | ||
468 | */ | ||
469 | mode_offset[AR5K_EEPROM_MODE_11A] = AR5K_EEPROM_MODES_11A(ah->ah_ee_version); | ||
470 | mode_offset[AR5K_EEPROM_MODE_11B] = AR5K_EEPROM_MODES_11B(ah->ah_ee_version); | ||
471 | mode_offset[AR5K_EEPROM_MODE_11G] = AR5K_EEPROM_MODES_11G(ah->ah_ee_version); | ||
472 | |||
473 | ee->ee_turbo_max_power[AR5K_EEPROM_MODE_11A] = | ||
474 | AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header); | ||
475 | |||
476 | for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) { | ||
477 | offset = mode_offset[mode]; | ||
478 | |||
479 | ret = ath5k_eeprom_read_ants(ah, &offset, mode); | ||
480 | if (ret) | ||
481 | return ret; | ||
482 | |||
483 | ret = ath5k_eeprom_read_modes(ah, &offset, mode); | ||
484 | if (ret) | ||
485 | return ret; | ||
486 | |||
487 | ret = ath5k_eeprom_read_turbo_modes(ah, &offset, mode); | ||
488 | if (ret) | ||
489 | return ret; | ||
490 | } | ||
491 | |||
492 | /* override for older eeprom versions for better performance */ | ||
493 | if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) { | ||
494 | ee->ee_thr_62[AR5K_EEPROM_MODE_11A] = 15; | ||
495 | ee->ee_thr_62[AR5K_EEPROM_MODE_11B] = 28; | ||
496 | ee->ee_thr_62[AR5K_EEPROM_MODE_11G] = 28; | ||
497 | } | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | /* Read the frequency piers for each mode (mostly used on newer eeproms with 0xff | ||
503 | * frequency mask) */ | ||
504 | static inline int | ||
505 | ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max, | ||
506 | struct ath5k_chan_pcal_info *pc, unsigned int mode) | ||
507 | { | ||
508 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
509 | int o = *offset; | ||
510 | int i = 0; | ||
511 | u8 freq1, freq2; | ||
512 | int ret; | ||
513 | u16 val; | ||
514 | |||
515 | ee->ee_n_piers[mode] = 0; | ||
516 | while(i < max) { | ||
517 | AR5K_EEPROM_READ(o++, val); | ||
518 | |||
519 | freq1 = val & 0xff; | ||
520 | if (!freq1) | ||
521 | break; | ||
522 | |||
523 | pc[i++].freq = ath5k_eeprom_bin2freq(ee, | ||
524 | freq1, mode); | ||
525 | ee->ee_n_piers[mode]++; | ||
526 | |||
527 | freq2 = (val >> 8) & 0xff; | ||
528 | if (!freq2) | ||
529 | break; | ||
530 | |||
531 | pc[i++].freq = ath5k_eeprom_bin2freq(ee, | ||
532 | freq2, mode); | ||
533 | ee->ee_n_piers[mode]++; | ||
534 | } | ||
535 | |||
536 | /* return new offset */ | ||
537 | *offset = o; | ||
538 | |||
539 | return 0; | ||
540 | } | ||
541 | |||
542 | /* Read frequency piers for 802.11a */ | ||
543 | static int | ||
544 | ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset) | ||
545 | { | ||
546 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
547 | struct ath5k_chan_pcal_info *pcal = ee->ee_pwr_cal_a; | ||
548 | int i, ret; | ||
549 | u16 val; | ||
550 | u8 mask; | ||
551 | |||
552 | if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) { | ||
553 | ath5k_eeprom_read_freq_list(ah, &offset, | ||
554 | AR5K_EEPROM_N_5GHZ_CHAN, pcal, | ||
555 | AR5K_EEPROM_MODE_11A); | ||
556 | } else { | ||
557 | mask = AR5K_EEPROM_FREQ_M(ah->ah_ee_version); | ||
558 | |||
559 | AR5K_EEPROM_READ(offset++, val); | ||
560 | pcal[0].freq = (val >> 9) & mask; | ||
561 | pcal[1].freq = (val >> 2) & mask; | ||
562 | pcal[2].freq = (val << 5) & mask; | ||
563 | |||
564 | AR5K_EEPROM_READ(offset++, val); | ||
565 | pcal[2].freq |= (val >> 11) & 0x1f; | ||
566 | pcal[3].freq = (val >> 4) & mask; | ||
567 | pcal[4].freq = (val << 3) & mask; | ||
568 | |||
569 | AR5K_EEPROM_READ(offset++, val); | ||
570 | pcal[4].freq |= (val >> 13) & 0x7; | ||
571 | pcal[5].freq = (val >> 6) & mask; | ||
572 | pcal[6].freq = (val << 1) & mask; | ||
573 | |||
574 | AR5K_EEPROM_READ(offset++, val); | ||
575 | pcal[6].freq |= (val >> 15) & 0x1; | ||
576 | pcal[7].freq = (val >> 8) & mask; | ||
577 | pcal[8].freq = (val >> 1) & mask; | ||
578 | pcal[9].freq = (val << 6) & mask; | ||
579 | |||
580 | AR5K_EEPROM_READ(offset++, val); | ||
581 | pcal[9].freq |= (val >> 10) & 0x3f; | ||
582 | |||
583 | /* Fixed number of piers */ | ||
584 | ee->ee_n_piers[AR5K_EEPROM_MODE_11A] = 10; | ||
585 | |||
586 | for (i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i++) { | ||
587 | pcal[i].freq = ath5k_eeprom_bin2freq(ee, | ||
588 | pcal[i].freq, AR5K_EEPROM_MODE_11A); | ||
589 | } | ||
590 | } | ||
591 | |||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | /* Read frequency piers for 802.11bg on eeprom versions >= 5 and eemap >= 2 */ | ||
596 | static inline int | ||
597 | ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset) | ||
598 | { | ||
599 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
600 | struct ath5k_chan_pcal_info *pcal; | ||
601 | |||
602 | switch(mode) { | ||
603 | case AR5K_EEPROM_MODE_11B: | ||
604 | pcal = ee->ee_pwr_cal_b; | ||
605 | break; | ||
606 | case AR5K_EEPROM_MODE_11G: | ||
607 | pcal = ee->ee_pwr_cal_g; | ||
608 | break; | ||
609 | default: | ||
610 | return -EINVAL; | ||
611 | } | ||
612 | |||
613 | ath5k_eeprom_read_freq_list(ah, &offset, | ||
614 | AR5K_EEPROM_N_2GHZ_CHAN_2413, pcal, | ||
615 | mode); | ||
616 | |||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | /* | ||
621 | * Read power calibration for RF5111 chips | ||
622 | * | ||
623 | * For RF5111 we have an XPD -eXternal Power Detector- curve | ||
624 | * for each calibrated channel. Each curve has 0,5dB Power steps | ||
625 | * on x axis and PCDAC steps (offsets) on y axis and looks like an | ||
626 | * exponential function. To recreate the curve we read 11 points | ||
627 | * here and interpolate later. | ||
628 | */ | ||
629 | |||
630 | /* Used to match PCDAC steps with power values on RF5111 chips | ||
631 | * (eeprom versions < 4). For RF5111 we have 11 pre-defined PCDAC | ||
632 | * steps that match with the power values we read from eeprom. On | ||
633 | * older eeprom versions (< 3.2) these steps are equaly spaced at | ||
634 | * 10% of the pcdac curve -until the curve reaches it's maximum- | ||
635 | * (11 steps from 0 to 100%) but on newer eeprom versions (>= 3.2) | ||
636 | * these 11 steps are spaced in a different way. This function returns | ||
637 | * the pcdac steps based on eeprom version and curve min/max so that we | ||
638 | * can have pcdac/pwr points. | ||
639 | */ | ||
640 | static inline void | ||
641 | ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp) | ||
642 | { | ||
643 | const static u16 intercepts3[] = | ||
644 | { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 }; | ||
645 | const static u16 intercepts3_2[] = | ||
646 | { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; | ||
647 | const u16 *ip; | ||
648 | int i; | ||
649 | |||
650 | if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2) | ||
651 | ip = intercepts3_2; | ||
652 | else | ||
653 | ip = intercepts3; | ||
654 | |||
655 | for (i = 0; i < ARRAY_SIZE(intercepts3); i++) | ||
656 | vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100; | ||
657 | } | ||
658 | |||
659 | /* Convert RF5111 specific data to generic raw data | ||
660 | * used by interpolation code */ | ||
661 | static int | ||
662 | ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode, | ||
663 | struct ath5k_chan_pcal_info *chinfo) | ||
664 | { | ||
665 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
666 | struct ath5k_chan_pcal_info_rf5111 *pcinfo; | ||
667 | struct ath5k_pdgain_info *pd; | ||
668 | u8 pier, point, idx; | ||
669 | u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; | ||
670 | |||
671 | /* Fill raw data for each calibration pier */ | ||
672 | for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { | ||
673 | |||
674 | pcinfo = &chinfo[pier].rf5111_info; | ||
675 | |||
676 | /* Allocate pd_curves for this cal pier */ | ||
677 | chinfo[pier].pd_curves = | ||
678 | kcalloc(AR5K_EEPROM_N_PD_CURVES, | ||
679 | sizeof(struct ath5k_pdgain_info), | ||
680 | GFP_KERNEL); | ||
681 | |||
682 | if (!chinfo[pier].pd_curves) | ||
683 | return -ENOMEM; | ||
684 | |||
685 | /* Only one curve for RF5111 | ||
686 | * find out which one and place | ||
687 | * in in pd_curves. | ||
688 | * Note: ee_x_gain is reversed here */ | ||
689 | for (idx = 0; idx < AR5K_EEPROM_N_PD_CURVES; idx++) { | ||
690 | |||
691 | if (!((ee->ee_x_gain[mode] >> idx) & 0x1)) { | ||
692 | pdgain_idx[0] = idx; | ||
693 | break; | ||
694 | } | ||
695 | } | ||
696 | |||
697 | ee->ee_pd_gains[mode] = 1; | ||
698 | |||
699 | pd = &chinfo[pier].pd_curves[idx]; | ||
700 | |||
701 | pd->pd_points = AR5K_EEPROM_N_PWR_POINTS_5111; | ||
702 | |||
703 | /* Allocate pd points for this curve */ | ||
704 | pd->pd_step = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, | ||
705 | sizeof(u8), GFP_KERNEL); | ||
706 | if (!pd->pd_step) | ||
707 | return -ENOMEM; | ||
708 | |||
709 | pd->pd_pwr = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, | ||
710 | sizeof(s16), GFP_KERNEL); | ||
711 | if (!pd->pd_pwr) | ||
712 | return -ENOMEM; | ||
713 | |||
714 | /* Fill raw dataset | ||
715 | * (convert power to 0.25dB units | ||
716 | * for RF5112 combatibility) */ | ||
717 | for (point = 0; point < pd->pd_points; point++) { | ||
718 | |||
719 | /* Absolute values */ | ||
720 | pd->pd_pwr[point] = 2 * pcinfo->pwr[point]; | ||
721 | |||
722 | /* Already sorted */ | ||
723 | pd->pd_step[point] = pcinfo->pcdac[point]; | ||
724 | } | ||
725 | |||
726 | /* Set min/max pwr */ | ||
727 | chinfo[pier].min_pwr = pd->pd_pwr[0]; | ||
728 | chinfo[pier].max_pwr = pd->pd_pwr[10]; | ||
729 | |||
730 | } | ||
731 | |||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | /* Parse EEPROM data */ | ||
736 | static int | ||
737 | ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode) | ||
738 | { | ||
739 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
740 | struct ath5k_chan_pcal_info *pcal; | ||
741 | int offset, ret; | ||
742 | int i; | ||
743 | u16 val; | ||
744 | |||
745 | offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); | ||
746 | switch(mode) { | ||
747 | case AR5K_EEPROM_MODE_11A: | ||
748 | if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) | ||
749 | return 0; | ||
750 | |||
751 | ret = ath5k_eeprom_init_11a_pcal_freq(ah, | ||
752 | offset + AR5K_EEPROM_GROUP1_OFFSET); | ||
753 | if (ret < 0) | ||
754 | return ret; | ||
755 | |||
756 | offset += AR5K_EEPROM_GROUP2_OFFSET; | ||
757 | pcal = ee->ee_pwr_cal_a; | ||
758 | break; | ||
759 | case AR5K_EEPROM_MODE_11B: | ||
760 | if (!AR5K_EEPROM_HDR_11B(ee->ee_header) && | ||
761 | !AR5K_EEPROM_HDR_11G(ee->ee_header)) | ||
762 | return 0; | ||
763 | |||
764 | pcal = ee->ee_pwr_cal_b; | ||
765 | offset += AR5K_EEPROM_GROUP3_OFFSET; | ||
766 | |||
767 | /* fixed piers */ | ||
768 | pcal[0].freq = 2412; | ||
769 | pcal[1].freq = 2447; | ||
770 | pcal[2].freq = 2484; | ||
771 | ee->ee_n_piers[mode] = 3; | ||
772 | break; | ||
773 | case AR5K_EEPROM_MODE_11G: | ||
774 | if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) | ||
775 | return 0; | ||
776 | |||
777 | pcal = ee->ee_pwr_cal_g; | ||
778 | offset += AR5K_EEPROM_GROUP4_OFFSET; | ||
779 | |||
780 | /* fixed piers */ | ||
781 | pcal[0].freq = 2312; | ||
782 | pcal[1].freq = 2412; | ||
783 | pcal[2].freq = 2484; | ||
784 | ee->ee_n_piers[mode] = 3; | ||
785 | break; | ||
786 | default: | ||
787 | return -EINVAL; | ||
788 | } | ||
789 | |||
790 | for (i = 0; i < ee->ee_n_piers[mode]; i++) { | ||
791 | struct ath5k_chan_pcal_info_rf5111 *cdata = | ||
792 | &pcal[i].rf5111_info; | ||
793 | |||
794 | AR5K_EEPROM_READ(offset++, val); | ||
795 | cdata->pcdac_max = ((val >> 10) & AR5K_EEPROM_PCDAC_M); | ||
796 | cdata->pcdac_min = ((val >> 4) & AR5K_EEPROM_PCDAC_M); | ||
797 | cdata->pwr[0] = ((val << 2) & AR5K_EEPROM_POWER_M); | ||
798 | |||
799 | AR5K_EEPROM_READ(offset++, val); | ||
800 | cdata->pwr[0] |= ((val >> 14) & 0x3); | ||
801 | cdata->pwr[1] = ((val >> 8) & AR5K_EEPROM_POWER_M); | ||
802 | cdata->pwr[2] = ((val >> 2) & AR5K_EEPROM_POWER_M); | ||
803 | cdata->pwr[3] = ((val << 4) & AR5K_EEPROM_POWER_M); | ||
804 | |||
805 | AR5K_EEPROM_READ(offset++, val); | ||
806 | cdata->pwr[3] |= ((val >> 12) & 0xf); | ||
807 | cdata->pwr[4] = ((val >> 6) & AR5K_EEPROM_POWER_M); | ||
808 | cdata->pwr[5] = (val & AR5K_EEPROM_POWER_M); | ||
809 | |||
810 | AR5K_EEPROM_READ(offset++, val); | ||
811 | cdata->pwr[6] = ((val >> 10) & AR5K_EEPROM_POWER_M); | ||
812 | cdata->pwr[7] = ((val >> 4) & AR5K_EEPROM_POWER_M); | ||
813 | cdata->pwr[8] = ((val << 2) & AR5K_EEPROM_POWER_M); | ||
814 | |||
815 | AR5K_EEPROM_READ(offset++, val); | ||
816 | cdata->pwr[8] |= ((val >> 14) & 0x3); | ||
817 | cdata->pwr[9] = ((val >> 8) & AR5K_EEPROM_POWER_M); | ||
818 | cdata->pwr[10] = ((val >> 2) & AR5K_EEPROM_POWER_M); | ||
819 | |||
820 | ath5k_get_pcdac_intercepts(ah, cdata->pcdac_min, | ||
821 | cdata->pcdac_max, cdata->pcdac); | ||
822 | } | ||
823 | |||
824 | return ath5k_eeprom_convert_pcal_info_5111(ah, mode, pcal); | ||
825 | } | ||
826 | |||
827 | |||
828 | /* | ||
829 | * Read power calibration for RF5112 chips | ||
830 | * | ||
831 | * For RF5112 we have 4 XPD -eXternal Power Detector- curves | ||
832 | * for each calibrated channel on 0, -6, -12 and -18dbm but we only | ||
833 | * use the higher (3) and the lower (0) curves. Each curve has 0.5dB | ||
834 | * power steps on x axis and PCDAC steps on y axis and looks like a | ||
835 | * linear function. To recreate the curve and pass the power values | ||
836 | * on hw, we read 4 points for xpd 0 (lower gain -> max power) | ||
837 | * and 3 points for xpd 3 (higher gain -> lower power) here and | ||
838 | * interpolate later. | ||
839 | * | ||
840 | * Note: Many vendors just use xpd 0 so xpd 3 is zeroed. | ||
841 | */ | ||
842 | |||
843 | /* Convert RF5112 specific data to generic raw data | ||
844 | * used by interpolation code */ | ||
845 | static int | ||
846 | ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, | ||
847 | struct ath5k_chan_pcal_info *chinfo) | ||
848 | { | ||
849 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
850 | struct ath5k_chan_pcal_info_rf5112 *pcinfo; | ||
851 | u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; | ||
852 | unsigned int pier, pdg, point; | ||
853 | |||
854 | /* Fill raw data for each calibration pier */ | ||
855 | for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { | ||
856 | |||
857 | pcinfo = &chinfo[pier].rf5112_info; | ||
858 | |||
859 | /* Allocate pd_curves for this cal pier */ | ||
860 | chinfo[pier].pd_curves = | ||
861 | kcalloc(AR5K_EEPROM_N_PD_CURVES, | ||
862 | sizeof(struct ath5k_pdgain_info), | ||
863 | GFP_KERNEL); | ||
864 | |||
865 | if (!chinfo[pier].pd_curves) | ||
866 | return -ENOMEM; | ||
867 | |||
868 | /* Fill pd_curves */ | ||
869 | for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { | ||
870 | |||
871 | u8 idx = pdgain_idx[pdg]; | ||
872 | struct ath5k_pdgain_info *pd = | ||
873 | &chinfo[pier].pd_curves[idx]; | ||
874 | |||
875 | /* Lowest gain curve (max power) */ | ||
876 | if (pdg == 0) { | ||
877 | /* One more point for better accuracy */ | ||
878 | pd->pd_points = AR5K_EEPROM_N_XPD0_POINTS; | ||
879 | |||
880 | /* Allocate pd points for this curve */ | ||
881 | pd->pd_step = kcalloc(pd->pd_points, | ||
882 | sizeof(u8), GFP_KERNEL); | ||
883 | |||
884 | if (!pd->pd_step) | ||
885 | return -ENOMEM; | ||
886 | |||
887 | pd->pd_pwr = kcalloc(pd->pd_points, | ||
888 | sizeof(s16), GFP_KERNEL); | ||
889 | |||
890 | if (!pd->pd_pwr) | ||
891 | return -ENOMEM; | ||
892 | |||
893 | |||
894 | /* Fill raw dataset | ||
895 | * (all power levels are in 0.25dB units) */ | ||
896 | pd->pd_step[0] = pcinfo->pcdac_x0[0]; | ||
897 | pd->pd_pwr[0] = pcinfo->pwr_x0[0]; | ||
898 | |||
899 | for (point = 1; point < pd->pd_points; | ||
900 | point++) { | ||
901 | /* Absolute values */ | ||
902 | pd->pd_pwr[point] = | ||
903 | pcinfo->pwr_x0[point]; | ||
904 | |||
905 | /* Deltas */ | ||
906 | pd->pd_step[point] = | ||
907 | pd->pd_step[point - 1] + | ||
908 | pcinfo->pcdac_x0[point]; | ||
909 | } | ||
910 | |||
911 | /* Set min power for this frequency */ | ||
912 | chinfo[pier].min_pwr = pd->pd_pwr[0]; | ||
913 | |||
914 | /* Highest gain curve (min power) */ | ||
915 | } else if (pdg == 1) { | ||
916 | |||
917 | pd->pd_points = AR5K_EEPROM_N_XPD3_POINTS; | ||
918 | |||
919 | /* Allocate pd points for this curve */ | ||
920 | pd->pd_step = kcalloc(pd->pd_points, | ||
921 | sizeof(u8), GFP_KERNEL); | ||
922 | |||
923 | if (!pd->pd_step) | ||
924 | return -ENOMEM; | ||
925 | |||
926 | pd->pd_pwr = kcalloc(pd->pd_points, | ||
927 | sizeof(s16), GFP_KERNEL); | ||
928 | |||
929 | if (!pd->pd_pwr) | ||
930 | return -ENOMEM; | ||
931 | |||
932 | /* Fill raw dataset | ||
933 | * (all power levels are in 0.25dB units) */ | ||
934 | for (point = 0; point < pd->pd_points; | ||
935 | point++) { | ||
936 | /* Absolute values */ | ||
937 | pd->pd_pwr[point] = | ||
938 | pcinfo->pwr_x3[point]; | ||
939 | |||
940 | /* Fixed points */ | ||
941 | pd->pd_step[point] = | ||
942 | pcinfo->pcdac_x3[point]; | ||
943 | } | ||
944 | |||
945 | /* Since we have a higher gain curve | ||
946 | * override min power */ | ||
947 | chinfo[pier].min_pwr = pd->pd_pwr[0]; | ||
948 | } | ||
949 | } | ||
950 | } | ||
951 | |||
952 | return 0; | ||
953 | } | ||
954 | |||
955 | /* Parse EEPROM data */ | ||
956 | static int | ||
957 | ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) | ||
958 | { | ||
959 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
960 | struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info; | ||
961 | struct ath5k_chan_pcal_info *gen_chan_info; | ||
962 | u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; | ||
963 | u32 offset; | ||
964 | u8 i, c; | ||
965 | u16 val; | ||
966 | int ret; | ||
967 | u8 pd_gains = 0; | ||
968 | |||
969 | /* Count how many curves we have and | ||
970 | * identify them (which one of the 4 | ||
971 | * available curves we have on each count). | ||
972 | * Curves are stored from lower (x0) to | ||
973 | * higher (x3) gain */ | ||
974 | for (i = 0; i < AR5K_EEPROM_N_PD_CURVES; i++) { | ||
975 | /* ee_x_gain[mode] is x gain mask */ | ||
976 | if ((ee->ee_x_gain[mode] >> i) & 0x1) | ||
977 | pdgain_idx[pd_gains++] = i; | ||
978 | } | ||
979 | ee->ee_pd_gains[mode] = pd_gains; | ||
980 | |||
981 | if (pd_gains == 0 || pd_gains > 2) | ||
982 | return -EINVAL; | ||
983 | |||
984 | switch (mode) { | ||
985 | case AR5K_EEPROM_MODE_11A: | ||
986 | /* | ||
987 | * Read 5GHz EEPROM channels | ||
988 | */ | ||
989 | offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); | ||
990 | ath5k_eeprom_init_11a_pcal_freq(ah, offset); | ||
991 | |||
992 | offset += AR5K_EEPROM_GROUP2_OFFSET; | ||
993 | gen_chan_info = ee->ee_pwr_cal_a; | ||
994 | break; | ||
995 | case AR5K_EEPROM_MODE_11B: | ||
996 | offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); | ||
997 | if (AR5K_EEPROM_HDR_11A(ee->ee_header)) | ||
998 | offset += AR5K_EEPROM_GROUP3_OFFSET; | ||
999 | |||
1000 | /* NB: frequency piers parsed during mode init */ | ||
1001 | gen_chan_info = ee->ee_pwr_cal_b; | ||
1002 | break; | ||
1003 | case AR5K_EEPROM_MODE_11G: | ||
1004 | offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); | ||
1005 | if (AR5K_EEPROM_HDR_11A(ee->ee_header)) | ||
1006 | offset += AR5K_EEPROM_GROUP4_OFFSET; | ||
1007 | else if (AR5K_EEPROM_HDR_11B(ee->ee_header)) | ||
1008 | offset += AR5K_EEPROM_GROUP2_OFFSET; | ||
1009 | |||
1010 | /* NB: frequency piers parsed during mode init */ | ||
1011 | gen_chan_info = ee->ee_pwr_cal_g; | ||
1012 | break; | ||
1013 | default: | ||
1014 | return -EINVAL; | ||
1015 | } | ||
1016 | |||
1017 | for (i = 0; i < ee->ee_n_piers[mode]; i++) { | ||
1018 | chan_pcal_info = &gen_chan_info[i].rf5112_info; | ||
1019 | |||
1020 | /* Power values in quarter dB | ||
1021 | * for the lower xpd gain curve | ||
1022 | * (0 dBm -> higher output power) */ | ||
1023 | for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) { | ||
1024 | AR5K_EEPROM_READ(offset++, val); | ||
1025 | chan_pcal_info->pwr_x0[c] = (s8) (val & 0xff); | ||
1026 | chan_pcal_info->pwr_x0[++c] = (s8) ((val >> 8) & 0xff); | ||
1027 | } | ||
1028 | |||
1029 | /* PCDAC steps | ||
1030 | * corresponding to the above power | ||
1031 | * measurements */ | ||
1032 | AR5K_EEPROM_READ(offset++, val); | ||
1033 | chan_pcal_info->pcdac_x0[1] = (val & 0x1f); | ||
1034 | chan_pcal_info->pcdac_x0[2] = ((val >> 5) & 0x1f); | ||
1035 | chan_pcal_info->pcdac_x0[3] = ((val >> 10) & 0x1f); | ||
1036 | |||
1037 | /* Power values in quarter dB | ||
1038 | * for the higher xpd gain curve | ||
1039 | * (18 dBm -> lower output power) */ | ||
1040 | AR5K_EEPROM_READ(offset++, val); | ||
1041 | chan_pcal_info->pwr_x3[0] = (s8) (val & 0xff); | ||
1042 | chan_pcal_info->pwr_x3[1] = (s8) ((val >> 8) & 0xff); | ||
1043 | |||
1044 | AR5K_EEPROM_READ(offset++, val); | ||
1045 | chan_pcal_info->pwr_x3[2] = (val & 0xff); | ||
1046 | |||
1047 | /* PCDAC steps | ||
1048 | * corresponding to the above power | ||
1049 | * measurements (fixed) */ | ||
1050 | chan_pcal_info->pcdac_x3[0] = 20; | ||
1051 | chan_pcal_info->pcdac_x3[1] = 35; | ||
1052 | chan_pcal_info->pcdac_x3[2] = 63; | ||
1053 | |||
1054 | if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) { | ||
1055 | chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0x3f); | ||
1056 | |||
1057 | /* Last xpd0 power level is also channel maximum */ | ||
1058 | gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3]; | ||
1059 | } else { | ||
1060 | chan_pcal_info->pcdac_x0[0] = 1; | ||
1061 | gen_chan_info[i].max_pwr = (s8) ((val >> 8) & 0xff); | ||
1062 | } | ||
1063 | |||
1064 | } | ||
1065 | |||
1066 | return ath5k_eeprom_convert_pcal_info_5112(ah, mode, gen_chan_info); | ||
1067 | } | ||
1068 | |||
1069 | |||
1070 | /* | ||
1071 | * Read power calibration for RF2413 chips | ||
1072 | * | ||
1073 | * For RF2413 we have a Power to PDDAC table (Power Detector) | ||
1074 | * instead of a PCDAC and 4 pd gain curves for each calibrated channel. | ||
1075 | * Each curve has power on x axis in 0.5 db steps and PDDADC steps on y | ||
1076 | * axis and looks like an exponential function like the RF5111 curve. | ||
1077 | * | ||
1078 | * To recreate the curves we read here the points and interpolate | ||
1079 | * later. Note that in most cases only 2 (higher and lower) curves are | ||
1080 | * used (like RF5112) but vendors have the oportunity to include all | ||
1081 | * 4 curves on eeprom. The final curve (higher power) has an extra | ||
1082 | * point for better accuracy like RF5112. | ||
1083 | */ | ||
1084 | |||
1085 | /* For RF2413 power calibration data doesn't start on a fixed location and | ||
1086 | * if a mode is not supported, it's section is missing -not zeroed-. | ||
1087 | * So we need to calculate the starting offset for each section by using | ||
1088 | * these two functions */ | ||
1089 | |||
1090 | /* Return the size of each section based on the mode and the number of pd | ||
1091 | * gains available (maximum 4). */ | ||
1092 | static inline unsigned int | ||
1093 | ath5k_pdgains_size_2413(struct ath5k_eeprom_info *ee, unsigned int mode) | ||
1094 | { | ||
1095 | static const unsigned int pdgains_size[] = { 4, 6, 9, 12 }; | ||
1096 | unsigned int sz; | ||
1097 | |||
1098 | sz = pdgains_size[ee->ee_pd_gains[mode] - 1]; | ||
1099 | sz *= ee->ee_n_piers[mode]; | ||
1100 | |||
1101 | return sz; | ||
1102 | } | ||
1103 | |||
1104 | /* Return the starting offset for a section based on the modes supported | ||
1105 | * and each section's size. */ | ||
1106 | static unsigned int | ||
1107 | ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode) | ||
1108 | { | ||
1109 | u32 offset = AR5K_EEPROM_CAL_DATA_START(ee->ee_misc4); | ||
1110 | |||
1111 | switch(mode) { | ||
1112 | case AR5K_EEPROM_MODE_11G: | ||
1113 | if (AR5K_EEPROM_HDR_11B(ee->ee_header)) | ||
1114 | offset += ath5k_pdgains_size_2413(ee, | ||
1115 | AR5K_EEPROM_MODE_11B) + | ||
1116 | AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; | ||
1117 | /* fall through */ | ||
1118 | case AR5K_EEPROM_MODE_11B: | ||
1119 | if (AR5K_EEPROM_HDR_11A(ee->ee_header)) | ||
1120 | offset += ath5k_pdgains_size_2413(ee, | ||
1121 | AR5K_EEPROM_MODE_11A) + | ||
1122 | AR5K_EEPROM_N_5GHZ_CHAN / 2; | ||
1123 | /* fall through */ | ||
1124 | case AR5K_EEPROM_MODE_11A: | ||
1125 | break; | ||
1126 | default: | ||
1127 | break; | ||
1128 | } | ||
1129 | |||
1130 | return offset; | ||
1131 | } | ||
1132 | |||
1133 | /* Convert RF2413 specific data to generic raw data | ||
1134 | * used by interpolation code */ | ||
1135 | static int | ||
1136 | ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode, | ||
1137 | struct ath5k_chan_pcal_info *chinfo) | ||
1138 | { | ||
1139 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
1140 | struct ath5k_chan_pcal_info_rf2413 *pcinfo; | ||
1141 | u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; | ||
1142 | unsigned int pier, pdg, point; | ||
1143 | |||
1144 | /* Fill raw data for each calibration pier */ | ||
1145 | for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { | ||
1146 | |||
1147 | pcinfo = &chinfo[pier].rf2413_info; | ||
1148 | |||
1149 | /* Allocate pd_curves for this cal pier */ | ||
1150 | chinfo[pier].pd_curves = | ||
1151 | kcalloc(AR5K_EEPROM_N_PD_CURVES, | ||
1152 | sizeof(struct ath5k_pdgain_info), | ||
1153 | GFP_KERNEL); | ||
1154 | |||
1155 | if (!chinfo[pier].pd_curves) | ||
1156 | return -ENOMEM; | ||
1157 | |||
1158 | /* Fill pd_curves */ | ||
1159 | for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { | ||
1160 | |||
1161 | u8 idx = pdgain_idx[pdg]; | ||
1162 | struct ath5k_pdgain_info *pd = | ||
1163 | &chinfo[pier].pd_curves[idx]; | ||
1164 | |||
1165 | /* One more point for the highest power | ||
1166 | * curve (lowest gain) */ | ||
1167 | if (pdg == ee->ee_pd_gains[mode] - 1) | ||
1168 | pd->pd_points = AR5K_EEPROM_N_PD_POINTS; | ||
1169 | else | ||
1170 | pd->pd_points = AR5K_EEPROM_N_PD_POINTS - 1; | ||
1171 | |||
1172 | /* Allocate pd points for this curve */ | ||
1173 | pd->pd_step = kcalloc(pd->pd_points, | ||
1174 | sizeof(u8), GFP_KERNEL); | ||
1175 | |||
1176 | if (!pd->pd_step) | ||
1177 | return -ENOMEM; | ||
1178 | |||
1179 | pd->pd_pwr = kcalloc(pd->pd_points, | ||
1180 | sizeof(s16), GFP_KERNEL); | ||
1181 | |||
1182 | if (!pd->pd_pwr) | ||
1183 | return -ENOMEM; | ||
1184 | |||
1185 | /* Fill raw dataset | ||
1186 | * convert all pwr levels to | ||
1187 | * quarter dB for RF5112 combatibility */ | ||
1188 | pd->pd_step[0] = pcinfo->pddac_i[pdg]; | ||
1189 | pd->pd_pwr[0] = 4 * pcinfo->pwr_i[pdg]; | ||
1190 | |||
1191 | for (point = 1; point < pd->pd_points; point++) { | ||
1192 | |||
1193 | pd->pd_pwr[point] = pd->pd_pwr[point - 1] + | ||
1194 | 2 * pcinfo->pwr[pdg][point - 1]; | ||
1195 | |||
1196 | pd->pd_step[point] = pd->pd_step[point - 1] + | ||
1197 | pcinfo->pddac[pdg][point - 1]; | ||
1198 | |||
1199 | } | ||
1200 | |||
1201 | /* Highest gain curve -> min power */ | ||
1202 | if (pdg == 0) | ||
1203 | chinfo[pier].min_pwr = pd->pd_pwr[0]; | ||
1204 | |||
1205 | /* Lowest gain curve -> max power */ | ||
1206 | if (pdg == ee->ee_pd_gains[mode] - 1) | ||
1207 | chinfo[pier].max_pwr = | ||
1208 | pd->pd_pwr[pd->pd_points - 1]; | ||
1209 | } | ||
1210 | } | ||
1211 | |||
1212 | return 0; | ||
1213 | } | ||
1214 | |||
1215 | /* Parse EEPROM data */ | ||
1216 | static int | ||
1217 | ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) | ||
1218 | { | ||
1219 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
1220 | struct ath5k_chan_pcal_info_rf2413 *pcinfo; | ||
1221 | struct ath5k_chan_pcal_info *chinfo; | ||
1222 | u8 *pdgain_idx = ee->ee_pdc_to_idx[mode]; | ||
1223 | u32 offset; | ||
1224 | int idx, i, ret; | ||
1225 | u16 val; | ||
1226 | u8 pd_gains = 0; | ||
1227 | |||
1228 | /* Count how many curves we have and | ||
1229 | * identify them (which one of the 4 | ||
1230 | * available curves we have on each count). | ||
1231 | * Curves are stored from higher to | ||
1232 | * lower gain so we go backwards */ | ||
1233 | for (idx = AR5K_EEPROM_N_PD_CURVES - 1; idx >= 0; idx--) { | ||
1234 | /* ee_x_gain[mode] is x gain mask */ | ||
1235 | if ((ee->ee_x_gain[mode] >> idx) & 0x1) | ||
1236 | pdgain_idx[pd_gains++] = idx; | ||
1237 | |||
1238 | } | ||
1239 | ee->ee_pd_gains[mode] = pd_gains; | ||
1240 | |||
1241 | if (pd_gains == 0) | ||
1242 | return -EINVAL; | ||
1243 | |||
1244 | offset = ath5k_cal_data_offset_2413(ee, mode); | ||
1245 | switch (mode) { | ||
1246 | case AR5K_EEPROM_MODE_11A: | ||
1247 | if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) | ||
1248 | return 0; | ||
1249 | |||
1250 | ath5k_eeprom_init_11a_pcal_freq(ah, offset); | ||
1251 | offset += AR5K_EEPROM_N_5GHZ_CHAN / 2; | ||
1252 | chinfo = ee->ee_pwr_cal_a; | ||
1253 | break; | ||
1254 | case AR5K_EEPROM_MODE_11B: | ||
1255 | if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) | ||
1256 | return 0; | ||
1257 | |||
1258 | ath5k_eeprom_init_11bg_2413(ah, mode, offset); | ||
1259 | offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; | ||
1260 | chinfo = ee->ee_pwr_cal_b; | ||
1261 | break; | ||
1262 | case AR5K_EEPROM_MODE_11G: | ||
1263 | if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) | ||
1264 | return 0; | ||
1265 | |||
1266 | ath5k_eeprom_init_11bg_2413(ah, mode, offset); | ||
1267 | offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; | ||
1268 | chinfo = ee->ee_pwr_cal_g; | ||
1269 | break; | ||
1270 | default: | ||
1271 | return -EINVAL; | ||
1272 | } | ||
1273 | |||
1274 | for (i = 0; i < ee->ee_n_piers[mode]; i++) { | ||
1275 | pcinfo = &chinfo[i].rf2413_info; | ||
1276 | |||
1277 | /* | ||
1278 | * Read pwr_i, pddac_i and the first | ||
1279 | * 2 pd points (pwr, pddac) | ||
1280 | */ | ||
1281 | AR5K_EEPROM_READ(offset++, val); | ||
1282 | pcinfo->pwr_i[0] = val & 0x1f; | ||
1283 | pcinfo->pddac_i[0] = (val >> 5) & 0x7f; | ||
1284 | pcinfo->pwr[0][0] = (val >> 12) & 0xf; | ||
1285 | |||
1286 | AR5K_EEPROM_READ(offset++, val); | ||
1287 | pcinfo->pddac[0][0] = val & 0x3f; | ||
1288 | pcinfo->pwr[0][1] = (val >> 6) & 0xf; | ||
1289 | pcinfo->pddac[0][1] = (val >> 10) & 0x3f; | ||
1290 | |||
1291 | AR5K_EEPROM_READ(offset++, val); | ||
1292 | pcinfo->pwr[0][2] = val & 0xf; | ||
1293 | pcinfo->pddac[0][2] = (val >> 4) & 0x3f; | ||
1294 | |||
1295 | pcinfo->pwr[0][3] = 0; | ||
1296 | pcinfo->pddac[0][3] = 0; | ||
1297 | |||
1298 | if (pd_gains > 1) { | ||
1299 | /* | ||
1300 | * Pd gain 0 is not the last pd gain | ||
1301 | * so it only has 2 pd points. | ||
1302 | * Continue wih pd gain 1. | ||
1303 | */ | ||
1304 | pcinfo->pwr_i[1] = (val >> 10) & 0x1f; | ||
1305 | |||
1306 | pcinfo->pddac_i[1] = (val >> 15) & 0x1; | ||
1307 | AR5K_EEPROM_READ(offset++, val); | ||
1308 | pcinfo->pddac_i[1] |= (val & 0x3F) << 1; | ||
1309 | |||
1310 | pcinfo->pwr[1][0] = (val >> 6) & 0xf; | ||
1311 | pcinfo->pddac[1][0] = (val >> 10) & 0x3f; | ||
1312 | |||
1313 | AR5K_EEPROM_READ(offset++, val); | ||
1314 | pcinfo->pwr[1][1] = val & 0xf; | ||
1315 | pcinfo->pddac[1][1] = (val >> 4) & 0x3f; | ||
1316 | pcinfo->pwr[1][2] = (val >> 10) & 0xf; | ||
1317 | |||
1318 | pcinfo->pddac[1][2] = (val >> 14) & 0x3; | ||
1319 | AR5K_EEPROM_READ(offset++, val); | ||
1320 | pcinfo->pddac[1][2] |= (val & 0xF) << 2; | ||
1321 | |||
1322 | pcinfo->pwr[1][3] = 0; | ||
1323 | pcinfo->pddac[1][3] = 0; | ||
1324 | } else if (pd_gains == 1) { | ||
1325 | /* | ||
1326 | * Pd gain 0 is the last one so | ||
1327 | * read the extra point. | ||
1328 | */ | ||
1329 | pcinfo->pwr[0][3] = (val >> 10) & 0xf; | ||
1330 | |||
1331 | pcinfo->pddac[0][3] = (val >> 14) & 0x3; | ||
1332 | AR5K_EEPROM_READ(offset++, val); | ||
1333 | pcinfo->pddac[0][3] |= (val & 0xF) << 2; | ||
1334 | } | ||
1335 | |||
1336 | /* | ||
1337 | * Proceed with the other pd_gains | ||
1338 | * as above. | ||
1339 | */ | ||
1340 | if (pd_gains > 2) { | ||
1341 | pcinfo->pwr_i[2] = (val >> 4) & 0x1f; | ||
1342 | pcinfo->pddac_i[2] = (val >> 9) & 0x7f; | ||
1343 | |||
1344 | AR5K_EEPROM_READ(offset++, val); | ||
1345 | pcinfo->pwr[2][0] = (val >> 0) & 0xf; | ||
1346 | pcinfo->pddac[2][0] = (val >> 4) & 0x3f; | ||
1347 | pcinfo->pwr[2][1] = (val >> 10) & 0xf; | ||
1348 | |||
1349 | pcinfo->pddac[2][1] = (val >> 14) & 0x3; | ||
1350 | AR5K_EEPROM_READ(offset++, val); | ||
1351 | pcinfo->pddac[2][1] |= (val & 0xF) << 2; | ||
1352 | |||
1353 | pcinfo->pwr[2][2] = (val >> 4) & 0xf; | ||
1354 | pcinfo->pddac[2][2] = (val >> 8) & 0x3f; | ||
1355 | |||
1356 | pcinfo->pwr[2][3] = 0; | ||
1357 | pcinfo->pddac[2][3] = 0; | ||
1358 | } else if (pd_gains == 2) { | ||
1359 | pcinfo->pwr[1][3] = (val >> 4) & 0xf; | ||
1360 | pcinfo->pddac[1][3] = (val >> 8) & 0x3f; | ||
1361 | } | ||
1362 | |||
1363 | if (pd_gains > 3) { | ||
1364 | pcinfo->pwr_i[3] = (val >> 14) & 0x3; | ||
1365 | AR5K_EEPROM_READ(offset++, val); | ||
1366 | pcinfo->pwr_i[3] |= ((val >> 0) & 0x7) << 2; | ||
1367 | |||
1368 | pcinfo->pddac_i[3] = (val >> 3) & 0x7f; | ||
1369 | pcinfo->pwr[3][0] = (val >> 10) & 0xf; | ||
1370 | pcinfo->pddac[3][0] = (val >> 14) & 0x3; | ||
1371 | |||
1372 | AR5K_EEPROM_READ(offset++, val); | ||
1373 | pcinfo->pddac[3][0] |= (val & 0xF) << 2; | ||
1374 | pcinfo->pwr[3][1] = (val >> 4) & 0xf; | ||
1375 | pcinfo->pddac[3][1] = (val >> 8) & 0x3f; | ||
1376 | |||
1377 | pcinfo->pwr[3][2] = (val >> 14) & 0x3; | ||
1378 | AR5K_EEPROM_READ(offset++, val); | ||
1379 | pcinfo->pwr[3][2] |= ((val >> 0) & 0x3) << 2; | ||
1380 | |||
1381 | pcinfo->pddac[3][2] = (val >> 2) & 0x3f; | ||
1382 | pcinfo->pwr[3][3] = (val >> 8) & 0xf; | ||
1383 | |||
1384 | pcinfo->pddac[3][3] = (val >> 12) & 0xF; | ||
1385 | AR5K_EEPROM_READ(offset++, val); | ||
1386 | pcinfo->pddac[3][3] |= ((val >> 0) & 0x3) << 4; | ||
1387 | } else if (pd_gains == 3) { | ||
1388 | pcinfo->pwr[2][3] = (val >> 14) & 0x3; | ||
1389 | AR5K_EEPROM_READ(offset++, val); | ||
1390 | pcinfo->pwr[2][3] |= ((val >> 0) & 0x3) << 2; | ||
1391 | |||
1392 | pcinfo->pddac[2][3] = (val >> 2) & 0x3f; | ||
1393 | } | ||
1394 | } | ||
1395 | |||
1396 | return ath5k_eeprom_convert_pcal_info_2413(ah, mode, chinfo); | ||
1397 | } | ||
1398 | |||
1399 | |||
1400 | /* | ||
1401 | * Read per rate target power (this is the maximum tx power | ||
1402 | * supported by the card). This info is used when setting | ||
1403 | * tx power, no matter the channel. | ||
1404 | * | ||
1405 | * This also works for v5 EEPROMs. | ||
1406 | */ | ||
1407 | static int | ||
1408 | ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode) | ||
1409 | { | ||
1410 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
1411 | struct ath5k_rate_pcal_info *rate_pcal_info; | ||
1412 | u8 *rate_target_pwr_num; | ||
1413 | u32 offset; | ||
1414 | u16 val; | ||
1415 | int ret, i; | ||
1416 | |||
1417 | offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1); | ||
1418 | rate_target_pwr_num = &ee->ee_rate_target_pwr_num[mode]; | ||
1419 | switch (mode) { | ||
1420 | case AR5K_EEPROM_MODE_11A: | ||
1421 | offset += AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version); | ||
1422 | rate_pcal_info = ee->ee_rate_tpwr_a; | ||
1423 | ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_CHAN; | ||
1424 | break; | ||
1425 | case AR5K_EEPROM_MODE_11B: | ||
1426 | offset += AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version); | ||
1427 | rate_pcal_info = ee->ee_rate_tpwr_b; | ||
1428 | ee->ee_rate_target_pwr_num[mode] = 2; /* 3rd is g mode's 1st */ | ||
1429 | break; | ||
1430 | case AR5K_EEPROM_MODE_11G: | ||
1431 | offset += AR5K_EEPROM_TARGET_PWR_OFF_11G(ee->ee_version); | ||
1432 | rate_pcal_info = ee->ee_rate_tpwr_g; | ||
1433 | ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_2GHZ_CHAN; | ||
1434 | break; | ||
1435 | default: | ||
1436 | return -EINVAL; | ||
1437 | } | ||
1438 | |||
1439 | /* Different freq mask for older eeproms (<= v3.2) */ | ||
1440 | if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2) { | ||
1441 | for (i = 0; i < (*rate_target_pwr_num); i++) { | ||
1442 | AR5K_EEPROM_READ(offset++, val); | ||
1443 | rate_pcal_info[i].freq = | ||
1444 | ath5k_eeprom_bin2freq(ee, (val >> 9) & 0x7f, mode); | ||
1445 | |||
1446 | rate_pcal_info[i].target_power_6to24 = ((val >> 3) & 0x3f); | ||
1447 | rate_pcal_info[i].target_power_36 = (val << 3) & 0x3f; | ||
1448 | |||
1449 | AR5K_EEPROM_READ(offset++, val); | ||
1450 | |||
1451 | if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS || | ||
1452 | val == 0) { | ||
1453 | (*rate_target_pwr_num) = i; | ||
1454 | break; | ||
1455 | } | ||
1456 | |||
1457 | rate_pcal_info[i].target_power_36 |= ((val >> 13) & 0x7); | ||
1458 | rate_pcal_info[i].target_power_48 = ((val >> 7) & 0x3f); | ||
1459 | rate_pcal_info[i].target_power_54 = ((val >> 1) & 0x3f); | ||
1460 | } | ||
1461 | } else { | ||
1462 | for (i = 0; i < (*rate_target_pwr_num); i++) { | ||
1463 | AR5K_EEPROM_READ(offset++, val); | ||
1464 | rate_pcal_info[i].freq = | ||
1465 | ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode); | ||
1466 | |||
1467 | rate_pcal_info[i].target_power_6to24 = ((val >> 2) & 0x3f); | ||
1468 | rate_pcal_info[i].target_power_36 = (val << 4) & 0x3f; | ||
1469 | |||
1470 | AR5K_EEPROM_READ(offset++, val); | ||
1471 | |||
1472 | if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS || | ||
1473 | val == 0) { | ||
1474 | (*rate_target_pwr_num) = i; | ||
1475 | break; | ||
1476 | } | ||
1477 | |||
1478 | rate_pcal_info[i].target_power_36 |= (val >> 12) & 0xf; | ||
1479 | rate_pcal_info[i].target_power_48 = ((val >> 6) & 0x3f); | ||
1480 | rate_pcal_info[i].target_power_54 = (val & 0x3f); | ||
1481 | } | ||
1482 | } | ||
1483 | |||
1484 | return 0; | ||
1485 | } | ||
1486 | |||
1487 | /* | ||
1488 | * Read per channel calibration info from EEPROM | ||
1489 | * | ||
1490 | * This info is used to calibrate the baseband power table. Imagine | ||
1491 | * that for each channel there is a power curve that's hw specific | ||
1492 | * (depends on amplifier etc) and we try to "correct" this curve using | ||
1493 | * offests we pass on to phy chip (baseband -> before amplifier) so that | ||
1494 | * it can use accurate power values when setting tx power (takes amplifier's | ||
1495 | * performance on each channel into account). | ||
1496 | * | ||
1497 | * EEPROM provides us with the offsets for some pre-calibrated channels | ||
1498 | * and we have to interpolate to create the full table for these channels and | ||
1499 | * also the table for any channel. | ||
1500 | */ | ||
1501 | static int | ||
1502 | ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah) | ||
1503 | { | ||
1504 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
1505 | int (*read_pcal)(struct ath5k_hw *hw, int mode); | ||
1506 | int mode; | ||
1507 | int err; | ||
1508 | |||
1509 | if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) && | ||
1510 | (AR5K_EEPROM_EEMAP(ee->ee_misc0) == 1)) | ||
1511 | read_pcal = ath5k_eeprom_read_pcal_info_5112; | ||
1512 | else if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0) && | ||
1513 | (AR5K_EEPROM_EEMAP(ee->ee_misc0) == 2)) | ||
1514 | read_pcal = ath5k_eeprom_read_pcal_info_2413; | ||
1515 | else | ||
1516 | read_pcal = ath5k_eeprom_read_pcal_info_5111; | ||
1517 | |||
1518 | |||
1519 | for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; | ||
1520 | mode++) { | ||
1521 | err = read_pcal(ah, mode); | ||
1522 | if (err) | ||
1523 | return err; | ||
1524 | |||
1525 | err = ath5k_eeprom_read_target_rate_pwr_info(ah, mode); | ||
1526 | if (err < 0) | ||
1527 | return err; | ||
1528 | } | ||
1529 | |||
1530 | return 0; | ||
1531 | } | ||
1532 | |||
1533 | static int | ||
1534 | ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode) | ||
1535 | { | ||
1536 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
1537 | struct ath5k_chan_pcal_info *chinfo; | ||
1538 | u8 pier, pdg; | ||
1539 | |||
1540 | switch (mode) { | ||
1541 | case AR5K_EEPROM_MODE_11A: | ||
1542 | if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) | ||
1543 | return 0; | ||
1544 | chinfo = ee->ee_pwr_cal_a; | ||
1545 | break; | ||
1546 | case AR5K_EEPROM_MODE_11B: | ||
1547 | if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) | ||
1548 | return 0; | ||
1549 | chinfo = ee->ee_pwr_cal_b; | ||
1550 | break; | ||
1551 | case AR5K_EEPROM_MODE_11G: | ||
1552 | if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) | ||
1553 | return 0; | ||
1554 | chinfo = ee->ee_pwr_cal_g; | ||
1555 | break; | ||
1556 | default: | ||
1557 | return -EINVAL; | ||
1558 | } | ||
1559 | |||
1560 | for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { | ||
1561 | if (!chinfo[pier].pd_curves) | ||
1562 | continue; | ||
1563 | |||
1564 | for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { | ||
1565 | struct ath5k_pdgain_info *pd = | ||
1566 | &chinfo[pier].pd_curves[pdg]; | ||
1567 | |||
1568 | if (pd != NULL) { | ||
1569 | kfree(pd->pd_step); | ||
1570 | kfree(pd->pd_pwr); | ||
1571 | } | ||
1572 | } | ||
1573 | |||
1574 | kfree(chinfo[pier].pd_curves); | ||
1575 | } | ||
1576 | |||
1577 | return 0; | ||
1578 | } | ||
1579 | |||
1580 | void | ||
1581 | ath5k_eeprom_detach(struct ath5k_hw *ah) | ||
1582 | { | ||
1583 | u8 mode; | ||
1584 | |||
1585 | for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) | ||
1586 | ath5k_eeprom_free_pcal_info(ah, mode); | ||
1587 | } | ||
1588 | |||
1589 | /* Read conformance test limits used for regulatory control */ | ||
1590 | static int | ||
1591 | ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) | ||
1592 | { | ||
1593 | struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; | ||
1594 | struct ath5k_edge_power *rep; | ||
1595 | unsigned int fmask, pmask; | ||
1596 | unsigned int ctl_mode; | ||
1597 | int ret, i, j; | ||
1598 | u32 offset; | ||
1599 | u16 val; | ||
1600 | |||
1601 | pmask = AR5K_EEPROM_POWER_M; | ||
1602 | fmask = AR5K_EEPROM_FREQ_M(ee->ee_version); | ||
1603 | offset = AR5K_EEPROM_CTL(ee->ee_version); | ||
1604 | ee->ee_ctls = AR5K_EEPROM_N_CTLS(ee->ee_version); | ||
1605 | for (i = 0; i < ee->ee_ctls; i += 2) { | ||
1606 | AR5K_EEPROM_READ(offset++, val); | ||
1607 | ee->ee_ctl[i] = (val >> 8) & 0xff; | ||
1608 | ee->ee_ctl[i + 1] = val & 0xff; | ||
1609 | } | ||
1610 | |||
1611 | offset = AR5K_EEPROM_GROUP8_OFFSET; | ||
1612 | if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0) | ||
1613 | offset += AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) - | ||
1614 | AR5K_EEPROM_GROUP5_OFFSET; | ||
1615 | else | ||
1616 | offset += AR5K_EEPROM_GROUPS_START(ee->ee_version); | ||
1617 | |||
1618 | rep = ee->ee_ctl_pwr; | ||
1619 | for(i = 0; i < ee->ee_ctls; i++) { | ||
1620 | switch(ee->ee_ctl[i] & AR5K_CTL_MODE_M) { | ||
1621 | case AR5K_CTL_11A: | ||
1622 | case AR5K_CTL_TURBO: | ||
1623 | ctl_mode = AR5K_EEPROM_MODE_11A; | ||
1624 | break; | ||
1625 | default: | ||
1626 | ctl_mode = AR5K_EEPROM_MODE_11G; | ||
1627 | break; | ||
1628 | } | ||
1629 | if (ee->ee_ctl[i] == 0) { | ||
1630 | if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) | ||
1631 | offset += 8; | ||
1632 | else | ||
1633 | offset += 7; | ||
1634 | rep += AR5K_EEPROM_N_EDGES; | ||
1635 | continue; | ||
1636 | } | ||
1637 | if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) { | ||
1638 | for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) { | ||
1639 | AR5K_EEPROM_READ(offset++, val); | ||
1640 | rep[j].freq = (val >> 8) & fmask; | ||
1641 | rep[j + 1].freq = val & fmask; | ||
1642 | } | ||
1643 | for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) { | ||
1644 | AR5K_EEPROM_READ(offset++, val); | ||
1645 | rep[j].edge = (val >> 8) & pmask; | ||
1646 | rep[j].flag = (val >> 14) & 1; | ||
1647 | rep[j + 1].edge = val & pmask; | ||
1648 | rep[j + 1].flag = (val >> 6) & 1; | ||
1649 | } | ||
1650 | } else { | ||
1651 | AR5K_EEPROM_READ(offset++, val); | ||
1652 | rep[0].freq = (val >> 9) & fmask; | ||
1653 | rep[1].freq = (val >> 2) & fmask; | ||
1654 | rep[2].freq = (val << 5) & fmask; | ||
1655 | |||
1656 | AR5K_EEPROM_READ(offset++, val); | ||
1657 | rep[2].freq |= (val >> 11) & 0x1f; | ||
1658 | rep[3].freq = (val >> 4) & fmask; | ||
1659 | rep[4].freq = (val << 3) & fmask; | ||
1660 | |||
1661 | AR5K_EEPROM_READ(offset++, val); | ||
1662 | rep[4].freq |= (val >> 13) & 0x7; | ||
1663 | rep[5].freq = (val >> 6) & fmask; | ||
1664 | rep[6].freq = (val << 1) & fmask; | ||
1665 | |||
1666 | AR5K_EEPROM_READ(offset++, val); | ||
1667 | rep[6].freq |= (val >> 15) & 0x1; | ||
1668 | rep[7].freq = (val >> 8) & fmask; | ||
1669 | |||
1670 | rep[0].edge = (val >> 2) & pmask; | ||
1671 | rep[1].edge = (val << 4) & pmask; | ||
1672 | |||
1673 | AR5K_EEPROM_READ(offset++, val); | ||
1674 | rep[1].edge |= (val >> 12) & 0xf; | ||
1675 | rep[2].edge = (val >> 6) & pmask; | ||
1676 | rep[3].edge = val & pmask; | ||
1677 | |||
1678 | AR5K_EEPROM_READ(offset++, val); | ||
1679 | rep[4].edge = (val >> 10) & pmask; | ||
1680 | rep[5].edge = (val >> 4) & pmask; | ||
1681 | rep[6].edge = (val << 2) & pmask; | ||
1682 | |||
1683 | AR5K_EEPROM_READ(offset++, val); | ||
1684 | rep[6].edge |= (val >> 14) & 0x3; | ||
1685 | rep[7].edge = (val >> 8) & pmask; | ||
1686 | } | ||
1687 | for (j = 0; j < AR5K_EEPROM_N_EDGES; j++) { | ||
1688 | rep[j].freq = ath5k_eeprom_bin2freq(ee, | ||
1689 | rep[j].freq, ctl_mode); | ||
1690 | } | ||
1691 | rep += AR5K_EEPROM_N_EDGES; | ||
1692 | } | ||
1693 | |||
1694 | return 0; | ||
1695 | } | ||
1696 | |||
1697 | |||
1698 | /* | ||
1699 | * Initialize eeprom power tables | ||
1700 | */ | ||
1701 | int | ||
1702 | ath5k_eeprom_init(struct ath5k_hw *ah) | ||
1703 | { | ||
1704 | int err; | ||
1705 | |||
1706 | err = ath5k_eeprom_init_header(ah); | ||
1707 | if (err < 0) | ||
1708 | return err; | ||
1709 | |||
1710 | err = ath5k_eeprom_init_modes(ah); | ||
1711 | if (err < 0) | ||
1712 | return err; | ||
1713 | |||
1714 | err = ath5k_eeprom_read_pcal_info(ah); | ||
1715 | if (err < 0) | ||
1716 | return err; | ||
1717 | |||
1718 | err = ath5k_eeprom_read_ctl_info(ah); | ||
1719 | if (err < 0) | ||
1720 | return err; | ||
1721 | |||
1722 | return 0; | ||
1723 | } | ||
1724 | |||
1725 | /* | ||
1726 | * Read the MAC address from eeprom | ||
1727 | */ | ||
1728 | int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) | ||
1729 | { | ||
1730 | u8 mac_d[ETH_ALEN] = {}; | ||
1731 | u32 total, offset; | ||
1732 | u16 data; | ||
1733 | int octet, ret; | ||
1734 | |||
1735 | ret = ath5k_hw_eeprom_read(ah, 0x20, &data); | ||
1736 | if (ret) | ||
1737 | return ret; | ||
1738 | |||
1739 | for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) { | ||
1740 | ret = ath5k_hw_eeprom_read(ah, offset, &data); | ||
1741 | if (ret) | ||
1742 | return ret; | ||
1743 | |||
1744 | total += data; | ||
1745 | mac_d[octet + 1] = data & 0xff; | ||
1746 | mac_d[octet] = data >> 8; | ||
1747 | octet += 2; | ||
1748 | } | ||
1749 | |||
1750 | if (!total || total == 3 * 0xffff) | ||
1751 | return -EINVAL; | ||
1752 | |||
1753 | memcpy(mac, mac_d, ETH_ALEN); | ||
1754 | |||
1755 | return 0; | ||
1756 | } | ||
1757 | |||
1758 | bool ath5k_eeprom_is_hb63(struct ath5k_hw *ah) | ||
1759 | { | ||
1760 | u16 data; | ||
1761 | |||
1762 | ath5k_hw_eeprom_read(ah, AR5K_EEPROM_IS_HB63, &data); | ||
1763 | |||
1764 | if ((ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4)) && data) | ||
1765 | return true; | ||
1766 | else | ||
1767 | return false; | ||
1768 | } | ||
1769 | |||