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