| 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 | } |