1 /* $OpenBSD: ar9285.c,v 1.29 2021/04/15 18:25:43 stsp Exp $ */ 2 3 /*- 4 * Copyright (c) 2009-2010 Damien Bergamini <damien.bergamini@free.fr> 5 * Copyright (c) 2008-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 AR9285 and AR9271 chipsets. 23 */ 24 25 #include "athn_usb.h" 26 #include "bpfilter.h" 27 28 #include <sys/param.h> 29 #include <sys/sockio.h> 30 #include <sys/mbuf.h> 31 #include <sys/kernel.h> 32 #include <sys/socket.h> 33 #include <sys/systm.h> 34 #include <sys/malloc.h> 35 #include <sys/queue.h> 36 #include <sys/timeout.h> 37 #include <sys/conf.h> 38 #include <sys/device.h> 39 #include <sys/endian.h> 40 41 #include <machine/bus.h> 42 #include <machine/intr.h> 43 44 #if NBPFILTER > 0 45 #include <net/bpf.h> 46 #endif 47 #include <net/if.h> 48 #include <net/if_media.h> 49 50 #include <netinet/in.h> 51 #include <netinet/if_ether.h> 52 53 #include <net80211/ieee80211_var.h> 54 #include <net80211/ieee80211_amrr.h> 55 #include <net80211/ieee80211_ra.h> 56 #include <net80211/ieee80211_radiotap.h> 57 58 #include <dev/ic/athnreg.h> 59 #include <dev/ic/athnvar.h> 60 61 #include <dev/ic/ar5008reg.h> 62 #include <dev/ic/ar9280reg.h> 63 #include <dev/ic/ar9285reg.h> 64 65 int ar9285_attach(struct athn_softc *); 66 void ar9285_setup(struct athn_softc *); 67 void ar9285_swap_rom(struct athn_softc *); 68 const struct ar_spur_chan *ar9285_get_spur_chans(struct athn_softc *, int); 69 void ar9285_init_from_rom(struct athn_softc *, struct ieee80211_channel *, 70 struct ieee80211_channel *); 71 void ar9285_pa_calib(struct athn_softc *); 72 void ar9271_pa_calib(struct athn_softc *); 73 int ar9285_cl_cal(struct athn_softc *, struct ieee80211_channel *, 74 struct ieee80211_channel *); 75 void ar9271_load_ani(struct athn_softc *); 76 int ar9285_init_calib(struct athn_softc *, struct ieee80211_channel *, 77 struct ieee80211_channel *); 78 void ar9285_get_pdadcs(struct athn_softc *, struct ieee80211_channel *, 79 int, uint8_t, uint8_t *, uint8_t *); 80 void ar9285_set_power_calib(struct athn_softc *, 81 struct ieee80211_channel *); 82 void ar9285_set_txpower(struct athn_softc *, struct ieee80211_channel *, 83 struct ieee80211_channel *); 84 85 /* Extern functions. */ 86 uint8_t athn_chan2fbin(struct ieee80211_channel *); 87 void athn_get_pier_ival(uint8_t, const uint8_t *, int, int *, int *); 88 int ar5008_attach(struct athn_softc *); 89 void ar5008_write_txpower(struct athn_softc *, int16_t power[]); 90 void ar5008_get_pdadcs(struct athn_softc *, uint8_t, struct athn_pier *, 91 struct athn_pier *, int, int, uint8_t, uint8_t *, uint8_t *); 92 void ar5008_get_lg_tpow(struct athn_softc *, struct ieee80211_channel *, 93 uint8_t, const struct ar_cal_target_power_leg *, int, uint8_t[]); 94 void ar5008_get_ht_tpow(struct athn_softc *, struct ieee80211_channel *, 95 uint8_t, const struct ar_cal_target_power_ht *, int, uint8_t[]); 96 int ar9280_set_synth(struct athn_softc *, struct ieee80211_channel *, 97 struct ieee80211_channel *); 98 void ar9280_spur_mitigate(struct athn_softc *, struct ieee80211_channel *, 99 struct ieee80211_channel *); 100 101 102 int 103 ar9285_attach(struct athn_softc *sc) 104 { 105 sc->eep_base = AR9285_EEP_START_LOC; 106 sc->eep_size = sizeof(struct ar9285_eeprom); 107 sc->ngpiopins = (sc->flags & ATHN_FLAG_USB) ? 16 : 12; 108 sc->led_pin = (sc->flags & ATHN_FLAG_USB) ? 15 : 1; 109 sc->workaround = AR9285_WA_DEFAULT; 110 sc->ops.setup = ar9285_setup; 111 sc->ops.swap_rom = ar9285_swap_rom; 112 sc->ops.init_from_rom = ar9285_init_from_rom; 113 sc->ops.set_txpower = ar9285_set_txpower; 114 sc->ops.set_synth = ar9280_set_synth; 115 sc->ops.spur_mitigate = ar9280_spur_mitigate; 116 sc->ops.get_spur_chans = ar9285_get_spur_chans; 117 #if NATHN_USB > 0 118 if (AR_SREV_9271(sc)) { 119 sc->cca_min_2g = AR9271_PHY_CCA_MIN_GOOD_VAL_2GHZ; 120 sc->cca_max_2g = AR9271_PHY_CCA_MAX_GOOD_VAL_2GHZ; 121 } else 122 #endif 123 { 124 sc->cca_min_2g = AR9285_PHY_CCA_MIN_GOOD_VAL_2GHZ; 125 sc->cca_max_2g = AR9285_PHY_CCA_MAX_GOOD_VAL_2GHZ; 126 } 127 #if NATHN_USB > 0 128 if (AR_SREV_9271(sc)) 129 sc->ini = &ar9271_ini; 130 else 131 #endif 132 sc->ini = &ar9285_1_2_ini; 133 sc->serdes = &ar9280_2_0_serdes; 134 135 return (ar5008_attach(sc)); 136 } 137 138 void 139 ar9285_setup(struct athn_softc *sc) 140 { 141 const struct ar9285_eeprom *eep = sc->eep; 142 uint8_t type; 143 144 /* Select initialization values based on ROM. */ 145 type = eep->baseEepHeader.txGainType; 146 DPRINTF(("Tx gain type=0x%x\n", type)); 147 #if NATHN_USB > 0 148 if (AR_SREV_9271(sc)) { 149 if (type == AR_EEP_TXGAIN_HIGH_POWER) 150 sc->tx_gain = &ar9271_tx_gain_high_power; 151 else 152 sc->tx_gain = &ar9271_tx_gain; 153 } else 154 #endif /* NATHN_USB */ 155 if ((AR_READ(sc, AR_AN_SYNTH9) & 0x7) == 0x1) { /* XE rev. */ 156 if (type == AR_EEP_TXGAIN_HIGH_POWER) 157 sc->tx_gain = &ar9285_2_0_tx_gain_high_power; 158 else 159 sc->tx_gain = &ar9285_2_0_tx_gain; 160 } else { 161 if (type == AR_EEP_TXGAIN_HIGH_POWER) 162 sc->tx_gain = &ar9285_1_2_tx_gain_high_power; 163 else 164 sc->tx_gain = &ar9285_1_2_tx_gain; 165 } 166 } 167 168 void 169 ar9285_swap_rom(struct athn_softc *sc) 170 { 171 struct ar9285_eeprom *eep = sc->eep; 172 int i; 173 174 eep->modalHeader.antCtrlCommon = 175 swap32(eep->modalHeader.antCtrlCommon); 176 eep->modalHeader.antCtrlChain = 177 swap32(eep->modalHeader.antCtrlChain); 178 179 for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { 180 eep->modalHeader.spurChans[i].spurChan = 181 swap16(eep->modalHeader.spurChans[i].spurChan); 182 } 183 } 184 185 const struct ar_spur_chan * 186 ar9285_get_spur_chans(struct athn_softc *sc, int is2ghz) 187 { 188 const struct ar9285_eeprom *eep = sc->eep; 189 190 KASSERT(is2ghz); 191 return (eep->modalHeader.spurChans); 192 } 193 194 void 195 ar9285_init_from_rom(struct athn_softc *sc, struct ieee80211_channel *c, 196 struct ieee80211_channel *extc) 197 { 198 const struct ar9285_eeprom *eep = sc->eep; 199 const struct ar9285_modal_eep_header *modal = &eep->modalHeader; 200 uint32_t reg, offset = 0x1000; 201 uint8_t ob[5], db1[5], db2[5]; 202 uint8_t txRxAtten; 203 204 AR_WRITE(sc, AR_PHY_SWITCH_COM, modal->antCtrlCommon); 205 AR_WRITE(sc, AR_PHY_SWITCH_CHAIN_0, modal->antCtrlChain); 206 207 reg = AR_READ(sc, AR_PHY_TIMING_CTRL4_0); 208 reg = RW(reg, AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, modal->iqCalI); 209 reg = RW(reg, AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, modal->iqCalQ); 210 AR_WRITE(sc, AR_PHY_TIMING_CTRL4_0, reg); 211 212 if (sc->eep_rev >= AR_EEP_MINOR_VER_3) { 213 reg = AR_READ(sc, AR_PHY_GAIN_2GHZ); 214 reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, 215 modal->bswMargin); 216 reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN1_DB, 217 modal->bswAtten); 218 reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, 219 modal->xatten2Margin); 220 reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN2_DB, 221 modal->xatten2Db); 222 AR_WRITE(sc, AR_PHY_GAIN_2GHZ, reg); 223 224 /* Duplicate values of chain 0 for chain 1. */ 225 reg = AR_READ(sc, AR_PHY_GAIN_2GHZ + offset); 226 reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, 227 modal->bswMargin); 228 reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN1_DB, 229 modal->bswAtten); 230 reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, 231 modal->xatten2Margin); 232 reg = RW(reg, AR_PHY_GAIN_2GHZ_XATTEN2_DB, 233 modal->xatten2Db); 234 AR_WRITE(sc, AR_PHY_GAIN_2GHZ + offset, reg); 235 } 236 if (sc->eep_rev >= AR_EEP_MINOR_VER_3) 237 txRxAtten = modal->txRxAtten; 238 else /* Workaround for ROM versions < 14.3. */ 239 txRxAtten = 23; 240 reg = AR_READ(sc, AR_PHY_RXGAIN); 241 reg = RW(reg, AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAtten); 242 reg = RW(reg, AR9280_PHY_RXGAIN_TXRX_MARGIN, modal->rxTxMargin); 243 AR_WRITE(sc, AR_PHY_RXGAIN, reg); 244 245 /* Duplicate values of chain 0 for chain 1. */ 246 reg = AR_READ(sc, AR_PHY_RXGAIN + offset); 247 reg = RW(reg, AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAtten); 248 reg = RW(reg, AR9280_PHY_RXGAIN_TXRX_MARGIN, modal->rxTxMargin); 249 AR_WRITE(sc, AR_PHY_RXGAIN + offset, reg); 250 251 if (modal->version >= 3) { 252 /* Setup antenna diversity from ROM. */ 253 reg = AR_READ(sc, AR_PHY_MULTICHAIN_GAIN_CTL); 254 reg = RW(reg, AR9285_PHY_ANT_DIV_CTL_ALL, 0); 255 reg = RW(reg, AR9285_PHY_ANT_DIV_CTL, 256 (modal->ob_234 >> 12) & 0x1); 257 reg = RW(reg, AR9285_PHY_ANT_DIV_ALT_LNACONF, 258 (modal->db1_234 >> 12) & 0x3); 259 reg = RW(reg, AR9285_PHY_ANT_DIV_MAIN_LNACONF, 260 (modal->db1_234 >> 14) & 0x3); 261 reg = RW(reg, AR9285_PHY_ANT_DIV_ALT_GAINTB, 262 (modal->ob_234 >> 13) & 0x1); 263 reg = RW(reg, AR9285_PHY_ANT_DIV_MAIN_GAINTB, 264 (modal->ob_234 >> 14) & 0x1); 265 AR_WRITE(sc, AR_PHY_MULTICHAIN_GAIN_CTL, reg); 266 reg = AR_READ(sc, AR_PHY_MULTICHAIN_GAIN_CTL); /* Flush. */ 267 268 reg = AR_READ(sc, AR_PHY_CCK_DETECT); 269 if (modal->ob_234 & (1 << 15)) 270 reg |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; 271 else 272 reg &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; 273 AR_WRITE(sc, AR_PHY_CCK_DETECT, reg); 274 reg = AR_READ(sc, AR_PHY_CCK_DETECT); /* Flush. */ 275 } 276 if (modal->version >= 2) { 277 ob [0] = (modal->ob_01 >> 0) & 0xf; 278 ob [1] = (modal->ob_01 >> 4) & 0xf; 279 ob [2] = (modal->ob_234 >> 0) & 0xf; 280 ob [3] = (modal->ob_234 >> 4) & 0xf; 281 ob [4] = (modal->ob_234 >> 8) & 0xf; 282 283 db1[0] = (modal->db1_01 >> 0) & 0xf; 284 db1[1] = (modal->db1_01 >> 4) & 0xf; 285 db1[2] = (modal->db1_234 >> 0) & 0xf; 286 db1[3] = (modal->db1_234 >> 4) & 0xf; 287 db1[4] = (modal->db1_234 >> 8) & 0xf; 288 289 db2[0] = (modal->db2_01 >> 0) & 0xf; 290 db2[1] = (modal->db2_01 >> 4) & 0xf; 291 db2[2] = (modal->db2_234 >> 0) & 0xf; 292 db2[3] = (modal->db2_234 >> 4) & 0xf; 293 db2[4] = (modal->db2_234 >> 8) & 0xf; 294 295 } else if (modal->version == 1) { 296 ob [0] = (modal->ob_01 >> 0) & 0xf; 297 ob [1] = (modal->ob_01 >> 4) & 0xf; 298 /* Field ob_234 does not exist, use ob_01. */ 299 ob [2] = ob [3] = ob [4] = ob [1]; 300 301 db1[0] = (modal->db1_01 >> 0) & 0xf; 302 db1[1] = (modal->db1_01 >> 4) & 0xf; 303 /* Field db1_234 does not exist, use db1_01. */ 304 db1[2] = db1[3] = db1[4] = db1[1]; 305 306 db2[0] = (modal->db2_01 >> 0) & 0xf; 307 db2[1] = (modal->db2_01 >> 4) & 0xf; 308 /* Field db2_234 does not exist, use db2_01. */ 309 db2[2] = db2[3] = db2[4] = db2[1]; 310 311 } else { 312 ob [0] = modal->ob_01; 313 ob [1] = ob [2] = ob [3] = ob [4] = ob [0]; 314 315 db1[0] = modal->db1_01; 316 db1[1] = db1[2] = db1[3] = db1[4] = db1[0]; 317 318 /* Field db2_01 does not exist, use db1_01. */ 319 db2[0] = modal->db1_01; 320 db2[1] = db2[2] = db2[3] = db2[4] = db2[0]; 321 } 322 #if NATHN_USB > 0 323 if (AR_SREV_9271(sc)) { 324 reg = AR_READ(sc, AR9285_AN_RF2G3); 325 reg = RW(reg, AR9271_AN_RF2G3_OB_CCK, ob [0]); 326 reg = RW(reg, AR9271_AN_RF2G3_OB_PSK, ob [1]); 327 reg = RW(reg, AR9271_AN_RF2G3_OB_QAM, ob [2]); 328 reg = RW(reg, AR9271_AN_RF2G3_DB1, db1[0]); 329 AR_WRITE(sc, AR9285_AN_RF2G3, reg); 330 AR_WRITE_BARRIER(sc); 331 DELAY(100); 332 reg = AR_READ(sc, AR9285_AN_RF2G4); 333 reg = RW(reg, AR9271_AN_RF2G4_DB2, db2[0]); 334 AR_WRITE(sc, AR9285_AN_RF2G4, reg); 335 AR_WRITE_BARRIER(sc); 336 DELAY(100); 337 } else 338 #endif /* ATHN_USB */ 339 { 340 reg = AR_READ(sc, AR9285_AN_RF2G3); 341 reg = RW(reg, AR9285_AN_RF2G3_OB_0, ob [0]); 342 reg = RW(reg, AR9285_AN_RF2G3_OB_1, ob [1]); 343 reg = RW(reg, AR9285_AN_RF2G3_OB_2, ob [2]); 344 reg = RW(reg, AR9285_AN_RF2G3_OB_3, ob [3]); 345 reg = RW(reg, AR9285_AN_RF2G3_OB_4, ob [4]); 346 reg = RW(reg, AR9285_AN_RF2G3_DB1_0, db1[0]); 347 reg = RW(reg, AR9285_AN_RF2G3_DB1_1, db1[1]); 348 reg = RW(reg, AR9285_AN_RF2G3_DB1_2, db1[2]); 349 AR_WRITE(sc, AR9285_AN_RF2G3, reg); 350 AR_WRITE_BARRIER(sc); 351 DELAY(100); 352 reg = AR_READ(sc, AR9285_AN_RF2G4); 353 reg = RW(reg, AR9285_AN_RF2G4_DB1_3, db1[3]); 354 reg = RW(reg, AR9285_AN_RF2G4_DB1_4, db1[4]); 355 reg = RW(reg, AR9285_AN_RF2G4_DB2_0, db2[0]); 356 reg = RW(reg, AR9285_AN_RF2G4_DB2_1, db2[1]); 357 reg = RW(reg, AR9285_AN_RF2G4_DB2_2, db2[2]); 358 reg = RW(reg, AR9285_AN_RF2G4_DB2_3, db2[3]); 359 reg = RW(reg, AR9285_AN_RF2G4_DB2_4, db2[4]); 360 AR_WRITE(sc, AR9285_AN_RF2G4, reg); 361 AR_WRITE_BARRIER(sc); 362 DELAY(100); 363 } 364 365 reg = AR_READ(sc, AR_PHY_SETTLING); 366 reg = RW(reg, AR_PHY_SETTLING_SWITCH, modal->switchSettling); 367 AR_WRITE(sc, AR_PHY_SETTLING, reg); 368 369 reg = AR_READ(sc, AR_PHY_DESIRED_SZ); 370 reg = RW(reg, AR_PHY_DESIRED_SZ_ADC, modal->adcDesiredSize); 371 AR_WRITE(sc, AR_PHY_DESIRED_SZ, reg); 372 373 reg = SM(AR_PHY_RF_CTL4_TX_END_XPAA_OFF, modal->txEndToXpaOff); 374 reg |= SM(AR_PHY_RF_CTL4_TX_END_XPAB_OFF, modal->txEndToXpaOff); 375 reg |= SM(AR_PHY_RF_CTL4_FRAME_XPAA_ON, modal->txFrameToXpaOn); 376 reg |= SM(AR_PHY_RF_CTL4_FRAME_XPAB_ON, modal->txFrameToXpaOn); 377 AR_WRITE(sc, AR_PHY_RF_CTL4, reg); 378 379 reg = AR_READ(sc, AR_PHY_RF_CTL3); 380 reg = RW(reg, AR_PHY_TX_END_TO_A2_RX_ON, modal->txEndToRxOn); 381 AR_WRITE(sc, AR_PHY_RF_CTL3, reg); 382 383 reg = AR_READ(sc, AR_PHY_CCA(0)); 384 reg = RW(reg, AR9280_PHY_CCA_THRESH62, modal->thresh62); 385 AR_WRITE(sc, AR_PHY_CCA(0), reg); 386 387 reg = AR_READ(sc, AR_PHY_EXT_CCA0); 388 reg = RW(reg, AR_PHY_EXT_CCA0_THRESH62, modal->thresh62); 389 AR_WRITE(sc, AR_PHY_EXT_CCA0, reg); 390 391 if (sc->eep_rev >= AR_EEP_MINOR_VER_2) { 392 reg = AR_READ(sc, AR_PHY_RF_CTL2); 393 reg = RW(reg, AR_PHY_TX_END_PA_ON, 394 modal->txFrameToPaOn); 395 reg = RW(reg, AR_PHY_TX_END_DATA_START, 396 modal->txFrameToDataStart); 397 AR_WRITE(sc, AR_PHY_RF_CTL2, reg); 398 } 399 if (sc->eep_rev >= AR_EEP_MINOR_VER_3 && extc != NULL) { 400 reg = AR_READ(sc, AR_PHY_SETTLING); 401 reg = RW(reg, AR_PHY_SETTLING_SWITCH, modal->swSettleHt40); 402 AR_WRITE(sc, AR_PHY_SETTLING, reg); 403 } 404 AR_WRITE_BARRIER(sc); 405 } 406 407 void 408 ar9285_pa_calib(struct athn_softc *sc) 409 { 410 /* List of registers that need to be saved/restored. */ 411 static const uint16_t regs[] = { 412 AR9285_AN_TOP3, 413 AR9285_AN_RXTXBB1, 414 AR9285_AN_RF2G1, 415 AR9285_AN_RF2G2, 416 AR9285_AN_TOP2, 417 AR9285_AN_RF2G8, 418 AR9285_AN_RF2G7 419 }; 420 uint32_t svg[7], reg, ccomp_svg; 421 int i; 422 423 /* No PA calibration needed for high power solutions. */ 424 if (AR_SREV_9285(sc) && 425 ((struct ar9285_base_eep_header *)sc->eep)->txGainType == 426 AR_EEP_TXGAIN_HIGH_POWER) /* XXX AR9287? */ 427 return; 428 429 /* Save registers. */ 430 for (i = 0; i < nitems(regs); i++) 431 svg[i] = AR_READ(sc, regs[i]); 432 433 AR_CLRBITS(sc, AR9285_AN_RF2G6, 1); 434 AR_SETBITS(sc, AR_PHY(2), 1 << 27); 435 436 AR_SETBITS(sc, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC); 437 AR_SETBITS(sc, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1); 438 AR_SETBITS(sc, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I); 439 AR_SETBITS(sc, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF); 440 AR_CLRBITS(sc, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL); 441 AR_CLRBITS(sc, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB); 442 AR_CLRBITS(sc, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL); 443 /* Power down PA drivers. */ 444 AR_CLRBITS(sc, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1); 445 AR_CLRBITS(sc, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2); 446 AR_CLRBITS(sc, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT); 447 448 reg = AR_READ(sc, AR9285_AN_RF2G8); 449 reg = RW(reg, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); 450 AR_WRITE(sc, AR9285_AN_RF2G8, reg); 451 452 reg = AR_READ(sc, AR9285_AN_RF2G7); 453 reg = RW(reg, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); 454 AR_WRITE(sc, AR9285_AN_RF2G7, reg); 455 456 reg = AR_READ(sc, AR9285_AN_RF2G6); 457 /* Save compensation capacitor value. */ 458 ccomp_svg = MS(reg, AR9285_AN_RF2G6_CCOMP); 459 /* Program compensation capacitor for dynamic PA. */ 460 reg = RW(reg, AR9285_AN_RF2G6_CCOMP, 0xf); 461 AR_WRITE(sc, AR9285_AN_RF2G6, reg); 462 463 AR_WRITE(sc, AR9285_AN_TOP2, AR9285_AN_TOP2_DEFAULT); 464 AR_WRITE_BARRIER(sc); 465 DELAY(30); 466 467 /* Clear offsets 6-1. */ 468 AR_CLRBITS(sc, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS_6_1); 469 /* Clear offset 0. */ 470 AR_CLRBITS(sc, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP); 471 /* Set offsets 6-1. */ 472 for (i = 6; i >= 1; i--) { 473 AR_SETBITS(sc, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS(i)); 474 AR_WRITE_BARRIER(sc); 475 DELAY(1); 476 if (AR_READ(sc, AR9285_AN_RF2G9) & AR9285_AN_RXTXBB1_SPARE9) { 477 AR_SETBITS(sc, AR9285_AN_RF2G6, 478 AR9285_AN_RF2G6_OFFS(i)); 479 } else { 480 AR_CLRBITS(sc, AR9285_AN_RF2G6, 481 AR9285_AN_RF2G6_OFFS(i)); 482 } 483 } 484 /* Set offset 0. */ 485 AR_SETBITS(sc, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP); 486 AR_WRITE_BARRIER(sc); 487 DELAY(1); 488 if (AR_READ(sc, AR9285_AN_RF2G9) & AR9285_AN_RXTXBB1_SPARE9) 489 AR_SETBITS(sc, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP); 490 else 491 AR_CLRBITS(sc, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP); 492 493 AR_WRITE_BARRIER(sc); 494 495 AR_SETBITS(sc, AR9285_AN_RF2G6, 1); 496 AR_CLRBITS(sc, AR_PHY(2), 1 << 27); 497 498 /* Restore registers. */ 499 for (i = 0; i < nitems(regs); i++) 500 AR_WRITE(sc, regs[i], svg[i]); 501 502 /* Restore compensation capacitor value. */ 503 reg = AR_READ(sc, AR9285_AN_RF2G6); 504 reg = RW(reg, AR9285_AN_RF2G6_CCOMP, ccomp_svg); 505 AR_WRITE(sc, AR9285_AN_RF2G6, reg); 506 AR_WRITE_BARRIER(sc); 507 } 508 509 void 510 ar9271_pa_calib(struct athn_softc *sc) 511 { 512 #if NATHN_USB > 0 513 /* List of registers that need to be saved/restored. */ 514 static const uint16_t regs[] = { 515 AR9285_AN_TOP3, 516 AR9285_AN_RXTXBB1, 517 AR9285_AN_RF2G1, 518 AR9285_AN_RF2G2, 519 AR9285_AN_TOP2, 520 AR9285_AN_RF2G8, 521 AR9285_AN_RF2G7 522 }; 523 uint32_t svg[7], reg, rf2g3_svg; 524 int i; 525 526 /* Save registers. */ 527 for (i = 0; i < nitems(regs); i++) 528 svg[i] = AR_READ(sc, regs[i]); 529 530 AR_CLRBITS(sc, AR9285_AN_RF2G6, 1); 531 AR_SETBITS(sc, AR_PHY(2), 1 << 27); 532 533 AR_SETBITS(sc, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC); 534 AR_SETBITS(sc, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1); 535 AR_SETBITS(sc, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I); 536 AR_SETBITS(sc, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF); 537 AR_CLRBITS(sc, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL); 538 AR_CLRBITS(sc, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB); 539 AR_CLRBITS(sc, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL); 540 /* Power down PA drivers. */ 541 AR_CLRBITS(sc, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1); 542 AR_CLRBITS(sc, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2); 543 AR_CLRBITS(sc, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT); 544 545 reg = AR_READ(sc, AR9285_AN_RF2G8); 546 reg = RW(reg, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); 547 AR_WRITE(sc, AR9285_AN_RF2G8, reg); 548 549 reg = AR_READ(sc, AR9285_AN_RF2G7); 550 reg = RW(reg, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); 551 AR_WRITE(sc, AR9285_AN_RF2G7, reg); 552 553 /* Save compensation capacitor value. */ 554 reg = rf2g3_svg = AR_READ(sc, AR9285_AN_RF2G3); 555 /* Program compensation capacitor for dynamic PA. */ 556 reg = RW(reg, AR9271_AN_RF2G3_CCOMP, 0xfff); 557 AR_WRITE(sc, AR9285_AN_RF2G3, reg); 558 559 AR_WRITE(sc, AR9285_AN_TOP2, AR9285_AN_TOP2_DEFAULT); 560 AR_WRITE_BARRIER(sc); 561 DELAY(30); 562 563 /* Clear offsets 6-0. */ 564 AR_CLRBITS(sc, AR9285_AN_RF2G6, AR9271_AN_RF2G6_OFFS_6_0); 565 /* Set offsets 6-1. */ 566 for (i = 6; i >= 1; i--) { 567 reg = AR_READ(sc, AR9285_AN_RF2G6); 568 reg |= AR9271_AN_RF2G6_OFFS(i); 569 AR_WRITE(sc, AR9285_AN_RF2G6, reg); 570 AR_WRITE_BARRIER(sc); 571 DELAY(1); 572 if (!(AR_READ(sc, AR9285_AN_RF2G9) & AR9285_AN_RXTXBB1_SPARE9)) 573 reg &= ~AR9271_AN_RF2G6_OFFS(i); 574 AR_WRITE(sc, AR9285_AN_RF2G6, reg); 575 } 576 AR_WRITE_BARRIER(sc); 577 578 AR_SETBITS(sc, AR9285_AN_RF2G6, 1); 579 AR_CLRBITS(sc, AR_PHY(2), 1 << 27); 580 581 /* Restore registers. */ 582 for (i = 0; i < nitems(regs); i++) 583 AR_WRITE(sc, regs[i], svg[i]); 584 585 /* Restore compensation capacitor value. */ 586 AR_WRITE(sc, AR9285_AN_RF2G3, rf2g3_svg); 587 AR_WRITE_BARRIER(sc); 588 #endif /* NATHN_USB */ 589 } 590 591 /* 592 * Carrier Leakage Calibration. 593 */ 594 int 595 ar9285_cl_cal(struct athn_softc *sc, struct ieee80211_channel *c, 596 struct ieee80211_channel *extc) 597 { 598 int ntries; 599 600 AR_SETBITS(sc, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 601 if (0 && extc == NULL) { /* XXX IS_CHAN_HT20!! */ 602 AR_SETBITS(sc, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); 603 AR_SETBITS(sc, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); 604 AR_CLRBITS(sc, AR_PHY_AGC_CONTROL, 605 AR_PHY_AGC_CONTROL_FLTR_CAL); 606 AR_CLRBITS(sc, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); 607 AR_SETBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); 608 for (ntries = 0; ntries < 10000; ntries++) { 609 if (!(AR_READ(sc, AR_PHY_AGC_CONTROL) & 610 AR_PHY_AGC_CONTROL_CAL)) 611 break; 612 DELAY(10); 613 } 614 if (ntries == 10000) 615 return (ETIMEDOUT); 616 AR_CLRBITS(sc, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN); 617 AR_CLRBITS(sc, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE); 618 AR_CLRBITS(sc, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 619 } 620 AR_CLRBITS(sc, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); 621 AR_SETBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); 622 AR_SETBITS(sc, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE); 623 AR_SETBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL); 624 for (ntries = 0; ntries < 10000; ntries++) { 625 if (!(AR_READ(sc, AR_PHY_AGC_CONTROL) & 626 AR_PHY_AGC_CONTROL_CAL)) 627 break; 628 DELAY(10); 629 } 630 if (ntries == 10000) 631 return (ETIMEDOUT); 632 AR_SETBITS(sc, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); 633 AR_CLRBITS(sc, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); 634 AR_CLRBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); 635 AR_WRITE_BARRIER(sc); 636 return (0); 637 } 638 639 void 640 ar9271_load_ani(struct athn_softc *sc) 641 { 642 #if NATHN_USB > 0 643 /* Write ANI registers. */ 644 AR_WRITE(sc, AR_PHY_DESIRED_SZ, 0x6d4000e2); 645 AR_WRITE(sc, AR_PHY_AGC_CTL1, 0x3139605e); 646 AR_WRITE(sc, AR_PHY_FIND_SIG, 0x7ec84d2e); 647 AR_WRITE(sc, AR_PHY_SFCORR_LOW, 0x06903881); 648 AR_WRITE(sc, AR_PHY_SFCORR, 0x5ac640d0); 649 AR_WRITE(sc, AR_PHY_CCK_DETECT, 0x803e68c8); 650 AR_WRITE(sc, AR_PHY_TIMING5, 0xd00a8007); 651 AR_WRITE(sc, AR_PHY_SFCORR_EXT, 0x05eea6d4); 652 AR_WRITE_BARRIER(sc); 653 #endif /* NATHN_USB */ 654 } 655 656 int 657 ar9285_init_calib(struct athn_softc *sc, struct ieee80211_channel *c, 658 struct ieee80211_channel *extc) 659 { 660 uint32_t reg, mask, clcgain, rf2g5_svg; 661 int i, maxgain, nclcs, thresh, error; 662 663 /* Do carrier leakage calibration. */ 664 if ((error = ar9285_cl_cal(sc, c, extc)) != 0) 665 return (error); 666 667 /* Workaround for high temperature is not applicable on AR9271. */ 668 if (AR_SREV_9271(sc)) 669 return (0); 670 671 mask = 0; 672 nclcs = 0; 673 reg = AR_READ(sc, AR_PHY_TX_PWRCTRL7); 674 maxgain = MS(reg, AR_PHY_TX_PWRCTRL_TX_GAIN_TAB_MAX); 675 for (i = 0; i <= maxgain; i++) { 676 reg = AR_READ(sc, AR_PHY_TX_GAIN_TBL(i)); 677 clcgain = MS(reg, AR_PHY_TX_GAIN_CLC); 678 /* NB: clcgain <= 0xf. */ 679 if (!(mask & (1 << clcgain))) { 680 mask |= 1 << clcgain; 681 nclcs++; 682 } 683 } 684 thresh = 0; 685 for (i = 0; i < nclcs; i++) { 686 reg = AR_READ(sc, AR_PHY_CLC_TBL(i)); 687 if (MS(reg, AR_PHY_CLC_I0) == 0) 688 thresh++; 689 if (MS(reg, AR_PHY_CLC_Q0) == 0) 690 thresh++; 691 } 692 if (thresh <= AR9285_CL_CAL_REDO_THRESH) 693 return (0); /* No need to redo. */ 694 695 /* Threshold reached, redo carrier leakage calibration. */ 696 DPRINTFN(2, ("CLC threshold=%d\n", thresh)); 697 rf2g5_svg = reg = AR_READ(sc, AR9285_AN_RF2G5); 698 if ((AR_READ(sc, AR_AN_SYNTH9) & 0x7) == 0x1) /* XE rev. */ 699 reg = RW(reg, AR9285_AN_RF2G5_IC50TX, 0x5); 700 else 701 reg = RW(reg, AR9285_AN_RF2G5_IC50TX, 0x4); 702 AR_WRITE(sc, AR9285_AN_RF2G5, reg); 703 AR_WRITE_BARRIER(sc); 704 error = ar9285_cl_cal(sc, c, extc); 705 AR_WRITE(sc, AR9285_AN_RF2G5, rf2g5_svg); 706 AR_WRITE_BARRIER(sc); 707 return (error); 708 } 709 710 void 711 ar9285_get_pdadcs(struct athn_softc *sc, struct ieee80211_channel *c, 712 int nxpdgains, uint8_t overlap, uint8_t *boundaries, uint8_t *pdadcs) 713 { 714 const struct ar9285_eeprom *eep = sc->eep; 715 const struct ar9285_cal_data_per_freq *pierdata; 716 const uint8_t *pierfreq; 717 struct athn_pier lopier, hipier; 718 uint8_t fbin; 719 int i, lo, hi, npiers; 720 721 pierfreq = eep->calFreqPier2G; 722 pierdata = eep->calPierData2G; 723 npiers = AR9285_NUM_2G_CAL_PIERS; 724 725 /* Find channel in ROM pier table. */ 726 fbin = athn_chan2fbin(c); 727 athn_get_pier_ival(fbin, pierfreq, npiers, &lo, &hi); 728 729 lopier.fbin = pierfreq[lo]; 730 hipier.fbin = pierfreq[hi]; 731 for (i = 0; i < nxpdgains; i++) { 732 lopier.pwr[i] = pierdata[lo].pwrPdg[i]; 733 lopier.vpd[i] = pierdata[lo].vpdPdg[i]; 734 hipier.pwr[i] = pierdata[lo].pwrPdg[i]; 735 hipier.vpd[i] = pierdata[lo].vpdPdg[i]; 736 } 737 ar5008_get_pdadcs(sc, fbin, &lopier, &hipier, nxpdgains, 738 AR9285_PD_GAIN_ICEPTS, overlap, boundaries, pdadcs); 739 } 740 741 void 742 ar9285_set_power_calib(struct athn_softc *sc, struct ieee80211_channel *c) 743 { 744 const struct ar9285_eeprom *eep = sc->eep; 745 uint8_t boundaries[AR_PD_GAINS_IN_MASK]; 746 uint8_t pdadcs[AR_NUM_PDADC_VALUES]; 747 uint8_t xpdgains[AR9285_NUM_PD_GAINS]; 748 uint8_t overlap; 749 uint32_t reg; 750 int i, nxpdgains; 751 752 if (sc->eep_rev < AR_EEP_MINOR_VER_2) { 753 overlap = MS(AR_READ(sc, AR_PHY_TPCRG5), 754 AR_PHY_TPCRG5_PD_GAIN_OVERLAP); 755 } else 756 overlap = eep->modalHeader.pdGainOverlap; 757 758 nxpdgains = 0; 759 memset(xpdgains, 0, sizeof(xpdgains)); 760 for (i = AR9285_PD_GAINS_IN_MASK - 1; i >= 0; i--) { 761 if (nxpdgains >= AR9285_NUM_PD_GAINS) 762 break; 763 if (eep->modalHeader.xpdGain & (1 << i)) 764 xpdgains[nxpdgains++] = i; 765 } 766 reg = AR_READ(sc, AR_PHY_TPCRG1); 767 reg = RW(reg, AR_PHY_TPCRG1_NUM_PD_GAIN, nxpdgains - 1); 768 reg = RW(reg, AR_PHY_TPCRG1_PD_GAIN_1, xpdgains[0]); 769 reg = RW(reg, AR_PHY_TPCRG1_PD_GAIN_2, xpdgains[1]); 770 AR_WRITE(sc, AR_PHY_TPCRG1, reg); 771 772 /* NB: No open loop power control for AR9285. */ 773 ar9285_get_pdadcs(sc, c, nxpdgains, overlap, boundaries, pdadcs); 774 775 /* Write boundaries. */ 776 reg = SM(AR_PHY_TPCRG5_PD_GAIN_OVERLAP, overlap); 777 reg |= SM(AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1, boundaries[0]); 778 reg |= SM(AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2, boundaries[1]); 779 reg |= SM(AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3, boundaries[2]); 780 reg |= SM(AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4, boundaries[3]); 781 AR_WRITE(sc, AR_PHY_TPCRG5, reg); 782 783 /* Write PDADC values. */ 784 for (i = 0; i < AR_NUM_PDADC_VALUES; i += 4) { 785 AR_WRITE(sc, AR_PHY_PDADC_TBL_BASE + i, 786 pdadcs[i + 0] << 0 | 787 pdadcs[i + 1] << 8 | 788 pdadcs[i + 2] << 16 | 789 pdadcs[i + 3] << 24); 790 } 791 AR_WRITE_BARRIER(sc); 792 } 793 794 void 795 ar9285_set_txpower(struct athn_softc *sc, struct ieee80211_channel *c, 796 struct ieee80211_channel *extc) 797 { 798 const struct ar9285_eeprom *eep = sc->eep; 799 const struct ar9285_modal_eep_header *modal = &eep->modalHeader; 800 uint8_t tpow_cck[4], tpow_ofdm[4]; 801 uint8_t tpow_cck_ext[4], tpow_ofdm_ext[4]; 802 uint8_t tpow_ht20[8], tpow_ht40[8]; 803 uint8_t ht40inc; 804 int16_t max_ant_gain, power[ATHN_POWER_COUNT]; 805 int i; 806 807 ar9285_set_power_calib(sc, c); 808 809 /* Compute transmit power reduction due to antenna gain. */ 810 max_ant_gain = modal->antennaGain; 811 /* XXX */ 812 813 /* Get CCK target powers. */ 814 ar5008_get_lg_tpow(sc, c, AR_CTL_11B, eep->calTargetPowerCck, 815 AR9285_NUM_2G_CCK_TARGET_POWERS, tpow_cck); 816 817 /* Get OFDM target powers. */ 818 ar5008_get_lg_tpow(sc, c, AR_CTL_11G, eep->calTargetPower2G, 819 AR9285_NUM_2G_20_TARGET_POWERS, tpow_ofdm); 820 821 /* Get HT-20 target powers. */ 822 ar5008_get_ht_tpow(sc, c, AR_CTL_2GHT20, eep->calTargetPower2GHT20, 823 AR9285_NUM_2G_20_TARGET_POWERS, tpow_ht20); 824 825 if (extc != NULL) { 826 /* Get HT-40 target powers. */ 827 ar5008_get_ht_tpow(sc, c, AR_CTL_2GHT40, 828 eep->calTargetPower2GHT40, AR9285_NUM_2G_40_TARGET_POWERS, 829 tpow_ht40); 830 831 /* Get secondary channel CCK target powers. */ 832 ar5008_get_lg_tpow(sc, extc, AR_CTL_11B, 833 eep->calTargetPowerCck, AR9285_NUM_2G_CCK_TARGET_POWERS, 834 tpow_cck_ext); 835 836 /* Get secondary channel OFDM target powers. */ 837 ar5008_get_lg_tpow(sc, extc, AR_CTL_11G, 838 eep->calTargetPower2G, AR9285_NUM_2G_20_TARGET_POWERS, 839 tpow_ofdm_ext); 840 } 841 842 memset(power, 0, sizeof(power)); 843 /* Shuffle target powers accross transmit rates. */ 844 power[ATHN_POWER_OFDM6 ] = 845 power[ATHN_POWER_OFDM9 ] = 846 power[ATHN_POWER_OFDM12 ] = 847 power[ATHN_POWER_OFDM18 ] = 848 power[ATHN_POWER_OFDM24 ] = tpow_ofdm[0]; 849 power[ATHN_POWER_OFDM36 ] = tpow_ofdm[1]; 850 power[ATHN_POWER_OFDM48 ] = tpow_ofdm[2]; 851 power[ATHN_POWER_OFDM54 ] = tpow_ofdm[3]; 852 power[ATHN_POWER_XR ] = tpow_ofdm[0]; 853 power[ATHN_POWER_CCK1_LP ] = tpow_cck[0]; 854 power[ATHN_POWER_CCK2_LP ] = 855 power[ATHN_POWER_CCK2_SP ] = tpow_cck[1]; 856 power[ATHN_POWER_CCK55_LP] = 857 power[ATHN_POWER_CCK55_SP] = tpow_cck[2]; 858 power[ATHN_POWER_CCK11_LP] = 859 power[ATHN_POWER_CCK11_SP] = tpow_cck[3]; 860 for (i = 0; i < nitems(tpow_ht20); i++) 861 power[ATHN_POWER_HT20(i)] = tpow_ht20[i]; 862 if (extc != NULL) { 863 /* Correct PAR difference between HT40 and HT20/Legacy. */ 864 if (sc->eep_rev >= AR_EEP_MINOR_VER_2) 865 ht40inc = modal->ht40PowerIncForPdadc; 866 else 867 ht40inc = AR_HT40_POWER_INC_FOR_PDADC; 868 for (i = 0; i < nitems(tpow_ht40); i++) 869 power[ATHN_POWER_HT40(i)] = tpow_ht40[i] + ht40inc; 870 power[ATHN_POWER_OFDM_DUP] = tpow_ht40[0]; 871 power[ATHN_POWER_CCK_DUP ] = tpow_ht40[0]; 872 power[ATHN_POWER_OFDM_EXT] = tpow_ofdm_ext[0]; 873 power[ATHN_POWER_CCK_EXT ] = tpow_cck_ext[0]; 874 } 875 876 for (i = 0; i < ATHN_POWER_COUNT; i++) { 877 power[i] -= AR_PWR_TABLE_OFFSET_DB * 2; /* In half dB. */ 878 if (power[i] > AR_MAX_RATE_POWER) 879 power[i] = AR_MAX_RATE_POWER; 880 } 881 882 /* Commit transmit power values to hardware. */ 883 ar5008_write_txpower(sc, power); 884 } 885