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