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