Line data Source code
1 : /* $OpenBSD: ar9380.c,v 1.26 2017/08/18 11:00:38 jsg Exp $ */
2 :
3 : /*-
4 : * Copyright (c) 2011 Damien Bergamini <damien.bergamini@free.fr>
5 : * Copyright (c) 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 AR9380 and AR9485 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/conf.h>
36 : #include <sys/device.h>
37 : #include <sys/endian.h>
38 :
39 : #include <machine/bus.h>
40 :
41 : #if NBPFILTER > 0
42 : #include <net/bpf.h>
43 : #endif
44 : #include <net/if.h>
45 : #include <net/if_media.h>
46 :
47 : #include <netinet/in.h>
48 : #include <netinet/if_ether.h>
49 :
50 : #include <net80211/ieee80211_var.h>
51 : #include <net80211/ieee80211_amrr.h>
52 : #include <net80211/ieee80211_mira.h>
53 : #include <net80211/ieee80211_radiotap.h>
54 :
55 : #include <dev/ic/athnreg.h>
56 : #include <dev/ic/athnvar.h>
57 :
58 : #include <dev/ic/ar9003reg.h>
59 : #include <dev/ic/ar9380reg.h>
60 :
61 : int ar9380_attach(struct athn_softc *);
62 : void ar9380_setup(struct athn_softc *);
63 : const uint8_t *ar9380_get_rom_template(struct athn_softc *, uint8_t);
64 : void ar9380_swap_rom(struct athn_softc *);
65 : int ar9380_set_synth(struct athn_softc *, struct ieee80211_channel *,
66 : struct ieee80211_channel *);
67 : void ar9380_get_paprd_masks(struct athn_softc *, struct ieee80211_channel *,
68 : uint32_t *, uint32_t *);
69 : void ar9380_init_from_rom(struct athn_softc *, struct ieee80211_channel *,
70 : struct ieee80211_channel *);
71 : void ar9380_init_swreg(struct athn_softc *);
72 : int ar9485_pmu_write(struct athn_softc *, uint32_t, uint32_t);
73 : void ar9485_init_swreg(struct athn_softc *);
74 : void ar9380_spur_mitigate_cck(struct athn_softc *,
75 : struct ieee80211_channel *, struct ieee80211_channel *);
76 : void ar9380_spur_mitigate_ofdm(struct athn_softc *,
77 : struct ieee80211_channel *, struct ieee80211_channel *);
78 : void ar9380_spur_mitigate(struct athn_softc *, struct ieee80211_channel *,
79 : struct ieee80211_channel *);
80 : void ar9380_set_txpower(struct athn_softc *, struct ieee80211_channel *,
81 : struct ieee80211_channel *);
82 : void ar9380_get_correction(struct athn_softc *, struct ieee80211_channel *,
83 : int, int *, int *);
84 : void ar9380_set_correction(struct athn_softc *, struct ieee80211_channel *);
85 :
86 : /* Extern functions. */
87 : int athn_interpolate(int, int, int, int, int);
88 : uint8_t athn_chan2fbin(struct ieee80211_channel *);
89 : void athn_get_pier_ival(uint8_t, const uint8_t *, int, int *, int *);
90 : int ar9003_attach(struct athn_softc *);
91 : void ar9003_write_txpower(struct athn_softc *, int16_t power[]);
92 : void ar9003_get_lg_tpow(struct athn_softc *, struct ieee80211_channel *,
93 : uint8_t, const uint8_t *, const struct ar_cal_target_power_leg *,
94 : int, uint8_t[]);
95 : void ar9003_get_ht_tpow(struct athn_softc *, struct ieee80211_channel *,
96 : uint8_t, const uint8_t *, const struct ar_cal_target_power_ht *,
97 : int, uint8_t[]);
98 :
99 :
100 : int
101 0 : ar9380_attach(struct athn_softc *sc)
102 : {
103 0 : sc->ngpiopins = 17;
104 0 : sc->ops.setup = ar9380_setup;
105 0 : sc->ops.get_rom_template = ar9380_get_rom_template;
106 0 : sc->ops.swap_rom = ar9380_swap_rom;
107 0 : sc->ops.init_from_rom = ar9380_init_from_rom;
108 0 : sc->ops.set_txpower = ar9380_set_txpower;
109 0 : sc->ops.set_synth = ar9380_set_synth;
110 0 : sc->ops.spur_mitigate = ar9380_spur_mitigate;
111 0 : sc->ops.get_paprd_masks = ar9380_get_paprd_masks;
112 0 : sc->cca_min_2g = AR9380_PHY_CCA_MIN_GOOD_VAL_2GHZ;
113 0 : sc->cca_max_2g = AR9380_PHY_CCA_MAX_GOOD_VAL_2GHZ;
114 0 : sc->cca_min_5g = AR9380_PHY_CCA_MIN_GOOD_VAL_5GHZ;
115 0 : sc->cca_max_5g = AR9380_PHY_CCA_MAX_GOOD_VAL_5GHZ;
116 0 : if (AR_SREV_9485(sc)) {
117 0 : sc->ini = &ar9485_1_1_ini;
118 0 : sc->serdes = &ar9485_1_1_serdes;
119 0 : } else {
120 0 : sc->ini = &ar9380_2_2_ini;
121 0 : sc->serdes = &ar9380_2_2_serdes;
122 : }
123 :
124 0 : return (ar9003_attach(sc));
125 : }
126 :
127 : void
128 0 : ar9380_setup(struct athn_softc *sc)
129 : {
130 0 : struct ieee80211com *ic = &sc->sc_ic;
131 0 : struct ar9380_eeprom *eep = sc->eep;
132 0 : struct ar9380_base_eep_hdr *base = &eep->baseEepHeader;
133 : uint8_t type;
134 :
135 0 : if (base->opFlags & AR_OPFLAGS_11A)
136 0 : sc->flags |= ATHN_FLAG_11A;
137 0 : if (base->opFlags & AR_OPFLAGS_11G)
138 0 : sc->flags |= ATHN_FLAG_11G;
139 0 : if (base->opFlags & AR_OPFLAGS_11N)
140 0 : sc->flags |= ATHN_FLAG_11N;
141 :
142 0 : IEEE80211_ADDR_COPY(ic->ic_myaddr, eep->macAddr);
143 0 : sc->led_pin = base->wlanLedGpio;
144 :
145 : /* Check if we have a hardware radio switch. */
146 0 : if (base->rfSilent & AR_EEP_RFSILENT_ENABLED) {
147 0 : sc->flags |= ATHN_FLAG_RFSILENT;
148 : /* Get GPIO pin used by hardware radio switch. */
149 0 : sc->rfsilent_pin = MS(base->rfSilent,
150 : AR_EEP_RFSILENT_GPIO_SEL);
151 : /* Get polarity of hardware radio switch. */
152 0 : if (base->rfSilent & AR_EEP_RFSILENT_POLARITY)
153 0 : sc->flags |= ATHN_FLAG_RFSILENT_REVERSED;
154 : }
155 :
156 : /* Set the number of HW key cache entries. */
157 0 : sc->kc_entries = AR_KEYTABLE_SIZE;
158 :
159 0 : sc->txchainmask = MS(base->txrxMask, AR_EEP_TX_MASK);
160 0 : sc->rxchainmask = MS(base->txrxMask, AR_EEP_RX_MASK);
161 :
162 : /* Fast PLL clock is always supported. */
163 0 : sc->flags |= ATHN_FLAG_FAST_PLL_CLOCK;
164 :
165 : /* Enable PA predistortion if supported. */
166 0 : if (base->featureEnable & AR_EEP_PAPRD)
167 0 : sc->flags |= ATHN_FLAG_PAPRD;
168 : /*
169 : * Some 3-stream chips may exceed the PCIe power requirements,
170 : * requiring to reduce the number of Tx chains in some cases.
171 : */
172 0 : if ((base->miscConfiguration & AR_EEP_CHAIN_MASK_REDUCE) &&
173 0 : sc->txchainmask == 0x7)
174 0 : sc->flags |= ATHN_FLAG_3TREDUCE_CHAIN;
175 :
176 : /* Select initialization values based on ROM. */
177 0 : type = MS(eep->baseEepHeader.txrxgain, AR_EEP_RX_GAIN);
178 0 : if (!AR_SREV_9485(sc)) {
179 0 : if (type == AR_EEP_RX_GAIN_WO_XLNA)
180 0 : sc->rx_gain = &ar9380_2_2_rx_gain_wo_xlna;
181 : else
182 0 : sc->rx_gain = &ar9380_2_2_rx_gain;
183 : } else
184 0 : sc->rx_gain = &ar9485_1_1_rx_gain;
185 :
186 : /* Select initialization values based on ROM. */
187 0 : type = MS(eep->baseEepHeader.txrxgain, AR_EEP_TX_GAIN);
188 0 : if (!AR_SREV_9485(sc)) {
189 0 : if (type == AR_EEP_TX_GAIN_HIGH_OB_DB)
190 0 : sc->tx_gain = &ar9380_2_2_tx_gain_high_ob_db;
191 0 : else if (type == AR_EEP_TX_GAIN_LOW_OB_DB)
192 0 : sc->tx_gain = &ar9380_2_2_tx_gain_low_ob_db;
193 0 : else if (type == AR_EEP_TX_GAIN_HIGH_POWER)
194 0 : sc->tx_gain = &ar9380_2_2_tx_gain_high_power;
195 : else
196 0 : sc->tx_gain = &ar9380_2_2_tx_gain;
197 : } else
198 0 : sc->tx_gain = &ar9485_1_1_tx_gain;
199 0 : }
200 :
201 : const uint8_t *
202 0 : ar9380_get_rom_template(struct athn_softc *sc, uint8_t ref)
203 : {
204 : int i;
205 :
206 : /* Retrieve template ROM image for given reference. */
207 0 : for (i = 0; i < nitems(ar9380_rom_templates); i++)
208 0 : if (ar9380_rom_templates[i][1] == ref)
209 0 : return (ar9380_rom_templates[i]);
210 0 : return (NULL);
211 0 : }
212 :
213 : void
214 0 : ar9380_swap_rom(struct athn_softc *sc)
215 : {
216 : #if BYTE_ORDER == BIG_ENDIAN
217 : struct ar9380_eeprom *eep = sc->eep;
218 : struct ar9380_base_eep_hdr *base = &eep->baseEepHeader;
219 : struct ar9380_modal_eep_header *modal;
220 : int i;
221 :
222 : base->regDmn[0] = swap16(base->regDmn[0]);
223 : base->regDmn[1] = swap16(base->regDmn[1]);
224 : base->swreg = swap32(base->swreg);
225 :
226 : modal = &eep->modalHeader2G;
227 : modal->antCtrlCommon = swap32(modal->antCtrlCommon);
228 : modal->antCtrlCommon2 = swap32(modal->antCtrlCommon2);
229 : modal->papdRateMaskHt20 = swap32(modal->papdRateMaskHt20);
230 : modal->papdRateMaskHt40 = swap32(modal->papdRateMaskHt40);
231 : for (i = 0; i < AR9380_MAX_CHAINS; i++)
232 : modal->antCtrlChain[i] = swap16(modal->antCtrlChain[i]);
233 :
234 : modal = &eep->modalHeader5G;
235 : modal->antCtrlCommon = swap32(modal->antCtrlCommon);
236 : modal->antCtrlCommon2 = swap32(modal->antCtrlCommon2);
237 : modal->papdRateMaskHt20 = swap32(modal->papdRateMaskHt20);
238 : modal->papdRateMaskHt40 = swap32(modal->papdRateMaskHt40);
239 : for (i = 0; i < AR9380_MAX_CHAINS; i++)
240 : modal->antCtrlChain[i] = swap16(modal->antCtrlChain[i]);
241 : #endif
242 0 : }
243 :
244 : void
245 0 : ar9380_get_paprd_masks(struct athn_softc *sc, struct ieee80211_channel *c,
246 : uint32_t *ht20mask, uint32_t *ht40mask)
247 : {
248 0 : const struct ar9380_eeprom *eep = sc->eep;
249 : const struct ar9380_modal_eep_header *modal;
250 :
251 0 : if (IEEE80211_IS_CHAN_2GHZ(c))
252 0 : modal = &eep->modalHeader2G;
253 : else
254 0 : modal = &eep->modalHeader5G;
255 0 : *ht20mask = modal->papdRateMaskHt20;
256 0 : *ht40mask = modal->papdRateMaskHt40;
257 0 : }
258 :
259 : int
260 0 : ar9380_set_synth(struct athn_softc *sc, struct ieee80211_channel *c,
261 : struct ieee80211_channel *extc)
262 : {
263 0 : uint32_t freq = c->ic_freq;
264 : uint32_t chansel, phy;
265 :
266 0 : if (IEEE80211_IS_CHAN_2GHZ(c)) {
267 0 : if (AR_SREV_9485(sc))
268 0 : chansel = ((freq << 16) - 215) / 15;
269 : else
270 0 : chansel = (freq << 16) / 15;
271 0 : AR_WRITE(sc, AR_PHY_SYNTH_CONTROL, AR9380_BMODE);
272 0 : } else {
273 0 : chansel = (freq << 15) / 15;
274 0 : chansel >>= 1;
275 0 : AR_WRITE(sc, AR_PHY_SYNTH_CONTROL, 0);
276 : }
277 :
278 : /* Enable Long Shift Select for synthesizer. */
279 0 : AR_SETBITS(sc, AR_PHY_65NM_CH0_SYNTH4,
280 : AR_PHY_SYNTH4_LONG_SHIFT_SELECT);
281 0 : AR_WRITE_BARRIER(sc);
282 :
283 : /* Program synthesizer. */
284 0 : phy = (chansel << 2) | AR9380_FRACMODE;
285 : DPRINTFN(4, ("AR_PHY_65NM_CH0_SYNTH7=0x%08x\n", phy));
286 0 : AR_WRITE(sc, AR_PHY_65NM_CH0_SYNTH7, phy);
287 0 : AR_WRITE_BARRIER(sc);
288 : /* Toggle Load Synth Channel bit. */
289 0 : AR_WRITE(sc, AR_PHY_65NM_CH0_SYNTH7, phy | AR9380_LOAD_SYNTH);
290 0 : AR_WRITE_BARRIER(sc);
291 0 : return (0);
292 : }
293 :
294 : void
295 0 : ar9380_init_from_rom(struct athn_softc *sc, struct ieee80211_channel *c,
296 : struct ieee80211_channel *extc)
297 : {
298 0 : const struct ar9380_eeprom *eep = sc->eep;
299 : const struct ar9380_modal_eep_header *modal;
300 : uint8_t db, margin, ant_div_ctrl;
301 : uint32_t reg;
302 : int i, maxchains;
303 :
304 0 : if (IEEE80211_IS_CHAN_2GHZ(c))
305 0 : modal = &eep->modalHeader2G;
306 : else
307 0 : modal = &eep->modalHeader5G;
308 :
309 : /* Apply XPA bias level. */
310 0 : if (AR_SREV_9485(sc)) {
311 0 : reg = AR_READ(sc, AR9485_PHY_65NM_CH0_TOP2);
312 0 : reg = RW(reg, AR9485_PHY_65NM_CH0_TOP2_XPABIASLVL,
313 : modal->xpaBiasLvl);
314 0 : AR_WRITE(sc, AR9485_PHY_65NM_CH0_TOP2, reg);
315 0 : } else {
316 0 : reg = AR_READ(sc, AR_PHY_65NM_CH0_TOP);
317 0 : reg = RW(reg, AR_PHY_65NM_CH0_TOP_XPABIASLVL,
318 : modal->xpaBiasLvl & 0x3);
319 0 : AR_WRITE(sc, AR_PHY_65NM_CH0_TOP, reg);
320 0 : reg = AR_READ(sc, AR_PHY_65NM_CH0_THERM);
321 0 : reg = RW(reg, AR_PHY_65NM_CH0_THERM_XPABIASLVL_MSB,
322 : modal->xpaBiasLvl >> 2);
323 0 : reg |= AR_PHY_65NM_CH0_THERM_XPASHORT2GND;
324 0 : AR_WRITE(sc, AR_PHY_65NM_CH0_THERM, reg);
325 : }
326 :
327 : /* Apply antenna control. */
328 0 : reg = AR_READ(sc, AR_PHY_SWITCH_COM);
329 0 : reg = RW(reg, AR_SWITCH_TABLE_COM_ALL, modal->antCtrlCommon);
330 0 : AR_WRITE(sc, AR_PHY_SWITCH_COM, reg);
331 0 : reg = AR_READ(sc, AR_PHY_SWITCH_COM_2);
332 0 : reg = RW(reg, AR_SWITCH_TABLE_COM_2_ALL, modal->antCtrlCommon2);
333 0 : AR_WRITE(sc, AR_PHY_SWITCH_COM_2, reg);
334 :
335 0 : maxchains = AR_SREV_9485(sc) ? 1 : AR9380_MAX_CHAINS;
336 0 : for (i = 0; i < maxchains; i++) {
337 0 : reg = AR_READ(sc, AR_PHY_SWITCH_CHAIN(i));
338 0 : reg = RW(reg, AR_SWITCH_TABLE_ALL, modal->antCtrlChain[i]);
339 0 : AR_WRITE(sc, AR_PHY_SWITCH_CHAIN(i), reg);
340 : }
341 :
342 0 : if (AR_SREV_9485(sc)) {
343 0 : ant_div_ctrl = eep->base_ext1.ant_div_control;
344 0 : reg = AR_READ(sc, AR_PHY_MC_GAIN_CTRL);
345 0 : reg = RW(reg, AR_PHY_MC_GAIN_CTRL_ANT_DIV_CTRL_ALL,
346 : MS(ant_div_ctrl, AR_EEP_ANT_DIV_CTRL_ALL));
347 0 : if (ant_div_ctrl & AR_EEP_ANT_DIV_CTRL_ANT_DIV)
348 0 : reg |= AR_PHY_MC_GAIN_CTRL_ENABLE_ANT_DIV;
349 : else
350 0 : reg &= ~AR_PHY_MC_GAIN_CTRL_ENABLE_ANT_DIV;
351 0 : AR_WRITE(sc, AR_PHY_MC_GAIN_CTRL, reg);
352 0 : reg = AR_READ(sc, AR_PHY_CCK_DETECT);
353 0 : if (ant_div_ctrl & AR_EEP_ANT_DIV_CTRL_FAST_DIV)
354 0 : reg |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
355 : else
356 0 : reg &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
357 0 : AR_WRITE(sc, AR_PHY_CCK_DETECT, reg);
358 0 : }
359 :
360 0 : if (eep->baseEepHeader.miscConfiguration & AR_EEP_DRIVE_STRENGTH) {
361 : /* Apply drive strength. */
362 0 : reg = AR_READ(sc, AR_PHY_65NM_CH0_BIAS1);
363 0 : reg = RW(reg, AR_PHY_65NM_CH0_BIAS1_0, 5);
364 0 : reg = RW(reg, AR_PHY_65NM_CH0_BIAS1_1, 5);
365 0 : reg = RW(reg, AR_PHY_65NM_CH0_BIAS1_2, 5);
366 0 : reg = RW(reg, AR_PHY_65NM_CH0_BIAS1_3, 5);
367 0 : reg = RW(reg, AR_PHY_65NM_CH0_BIAS1_4, 5);
368 0 : reg = RW(reg, AR_PHY_65NM_CH0_BIAS1_5, 5);
369 0 : AR_WRITE(sc, AR_PHY_65NM_CH0_BIAS1, reg);
370 :
371 0 : reg = AR_READ(sc, AR_PHY_65NM_CH0_BIAS2);
372 0 : reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_0, 5);
373 0 : reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_1, 5);
374 0 : reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_2, 5);
375 0 : reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_3, 5);
376 0 : reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_4, 5);
377 0 : reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_5, 5);
378 0 : reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_6, 5);
379 0 : reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_7, 5);
380 0 : reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_8, 5);
381 0 : AR_WRITE(sc, AR_PHY_65NM_CH0_BIAS2, reg);
382 :
383 0 : reg = AR_READ(sc, AR_PHY_65NM_CH0_BIAS4);
384 0 : reg = RW(reg, AR_PHY_65NM_CH0_BIAS4_0, 5);
385 0 : reg = RW(reg, AR_PHY_65NM_CH0_BIAS4_1, 5);
386 0 : reg = RW(reg, AR_PHY_65NM_CH0_BIAS4_2, 5);
387 0 : AR_WRITE(sc, AR_PHY_65NM_CH0_BIAS4, reg);
388 0 : }
389 :
390 : /* Apply attenuation settings. */
391 0 : maxchains = AR_SREV_9485(sc) ? 1 : AR9380_MAX_CHAINS;
392 0 : for (i = 0; i < maxchains; i++) {
393 0 : if (IEEE80211_IS_CHAN_5GHZ(c) &&
394 0 : eep->base_ext2.xatten1DBLow[i] != 0) {
395 0 : if (c->ic_freq <= 5500) {
396 0 : db = athn_interpolate(c->ic_freq,
397 : 5180, eep->base_ext2.xatten1DBLow[i],
398 0 : 5500, modal->xatten1DB[i]);
399 0 : } else {
400 0 : db = athn_interpolate(c->ic_freq,
401 0 : 5500, modal->xatten1DB[i],
402 0 : 5785, eep->base_ext2.xatten1DBHigh[i]);
403 : }
404 : } else
405 0 : db = modal->xatten1DB[i];
406 0 : if (IEEE80211_IS_CHAN_5GHZ(c) &&
407 0 : eep->base_ext2.xatten1MarginLow[i] != 0) {
408 0 : if (c->ic_freq <= 5500) {
409 0 : margin = athn_interpolate(c->ic_freq,
410 : 5180, eep->base_ext2.xatten1MarginLow[i],
411 0 : 5500, modal->xatten1Margin[i]);
412 0 : } else {
413 0 : margin = athn_interpolate(c->ic_freq,
414 0 : 5500, modal->xatten1Margin[i],
415 0 : 5785, eep->base_ext2.xatten1MarginHigh[i]);
416 : }
417 : } else
418 0 : margin = modal->xatten1Margin[i];
419 0 : reg = AR_READ(sc, AR_PHY_EXT_ATTEN_CTL(i));
420 0 : reg = RW(reg, AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, db);
421 0 : reg = RW(reg, AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, margin);
422 0 : AR_WRITE(sc, AR_PHY_EXT_ATTEN_CTL(i), reg);
423 : }
424 :
425 : /* Initialize switching regulator. */
426 0 : if (AR_SREV_9485(sc))
427 0 : ar9485_init_swreg(sc);
428 : else
429 0 : ar9380_init_swreg(sc);
430 :
431 : /* Apply tuning capabilities. */
432 0 : if (AR_SREV_9485(sc) &&
433 0 : (eep->baseEepHeader.featureEnable & AR_EEP_TUNING_CAPS)) {
434 0 : reg = AR_READ(sc, AR9485_PHY_CH0_XTAL);
435 0 : reg = RW(reg, AR9485_PHY_CH0_XTAL_CAPINDAC,
436 : eep->baseEepHeader.params_for_tuning_caps[0]);
437 0 : reg = RW(reg, AR9485_PHY_CH0_XTAL_CAPOUTDAC,
438 : eep->baseEepHeader.params_for_tuning_caps[0]);
439 0 : AR_WRITE(sc, AR9485_PHY_CH0_XTAL, reg);
440 0 : }
441 0 : AR_WRITE_BARRIER(sc);
442 0 : }
443 :
444 : void
445 0 : ar9380_init_swreg(struct athn_softc *sc)
446 : {
447 0 : const struct ar9380_eeprom *eep = sc->eep;
448 :
449 0 : if (eep->baseEepHeader.featureEnable & AR_EEP_INTERNAL_REGULATOR) {
450 : /* Internal regulator is ON. */
451 0 : AR_CLRBITS(sc, AR_RTC_REG_CONTROL1,
452 : AR_RTC_REG_CONTROL1_SWREG_PROGRAM);
453 0 : AR_WRITE(sc, AR_RTC_REG_CONTROL0, eep->baseEepHeader.swreg);
454 0 : AR_SETBITS(sc, AR_RTC_REG_CONTROL1,
455 : AR_RTC_REG_CONTROL1_SWREG_PROGRAM);
456 0 : } else
457 0 : AR_SETBITS(sc, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_SWREG_PRD);
458 0 : AR_WRITE_BARRIER(sc);
459 0 : }
460 :
461 : int
462 0 : ar9485_pmu_write(struct athn_softc *sc, uint32_t addr, uint32_t val)
463 : {
464 : int ntries;
465 :
466 0 : AR_WRITE(sc, addr, val);
467 : /* Wait for write to complete. */
468 0 : for (ntries = 0; ntries < 100; ntries++) {
469 0 : if (AR_READ(sc, addr) == val)
470 0 : return (0);
471 0 : AR_WRITE(sc, addr, val); /* Insist. */
472 0 : AR_WRITE_BARRIER(sc);
473 0 : DELAY(10);
474 : }
475 0 : return (ETIMEDOUT);
476 0 : }
477 :
478 : #define ar9486_pmu_read AR_READ
479 :
480 : void
481 0 : ar9485_init_swreg(struct athn_softc *sc)
482 : {
483 0 : const struct ar9380_eeprom *eep = sc->eep;
484 : uint32_t reg;
485 :
486 0 : ar9485_pmu_write(sc, AR_PHY_PMU2,
487 0 : ar9486_pmu_read(sc, AR_PHY_PMU2) & ~AR_PHY_PMU2_PGM);
488 :
489 0 : if (eep->baseEepHeader.featureEnable & AR_EEP_INTERNAL_REGULATOR) {
490 0 : ar9485_pmu_write(sc, AR_PHY_PMU1, 0x131dc17a);
491 :
492 0 : reg = ar9486_pmu_read(sc, AR_PHY_PMU2);
493 0 : reg = (reg & ~0xffc00000) | 0x10000000;
494 0 : ar9485_pmu_write(sc, AR_PHY_PMU2, reg);
495 0 : } else {
496 0 : ar9485_pmu_write(sc, AR_PHY_PMU1,
497 0 : ar9486_pmu_read(sc, AR_PHY_PMU1) | AR_PHY_PMU1_PWD);
498 : }
499 :
500 0 : ar9485_pmu_write(sc, AR_PHY_PMU2,
501 0 : ar9486_pmu_read(sc, AR_PHY_PMU2) | AR_PHY_PMU2_PGM);
502 0 : }
503 :
504 : void
505 0 : ar9380_spur_mitigate_cck(struct athn_softc *sc, struct ieee80211_channel *c,
506 : struct ieee80211_channel *extc)
507 : {
508 : /* NB: It is safe to call this function for 5GHz channels. */
509 : static const int16_t freqs[] = { 2420, 2440, 2464, 2480 };
510 : int i, spur, freq;
511 : uint32_t reg;
512 :
513 0 : for (i = 0; i < nitems(freqs); i++) {
514 0 : spur = freqs[i] - c->ic_freq;
515 0 : if (abs(spur) < 10) /* +/- 10MHz range. */
516 : break;
517 : }
518 0 : if (i == nitems(freqs)) {
519 : /* Disable CCK spur mitigation. */
520 0 : reg = AR_READ(sc, AR_PHY_AGC_CONTROL);
521 0 : reg = RW(reg, AR_PHY_AGC_CONTROL_YCOK_MAX, 0x5);
522 0 : AR_WRITE(sc, AR_PHY_AGC_CONTROL, reg);
523 0 : reg = AR_READ(sc, AR_PHY_CCK_SPUR_MIT);
524 0 : reg = RW(reg, AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ, 0);
525 0 : reg &= ~AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT;
526 0 : AR_WRITE(sc, AR_PHY_CCK_SPUR_MIT, reg);
527 0 : AR_WRITE_BARRIER(sc);
528 0 : return;
529 : }
530 0 : freq = (spur * 524288) / 11;
531 :
532 0 : reg = AR_READ(sc, AR_PHY_AGC_CONTROL);
533 0 : reg = RW(reg, AR_PHY_AGC_CONTROL_YCOK_MAX, 0x7);
534 0 : AR_WRITE(sc, AR_PHY_AGC_CONTROL, reg);
535 :
536 0 : reg = AR_READ(sc, AR_PHY_CCK_SPUR_MIT);
537 0 : reg = RW(reg, AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ, freq);
538 0 : reg = RW(reg, AR_PHY_CCK_SPUR_MIT_SPUR_RSSI_THR, 0x7f);
539 0 : reg = RW(reg, AR_PHY_CCK_SPUR_MIT_SPUR_FILTER_TYPE, 0x2);
540 0 : reg |= AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT;
541 0 : AR_WRITE(sc, AR_PHY_CCK_SPUR_MIT, reg);
542 0 : AR_WRITE_BARRIER(sc);
543 0 : }
544 :
545 : void
546 0 : ar9380_spur_mitigate_ofdm(struct athn_softc *sc, struct ieee80211_channel *c,
547 : struct ieee80211_channel *extc)
548 : {
549 0 : const struct ar9380_eeprom *eep = sc->eep;
550 : const uint8_t *spurchans;
551 : uint32_t reg;
552 : int idx, spur_delta_phase, spur_off, range, i;
553 : int freq, spur, spur_freq_sd, spur_subchannel_sd;
554 :
555 0 : if (IEEE80211_IS_CHAN_2GHZ(c))
556 0 : spurchans = eep->modalHeader2G.spurChans;
557 : else
558 0 : spurchans = eep->modalHeader5G.spurChans;
559 0 : if (spurchans[0] == 0)
560 0 : return;
561 :
562 : /* Disable OFDM spur mitigation. */
563 0 : AR_CLRBITS(sc, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_FILTER);
564 :
565 0 : reg = AR_READ(sc, AR_PHY_TIMING11);
566 0 : reg = RW(reg, AR_PHY_TIMING11_SPUR_FREQ_SD, 0);
567 0 : reg = RW(reg, AR_PHY_TIMING11_SPUR_DELTA_PHASE, 0);
568 0 : reg &= ~AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC;
569 : reg &= ~AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR;
570 0 : AR_WRITE(sc, AR_PHY_TIMING11, reg);
571 :
572 0 : AR_CLRBITS(sc, AR_PHY_SFCORR_EXT,
573 : AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD);
574 :
575 0 : AR_CLRBITS(sc, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_RSSI);
576 :
577 0 : reg = AR_READ(sc, AR_PHY_SPUR_REG);
578 0 : reg = RW(reg, AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0);
579 0 : reg &= ~AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI;
580 0 : reg &= ~AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT;
581 0 : reg &= ~AR_PHY_SPUR_REG_ENABLE_MASK_PPM;
582 0 : AR_WRITE(sc, AR_PHY_SPUR_REG, reg);
583 0 : AR_WRITE_BARRIER(sc);
584 :
585 0 : freq = c->ic_freq;
586 0 : if (extc != NULL) {
587 : range = 19; /* +/- 19MHz range. */
588 0 : if (AR_READ(sc, AR_PHY_GEN_CTRL) & AR_PHY_GC_DYN2040_PRI_CH)
589 0 : freq += 10;
590 : else
591 0 : freq -= 10;
592 : } else
593 : range = 10; /* +/- 10MHz range. */
594 0 : for (i = 0; i < AR9380_EEPROM_MODAL_SPURS; i++) {
595 0 : spur = spurchans[i];
596 0 : if (spur == 0)
597 0 : return;
598 : /* Convert to frequency. */
599 0 : if (IEEE80211_IS_CHAN_2GHZ(c))
600 0 : spur = 2300 + spur;
601 : else
602 0 : spur = 4900 + (spur * 5);
603 0 : spur -= freq;
604 0 : if (abs(spur) < range)
605 : break;
606 : }
607 0 : if (i == AR9380_EEPROM_MODAL_SPURS)
608 0 : return;
609 :
610 : /* Enable OFDM spur mitigation. */
611 0 : if (extc != NULL) {
612 0 : spur_delta_phase = (spur * 131072) / 5;
613 0 : reg = AR_READ(sc, AR_PHY_GEN_CTRL);
614 0 : if (spur < 0) {
615 : spur_subchannel_sd =
616 0 : (reg & AR_PHY_GC_DYN2040_PRI_CH) == 0;
617 0 : spur_off = spur + 10;
618 0 : } else {
619 : spur_subchannel_sd =
620 0 : (reg & AR_PHY_GC_DYN2040_PRI_CH) != 0;
621 0 : spur_off = spur - 10;
622 : }
623 : } else {
624 0 : spur_delta_phase = (spur * 262144) / 5;
625 : spur_subchannel_sd = 0;
626 : spur_off = spur;
627 : }
628 0 : spur_freq_sd = (spur_off * 512) / 11;
629 :
630 0 : AR_SETBITS(sc, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_FILTER);
631 :
632 0 : reg = AR_READ(sc, AR_PHY_TIMING11);
633 0 : reg = RW(reg, AR_PHY_TIMING11_SPUR_FREQ_SD, spur_freq_sd);
634 0 : reg = RW(reg, AR_PHY_TIMING11_SPUR_DELTA_PHASE, spur_delta_phase);
635 0 : reg |= AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC;
636 0 : reg |= AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR;
637 0 : AR_WRITE(sc, AR_PHY_TIMING11, reg);
638 :
639 0 : reg = AR_READ(sc, AR_PHY_SFCORR_EXT);
640 0 : if (spur_subchannel_sd)
641 0 : reg |= AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD;
642 : else
643 0 : reg &= ~AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD;
644 0 : AR_WRITE(sc, AR_PHY_SFCORR_EXT, reg);
645 :
646 0 : AR_SETBITS(sc, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_RSSI);
647 :
648 0 : reg = AR_READ(sc, AR_PHY_SPUR_REG);
649 0 : reg = RW(reg, AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0xff);
650 0 : reg = RW(reg, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH, 34);
651 0 : reg |= AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI;
652 0 : if (AR_READ(sc, AR_PHY_MODE) & AR_PHY_MODE_DYNAMIC)
653 0 : reg |= AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT;
654 0 : reg |= AR_PHY_SPUR_REG_ENABLE_MASK_PPM;
655 0 : AR_WRITE(sc, AR_PHY_SPUR_REG, reg);
656 :
657 0 : idx = (spur * 16) / 5;
658 0 : if (idx < 0)
659 0 : idx--;
660 :
661 : /* Write pilot mask. */
662 0 : AR_SETBITS(sc, AR_PHY_TIMING4,
663 : AR_PHY_TIMING4_ENABLE_PILOT_MASK |
664 : AR_PHY_TIMING4_ENABLE_CHAN_MASK);
665 :
666 0 : reg = AR_READ(sc, AR_PHY_PILOT_SPUR_MASK);
667 0 : reg = RW(reg, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A, idx);
668 0 : reg = RW(reg, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A, 0x0c);
669 0 : AR_WRITE(sc, AR_PHY_PILOT_SPUR_MASK, reg);
670 :
671 0 : reg = AR_READ(sc, AR_PHY_SPUR_MASK_A);
672 0 : reg = RW(reg, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A, idx);
673 0 : reg = RW(reg, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0xa0);
674 0 : AR_WRITE(sc, AR_PHY_SPUR_MASK_A, reg);
675 :
676 0 : reg = AR_READ(sc, AR_PHY_CHAN_SPUR_MASK);
677 0 : reg = RW(reg, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A, idx);
678 0 : reg = RW(reg, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A, 0x0c);
679 0 : AR_WRITE(sc, AR_PHY_CHAN_SPUR_MASK, reg);
680 0 : AR_WRITE_BARRIER(sc);
681 0 : }
682 :
683 : void
684 0 : ar9380_spur_mitigate(struct athn_softc *sc, struct ieee80211_channel *c,
685 : struct ieee80211_channel *extc)
686 : {
687 : /* NB: We call spur_mitigate_cck for 5GHz too, just to disable it. */
688 0 : ar9380_spur_mitigate_cck(sc, c, extc);
689 0 : ar9380_spur_mitigate_ofdm(sc, c, extc);
690 0 : }
691 :
692 : void
693 0 : ar9380_set_txpower(struct athn_softc *sc, struct ieee80211_channel *c,
694 : struct ieee80211_channel *extc)
695 : {
696 0 : const struct ar9380_eeprom *eep = sc->eep;
697 0 : uint8_t tpow_cck[4], tpow_ofdm[4];
698 0 : uint8_t tpow_ht20[14], tpow_ht40[14];
699 0 : int16_t power[ATHN_POWER_COUNT];
700 :
701 0 : if (IEEE80211_IS_CHAN_2GHZ(c)) {
702 : /* Get CCK target powers. */
703 0 : ar9003_get_lg_tpow(sc, c, AR_CTL_11B,
704 0 : eep->calTargetFbinCck, eep->calTargetPowerCck,
705 0 : AR9380_NUM_2G_CCK_TARGET_POWERS, tpow_cck);
706 :
707 : /* Get OFDM target powers. */
708 0 : ar9003_get_lg_tpow(sc, c, AR_CTL_11G,
709 0 : eep->calTargetFbin2G, eep->calTargetPower2G,
710 0 : AR9380_NUM_2G_20_TARGET_POWERS, tpow_ofdm);
711 :
712 : /* Get HT-20 target powers. */
713 0 : ar9003_get_ht_tpow(sc, c, AR_CTL_2GHT20,
714 0 : eep->calTargetFbin2GHT20, eep->calTargetPower2GHT20,
715 0 : AR9380_NUM_2G_20_TARGET_POWERS, tpow_ht20);
716 :
717 0 : if (extc != NULL) {
718 : /* Get HT-40 target powers. */
719 0 : ar9003_get_ht_tpow(sc, c, AR_CTL_2GHT40,
720 0 : eep->calTargetFbin2GHT40,
721 0 : eep->calTargetPower2GHT40,
722 0 : AR9380_NUM_2G_40_TARGET_POWERS, tpow_ht40);
723 0 : }
724 : } else {
725 : /* Get OFDM target powers. */
726 0 : ar9003_get_lg_tpow(sc, c, AR_CTL_11A,
727 0 : eep->calTargetFbin5G, eep->calTargetPower5G,
728 0 : AR9380_NUM_5G_20_TARGET_POWERS, tpow_ofdm);
729 :
730 : /* Get HT-20 target powers. */
731 0 : ar9003_get_ht_tpow(sc, c, AR_CTL_5GHT20,
732 0 : eep->calTargetFbin5GHT20, eep->calTargetPower5GHT20,
733 0 : AR9380_NUM_5G_20_TARGET_POWERS, tpow_ht20);
734 :
735 0 : if (extc != NULL) {
736 : /* Get HT-40 target powers. */
737 0 : ar9003_get_ht_tpow(sc, c, AR_CTL_5GHT40,
738 0 : eep->calTargetFbin5GHT40,
739 0 : eep->calTargetPower5GHT40,
740 0 : AR9380_NUM_5G_40_TARGET_POWERS, tpow_ht40);
741 0 : }
742 : }
743 :
744 0 : memset(power, 0, sizeof(power));
745 : /* Shuffle target powers accross transmit rates. */
746 0 : power[ATHN_POWER_OFDM6 ] =
747 0 : power[ATHN_POWER_OFDM9 ] =
748 0 : power[ATHN_POWER_OFDM12] =
749 0 : power[ATHN_POWER_OFDM18] =
750 0 : power[ATHN_POWER_OFDM24] = tpow_ofdm[0];
751 0 : power[ATHN_POWER_OFDM36] = tpow_ofdm[1];
752 0 : power[ATHN_POWER_OFDM48] = tpow_ofdm[2];
753 0 : power[ATHN_POWER_OFDM54] = tpow_ofdm[3];
754 0 : if (IEEE80211_IS_CHAN_2GHZ(c)) {
755 0 : power[ATHN_POWER_CCK1_LP ] =
756 0 : power[ATHN_POWER_CCK2_LP ] =
757 0 : power[ATHN_POWER_CCK2_SP ] =
758 0 : power[ATHN_POWER_CCK55_LP] = tpow_cck[0];
759 0 : power[ATHN_POWER_CCK55_SP] = tpow_cck[1];
760 0 : power[ATHN_POWER_CCK11_LP] = tpow_cck[2];
761 0 : power[ATHN_POWER_CCK11_SP] = tpow_cck[3];
762 0 : }
763 : /* Next entry covers MCS0, MCS8 and MCS16. */
764 0 : power[ATHN_POWER_HT20( 0)] = tpow_ht20[ 0];
765 : /* Next entry covers MCS1-3, MCS9-11 and MCS17-19. */
766 0 : power[ATHN_POWER_HT20( 1)] = tpow_ht20[ 1];
767 0 : power[ATHN_POWER_HT20( 4)] = tpow_ht20[ 2];
768 0 : power[ATHN_POWER_HT20( 5)] = tpow_ht20[ 3];
769 0 : power[ATHN_POWER_HT20( 6)] = tpow_ht20[ 4];
770 0 : power[ATHN_POWER_HT20( 7)] = tpow_ht20[ 5];
771 0 : power[ATHN_POWER_HT20(12)] = tpow_ht20[ 6];
772 0 : power[ATHN_POWER_HT20(13)] = tpow_ht20[ 7];
773 0 : power[ATHN_POWER_HT20(14)] = tpow_ht20[ 8];
774 0 : power[ATHN_POWER_HT20(15)] = tpow_ht20[ 9];
775 0 : power[ATHN_POWER_HT20(20)] = tpow_ht20[10];
776 0 : power[ATHN_POWER_HT20(21)] = tpow_ht20[11];
777 0 : power[ATHN_POWER_HT20(22)] = tpow_ht20[12];
778 0 : power[ATHN_POWER_HT20(23)] = tpow_ht20[13];
779 0 : if (extc != NULL) {
780 : /* Next entry covers MCS0, MCS8 and MCS16. */
781 0 : power[ATHN_POWER_HT40( 0)] = tpow_ht40[ 0];
782 : /* Next entry covers MCS1-3, MCS9-11 and MCS17-19. */
783 0 : power[ATHN_POWER_HT40( 1)] = tpow_ht40[ 1];
784 0 : power[ATHN_POWER_HT40( 4)] = tpow_ht40[ 2];
785 0 : power[ATHN_POWER_HT40( 5)] = tpow_ht40[ 3];
786 0 : power[ATHN_POWER_HT40( 6)] = tpow_ht40[ 4];
787 0 : power[ATHN_POWER_HT40( 7)] = tpow_ht40[ 5];
788 0 : power[ATHN_POWER_HT40(12)] = tpow_ht40[ 6];
789 0 : power[ATHN_POWER_HT40(13)] = tpow_ht40[ 7];
790 0 : power[ATHN_POWER_HT40(14)] = tpow_ht40[ 8];
791 0 : power[ATHN_POWER_HT40(15)] = tpow_ht40[ 9];
792 0 : power[ATHN_POWER_HT40(20)] = tpow_ht40[10];
793 0 : power[ATHN_POWER_HT40(21)] = tpow_ht40[11];
794 0 : power[ATHN_POWER_HT40(22)] = tpow_ht40[12];
795 0 : power[ATHN_POWER_HT40(23)] = tpow_ht40[13];
796 0 : }
797 :
798 : /* Write transmit power values to hardware. */
799 0 : ar9003_write_txpower(sc, power);
800 :
801 : /* Apply transmit power correction. */
802 0 : ar9380_set_correction(sc, c);
803 0 : }
804 :
805 : void
806 0 : ar9380_get_correction(struct athn_softc *sc, struct ieee80211_channel *c,
807 : int chain, int *corr, int *temp)
808 : {
809 0 : const struct ar9380_eeprom *eep = sc->eep;
810 : const struct ar9380_cal_data_per_freq_op_loop *pierdata;
811 : const uint8_t *pierfreq;
812 : uint8_t fbin;
813 0 : int lo, hi, npiers;
814 :
815 0 : if (IEEE80211_IS_CHAN_2GHZ(c)) {
816 0 : pierfreq = eep->calFreqPier2G;
817 0 : pierdata = eep->calPierData2G[chain];
818 : npiers = AR9380_NUM_2G_CAL_PIERS;
819 0 : } else {
820 0 : pierfreq = eep->calFreqPier5G;
821 0 : pierdata = eep->calPierData5G[chain];
822 : npiers = AR9380_NUM_5G_CAL_PIERS;
823 : }
824 : /* Find channel in ROM pier table. */
825 0 : fbin = athn_chan2fbin(c);
826 0 : athn_get_pier_ival(fbin, pierfreq, npiers, &lo, &hi);
827 :
828 0 : *corr = athn_interpolate(fbin,
829 0 : pierfreq[lo], pierdata[lo].refPower,
830 0 : pierfreq[hi], pierdata[hi].refPower);
831 0 : *temp = athn_interpolate(fbin,
832 0 : pierfreq[lo], pierdata[lo].tempMeas,
833 0 : pierfreq[hi], pierdata[hi].tempMeas);
834 0 : }
835 :
836 : void
837 0 : ar9380_set_correction(struct athn_softc *sc, struct ieee80211_channel *c)
838 : {
839 0 : const struct ar9380_eeprom *eep = sc->eep;
840 : const struct ar9380_modal_eep_header *modal;
841 : uint32_t reg;
842 : int8_t slope;
843 0 : int i, corr, temp, temp0;
844 :
845 0 : if (IEEE80211_IS_CHAN_2GHZ(c))
846 0 : modal = &eep->modalHeader2G;
847 : else
848 0 : modal = &eep->modalHeader5G;
849 :
850 0 : for (i = 0; i < AR9380_MAX_CHAINS; i++) {
851 0 : ar9380_get_correction(sc, c, i, &corr, &temp);
852 0 : if (i == 0)
853 0 : temp0 = temp;
854 :
855 0 : reg = AR_READ(sc, AR_PHY_TPC_11_B(i));
856 0 : reg = RW(reg, AR_PHY_TPC_11_OLPC_GAIN_DELTA, corr);
857 0 : AR_WRITE(sc, AR_PHY_TPC_11_B(i), reg);
858 :
859 : /* Enable open loop power control. */
860 0 : reg = AR_READ(sc, AR_PHY_TPC_6_B(i));
861 0 : reg = RW(reg, AR_PHY_TPC_6_ERROR_EST_MODE, 3);
862 0 : AR_WRITE(sc, AR_PHY_TPC_6_B(i), reg);
863 : }
864 :
865 : /* Enable temperature compensation. */
866 0 : if (IEEE80211_IS_CHAN_5GHZ(c) &&
867 0 : eep->base_ext2.tempSlopeLow != 0) {
868 0 : if (c->ic_freq <= 5500) {
869 0 : slope = athn_interpolate(c->ic_freq,
870 : 5180, eep->base_ext2.tempSlopeLow,
871 0 : 5500, modal->tempSlope);
872 0 : } else {
873 0 : slope = athn_interpolate(c->ic_freq,
874 0 : 5500, modal->tempSlope,
875 0 : 5785, eep->base_ext2.tempSlopeHigh);
876 : }
877 : } else
878 0 : slope = modal->tempSlope;
879 :
880 0 : reg = AR_READ(sc, AR_PHY_TPC_19);
881 0 : reg = RW(reg, AR_PHY_TPC_19_ALPHA_THERM, slope);
882 0 : AR_WRITE(sc, AR_PHY_TPC_19, reg);
883 :
884 0 : reg = AR_READ(sc, AR_PHY_TPC_18);
885 0 : reg = RW(reg, AR_PHY_TPC_18_THERM_CAL, temp0);
886 0 : AR_WRITE(sc, AR_PHY_TPC_18, reg);
887 0 : AR_WRITE_BARRIER(sc);
888 0 : }
|