1 | /* $NetBSD: arn9285.c,v 1.3 2013/10/17 21:24:24 christos Exp $ */ |
2 | /* $OpenBSD: ar9285.c,v 1.19 2012/06/10 21:23:36 kettenis Exp $ */ |
3 | |
4 | /*- |
5 | * Copyright (c) 2009-2010 Damien Bergamini <damien.bergamini@free.fr> |
6 | * Copyright (c) 2008-2010 Atheros Communications Inc. |
7 | * |
8 | * Permission to use, copy, modify, and/or distribute this software for any |
9 | * purpose with or without fee is hereby granted, provided that the above |
10 | * copyright notice and this permission notice appear in all copies. |
11 | * |
12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
16 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
17 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
18 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
19 | */ |
20 | |
21 | /* |
22 | * Driver for Atheros 802.11a/g/n chipsets. |
23 | * Routines for AR9285 and AR9271 chipsets. |
24 | */ |
25 | |
26 | #include <sys/cdefs.h> |
27 | __KERNEL_RCSID(0, "$NetBSD: arn9285.c,v 1.3 2013/10/17 21:24:24 christos Exp $" ); |
28 | |
29 | #ifndef _MODULE |
30 | #include "athn_usb.h" |
31 | #endif |
32 | |
33 | #include <sys/param.h> |
34 | #include <sys/sockio.h> |
35 | #include <sys/mbuf.h> |
36 | #include <sys/kernel.h> |
37 | #include <sys/socket.h> |
38 | #include <sys/systm.h> |
39 | #include <sys/malloc.h> |
40 | #include <sys/queue.h> |
41 | #include <sys/callout.h> |
42 | #include <sys/conf.h> |
43 | #include <sys/device.h> |
44 | |
45 | #include <sys/bus.h> |
46 | #include <sys/endian.h> |
47 | #include <sys/intr.h> |
48 | |
49 | #include <net/bpf.h> |
50 | #include <net/if.h> |
51 | #include <net/if_arp.h> |
52 | #include <net/if_dl.h> |
53 | #include <net/if_ether.h> |
54 | #include <net/if_media.h> |
55 | #include <net/if_types.h> |
56 | |
57 | #include <netinet/in.h> |
58 | #include <netinet/in_systm.h> |
59 | #include <netinet/in_var.h> |
60 | #include <netinet/ip.h> |
61 | |
62 | #include <net80211/ieee80211_var.h> |
63 | #include <net80211/ieee80211_amrr.h> |
64 | #include <net80211/ieee80211_radiotap.h> |
65 | |
66 | #include <dev/ic/athnreg.h> |
67 | #include <dev/ic/athnvar.h> |
68 | #include <dev/ic/arn9285.h> |
69 | |
70 | #include <dev/ic/arn5008reg.h> |
71 | #include <dev/ic/arn9280reg.h> |
72 | #include <dev/ic/arn9285reg.h> |
73 | |
74 | #include <dev/ic/arn5008.h> |
75 | #include <dev/ic/arn9280.h> |
76 | #include <dev/ic/arn9285.h> |
77 | |
78 | #define Static static |
79 | |
80 | Static int ar9285_cl_cal(struct athn_softc *, struct ieee80211_channel *, |
81 | struct ieee80211_channel *); |
82 | Static void ar9285_get_pdadcs(struct athn_softc *, |
83 | struct ieee80211_channel *, int, uint8_t, uint8_t *, |
84 | uint8_t *); |
85 | Static const struct ar_spur_chan * |
86 | ar9285_get_spur_chans(struct athn_softc *, int); |
87 | Static void ar9285_init_from_rom(struct athn_softc *, |
88 | struct ieee80211_channel *, struct ieee80211_channel *); |
89 | Static void ar9285_set_power_calib(struct athn_softc *, |
90 | struct ieee80211_channel *); |
91 | Static void ar9285_set_txpower(struct athn_softc *, |
92 | struct ieee80211_channel *, struct ieee80211_channel *); |
93 | Static void ar9285_setup(struct athn_softc *); |
94 | Static void ar9285_swap_rom(struct athn_softc *); |
95 | |
96 | PUBLIC int |
97 | ar9285_attach(struct athn_softc *sc) |
98 | { |
99 | |
100 | sc->sc_eep_base = AR9285_EEP_START_LOC; |
101 | sc->sc_eep_size = sizeof(struct ar9285_eeprom); |
102 | sc->sc_def_nf = AR9285_PHY_CCA_MAX_GOOD_VALUE; |
103 | sc->sc_ngpiopins = (sc->sc_flags & ATHN_FLAG_USB) ? 16 : 12; |
104 | sc->sc_led_pin = (sc->sc_flags & ATHN_FLAG_USB) ? 15 : 1; |
105 | sc->sc_workaround = AR9285_WA_DEFAULT; |
106 | sc->sc_ops.setup = ar9285_setup; |
107 | sc->sc_ops.swap_rom = ar9285_swap_rom; |
108 | sc->sc_ops.init_from_rom = ar9285_init_from_rom; |
109 | sc->sc_ops.set_txpower = ar9285_set_txpower; |
110 | sc->sc_ops.set_synth = ar9280_set_synth; |
111 | sc->sc_ops.spur_mitigate = ar9280_spur_mitigate; |
112 | sc->sc_ops.get_spur_chans = ar9285_get_spur_chans; |
113 | #if NATHN_USB > 0 |
114 | if (AR_SREV_9271(sc)) |
115 | sc->sc_ini = &ar9271_ini; |
116 | else |
117 | #endif |
118 | sc->sc_ini = &ar9285_1_2_ini; |
119 | sc->sc_serdes = &ar9280_2_0_serdes; |
120 | |
121 | return ar5008_attach(sc); |
122 | } |
123 | |
124 | Static void |
125 | ar9285_setup(struct athn_softc *sc) |
126 | { |
127 | const struct ar9285_eeprom *eep = sc->sc_eep; |
128 | uint8_t type; |
129 | |
130 | /* Select initialization values based on ROM. */ |
131 | type = eep->baseEepHeader.txGainType; |
132 | DPRINTFN(DBG_TX, sc, "Tx gain type=0x%x\n" , type); |
133 | #if NATHN_USB > 0 |
134 | if (AR_SREV_9271(sc)) { |
135 | if (type == AR_EEP_TXGAIN_HIGH_POWER) |
136 | sc->sc_tx_gain = &ar9271_tx_gain_high_power; |
137 | else |
138 | sc->sc_tx_gain = &ar9271_tx_gain; |
139 | } |
140 | else |
141 | #endif /* NATHN_USB */ |
142 | if ((AR_READ(sc, AR_AN_SYNTH9) & 0x7) == 0x1) { /* XE rev. */ |
143 | if (type == AR_EEP_TXGAIN_HIGH_POWER) |
144 | sc->sc_tx_gain = &ar9285_2_0_tx_gain_high_power; |
145 | else |
146 | sc->sc_tx_gain = &ar9285_2_0_tx_gain; |
147 | } |
148 | else { |
149 | if (type == AR_EEP_TXGAIN_HIGH_POWER) |
150 | sc->sc_tx_gain = &ar9285_1_2_tx_gain_high_power; |
151 | else |
152 | sc->sc_tx_gain = &ar9285_1_2_tx_gain; |
153 | } |
154 | } |
155 | |
156 | Static void |
157 | ar9285_swap_rom(struct athn_softc *sc) |
158 | { |
159 | struct ar9285_eeprom *eep = sc->sc_eep; |
160 | int i; |
161 | |
162 | eep->modalHeader.antCtrlCommon = |
163 | bswap32(eep->modalHeader.antCtrlCommon); |
164 | eep->modalHeader.antCtrlChain = |
165 | bswap32(eep->modalHeader.antCtrlChain); |
166 | |
167 | for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { |
168 | eep->modalHeader.spurChans[i].spurChan = |
169 | bswap16(eep->modalHeader.spurChans[i].spurChan); |
170 | } |
171 | } |
172 | |
173 | Static const struct ar_spur_chan * |
174 | ar9285_get_spur_chans(struct athn_softc *sc, int is2ghz) |
175 | { |
176 | const struct ar9285_eeprom *eep = sc->sc_eep; |
177 | |
178 | KASSERT(is2ghz); |
179 | return eep->modalHeader.spurChans; |
180 | } |
181 | |
182 | Static void |
183 | ar9285_init_from_rom(struct athn_softc *sc, struct ieee80211_channel *c, |
184 | struct ieee80211_channel *extc) |
185 | { |
186 | const struct ar9285_eeprom *eep = sc->sc_eep; |
187 | const struct ar9285_modal_eep_header *modal = &eep->modalHeader; |
188 | uint32_t reg, offset = 0x1000; |
189 | uint8_t ob[5], db1[5], db2[5]; |
190 | uint8_t txRxAtten; |
191 | |
192 | AR_WRITE(sc, AR_PHY_SWITCH_COM, modal->antCtrlCommon); |
193 | AR_WRITE(sc, AR_PHY_SWITCH_CHAIN_0, modal->antCtrlChain); |
194 | |
195 | reg = AR_READ(sc, AR_PHY_TIMING_CTRL4_0); |
196 | reg = RW(reg, AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, modal->iqCalI); |
197 | reg = RW(reg, AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, modal->iqCalQ); |
198 | AR_WRITE(sc, AR_PHY_TIMING_CTRL4_0, reg); |
199 | |
200 | if (sc->sc_eep_rev >= AR_EEP_MINOR_VER_3) { |
201 | reg = AR_READ(sc, AR_PHY_GAIN_2GHZ); |
202 | reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, |
203 | modal->bswMargin); |
204 | reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN1_DB, |
205 | modal->bswAtten); |
206 | reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, |
207 | modal->xatten2Margin); |
208 | reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN2_DB, |
209 | modal->xatten2Db); |
210 | AR_WRITE(sc, AR_PHY_GAIN_2GHZ, reg); |
211 | |
212 | /* Duplicate values of chain 0 for chain 1. */ |
213 | reg = AR_READ(sc, AR_PHY_GAIN_2GHZ + offset); |
214 | reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, |
215 | modal->bswMargin); |
216 | reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN1_DB, |
217 | modal->bswAtten); |
218 | reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, |
219 | modal->xatten2Margin); |
220 | reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN2_DB, |
221 | modal->xatten2Db); |
222 | AR_WRITE(sc, AR_PHY_GAIN_2GHZ + offset, reg); |
223 | } |
224 | if (sc->sc_eep_rev >= AR_EEP_MINOR_VER_3) |
225 | txRxAtten = modal->txRxAtten; |
226 | else /* Workaround for ROM versions < 14.3. */ |
227 | txRxAtten = 23; |
228 | reg = AR_READ(sc, AR_PHY_RXGAIN); |
229 | reg = RW(reg, AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAtten); |
230 | reg = RW(reg, AR9280_PHY_RXGAIN_TXRX_MARGIN, modal->rxTxMargin); |
231 | AR_WRITE(sc, AR_PHY_RXGAIN, reg); |
232 | |
233 | /* Duplicate values of chain 0 for chain 1. */ |
234 | reg = AR_READ(sc, AR_PHY_RXGAIN + offset); |
235 | reg = RW(reg, AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAtten); |
236 | reg = RW(reg, AR9280_PHY_RXGAIN_TXRX_MARGIN, modal->rxTxMargin); |
237 | AR_WRITE(sc, AR_PHY_RXGAIN + offset, reg); |
238 | |
239 | if (modal->version >= 3) { |
240 | /* Setup antenna diversity from ROM. */ |
241 | reg = AR_READ(sc, AR_PHY_MULTICHAIN_GAIN_CTL); |
242 | reg = RW(reg, AR9285_PHY_ANT_DIV_CTL_ALL, 0); |
243 | reg = RW(reg, AR9285_PHY_ANT_DIV_CTL, |
244 | (modal->ob_234 >> 12) & 0x1); |
245 | reg = RW(reg, AR9285_PHY_ANT_DIV_ALT_LNACONF, |
246 | (modal->db1_234 >> 12) & 0x3); |
247 | reg = RW(reg, AR9285_PHY_ANT_DIV_MAIN_LNACONF, |
248 | (modal->db1_234 >> 14) & 0x3); |
249 | reg = RW(reg, AR9285_PHY_ANT_DIV_ALT_GAINTB, |
250 | (modal->ob_234 >> 13) & 0x1); |
251 | reg = RW(reg, AR9285_PHY_ANT_DIV_MAIN_GAINTB, |
252 | (modal->ob_234 >> 14) & 0x1); |
253 | AR_WRITE(sc, AR_PHY_MULTICHAIN_GAIN_CTL, reg); |
254 | reg = AR_READ(sc, AR_PHY_MULTICHAIN_GAIN_CTL); /* Flush. */ |
255 | |
256 | reg = AR_READ(sc, AR_PHY_CCK_DETECT); |
257 | if (modal->ob_234 & (1 << 15)) |
258 | reg |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; |
259 | else |
260 | reg &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; |
261 | AR_WRITE(sc, AR_PHY_CCK_DETECT, reg); |
262 | reg = AR_READ(sc, AR_PHY_CCK_DETECT); /* Flush. */ |
263 | } |
264 | if (modal->version >= 2) { |
265 | ob [0] = (modal->ob_01 >> 0) & 0xf; |
266 | ob [1] = (modal->ob_01 >> 4) & 0xf; |
267 | ob [2] = (modal->ob_234 >> 0) & 0xf; |
268 | ob [3] = (modal->ob_234 >> 4) & 0xf; |
269 | ob [4] = (modal->ob_234 >> 8) & 0xf; |
270 | |
271 | db1[0] = (modal->db1_01 >> 0) & 0xf; |
272 | db1[1] = (modal->db1_01 >> 4) & 0xf; |
273 | db1[2] = (modal->db1_234 >> 0) & 0xf; |
274 | db1[3] = (modal->db1_234 >> 4) & 0xf; |
275 | db1[4] = (modal->db1_234 >> 8) & 0xf; |
276 | |
277 | db2[0] = (modal->db2_01 >> 0) & 0xf; |
278 | db2[1] = (modal->db2_01 >> 4) & 0xf; |
279 | db2[2] = (modal->db2_234 >> 0) & 0xf; |
280 | db2[3] = (modal->db2_234 >> 4) & 0xf; |
281 | db2[4] = (modal->db2_234 >> 8) & 0xf; |
282 | |
283 | } |
284 | else if (modal->version == 1) { |
285 | ob [0] = (modal->ob_01 >> 0) & 0xf; |
286 | ob [1] = (modal->ob_01 >> 4) & 0xf; |
287 | /* Field ob_234 does not exist, use ob_01. */ |
288 | ob [2] = ob [3] = ob [4] = ob [1]; |
289 | |
290 | db1[0] = (modal->db1_01 >> 0) & 0xf; |
291 | db1[1] = (modal->db1_01 >> 4) & 0xf; |
292 | /* Field db1_234 does not exist, use db1_01. */ |
293 | db1[2] = db1[3] = db1[4] = db1[1]; |
294 | |
295 | db2[0] = (modal->db2_01 >> 0) & 0xf; |
296 | db2[1] = (modal->db2_01 >> 4) & 0xf; |
297 | /* Field db2_234 does not exist, use db2_01. */ |
298 | db2[2] = db2[3] = db2[4] = db2[1]; |
299 | |
300 | } |
301 | else { |
302 | ob [0] = modal->ob_01; |
303 | ob [1] = ob [2] = ob [3] = ob [4] = ob [0]; |
304 | |
305 | db1[0] = modal->db1_01; |
306 | db1[1] = db1[2] = db1[3] = db1[4] = db1[0]; |
307 | |
308 | /* Field db2_01 does not exist, use db1_01. */ |
309 | db2[0] = modal->db1_01; |
310 | db2[1] = db2[2] = db2[3] = db2[4] = db2[0]; |
311 | } |
312 | #if NATHN_USB > 0 |
313 | if (AR_SREV_9271(sc)) { |
314 | reg = AR_READ(sc, AR9285_AN_RF2G3); |
315 | reg = RW(reg, AR9271_AN_RF2G3_OB_CCK, ob [0]); |
316 | reg = RW(reg, AR9271_AN_RF2G3_OB_PSK, ob [1]); |
317 | reg = RW(reg, AR9271_AN_RF2G3_OB_QAM, ob [2]); |
318 | reg = RW(reg, AR9271_AN_RF2G3_DB1, db1[0]); |
319 | AR_WRITE(sc, AR9285_AN_RF2G3, reg); |
320 | AR_WRITE_BARRIER(sc); |
321 | DELAY(100); |
322 | reg = AR_READ(sc, AR9285_AN_RF2G4); |
323 | reg = RW(reg, AR9271_AN_RF2G4_DB2, db2[0]); |
324 | AR_WRITE(sc, AR9285_AN_RF2G4, reg); |
325 | AR_WRITE_BARRIER(sc); |
326 | DELAY(100); |
327 | } |
328 | else |
329 | #endif /* ATHN_USB */ |
330 | { |
331 | reg = AR_READ(sc, AR9285_AN_RF2G3); |
332 | reg = RW(reg, AR9285_AN_RF2G3_OB_0, ob [0]); |
333 | reg = RW(reg, AR9285_AN_RF2G3_OB_1, ob [1]); |
334 | reg = RW(reg, AR9285_AN_RF2G3_OB_2, ob [2]); |
335 | reg = RW(reg, AR9285_AN_RF2G3_OB_3, ob [3]); |
336 | reg = RW(reg, AR9285_AN_RF2G3_OB_4, ob [4]); |
337 | reg = RW(reg, AR9285_AN_RF2G3_DB1_0, db1[0]); |
338 | reg = RW(reg, AR9285_AN_RF2G3_DB1_1, db1[1]); |
339 | reg = RW(reg, AR9285_AN_RF2G3_DB1_2, db1[2]); |
340 | AR_WRITE(sc, AR9285_AN_RF2G3, reg); |
341 | AR_WRITE_BARRIER(sc); |
342 | DELAY(100); |
343 | reg = AR_READ(sc, AR9285_AN_RF2G4); |
344 | reg = RW(reg, AR9285_AN_RF2G4_DB1_3, db1[3]); |
345 | reg = RW(reg, AR9285_AN_RF2G4_DB1_4, db1[4]); |
346 | reg = RW(reg, AR9285_AN_RF2G4_DB2_0, db2[0]); |
347 | reg = RW(reg, AR9285_AN_RF2G4_DB2_1, db2[1]); |
348 | reg = RW(reg, AR9285_AN_RF2G4_DB2_2, db2[2]); |
349 | reg = RW(reg, AR9285_AN_RF2G4_DB2_3, db2[3]); |
350 | reg = RW(reg, AR9285_AN_RF2G4_DB2_4, db2[4]); |
351 | AR_WRITE(sc, AR9285_AN_RF2G4, reg); |
352 | AR_WRITE_BARRIER(sc); |
353 | DELAY(100); |
354 | } |
355 | |
356 | reg = AR_READ(sc, AR_PHY_SETTLING); |
357 | reg = RW(reg, AR_PHY_SETTLING_SWITCH, modal->switchSettling); |
358 | AR_WRITE(sc, AR_PHY_SETTLING, reg); |
359 | |
360 | reg = AR_READ(sc, AR_PHY_DESIRED_SZ); |
361 | reg = RW(reg, AR_PHY_DESIRED_SZ_ADC, modal->adcDesiredSize); |
362 | AR_WRITE(sc, AR_PHY_DESIRED_SZ, reg); |
363 | |
364 | reg = SM(AR_PHY_RF_CTL4_TX_END_XPAA_OFF, modal->txEndToXpaOff); |
365 | reg |= SM(AR_PHY_RF_CTL4_TX_END_XPAB_OFF, modal->txEndToXpaOff); |
366 | reg |= SM(AR_PHY_RF_CTL4_FRAME_XPAA_ON, modal->txFrameToXpaOn); |
367 | reg |= SM(AR_PHY_RF_CTL4_FRAME_XPAB_ON, modal->txFrameToXpaOn); |
368 | AR_WRITE(sc, AR_PHY_RF_CTL4, reg); |
369 | |
370 | reg = AR_READ(sc, AR_PHY_RF_CTL3); |
371 | reg = RW(reg, AR_PHY_TX_END_TO_A2_RX_ON, modal->txEndToRxOn); |
372 | AR_WRITE(sc, AR_PHY_RF_CTL3, reg); |
373 | |
374 | reg = AR_READ(sc, AR_PHY_CCA(0)); |
375 | reg = RW(reg, AR9280_PHY_CCA_THRESH62, modal->thresh62); |
376 | AR_WRITE(sc, AR_PHY_CCA(0), reg); |
377 | |
378 | reg = AR_READ(sc, AR_PHY_EXT_CCA0); |
379 | reg = RW(reg, AR_PHY_EXT_CCA0_THRESH62, modal->thresh62); |
380 | AR_WRITE(sc, AR_PHY_EXT_CCA0, reg); |
381 | |
382 | if (sc->sc_eep_rev >= AR_EEP_MINOR_VER_2) { |
383 | reg = AR_READ(sc, AR_PHY_RF_CTL2); |
384 | reg = RW(reg, AR_PHY_TX_END_PA_ON, |
385 | modal->txFrameToPaOn); |
386 | reg = RW(reg, AR_PHY_TX_END_DATA_START, |
387 | modal->txFrameToDataStart); |
388 | AR_WRITE(sc, AR_PHY_RF_CTL2, reg); |
389 | } |
390 | #ifndef IEEE80211_NO_HT |
391 | if (sc->sc_eep_rev >= AR_EEP_MINOR_VER_3 && extc != NULL) { |
392 | reg = AR_READ(sc, AR_PHY_SETTLING); |
393 | reg = RW(reg, AR_PHY_SETTLING_SWITCH, modal->swSettleHt40); |
394 | AR_WRITE(sc, AR_PHY_SETTLING, reg); |
395 | } |
396 | #endif |
397 | AR_WRITE_BARRIER(sc); |
398 | } |
399 | |
400 | PUBLIC void |
401 | ar9285_pa_calib(struct athn_softc *sc) |
402 | { |
403 | /* List of registers that need to be saved/restored. */ |
404 | static const uint16_t regs[] = { |
405 | AR9285_AN_TOP3, |
406 | AR9285_AN_RXTXBB1, |
407 | AR9285_AN_RF2G1, |
408 | AR9285_AN_RF2G2, |
409 | AR9285_AN_TOP2, |
410 | AR9285_AN_RF2G8, |
411 | AR9285_AN_RF2G7 |
412 | }; |
413 | uint32_t svg[7], reg, ccomp_svg; |
414 | size_t i; |
415 | |
416 | /* No PA calibration needed for high power solutions. */ |
417 | if (AR_SREV_9285(sc) && |
418 | ((struct ar9285_base_eep_header *)sc->sc_eep)->txGainType == |
419 | AR_EEP_TXGAIN_HIGH_POWER) /* XXX AR9287? */ |
420 | return; |
421 | |
422 | /* Save registers. */ |
423 | for (i = 0; i < __arraycount(regs); i++) |
424 | svg[i] = AR_READ(sc, regs[i]); |
425 | |
426 | AR_CLRBITS(sc, AR9285_AN_RF2G6, 1); |
427 | AR_SETBITS(sc, AR_PHY(2), 1 << 27); |
428 | |
429 | AR_SETBITS(sc, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC); |
430 | AR_SETBITS(sc, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1); |
431 | AR_SETBITS(sc, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I); |
432 | AR_SETBITS(sc, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF); |
433 | AR_CLRBITS(sc, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL); |
434 | AR_CLRBITS(sc, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB); |
435 | AR_CLRBITS(sc, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL); |
436 | /* Power down PA drivers. */ |
437 | AR_CLRBITS(sc, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1); |
438 | AR_CLRBITS(sc, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2); |
439 | AR_CLRBITS(sc, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT); |
440 | |
441 | reg = AR_READ(sc, AR9285_AN_RF2G8); |
442 | reg = RW(reg, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); |
443 | AR_WRITE(sc, AR9285_AN_RF2G8, reg); |
444 | |
445 | reg = AR_READ(sc, AR9285_AN_RF2G7); |
446 | reg = RW(reg, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); |
447 | AR_WRITE(sc, AR9285_AN_RF2G7, reg); |
448 | |
449 | reg = AR_READ(sc, AR9285_AN_RF2G6); |
450 | /* Save compensation capacitor value. */ |
451 | ccomp_svg = MS(reg, AR9285_AN_RF2G6_CCOMP); |
452 | /* Program compensation capacitor for dynamic PA. */ |
453 | reg = RW(reg, AR9285_AN_RF2G6_CCOMP, 0xf); |
454 | AR_WRITE(sc, AR9285_AN_RF2G6, reg); |
455 | |
456 | AR_WRITE(sc, AR9285_AN_TOP2, AR9285_AN_TOP2_DEFAULT); |
457 | AR_WRITE_BARRIER(sc); |
458 | DELAY(30); |
459 | |
460 | /* Clear offsets 6-1. */ |
461 | AR_CLRBITS(sc, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS_6_1); |
462 | /* Clear offset 0. */ |
463 | AR_CLRBITS(sc, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP); |
464 | /* Set offsets 6-1. */ |
465 | for (i = 6; i >= 1; i--) { |
466 | AR_SETBITS(sc, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS(i)); |
467 | AR_WRITE_BARRIER(sc); |
468 | DELAY(1); |
469 | if (AR_READ(sc, AR9285_AN_RF2G9) & AR9285_AN_RXTXBB1_SPARE9) { |
470 | AR_SETBITS(sc, AR9285_AN_RF2G6, |
471 | AR9285_AN_RF2G6_OFFS(i)); |
472 | } |
473 | else { |
474 | AR_CLRBITS(sc, AR9285_AN_RF2G6, |
475 | AR9285_AN_RF2G6_OFFS(i)); |
476 | } |
477 | } |
478 | /* Set offset 0. */ |
479 | AR_SETBITS(sc, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP); |
480 | AR_WRITE_BARRIER(sc); |
481 | DELAY(1); |
482 | if (AR_READ(sc, AR9285_AN_RF2G9) & AR9285_AN_RXTXBB1_SPARE9) |
483 | AR_SETBITS(sc, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP); |
484 | else |
485 | AR_CLRBITS(sc, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP); |
486 | |
487 | AR_WRITE_BARRIER(sc); |
488 | |
489 | AR_SETBITS(sc, AR9285_AN_RF2G6, 1); |
490 | AR_CLRBITS(sc, AR_PHY(2), 1 << 27); |
491 | |
492 | /* Restore registers. */ |
493 | for (i = 0; i < __arraycount(regs); i++) |
494 | AR_WRITE(sc, regs[i], svg[i]); |
495 | |
496 | /* Restore compensation capacitor value. */ |
497 | reg = AR_READ(sc, AR9285_AN_RF2G6); |
498 | reg = RW(reg, AR9285_AN_RF2G6_CCOMP, ccomp_svg); |
499 | AR_WRITE(sc, AR9285_AN_RF2G6, reg); |
500 | AR_WRITE_BARRIER(sc); |
501 | } |
502 | |
503 | PUBLIC void |
504 | ar9271_pa_calib(struct athn_softc *sc) |
505 | { |
506 | #if NATHN_USB > 0 |
507 | /* List of registers that need to be saved/restored. */ |
508 | static const uint16_t regs[] = { |
509 | AR9285_AN_TOP3, |
510 | AR9285_AN_RXTXBB1, |
511 | AR9285_AN_RF2G1, |
512 | AR9285_AN_RF2G2, |
513 | AR9285_AN_TOP2, |
514 | AR9285_AN_RF2G8, |
515 | AR9285_AN_RF2G7 |
516 | }; |
517 | uint32_t svg[7], reg, rf2g3_svg; |
518 | size_t i; |
519 | |
520 | /* Save registers. */ |
521 | for (i = 0; i < __arraycount(regs); i++) |
522 | svg[i] = AR_READ(sc, regs[i]); |
523 | |
524 | AR_CLRBITS(sc, AR9285_AN_RF2G6, 1); |
525 | AR_SETBITS(sc, AR_PHY(2), 1 << 27); |
526 | |
527 | AR_SETBITS(sc, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC); |
528 | AR_SETBITS(sc, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1); |
529 | AR_SETBITS(sc, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I); |
530 | AR_SETBITS(sc, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF); |
531 | AR_CLRBITS(sc, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL); |
532 | AR_CLRBITS(sc, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB); |
533 | AR_CLRBITS(sc, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL); |
534 | /* Power down PA drivers. */ |
535 | AR_CLRBITS(sc, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1); |
536 | AR_CLRBITS(sc, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2); |
537 | AR_CLRBITS(sc, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT); |
538 | |
539 | reg = AR_READ(sc, AR9285_AN_RF2G8); |
540 | reg = RW(reg, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); |
541 | AR_WRITE(sc, AR9285_AN_RF2G8, reg); |
542 | |
543 | reg = AR_READ(sc, AR9285_AN_RF2G7); |
544 | reg = RW(reg, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); |
545 | AR_WRITE(sc, AR9285_AN_RF2G7, reg); |
546 | |
547 | /* Save compensation capacitor value. */ |
548 | reg = rf2g3_svg = AR_READ(sc, AR9285_AN_RF2G3); |
549 | /* Program compensation capacitor for dynamic PA. */ |
550 | reg = RW(reg, AR9271_AN_RF2G3_CCOMP, 0xfff); |
551 | AR_WRITE(sc, AR9285_AN_RF2G3, reg); |
552 | |
553 | AR_WRITE(sc, AR9285_AN_TOP2, AR9285_AN_TOP2_DEFAULT); |
554 | AR_WRITE_BARRIER(sc); |
555 | DELAY(30); |
556 | |
557 | /* Clear offsets 6-0. */ |
558 | AR_CLRBITS(sc, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS_6_0); |
559 | /* Set offsets 6-1. */ |
560 | for (i = 6; i >= 1; i--) { |
561 | reg = AR_READ(sc, AR9285_AN_RF2G6); |
562 | reg |= AR9271_AN_RF2G6_OFFS(i); |
563 | AR_WRITE(sc, AR9285_AN_RF2G6, reg); |
564 | AR_WRITE_BARRIER(sc); |
565 | DELAY(1); |
566 | if (!(AR_READ(sc, AR9285_AN_RF2G9) & AR9285_AN_RXTXBB1_SPARE9)) |
567 | reg &= ~AR9271_AN_RF2G6_OFFS(i); |
568 | AR_WRITE(sc, AR9285_AN_RF2G6, reg); |
569 | } |
570 | AR_WRITE_BARRIER(sc); |
571 | |
572 | AR_SETBITS(sc, AR9285_AN_RF2G6, 1); |
573 | AR_CLRBITS(sc, AR_PHY(2), 1 << 27); |
574 | |
575 | /* Restore registers. */ |
576 | for (i = 0; i < __arraycount(regs); i++) |
577 | AR_WRITE(sc, regs[i], svg[i]); |
578 | |
579 | /* Restore compensation capacitor value. */ |
580 | AR_WRITE(sc, AR9285_AN_RF2G3, rf2g3_svg); |
581 | AR_WRITE_BARRIER(sc); |
582 | #endif /* NATHN_USB */ |
583 | } |
584 | |
585 | /* |
586 | * Carrier Leakage Calibration. |
587 | */ |
588 | int |
589 | ar9285_cl_cal(struct athn_softc *sc, struct ieee80211_channel *c, |
590 | struct ieee80211_channel *extc) |
591 | { |
592 | int ntries; |
593 | |
594 | AR_SETBITS(sc, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); |
595 | #ifndef IEEE80211_NO_HT |
596 | if (0 && extc == NULL) { /* XXX IS_CHAN_HT20!! */ |
597 | AR_SETBITS(sc, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); |
598 | AR_SETBITS(sc, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); |
599 | AR_CLRBITS(sc, AR_PHY_AGC_CONTROL, |
600 | AR_PHY_AGC_CONTROL_FLTR_CAL); |
601 | AR_CLRBITS(sc, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); |
602 | AR_SETBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); |
603 | for (ntries = 0; ntries < 10000; ntries++) { |
604 | if (!(AR_READ(sc, AR_PHY_AGC_CONTROL) & |
605 | AR_PHY_AGC_CONTROL_CAL)) |
606 | break; |
607 | DELAY(10); |
608 | } |
609 | if (ntries == 10000) |
610 | return ETIMEDOUT; |
611 | AR_CLRBITS(sc, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); |
612 | AR_CLRBITS(sc, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); |
613 | AR_CLRBITS(sc, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); |
614 | } |
615 | #endif |
616 | AR_CLRBITS(sc, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); |
617 | AR_SETBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); |
618 | AR_SETBITS(sc, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); |
619 | AR_SETBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); |
620 | for (ntries = 0; ntries < 10000; ntries++) { |
621 | if (!(AR_READ(sc, AR_PHY_AGC_CONTROL) & |
622 | AR_PHY_AGC_CONTROL_CAL)) |
623 | break; |
624 | DELAY(10); |
625 | } |
626 | if (ntries == 10000) |
627 | return ETIMEDOUT; |
628 | AR_SETBITS(sc, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); |
629 | AR_CLRBITS(sc, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); |
630 | AR_CLRBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); |
631 | AR_WRITE_BARRIER(sc); |
632 | return 0; |
633 | } |
634 | |
635 | PUBLIC void |
636 | ar9271_load_ani(struct athn_softc *sc) |
637 | { |
638 | |
639 | #if NATHN_USB > 0 |
640 | /* Write ANI registers. */ |
641 | AR_WRITE(sc, AR_PHY_DESIRED_SZ, 0x6d4000e2); |
642 | AR_WRITE(sc, AR_PHY_AGC_CTL1, 0x3139605e); |
643 | AR_WRITE(sc, AR_PHY_FIND_SIG, 0x7ec84d2e); |
644 | AR_WRITE(sc, AR_PHY_SFCORR_LOW, 0x06903881); |
645 | AR_WRITE(sc, AR_PHY_SFCORR, 0x5ac640d0); |
646 | AR_WRITE(sc, AR_PHY_CCK_DETECT, 0x803e68c8); |
647 | AR_WRITE(sc, AR_PHY_TIMING5, 0xd00a8007); |
648 | AR_WRITE(sc, AR_PHY_SFCORR_EXT, 0x05eea6d4); |
649 | AR_WRITE_BARRIER(sc); |
650 | #endif /* NATHN_USB */ |
651 | } |
652 | |
653 | int |
654 | ar9285_init_calib(struct athn_softc *sc, struct ieee80211_channel *c, |
655 | struct ieee80211_channel *extc) |
656 | { |
657 | uint32_t reg, mask, clcgain, rf2g5_svg; |
658 | int i, maxgain, nclcs, thresh, error; |
659 | |
660 | /* Do carrier leakage calibration. */ |
661 | if ((error = ar9285_cl_cal(sc, c, extc)) != 0) |
662 | return error; |
663 | |
664 | /* Workaround for high temperature is not applicable on AR9271. */ |
665 | if (AR_SREV_9271(sc)) |
666 | return 0; |
667 | |
668 | mask = 0; |
669 | nclcs = 0; |
670 | reg = AR_READ(sc, AR_PHY_TX_PWRCTRL7); |
671 | maxgain = MS(reg, AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX); |
672 | for (i = 0; i <= maxgain; i++) { |
673 | reg = AR_READ(sc, AR_PHY_TX_GAIN_TBL(i)); |
674 | clcgain = MS(reg, AR_PHY_TX_GAIN_CLC); |
675 | /* NB: clcgain <= 0xf. */ |
676 | if (!(mask & (1 << clcgain))) { |
677 | mask |= 1 << clcgain; |
678 | nclcs++; |
679 | } |
680 | } |
681 | thresh = 0; |
682 | for (i = 0; i < nclcs; i++) { |
683 | reg = AR_READ(sc, AR_PHY_CLC_TBL(i)); |
684 | if (MS(reg, AR_PHY_CLC_I0) == 0) |
685 | thresh++; |
686 | if (MS(reg, AR_PHY_CLC_Q0) == 0) |
687 | thresh++; |
688 | } |
689 | if (thresh <= AR9285_CL_CAL_REDO_THRESH) |
690 | return 0; /* No need to redo. */ |
691 | |
692 | /* Threshold reached, redo carrier leakage calibration. */ |
693 | DPRINTFN(DBG_INIT, sc, "CLC threshold=%d\n" , thresh); |
694 | rf2g5_svg = reg = AR_READ(sc, AR9285_AN_RF2G5); |
695 | if ((AR_READ(sc, AR_AN_SYNTH9) & 0x7) == 0x1) /* XE rev. */ |
696 | reg = RW(reg, AR9285_AN_RF2G5_IC50TX, 0x5); |
697 | else |
698 | reg = RW(reg, AR9285_AN_RF2G5_IC50TX, 0x4); |
699 | AR_WRITE(sc, AR9285_AN_RF2G5, reg); |
700 | AR_WRITE_BARRIER(sc); |
701 | error = ar9285_cl_cal(sc, c, extc); |
702 | AR_WRITE(sc, AR9285_AN_RF2G5, rf2g5_svg); |
703 | AR_WRITE_BARRIER(sc); |
704 | return error; |
705 | } |
706 | |
707 | Static void |
708 | ar9285_get_pdadcs(struct athn_softc *sc, struct ieee80211_channel *c, |
709 | int nxpdgains, uint8_t overlap, uint8_t *boundaries, uint8_t *pdadcs) |
710 | { |
711 | const struct ar9285_eeprom *eep = sc->sc_eep; |
712 | const struct ar9285_cal_data_per_freq *pierdata; |
713 | const uint8_t *pierfreq; |
714 | struct athn_pier lopier, hipier; |
715 | uint8_t fbin; |
716 | int i, lo, hi, npiers; |
717 | |
718 | pierfreq = eep->calFreqPier2G; |
719 | pierdata = eep->calPierData2G; |
720 | npiers = AR9285_NUM_2G_CAL_PIERS; |
721 | |
722 | /* Find channel in ROM pier table. */ |
723 | fbin = athn_chan2fbin(c); |
724 | athn_get_pier_ival(fbin, pierfreq, npiers, &lo, &hi); |
725 | |
726 | lopier.fbin = pierfreq[lo]; |
727 | hipier.fbin = pierfreq[hi]; |
728 | for (i = 0; i < nxpdgains; i++) { |
729 | lopier.pwr[i] = pierdata[lo].pwrPdg[i]; |
730 | lopier.vpd[i] = pierdata[lo].vpdPdg[i]; |
731 | hipier.pwr[i] = pierdata[lo].pwrPdg[i]; |
732 | hipier.vpd[i] = pierdata[lo].vpdPdg[i]; |
733 | } |
734 | ar5008_get_pdadcs(sc, fbin, &lopier, &hipier, nxpdgains, |
735 | AR9285_PD_GAIN_ICEPTS, overlap, boundaries, pdadcs); |
736 | } |
737 | |
738 | Static void |
739 | ar9285_set_power_calib(struct athn_softc *sc, struct ieee80211_channel *c) |
740 | { |
741 | const struct ar9285_eeprom *eep = sc->sc_eep; |
742 | uint8_t boundaries[AR_PD_GAINS_IN_MASK]; |
743 | uint8_t pdadcs[AR_NUM_PDADC_VALUES]; |
744 | uint8_t xpdgains[AR9285_NUM_PD_GAINS]; |
745 | uint8_t overlap; |
746 | uint32_t reg; |
747 | int i, nxpdgains; |
748 | |
749 | if (sc->sc_eep_rev < AR_EEP_MINOR_VER_2) { |
750 | overlap = MS(AR_READ(sc, AR_PHY_TPCRG5), |
751 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP); |
752 | } |
753 | else |
754 | overlap = eep->modalHeader.pdGainOverlap; |
755 | |
756 | nxpdgains = 0; |
757 | memset(xpdgains, 0, sizeof(xpdgains)); |
758 | for (i = AR9285_PD_GAINS_IN_MASK - 1; i >= 0; i--) { |
759 | if (nxpdgains >= AR9285_NUM_PD_GAINS) |
760 | break; |
761 | if (eep->modalHeader.xpdGain & (1 << i)) |
762 | xpdgains[nxpdgains++] = i; |
763 | } |
764 | reg = AR_READ(sc, AR_PHY_TPCRG1); |
765 | reg = RW(reg, AR_PHY_TPCRG1_NUM_PD_GAIN, nxpdgains - 1); |
766 | reg = RW(reg, AR_PHY_TPCRG1_PD_GAIN_1, xpdgains[0]); |
767 | reg = RW(reg, AR_PHY_TPCRG1_PD_GAIN_2, xpdgains[1]); |
768 | AR_WRITE(sc, AR_PHY_TPCRG1, reg); |
769 | |
770 | /* NB: No open loop power control for AR9285. */ |
771 | ar9285_get_pdadcs(sc, c, nxpdgains, overlap, boundaries, pdadcs); |
772 | |
773 | /* Write boundaries. */ |
774 | reg = SM(AR_PHY_TPCRG5_PD_GAIN_OVERLAP, overlap); |
775 | reg |= SM(AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1, boundaries[0]); |
776 | reg |= SM(AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2, boundaries[1]); |
777 | reg |= SM(AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3, boundaries[2]); |
778 | reg |= SM(AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4, boundaries[3]); |
779 | AR_WRITE(sc, AR_PHY_TPCRG5, reg); |
780 | |
781 | /* Write PDADC values. */ |
782 | for (i = 0; i < AR_NUM_PDADC_VALUES; i += 4) { |
783 | AR_WRITE(sc, AR_PHY_PDADC_TBL_BASE + i, |
784 | pdadcs[i + 0] << 0 | |
785 | pdadcs[i + 1] << 8 | |
786 | pdadcs[i + 2] << 16 | |
787 | pdadcs[i + 3] << 24); |
788 | } |
789 | AR_WRITE_BARRIER(sc); |
790 | } |
791 | |
792 | Static void |
793 | ar9285_set_txpower(struct athn_softc *sc, struct ieee80211_channel *c, |
794 | struct ieee80211_channel *extc) |
795 | { |
796 | const struct ar9285_eeprom *eep = sc->sc_eep; |
797 | #ifdef notyet |
798 | const struct ar9285_modal_eep_header *modal = &eep->modalHeader; |
799 | #endif |
800 | uint8_t tpow_cck[4], tpow_ofdm[4]; |
801 | #ifndef IEEE80211_NO_HT |
802 | uint8_t tpow_cck_ext[4], tpow_ofdm_ext[4]; |
803 | uint8_t tpow_ht20[8], tpow_ht40[8]; |
804 | uint8_t ht40inc; |
805 | #endif |
806 | int16_t power[ATHN_POWER_COUNT]; |
807 | int i; |
808 | |
809 | ar9285_set_power_calib(sc, c); |
810 | |
811 | #ifdef notyet |
812 | /* Compute transmit power reduction due to antenna gain. */ |
813 | uint16_t max_ant_gain = modal->antennaGain; |
814 | /* XXX */ |
815 | #endif |
816 | |
817 | /* Get CCK target powers. */ |
818 | ar5008_get_lg_tpow(sc, c, AR_CTL_11B, eep->calTargetPowerCck, |
819 | AR9285_NUM_2G_CCK_TARGET_POWERS, tpow_cck); |
820 | |
821 | /* Get OFDM target powers. */ |
822 | ar5008_get_lg_tpow(sc, c, AR_CTL_11G, eep->calTargetPower2G, |
823 | AR9285_NUM_2G_20_TARGET_POWERS, tpow_ofdm); |
824 | |
825 | #ifndef IEEE80211_NO_HT |
826 | /* Get HT-20 target powers. */ |
827 | ar5008_get_ht_tpow(sc, c, AR_CTL_2GHT20, eep->calTargetPower2GHT20, |
828 | AR9285_NUM_2G_20_TARGET_POWERS, tpow_ht20); |
829 | |
830 | if (extc != NULL) { |
831 | /* Get HT-40 target powers. */ |
832 | ar5008_get_ht_tpow(sc, c, AR_CTL_2GHT40, |
833 | eep->calTargetPower2GHT40, AR9285_NUM_2G_40_TARGET_POWERS, |
834 | tpow_ht40); |
835 | |
836 | /* Get secondary channel CCK target powers. */ |
837 | ar5008_get_lg_tpow(sc, extc, AR_CTL_11B, |
838 | eep->calTargetPowerCck, AR9285_NUM_2G_CCK_TARGET_POWERS, |
839 | tpow_cck_ext); |
840 | |
841 | /* Get secondary channel OFDM target powers. */ |
842 | ar5008_get_lg_tpow(sc, extc, AR_CTL_11G, |
843 | eep->calTargetPower2G, AR9285_NUM_2G_20_TARGET_POWERS, |
844 | tpow_ofdm_ext); |
845 | } |
846 | #endif |
847 | |
848 | memset(power, 0, sizeof(power)); |
849 | /* Shuffle target powers accross transmit rates. */ |
850 | power[ATHN_POWER_OFDM6 ] = |
851 | power[ATHN_POWER_OFDM9 ] = |
852 | power[ATHN_POWER_OFDM12 ] = |
853 | power[ATHN_POWER_OFDM18 ] = |
854 | power[ATHN_POWER_OFDM24 ] = tpow_ofdm[0]; |
855 | power[ATHN_POWER_OFDM36 ] = tpow_ofdm[1]; |
856 | power[ATHN_POWER_OFDM48 ] = tpow_ofdm[2]; |
857 | power[ATHN_POWER_OFDM54 ] = tpow_ofdm[3]; |
858 | power[ATHN_POWER_XR ] = tpow_ofdm[0]; |
859 | power[ATHN_POWER_CCK1_LP ] = tpow_cck[0]; |
860 | power[ATHN_POWER_CCK2_LP ] = |
861 | power[ATHN_POWER_CCK2_SP ] = tpow_cck[1]; |
862 | power[ATHN_POWER_CCK55_LP] = |
863 | power[ATHN_POWER_CCK55_SP] = tpow_cck[2]; |
864 | power[ATHN_POWER_CCK11_LP] = |
865 | power[ATHN_POWER_CCK11_SP] = tpow_cck[3]; |
866 | #ifndef IEEE80211_NO_HT |
867 | for (i = 0; i < __arraycount(tpow_ht20); i++) |
868 | power[ATHN_POWER_HT20(i)] = tpow_ht20[i]; |
869 | if (extc != NULL) { |
870 | /* Correct PAR difference between HT40 and HT20/Legacy. */ |
871 | if (sc->sc_eep_rev >= AR_EEP_MINOR_VER_2) |
872 | ht40inc = modal->ht40PowerIncForPdadc; |
873 | else |
874 | ht40inc = AR_HT40_POWER_INC_FOR_PDADC; |
875 | for (i = 0; i < __arraycount(tpow_ht40); i++) |
876 | power[ATHN_POWER_HT40(i)] = tpow_ht40[i] + ht40inc; |
877 | power[ATHN_POWER_OFDM_DUP] = tpow_ht40[0]; |
878 | power[ATHN_POWER_CCK_DUP ] = tpow_ht40[0]; |
879 | power[ATHN_POWER_OFDM_EXT] = tpow_ofdm_ext[0]; |
880 | power[ATHN_POWER_CCK_EXT ] = tpow_cck_ext[0]; |
881 | } |
882 | #endif |
883 | |
884 | for (i = 0; i < ATHN_POWER_COUNT; i++) { |
885 | power[i] -= AR_PWR_TABLE_OFFSET_DB * 2; /* In half dB. */ |
886 | if (power[i] > AR_MAX_RATE_POWER) |
887 | power[i] = AR_MAX_RATE_POWER; |
888 | } |
889 | |
890 | /* Commit transmit power values to hardware. */ |
891 | ar5008_write_txpower(sc, power); |
892 | } |
893 | |