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