File: | dev/ic/ar5416.c |
Warning: | line 627, column 44 The left operand of '+' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: ar5416.c,v 1.23 2022/01/09 05:42:38 jsg Exp $ */ | |||
2 | ||||
3 | /*- | |||
4 | * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr> | |||
5 | * Copyright (c) 2008-2009 Atheros Communications Inc. | |||
6 | * | |||
7 | * Permission to use, copy, modify, and/or distribute this software for any | |||
8 | * purpose with or without fee is hereby granted, provided that the above | |||
9 | * copyright notice and this permission notice appear in all copies. | |||
10 | * | |||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
18 | */ | |||
19 | ||||
20 | /* | |||
21 | * Driver for Atheros 802.11a/g/n chipsets. | |||
22 | * Routines for AR5416, AR5418 and AR9160 chipsets. | |||
23 | */ | |||
24 | ||||
25 | #include "bpfilter.h" | |||
26 | ||||
27 | #include <sys/param.h> | |||
28 | #include <sys/sockio.h> | |||
29 | #include <sys/mbuf.h> | |||
30 | #include <sys/kernel.h> | |||
31 | #include <sys/socket.h> | |||
32 | #include <sys/systm.h> | |||
33 | #include <sys/malloc.h> | |||
34 | #include <sys/queue.h> | |||
35 | #include <sys/timeout.h> | |||
36 | #include <sys/conf.h> | |||
37 | #include <sys/device.h> | |||
38 | #include <sys/endian.h> | |||
39 | ||||
40 | #include <machine/bus.h> | |||
41 | #include <machine/intr.h> | |||
42 | ||||
43 | #if NBPFILTER1 > 0 | |||
44 | #include <net/bpf.h> | |||
45 | #endif | |||
46 | #include <net/if.h> | |||
47 | #include <net/if_media.h> | |||
48 | ||||
49 | #include <netinet/in.h> | |||
50 | #include <netinet/if_ether.h> | |||
51 | ||||
52 | #include <net80211/ieee80211_var.h> | |||
53 | #include <net80211/ieee80211_amrr.h> | |||
54 | #include <net80211/ieee80211_ra.h> | |||
55 | #include <net80211/ieee80211_radiotap.h> | |||
56 | ||||
57 | #include <dev/ic/athnreg.h> | |||
58 | #include <dev/ic/athnvar.h> | |||
59 | ||||
60 | #include <dev/ic/ar5008reg.h> | |||
61 | #include <dev/ic/ar5416reg.h> | |||
62 | ||||
63 | int ar5416_attach(struct athn_softc *); | |||
64 | void ar5416_setup(struct athn_softc *); | |||
65 | void ar5416_swap_rom(struct athn_softc *); | |||
66 | const struct ar_spur_chan * | |||
67 | ar5416_get_spur_chans(struct athn_softc *, int); | |||
68 | int ar5416_set_synth(struct athn_softc *, struct ieee80211_channel *, | |||
69 | struct ieee80211_channel *); | |||
70 | uint8_t ar5416_reverse_bits(uint8_t, int); | |||
71 | uint8_t ar5416_get_rf_rev(struct athn_softc *); | |||
72 | void ar5416_init_from_rom(struct athn_softc *, struct ieee80211_channel *, | |||
73 | struct ieee80211_channel *); | |||
74 | int ar5416_init_calib(struct athn_softc *, struct ieee80211_channel *, | |||
75 | struct ieee80211_channel *); | |||
76 | void ar5416_set_power_calib(struct athn_softc *, | |||
77 | struct ieee80211_channel *); | |||
78 | void ar5416_set_txpower(struct athn_softc *, struct ieee80211_channel *, | |||
79 | struct ieee80211_channel *); | |||
80 | void ar5416_spur_mitigate(struct athn_softc *, struct ieee80211_channel *, | |||
81 | struct ieee80211_channel *); | |||
82 | void ar5416_rw_rfbits(uint32_t *, int, int, uint32_t, int); | |||
83 | void ar5416_rw_bank6tpc(struct athn_softc *, struct ieee80211_channel *, | |||
84 | uint32_t *); | |||
85 | void ar5416_rf_reset(struct athn_softc *, struct ieee80211_channel *); | |||
86 | void ar5416_reset_bb_gain(struct athn_softc *, struct ieee80211_channel *); | |||
87 | void ar5416_force_bias(struct athn_softc *, struct ieee80211_channel *); | |||
88 | void ar9160_rw_addac(struct athn_softc *, struct ieee80211_channel *, | |||
89 | uint32_t *); | |||
90 | void ar5416_reset_addac(struct athn_softc *, struct ieee80211_channel *); | |||
91 | void ar5416_get_pdadcs(struct athn_softc *, struct ieee80211_channel *, | |||
92 | int, int, uint8_t, uint8_t *, uint8_t *); | |||
93 | ||||
94 | /* Extern functions. */ | |||
95 | uint8_t athn_chan2fbin(struct ieee80211_channel *); | |||
96 | void athn_get_pier_ival(uint8_t, const uint8_t *, int, int *, int *); | |||
97 | int ar5008_attach(struct athn_softc *); | |||
98 | void ar5008_write_txpower(struct athn_softc *, int16_t power[]); | |||
99 | void ar5008_get_pdadcs(struct athn_softc *, uint8_t, struct athn_pier *, | |||
100 | struct athn_pier *, int, int, uint8_t, uint8_t *, uint8_t *); | |||
101 | void ar5008_set_viterbi_mask(struct athn_softc *, int); | |||
102 | void ar5008_get_lg_tpow(struct athn_softc *, struct ieee80211_channel *, | |||
103 | uint8_t, const struct ar_cal_target_power_leg *, int, uint8_t[]); | |||
104 | void ar5008_get_ht_tpow(struct athn_softc *, struct ieee80211_channel *, | |||
105 | uint8_t, const struct ar_cal_target_power_ht *, int, uint8_t[]); | |||
106 | void ar9280_olpc_get_pdadcs(struct athn_softc *, struct ieee80211_channel *, | |||
107 | int, uint8_t *, uint8_t *, uint8_t *); | |||
108 | ||||
109 | ||||
110 | int | |||
111 | ar5416_attach(struct athn_softc *sc) | |||
112 | { | |||
113 | sc->eep_base = AR5416_EEP_START_LOC256; | |||
114 | sc->eep_size = sizeof(struct ar5416_eeprom); | |||
115 | sc->ngpiopins = 14; | |||
116 | sc->led_pin = 1; | |||
117 | sc->workaround = AR5416_WA_DEFAULT0x0000073f; | |||
118 | sc->ops.setup = ar5416_setup; | |||
119 | sc->ops.swap_rom = ar5416_swap_rom; | |||
120 | sc->ops.init_from_rom = ar5416_init_from_rom; | |||
121 | sc->ops.set_txpower = ar5416_set_txpower; | |||
122 | sc->ops.set_synth = ar5416_set_synth; | |||
123 | sc->ops.spur_mitigate = ar5416_spur_mitigate; | |||
124 | sc->ops.get_spur_chans = ar5416_get_spur_chans; | |||
125 | sc->cca_min_2g = AR5416_PHY_CCA_MIN_GOOD_VAL_2GHZ(-100); | |||
126 | sc->cca_max_2g = AR5416_PHY_CCA_MAX_GOOD_VAL_2GHZ(-80); | |||
127 | sc->cca_min_5g = AR5416_PHY_CCA_MIN_GOOD_VAL_5GHZ(-110); | |||
128 | sc->cca_max_5g = AR5416_PHY_CCA_MAX_GOOD_VAL_5GHZ(-90); | |||
129 | if (AR_SREV_9160_10_OR_LATER(sc)((sc)->mac_ver >= 0x040)) | |||
130 | sc->ini = &ar9160_ini; | |||
131 | else | |||
132 | sc->ini = &ar5416_ini; | |||
133 | sc->serdes = &ar5416_serdes; | |||
134 | ||||
135 | return (ar5008_attach(sc)); | |||
136 | } | |||
137 | ||||
138 | void | |||
139 | ar5416_setup(struct athn_softc *sc) | |||
140 | { | |||
141 | /* Select ADDAC programming. */ | |||
142 | if (AR_SREV_9160_11(sc)(((sc)->mac_ver == 0x040) && (sc)->mac_rev == 1 )) | |||
143 | sc->addac = &ar9160_1_1_addac; | |||
144 | else if (AR_SREV_9160_10_OR_LATER(sc)((sc)->mac_ver >= 0x040)) | |||
145 | sc->addac = &ar9160_1_0_addac; | |||
146 | else if (AR_SREV_5416_22_OR_LATER(sc)((((sc)->mac_ver == 0x00d || (sc)->mac_ver == 0x00c) && (sc)->mac_rev >= 2) || (sc)->mac_ver >= 0x014)) | |||
147 | sc->addac = &ar5416_2_2_addac; | |||
148 | else | |||
149 | sc->addac = &ar5416_2_1_addac; | |||
150 | } | |||
151 | ||||
152 | void | |||
153 | ar5416_swap_rom(struct athn_softc *sc) | |||
154 | { | |||
155 | struct ar5416_eeprom *eep = sc->eep; | |||
156 | struct ar5416_modal_eep_header *modal; | |||
157 | int i, j; | |||
158 | ||||
159 | for (i = 0; i < 2; i++) { /* Dual-band. */ | |||
160 | modal = &eep->modalHeader[i]; | |||
161 | ||||
162 | 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)); | |||
163 | for (j = 0; j < AR5416_MAX_CHAINS3; j++) { | |||
164 | modal->antCtrlChain[j] = | |||
165 | swap32(modal->antCtrlChain[j])(__uint32_t)(__builtin_constant_p(modal->antCtrlChain[j]) ? (__uint32_t)(((__uint32_t)(modal->antCtrlChain[j]) & 0xff ) << 24 | ((__uint32_t)(modal->antCtrlChain[j]) & 0xff00) << 8 | ((__uint32_t)(modal->antCtrlChain[j] ) & 0xff0000) >> 8 | ((__uint32_t)(modal->antCtrlChain [j]) & 0xff000000) >> 24) : __swap32md(modal->antCtrlChain [j])); | |||
166 | } | |||
167 | for (j = 0; j < AR_EEPROM_MODAL_SPURS5; j++) { | |||
168 | modal->spurChans[j].spurChan = | |||
169 | swap16(modal->spurChans[j].spurChan)(__uint16_t)(__builtin_constant_p(modal->spurChans[j].spurChan ) ? (__uint16_t)(((__uint16_t)(modal->spurChans[j].spurChan ) & 0xffU) << 8 | ((__uint16_t)(modal->spurChans [j].spurChan) & 0xff00U) >> 8) : __swap16md(modal-> spurChans[j].spurChan)); | |||
170 | } | |||
171 | } | |||
172 | } | |||
173 | ||||
174 | const struct ar_spur_chan * | |||
175 | ar5416_get_spur_chans(struct athn_softc *sc, int is2ghz) | |||
176 | { | |||
177 | const struct ar5416_eeprom *eep = sc->eep; | |||
178 | ||||
179 | return (eep->modalHeader[is2ghz].spurChans); | |||
180 | } | |||
181 | ||||
182 | int | |||
183 | ar5416_set_synth(struct athn_softc *sc, struct ieee80211_channel *c, | |||
184 | struct ieee80211_channel *extc) | |||
185 | { | |||
186 | uint32_t phy, reg; | |||
187 | uint32_t freq = c->ic_freq; | |||
188 | uint8_t chansel; | |||
189 | ||||
190 | phy = 0; | |||
191 | if (IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)) { | |||
192 | if (((freq - 2192) % 5) == 0) { | |||
193 | chansel = ((freq - 672) * 2 - 3040) / 10; | |||
194 | } else if (((freq - 2224) % 5) == 0) { | |||
195 | chansel = ((freq - 704) * 2 - 3040) / 10; | |||
196 | phy |= AR5416_BMODE_SYNTH0x00000002; | |||
197 | } else | |||
198 | return (EINVAL22); | |||
199 | chansel <<= 2; | |||
200 | ||||
201 | reg = AR_READ(sc, AR_PHY_CCK_TX_CTRL)(sc)->ops.read((sc), (0xa204)); | |||
202 | if (freq == 2484) /* Channel 14. */ | |||
203 | reg |= AR_PHY_CCK_TX_CTRL_JAPAN0x00000010; | |||
204 | else | |||
205 | reg &= ~AR_PHY_CCK_TX_CTRL_JAPAN0x00000010; | |||
206 | AR_WRITE(sc, AR_PHY_CCK_TX_CTRL, reg)(sc)->ops.write((sc), (0xa204), (reg)); | |||
207 | ||||
208 | /* Fix for orientation sensitivity issue. */ | |||
209 | if (AR_SREV_5416(sc)((sc)->mac_ver == 0x00d || (sc)->mac_ver == 0x00c)) | |||
210 | ar5416_force_bias(sc, c); | |||
211 | } else { | |||
212 | if (freq >= 5120 && (freq % 20) == 0) { | |||
213 | chansel = (freq - 4800) / 20; | |||
214 | chansel <<= 2; | |||
215 | phy |= SM(AR5416_AMODE_REFSEL, 2)(((uint32_t)(2) << 2) & 0x0000000c); | |||
216 | } else if ((freq % 10) == 0) { | |||
217 | chansel = (freq - 4800) / 10; | |||
218 | chansel <<= 1; | |||
219 | if (AR_SREV_9160_10_OR_LATER(sc)((sc)->mac_ver >= 0x040)) | |||
220 | phy |= SM(AR5416_AMODE_REFSEL, 1)(((uint32_t)(1) << 2) & 0x0000000c); | |||
221 | else | |||
222 | phy |= SM(AR5416_AMODE_REFSEL, 2)(((uint32_t)(2) << 2) & 0x0000000c); | |||
223 | } else if ((freq % 5) == 0) { | |||
224 | chansel = (freq - 4800) / 5; | |||
225 | phy |= SM(AR5416_AMODE_REFSEL, 2)(((uint32_t)(2) << 2) & 0x0000000c); | |||
226 | } else | |||
227 | return (EINVAL22); | |||
228 | } | |||
229 | chansel = ar5416_reverse_bits(chansel, 8); | |||
230 | phy |= chansel << 8 | 1 << 5 | 1; | |||
231 | DPRINTFN(4, ("AR_PHY(0x37)=0x%08x\n", phy)); | |||
232 | AR_WRITE(sc, AR_PHY(0x37), phy)(sc)->ops.write((sc), ((0x9800 + (0x37) * 4)), (phy)); | |||
233 | return (0); | |||
234 | } | |||
235 | ||||
236 | void | |||
237 | ar5416_init_from_rom(struct athn_softc *sc, struct ieee80211_channel *c, | |||
238 | struct ieee80211_channel *extc) | |||
239 | { | |||
240 | static const uint32_t chainoffset[] = { 0x0000, 0x2000, 0x1000 }; | |||
241 | const struct ar5416_eeprom *eep = sc->eep; | |||
242 | const struct ar5416_modal_eep_header *modal; | |||
243 | uint32_t reg, offset; | |||
244 | uint8_t txRxAtten; | |||
245 | int i; | |||
246 | ||||
247 | modal = &eep->modalHeader[IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)]; | |||
248 | ||||
249 | AR_WRITE(sc, AR_PHY_SWITCH_COM, modal->antCtrlCommon)(sc)->ops.write((sc), (0x9964), (modal->antCtrlCommon)); | |||
250 | ||||
251 | for (i = 0; i < AR5416_MAX_CHAINS3; i++) { | |||
252 | if (AR_SREV_5416_20_OR_LATER(sc)((((sc)->mac_ver == 0x00d || (sc)->mac_ver == 0x00c) && (sc)->mac_rev >= 1) || (sc)->mac_ver >= 0x014) && | |||
253 | (sc->rxchainmask == 0x5 || sc->txchainmask == 0x5)) | |||
254 | offset = chainoffset[i]; | |||
255 | else | |||
256 | offset = i * 0x1000; | |||
257 | ||||
258 | AR_WRITE(sc, AR_PHY_SWITCH_CHAIN_0 + offset,(sc)->ops.write((sc), (0x9960 + offset), (modal->antCtrlChain [i])) | |||
259 | modal->antCtrlChain[i])(sc)->ops.write((sc), (0x9960 + offset), (modal->antCtrlChain [i])); | |||
260 | ||||
261 | reg = AR_READ(sc, AR_PHY_TIMING_CTRL4_0 + offset)(sc)->ops.read((sc), (0x9920 + offset)); | |||
262 | reg = RW(reg, AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF,(((reg) & ~0x000007e0) | (((uint32_t)(modal->iqCalICh[ i]) << 5) & 0x000007e0)) | |||
263 | modal->iqCalICh[i])(((reg) & ~0x000007e0) | (((uint32_t)(modal->iqCalICh[ i]) << 5) & 0x000007e0)); | |||
264 | reg = RW(reg, AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF,(((reg) & ~0x0000001f) | (((uint32_t)(modal->iqCalQCh[ i]) << 0) & 0x0000001f)) | |||
265 | modal->iqCalQCh[i])(((reg) & ~0x0000001f) | (((uint32_t)(modal->iqCalQCh[ i]) << 0) & 0x0000001f)); | |||
266 | AR_WRITE(sc, AR_PHY_TIMING_CTRL4_0 + offset, reg)(sc)->ops.write((sc), (0x9920 + offset), (reg)); | |||
267 | ||||
268 | if (i > 0 && !AR_SREV_5416_20_OR_LATER(sc)((((sc)->mac_ver == 0x00d || (sc)->mac_ver == 0x00c) && (sc)->mac_rev >= 1) || (sc)->mac_ver >= 0x014)) | |||
269 | continue; | |||
270 | ||||
271 | if (sc->eep_rev >= AR_EEP_MINOR_VER_33) { | |||
272 | reg = AR_READ(sc, AR_PHY_GAIN_2GHZ + offset)(sc)->ops.read((sc), (0xa20c + offset)); | |||
273 | reg = RW(reg, AR_PHY_GAIN_2GHZ_BSW_MARGIN,(((reg) & ~0x00003c00) | (((uint32_t)(modal->bswMargin [i]) << 10) & 0x00003c00)) | |||
274 | modal->bswMargin[i])(((reg) & ~0x00003c00) | (((uint32_t)(modal->bswMargin [i]) << 10) & 0x00003c00)); | |||
275 | reg = RW(reg, AR_PHY_GAIN_2GHZ_BSW_ATTEN,(((reg) & ~0x0000001f) | (((uint32_t)(modal->bswAtten[ i]) << 0) & 0x0000001f)) | |||
276 | modal->bswAtten[i])(((reg) & ~0x0000001f) | (((uint32_t)(modal->bswAtten[ i]) << 0) & 0x0000001f)); | |||
277 | AR_WRITE(sc, AR_PHY_GAIN_2GHZ + offset, reg)(sc)->ops.write((sc), (0xa20c + offset), (reg)); | |||
278 | } | |||
279 | if (sc->eep_rev >= AR_EEP_MINOR_VER_33) | |||
280 | txRxAtten = modal->txRxAttenCh[i]; | |||
281 | else /* Workaround for ROM versions < 14.3. */ | |||
282 | txRxAtten = IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0) ? 23 : 44; | |||
283 | reg = AR_READ(sc, AR_PHY_RXGAIN + offset)(sc)->ops.read((sc), (0x9848 + offset)); | |||
284 | reg = RW(reg, AR_PHY_RXGAIN_TXRX_ATTEN, txRxAtten)(((reg) & ~0x0003f000) | (((uint32_t)(txRxAtten) << 12) & 0x0003f000)); | |||
285 | AR_WRITE(sc, AR_PHY_RXGAIN + offset, reg)(sc)->ops.write((sc), (0x9848 + offset), (reg)); | |||
286 | ||||
287 | reg = AR_READ(sc, AR_PHY_GAIN_2GHZ + offset)(sc)->ops.read((sc), (0xa20c + offset)); | |||
288 | reg = RW(reg, AR_PHY_GAIN_2GHZ_RXTX_MARGIN,(((reg) & ~0x00fc0000) | (((uint32_t)(modal->rxTxMarginCh [i]) << 18) & 0x00fc0000)) | |||
289 | modal->rxTxMarginCh[i])(((reg) & ~0x00fc0000) | (((uint32_t)(modal->rxTxMarginCh [i]) << 18) & 0x00fc0000)); | |||
290 | AR_WRITE(sc, AR_PHY_GAIN_2GHZ + offset, reg)(sc)->ops.write((sc), (0xa20c + offset), (reg)); | |||
291 | } | |||
292 | reg = AR_READ(sc, AR_PHY_SETTLING)(sc)->ops.read((sc), (0x9844)); | |||
293 | reg = RW(reg, AR_PHY_SETTLING_SWITCH, modal->switchSettling)(((reg) & ~0x00003f80) | (((uint32_t)(modal->switchSettling ) << 7) & 0x00003f80)); | |||
294 | AR_WRITE(sc, AR_PHY_SETTLING, reg)(sc)->ops.write((sc), (0x9844), (reg)); | |||
295 | ||||
296 | reg = AR_READ(sc, AR_PHY_DESIRED_SZ)(sc)->ops.read((sc), (0x9850)); | |||
297 | reg = RW(reg, AR_PHY_DESIRED_SZ_ADC, modal->adcDesiredSize)(((reg) & ~0x000000ff) | (((uint32_t)(modal->adcDesiredSize ) << 0) & 0x000000ff)); | |||
298 | reg = RW(reg, AR_PHY_DESIRED_SZ_PGA, modal->pgaDesiredSize)(((reg) & ~0x0000ff00) | (((uint32_t)(modal->pgaDesiredSize ) << 8) & 0x0000ff00)); | |||
299 | AR_WRITE(sc, AR_PHY_DESIRED_SZ, reg)(sc)->ops.write((sc), (0x9850), (reg)); | |||
300 | ||||
301 | reg = SM(AR_PHY_RF_CTL4_TX_END_XPAA_OFF, modal->txEndToXpaOff)(((uint32_t)(modal->txEndToXpaOff) << 16) & 0x00ff0000 ); | |||
302 | reg |= SM(AR_PHY_RF_CTL4_TX_END_XPAB_OFF, modal->txEndToXpaOff)(((uint32_t)(modal->txEndToXpaOff) << 24) & 0xff000000 ); | |||
303 | reg |= SM(AR_PHY_RF_CTL4_FRAME_XPAA_ON, modal->txFrameToXpaOn)(((uint32_t)(modal->txFrameToXpaOn) << 0) & 0x000000ff ); | |||
304 | reg |= SM(AR_PHY_RF_CTL4_FRAME_XPAB_ON, modal->txFrameToXpaOn)(((uint32_t)(modal->txFrameToXpaOn) << 8) & 0x0000ff00 ); | |||
305 | AR_WRITE(sc, AR_PHY_RF_CTL4, reg)(sc)->ops.write((sc), (0x9834), (reg)); | |||
306 | ||||
307 | reg = AR_READ(sc, AR_PHY_RF_CTL3)(sc)->ops.read((sc), (0x9828)); | |||
308 | reg = RW(reg, AR_PHY_TX_END_TO_A2_RX_ON, modal->txEndToRxOn)(((reg) & ~0x00ff0000) | (((uint32_t)(modal->txEndToRxOn ) << 16) & 0x00ff0000)); | |||
309 | AR_WRITE(sc, AR_PHY_RF_CTL3, reg)(sc)->ops.write((sc), (0x9828), (reg)); | |||
310 | ||||
311 | reg = AR_READ(sc, AR_PHY_CCA(0))(sc)->ops.read((sc), ((0x9864 + (0) * 0x1000))); | |||
312 | reg = RW(reg, AR_PHY_CCA_THRESH62, modal->thresh62)(((reg) & ~0x0007f000) | (((uint32_t)(modal->thresh62) << 12) & 0x0007f000)); | |||
313 | AR_WRITE(sc, AR_PHY_CCA(0), reg)(sc)->ops.write((sc), ((0x9864 + (0) * 0x1000)), (reg)); | |||
314 | ||||
315 | reg = AR_READ(sc, AR_PHY_EXT_CCA(0))(sc)->ops.read((sc), ((0x99bc + (0) * 0x1000))); | |||
316 | reg = RW(reg, AR_PHY_EXT_CCA_THRESH62, modal->thresh62)(((reg) & ~0x007f0000) | (((uint32_t)(modal->thresh62) << 16) & 0x007f0000)); | |||
317 | AR_WRITE(sc, AR_PHY_EXT_CCA(0), reg)(sc)->ops.write((sc), ((0x99bc + (0) * 0x1000)), (reg)); | |||
318 | ||||
319 | if (sc->eep_rev >= AR_EEP_MINOR_VER_22) { | |||
320 | reg = AR_READ(sc, AR_PHY_RF_CTL2)(sc)->ops.read((sc), (0x9824)); | |||
321 | reg = RW(reg, AR_PHY_TX_END_DATA_START,(((reg) & ~0x000000ff) | (((uint32_t)(modal->txFrameToDataStart ) << 0) & 0x000000ff)) | |||
322 | modal->txFrameToDataStart)(((reg) & ~0x000000ff) | (((uint32_t)(modal->txFrameToDataStart ) << 0) & 0x000000ff)); | |||
323 | reg = RW(reg, AR_PHY_TX_END_PA_ON, modal->txFrameToPaOn)(((reg) & ~0x0000ff00) | (((uint32_t)(modal->txFrameToPaOn ) << 8) & 0x0000ff00)); | |||
324 | AR_WRITE(sc, AR_PHY_RF_CTL2, reg)(sc)->ops.write((sc), (0x9824), (reg)); | |||
325 | } | |||
326 | if (sc->eep_rev >= AR_EEP_MINOR_VER_33 && extc != NULL((void *)0)) { | |||
327 | /* Overwrite switch settling with HT-40 value. */ | |||
328 | reg = AR_READ(sc, AR_PHY_SETTLING)(sc)->ops.read((sc), (0x9844)); | |||
329 | reg = RW(reg, AR_PHY_SETTLING_SWITCH, modal->swSettleHt40)(((reg) & ~0x00003f80) | (((uint32_t)(modal->swSettleHt40 ) << 7) & 0x00003f80)); | |||
330 | AR_WRITE(sc, AR_PHY_SETTLING, reg)(sc)->ops.write((sc), (0x9844), (reg)); | |||
331 | } | |||
332 | } | |||
333 | ||||
334 | int | |||
335 | ar5416_init_calib(struct athn_softc *sc, struct ieee80211_channel *c, | |||
336 | struct ieee80211_channel *extc) | |||
337 | { | |||
338 | int ntries; | |||
339 | ||||
340 | if (AR_SREV_9280_10_OR_LATER(sc)((sc)->mac_ver >= 0x080)) { | |||
341 | /* XXX Linux tests AR9287?! */ | |||
342 | AR_CLRBITS(sc, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC)(sc)->ops.write((sc), (0x982c), ((sc)->ops.read((sc), ( 0x982c)) & ~(0x00008000))); | |||
343 | AR_SETBITS(sc, AR_PHY_AGC_CONTROL,(sc)->ops.write((sc), (0x9860), ((sc)->ops.read((sc), ( 0x9860)) | (0x00010000))) | |||
344 | AR_PHY_AGC_CONTROL_FLTR_CAL)(sc)->ops.write((sc), (0x9860), ((sc)->ops.read((sc), ( 0x9860)) | (0x00010000))); | |||
345 | } | |||
346 | /* Calibrate the AGC. */ | |||
347 | AR_SETBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL)(sc)->ops.write((sc), (0x9860), ((sc)->ops.read((sc), ( 0x9860)) | (0x00000001))); | |||
348 | /* Poll for offset calibration completion. */ | |||
349 | for (ntries = 0; ntries < 10000; ntries++) { | |||
350 | if (!(AR_READ(sc, AR_PHY_AGC_CONTROL)(sc)->ops.read((sc), (0x9860)) & | |||
351 | AR_PHY_AGC_CONTROL_CAL0x00000001)) | |||
352 | break; | |||
353 | DELAY(10)(*delay_func)(10); | |||
354 | } | |||
355 | if (ntries == 10000) | |||
356 | return (ETIMEDOUT60); | |||
357 | if (AR_SREV_9280_10_OR_LATER(sc)((sc)->mac_ver >= 0x080)) { | |||
358 | AR_SETBITS(sc, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC)(sc)->ops.write((sc), (0x982c), ((sc)->ops.read((sc), ( 0x982c)) | (0x00008000))); | |||
359 | AR_CLRBITS(sc, AR_PHY_AGC_CONTROL,(sc)->ops.write((sc), (0x9860), ((sc)->ops.read((sc), ( 0x9860)) & ~(0x00010000))) | |||
360 | AR_PHY_AGC_CONTROL_FLTR_CAL)(sc)->ops.write((sc), (0x9860), ((sc)->ops.read((sc), ( 0x9860)) & ~(0x00010000))); | |||
361 | } | |||
362 | return (0); | |||
363 | } | |||
364 | ||||
365 | void | |||
366 | ar5416_get_pdadcs(struct athn_softc *sc, struct ieee80211_channel *c, | |||
367 | int chain, int nxpdgains, uint8_t overlap, uint8_t *boundaries, | |||
368 | uint8_t *pdadcs) | |||
369 | { | |||
370 | const struct ar5416_eeprom *eep = sc->eep; | |||
371 | const struct ar5416_cal_data_per_freq *pierdata; | |||
372 | const uint8_t *pierfreq; | |||
373 | struct athn_pier lopier, hipier; | |||
374 | int16_t delta; | |||
375 | uint8_t fbin, pwroff; | |||
376 | int i, lo, hi, npiers; | |||
377 | ||||
378 | if (IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)) { | |||
379 | pierfreq = eep->calFreqPier2G; | |||
380 | pierdata = eep->calPierData2G[chain]; | |||
381 | npiers = AR5416_NUM_2G_CAL_PIERS4; | |||
382 | } else { | |||
383 | pierfreq = eep->calFreqPier5G; | |||
384 | pierdata = eep->calPierData5G[chain]; | |||
385 | npiers = AR5416_NUM_5G_CAL_PIERS8; | |||
386 | } | |||
387 | /* Find channel in ROM pier table. */ | |||
388 | fbin = athn_chan2fbin(c); | |||
389 | athn_get_pier_ival(fbin, pierfreq, npiers, &lo, &hi); | |||
390 | ||||
391 | lopier.fbin = pierfreq[lo]; | |||
392 | hipier.fbin = pierfreq[hi]; | |||
393 | for (i = 0; i < nxpdgains; i++) { | |||
394 | lopier.pwr[i] = pierdata[lo].pwrPdg[i]; | |||
395 | lopier.vpd[i] = pierdata[lo].vpdPdg[i]; | |||
396 | hipier.pwr[i] = pierdata[lo].pwrPdg[i]; | |||
397 | hipier.vpd[i] = pierdata[lo].vpdPdg[i]; | |||
398 | } | |||
399 | ar5008_get_pdadcs(sc, fbin, &lopier, &hipier, nxpdgains, | |||
400 | AR5416_PD_GAIN_ICEPTS5, overlap, boundaries, pdadcs); | |||
401 | ||||
402 | if (!AR_SREV_9280_20_OR_LATER(sc)((sc)->mac_ver > 0x080 || (((sc)->mac_ver == 0x080) && (sc)->mac_rev >= 1))) | |||
403 | return; | |||
404 | ||||
405 | if (sc->eep_rev >= AR_EEP_MINOR_VER_2121) | |||
406 | pwroff = eep->baseEepHeader.pwrTableOffset; | |||
407 | else | |||
408 | pwroff = AR_PWR_TABLE_OFFSET_DB(-5); | |||
409 | delta = (pwroff - AR_PWR_TABLE_OFFSET_DB(-5)) * 2; /* In half dB. */ | |||
410 | ||||
411 | /* Change the original gain boundaries setting. */ | |||
412 | for (i = 0; i < nxpdgains; i++) { | |||
413 | /* XXX Possible overflows? */ | |||
414 | boundaries[i] -= delta; | |||
415 | if (boundaries[i] > AR_MAX_RATE_POWER63 - overlap) | |||
416 | boundaries[i] = AR_MAX_RATE_POWER63 - overlap; | |||
417 | } | |||
418 | if (delta != 0) { | |||
419 | /* Shift the PDADC table to start at the new offset. */ | |||
420 | for (i = 0; i < AR_NUM_PDADC_VALUES128; i++) | |||
421 | pdadcs[i] = pdadcs[MIN(i + delta,(((i + delta)<(128 - 1))?(i + delta):(128 - 1)) | |||
422 | AR_NUM_PDADC_VALUES - 1)(((i + delta)<(128 - 1))?(i + delta):(128 - 1))]; | |||
423 | } | |||
424 | } | |||
425 | ||||
426 | void | |||
427 | ar5416_set_power_calib(struct athn_softc *sc, struct ieee80211_channel *c) | |||
428 | { | |||
429 | static const uint32_t chainoffset[] = { 0x0000, 0x2000, 0x1000 }; | |||
430 | const struct ar5416_eeprom *eep = sc->eep; | |||
431 | const struct ar5416_modal_eep_header *modal; | |||
432 | uint8_t boundaries[AR_PD_GAINS_IN_MASK4]; | |||
433 | uint8_t pdadcs[AR_NUM_PDADC_VALUES128]; | |||
434 | uint8_t xpdgains[AR5416_NUM_PD_GAINS4]; | |||
435 | uint8_t overlap, txgain; | |||
436 | uint32_t reg, offset; | |||
437 | int i, j, nxpdgains; | |||
438 | ||||
439 | modal = &eep->modalHeader[IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)]; | |||
440 | ||||
441 | if (sc->eep_rev < AR_EEP_MINOR_VER_22) { | |||
442 | overlap = MS(AR_READ(sc, AR_PHY_TPCRG5),(((uint32_t)((sc)->ops.read((sc), (0xa26c))) & 0x0000000f ) >> 0) | |||
443 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP)(((uint32_t)((sc)->ops.read((sc), (0xa26c))) & 0x0000000f ) >> 0); | |||
444 | } else | |||
445 | overlap = modal->pdGainOverlap; | |||
446 | ||||
447 | if ((sc->flags & ATHN_FLAG_OLPC(1 << 2)) && IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)) { | |||
448 | /* XXX not here. */ | |||
449 | sc->pdadc = | |||
450 | ((const struct ar_cal_data_per_freq_olpc *) | |||
451 | eep->calPierData2G[0])->vpdPdg[0][0]; | |||
452 | } | |||
453 | ||||
454 | nxpdgains = 0; | |||
455 | memset(xpdgains, 0, sizeof(xpdgains))__builtin_memset((xpdgains), (0), (sizeof(xpdgains))); | |||
456 | for (i = AR5416_PD_GAINS_IN_MASK4 - 1; i >= 0; i--) { | |||
457 | if (nxpdgains >= AR5416_NUM_PD_GAINS4) | |||
458 | break; /* Can't happen. */ | |||
459 | if (modal->xpdGain & (1 << i)) | |||
460 | xpdgains[nxpdgains++] = i; | |||
461 | } | |||
462 | reg = AR_READ(sc, AR_PHY_TPCRG1)(sc)->ops.read((sc), (0xa258)); | |||
463 | reg = RW(reg, AR_PHY_TPCRG1_NUM_PD_GAIN, nxpdgains - 1)(((reg) & ~0x0000c000) | (((uint32_t)(nxpdgains - 1) << 14) & 0x0000c000)); | |||
464 | reg = RW(reg, AR_PHY_TPCRG1_PD_GAIN_1, xpdgains[0])(((reg) & ~0x00030000) | (((uint32_t)(xpdgains[0]) << 16) & 0x00030000)); | |||
465 | reg = RW(reg, AR_PHY_TPCRG1_PD_GAIN_2, xpdgains[1])(((reg) & ~0x000c0000) | (((uint32_t)(xpdgains[1]) << 18) & 0x000c0000)); | |||
466 | reg = RW(reg, AR_PHY_TPCRG1_PD_GAIN_3, xpdgains[2])(((reg) & ~0x00300000) | (((uint32_t)(xpdgains[2]) << 20) & 0x00300000)); | |||
467 | AR_WRITE(sc, AR_PHY_TPCRG1, reg)(sc)->ops.write((sc), (0xa258), (reg)); | |||
468 | ||||
469 | for (i = 0; i < AR5416_MAX_CHAINS3; i++) { | |||
470 | if (!(sc->txchainmask & (1 << i))) | |||
471 | continue; | |||
472 | ||||
473 | if (AR_SREV_5416_20_OR_LATER(sc)((((sc)->mac_ver == 0x00d || (sc)->mac_ver == 0x00c) && (sc)->mac_rev >= 1) || (sc)->mac_ver >= 0x014) && | |||
474 | (sc->rxchainmask == 0x5 || sc->txchainmask == 0x5)) | |||
475 | offset = chainoffset[i]; | |||
476 | else | |||
477 | offset = i * 0x1000; | |||
478 | ||||
479 | if (sc->flags & ATHN_FLAG_OLPC(1 << 2)) { | |||
480 | ar9280_olpc_get_pdadcs(sc, c, i, boundaries, | |||
481 | pdadcs, &txgain); | |||
482 | ||||
483 | reg = AR_READ(sc, AR_PHY_TX_PWRCTRL6_0)(sc)->ops.read((sc), (0xa270)); | |||
484 | reg = RW(reg, AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3)(((reg) & ~0x03000000) | (((uint32_t)(3) << 24) & 0x03000000)); | |||
485 | AR_WRITE(sc, AR_PHY_TX_PWRCTRL6_0, reg)(sc)->ops.write((sc), (0xa270), (reg)); | |||
486 | ||||
487 | reg = AR_READ(sc, AR_PHY_TX_PWRCTRL6_1)(sc)->ops.read((sc), (0xb270)); | |||
488 | reg = RW(reg, AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3)(((reg) & ~0x03000000) | (((uint32_t)(3) << 24) & 0x03000000)); | |||
489 | AR_WRITE(sc, AR_PHY_TX_PWRCTRL6_1, reg)(sc)->ops.write((sc), (0xb270), (reg)); | |||
490 | ||||
491 | reg = AR_READ(sc, AR_PHY_TX_PWRCTRL7)(sc)->ops.read((sc), (0xa274)); | |||
492 | reg = RW(reg, AR_PHY_TX_PWRCTRL_INIT_TX_GAIN, txgain)(((reg) & ~0x01f80000) | (((uint32_t)(txgain) << 19 ) & 0x01f80000)); | |||
493 | AR_WRITE(sc, AR_PHY_TX_PWRCTRL7, reg)(sc)->ops.write((sc), (0xa274), (reg)); | |||
494 | ||||
495 | overlap = 6; | |||
496 | } else { | |||
497 | ar5416_get_pdadcs(sc, c, i, nxpdgains, overlap, | |||
498 | boundaries, pdadcs); | |||
499 | } | |||
500 | /* Write boundaries. */ | |||
501 | if (i == 0 || AR_SREV_5416_20_OR_LATER(sc)((((sc)->mac_ver == 0x00d || (sc)->mac_ver == 0x00c) && (sc)->mac_rev >= 1) || (sc)->mac_ver >= 0x014)) { | |||
502 | reg = SM(AR_PHY_TPCRG5_PD_GAIN_OVERLAP,(((uint32_t)(overlap) << 0) & 0x0000000f) | |||
503 | overlap)(((uint32_t)(overlap) << 0) & 0x0000000f); | |||
504 | reg |= SM(AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1,(((uint32_t)(boundaries[0]) << 4) & 0x000003f0) | |||
505 | boundaries[0])(((uint32_t)(boundaries[0]) << 4) & 0x000003f0); | |||
506 | reg |= SM(AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2,(((uint32_t)(boundaries[1]) << 10) & 0x0000fc00) | |||
507 | boundaries[1])(((uint32_t)(boundaries[1]) << 10) & 0x0000fc00); | |||
508 | reg |= SM(AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3,(((uint32_t)(boundaries[2]) << 16) & 0x003f0000) | |||
509 | boundaries[2])(((uint32_t)(boundaries[2]) << 16) & 0x003f0000); | |||
510 | reg |= SM(AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4,(((uint32_t)(boundaries[3]) << 22) & 0x0fc00000) | |||
511 | boundaries[3])(((uint32_t)(boundaries[3]) << 22) & 0x0fc00000); | |||
512 | AR_WRITE(sc, AR_PHY_TPCRG5 + offset, reg)(sc)->ops.write((sc), (0xa26c + offset), (reg)); | |||
513 | } | |||
514 | /* Write PDADC values. */ | |||
515 | for (j = 0; j < AR_NUM_PDADC_VALUES128; j += 4) { | |||
516 | AR_WRITE(sc, AR_PHY_PDADC_TBL_BASE + offset + j,(sc)->ops.write((sc), (0xa280 + offset + j), (pdadcs[j + 0 ] << 0 | pdadcs[j + 1] << 8 | pdadcs[j + 2] << 16 | pdadcs[j + 3] << 24)) | |||
517 | pdadcs[j + 0] << 0 |(sc)->ops.write((sc), (0xa280 + offset + j), (pdadcs[j + 0 ] << 0 | pdadcs[j + 1] << 8 | pdadcs[j + 2] << 16 | pdadcs[j + 3] << 24)) | |||
518 | pdadcs[j + 1] << 8 |(sc)->ops.write((sc), (0xa280 + offset + j), (pdadcs[j + 0 ] << 0 | pdadcs[j + 1] << 8 | pdadcs[j + 2] << 16 | pdadcs[j + 3] << 24)) | |||
519 | pdadcs[j + 2] << 16 |(sc)->ops.write((sc), (0xa280 + offset + j), (pdadcs[j + 0 ] << 0 | pdadcs[j + 1] << 8 | pdadcs[j + 2] << 16 | pdadcs[j + 3] << 24)) | |||
520 | pdadcs[j + 3] << 24)(sc)->ops.write((sc), (0xa280 + offset + j), (pdadcs[j + 0 ] << 0 | pdadcs[j + 1] << 8 | pdadcs[j + 2] << 16 | pdadcs[j + 3] << 24)); | |||
521 | } | |||
522 | } | |||
523 | } | |||
524 | ||||
525 | void | |||
526 | ar5416_set_txpower(struct athn_softc *sc, struct ieee80211_channel *c, | |||
527 | struct ieee80211_channel *extc) | |||
528 | { | |||
529 | const struct ar5416_eeprom *eep = sc->eep; | |||
530 | const struct ar5416_modal_eep_header *modal; | |||
531 | uint8_t tpow_cck[4], tpow_ofdm[4]; | |||
532 | uint8_t tpow_cck_ext[4], tpow_ofdm_ext[4]; | |||
533 | uint8_t tpow_ht20[8], tpow_ht40[8]; | |||
534 | uint8_t ht40inc; | |||
535 | int16_t pwr = 0, pwroff, max_ant_gain, power[ATHN_POWER_COUNT68]; | |||
536 | uint8_t cckinc; | |||
537 | int i; | |||
538 | ||||
539 | ar5416_set_power_calib(sc, c); | |||
540 | ||||
541 | modal = &eep->modalHeader[IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)]; | |||
| ||||
542 | ||||
543 | /* Compute transmit power reduction due to antenna gain. */ | |||
544 | max_ant_gain = MAX(modal->antennaGainCh[0], modal->antennaGainCh[1])(((modal->antennaGainCh[0])>(modal->antennaGainCh[1] ))?(modal->antennaGainCh[0]):(modal->antennaGainCh[1])); | |||
545 | max_ant_gain = MAX(modal->antennaGainCh[2], max_ant_gain)(((modal->antennaGainCh[2])>(max_ant_gain))?(modal-> antennaGainCh[2]):(max_ant_gain)); | |||
546 | /* XXX */ | |||
547 | ||||
548 | /* | |||
549 | * Reduce scaled power by number of active chains to get per-chain | |||
550 | * transmit power level. | |||
551 | */ | |||
552 | if (sc->ntxchains == 2) | |||
553 | pwr -= AR_PWR_DECREASE_FOR_2_CHAIN6; | |||
554 | else if (sc->ntxchains == 3) | |||
555 | pwr -= AR_PWR_DECREASE_FOR_3_CHAIN9; | |||
556 | if (pwr
| |||
557 | pwr = 0; | |||
558 | ||||
559 | if (IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)) { | |||
560 | /* Get CCK target powers. */ | |||
561 | ar5008_get_lg_tpow(sc, c, AR_CTL_11B1, eep->calTargetPowerCck, | |||
562 | AR5416_NUM_2G_CCK_TARGET_POWERS3, tpow_cck); | |||
563 | ||||
564 | /* Get OFDM target powers. */ | |||
565 | ar5008_get_lg_tpow(sc, c, AR_CTL_11G2, eep->calTargetPower2G, | |||
566 | AR5416_NUM_2G_20_TARGET_POWERS4, tpow_ofdm); | |||
567 | ||||
568 | /* Get HT-20 target powers. */ | |||
569 | ar5008_get_ht_tpow(sc, c, AR_CTL_2GHT205, | |||
570 | eep->calTargetPower2GHT20, AR5416_NUM_2G_20_TARGET_POWERS4, | |||
571 | tpow_ht20); | |||
572 | ||||
573 | if (extc != NULL((void *)0)) { | |||
574 | /* Get HT-40 target powers. */ | |||
575 | ar5008_get_ht_tpow(sc, c, AR_CTL_2GHT407, | |||
576 | eep->calTargetPower2GHT40, | |||
577 | AR5416_NUM_2G_40_TARGET_POWERS4, tpow_ht40); | |||
578 | ||||
579 | /* Get secondary channel CCK target powers. */ | |||
580 | ar5008_get_lg_tpow(sc, extc, AR_CTL_11B1, | |||
581 | eep->calTargetPowerCck, | |||
582 | AR5416_NUM_2G_CCK_TARGET_POWERS3, tpow_cck_ext); | |||
583 | ||||
584 | /* Get secondary channel OFDM target powers. */ | |||
585 | ar5008_get_lg_tpow(sc, extc, AR_CTL_11G2, | |||
586 | eep->calTargetPower2G, | |||
587 | AR5416_NUM_2G_20_TARGET_POWERS4, tpow_ofdm_ext); | |||
588 | } | |||
589 | } else { | |||
590 | /* Get OFDM target powers. */ | |||
591 | ar5008_get_lg_tpow(sc, c, AR_CTL_11A0, eep->calTargetPower5G, | |||
592 | AR5416_NUM_5G_20_TARGET_POWERS8, tpow_ofdm); | |||
593 | ||||
594 | /* Get HT-20 target powers. */ | |||
595 | ar5008_get_ht_tpow(sc, c, AR_CTL_5GHT206, | |||
596 | eep->calTargetPower5GHT20, AR5416_NUM_5G_20_TARGET_POWERS8, | |||
597 | tpow_ht20); | |||
598 | ||||
599 | if (extc != NULL((void *)0)) { | |||
600 | /* Get HT-40 target powers. */ | |||
601 | ar5008_get_ht_tpow(sc, c, AR_CTL_5GHT408, | |||
602 | eep->calTargetPower5GHT40, | |||
603 | AR5416_NUM_5G_40_TARGET_POWERS8, tpow_ht40); | |||
604 | ||||
605 | /* Get secondary channel OFDM target powers. */ | |||
606 | ar5008_get_lg_tpow(sc, extc, AR_CTL_11A0, | |||
607 | eep->calTargetPower5G, | |||
608 | AR5416_NUM_5G_20_TARGET_POWERS8, tpow_ofdm_ext); | |||
609 | } | |||
610 | } | |||
611 | ||||
612 | /* Compute CCK/OFDM delta. */ | |||
613 | cckinc = (sc->flags & ATHN_FLAG_OLPC(1 << 2)) ? -2 : 0; | |||
614 | ||||
615 | memset(power, 0, sizeof(power))__builtin_memset((power), (0), (sizeof(power))); | |||
616 | /* Shuffle target powers across transmit rates. */ | |||
617 | power[ATHN_POWER_OFDM60 ] = | |||
618 | power[ATHN_POWER_OFDM91 ] = | |||
619 | power[ATHN_POWER_OFDM122] = | |||
620 | power[ATHN_POWER_OFDM183] = | |||
621 | power[ATHN_POWER_OFDM244] = tpow_ofdm[0]; | |||
622 | power[ATHN_POWER_OFDM365] = tpow_ofdm[1]; | |||
623 | power[ATHN_POWER_OFDM486] = tpow_ofdm[2]; | |||
624 | power[ATHN_POWER_OFDM547] = tpow_ofdm[3]; | |||
625 | power[ATHN_POWER_XR15 ] = tpow_ofdm[0]; | |||
626 | if (IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)) { | |||
627 | power[ATHN_POWER_CCK1_LP8 ] = tpow_cck[0] + cckinc; | |||
| ||||
628 | power[ATHN_POWER_CCK2_LP9 ] = | |||
629 | power[ATHN_POWER_CCK2_SP10 ] = tpow_cck[1] + cckinc; | |||
630 | power[ATHN_POWER_CCK55_LP11] = | |||
631 | power[ATHN_POWER_CCK55_SP12] = tpow_cck[2] + cckinc; | |||
632 | power[ATHN_POWER_CCK11_LP13] = | |||
633 | power[ATHN_POWER_CCK11_SP14] = tpow_cck[3] + cckinc; | |||
634 | } | |||
635 | for (i = 0; i < nitems(tpow_ht20)(sizeof((tpow_ht20)) / sizeof((tpow_ht20)[0])); i++) | |||
636 | power[ATHN_POWER_HT20(i)(16 + (i))] = tpow_ht20[i]; | |||
637 | if (extc != NULL((void *)0)) { | |||
638 | /* Correct PAR difference between HT40 and HT20/Legacy. */ | |||
639 | if (sc->eep_rev >= AR_EEP_MINOR_VER_22) | |||
640 | ht40inc = modal->ht40PowerIncForPdadc; | |||
641 | else | |||
642 | ht40inc = AR_HT40_POWER_INC_FOR_PDADC2; | |||
643 | for (i = 0; i < nitems(tpow_ht40)(sizeof((tpow_ht40)) / sizeof((tpow_ht40)[0])); i++) | |||
644 | power[ATHN_POWER_HT40(i)(40 + (i))] = tpow_ht40[i] + ht40inc; | |||
645 | power[ATHN_POWER_OFDM_DUP65] = tpow_ht40[0]; | |||
646 | power[ATHN_POWER_CCK_DUP64 ] = tpow_ht40[0] + cckinc; | |||
647 | power[ATHN_POWER_OFDM_EXT67] = tpow_ofdm_ext[0]; | |||
648 | if (IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)) | |||
649 | power[ATHN_POWER_CCK_EXT66] = tpow_cck_ext[0] + cckinc; | |||
650 | } | |||
651 | ||||
652 | if (AR_SREV_9280_10_OR_LATER(sc)((sc)->mac_ver >= 0x080)) { | |||
653 | if (sc->eep_rev >= AR_EEP_MINOR_VER_2121) | |||
654 | pwroff = eep->baseEepHeader.pwrTableOffset; | |||
655 | else | |||
656 | pwroff = AR_PWR_TABLE_OFFSET_DB(-5); | |||
657 | for (i = 0; i < ATHN_POWER_COUNT68; i++) | |||
658 | power[i] -= pwroff * 2; /* In half dB. */ | |||
659 | } | |||
660 | for (i = 0; i < ATHN_POWER_COUNT68; i++) { | |||
661 | if (power[i] > AR_MAX_RATE_POWER63) | |||
662 | power[i] = AR_MAX_RATE_POWER63; | |||
663 | } | |||
664 | ||||
665 | /* Write transmit power values to hardware. */ | |||
666 | ar5008_write_txpower(sc, power); | |||
667 | ||||
668 | /* | |||
669 | * Write transmit power subtraction for dynamic chain changing | |||
670 | * and per-packet transmit power. | |||
671 | */ | |||
672 | AR_WRITE(sc, AR_PHY_POWER_TX_SUB,(sc)->ops.write((sc), (0xa3c8), ((modal->pwrDecreaseFor3Chain & 0x3f) << 6 | (modal->pwrDecreaseFor2Chain & 0x3f))) | |||
673 | (modal->pwrDecreaseFor3Chain & 0x3f) << 6 |(sc)->ops.write((sc), (0xa3c8), ((modal->pwrDecreaseFor3Chain & 0x3f) << 6 | (modal->pwrDecreaseFor2Chain & 0x3f))) | |||
674 | (modal->pwrDecreaseFor2Chain & 0x3f))(sc)->ops.write((sc), (0xa3c8), ((modal->pwrDecreaseFor3Chain & 0x3f) << 6 | (modal->pwrDecreaseFor2Chain & 0x3f))); | |||
675 | } | |||
676 | ||||
677 | void | |||
678 | ar5416_spur_mitigate(struct athn_softc *sc, struct ieee80211_channel *c, | |||
679 | struct ieee80211_channel *extc) | |||
680 | { | |||
681 | const struct ar_spur_chan *spurchans; | |||
682 | int i, spur, bin, spur_delta_phase, spur_freq_sd; | |||
683 | ||||
684 | spurchans = sc->ops.get_spur_chans(sc, IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)); | |||
685 | for (i = 0; i < AR_EEPROM_MODAL_SPURS5; i++) { | |||
686 | spur = spurchans[i].spurChan; | |||
687 | if (spur == AR_NO_SPUR0x8000) | |||
688 | return; /* XXX disable if it was enabled! */ | |||
689 | spur -= c->ic_freq * 10; | |||
690 | /* Verify range +/-9.5MHz */ | |||
691 | if (abs(spur) < 95) | |||
692 | break; | |||
693 | } | |||
694 | if (i == AR_EEPROM_MODAL_SPURS5) | |||
695 | return; /* XXX disable if it was enabled! */ | |||
696 | DPRINTFN(2, ("enabling spur mitigation\n")); | |||
697 | ||||
698 | AR_SETBITS(sc, AR_PHY_TIMING_CTRL4_0,(sc)->ops.write((sc), (0x9920), ((sc)->ops.read((sc), ( 0x9920)) | (0x80000000 | 0x40000000 | 0x20000000 | 0x10000000 ))) | |||
699 | AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI |(sc)->ops.write((sc), (0x9920), ((sc)->ops.read((sc), ( 0x9920)) | (0x80000000 | 0x40000000 | 0x20000000 | 0x10000000 ))) | |||
700 | AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER |(sc)->ops.write((sc), (0x9920), ((sc)->ops.read((sc), ( 0x9920)) | (0x80000000 | 0x40000000 | 0x20000000 | 0x10000000 ))) | |||
701 | AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK |(sc)->ops.write((sc), (0x9920), ((sc)->ops.read((sc), ( 0x9920)) | (0x80000000 | 0x40000000 | 0x20000000 | 0x10000000 ))) | |||
702 | AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK)(sc)->ops.write((sc), (0x9920), ((sc)->ops.read((sc), ( 0x9920)) | (0x80000000 | 0x40000000 | 0x20000000 | 0x10000000 ))); | |||
703 | ||||
704 | AR_WRITE(sc, AR_PHY_SPUR_REG,(sc)->ops.write((sc), (0x994c), (0x03fc0000 | 0x00020000 | 0x0001fe00 | 0x00000100 | (((uint32_t)(40) << 0) & 0x0000007f))) | |||
705 | AR_PHY_SPUR_REG_MASK_RATE_CNTL |(sc)->ops.write((sc), (0x994c), (0x03fc0000 | 0x00020000 | 0x0001fe00 | 0x00000100 | (((uint32_t)(40) << 0) & 0x0000007f))) | |||
706 | AR_PHY_SPUR_REG_ENABLE_MASK_PPM |(sc)->ops.write((sc), (0x994c), (0x03fc0000 | 0x00020000 | 0x0001fe00 | 0x00000100 | (((uint32_t)(40) << 0) & 0x0000007f))) | |||
707 | AR_PHY_SPUR_REG_MASK_RATE_SELECT |(sc)->ops.write((sc), (0x994c), (0x03fc0000 | 0x00020000 | 0x0001fe00 | 0x00000100 | (((uint32_t)(40) << 0) & 0x0000007f))) | |||
708 | AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI |(sc)->ops.write((sc), (0x994c), (0x03fc0000 | 0x00020000 | 0x0001fe00 | 0x00000100 | (((uint32_t)(40) << 0) & 0x0000007f))) | |||
709 | SM(AR_PHY_SPUR_REG_SPUR_RSSI_THRESH, AR_SPUR_RSSI_THRESH))(sc)->ops.write((sc), (0x994c), (0x03fc0000 | 0x00020000 | 0x0001fe00 | 0x00000100 | (((uint32_t)(40) << 0) & 0x0000007f))); | |||
710 | ||||
711 | spur_delta_phase = (spur * 524288) / 100; | |||
712 | if (IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)) | |||
713 | spur_freq_sd = (spur * 2048) / 440; | |||
714 | else | |||
715 | spur_freq_sd = (spur * 2048) / 400; | |||
716 | ||||
717 | AR_WRITE(sc, AR_PHY_TIMING11,(sc)->ops.write((sc), (0x99a0), (0x40000000 | (((uint32_t) (spur_freq_sd) << 20) & 0x3ff00000) | (((uint32_t)( spur_delta_phase) << 0) & 0x000fffff))) | |||
718 | AR_PHY_TIMING11_USE_SPUR_IN_AGC |(sc)->ops.write((sc), (0x99a0), (0x40000000 | (((uint32_t) (spur_freq_sd) << 20) & 0x3ff00000) | (((uint32_t)( spur_delta_phase) << 0) & 0x000fffff))) | |||
719 | SM(AR_PHY_TIMING11_SPUR_FREQ_SD, spur_freq_sd) |(sc)->ops.write((sc), (0x99a0), (0x40000000 | (((uint32_t) (spur_freq_sd) << 20) & 0x3ff00000) | (((uint32_t)( spur_delta_phase) << 0) & 0x000fffff))) | |||
720 | SM(AR_PHY_TIMING11_SPUR_DELTA_PHASE, spur_delta_phase))(sc)->ops.write((sc), (0x99a0), (0x40000000 | (((uint32_t) (spur_freq_sd) << 20) & 0x3ff00000) | (((uint32_t)( spur_delta_phase) << 0) & 0x000fffff))); | |||
721 | ||||
722 | bin = spur * 32; | |||
723 | ar5008_set_viterbi_mask(sc, bin); | |||
724 | } | |||
725 | ||||
726 | uint8_t | |||
727 | ar5416_reverse_bits(uint8_t v, int nbits) | |||
728 | { | |||
729 | KASSERT(nbits <= 8)((nbits <= 8) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/ic/ar5416.c" , 729, "nbits <= 8")); | |||
730 | v = ((v >> 1) & 0x55) | ((v & 0x55) << 1); | |||
731 | v = ((v >> 2) & 0x33) | ((v & 0x33) << 2); | |||
732 | v = ((v >> 4) & 0x0f) | ((v & 0x0f) << 4); | |||
733 | return (v >> (8 - nbits)); | |||
734 | } | |||
735 | ||||
736 | uint8_t | |||
737 | ar5416_get_rf_rev(struct athn_softc *sc) | |||
738 | { | |||
739 | uint8_t rev, reg; | |||
740 | int i; | |||
741 | ||||
742 | /* Allow access to analog chips. */ | |||
743 | AR_WRITE(sc, AR_PHY(0), 0x00000007)(sc)->ops.write((sc), ((0x9800 + (0) * 4)), (0x00000007)); | |||
744 | ||||
745 | AR_WRITE(sc, AR_PHY(0x36), 0x00007058)(sc)->ops.write((sc), ((0x9800 + (0x36) * 4)), (0x00007058 )); | |||
746 | for (i = 0; i < 8; i++) | |||
747 | AR_WRITE(sc, AR_PHY(0x20), 0x00010000)(sc)->ops.write((sc), ((0x9800 + (0x20) * 4)), (0x00010000 )); | |||
748 | reg = (AR_READ(sc, AR_PHY(256))(sc)->ops.read((sc), ((0x9800 + (256) * 4))) >> 24) & 0xff; | |||
749 | reg = (reg & 0xf0) >> 4 | (reg & 0x0f) << 4; | |||
750 | ||||
751 | rev = ar5416_reverse_bits(reg, 8); | |||
752 | if ((rev & AR_RADIO_SREV_MAJOR0xf0) == 0) | |||
753 | rev = AR_RAD5133_SREV_MAJOR0xc0; | |||
754 | return (rev); | |||
755 | } | |||
756 | ||||
757 | /* | |||
758 | * Replace bits "off" to "off+nbits-1" in column "col" with the specified | |||
759 | * value. | |||
760 | */ | |||
761 | void | |||
762 | ar5416_rw_rfbits(uint32_t *buf, int col, int off, uint32_t val, int nbits) | |||
763 | { | |||
764 | int idx, bit; | |||
765 | ||||
766 | KASSERT(off >= 1 && col < 4 && nbits <= 32)((off >= 1 && col < 4 && nbits <= 32 ) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/dev/ic/ar5416.c" , 766, "off >= 1 && col < 4 && nbits <= 32" )); | |||
767 | ||||
768 | off--; /* Starts at 1. */ | |||
769 | while (nbits-- > 0) { | |||
770 | idx = off / 8; | |||
771 | bit = off % 8; | |||
772 | buf[idx] &= ~(1 << (bit + col * 8)); | |||
773 | buf[idx] |= ((val >> nbits) & 1) << (bit + col * 8); | |||
774 | off++; | |||
775 | } | |||
776 | } | |||
777 | ||||
778 | /* | |||
779 | * Overwrite db and ob based on ROM settings. | |||
780 | */ | |||
781 | void | |||
782 | ar5416_rw_bank6tpc(struct athn_softc *sc, struct ieee80211_channel *c, | |||
783 | uint32_t *rwbank6tpc) | |||
784 | { | |||
785 | const struct ar5416_eeprom *eep = sc->eep; | |||
786 | const struct ar5416_modal_eep_header *modal; | |||
787 | ||||
788 | if (IEEE80211_IS_CHAN_5GHZ(c)(((c)->ic_flags & 0x0100) != 0)) { | |||
789 | modal = &eep->modalHeader[0]; | |||
790 | /* 5GHz db in column 0, bits [200-202]. */ | |||
791 | ar5416_rw_rfbits(rwbank6tpc, 0, 200, modal->db, 3); | |||
792 | /* 5GHz ob in column 0, bits [203-205]. */ | |||
793 | ar5416_rw_rfbits(rwbank6tpc, 0, 203, modal->ob, 3); | |||
794 | } else { | |||
795 | modal = &eep->modalHeader[1]; | |||
796 | /* 2GHz db in column 0, bits [194-196]. */ | |||
797 | ar5416_rw_rfbits(rwbank6tpc, 0, 194, modal->db, 3); | |||
798 | /* 2GHz ob in column 0, bits [197-199]. */ | |||
799 | ar5416_rw_rfbits(rwbank6tpc, 0, 197, modal->ob, 3); | |||
800 | } | |||
801 | } | |||
802 | ||||
803 | /* | |||
804 | * Program analog RF. | |||
805 | */ | |||
806 | void | |||
807 | ar5416_rf_reset(struct athn_softc *sc, struct ieee80211_channel *c) | |||
808 | { | |||
809 | const uint32_t *bank6tpc; | |||
810 | int i; | |||
811 | ||||
812 | /* Bank 0. */ | |||
813 | AR_WRITE(sc, 0x98b0, 0x1e5795e5)(sc)->ops.write((sc), (0x98b0), (0x1e5795e5)); | |||
814 | AR_WRITE(sc, 0x98e0, 0x02008020)(sc)->ops.write((sc), (0x98e0), (0x02008020)); | |||
815 | ||||
816 | /* Bank 1. */ | |||
817 | AR_WRITE(sc, 0x98b0, 0x02108421)(sc)->ops.write((sc), (0x98b0), (0x02108421)); | |||
818 | AR_WRITE(sc, 0x98ec, 0x00000008)(sc)->ops.write((sc), (0x98ec), (0x00000008)); | |||
819 | ||||
820 | /* Bank 2. */ | |||
821 | AR_WRITE(sc, 0x98b0, 0x0e73ff17)(sc)->ops.write((sc), (0x98b0), (0x0e73ff17)); | |||
822 | AR_WRITE(sc, 0x98e0, 0x00000420)(sc)->ops.write((sc), (0x98e0), (0x00000420)); | |||
823 | ||||
824 | /* Bank 3. */ | |||
825 | if (IEEE80211_IS_CHAN_5GHZ(c)(((c)->ic_flags & 0x0100) != 0)) | |||
826 | AR_WRITE(sc, 0x98f0, 0x01400018)(sc)->ops.write((sc), (0x98f0), (0x01400018)); | |||
827 | else | |||
828 | AR_WRITE(sc, 0x98f0, 0x01c00018)(sc)->ops.write((sc), (0x98f0), (0x01c00018)); | |||
829 | ||||
830 | /* Select the Bank 6 TPC values to use. */ | |||
831 | if (AR_SREV_9160_10_OR_LATER(sc)((sc)->mac_ver >= 0x040)) | |||
832 | bank6tpc = ar9160_bank6tpc_vals; | |||
833 | else | |||
834 | bank6tpc = ar5416_bank6tpc_vals; | |||
835 | if (sc->eep_rev >= AR_EEP_MINOR_VER_22) { | |||
836 | uint32_t *rwbank6tpc = sc->rwbuf; | |||
837 | ||||
838 | /* Copy values from .rodata to writable buffer. */ | |||
839 | memcpy(rwbank6tpc, bank6tpc, 32 * sizeof(uint32_t))__builtin_memcpy((rwbank6tpc), (bank6tpc), (32 * sizeof(uint32_t ))); | |||
840 | ar5416_rw_bank6tpc(sc, c, rwbank6tpc); | |||
841 | bank6tpc = rwbank6tpc; | |||
842 | } | |||
843 | /* Bank 6 TPC. */ | |||
844 | for (i = 0; i < 32; i++) | |||
845 | AR_WRITE(sc, 0x989c, bank6tpc[i])(sc)->ops.write((sc), (0x989c), (bank6tpc[i])); | |||
846 | if (IEEE80211_IS_CHAN_5GHZ(c)(((c)->ic_flags & 0x0100) != 0)) | |||
847 | AR_WRITE(sc, 0x98d0, 0x0000000f)(sc)->ops.write((sc), (0x98d0), (0x0000000f)); | |||
848 | else | |||
849 | AR_WRITE(sc, 0x98d0, 0x0010000f)(sc)->ops.write((sc), (0x98d0), (0x0010000f)); | |||
850 | ||||
851 | /* Bank 7. */ | |||
852 | AR_WRITE(sc, 0x989c, 0x00000500)(sc)->ops.write((sc), (0x989c), (0x00000500)); | |||
853 | AR_WRITE(sc, 0x989c, 0x00000800)(sc)->ops.write((sc), (0x989c), (0x00000800)); | |||
854 | AR_WRITE(sc, 0x98cc, 0x0000000e)(sc)->ops.write((sc), (0x98cc), (0x0000000e)); | |||
855 | } | |||
856 | ||||
857 | void | |||
858 | ar5416_reset_bb_gain(struct athn_softc *sc, struct ieee80211_channel *c) | |||
859 | { | |||
860 | const uint32_t *pvals; | |||
861 | int i; | |||
862 | ||||
863 | if (IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)) | |||
864 | pvals = ar5416_bb_rfgain_vals_2g; | |||
865 | else | |||
866 | pvals = ar5416_bb_rfgain_vals_5g; | |||
867 | for (i = 0; i < 64; i++) | |||
868 | AR_WRITE(sc, AR_PHY_BB_RFGAIN(i), pvals[i])(sc)->ops.write((sc), ((0x9a00 + (i) * 4)), (pvals[i])); | |||
869 | } | |||
870 | ||||
871 | /* | |||
872 | * Fix orientation sensitivity issue on AR5416/2GHz by increasing | |||
873 | * rf_pwd_icsyndiv. | |||
874 | */ | |||
875 | void | |||
876 | ar5416_force_bias(struct athn_softc *sc, struct ieee80211_channel *c) | |||
877 | { | |||
878 | uint32_t *rwbank6 = sc->rwbuf; | |||
879 | uint8_t bias; | |||
880 | int i; | |||
881 | ||||
882 | KASSERT(IEEE80211_IS_CHAN_2GHZ(c))(((((c)->ic_flags & 0x0080) != 0)) ? (void)0 : __assert ("diagnostic ", "/usr/src/sys/dev/ic/ar5416.c", 882, "IEEE80211_IS_CHAN_2GHZ(c)" )); | |||
883 | ||||
884 | /* Copy values from .rodata to writable buffer. */ | |||
885 | memcpy(rwbank6, ar5416_bank6_vals, sizeof(ar5416_bank6_vals))__builtin_memcpy((rwbank6), (ar5416_bank6_vals), (sizeof(ar5416_bank6_vals ))); | |||
886 | ||||
887 | if (c->ic_freq < 2412) | |||
888 | bias = 0; | |||
889 | else if (c->ic_freq < 2422) | |||
890 | bias = 1; | |||
891 | else | |||
892 | bias = 2; | |||
893 | ar5416_reverse_bits(bias, 3); | |||
894 | ||||
895 | /* Overwrite "rf_pwd_icsyndiv" (column 3, bits [181-183].) */ | |||
896 | ar5416_rw_rfbits(rwbank6, 3, 181, bias, 3); | |||
897 | ||||
898 | /* Write Bank 6. */ | |||
899 | for (i = 0; i < 32; i++) | |||
900 | AR_WRITE(sc, 0x989c, rwbank6[i])(sc)->ops.write((sc), (0x989c), (rwbank6[i])); | |||
901 | AR_WRITE(sc, 0x98d0, 0x0010000f)(sc)->ops.write((sc), (0x98d0), (0x0010000f)); | |||
902 | } | |||
903 | ||||
904 | /* | |||
905 | * Overwrite XPA bias level based on ROM setting. | |||
906 | */ | |||
907 | void | |||
908 | ar9160_rw_addac(struct athn_softc *sc, struct ieee80211_channel *c, | |||
909 | uint32_t *addac) | |||
910 | { | |||
911 | struct ar5416_eeprom *eep = sc->eep; | |||
912 | struct ar5416_modal_eep_header *modal; | |||
913 | uint8_t fbin, bias; | |||
914 | int i; | |||
915 | ||||
916 | /* XXX xpaBiasLvlFreq values have not been endian-swapped? */ | |||
917 | ||||
918 | /* Get the XPA bias level to use for the specified channel. */ | |||
919 | modal = &eep->modalHeader[IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)]; | |||
920 | if (modal->xpaBiasLvl == 0xff) { | |||
921 | bias = modal->xpaBiasLvlFreq[0] >> 14; | |||
922 | fbin = athn_chan2fbin(c); | |||
923 | for (i = 1; i < 3; i++) { | |||
924 | if (modal->xpaBiasLvlFreq[i] == 0) | |||
925 | break; | |||
926 | if ((modal->xpaBiasLvlFreq[i] & 0xff) < fbin) | |||
927 | break; | |||
928 | bias = modal->xpaBiasLvlFreq[i] >> 14; | |||
929 | } | |||
930 | } else | |||
931 | bias = modal->xpaBiasLvl & 0x3; | |||
932 | ||||
933 | bias = ar5416_reverse_bits(bias, 2); /* Put in host bit-order. */ | |||
934 | DPRINTFN(4, ("bias level=%d\n", bias)); | |||
935 | if (IEEE80211_IS_CHAN_2GHZ(c)(((c)->ic_flags & 0x0080) != 0)) | |||
936 | ar5416_rw_rfbits(addac, 0, 60, bias, 2); | |||
937 | else | |||
938 | ar5416_rw_rfbits(addac, 0, 55, bias, 2); | |||
939 | } | |||
940 | ||||
941 | void | |||
942 | ar5416_reset_addac(struct athn_softc *sc, struct ieee80211_channel *c) | |||
943 | { | |||
944 | const struct athn_addac *addac = sc->addac; | |||
945 | const uint32_t *pvals; | |||
946 | int i; | |||
947 | ||||
948 | if (AR_SREV_9160(sc)((sc)->mac_ver == 0x040) && sc->eep_rev >= AR_EEP_MINOR_VER_77) { | |||
949 | uint32_t *rwaddac = sc->rwbuf; | |||
950 | ||||
951 | /* Copy values from .rodata to writable buffer. */ | |||
952 | memcpy(rwaddac, addac->vals, addac->nvals * sizeof(uint32_t))__builtin_memcpy((rwaddac), (addac->vals), (addac->nvals * sizeof(uint32_t))); | |||
953 | ar9160_rw_addac(sc, c, rwaddac); | |||
954 | pvals = rwaddac; | |||
955 | } else | |||
956 | pvals = addac->vals; | |||
957 | for (i = 0; i < addac->nvals; i++) | |||
958 | AR_WRITE(sc, 0x989c, pvals[i])(sc)->ops.write((sc), (0x989c), (pvals[i])); | |||
959 | AR_WRITE(sc, 0x98cc, 0)(sc)->ops.write((sc), (0x98cc), (0)); /* Finalize. */ | |||
960 | } |