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