Line data Source code
1 : /* $OpenBSD: ar9280.c,v 1.26 2017/01/12 16:32:28 stsp Exp $ */
2 :
3 : /*-
4 : * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr>
5 : * Copyright (c) 2008-2009 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 AR9220, AR9223, AR9280 and AR9281 chipsets.
23 : */
24 :
25 : #include "bpfilter.h"
26 :
27 : #include <sys/param.h>
28 : #include <sys/sockio.h>
29 : #include <sys/mbuf.h>
30 : #include <sys/kernel.h>
31 : #include <sys/socket.h>
32 : #include <sys/systm.h>
33 : #include <sys/malloc.h>
34 : #include <sys/queue.h>
35 : #include <sys/timeout.h>
36 : #include <sys/conf.h>
37 : #include <sys/device.h>
38 : #include <sys/endian.h>
39 :
40 : #include <machine/bus.h>
41 : #include <machine/intr.h>
42 :
43 : #if NBPFILTER > 0
44 : #include <net/bpf.h>
45 : #endif
46 : #include <net/if.h>
47 : #include <net/if_media.h>
48 :
49 : #include <netinet/in.h>
50 : #include <netinet/if_ether.h>
51 :
52 : #include <net80211/ieee80211_var.h>
53 : #include <net80211/ieee80211_amrr.h>
54 : #include <net80211/ieee80211_mira.h>
55 : #include <net80211/ieee80211_radiotap.h>
56 :
57 : #include <dev/ic/athnreg.h>
58 : #include <dev/ic/athnvar.h>
59 :
60 : #include <dev/ic/ar5008reg.h>
61 : #include <dev/ic/ar5416reg.h> /* We share the ROM layout. */
62 : #include <dev/ic/ar9280reg.h>
63 :
64 : int ar9280_attach(struct athn_softc *);
65 : void ar9280_setup(struct athn_softc *);
66 : int ar9280_set_synth(struct athn_softc *, struct ieee80211_channel *,
67 : struct ieee80211_channel *);
68 : void ar9280_init_from_rom(struct athn_softc *, struct ieee80211_channel *,
69 : struct ieee80211_channel *);
70 : void ar9280_spur_mitigate(struct athn_softc *, struct ieee80211_channel *,
71 : struct ieee80211_channel *);
72 : void ar9280_olpc_get_pdadcs(struct athn_softc *,
73 : struct ieee80211_channel *, int, uint8_t *, uint8_t *, uint8_t *);
74 : void ar9280_reset_rx_gain(struct athn_softc *, struct ieee80211_channel *);
75 : void ar9280_reset_tx_gain(struct athn_softc *, struct ieee80211_channel *);
76 : void ar9280_olpc_init(struct athn_softc *);
77 : void ar9280_olpc_temp_compensation(struct athn_softc *);
78 :
79 : /* Extern functions. */
80 : uint8_t athn_chan2fbin(struct ieee80211_channel *);
81 : void athn_get_pier_ival(uint8_t, const uint8_t *, int, int *, int *);
82 : int ar5008_attach(struct athn_softc *);
83 : void ar5008_set_viterbi_mask(struct athn_softc *, int);
84 : void ar5416_swap_rom(struct athn_softc *);
85 : void ar5416_set_txpower(struct athn_softc *, struct ieee80211_channel *,
86 : struct ieee80211_channel *);
87 : const struct ar_spur_chan *
88 : ar5416_get_spur_chans(struct athn_softc *, int);
89 :
90 :
91 : int
92 0 : ar9280_attach(struct athn_softc *sc)
93 : {
94 0 : sc->eep_base = AR5416_EEP_START_LOC;
95 0 : sc->eep_size = sizeof(struct ar5416_eeprom);
96 0 : sc->def_nf = AR9280_PHY_CCA_MAX_GOOD_VALUE;
97 0 : sc->ngpiopins = (sc->flags & ATHN_FLAG_USB) ? 16 : 10;
98 0 : sc->led_pin = 1;
99 0 : sc->workaround = AR9280_WA_DEFAULT;
100 0 : sc->ops.setup = ar9280_setup;
101 0 : sc->ops.swap_rom = ar5416_swap_rom;
102 0 : sc->ops.init_from_rom = ar9280_init_from_rom;
103 0 : sc->ops.set_txpower = ar5416_set_txpower;
104 0 : sc->ops.set_synth = ar9280_set_synth;
105 0 : sc->ops.spur_mitigate = ar9280_spur_mitigate;
106 0 : sc->ops.get_spur_chans = ar5416_get_spur_chans;
107 0 : sc->ops.olpc_init = ar9280_olpc_init;
108 0 : sc->ops.olpc_temp_compensation = ar9280_olpc_temp_compensation;
109 0 : sc->ini = &ar9280_2_0_ini;
110 0 : sc->serdes = &ar9280_2_0_serdes;
111 :
112 0 : return (ar5008_attach(sc));
113 : }
114 :
115 : void
116 0 : ar9280_setup(struct athn_softc *sc)
117 : {
118 0 : const struct ar5416_eeprom *eep = sc->eep;
119 : uint8_t type;
120 :
121 : /* Determine if open loop power control should be used. */
122 0 : if (sc->eep_rev >= AR_EEP_MINOR_VER_19 &&
123 0 : eep->baseEepHeader.openLoopPwrCntl)
124 0 : sc->flags |= ATHN_FLAG_OLPC;
125 :
126 : /* Determine if fast PLL clock is supported. */
127 0 : if (AR_SREV_9280_20(sc) &&
128 0 : (sc->eep_rev <= AR_EEP_MINOR_VER_16 ||
129 0 : eep->baseEepHeader.fastClk5g))
130 0 : sc->flags |= ATHN_FLAG_FAST_PLL_CLOCK;
131 :
132 : /*
133 : * Determine if initialization value for AR_AN_TOP2 must be fixed.
134 : * This is required for some AR9220 devices such as Ubiquiti SR71-12.
135 : */
136 0 : if (AR_SREV_9280_20(sc) &&
137 0 : sc->eep_rev > AR_EEP_MINOR_VER_10 &&
138 0 : !eep->baseEepHeader.pwdclkind) {
139 : DPRINTF(("AR_AN_TOP2 fixup required\n"));
140 0 : sc->flags |= ATHN_FLAG_AN_TOP2_FIXUP;
141 0 : }
142 :
143 0 : if (AR_SREV_9280_20(sc)) {
144 : /* Check if we have a valid rxGainType field in ROM. */
145 0 : if (sc->eep_rev >= AR_EEP_MINOR_VER_17) {
146 : /* Select initialization values based on ROM. */
147 0 : type = eep->baseEepHeader.rxGainType;
148 : DPRINTF(("Rx gain type=0x%x\n", type));
149 0 : if (type == AR5416_EEP_RXGAIN_23DB_BACKOFF)
150 0 : sc->rx_gain = &ar9280_2_0_rx_gain_23db_backoff;
151 0 : else if (type == AR5416_EEP_RXGAIN_13DB_BACKOFF)
152 0 : sc->rx_gain = &ar9280_2_0_rx_gain_13db_backoff;
153 : else
154 0 : sc->rx_gain = &ar9280_2_0_rx_gain;
155 : } else
156 0 : sc->rx_gain = &ar9280_2_0_rx_gain;
157 :
158 : /* Check if we have a valid txGainType field in ROM. */
159 0 : if (sc->eep_rev >= AR_EEP_MINOR_VER_19) {
160 : /* Select initialization values based on ROM. */
161 0 : type = eep->baseEepHeader.txGainType;
162 : DPRINTF(("Tx gain type=0x%x\n", type));
163 0 : if (type == AR_EEP_TXGAIN_HIGH_POWER)
164 0 : sc->tx_gain = &ar9280_2_0_tx_gain_high_power;
165 : else
166 0 : sc->tx_gain = &ar9280_2_0_tx_gain;
167 : } else
168 0 : sc->tx_gain = &ar9280_2_0_tx_gain;
169 : }
170 0 : }
171 :
172 : int
173 0 : ar9280_set_synth(struct athn_softc *sc, struct ieee80211_channel *c,
174 : struct ieee80211_channel *extc)
175 : {
176 : uint32_t phy, reg, ndiv = 0;
177 0 : uint32_t freq = c->ic_freq;
178 :
179 0 : phy = AR_READ(sc, AR9280_PHY_SYNTH_CONTROL) & ~0x3fffffff;
180 :
181 0 : if (IEEE80211_IS_CHAN_2GHZ(c)) {
182 0 : phy |= (freq << 16) / 15;
183 0 : phy |= AR9280_BMODE | AR9280_FRACMODE;
184 :
185 0 : if (AR_SREV_9287_11_OR_LATER(sc)) {
186 : /* NB: Magic values from the Linux driver. */
187 0 : if (freq == 2484) { /* Channel 14. */
188 : /* Japanese regulatory requirements. */
189 0 : AR_WRITE(sc, AR_PHY(637), 0x00000000);
190 0 : AR_WRITE(sc, AR_PHY(638), 0xefff0301);
191 0 : AR_WRITE(sc, AR_PHY(639), 0xca9228ee);
192 0 : } else {
193 0 : AR_WRITE(sc, AR_PHY(637), 0x00fffeff);
194 0 : AR_WRITE(sc, AR_PHY(638), 0x00f5f9ff);
195 0 : AR_WRITE(sc, AR_PHY(639), 0xb79f6427);
196 : }
197 : } else {
198 0 : reg = AR_READ(sc, AR_PHY_CCK_TX_CTRL);
199 0 : if (freq == 2484) /* Channel 14. */
200 0 : reg |= AR_PHY_CCK_TX_CTRL_JAPAN;
201 : else
202 0 : reg &= ~AR_PHY_CCK_TX_CTRL_JAPAN;
203 0 : AR_WRITE(sc, AR_PHY_CCK_TX_CTRL, reg);
204 : }
205 : } else {
206 0 : if (AR_SREV_9285_10_OR_LATER(sc) ||
207 0 : sc->eep_rev < AR_EEP_MINOR_VER_22 ||
208 0 : !((struct ar5416_base_eep_header *)sc->eep)->frac_n_5g) {
209 0 : if ((freq % 20) == 0) {
210 0 : ndiv = (freq * 3) / 60;
211 0 : phy |= SM(AR9280_AMODE_REFSEL, 3);
212 0 : } else if ((freq % 10) == 0) {
213 0 : ndiv = (freq * 6) / 60;
214 0 : phy |= SM(AR9280_AMODE_REFSEL, 2);
215 0 : }
216 : }
217 0 : if (ndiv != 0) {
218 0 : phy |= (ndiv & 0x1ff) << 17;
219 0 : phy |= (ndiv & ~0x1ff) * 2;
220 0 : } else {
221 0 : phy |= (freq << 15) / 15;
222 0 : phy |= AR9280_FRACMODE;
223 :
224 0 : reg = AR_READ(sc, AR_AN_SYNTH9);
225 0 : reg = RW(reg, AR_AN_SYNTH9_REFDIVA, 1);
226 0 : AR_WRITE(sc, AR_AN_SYNTH9, reg);
227 : }
228 : }
229 0 : AR_WRITE_BARRIER(sc);
230 : DPRINTFN(4, ("AR9280_PHY_SYNTH_CONTROL=0x%08x\n", phy));
231 0 : AR_WRITE(sc, AR9280_PHY_SYNTH_CONTROL, phy);
232 0 : AR_WRITE_BARRIER(sc);
233 0 : return (0);
234 : }
235 :
236 : void
237 0 : ar9280_init_from_rom(struct athn_softc *sc, struct ieee80211_channel *c,
238 : struct ieee80211_channel *extc)
239 : {
240 : static const uint32_t chainoffset[] = { 0x0000, 0x2000, 0x1000 };
241 0 : const struct ar5416_eeprom *eep = sc->eep;
242 : const struct ar5416_modal_eep_header *modal;
243 : uint32_t reg, offset;
244 : uint8_t txRxAtten;
245 : int i;
246 :
247 0 : modal = &eep->modalHeader[IEEE80211_IS_CHAN_2GHZ(c)];
248 :
249 0 : AR_WRITE(sc, AR_PHY_SWITCH_COM, modal->antCtrlCommon);
250 :
251 0 : for (i = 0; i < AR9280_MAX_CHAINS; i++) {
252 0 : if (sc->rxchainmask == 0x5 || sc->txchainmask == 0x5)
253 0 : offset = chainoffset[i];
254 : else
255 0 : offset = i * 0x1000;
256 :
257 0 : AR_WRITE(sc, AR_PHY_SWITCH_CHAIN_0 + offset,
258 : modal->antCtrlChain[i]);
259 :
260 0 : reg = AR_READ(sc, AR_PHY_TIMING_CTRL4_0 + offset);
261 0 : reg = RW(reg, AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,
262 : modal->iqCalICh[i]);
263 0 : reg = RW(reg, AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,
264 : modal->iqCalQCh[i]);
265 0 : AR_WRITE(sc, AR_PHY_TIMING_CTRL4_0 + offset, reg);
266 :
267 0 : if (sc->eep_rev >= AR_EEP_MINOR_VER_3) {
268 0 : reg = AR_READ(sc, AR_PHY_GAIN_2GHZ + offset);
269 0 : reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
270 : modal->bswMargin[i]);
271 0 : reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN1_DB,
272 : modal->bswAtten[i]);
273 0 : reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
274 : modal->xatten2Margin[i]);
275 0 : reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN2_DB,
276 : modal->xatten2Db[i]);
277 0 : AR_WRITE(sc, AR_PHY_GAIN_2GHZ + offset, reg);
278 0 : }
279 0 : if (sc->eep_rev >= AR_EEP_MINOR_VER_3)
280 0 : txRxAtten = modal->txRxAttenCh[i];
281 : else /* Workaround for ROM versions < 14.3. */
282 0 : txRxAtten = IEEE80211_IS_CHAN_2GHZ(c) ? 23 : 44;
283 0 : reg = AR_READ(sc, AR_PHY_RXGAIN + offset);
284 0 : reg = RW(reg, AR9280_PHY_RXGAIN_TXRX_ATTEN,
285 : txRxAtten);
286 0 : reg = RW(reg, AR9280_PHY_RXGAIN_TXRX_MARGIN,
287 : modal->rxTxMarginCh[i]);
288 0 : AR_WRITE(sc, AR_PHY_RXGAIN + offset, reg);
289 : }
290 0 : if (IEEE80211_IS_CHAN_2GHZ(c)) {
291 0 : reg = AR_READ(sc, AR_AN_RF2G1_CH0);
292 0 : reg = RW(reg, AR_AN_RF2G1_CH0_OB, modal->ob);
293 0 : reg = RW(reg, AR_AN_RF2G1_CH0_DB, modal->db);
294 0 : AR_WRITE(sc, AR_AN_RF2G1_CH0, reg);
295 0 : AR_WRITE_BARRIER(sc);
296 0 : DELAY(100);
297 :
298 0 : reg = AR_READ(sc, AR_AN_RF2G1_CH1);
299 0 : reg = RW(reg, AR_AN_RF2G1_CH1_OB, modal->ob_ch1);
300 0 : reg = RW(reg, AR_AN_RF2G1_CH1_DB, modal->db_ch1);
301 0 : AR_WRITE(sc, AR_AN_RF2G1_CH1, reg);
302 0 : AR_WRITE_BARRIER(sc);
303 0 : DELAY(100);
304 0 : } else {
305 0 : reg = AR_READ(sc, AR_AN_RF5G1_CH0);
306 0 : reg = RW(reg, AR_AN_RF5G1_CH0_OB5, modal->ob);
307 0 : reg = RW(reg, AR_AN_RF5G1_CH0_DB5, modal->db);
308 0 : AR_WRITE(sc, AR_AN_RF5G1_CH0, reg);
309 0 : AR_WRITE_BARRIER(sc);
310 0 : DELAY(100);
311 :
312 0 : reg = AR_READ(sc, AR_AN_RF5G1_CH1);
313 0 : reg = RW(reg, AR_AN_RF5G1_CH1_OB5, modal->ob_ch1);
314 0 : reg = RW(reg, AR_AN_RF5G1_CH1_DB5, modal->db_ch1);
315 0 : AR_WRITE(sc, AR_AN_RF5G1_CH1, reg);
316 0 : AR_WRITE_BARRIER(sc);
317 0 : DELAY(100);
318 : }
319 0 : reg = AR_READ(sc, AR_AN_TOP2);
320 0 : if ((sc->flags & ATHN_FLAG_USB) && IEEE80211_IS_CHAN_5GHZ(c)) {
321 : /*
322 : * Hardcode the output voltage of x-PA bias LDO to the
323 : * lowest value for UB94 such that the card doesn't get
324 : * too hot.
325 : */
326 0 : reg = RW(reg, AR_AN_TOP2_XPABIAS_LVL, 0);
327 0 : } else
328 0 : reg = RW(reg, AR_AN_TOP2_XPABIAS_LVL, modal->xpaBiasLvl);
329 0 : if (modal->flagBits & AR5416_EEP_FLAG_LOCALBIAS)
330 0 : reg |= AR_AN_TOP2_LOCALBIAS;
331 : else
332 0 : reg &= ~AR_AN_TOP2_LOCALBIAS;
333 0 : AR_WRITE(sc, AR_AN_TOP2, reg);
334 0 : AR_WRITE_BARRIER(sc);
335 0 : DELAY(100);
336 :
337 0 : reg = AR_READ(sc, AR_PHY_XPA_CFG);
338 0 : if (modal->flagBits & AR5416_EEP_FLAG_FORCEXPAON)
339 0 : reg |= AR_PHY_FORCE_XPA_CFG;
340 : else
341 0 : reg &= ~AR_PHY_FORCE_XPA_CFG;
342 0 : AR_WRITE(sc, AR_PHY_XPA_CFG, reg);
343 :
344 0 : reg = AR_READ(sc, AR_PHY_SETTLING);
345 0 : reg = RW(reg, AR_PHY_SETTLING_SWITCH, modal->switchSettling);
346 0 : AR_WRITE(sc, AR_PHY_SETTLING, reg);
347 :
348 0 : reg = AR_READ(sc, AR_PHY_DESIRED_SZ);
349 0 : reg = RW(reg, AR_PHY_DESIRED_SZ_ADC, modal->adcDesiredSize);
350 0 : AR_WRITE(sc, AR_PHY_DESIRED_SZ, reg);
351 :
352 0 : reg = SM(AR_PHY_RF_CTL4_TX_END_XPAA_OFF, modal->txEndToXpaOff);
353 0 : reg |= SM(AR_PHY_RF_CTL4_TX_END_XPAB_OFF, modal->txEndToXpaOff);
354 0 : reg |= SM(AR_PHY_RF_CTL4_FRAME_XPAA_ON, modal->txFrameToXpaOn);
355 0 : reg |= SM(AR_PHY_RF_CTL4_FRAME_XPAB_ON, modal->txFrameToXpaOn);
356 0 : AR_WRITE(sc, AR_PHY_RF_CTL4, reg);
357 :
358 0 : reg = AR_READ(sc, AR_PHY_RF_CTL3);
359 0 : reg = RW(reg, AR_PHY_TX_END_TO_A2_RX_ON, modal->txEndToRxOn);
360 0 : AR_WRITE(sc, AR_PHY_RF_CTL3, reg);
361 :
362 0 : reg = AR_READ(sc, AR_PHY_CCA(0));
363 0 : reg = RW(reg, AR9280_PHY_CCA_THRESH62, modal->thresh62);
364 0 : AR_WRITE(sc, AR_PHY_CCA(0), reg);
365 :
366 0 : reg = AR_READ(sc, AR_PHY_EXT_CCA0);
367 0 : reg = RW(reg, AR_PHY_EXT_CCA0_THRESH62, modal->thresh62);
368 0 : AR_WRITE(sc, AR_PHY_EXT_CCA0, reg);
369 :
370 0 : if (sc->eep_rev >= AR_EEP_MINOR_VER_2) {
371 0 : reg = AR_READ(sc, AR_PHY_RF_CTL2);
372 0 : reg = RW(reg, AR_PHY_TX_END_DATA_START,
373 : modal->txFrameToDataStart);
374 0 : reg = RW(reg, AR_PHY_TX_END_PA_ON, modal->txFrameToPaOn);
375 0 : AR_WRITE(sc, AR_PHY_RF_CTL2, reg);
376 0 : }
377 0 : if (sc->eep_rev >= AR_EEP_MINOR_VER_3 && extc != NULL) {
378 : /* Overwrite switch settling with HT-40 value. */
379 0 : reg = AR_READ(sc, AR_PHY_SETTLING);
380 0 : reg = RW(reg, AR_PHY_SETTLING_SWITCH, modal->swSettleHt40);
381 0 : AR_WRITE(sc, AR_PHY_SETTLING, reg);
382 0 : }
383 0 : if (sc->eep_rev >= AR_EEP_MINOR_VER_19) {
384 0 : reg = AR_READ(sc, AR_PHY_CCK_TX_CTRL);
385 0 : reg = RW(reg, AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK,
386 : MS(modal->miscBits, AR5416_EEP_MISC_TX_DAC_SCALE_CCK));
387 0 : AR_WRITE(sc, AR_PHY_CCK_TX_CTRL, reg);
388 0 : }
389 0 : if (AR_SREV_9280_20(sc) &&
390 0 : sc->eep_rev >= AR_EEP_MINOR_VER_20) {
391 0 : reg = AR_READ(sc, AR_AN_TOP1);
392 0 : if (eep->baseEepHeader.dacLpMode &&
393 0 : (IEEE80211_IS_CHAN_2GHZ(c) ||
394 0 : !eep->baseEepHeader.dacHiPwrMode_5G))
395 0 : reg |= AR_AN_TOP1_DACLPMODE;
396 : else
397 0 : reg &= ~AR_AN_TOP1_DACLPMODE;
398 0 : AR_WRITE(sc, AR_AN_TOP1, reg);
399 0 : AR_WRITE_BARRIER(sc);
400 0 : DELAY(100);
401 :
402 0 : reg = AR_READ(sc, AR_PHY_FRAME_CTL);
403 0 : reg = RW(reg, AR_PHY_FRAME_CTL_TX_CLIP,
404 : MS(modal->miscBits, AR5416_EEP_MISC_TX_CLIP));
405 0 : AR_WRITE(sc, AR_PHY_FRAME_CTL, reg);
406 :
407 0 : reg = AR_READ(sc, AR_PHY_TX_PWRCTRL9);
408 0 : reg = RW(reg, AR_PHY_TX_DESIRED_SCALE_CCK,
409 : eep->baseEepHeader.desiredScaleCCK);
410 0 : AR_WRITE(sc, AR_PHY_TX_PWRCTRL9, reg);
411 0 : }
412 0 : AR_WRITE_BARRIER(sc);
413 0 : }
414 :
415 : void
416 0 : ar9280_olpc_get_pdadcs(struct athn_softc *sc, struct ieee80211_channel *c,
417 : int chain, uint8_t *boundaries, uint8_t *pdadcs, uint8_t *txgain)
418 : {
419 0 : const struct ar5416_eeprom *eep = sc->eep;
420 : const struct ar_cal_data_per_freq_olpc *pierdata;
421 : const uint8_t *pierfreq;
422 : uint8_t fbin, pcdac, pwr, idx;
423 0 : int i, lo, hi, npiers;
424 :
425 0 : if (IEEE80211_IS_CHAN_2GHZ(c)) {
426 0 : pierfreq = eep->calFreqPier2G;
427 0 : pierdata = (const struct ar_cal_data_per_freq_olpc *)
428 0 : eep->calPierData2G[chain];
429 : npiers = AR5416_NUM_2G_CAL_PIERS;
430 0 : } else {
431 0 : pierfreq = eep->calFreqPier5G;
432 0 : pierdata = (const struct ar_cal_data_per_freq_olpc *)
433 0 : eep->calPierData5G[chain];
434 : npiers = AR5416_NUM_5G_CAL_PIERS;
435 : }
436 : /* Find channel in ROM pier table. */
437 0 : fbin = athn_chan2fbin(c);
438 0 : athn_get_pier_ival(fbin, pierfreq, npiers, &lo, &hi);
439 :
440 : /* Get average. */
441 0 : pwr = (pierdata[lo].pwrPdg[0][0] + pierdata[hi].pwrPdg[0][0]) / 2;
442 0 : pwr /= 2; /* Convert to dB. */
443 :
444 : /* Find power control digital-to-analog converter (PCDAC) value. */
445 0 : pcdac = pierdata[hi].pcdac[0][0];
446 0 : for (idx = 0; idx < AR9280_TX_GAIN_TABLE_SIZE - 1; idx++)
447 0 : if (pcdac <= sc->tx_gain_tbl[idx])
448 : break;
449 0 : *txgain = idx;
450 :
451 : DPRINTFN(3, ("fbin=%d lo=%d hi=%d pwr=%d pcdac=%d txgain=%d\n",
452 : fbin, lo, hi, pwr, pcdac, idx));
453 :
454 : /* Fill phase domain analog-to-digital converter (PDADC) table. */
455 0 : for (i = 0; i < AR_NUM_PDADC_VALUES; i++)
456 0 : pdadcs[i] = (i < pwr) ? 0x00 : 0xff;
457 :
458 0 : for (i = 0; i < AR_PD_GAINS_IN_MASK; i++)
459 0 : boundaries[i] = AR9280_PD_GAIN_BOUNDARY_DEFAULT;
460 0 : }
461 :
462 : void
463 0 : ar9280_spur_mitigate(struct athn_softc *sc, struct ieee80211_channel *c,
464 : struct ieee80211_channel *extc)
465 : {
466 : const struct ar_spur_chan *spurchans;
467 : int spur, bin, spur_delta_phase, spur_freq_sd, spur_subchannel_sd;
468 : int spur_off, range, i;
469 :
470 : /* NB: Always clear. */
471 0 : AR_CLRBITS(sc, AR_PHY_FORCE_CLKEN_CCK, AR_PHY_FORCE_CLKEN_CCK_MRC_MUX);
472 :
473 0 : range = (extc != NULL) ? 19 : 10;
474 :
475 0 : spurchans = sc->ops.get_spur_chans(sc, IEEE80211_IS_CHAN_2GHZ(c));
476 0 : for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
477 0 : spur = spurchans[i].spurChan;
478 0 : if (spur == AR_NO_SPUR)
479 0 : return; /* XXX disable if it was enabled! */
480 0 : spur /= 10;
481 0 : if (IEEE80211_IS_CHAN_2GHZ(c))
482 0 : spur += AR_BASE_FREQ_2GHZ;
483 : else
484 0 : spur += AR_BASE_FREQ_5GHZ;
485 0 : spur -= c->ic_freq;
486 0 : if (abs(spur) < range)
487 : break;
488 : }
489 0 : if (i == AR_EEPROM_MODAL_SPURS)
490 0 : return; /* XXX disable if it was enabled! */
491 : DPRINTFN(2, ("enabling spur mitigation\n"));
492 :
493 0 : AR_SETBITS(sc, AR_PHY_TIMING_CTRL4_0,
494 : AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |
495 : AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |
496 : AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |
497 : AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK);
498 :
499 0 : AR_WRITE(sc, AR_PHY_SPUR_REG,
500 : AR_PHY_SPUR_REG_MASK_RATE_CNTL |
501 : AR_PHY_SPUR_REG_ENABLE_MASK_PPM |
502 : AR_PHY_SPUR_REG_MASK_RATE_SELECT |
503 : AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |
504 : SM(AR_PHY_SPUR_REG_SPUR_RSSI_THRESH, AR_SPUR_RSSI_THRESH));
505 :
506 0 : if (extc != NULL) {
507 0 : spur_delta_phase = (spur * 262144) / 10;
508 0 : if (spur < 0) {
509 : spur_subchannel_sd = 1;
510 0 : spur_off = spur + 10;
511 0 : } else {
512 : spur_subchannel_sd = 0;
513 0 : spur_off = spur - 10;
514 : }
515 : } else {
516 0 : spur_delta_phase = (spur * 524288) / 10;
517 : spur_subchannel_sd = 0;
518 : spur_off = spur;
519 : }
520 0 : if (IEEE80211_IS_CHAN_2GHZ(c))
521 0 : spur_freq_sd = (spur_off * 2048) / 44;
522 : else
523 0 : spur_freq_sd = (spur_off * 2048) / 40;
524 :
525 0 : AR_WRITE(sc, AR_PHY_TIMING11,
526 : AR_PHY_TIMING11_USE_SPUR_IN_AGC |
527 : SM(AR_PHY_TIMING11_SPUR_FREQ_SD, spur_freq_sd) |
528 : SM(AR_PHY_TIMING11_SPUR_DELTA_PHASE, spur_delta_phase));
529 :
530 0 : AR_WRITE(sc, AR_PHY_SFCORR_EXT,
531 : SM(AR_PHY_SFCORR_SPUR_SUBCHNL_SD, spur_subchannel_sd));
532 0 : AR_WRITE_BARRIER(sc);
533 :
534 0 : bin = spur * 320;
535 0 : ar5008_set_viterbi_mask(sc, bin);
536 0 : }
537 :
538 : void
539 0 : ar9280_reset_rx_gain(struct athn_softc *sc, struct ieee80211_channel *c)
540 : {
541 0 : const struct athn_gain *prog = sc->rx_gain;
542 : const uint32_t *pvals;
543 : int i;
544 :
545 0 : if (IEEE80211_IS_CHAN_2GHZ(c))
546 0 : pvals = prog->vals_2g;
547 : else
548 0 : pvals = prog->vals_5g;
549 0 : for (i = 0; i < prog->nregs; i++)
550 0 : AR_WRITE(sc, prog->regs[i], pvals[i]);
551 0 : }
552 :
553 : void
554 0 : ar9280_reset_tx_gain(struct athn_softc *sc, struct ieee80211_channel *c)
555 : {
556 0 : const struct athn_gain *prog = sc->tx_gain;
557 : const uint32_t *pvals;
558 : int i;
559 :
560 0 : if (IEEE80211_IS_CHAN_2GHZ(c))
561 0 : pvals = prog->vals_2g;
562 : else
563 0 : pvals = prog->vals_5g;
564 0 : for (i = 0; i < prog->nregs; i++)
565 0 : AR_WRITE(sc, prog->regs[i], pvals[i]);
566 0 : }
567 :
568 : void
569 0 : ar9280_olpc_init(struct athn_softc *sc)
570 : {
571 : uint32_t reg;
572 : int i;
573 :
574 : /* Save original Tx gain values. */
575 0 : for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
576 0 : reg = AR_READ(sc, AR_PHY_TX_GAIN_TBL(i));
577 0 : sc->tx_gain_tbl[i] = MS(reg, AR_PHY_TX_GAIN);
578 : }
579 : /* Initial Tx gain temperature compensation. */
580 0 : sc->tcomp = 0;
581 0 : }
582 :
583 : void
584 0 : ar9280_olpc_temp_compensation(struct athn_softc *sc)
585 : {
586 0 : const struct ar5416_eeprom *eep = sc->eep;
587 : int8_t pdadc, txgain, tcomp;
588 : uint32_t reg;
589 : int i;
590 :
591 0 : reg = AR_READ(sc, AR_PHY_TX_PWRCTRL4);
592 0 : pdadc = MS(reg, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
593 : DPRINTFN(3, ("PD Avg Out=%d\n", pdadc));
594 :
595 0 : if (sc->pdadc == 0 || pdadc == 0)
596 0 : return; /* No frames transmitted yet. */
597 :
598 : /* Compute Tx gain temperature compensation. */
599 0 : if (sc->eep_rev >= AR_EEP_MINOR_VER_20 &&
600 0 : eep->baseEepHeader.dacHiPwrMode_5G)
601 0 : tcomp = (pdadc - sc->pdadc + 4) / 8;
602 : else
603 0 : tcomp = (pdadc - sc->pdadc + 5) / 10;
604 : DPRINTFN(3, ("OLPC temp compensation=%d\n", tcomp));
605 :
606 0 : if (tcomp == sc->tcomp)
607 0 : return; /* Don't rewrite the same values. */
608 0 : sc->tcomp = tcomp;
609 :
610 : /* Adjust Tx gain values. */
611 0 : for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
612 0 : txgain = sc->tx_gain_tbl[i] - tcomp;
613 0 : if (txgain < 0)
614 : txgain = 0;
615 0 : reg = AR_READ(sc, AR_PHY_TX_GAIN_TBL(i));
616 0 : reg = RW(reg, AR_PHY_TX_GAIN, txgain);
617 0 : AR_WRITE(sc, AR_PHY_TX_GAIN_TBL(i), reg);
618 : }
619 0 : AR_WRITE_BARRIER(sc);
620 0 : }
|