File: | dev/ic/ar9380.c |
Warning: | line 758, column 30 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: ar9380.c,v 1.28 2022/01/09 05:42: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 NBPFILTER1 > 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_ra.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 | ar9380_attach(struct athn_softc *sc) | |||
102 | { | |||
103 | sc->ngpiopins = 17; | |||
104 | sc->ops.setup = ar9380_setup; | |||
105 | sc->ops.get_rom_template = ar9380_get_rom_template; | |||
106 | sc->ops.swap_rom = ar9380_swap_rom; | |||
107 | sc->ops.init_from_rom = ar9380_init_from_rom; | |||
108 | sc->ops.set_txpower = ar9380_set_txpower; | |||
109 | sc->ops.set_synth = ar9380_set_synth; | |||
110 | sc->ops.spur_mitigate = ar9380_spur_mitigate; | |||
111 | sc->ops.get_paprd_masks = ar9380_get_paprd_masks; | |||
112 | sc->cca_min_2g = AR9380_PHY_CCA_MIN_GOOD_VAL_2GHZ(-125); | |||
113 | sc->cca_max_2g = AR9380_PHY_CCA_MAX_GOOD_VAL_2GHZ( -95); | |||
114 | sc->cca_min_5g = AR9380_PHY_CCA_MIN_GOOD_VAL_5GHZ(-125); | |||
115 | sc->cca_max_5g = AR9380_PHY_CCA_MAX_GOOD_VAL_5GHZ(-100); | |||
116 | if (AR_SREV_9485(sc)((sc)->mac_ver == 0x240)) { | |||
117 | sc->ini = &ar9485_1_1_ini; | |||
118 | sc->serdes = &ar9485_1_1_serdes; | |||
119 | } else { | |||
120 | sc->ini = &ar9380_2_2_ini; | |||
121 | sc->serdes = &ar9380_2_2_serdes; | |||
122 | } | |||
123 | ||||
124 | return (ar9003_attach(sc)); | |||
125 | } | |||
126 | ||||
127 | void | |||
128 | ar9380_setup(struct athn_softc *sc) | |||
129 | { | |||
130 | struct ieee80211com *ic = &sc->sc_ic; | |||
131 | struct ar9380_eeprom *eep = sc->eep; | |||
132 | struct ar9380_base_eep_hdr *base = &eep->baseEepHeader; | |||
133 | uint8_t type; | |||
134 | ||||
135 | if (base->opFlags & AR_OPFLAGS_11A0x01) | |||
136 | sc->flags |= ATHN_FLAG_11A(1 << 9); | |||
137 | if (base->opFlags & AR_OPFLAGS_11G0x02) | |||
138 | sc->flags |= ATHN_FLAG_11G(1 << 10); | |||
139 | if (base->opFlags & AR_OPFLAGS_11N0x3c) | |||
140 | sc->flags |= ATHN_FLAG_11N(1 << 11); | |||
141 | ||||
142 | IEEE80211_ADDR_COPY(ic->ic_myaddr, eep->macAddr)__builtin_memcpy((ic->ic_myaddr), (eep->macAddr), (6)); | |||
143 | sc->led_pin = base->wlanLedGpio; | |||
144 | ||||
145 | /* Check if we have a hardware radio switch. */ | |||
146 | if (base->rfSilent & AR_EEP_RFSILENT_ENABLED0x0001) { | |||
147 | sc->flags |= ATHN_FLAG_RFSILENT(1 << 5); | |||
148 | /* Get GPIO pin used by hardware radio switch. */ | |||
149 | sc->rfsilent_pin = MS(base->rfSilent,(((uint32_t)(base->rfSilent) & 0x001c) >> 2) | |||
150 | AR_EEP_RFSILENT_GPIO_SEL)(((uint32_t)(base->rfSilent) & 0x001c) >> 2); | |||
151 | /* Get polarity of hardware radio switch. */ | |||
152 | if (base->rfSilent & AR_EEP_RFSILENT_POLARITY0x0002) | |||
153 | sc->flags |= ATHN_FLAG_RFSILENT_REVERSED(1 << 6); | |||
154 | } | |||
155 | ||||
156 | /* Set the number of HW key cache entries. */ | |||
157 | sc->kc_entries = AR_KEYTABLE_SIZE128; | |||
158 | ||||
159 | sc->txchainmask = MS(base->txrxMask, AR_EEP_TX_MASK)(((uint32_t)(base->txrxMask) & 0xf0) >> 4); | |||
160 | sc->rxchainmask = MS(base->txrxMask, AR_EEP_RX_MASK)(((uint32_t)(base->txrxMask) & 0x0f) >> 0); | |||
161 | ||||
162 | /* Fast PLL clock is always supported. */ | |||
163 | sc->flags |= ATHN_FLAG_FAST_PLL_CLOCK(1 << 4); | |||
164 | ||||
165 | /* Enable PA predistortion if supported. */ | |||
166 | if (base->featureEnable & AR_EEP_PAPRD0x20) | |||
167 | sc->flags |= ATHN_FLAG_PAPRD(1 << 3); | |||
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 | if ((base->miscConfiguration & AR_EEP_CHAIN_MASK_REDUCE0x08) && | |||
173 | sc->txchainmask == 0x7) | |||
174 | sc->flags |= ATHN_FLAG_3TREDUCE_CHAIN(1 << 14); | |||
175 | ||||
176 | /* Select initialization values based on ROM. */ | |||
177 | type = MS(eep->baseEepHeader.txrxgain, AR_EEP_RX_GAIN)(((uint32_t)(eep->baseEepHeader.txrxgain) & 0x0f) >> 0); | |||
178 | if (!AR_SREV_9485(sc)((sc)->mac_ver == 0x240)) { | |||
179 | if (type == AR_EEP_RX_GAIN_WO_XLNA1) | |||
180 | sc->rx_gain = &ar9380_2_2_rx_gain_wo_xlna; | |||
181 | else | |||
182 | sc->rx_gain = &ar9380_2_2_rx_gain; | |||
183 | } else | |||
184 | sc->rx_gain = &ar9485_1_1_rx_gain; | |||
185 | ||||
186 | /* Select initialization values based on ROM. */ | |||
187 | type = MS(eep->baseEepHeader.txrxgain, AR_EEP_TX_GAIN)(((uint32_t)(eep->baseEepHeader.txrxgain) & 0xf0) >> 4); | |||
188 | if (!AR_SREV_9485(sc)((sc)->mac_ver == 0x240)) { | |||
189 | if (type == AR_EEP_TX_GAIN_HIGH_OB_DB1) | |||
190 | sc->tx_gain = &ar9380_2_2_tx_gain_high_ob_db; | |||
191 | else if (type == AR_EEP_TX_GAIN_LOW_OB_DB2) | |||
192 | sc->tx_gain = &ar9380_2_2_tx_gain_low_ob_db; | |||
193 | else if (type == AR_EEP_TX_GAIN_HIGH_POWER3) | |||
194 | sc->tx_gain = &ar9380_2_2_tx_gain_high_power; | |||
195 | else | |||
196 | sc->tx_gain = &ar9380_2_2_tx_gain; | |||
197 | } else | |||
198 | sc->tx_gain = &ar9485_1_1_tx_gain; | |||
199 | } | |||
200 | ||||
201 | const uint8_t * | |||
202 | 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 | for (i = 0; i < nitems(ar9380_rom_templates)(sizeof((ar9380_rom_templates)) / sizeof((ar9380_rom_templates )[0])); i++) | |||
208 | if (ar9380_rom_templates[i][1] == ref) | |||
209 | return (ar9380_rom_templates[i]); | |||
210 | return (NULL((void *)0)); | |||
211 | } | |||
212 | ||||
213 | void | |||
214 | ar9380_swap_rom(struct athn_softc *sc) | |||
215 | { | |||
216 | #if BYTE_ORDER1234 == BIG_ENDIAN4321 | |||
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])(__uint16_t)(__builtin_constant_p(base->regDmn[0]) ? (__uint16_t )(((__uint16_t)(base->regDmn[0]) & 0xffU) << 8 | ((__uint16_t)(base->regDmn[0]) & 0xff00U) >> 8) : __swap16md(base->regDmn[0])); | |||
223 | base->regDmn[1] = swap16(base->regDmn[1])(__uint16_t)(__builtin_constant_p(base->regDmn[1]) ? (__uint16_t )(((__uint16_t)(base->regDmn[1]) & 0xffU) << 8 | ((__uint16_t)(base->regDmn[1]) & 0xff00U) >> 8) : __swap16md(base->regDmn[1])); | |||
224 | base->swreg = swap32(base->swreg)(__uint32_t)(__builtin_constant_p(base->swreg) ? (__uint32_t )(((__uint32_t)(base->swreg) & 0xff) << 24 | ((__uint32_t )(base->swreg) & 0xff00) << 8 | ((__uint32_t)(base ->swreg) & 0xff0000) >> 8 | ((__uint32_t)(base-> swreg) & 0xff000000) >> 24) : __swap32md(base->swreg )); | |||
225 | ||||
226 | modal = &eep->modalHeader2G; | |||
227 | modal->antCtrlCommon = swap32(modal->antCtrlCommon)(__uint32_t)(__builtin_constant_p(modal->antCtrlCommon) ? ( __uint32_t)(((__uint32_t)(modal->antCtrlCommon) & 0xff ) << 24 | ((__uint32_t)(modal->antCtrlCommon) & 0xff00 ) << 8 | ((__uint32_t)(modal->antCtrlCommon) & 0xff0000 ) >> 8 | ((__uint32_t)(modal->antCtrlCommon) & 0xff000000 ) >> 24) : __swap32md(modal->antCtrlCommon)); | |||
228 | modal->antCtrlCommon2 = swap32(modal->antCtrlCommon2)(__uint32_t)(__builtin_constant_p(modal->antCtrlCommon2) ? (__uint32_t)(((__uint32_t)(modal->antCtrlCommon2) & 0xff ) << 24 | ((__uint32_t)(modal->antCtrlCommon2) & 0xff00) << 8 | ((__uint32_t)(modal->antCtrlCommon2) & 0xff0000) >> 8 | ((__uint32_t)(modal->antCtrlCommon2 ) & 0xff000000) >> 24) : __swap32md(modal->antCtrlCommon2 )); | |||
229 | modal->papdRateMaskHt20 = swap32(modal->papdRateMaskHt20)(__uint32_t)(__builtin_constant_p(modal->papdRateMaskHt20) ? (__uint32_t)(((__uint32_t)(modal->papdRateMaskHt20) & 0xff) << 24 | ((__uint32_t)(modal->papdRateMaskHt20 ) & 0xff00) << 8 | ((__uint32_t)(modal->papdRateMaskHt20 ) & 0xff0000) >> 8 | ((__uint32_t)(modal->papdRateMaskHt20 ) & 0xff000000) >> 24) : __swap32md(modal->papdRateMaskHt20 )); | |||
230 | modal->papdRateMaskHt40 = swap32(modal->papdRateMaskHt40)(__uint32_t)(__builtin_constant_p(modal->papdRateMaskHt40) ? (__uint32_t)(((__uint32_t)(modal->papdRateMaskHt40) & 0xff) << 24 | ((__uint32_t)(modal->papdRateMaskHt40 ) & 0xff00) << 8 | ((__uint32_t)(modal->papdRateMaskHt40 ) & 0xff0000) >> 8 | ((__uint32_t)(modal->papdRateMaskHt40 ) & 0xff000000) >> 24) : __swap32md(modal->papdRateMaskHt40 )); | |||
231 | for (i = 0; i < AR9380_MAX_CHAINS3; i++) | |||
232 | modal->antCtrlChain[i] = swap16(modal->antCtrlChain[i])(__uint16_t)(__builtin_constant_p(modal->antCtrlChain[i]) ? (__uint16_t)(((__uint16_t)(modal->antCtrlChain[i]) & 0xffU ) << 8 | ((__uint16_t)(modal->antCtrlChain[i]) & 0xff00U) >> 8) : __swap16md(modal->antCtrlChain[i]) ); | |||
233 | ||||
234 | modal = &eep->modalHeader5G; | |||
235 | modal->antCtrlCommon = swap32(modal->antCtrlCommon)(__uint32_t)(__builtin_constant_p(modal->antCtrlCommon) ? ( __uint32_t)(((__uint32_t)(modal->antCtrlCommon) & 0xff ) << 24 | ((__uint32_t)(modal->antCtrlCommon) & 0xff00 ) << 8 | ((__uint32_t)(modal->antCtrlCommon) & 0xff0000 ) >> 8 | ((__uint32_t)(modal->antCtrlCommon) & 0xff000000 ) >> 24) : __swap32md(modal->antCtrlCommon)); | |||
236 | modal->antCtrlCommon2 = swap32(modal->antCtrlCommon2)(__uint32_t)(__builtin_constant_p(modal->antCtrlCommon2) ? (__uint32_t)(((__uint32_t)(modal->antCtrlCommon2) & 0xff ) << 24 | ((__uint32_t)(modal->antCtrlCommon2) & 0xff00) << 8 | ((__uint32_t)(modal->antCtrlCommon2) & 0xff0000) >> 8 | ((__uint32_t)(modal->antCtrlCommon2 ) & 0xff000000) >> 24) : __swap32md(modal->antCtrlCommon2 )); | |||
237 | modal->papdRateMaskHt20 = swap32(modal->papdRateMaskHt20)(__uint32_t)(__builtin_constant_p(modal->papdRateMaskHt20) ? (__uint32_t)(((__uint32_t)(modal->papdRateMaskHt20) & 0xff) << 24 | ((__uint32_t)(modal->papdRateMaskHt20 ) & 0xff00) << 8 | ((__uint32_t)(modal->papdRateMaskHt20 ) & 0xff0000) >> 8 | ((__uint32_t)(modal->papdRateMaskHt20 ) & 0xff000000) >> 24) : __swap32md(modal->papdRateMaskHt20 )); | |||
238 | modal->papdRateMaskHt40 = swap32(modal->papdRateMaskHt40)(__uint32_t)(__builtin_constant_p(modal->papdRateMaskHt40) ? (__uint32_t)(((__uint32_t)(modal->papdRateMaskHt40) & 0xff) << 24 | ((__uint32_t)(modal->papdRateMaskHt40 ) & 0xff00) << 8 | ((__uint32_t)(modal->papdRateMaskHt40 ) & 0xff0000) >> 8 | ((__uint32_t)(modal->papdRateMaskHt40 ) & 0xff000000) >> 24) : __swap32md(modal->papdRateMaskHt40 )); | |||
239 | for (i = 0; i < AR9380_MAX_CHAINS3; i++) | |||
240 | modal->antCtrlChain[i] = swap16(modal->antCtrlChain[i])(__uint16_t)(__builtin_constant_p(modal->antCtrlChain[i]) ? (__uint16_t)(((__uint16_t)(modal->antCtrlChain[i]) & 0xffU ) << 8 | ((__uint16_t)(modal->antCtrlChain[i]) & 0xff00U) >> 8) : __swap16md(modal->antCtrlChain[i]) ); | |||
241 | #endif | |||
242 | } | |||
243 | ||||
244 | void | |||
245 | ar9380_get_paprd_masks(struct athn_softc *sc, struct ieee80211_channel *c, | |||
246 | uint32_t *ht20mask, uint32_t *ht40mask) | |||
247 | { | |||
248 | const struct ar9380_eeprom *eep = sc->eep; | |||
249 | const struct ar9380_modal_eep_header *modal; | |||
250 | ||||
251 | if (IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)) | |||
252 | modal = &eep->modalHeader2G; | |||
253 | else | |||
254 | modal = &eep->modalHeader5G; | |||
255 | *ht20mask = modal->papdRateMaskHt20; | |||
256 | *ht40mask = modal->papdRateMaskHt40; | |||
257 | } | |||
258 | ||||
259 | int | |||
260 | ar9380_set_synth(struct athn_softc *sc, struct ieee80211_channel *c, | |||
261 | struct ieee80211_channel *extc) | |||
262 | { | |||
263 | uint32_t freq = c->ic_freq; | |||
264 | uint32_t chansel, phy; | |||
265 | ||||
266 | if (IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)) { | |||
267 | if (AR_SREV_9485(sc)((sc)->mac_ver == 0x240)) | |||
268 | chansel = ((freq << 16) - 215) / 15; | |||
269 | else | |||
270 | chansel = (freq << 16) / 15; | |||
271 | AR_WRITE(sc, AR_PHY_SYNTH_CONTROL, AR9380_BMODE)(sc)->ops.write((sc), (0x0a340), (0x20000000)); | |||
272 | } else { | |||
273 | chansel = (freq << 15) / 15; | |||
274 | chansel >>= 1; | |||
275 | AR_WRITE(sc, AR_PHY_SYNTH_CONTROL, 0)(sc)->ops.write((sc), (0x0a340), (0)); | |||
276 | } | |||
277 | ||||
278 | /* Enable Long Shift Select for synthesizer. */ | |||
279 | AR_SETBITS(sc, AR_PHY_65NM_CH0_SYNTH4,(sc)->ops.write((sc), (0x1608c), ((sc)->ops.read((sc), ( 0x1608c)) | (0x00000002))) | |||
280 | AR_PHY_SYNTH4_LONG_SHIFT_SELECT)(sc)->ops.write((sc), (0x1608c), ((sc)->ops.read((sc), ( 0x1608c)) | (0x00000002))); | |||
281 | AR_WRITE_BARRIER(sc)(sc)->ops.write_barrier((sc)); | |||
282 | ||||
283 | /* Program synthesizer. */ | |||
284 | phy = (chansel << 2) | AR9380_FRACMODE0x40000000; | |||
285 | DPRINTFN(4, ("AR_PHY_65NM_CH0_SYNTH7=0x%08x\n", phy)); | |||
286 | AR_WRITE(sc, AR_PHY_65NM_CH0_SYNTH7, phy)(sc)->ops.write((sc), (0x16098), (phy)); | |||
287 | AR_WRITE_BARRIER(sc)(sc)->ops.write_barrier((sc)); | |||
288 | /* Toggle Load Synth Channel bit. */ | |||
289 | AR_WRITE(sc, AR_PHY_65NM_CH0_SYNTH7, phy | AR9380_LOAD_SYNTH)(sc)->ops.write((sc), (0x16098), (phy | 0x80000000)); | |||
290 | AR_WRITE_BARRIER(sc)(sc)->ops.write_barrier((sc)); | |||
291 | return (0); | |||
292 | } | |||
293 | ||||
294 | void | |||
295 | ar9380_init_from_rom(struct athn_softc *sc, struct ieee80211_channel *c, | |||
296 | struct ieee80211_channel *extc) | |||
297 | { | |||
298 | 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 | if (IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)) | |||
305 | modal = &eep->modalHeader2G; | |||
306 | else | |||
307 | modal = &eep->modalHeader5G; | |||
308 | ||||
309 | /* Apply XPA bias level. */ | |||
310 | if (AR_SREV_9485(sc)((sc)->mac_ver == 0x240)) { | |||
311 | reg = AR_READ(sc, AR9485_PHY_65NM_CH0_TOP2)(sc)->ops.read((sc), (0x16284)); | |||
312 | reg = RW(reg, AR9485_PHY_65NM_CH0_TOP2_XPABIASLVL,(((reg) & ~0x0000f000) | (((uint32_t)(modal->xpaBiasLvl ) << 12) & 0x0000f000)) | |||
313 | modal->xpaBiasLvl)(((reg) & ~0x0000f000) | (((uint32_t)(modal->xpaBiasLvl ) << 12) & 0x0000f000)); | |||
314 | AR_WRITE(sc, AR9485_PHY_65NM_CH0_TOP2, reg)(sc)->ops.write((sc), (0x16284), (reg)); | |||
315 | } else { | |||
316 | reg = AR_READ(sc, AR_PHY_65NM_CH0_TOP)(sc)->ops.read((sc), (0x16288)); | |||
317 | reg = RW(reg, AR_PHY_65NM_CH0_TOP_XPABIASLVL,(((reg) & ~0x00000300) | (((uint32_t)(modal->xpaBiasLvl & 0x3) << 8) & 0x00000300)) | |||
318 | modal->xpaBiasLvl & 0x3)(((reg) & ~0x00000300) | (((uint32_t)(modal->xpaBiasLvl & 0x3) << 8) & 0x00000300)); | |||
319 | AR_WRITE(sc, AR_PHY_65NM_CH0_TOP, reg)(sc)->ops.write((sc), (0x16288), (reg)); | |||
320 | reg = AR_READ(sc, AR_PHY_65NM_CH0_THERM)(sc)->ops.read((sc), (0x16290)); | |||
321 | reg = RW(reg, AR_PHY_65NM_CH0_THERM_XPABIASLVL_MSB,(((reg) & ~0x00000003) | (((uint32_t)(modal->xpaBiasLvl >> 2) << 0) & 0x00000003)) | |||
322 | modal->xpaBiasLvl >> 2)(((reg) & ~0x00000003) | (((uint32_t)(modal->xpaBiasLvl >> 2) << 0) & 0x00000003)); | |||
323 | reg |= AR_PHY_65NM_CH0_THERM_XPASHORT2GND0x00000004; | |||
324 | AR_WRITE(sc, AR_PHY_65NM_CH0_THERM, reg)(sc)->ops.write((sc), (0x16290), (reg)); | |||
325 | } | |||
326 | ||||
327 | /* Apply antenna control. */ | |||
328 | reg = AR_READ(sc, AR_PHY_SWITCH_COM)(sc)->ops.read((sc), (0x0a288)); | |||
329 | reg = RW(reg, AR_SWITCH_TABLE_COM_ALL, modal->antCtrlCommon)(((reg) & ~0x0000ffff) | (((uint32_t)(modal->antCtrlCommon ) << 0) & 0x0000ffff)); | |||
330 | AR_WRITE(sc, AR_PHY_SWITCH_COM, reg)(sc)->ops.write((sc), (0x0a288), (reg)); | |||
331 | reg = AR_READ(sc, AR_PHY_SWITCH_COM_2)(sc)->ops.read((sc), (0x0a28c)); | |||
332 | reg = RW(reg, AR_SWITCH_TABLE_COM_2_ALL, modal->antCtrlCommon2)(((reg) & ~0x00ffffff) | (((uint32_t)(modal->antCtrlCommon2 ) << 0) & 0x00ffffff)); | |||
333 | AR_WRITE(sc, AR_PHY_SWITCH_COM_2, reg)(sc)->ops.write((sc), (0x0a28c), (reg)); | |||
334 | ||||
335 | maxchains = AR_SREV_9485(sc)((sc)->mac_ver == 0x240) ? 1 : AR9380_MAX_CHAINS3; | |||
336 | for (i = 0; i < maxchains; i++) { | |||
337 | reg = AR_READ(sc, AR_PHY_SWITCH_CHAIN(i))(sc)->ops.read((sc), ((0x0a284 + (i) * 0x1000))); | |||
338 | reg = RW(reg, AR_SWITCH_TABLE_ALL, modal->antCtrlChain[i])(((reg) & ~0x00000fff) | (((uint32_t)(modal->antCtrlChain [i]) << 0) & 0x00000fff)); | |||
339 | AR_WRITE(sc, AR_PHY_SWITCH_CHAIN(i), reg)(sc)->ops.write((sc), ((0x0a284 + (i) * 0x1000)), (reg)); | |||
340 | } | |||
341 | ||||
342 | if (AR_SREV_9485(sc)((sc)->mac_ver == 0x240)) { | |||
343 | ant_div_ctrl = eep->base_ext1.ant_div_control; | |||
344 | reg = AR_READ(sc, AR_PHY_MC_GAIN_CTRL)(sc)->ops.read((sc), (0x09e28)); | |||
345 | reg = RW(reg, AR_PHY_MC_GAIN_CTRL_ANT_DIV_CTRL_ALL,(((reg) & ~0x7e000000) | (((uint32_t)((((uint32_t)(ant_div_ctrl ) & 0x3f) >> 0)) << 25) & 0x7e000000)) | |||
346 | MS(ant_div_ctrl, AR_EEP_ANT_DIV_CTRL_ALL))(((reg) & ~0x7e000000) | (((uint32_t)((((uint32_t)(ant_div_ctrl ) & 0x3f) >> 0)) << 25) & 0x7e000000)); | |||
347 | if (ant_div_ctrl & AR_EEP_ANT_DIV_CTRL_ANT_DIV0x40) | |||
348 | reg |= AR_PHY_MC_GAIN_CTRL_ENABLE_ANT_DIV0x01000000; | |||
349 | else | |||
350 | reg &= ~AR_PHY_MC_GAIN_CTRL_ENABLE_ANT_DIV0x01000000; | |||
351 | AR_WRITE(sc, AR_PHY_MC_GAIN_CTRL, reg)(sc)->ops.write((sc), (0x09e28), (reg)); | |||
352 | reg = AR_READ(sc, AR_PHY_CCK_DETECT)(sc)->ops.read((sc), (0x09fc0)); | |||
353 | if (ant_div_ctrl & AR_EEP_ANT_DIV_CTRL_FAST_DIV0x80) | |||
354 | reg |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV0x00002000; | |||
355 | else | |||
356 | reg &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV0x00002000; | |||
357 | AR_WRITE(sc, AR_PHY_CCK_DETECT, reg)(sc)->ops.write((sc), (0x09fc0), (reg)); | |||
358 | } | |||
359 | ||||
360 | if (eep->baseEepHeader.miscConfiguration & AR_EEP_DRIVE_STRENGTH0x01) { | |||
361 | /* Apply drive strength. */ | |||
362 | reg = AR_READ(sc, AR_PHY_65NM_CH0_BIAS1)(sc)->ops.read((sc), (0x160c0)); | |||
363 | reg = RW(reg, AR_PHY_65NM_CH0_BIAS1_0, 5)(((reg) & ~0x000001c0) | (((uint32_t)(5) << 6) & 0x000001c0)); | |||
364 | reg = RW(reg, AR_PHY_65NM_CH0_BIAS1_1, 5)(((reg) & ~0x00000e00) | (((uint32_t)(5) << 9) & 0x00000e00)); | |||
365 | reg = RW(reg, AR_PHY_65NM_CH0_BIAS1_2, 5)(((reg) & ~0x00007000) | (((uint32_t)(5) << 12) & 0x00007000)); | |||
366 | reg = RW(reg, AR_PHY_65NM_CH0_BIAS1_3, 5)(((reg) & ~0x00038000) | (((uint32_t)(5) << 15) & 0x00038000)); | |||
367 | reg = RW(reg, AR_PHY_65NM_CH0_BIAS1_4, 5)(((reg) & ~0x001c0000) | (((uint32_t)(5) << 18) & 0x001c0000)); | |||
368 | reg = RW(reg, AR_PHY_65NM_CH0_BIAS1_5, 5)(((reg) & ~0x00e00000) | (((uint32_t)(5) << 21) & 0x00e00000)); | |||
369 | AR_WRITE(sc, AR_PHY_65NM_CH0_BIAS1, reg)(sc)->ops.write((sc), (0x160c0), (reg)); | |||
370 | ||||
371 | reg = AR_READ(sc, AR_PHY_65NM_CH0_BIAS2)(sc)->ops.read((sc), (0x160c4)); | |||
372 | reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_0, 5)(((reg) & ~0x000000e0) | (((uint32_t)(5) << 5) & 0x000000e0)); | |||
373 | reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_1, 5)(((reg) & ~0x00000700) | (((uint32_t)(5) << 8) & 0x00000700)); | |||
374 | reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_2, 5)(((reg) & ~0x00003800) | (((uint32_t)(5) << 11) & 0x00003800)); | |||
375 | reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_3, 5)(((reg) & ~0x0001c000) | (((uint32_t)(5) << 14) & 0x0001c000)); | |||
376 | reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_4, 5)(((reg) & ~0x000e0000) | (((uint32_t)(5) << 17) & 0x000e0000)); | |||
377 | reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_5, 5)(((reg) & ~0x00700000) | (((uint32_t)(5) << 20) & 0x00700000)); | |||
378 | reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_6, 5)(((reg) & ~0x03800000) | (((uint32_t)(5) << 23) & 0x03800000)); | |||
379 | reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_7, 5)(((reg) & ~0x1c000000) | (((uint32_t)(5) << 26) & 0x1c000000)); | |||
380 | reg = RW(reg, AR_PHY_65NM_CH0_BIAS2_8, 5)(((reg) & ~0xe0000000) | (((uint32_t)(5) << 29) & 0xe0000000)); | |||
381 | AR_WRITE(sc, AR_PHY_65NM_CH0_BIAS2, reg)(sc)->ops.write((sc), (0x160c4), (reg)); | |||
382 | ||||
383 | reg = AR_READ(sc, AR_PHY_65NM_CH0_BIAS4)(sc)->ops.read((sc), (0x160cc)); | |||
384 | reg = RW(reg, AR_PHY_65NM_CH0_BIAS4_0, 5)(((reg) & ~0x03800000) | (((uint32_t)(5) << 23) & 0x03800000)); | |||
385 | reg = RW(reg, AR_PHY_65NM_CH0_BIAS4_1, 5)(((reg) & ~0x1c000000) | (((uint32_t)(5) << 26) & 0x1c000000)); | |||
386 | reg = RW(reg, AR_PHY_65NM_CH0_BIAS4_2, 5)(((reg) & ~0xe0000000) | (((uint32_t)(5) << 29) & 0xe0000000)); | |||
387 | AR_WRITE(sc, AR_PHY_65NM_CH0_BIAS4, reg)(sc)->ops.write((sc), (0x160cc), (reg)); | |||
388 | } | |||
389 | ||||
390 | /* Apply attenuation settings. */ | |||
391 | maxchains = AR_SREV_9485(sc)((sc)->mac_ver == 0x240) ? 1 : AR9380_MAX_CHAINS3; | |||
392 | for (i = 0; i < maxchains; i++) { | |||
393 | if (IEEE80211_IS_CHAN_5GHZ(c)(((c)->ic_flags & 0x0100) != 0) && | |||
394 | eep->base_ext2.xatten1DBLow[i] != 0) { | |||
395 | if (c->ic_freq <= 5500) { | |||
396 | db = athn_interpolate(c->ic_freq, | |||
397 | 5180, eep->base_ext2.xatten1DBLow[i], | |||
398 | 5500, modal->xatten1DB[i]); | |||
399 | } else { | |||
400 | db = athn_interpolate(c->ic_freq, | |||
401 | 5500, modal->xatten1DB[i], | |||
402 | 5785, eep->base_ext2.xatten1DBHigh[i]); | |||
403 | } | |||
404 | } else | |||
405 | db = modal->xatten1DB[i]; | |||
406 | if (IEEE80211_IS_CHAN_5GHZ(c)(((c)->ic_flags & 0x0100) != 0) && | |||
407 | eep->base_ext2.xatten1MarginLow[i] != 0) { | |||
408 | if (c->ic_freq <= 5500) { | |||
409 | margin = athn_interpolate(c->ic_freq, | |||
410 | 5180, eep->base_ext2.xatten1MarginLow[i], | |||
411 | 5500, modal->xatten1Margin[i]); | |||
412 | } else { | |||
413 | margin = athn_interpolate(c->ic_freq, | |||
414 | 5500, modal->xatten1Margin[i], | |||
415 | 5785, eep->base_ext2.xatten1MarginHigh[i]); | |||
416 | } | |||
417 | } else | |||
418 | margin = modal->xatten1Margin[i]; | |||
419 | reg = AR_READ(sc, AR_PHY_EXT_ATTEN_CTL(i))(sc)->ops.read((sc), ((0x09e18 + (i) * 0x1000))); | |||
420 | reg = RW(reg, AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, db)(((reg) & ~0x0000003f) | (((uint32_t)(db) << 0) & 0x0000003f)); | |||
421 | reg = RW(reg, AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, margin)(((reg) & ~0x0001f000) | (((uint32_t)(margin) << 12 ) & 0x0001f000)); | |||
422 | AR_WRITE(sc, AR_PHY_EXT_ATTEN_CTL(i), reg)(sc)->ops.write((sc), ((0x09e18 + (i) * 0x1000)), (reg)); | |||
423 | } | |||
424 | ||||
425 | /* Initialize switching regulator. */ | |||
426 | if (AR_SREV_9485(sc)((sc)->mac_ver == 0x240)) | |||
427 | ar9485_init_swreg(sc); | |||
428 | else | |||
429 | ar9380_init_swreg(sc); | |||
430 | ||||
431 | /* Apply tuning capabilities. */ | |||
432 | if (AR_SREV_9485(sc)((sc)->mac_ver == 0x240) && | |||
433 | (eep->baseEepHeader.featureEnable & AR_EEP_TUNING_CAPS0x40)) { | |||
434 | reg = AR_READ(sc, AR9485_PHY_CH0_XTAL)(sc)->ops.read((sc), (0x16290)); | |||
435 | reg = RW(reg, AR9485_PHY_CH0_XTAL_CAPINDAC,(((reg) & ~0x7f000000) | (((uint32_t)(eep->baseEepHeader .params_for_tuning_caps[0]) << 24) & 0x7f000000)) | |||
436 | eep->baseEepHeader.params_for_tuning_caps[0])(((reg) & ~0x7f000000) | (((uint32_t)(eep->baseEepHeader .params_for_tuning_caps[0]) << 24) & 0x7f000000)); | |||
437 | reg = RW(reg, AR9485_PHY_CH0_XTAL_CAPOUTDAC,(((reg) & ~0x00fe0000) | (((uint32_t)(eep->baseEepHeader .params_for_tuning_caps[0]) << 17) & 0x00fe0000)) | |||
438 | eep->baseEepHeader.params_for_tuning_caps[0])(((reg) & ~0x00fe0000) | (((uint32_t)(eep->baseEepHeader .params_for_tuning_caps[0]) << 17) & 0x00fe0000)); | |||
439 | AR_WRITE(sc, AR9485_PHY_CH0_XTAL, reg)(sc)->ops.write((sc), (0x16290), (reg)); | |||
440 | } | |||
441 | AR_WRITE_BARRIER(sc)(sc)->ops.write_barrier((sc)); | |||
442 | } | |||
443 | ||||
444 | void | |||
445 | ar9380_init_swreg(struct athn_softc *sc) | |||
446 | { | |||
447 | const struct ar9380_eeprom *eep = sc->eep; | |||
448 | ||||
449 | if (eep->baseEepHeader.featureEnable & AR_EEP_INTERNAL_REGULATOR0x10) { | |||
450 | /* Internal regulator is ON. */ | |||
451 | AR_CLRBITS(sc, AR_RTC_REG_CONTROL1,(sc)->ops.write((sc), (0x700c), ((sc)->ops.read((sc), ( 0x700c)) & ~(0x00000001))) | |||
452 | AR_RTC_REG_CONTROL1_SWREG_PROGRAM)(sc)->ops.write((sc), (0x700c), ((sc)->ops.read((sc), ( 0x700c)) & ~(0x00000001))); | |||
453 | AR_WRITE(sc, AR_RTC_REG_CONTROL0, eep->baseEepHeader.swreg)(sc)->ops.write((sc), (0x7008), (eep->baseEepHeader.swreg )); | |||
454 | AR_SETBITS(sc, AR_RTC_REG_CONTROL1,(sc)->ops.write((sc), (0x700c), ((sc)->ops.read((sc), ( 0x700c)) | (0x00000001))) | |||
455 | AR_RTC_REG_CONTROL1_SWREG_PROGRAM)(sc)->ops.write((sc), (0x700c), ((sc)->ops.read((sc), ( 0x700c)) | (0x00000001))); | |||
456 | } else | |||
457 | AR_SETBITS(sc, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_SWREG_PRD)(sc)->ops.write((sc), (0x7048), ((sc)->ops.read((sc), ( 0x7048)) | (0x00000004))); | |||
458 | AR_WRITE_BARRIER(sc)(sc)->ops.write_barrier((sc)); | |||
459 | } | |||
460 | ||||
461 | int | |||
462 | ar9485_pmu_write(struct athn_softc *sc, uint32_t addr, uint32_t val) | |||
463 | { | |||
464 | int ntries; | |||
465 | ||||
466 | AR_WRITE(sc, addr, val)(sc)->ops.write((sc), (addr), (val)); | |||
467 | /* Wait for write to complete. */ | |||
468 | for (ntries = 0; ntries < 100; ntries++) { | |||
469 | if (AR_READ(sc, addr)(sc)->ops.read((sc), (addr)) == val) | |||
470 | return (0); | |||
471 | AR_WRITE(sc, addr, val)(sc)->ops.write((sc), (addr), (val)); /* Insist. */ | |||
472 | AR_WRITE_BARRIER(sc)(sc)->ops.write_barrier((sc)); | |||
473 | DELAY(10)(*delay_func)(10); | |||
474 | } | |||
475 | return (ETIMEDOUT60); | |||
476 | } | |||
477 | ||||
478 | #define ar9486_pmu_readAR_READ AR_READ | |||
479 | ||||
480 | void | |||
481 | ar9485_init_swreg(struct athn_softc *sc) | |||
482 | { | |||
483 | const struct ar9380_eeprom *eep = sc->eep; | |||
484 | uint32_t reg; | |||
485 | ||||
486 | ar9485_pmu_write(sc, AR_PHY_PMU20x16c44, | |||
487 | ar9486_pmu_read(sc, AR_PHY_PMU2)(sc)->ops.read((sc), (0x16c44)) & ~AR_PHY_PMU2_PGM0x00200000); | |||
488 | ||||
489 | if (eep->baseEepHeader.featureEnable & AR_EEP_INTERNAL_REGULATOR0x10) { | |||
490 | ar9485_pmu_write(sc, AR_PHY_PMU10x16c40, 0x131dc17a); | |||
491 | ||||
492 | reg = ar9486_pmu_read(sc, AR_PHY_PMU2)(sc)->ops.read((sc), (0x16c44)); | |||
493 | reg = (reg & ~0xffc00000) | 0x10000000; | |||
494 | ar9485_pmu_write(sc, AR_PHY_PMU20x16c44, reg); | |||
495 | } else { | |||
496 | ar9485_pmu_write(sc, AR_PHY_PMU10x16c40, | |||
497 | ar9486_pmu_read(sc, AR_PHY_PMU1)(sc)->ops.read((sc), (0x16c40)) | AR_PHY_PMU1_PWD0x00000001); | |||
498 | } | |||
499 | ||||
500 | ar9485_pmu_write(sc, AR_PHY_PMU20x16c44, | |||
501 | ar9486_pmu_read(sc, AR_PHY_PMU2)(sc)->ops.read((sc), (0x16c44)) | AR_PHY_PMU2_PGM0x00200000); | |||
502 | } | |||
503 | ||||
504 | void | |||
505 | 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 | for (i = 0; i < nitems(freqs)(sizeof((freqs)) / sizeof((freqs)[0])); i++) { | |||
514 | spur = freqs[i] - c->ic_freq; | |||
515 | if (abs(spur) < 10) /* +/- 10MHz range. */ | |||
516 | break; | |||
517 | } | |||
518 | if (i == nitems(freqs)(sizeof((freqs)) / sizeof((freqs)[0]))) { | |||
519 | /* Disable CCK spur mitigation. */ | |||
520 | reg = AR_READ(sc, AR_PHY_AGC_CONTROL)(sc)->ops.read((sc), (0x0a2c4)); | |||
521 | reg = RW(reg, AR_PHY_AGC_CONTROL_YCOK_MAX, 0x5)(((reg) & ~0x000003c0) | (((uint32_t)(0x5) << 6) & 0x000003c0)); | |||
522 | AR_WRITE(sc, AR_PHY_AGC_CONTROL, reg)(sc)->ops.write((sc), (0x0a2c4), (reg)); | |||
523 | reg = AR_READ(sc, AR_PHY_CCK_SPUR_MIT)(sc)->ops.read((sc), (0x09fcc)); | |||
524 | reg = RW(reg, AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ, 0)(((reg) & ~0x1ffffe00) | (((uint32_t)(0) << 9) & 0x1ffffe00)); | |||
525 | reg &= ~AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT0x00000001; | |||
526 | AR_WRITE(sc, AR_PHY_CCK_SPUR_MIT, reg)(sc)->ops.write((sc), (0x09fcc), (reg)); | |||
527 | AR_WRITE_BARRIER(sc)(sc)->ops.write_barrier((sc)); | |||
528 | return; | |||
529 | } | |||
530 | freq = (spur * 524288) / 11; | |||
531 | ||||
532 | reg = AR_READ(sc, AR_PHY_AGC_CONTROL)(sc)->ops.read((sc), (0x0a2c4)); | |||
533 | reg = RW(reg, AR_PHY_AGC_CONTROL_YCOK_MAX, 0x7)(((reg) & ~0x000003c0) | (((uint32_t)(0x7) << 6) & 0x000003c0)); | |||
534 | AR_WRITE(sc, AR_PHY_AGC_CONTROL, reg)(sc)->ops.write((sc), (0x0a2c4), (reg)); | |||
535 | ||||
536 | reg = AR_READ(sc, AR_PHY_CCK_SPUR_MIT)(sc)->ops.read((sc), (0x09fcc)); | |||
537 | reg = RW(reg, AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ, freq)(((reg) & ~0x1ffffe00) | (((uint32_t)(freq) << 9) & 0x1ffffe00)); | |||
538 | reg = RW(reg, AR_PHY_CCK_SPUR_MIT_SPUR_RSSI_THR, 0x7f)(((reg) & ~0x000001fe) | (((uint32_t)(0x7f) << 1) & 0x000001fe)); | |||
539 | reg = RW(reg, AR_PHY_CCK_SPUR_MIT_SPUR_FILTER_TYPE, 0x2)(((reg) & ~0x60000000) | (((uint32_t)(0x2) << 29) & 0x60000000)); | |||
540 | reg |= AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT0x00000001; | |||
541 | AR_WRITE(sc, AR_PHY_CCK_SPUR_MIT, reg)(sc)->ops.write((sc), (0x09fcc), (reg)); | |||
542 | AR_WRITE_BARRIER(sc)(sc)->ops.write_barrier((sc)); | |||
543 | } | |||
544 | ||||
545 | void | |||
546 | ar9380_spur_mitigate_ofdm(struct athn_softc *sc, struct ieee80211_channel *c, | |||
547 | struct ieee80211_channel *extc) | |||
548 | { | |||
549 | 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 | if (IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)) | |||
556 | spurchans = eep->modalHeader2G.spurChans; | |||
557 | else | |||
558 | spurchans = eep->modalHeader5G.spurChans; | |||
559 | if (spurchans[0] == 0) | |||
560 | return; | |||
561 | ||||
562 | /* Disable OFDM spur mitigation. */ | |||
563 | AR_CLRBITS(sc, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_FILTER)(sc)->ops.write((sc), (0x0980c), ((sc)->ops.read((sc), ( 0x0980c)) & ~(0x40000000))); | |||
564 | ||||
565 | reg = AR_READ(sc, AR_PHY_TIMING11)(sc)->ops.read((sc), (0x09818)); | |||
566 | reg = RW(reg, AR_PHY_TIMING11_SPUR_FREQ_SD, 0)(((reg) & ~0x3ff00000) | (((uint32_t)(0) << 20) & 0x3ff00000)); | |||
567 | reg = RW(reg, AR_PHY_TIMING11_SPUR_DELTA_PHASE, 0)(((reg) & ~0x000fffff) | (((uint32_t)(0) << 0) & 0x000fffff)); | |||
568 | reg &= ~AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC0x40000000; | |||
569 | reg &= ~AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR0x80000000; | |||
570 | AR_WRITE(sc, AR_PHY_TIMING11, reg)(sc)->ops.write((sc), (0x09818), (reg)); | |||
571 | ||||
572 | AR_CLRBITS(sc, AR_PHY_SFCORR_EXT,(sc)->ops.write((sc), (0x0982c), ((sc)->ops.read((sc), ( 0x0982c)) & ~(0x10000000))) | |||
573 | AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD)(sc)->ops.write((sc), (0x0982c), ((sc)->ops.read((sc), ( 0x0982c)) & ~(0x10000000))); | |||
574 | ||||
575 | AR_CLRBITS(sc, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_RSSI)(sc)->ops.write((sc), (0x0980c), ((sc)->ops.read((sc), ( 0x0980c)) & ~(0x80000000))); | |||
576 | ||||
577 | reg = AR_READ(sc, AR_PHY_SPUR_REG)(sc)->ops.read((sc), (0x0981c)); | |||
578 | reg = RW(reg, AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0)(((reg) & ~0x03fc0000) | (((uint32_t)(0) << 18) & 0x03fc0000)); | |||
579 | reg &= ~AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI0x00000100; | |||
580 | reg &= ~AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT0x04000000; | |||
581 | reg &= ~AR_PHY_SPUR_REG_ENABLE_MASK_PPM0x00020000; | |||
582 | AR_WRITE(sc, AR_PHY_SPUR_REG, reg)(sc)->ops.write((sc), (0x0981c), (reg)); | |||
583 | AR_WRITE_BARRIER(sc)(sc)->ops.write_barrier((sc)); | |||
584 | ||||
585 | freq = c->ic_freq; | |||
586 | if (extc != NULL((void *)0)) { | |||
587 | range = 19; /* +/- 19MHz range. */ | |||
588 | if (AR_READ(sc, AR_PHY_GEN_CTRL)(sc)->ops.read((sc), (0x0a204)) & AR_PHY_GC_DYN2040_PRI_CH0x00000010) | |||
589 | freq += 10; | |||
590 | else | |||
591 | freq -= 10; | |||
592 | } else | |||
593 | range = 10; /* +/- 10MHz range. */ | |||
594 | for (i = 0; i < AR9380_EEPROM_MODAL_SPURS5; i++) { | |||
595 | spur = spurchans[i]; | |||
596 | if (spur == 0) | |||
597 | return; | |||
598 | /* Convert to frequency. */ | |||
599 | if (IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)) | |||
600 | spur = 2300 + spur; | |||
601 | else | |||
602 | spur = 4900 + (spur * 5); | |||
603 | spur -= freq; | |||
604 | if (abs(spur) < range) | |||
605 | break; | |||
606 | } | |||
607 | if (i == AR9380_EEPROM_MODAL_SPURS5) | |||
608 | return; | |||
609 | ||||
610 | /* Enable OFDM spur mitigation. */ | |||
611 | if (extc != NULL((void *)0)) { | |||
612 | spur_delta_phase = (spur * 131072) / 5; | |||
613 | reg = AR_READ(sc, AR_PHY_GEN_CTRL)(sc)->ops.read((sc), (0x0a204)); | |||
614 | if (spur < 0) { | |||
615 | spur_subchannel_sd = | |||
616 | (reg & AR_PHY_GC_DYN2040_PRI_CH0x00000010) == 0; | |||
617 | spur_off = spur + 10; | |||
618 | } else { | |||
619 | spur_subchannel_sd = | |||
620 | (reg & AR_PHY_GC_DYN2040_PRI_CH0x00000010) != 0; | |||
621 | spur_off = spur - 10; | |||
622 | } | |||
623 | } else { | |||
624 | spur_delta_phase = (spur * 262144) / 5; | |||
625 | spur_subchannel_sd = 0; | |||
626 | spur_off = spur; | |||
627 | } | |||
628 | spur_freq_sd = (spur_off * 512) / 11; | |||
629 | ||||
630 | AR_SETBITS(sc, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_FILTER)(sc)->ops.write((sc), (0x0980c), ((sc)->ops.read((sc), ( 0x0980c)) | (0x40000000))); | |||
631 | ||||
632 | reg = AR_READ(sc, AR_PHY_TIMING11)(sc)->ops.read((sc), (0x09818)); | |||
633 | reg = RW(reg, AR_PHY_TIMING11_SPUR_FREQ_SD, spur_freq_sd)(((reg) & ~0x3ff00000) | (((uint32_t)(spur_freq_sd) << 20) & 0x3ff00000)); | |||
634 | reg = RW(reg, AR_PHY_TIMING11_SPUR_DELTA_PHASE, spur_delta_phase)(((reg) & ~0x000fffff) | (((uint32_t)(spur_delta_phase) << 0) & 0x000fffff)); | |||
635 | reg |= AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC0x40000000; | |||
636 | reg |= AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR0x80000000; | |||
637 | AR_WRITE(sc, AR_PHY_TIMING11, reg)(sc)->ops.write((sc), (0x09818), (reg)); | |||
638 | ||||
639 | reg = AR_READ(sc, AR_PHY_SFCORR_EXT)(sc)->ops.read((sc), (0x0982c)); | |||
640 | if (spur_subchannel_sd) | |||
641 | reg |= AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD0x10000000; | |||
642 | else | |||
643 | reg &= ~AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD0x10000000; | |||
644 | AR_WRITE(sc, AR_PHY_SFCORR_EXT, reg)(sc)->ops.write((sc), (0x0982c), (reg)); | |||
645 | ||||
646 | AR_SETBITS(sc, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_RSSI)(sc)->ops.write((sc), (0x0980c), ((sc)->ops.read((sc), ( 0x0980c)) | (0x80000000))); | |||
647 | ||||
648 | reg = AR_READ(sc, AR_PHY_SPUR_REG)(sc)->ops.read((sc), (0x0981c)); | |||
649 | reg = RW(reg, AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0xff)(((reg) & ~0x03fc0000) | (((uint32_t)(0xff) << 18) & 0x03fc0000)); | |||
650 | reg = RW(reg, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH, 34)(((reg) & ~0x000000ff) | (((uint32_t)(34) << 0) & 0x000000ff)); | |||
651 | reg |= AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI0x00000100; | |||
652 | if (AR_READ(sc, AR_PHY_MODE)(sc)->ops.read((sc), (0x0a208)) & AR_PHY_MODE_DYNAMIC0x00000004) | |||
653 | reg |= AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT0x04000000; | |||
654 | reg |= AR_PHY_SPUR_REG_ENABLE_MASK_PPM0x00020000; | |||
655 | AR_WRITE(sc, AR_PHY_SPUR_REG, reg)(sc)->ops.write((sc), (0x0981c), (reg)); | |||
656 | ||||
657 | idx = (spur * 16) / 5; | |||
658 | if (idx < 0) | |||
659 | idx--; | |||
660 | ||||
661 | /* Write pilot mask. */ | |||
662 | AR_SETBITS(sc, AR_PHY_TIMING4,(sc)->ops.write((sc), (0x0980c), ((sc)->ops.read((sc), ( 0x0980c)) | (0x10000000 | 0x20000000))) | |||
663 | AR_PHY_TIMING4_ENABLE_PILOT_MASK |(sc)->ops.write((sc), (0x0980c), ((sc)->ops.read((sc), ( 0x0980c)) | (0x10000000 | 0x20000000))) | |||
664 | AR_PHY_TIMING4_ENABLE_CHAN_MASK)(sc)->ops.write((sc), (0x0980c), ((sc)->ops.read((sc), ( 0x0980c)) | (0x10000000 | 0x20000000))); | |||
665 | ||||
666 | reg = AR_READ(sc, AR_PHY_PILOT_SPUR_MASK)(sc)->ops.read((sc), (0x09c0c)); | |||
667 | reg = RW(reg, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A, idx)(((reg) & ~0x00000fe0) | (((uint32_t)(idx) << 5) & 0x00000fe0)); | |||
668 | reg = RW(reg, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A, 0x0c)(((reg) & ~0x0000001f) | (((uint32_t)(0x0c) << 0) & 0x0000001f)); | |||
669 | AR_WRITE(sc, AR_PHY_PILOT_SPUR_MASK, reg)(sc)->ops.write((sc), (0x09c0c), (reg)); | |||
670 | ||||
671 | reg = AR_READ(sc, AR_PHY_SPUR_MASK_A)(sc)->ops.read((sc), (0x0a220)); | |||
672 | reg = RW(reg, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A, idx)(((reg) & ~0x0001fc00) | (((uint32_t)(idx) << 10) & 0x0001fc00)); | |||
673 | reg = RW(reg, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0xa0)(((reg) & ~0x000003ff) | (((uint32_t)(0xa0) << 0) & 0x000003ff)); | |||
674 | AR_WRITE(sc, AR_PHY_SPUR_MASK_A, reg)(sc)->ops.write((sc), (0x0a220), (reg)); | |||
675 | ||||
676 | reg = AR_READ(sc, AR_PHY_CHAN_SPUR_MASK)(sc)->ops.read((sc), (0x09c10)); | |||
677 | reg = RW(reg, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A, idx)(((reg) & ~0x00000fe0) | (((uint32_t)(idx) << 5) & 0x00000fe0)); | |||
678 | reg = RW(reg, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A, 0x0c)(((reg) & ~0x0000001f) | (((uint32_t)(0x0c) << 0) & 0x0000001f)); | |||
679 | AR_WRITE(sc, AR_PHY_CHAN_SPUR_MASK, reg)(sc)->ops.write((sc), (0x09c10), (reg)); | |||
680 | AR_WRITE_BARRIER(sc)(sc)->ops.write_barrier((sc)); | |||
681 | } | |||
682 | ||||
683 | void | |||
684 | 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 | ar9380_spur_mitigate_cck(sc, c, extc); | |||
689 | ar9380_spur_mitigate_ofdm(sc, c, extc); | |||
690 | } | |||
691 | ||||
692 | void | |||
693 | ar9380_set_txpower(struct athn_softc *sc, struct ieee80211_channel *c, | |||
694 | struct ieee80211_channel *extc) | |||
695 | { | |||
696 | const struct ar9380_eeprom *eep = sc->eep; | |||
697 | uint8_t tpow_cck[4], tpow_ofdm[4]; | |||
698 | uint8_t tpow_ht20[14], tpow_ht40[14]; | |||
699 | int16_t power[ATHN_POWER_COUNT68]; | |||
700 | ||||
701 | if (IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)) { | |||
| ||||
702 | /* Get CCK target powers. */ | |||
703 | ar9003_get_lg_tpow(sc, c, AR_CTL_11B1, | |||
704 | eep->calTargetFbinCck, eep->calTargetPowerCck, | |||
705 | AR9380_NUM_2G_CCK_TARGET_POWERS2, tpow_cck); | |||
706 | ||||
707 | /* Get OFDM target powers. */ | |||
708 | ar9003_get_lg_tpow(sc, c, AR_CTL_11G2, | |||
709 | eep->calTargetFbin2G, eep->calTargetPower2G, | |||
710 | AR9380_NUM_2G_20_TARGET_POWERS3, tpow_ofdm); | |||
711 | ||||
712 | /* Get HT-20 target powers. */ | |||
713 | ar9003_get_ht_tpow(sc, c, AR_CTL_2GHT205, | |||
714 | eep->calTargetFbin2GHT20, eep->calTargetPower2GHT20, | |||
715 | AR9380_NUM_2G_20_TARGET_POWERS3, tpow_ht20); | |||
716 | ||||
717 | if (extc != NULL((void *)0)) { | |||
718 | /* Get HT-40 target powers. */ | |||
719 | ar9003_get_ht_tpow(sc, c, AR_CTL_2GHT407, | |||
720 | eep->calTargetFbin2GHT40, | |||
721 | eep->calTargetPower2GHT40, | |||
722 | AR9380_NUM_2G_40_TARGET_POWERS3, tpow_ht40); | |||
723 | } | |||
724 | } else { | |||
725 | /* Get OFDM target powers. */ | |||
726 | ar9003_get_lg_tpow(sc, c, AR_CTL_11A0, | |||
727 | eep->calTargetFbin5G, eep->calTargetPower5G, | |||
728 | AR9380_NUM_5G_20_TARGET_POWERS8, tpow_ofdm); | |||
729 | ||||
730 | /* Get HT-20 target powers. */ | |||
731 | ar9003_get_ht_tpow(sc, c, AR_CTL_5GHT206, | |||
732 | eep->calTargetFbin5GHT20, eep->calTargetPower5GHT20, | |||
733 | AR9380_NUM_5G_20_TARGET_POWERS8, tpow_ht20); | |||
734 | ||||
735 | if (extc != NULL((void *)0)) { | |||
736 | /* Get HT-40 target powers. */ | |||
737 | ar9003_get_ht_tpow(sc, c, AR_CTL_5GHT408, | |||
738 | eep->calTargetFbin5GHT40, | |||
739 | eep->calTargetPower5GHT40, | |||
740 | AR9380_NUM_5G_40_TARGET_POWERS8, tpow_ht40); | |||
741 | } | |||
742 | } | |||
743 | ||||
744 | memset(power, 0, sizeof(power))__builtin_memset((power), (0), (sizeof(power))); | |||
745 | /* Shuffle target powers across transmit rates. */ | |||
746 | power[ATHN_POWER_OFDM60 ] = | |||
747 | power[ATHN_POWER_OFDM91 ] = | |||
748 | power[ATHN_POWER_OFDM122] = | |||
749 | power[ATHN_POWER_OFDM183] = | |||
750 | power[ATHN_POWER_OFDM244] = tpow_ofdm[0]; | |||
751 | power[ATHN_POWER_OFDM365] = tpow_ofdm[1]; | |||
752 | power[ATHN_POWER_OFDM486] = tpow_ofdm[2]; | |||
753 | power[ATHN_POWER_OFDM547] = tpow_ofdm[3]; | |||
754 | if (IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)) { | |||
755 | power[ATHN_POWER_CCK1_LP8 ] = | |||
756 | power[ATHN_POWER_CCK2_LP9 ] = | |||
757 | power[ATHN_POWER_CCK2_SP10 ] = | |||
758 | power[ATHN_POWER_CCK55_LP11] = tpow_cck[0]; | |||
| ||||
759 | power[ATHN_POWER_CCK55_SP12] = tpow_cck[1]; | |||
760 | power[ATHN_POWER_CCK11_LP13] = tpow_cck[2]; | |||
761 | power[ATHN_POWER_CCK11_SP14] = tpow_cck[3]; | |||
762 | } | |||
763 | /* Next entry covers MCS0, MCS8 and MCS16. */ | |||
764 | power[ATHN_POWER_HT20( 0)(16 + (0))] = tpow_ht20[ 0]; | |||
765 | /* Next entry covers MCS1-3, MCS9-11 and MCS17-19. */ | |||
766 | power[ATHN_POWER_HT20( 1)(16 + (1))] = tpow_ht20[ 1]; | |||
767 | power[ATHN_POWER_HT20( 4)(16 + (4))] = tpow_ht20[ 2]; | |||
768 | power[ATHN_POWER_HT20( 5)(16 + (5))] = tpow_ht20[ 3]; | |||
769 | power[ATHN_POWER_HT20( 6)(16 + (6))] = tpow_ht20[ 4]; | |||
770 | power[ATHN_POWER_HT20( 7)(16 + (7))] = tpow_ht20[ 5]; | |||
771 | power[ATHN_POWER_HT20(12)(16 + (12))] = tpow_ht20[ 6]; | |||
772 | power[ATHN_POWER_HT20(13)(16 + (13))] = tpow_ht20[ 7]; | |||
773 | power[ATHN_POWER_HT20(14)(16 + (14))] = tpow_ht20[ 8]; | |||
774 | power[ATHN_POWER_HT20(15)(16 + (15))] = tpow_ht20[ 9]; | |||
775 | power[ATHN_POWER_HT20(20)(16 + (20))] = tpow_ht20[10]; | |||
776 | power[ATHN_POWER_HT20(21)(16 + (21))] = tpow_ht20[11]; | |||
777 | power[ATHN_POWER_HT20(22)(16 + (22))] = tpow_ht20[12]; | |||
778 | power[ATHN_POWER_HT20(23)(16 + (23))] = tpow_ht20[13]; | |||
779 | if (extc != NULL((void *)0)) { | |||
780 | /* Next entry covers MCS0, MCS8 and MCS16. */ | |||
781 | power[ATHN_POWER_HT40( 0)(40 + (0))] = tpow_ht40[ 0]; | |||
782 | /* Next entry covers MCS1-3, MCS9-11 and MCS17-19. */ | |||
783 | power[ATHN_POWER_HT40( 1)(40 + (1))] = tpow_ht40[ 1]; | |||
784 | power[ATHN_POWER_HT40( 4)(40 + (4))] = tpow_ht40[ 2]; | |||
785 | power[ATHN_POWER_HT40( 5)(40 + (5))] = tpow_ht40[ 3]; | |||
786 | power[ATHN_POWER_HT40( 6)(40 + (6))] = tpow_ht40[ 4]; | |||
787 | power[ATHN_POWER_HT40( 7)(40 + (7))] = tpow_ht40[ 5]; | |||
788 | power[ATHN_POWER_HT40(12)(40 + (12))] = tpow_ht40[ 6]; | |||
789 | power[ATHN_POWER_HT40(13)(40 + (13))] = tpow_ht40[ 7]; | |||
790 | power[ATHN_POWER_HT40(14)(40 + (14))] = tpow_ht40[ 8]; | |||
791 | power[ATHN_POWER_HT40(15)(40 + (15))] = tpow_ht40[ 9]; | |||
792 | power[ATHN_POWER_HT40(20)(40 + (20))] = tpow_ht40[10]; | |||
793 | power[ATHN_POWER_HT40(21)(40 + (21))] = tpow_ht40[11]; | |||
794 | power[ATHN_POWER_HT40(22)(40 + (22))] = tpow_ht40[12]; | |||
795 | power[ATHN_POWER_HT40(23)(40 + (23))] = tpow_ht40[13]; | |||
796 | } | |||
797 | ||||
798 | /* Write transmit power values to hardware. */ | |||
799 | ar9003_write_txpower(sc, power); | |||
800 | ||||
801 | /* Apply transmit power correction. */ | |||
802 | ar9380_set_correction(sc, c); | |||
803 | } | |||
804 | ||||
805 | void | |||
806 | ar9380_get_correction(struct athn_softc *sc, struct ieee80211_channel *c, | |||
807 | int chain, int *corr, int *temp) | |||
808 | { | |||
809 | 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 | int lo, hi, npiers; | |||
814 | ||||
815 | if (IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)) { | |||
816 | pierfreq = eep->calFreqPier2G; | |||
817 | pierdata = eep->calPierData2G[chain]; | |||
818 | npiers = AR9380_NUM_2G_CAL_PIERS3; | |||
819 | } else { | |||
820 | pierfreq = eep->calFreqPier5G; | |||
821 | pierdata = eep->calPierData5G[chain]; | |||
822 | npiers = AR9380_NUM_5G_CAL_PIERS8; | |||
823 | } | |||
824 | /* Find channel in ROM pier table. */ | |||
825 | fbin = athn_chan2fbin(c); | |||
826 | athn_get_pier_ival(fbin, pierfreq, npiers, &lo, &hi); | |||
827 | ||||
828 | *corr = athn_interpolate(fbin, | |||
829 | pierfreq[lo], pierdata[lo].refPower, | |||
830 | pierfreq[hi], pierdata[hi].refPower); | |||
831 | *temp = athn_interpolate(fbin, | |||
832 | pierfreq[lo], pierdata[lo].tempMeas, | |||
833 | pierfreq[hi], pierdata[hi].tempMeas); | |||
834 | } | |||
835 | ||||
836 | void | |||
837 | ar9380_set_correction(struct athn_softc *sc, struct ieee80211_channel *c) | |||
838 | { | |||
839 | const struct ar9380_eeprom *eep = sc->eep; | |||
840 | const struct ar9380_modal_eep_header *modal; | |||
841 | uint32_t reg; | |||
842 | int8_t slope; | |||
843 | int i, corr, temp, temp0; | |||
844 | ||||
845 | if (IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)) | |||
846 | modal = &eep->modalHeader2G; | |||
847 | else | |||
848 | modal = &eep->modalHeader5G; | |||
849 | ||||
850 | for (i = 0; i < AR9380_MAX_CHAINS3; i++) { | |||
851 | ar9380_get_correction(sc, c, i, &corr, &temp); | |||
852 | if (i == 0) | |||
853 | temp0 = temp; | |||
854 | ||||
855 | reg = AR_READ(sc, AR_PHY_TPC_11_B(i))(sc)->ops.read((sc), ((0x0a420 + (i) * 0x1000))); | |||
856 | reg = RW(reg, AR_PHY_TPC_11_OLPC_GAIN_DELTA, corr)(((reg) & ~0x00ff0000) | (((uint32_t)(corr) << 16) & 0x00ff0000)); | |||
857 | AR_WRITE(sc, AR_PHY_TPC_11_B(i), reg)(sc)->ops.write((sc), ((0x0a420 + (i) * 0x1000)), (reg)); | |||
858 | ||||
859 | /* Enable open loop power control. */ | |||
860 | reg = AR_READ(sc, AR_PHY_TPC_6_B(i))(sc)->ops.read((sc), ((0x0a40c + (i) * 0x1000))); | |||
861 | reg = RW(reg, AR_PHY_TPC_6_ERROR_EST_MODE, 3)(((reg) & ~0x03000000) | (((uint32_t)(3) << 24) & 0x03000000)); | |||
862 | AR_WRITE(sc, AR_PHY_TPC_6_B(i), reg)(sc)->ops.write((sc), ((0x0a40c + (i) * 0x1000)), (reg)); | |||
863 | } | |||
864 | ||||
865 | /* Enable temperature compensation. */ | |||
866 | if (IEEE80211_IS_CHAN_5GHZ(c)(((c)->ic_flags & 0x0100) != 0) && | |||
867 | eep->base_ext2.tempSlopeLow != 0) { | |||
868 | if (c->ic_freq <= 5500) { | |||
869 | slope = athn_interpolate(c->ic_freq, | |||
870 | 5180, eep->base_ext2.tempSlopeLow, | |||
871 | 5500, modal->tempSlope); | |||
872 | } else { | |||
873 | slope = athn_interpolate(c->ic_freq, | |||
874 | 5500, modal->tempSlope, | |||
875 | 5785, eep->base_ext2.tempSlopeHigh); | |||
876 | } | |||
877 | } else | |||
878 | slope = modal->tempSlope; | |||
879 | ||||
880 | reg = AR_READ(sc, AR_PHY_TPC_19)(sc)->ops.read((sc), (0x0a440)); | |||
881 | reg = RW(reg, AR_PHY_TPC_19_ALPHA_THERM, slope)(((reg) & ~0x000000ff) | (((uint32_t)(slope) << 0) & 0x000000ff)); | |||
882 | AR_WRITE(sc, AR_PHY_TPC_19, reg)(sc)->ops.write((sc), (0x0a440), (reg)); | |||
883 | ||||
884 | reg = AR_READ(sc, AR_PHY_TPC_18)(sc)->ops.read((sc), (0x0a43c)); | |||
885 | reg = RW(reg, AR_PHY_TPC_18_THERM_CAL, temp0)(((reg) & ~0x000000ff) | (((uint32_t)(temp0) << 0) & 0x000000ff)); | |||
886 | AR_WRITE(sc, AR_PHY_TPC_18, reg)(sc)->ops.write((sc), (0x0a43c), (reg)); | |||
887 | AR_WRITE_BARRIER(sc)(sc)->ops.write_barrier((sc)); | |||
888 | } |