1 /* $OpenBSD: ar9287.c,v 1.24 2016/01/05 18:41:15 stsp Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 Damien Bergamini <damien.bergamini@free.fr> 5 * Copyright (c) 2008-2009 Atheros Communications Inc. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* 21 * Driver for Atheros 802.11a/g/n chipsets. 22 * Routines for AR9227 and AR9287 chipsets. 23 */ 24 25 #include "bpfilter.h" 26 27 #include <sys/param.h> 28 #include <sys/sockio.h> 29 #include <sys/mbuf.h> 30 #include <sys/kernel.h> 31 #include <sys/socket.h> 32 #include <sys/systm.h> 33 #include <sys/malloc.h> 34 #include <sys/queue.h> 35 #include <sys/timeout.h> 36 #include <sys/conf.h> 37 #include <sys/device.h> 38 #include <sys/endian.h> 39 40 #include <machine/bus.h> 41 #include <machine/intr.h> 42 43 #if NBPFILTER > 0 44 #include <net/bpf.h> 45 #endif 46 #include <net/if.h> 47 #include <net/if_media.h> 48 49 #include <netinet/in.h> 50 #include <netinet/if_ether.h> 51 52 #include <net80211/ieee80211_var.h> 53 #include <net80211/ieee80211_amrr.h> 54 #include <net80211/ieee80211_radiotap.h> 55 56 #include <dev/ic/athnreg.h> 57 #include <dev/ic/athnvar.h> 58 59 #include <dev/ic/ar5008reg.h> 60 #include <dev/ic/ar9280reg.h> 61 #include <dev/ic/ar9287reg.h> 62 63 int ar9287_attach(struct athn_softc *); 64 void ar9287_setup(struct athn_softc *); 65 void ar9287_swap_rom(struct athn_softc *); 66 const struct ar_spur_chan *ar9287_get_spur_chans(struct athn_softc *, int); 67 void ar9287_init_from_rom(struct athn_softc *, struct ieee80211_channel *, 68 struct ieee80211_channel *); 69 void ar9287_get_pdadcs(struct athn_softc *, struct ieee80211_channel *, 70 int, int, uint8_t, uint8_t *, uint8_t *); 71 void ar9287_olpc_get_pdgain(struct athn_softc *, struct ieee80211_channel *, 72 int, int8_t *); 73 void ar9287_set_power_calib(struct athn_softc *, 74 struct ieee80211_channel *); 75 void ar9287_set_txpower(struct athn_softc *, struct ieee80211_channel *, 76 struct ieee80211_channel *); 77 void ar9287_olpc_init(struct athn_softc *); 78 void ar9287_olpc_temp_compensation(struct athn_softc *); 79 void ar9287_1_3_enable_async_fifo(struct athn_softc *); 80 void ar9287_1_3_setup_async_fifo(struct athn_softc *); 81 82 /* Extern functions. */ 83 uint8_t athn_chan2fbin(struct ieee80211_channel *); 84 void athn_get_pier_ival(uint8_t, const uint8_t *, int, int *, int *); 85 int ar5008_attach(struct athn_softc *); 86 void ar5008_write_txpower(struct athn_softc *, int16_t power[]); 87 void ar5008_get_pdadcs(struct athn_softc *, uint8_t, struct athn_pier *, 88 struct athn_pier *, int, int, uint8_t, uint8_t *, uint8_t *); 89 void ar5008_get_lg_tpow(struct athn_softc *, struct ieee80211_channel *, 90 uint8_t, const struct ar_cal_target_power_leg *, int, uint8_t[]); 91 void ar5008_get_ht_tpow(struct athn_softc *, struct ieee80211_channel *, 92 uint8_t, const struct ar_cal_target_power_ht *, int, uint8_t[]); 93 int ar9280_set_synth(struct athn_softc *, struct ieee80211_channel *, 94 struct ieee80211_channel *); 95 void ar9280_spur_mitigate(struct athn_softc *, struct ieee80211_channel *, 96 struct ieee80211_channel *); 97 98 99 int 100 ar9287_attach(struct athn_softc *sc) 101 { 102 sc->eep_base = AR9287_EEP_START_LOC; 103 sc->eep_size = sizeof(struct ar9287_eeprom); 104 sc->def_nf = AR9287_PHY_CCA_MAX_GOOD_VALUE; 105 sc->ngpiopins = (sc->flags & ATHN_FLAG_USB) ? 16 : 11; 106 sc->led_pin = 8; 107 sc->workaround = AR9285_WA_DEFAULT; 108 sc->ops.setup = ar9287_setup; 109 sc->ops.swap_rom = ar9287_swap_rom; 110 sc->ops.init_from_rom = ar9287_init_from_rom; 111 sc->ops.set_txpower = ar9287_set_txpower; 112 sc->ops.set_synth = ar9280_set_synth; 113 sc->ops.spur_mitigate = ar9280_spur_mitigate; 114 sc->ops.get_spur_chans = ar9287_get_spur_chans; 115 sc->ops.olpc_init = ar9287_olpc_init; 116 sc->ops.olpc_temp_compensation = ar9287_olpc_temp_compensation; 117 sc->ini = &ar9287_1_1_ini; 118 sc->serdes = &ar9280_2_0_serdes; 119 120 return (ar5008_attach(sc)); 121 } 122 123 void 124 ar9287_setup(struct athn_softc *sc) 125 { 126 const struct ar9287_eeprom *eep = sc->eep; 127 128 /* Determine if open loop power control should be used. */ 129 if (eep->baseEepHeader.openLoopPwrCntl) 130 sc->flags |= ATHN_FLAG_OLPC; 131 132 sc->rx_gain = &ar9287_1_1_rx_gain; 133 sc->tx_gain = &ar9287_1_1_tx_gain; 134 } 135 136 void 137 ar9287_swap_rom(struct athn_softc *sc) 138 { 139 struct ar9287_eeprom *eep = sc->eep; 140 int i; 141 142 eep->modalHeader.antCtrlCommon = 143 swap32(eep->modalHeader.antCtrlCommon); 144 145 for (i = 0; i < AR9287_MAX_CHAINS; i++) { 146 eep->modalHeader.antCtrlChain[i] = 147 swap32(eep->modalHeader.antCtrlChain[i]); 148 } 149 for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { 150 eep->modalHeader.spurChans[i].spurChan = 151 swap16(eep->modalHeader.spurChans[i].spurChan); 152 } 153 } 154 155 const struct ar_spur_chan * 156 ar9287_get_spur_chans(struct athn_softc *sc, int is2ghz) 157 { 158 const struct ar9287_eeprom *eep = sc->eep; 159 160 KASSERT(is2ghz); 161 return (eep->modalHeader.spurChans); 162 } 163 164 void 165 ar9287_init_from_rom(struct athn_softc *sc, struct ieee80211_channel *c, 166 struct ieee80211_channel *extc) 167 { 168 const struct ar9287_eeprom *eep = sc->eep; 169 const struct ar9287_modal_eep_header *modal = &eep->modalHeader; 170 uint32_t reg, offset; 171 int i; 172 173 AR_WRITE(sc, AR_PHY_SWITCH_COM, modal->antCtrlCommon); 174 175 for (i = 0; i < AR9287_MAX_CHAINS; i++) { 176 offset = i * 0x1000; 177 178 AR_WRITE(sc, AR_PHY_SWITCH_CHAIN_0 + offset, 179 modal->antCtrlChain[i]); 180 181 reg = AR_READ(sc, AR_PHY_TIMING_CTRL4_0 + offset); 182 reg = RW(reg, AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, 183 modal->iqCalICh[i]); 184 reg = RW(reg, AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, 185 modal->iqCalQCh[i]); 186 AR_WRITE(sc, AR_PHY_TIMING_CTRL4_0 + offset, reg); 187 188 reg = AR_READ(sc, AR_PHY_GAIN_2GHZ + offset); 189 reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, 190 modal->bswMargin[i]); 191 reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN1_DB, 192 modal->bswAtten[i]); 193 AR_WRITE(sc, AR_PHY_GAIN_2GHZ + offset, reg); 194 195 reg = AR_READ(sc, AR_PHY_RXGAIN + offset); 196 reg = RW(reg, AR9280_PHY_RXGAIN_TXRX_MARGIN, 197 modal->rxTxMarginCh[i]); 198 reg = RW(reg, AR9280_PHY_RXGAIN_TXRX_ATTEN, 199 modal->txRxAttenCh[i]); 200 AR_WRITE(sc, AR_PHY_RXGAIN + offset, reg); 201 } 202 203 reg = AR_READ(sc, AR_PHY_SETTLING); 204 if (extc != NULL) 205 reg = RW(reg, AR_PHY_SETTLING_SWITCH, modal->swSettleHt40); 206 else 207 reg = RW(reg, AR_PHY_SETTLING_SWITCH, modal->switchSettling); 208 AR_WRITE(sc, AR_PHY_SETTLING, reg); 209 210 reg = AR_READ(sc, AR_PHY_DESIRED_SZ); 211 reg = RW(reg, AR_PHY_DESIRED_SZ_ADC, modal->adcDesiredSize); 212 AR_WRITE(sc, AR_PHY_DESIRED_SZ, reg); 213 214 reg = SM(AR_PHY_RF_CTL4_TX_END_XPAA_OFF, modal->txEndToXpaOff); 215 reg |= SM(AR_PHY_RF_CTL4_TX_END_XPAB_OFF, modal->txEndToXpaOff); 216 reg |= SM(AR_PHY_RF_CTL4_FRAME_XPAA_ON, modal->txFrameToXpaOn); 217 reg |= SM(AR_PHY_RF_CTL4_FRAME_XPAB_ON, modal->txFrameToXpaOn); 218 AR_WRITE(sc, AR_PHY_RF_CTL4, reg); 219 220 reg = AR_READ(sc, AR_PHY_RF_CTL3); 221 reg = RW(reg, AR_PHY_TX_END_TO_A2_RX_ON, modal->txEndToRxOn); 222 AR_WRITE(sc, AR_PHY_RF_CTL3, reg); 223 224 reg = AR_READ(sc, AR_PHY_CCA(0)); 225 reg = RW(reg, AR9280_PHY_CCA_THRESH62, modal->thresh62); 226 AR_WRITE(sc, AR_PHY_CCA(0), reg); 227 228 reg = AR_READ(sc, AR_PHY_EXT_CCA0); 229 reg = RW(reg, AR_PHY_EXT_CCA0_THRESH62, modal->thresh62); 230 AR_WRITE(sc, AR_PHY_EXT_CCA0, reg); 231 232 reg = AR_READ(sc, AR9287_AN_RF2G3_CH0); 233 reg = RW(reg, AR9287_AN_RF2G3_DB1, modal->db1); 234 reg = RW(reg, AR9287_AN_RF2G3_DB2, modal->db2); 235 reg = RW(reg, AR9287_AN_RF2G3_OB_CCK, modal->ob_cck); 236 reg = RW(reg, AR9287_AN_RF2G3_OB_PSK, modal->ob_psk); 237 reg = RW(reg, AR9287_AN_RF2G3_OB_QAM, modal->ob_qam); 238 reg = RW(reg, AR9287_AN_RF2G3_OB_PAL_OFF, modal->ob_pal_off); 239 AR_WRITE(sc, AR9287_AN_RF2G3_CH0, reg); 240 AR_WRITE_BARRIER(sc); 241 DELAY(100); 242 243 reg = AR_READ(sc, AR9287_AN_RF2G3_CH1); 244 reg = RW(reg, AR9287_AN_RF2G3_DB1, modal->db1); 245 reg = RW(reg, AR9287_AN_RF2G3_DB2, modal->db2); 246 reg = RW(reg, AR9287_AN_RF2G3_OB_CCK, modal->ob_cck); 247 reg = RW(reg, AR9287_AN_RF2G3_OB_PSK, modal->ob_psk); 248 reg = RW(reg, AR9287_AN_RF2G3_OB_QAM, modal->ob_qam); 249 reg = RW(reg, AR9287_AN_RF2G3_OB_PAL_OFF, modal->ob_pal_off); 250 AR_WRITE(sc, AR9287_AN_RF2G3_CH1, reg); 251 AR_WRITE_BARRIER(sc); 252 DELAY(100); 253 254 reg = AR_READ(sc, AR_PHY_RF_CTL2); 255 reg = RW(reg, AR_PHY_TX_END_DATA_START, modal->txFrameToDataStart); 256 reg = RW(reg, AR_PHY_TX_END_PA_ON, modal->txFrameToPaOn); 257 AR_WRITE(sc, AR_PHY_RF_CTL2, reg); 258 259 reg = AR_READ(sc, AR9287_AN_TOP2); 260 reg = RW(reg, AR9287_AN_TOP2_XPABIAS_LVL, modal->xpaBiasLvl); 261 AR_WRITE(sc, AR9287_AN_TOP2, reg); 262 AR_WRITE_BARRIER(sc); 263 DELAY(100); 264 } 265 266 void 267 ar9287_get_pdadcs(struct athn_softc *sc, struct ieee80211_channel *c, 268 int chain, int nxpdgains, uint8_t overlap, uint8_t *boundaries, 269 uint8_t *pdadcs) 270 { 271 const struct ar9287_eeprom *eep = sc->eep; 272 const struct ar9287_cal_data_per_freq *pierdata; 273 const uint8_t *pierfreq; 274 struct athn_pier lopier, hipier; 275 int16_t delta; 276 uint8_t fbin; 277 int i, lo, hi, npiers; 278 279 pierfreq = eep->calFreqPier2G; 280 pierdata = (const struct ar9287_cal_data_per_freq *) 281 eep->calPierData2G[chain]; 282 npiers = AR9287_NUM_2G_CAL_PIERS; 283 284 /* Find channel in ROM pier table. */ 285 fbin = athn_chan2fbin(c); 286 athn_get_pier_ival(fbin, pierfreq, npiers, &lo, &hi); 287 288 lopier.fbin = pierfreq[lo]; 289 hipier.fbin = pierfreq[hi]; 290 for (i = 0; i < nxpdgains; i++) { 291 lopier.pwr[i] = pierdata[lo].pwrPdg[i]; 292 lopier.vpd[i] = pierdata[lo].vpdPdg[i]; 293 hipier.pwr[i] = pierdata[lo].pwrPdg[i]; 294 hipier.vpd[i] = pierdata[lo].vpdPdg[i]; 295 } 296 ar5008_get_pdadcs(sc, fbin, &lopier, &hipier, nxpdgains, 297 AR9287_PD_GAIN_ICEPTS, overlap, boundaries, pdadcs); 298 299 delta = (eep->baseEepHeader.pwrTableOffset - 300 AR_PWR_TABLE_OFFSET_DB) * 2; /* In half dB. */ 301 if (delta != 0) { 302 /* Shift the PDADC table to start at the new offset. */ 303 /* XXX Our padding value differs from Linux. */ 304 for (i = 0; i < AR_NUM_PDADC_VALUES; i++) 305 pdadcs[i] = pdadcs[MIN(i + delta, 306 AR_NUM_PDADC_VALUES - 1)]; 307 } 308 } 309 310 void 311 ar9287_olpc_get_pdgain(struct athn_softc *sc, struct ieee80211_channel *c, 312 int chain, int8_t *pwr) 313 { 314 const struct ar9287_eeprom *eep = sc->eep; 315 const struct ar_cal_data_per_freq_olpc *pierdata; 316 const uint8_t *pierfreq; 317 uint8_t fbin; 318 int lo, hi, npiers; 319 320 pierfreq = eep->calFreqPier2G; 321 pierdata = (const struct ar_cal_data_per_freq_olpc *) 322 eep->calPierData2G[chain]; 323 npiers = AR9287_NUM_2G_CAL_PIERS; 324 325 /* Find channel in ROM pier table. */ 326 fbin = athn_chan2fbin(c); 327 athn_get_pier_ival(fbin, pierfreq, npiers, &lo, &hi); 328 329 #if 0 330 *pwr = athn_interpolate(fbin, 331 pierfreq[lo], pierdata[lo].pwrPdg[0][0], 332 pierfreq[hi], pierdata[hi].pwrPdg[0][0]); 333 #else 334 *pwr = (pierdata[lo].pwrPdg[0][0] + pierdata[hi].pwrPdg[0][0]) / 2; 335 #endif 336 } 337 338 void 339 ar9287_set_power_calib(struct athn_softc *sc, struct ieee80211_channel *c) 340 { 341 const struct ar9287_eeprom *eep = sc->eep; 342 uint8_t boundaries[AR_PD_GAINS_IN_MASK]; 343 uint8_t pdadcs[AR_NUM_PDADC_VALUES]; 344 uint8_t xpdgains[AR9287_NUM_PD_GAINS]; 345 int8_t txpower; 346 uint8_t overlap; 347 uint32_t reg, offset; 348 int i, j, nxpdgains; 349 350 if (sc->eep_rev < AR_EEP_MINOR_VER_2) { 351 overlap = MS(AR_READ(sc, AR_PHY_TPCRG5), 352 AR_PHY_TPCRG5_PD_GAIN_OVERLAP); 353 } else 354 overlap = eep->modalHeader.pdGainOverlap; 355 356 if (sc->flags & ATHN_FLAG_OLPC) { 357 /* XXX not here. */ 358 sc->pdadc = 359 ((const struct ar_cal_data_per_freq_olpc *) 360 eep->calPierData2G[0])->vpdPdg[0][0]; 361 } 362 363 nxpdgains = 0; 364 memset(xpdgains, 0, sizeof(xpdgains)); 365 for (i = AR9287_PD_GAINS_IN_MASK - 1; i >= 0; i--) { 366 if (nxpdgains >= AR9287_NUM_PD_GAINS) 367 break; /* Can't happen. */ 368 if (eep->modalHeader.xpdGain & (1 << i)) 369 xpdgains[nxpdgains++] = i; 370 } 371 reg = AR_READ(sc, AR_PHY_TPCRG1); 372 reg = RW(reg, AR_PHY_TPCRG1_NUM_PD_GAIN, nxpdgains - 1); 373 reg = RW(reg, AR_PHY_TPCRG1_PD_GAIN_1, xpdgains[0]); 374 reg = RW(reg, AR_PHY_TPCRG1_PD_GAIN_2, xpdgains[1]); 375 AR_WRITE(sc, AR_PHY_TPCRG1, reg); 376 AR_WRITE_BARRIER(sc); 377 378 for (i = 0; i < AR9287_MAX_CHAINS; i++) { 379 if (!(sc->txchainmask & (1 << i))) 380 continue; 381 382 offset = i * 0x1000; 383 384 if (sc->flags & ATHN_FLAG_OLPC) { 385 ar9287_olpc_get_pdgain(sc, c, i, &txpower); 386 387 reg = AR_READ(sc, AR_PHY_TX_PWRCTRL6_0); 388 reg = RW(reg, AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); 389 AR_WRITE(sc, AR_PHY_TX_PWRCTRL6_0, reg); 390 391 reg = AR_READ(sc, AR_PHY_TX_PWRCTRL6_1); 392 reg = RW(reg, AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); 393 AR_WRITE(sc, AR_PHY_TX_PWRCTRL6_1, reg); 394 395 /* NB: txpower is in half dB. */ 396 reg = AR_READ(sc, AR_PHY_CH0_TX_PWRCTRL11 + offset); 397 reg = RW(reg, AR_PHY_TX_PWRCTRL_OLPC_PWR, txpower); 398 AR_WRITE(sc, AR_PHY_CH0_TX_PWRCTRL11 + offset, reg); 399 400 AR_WRITE_BARRIER(sc); 401 continue; /* That's it for open loop mode. */ 402 } 403 404 /* Closed loop power control. */ 405 ar9287_get_pdadcs(sc, c, i, nxpdgains, overlap, 406 boundaries, pdadcs); 407 408 /* Write boundaries. */ 409 if (i == 0) { 410 reg = SM(AR_PHY_TPCRG5_PD_GAIN_OVERLAP, 411 overlap); 412 reg |= SM(AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1, 413 boundaries[0]); 414 reg |= SM(AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2, 415 boundaries[1]); 416 reg |= SM(AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3, 417 boundaries[2]); 418 reg |= SM(AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4, 419 boundaries[3]); 420 AR_WRITE(sc, AR_PHY_TPCRG5 + offset, reg); 421 } 422 /* Write PDADC values. */ 423 for (j = 0; j < AR_NUM_PDADC_VALUES; j += 4) { 424 AR_WRITE(sc, AR_PHY_PDADC_TBL_BASE + offset + j, 425 pdadcs[j + 0] << 0 | 426 pdadcs[j + 1] << 8 | 427 pdadcs[j + 2] << 16 | 428 pdadcs[j + 3] << 24); 429 } 430 AR_WRITE_BARRIER(sc); 431 } 432 } 433 434 void 435 ar9287_set_txpower(struct athn_softc *sc, struct ieee80211_channel *c, 436 struct ieee80211_channel *extc) 437 { 438 const struct ar9287_eeprom *eep = sc->eep; 439 const struct ar9287_modal_eep_header *modal = &eep->modalHeader; 440 uint8_t tpow_cck[4], tpow_ofdm[4]; 441 uint8_t tpow_cck_ext[4], tpow_ofdm_ext[4]; 442 uint8_t tpow_ht20[8], tpow_ht40[8]; 443 uint8_t ht40inc; 444 int16_t pwr = 0, max_ant_gain, power[ATHN_POWER_COUNT]; 445 int i; 446 447 ar9287_set_power_calib(sc, c); 448 449 /* Compute transmit power reduction due to antenna gain. */ 450 max_ant_gain = MAX(modal->antennaGainCh[0], modal->antennaGainCh[1]); 451 /* XXX */ 452 453 /* 454 * Reduce scaled power by number of active chains to get per-chain 455 * transmit power level. 456 */ 457 if (sc->ntxchains == 2) 458 pwr -= AR_PWR_DECREASE_FOR_2_CHAIN; 459 if (pwr < 0) 460 pwr = 0; 461 462 /* Get CCK target powers. */ 463 ar5008_get_lg_tpow(sc, c, AR_CTL_11B, eep->calTargetPowerCck, 464 AR9287_NUM_2G_CCK_TARGET_POWERS, tpow_cck); 465 466 /* Get OFDM target powers. */ 467 ar5008_get_lg_tpow(sc, c, AR_CTL_11G, eep->calTargetPower2G, 468 AR9287_NUM_2G_20_TARGET_POWERS, tpow_ofdm); 469 470 /* Get HT-20 target powers. */ 471 ar5008_get_ht_tpow(sc, c, AR_CTL_2GHT20, eep->calTargetPower2GHT20, 472 AR9287_NUM_2G_20_TARGET_POWERS, tpow_ht20); 473 474 if (extc != NULL) { 475 /* Get HT-40 target powers. */ 476 ar5008_get_ht_tpow(sc, c, AR_CTL_2GHT40, 477 eep->calTargetPower2GHT40, AR9287_NUM_2G_40_TARGET_POWERS, 478 tpow_ht40); 479 480 /* Get secondary channel CCK target powers. */ 481 ar5008_get_lg_tpow(sc, extc, AR_CTL_11B, 482 eep->calTargetPowerCck, AR9287_NUM_2G_CCK_TARGET_POWERS, 483 tpow_cck_ext); 484 485 /* Get secondary channel OFDM target powers. */ 486 ar5008_get_lg_tpow(sc, extc, AR_CTL_11G, 487 eep->calTargetPower2G, AR9287_NUM_2G_20_TARGET_POWERS, 488 tpow_ofdm_ext); 489 } 490 491 memset(power, 0, sizeof(power)); 492 /* Shuffle target powers accross transmit rates. */ 493 power[ATHN_POWER_OFDM6 ] = 494 power[ATHN_POWER_OFDM9 ] = 495 power[ATHN_POWER_OFDM12 ] = 496 power[ATHN_POWER_OFDM18 ] = 497 power[ATHN_POWER_OFDM24 ] = tpow_ofdm[0]; 498 power[ATHN_POWER_OFDM36 ] = tpow_ofdm[1]; 499 power[ATHN_POWER_OFDM48 ] = tpow_ofdm[2]; 500 power[ATHN_POWER_OFDM54 ] = tpow_ofdm[3]; 501 power[ATHN_POWER_XR ] = tpow_ofdm[0]; 502 power[ATHN_POWER_CCK1_LP ] = tpow_cck[0]; 503 power[ATHN_POWER_CCK2_LP ] = 504 power[ATHN_POWER_CCK2_SP ] = tpow_cck[1]; 505 power[ATHN_POWER_CCK55_LP] = 506 power[ATHN_POWER_CCK55_SP] = tpow_cck[2]; 507 power[ATHN_POWER_CCK11_LP] = 508 power[ATHN_POWER_CCK11_SP] = tpow_cck[3]; 509 for (i = 0; i < nitems(tpow_ht20); i++) 510 power[ATHN_POWER_HT20(i)] = tpow_ht20[i]; 511 if (extc != NULL) { 512 /* Correct PAR difference between HT40 and HT20/Legacy. */ 513 if (sc->eep_rev >= AR_EEP_MINOR_VER_2) 514 ht40inc = modal->ht40PowerIncForPdadc; 515 else 516 ht40inc = AR_HT40_POWER_INC_FOR_PDADC; 517 for (i = 0; i < nitems(tpow_ht40); i++) 518 power[ATHN_POWER_HT40(i)] = tpow_ht40[i] + ht40inc; 519 power[ATHN_POWER_OFDM_DUP] = tpow_ht40[0]; 520 power[ATHN_POWER_CCK_DUP ] = tpow_ht40[0]; 521 power[ATHN_POWER_OFDM_EXT] = tpow_ofdm_ext[0]; 522 if (IEEE80211_IS_CHAN_2GHZ(c)) 523 power[ATHN_POWER_CCK_EXT] = tpow_cck_ext[0]; 524 } 525 526 for (i = 0; i < ATHN_POWER_COUNT; i++) { 527 power[i] -= AR_PWR_TABLE_OFFSET_DB * 2; /* In half dB. */ 528 if (power[i] > AR_MAX_RATE_POWER) 529 power[i] = AR_MAX_RATE_POWER; 530 } 531 /* Commit transmit power values to hardware. */ 532 ar5008_write_txpower(sc, power); 533 } 534 535 void 536 ar9287_olpc_init(struct athn_softc *sc) 537 { 538 uint32_t reg; 539 540 AR_SETBITS(sc, AR_PHY_TX_PWRCTRL9, AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL); 541 542 reg = AR_READ(sc, AR9287_AN_TXPC0); 543 reg = RW(reg, AR9287_AN_TXPC0_TXPCMODE, 544 AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE); 545 AR_WRITE(sc, AR9287_AN_TXPC0, reg); 546 AR_WRITE_BARRIER(sc); 547 DELAY(100); 548 } 549 550 void 551 ar9287_olpc_temp_compensation(struct athn_softc *sc) 552 { 553 const struct ar9287_eeprom *eep = sc->eep; 554 int8_t pdadc, slope, tcomp; 555 uint32_t reg; 556 557 reg = AR_READ(sc, AR_PHY_TX_PWRCTRL4); 558 pdadc = MS(reg, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); 559 DPRINTFN(3, ("PD Avg Out=%d\n", pdadc)); 560 561 if (sc->pdadc == 0 || pdadc == 0) 562 return; /* No frames transmitted yet. */ 563 564 /* Compute Tx gain temperature compensation. */ 565 if (sc->eep_rev >= AR_EEP_MINOR_VER_2) 566 slope = eep->baseEepHeader.tempSensSlope; 567 else 568 slope = 0; 569 if (slope != 0) /* Prevents division by zero. */ 570 tcomp = ((pdadc - sc->pdadc) * 4) / slope; 571 else 572 tcomp = 0; 573 DPRINTFN(3, ("OLPC temp compensation=%d\n", tcomp)); 574 575 /* Write compensation value for both Tx chains. */ 576 reg = AR_READ(sc, AR_PHY_CH0_TX_PWRCTRL11); 577 reg = RW(reg, AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, tcomp); 578 AR_WRITE(sc, AR_PHY_CH0_TX_PWRCTRL11, reg); 579 580 reg = AR_READ(sc, AR_PHY_CH1_TX_PWRCTRL11); 581 reg = RW(reg, AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP, tcomp); 582 AR_WRITE(sc, AR_PHY_CH1_TX_PWRCTRL11, reg); 583 AR_WRITE_BARRIER(sc); 584 } 585 586 void 587 ar9287_1_3_enable_async_fifo(struct athn_softc *sc) 588 { 589 /* Enable ASYNC FIFO. */ 590 AR_SETBITS(sc, AR_MAC_PCU_ASYNC_FIFO_REG3, 591 AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL); 592 AR_SETBITS(sc, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO); 593 AR_CLRBITS(sc, AR_MAC_PCU_ASYNC_FIFO_REG3, 594 AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET); 595 AR_SETBITS(sc, AR_MAC_PCU_ASYNC_FIFO_REG3, 596 AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET); 597 AR_WRITE_BARRIER(sc); 598 } 599 600 void 601 ar9287_1_3_setup_async_fifo(struct athn_softc *sc) 602 { 603 uint32_t reg; 604 605 /* 606 * MAC runs at 117MHz (instead of 88/44MHz) when ASYNC FIFO is 607 * enabled, so the following counters have to be changed. 608 */ 609 AR_WRITE(sc, AR_D_GBL_IFS_SIFS, AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR); 610 AR_WRITE(sc, AR_D_GBL_IFS_SLOT, AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR); 611 AR_WRITE(sc, AR_D_GBL_IFS_EIFS, AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR); 612 613 AR_WRITE(sc, AR_TIME_OUT, AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR); 614 AR_WRITE(sc, AR_USEC, AR_USEC_ASYNC_FIFO_DUR); 615 616 AR_SETBITS(sc, AR_MAC_PCU_LOGIC_ANALYZER, 617 AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768); 618 619 reg = AR_READ(sc, AR_AHB_MODE); 620 reg = RW(reg, AR_AHB_CUSTOM_BURST, AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL); 621 AR_WRITE(sc, AR_AHB_MODE, reg); 622 623 AR_SETBITS(sc, AR_PCU_MISC_MODE2, AR_PCU_MISC_MODE2_ENABLE_AGGWEP); 624 AR_WRITE_BARRIER(sc); 625 } 626