static void ar9280AdjustPDADCValues(struct ath_hal *ah, int8_t pwr_table_offset, int16_t diff, uint8_t *pdadcValues) { #define NUM_PDADC(diff) (AR5416_NUM_PDADC_VALUES - diff) uint16_t k; /* If this is a board that has a pwrTableOffset that differs from * the default AR5416_PWR_TABLE_OFFSET_DB then the start of the * pdadc vs pwr table needs to be adjusted prior to writing to the * chip. */ if (AR_SREV_MERLIN_20_OR_LATER(ah)) { if (AR5416_PWR_TABLE_OFFSET_DB != pwr_table_offset) { /* shift the table to start at the new offset */ for (k = 0; k < (uint16_t)NUM_PDADC(diff); k++ ) { pdadcValues[k] = pdadcValues[k + diff]; } /* fill the back of the table */ for (k = (uint16_t)NUM_PDADC(diff); k < NUM_PDADC(0); k++) { pdadcValues[k] = pdadcValues[NUM_PDADC(diff)]; } } } #undef NUM_PDADC }
static void ar9280WriteIni(struct ath_hal *ah, const struct ieee80211_channel *chan) { u_int modesIndex, freqIndex; int regWrites = 0; /* Setup the indices for the next set of register array writes */ /* XXX Ignore 11n dynamic mode on the AR5416 for the moment */ if (IEEE80211_IS_CHAN_2GHZ(chan)) { freqIndex = 2; if (IEEE80211_IS_CHAN_HT40(chan)) modesIndex = 3; else if (IEEE80211_IS_CHAN_108G(chan)) modesIndex = 5; else modesIndex = 4; } else { freqIndex = 1; if (IEEE80211_IS_CHAN_HT40(chan) || IEEE80211_IS_CHAN_TURBO(chan)) modesIndex = 2; else modesIndex = 1; } /* Set correct Baseband to analog shift setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); OS_REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); /* XXX Merlin ini fixups */ /* XXX Merlin 100us delay for shift registers */ regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_modes, modesIndex, regWrites); if (AR_SREV_MERLIN_20_OR_LATER(ah)) { regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_rxgain, modesIndex, regWrites); regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_txgain, modesIndex, regWrites); } /* XXX Merlin 100us delay for shift registers */ regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_common, 1, regWrites); if (AR_SREV_MERLIN_20(ah) && IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { /* 5GHz channels w/ Fast Clock use different modal values */ regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_xmodes, modesIndex, regWrites); } }
/* * Configure GPIO Output Mux control */ static void cfgOutputMux(struct ath_hal *ah, uint32_t gpio, uint32_t type) { int addr; uint32_t gpio_shift, tmp; HALDEBUG(ah, HAL_DEBUG_GPIO, "%s: gpio=%d, type=%d\n", __func__, gpio, type); /* each MUX controls 6 GPIO pins */ if (gpio > 11) addr = AR_GPIO_OUTPUT_MUX3; else if (gpio > 5) addr = AR_GPIO_OUTPUT_MUX2; else addr = AR_GPIO_OUTPUT_MUX1; /* * 5 bits per GPIO pin. Bits 0..4 for 1st pin in that mux, * bits 5..9 for 2nd pin, etc. */ gpio_shift = (gpio % 6) * 5; /* * From Owl to Merlin 1.0, the value read from MUX1 bit 4 to bit * 9 are wrong. Here is hardware's coding: * PRDATA[4:0] <= gpio_output_mux[0]; * PRDATA[9:4] <= gpio_output_mux[1]; * <==== Bit 4 is used by both gpio_output_mux[0] [1]. * Currently the max value for gpio_output_mux[] is 6. So bit 4 * will never be used. So it should be fine that bit 4 won't be * able to recover. */ if (AR_SREV_MERLIN_20_OR_LATER(ah) || (addr != AR_GPIO_OUTPUT_MUX1)) { OS_REG_RMW(ah, addr, (type << gpio_shift), (0x1f << gpio_shift)); } else { tmp = OS_REG_READ(ah, addr); tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0); tmp &= ~(0x1f << gpio_shift); tmp |= type << gpio_shift; OS_REG_WRITE(ah, addr, tmp); } }
/* * Configure GPIO Output Mux control */ static void ar5416GpioCfgOutputMux(struct ath_hal *ah, u_int32_t gpio, u_int32_t type) { int addr; u_int32_t gpio_shift, tmp; // each MUX controls 6 GPIO pins if (gpio > 11) { addr = AR_GPIO_OUTPUT_MUX3; } else if (gpio > 5) { addr = AR_GPIO_OUTPUT_MUX2; } else { addr = AR_GPIO_OUTPUT_MUX1; } // 5 bits per GPIO pin. Bits 0..4 for 1st pin in that mux, bits 5..9 for 2nd pin, etc. gpio_shift = (gpio % 6) * 5; /* * From Owl to Merlin 1.0, the value read from MUX1 bit 4 to bit 9 are wrong. * Here is hardware's coding: * PRDATA[4:0] <= gpio_output_mux[0]; * PRDATA[9:4] <= gpio_output_mux[1]; <==== Bit 4 is used by both gpio_output_mux[0] [1]. * Currently the max value for gpio_output_mux[] is 6. So bit 4 will never be used. * So it should be fine that bit 4 won't be able to recover. */ if (AR_SREV_MERLIN_20_OR_LATER(ah) || (addr != AR_GPIO_OUTPUT_MUX1)) { OS_REG_RMW(ah, addr, (type << gpio_shift), (0x1f << gpio_shift)); } else { tmp = OS_REG_READ(ah, addr); tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0); tmp &= ~(0x1f << gpio_shift); tmp |= (type << gpio_shift); OS_REG_WRITE(ah, addr, tmp); } }
/* * Configure GPIO Output Mux control */ static void cfgOutputMux(struct ath_hal *ah, uint32_t gpio, uint32_t type) { int addr; uint32_t gpio_shift, reg; /* each MUX controls 6 GPIO pins */ if (gpio > 11) addr = AR_GPIO_OUTPUT_MUX3; else if (gpio > 5) addr = AR_GPIO_OUTPUT_MUX2; else addr = AR_GPIO_OUTPUT_MUX1; /* * 5 bits per GPIO pin. Bits 0..4 for 1st pin in that mux, * bits 5..9 for 2nd pin, etc. */ gpio_shift = (gpio % 6) * 5; /* * From Owl to Merlin 1.0, the value read from MUX1 bit 4 to bit * 9 are wrong. Here is hardware's coding: * PRDATA[4:0] <= gpio_output_mux[0]; * PRDATA[9:4] <= gpio_output_mux[1]; * <==== Bit 4 is used by both gpio_output_mux[0] [1]. * Currently the max value for gpio_output_mux[] is 6. So bit 4 * will never be used. So it should be fine that bit 4 won't be * able to recover. */ reg = OS_REG_READ(ah, addr); if (addr == AR_GPIO_OUTPUT_MUX1 && !AR_SREV_MERLIN_20_OR_LATER(ah)) reg = ((reg & 0x1F0) << 1) | (reg & ~0x1F0); reg &= ~(0x1f << gpio_shift); reg |= type << gpio_shift; OS_REG_WRITE(ah, addr, reg); }
static int16_t ar9280ChangeGainBoundarySettings(struct ath_hal *ah, uint16_t *gb, uint16_t numXpdGain, uint16_t pdGainOverlap_t2, int8_t pwr_table_offset, int16_t *diff) { uint16_t k; /* Prior to writing the boundaries or the pdadc vs. power table * into the chip registers the default starting point on the pdadc * vs. power table needs to be checked and the curve boundaries * adjusted accordingly */ if (AR_SREV_MERLIN_20_OR_LATER(ah)) { uint16_t gb_limit; if (AR5416_PWR_TABLE_OFFSET_DB != pwr_table_offset) { /* get the difference in dB */ *diff = (uint16_t)(pwr_table_offset - AR5416_PWR_TABLE_OFFSET_DB); /* get the number of half dB steps */ *diff *= 2; /* change the original gain boundary settings * by the number of half dB steps */ for (k = 0; k < numXpdGain; k++) gb[k] = (uint16_t)(gb[k] - *diff); } /* Because of a hardware limitation, ensure the gain boundary * is not larger than (63 - overlap) */ gb_limit = (uint16_t)(AR5416_MAX_RATE_POWER - pdGainOverlap_t2); for (k = 0; k < numXpdGain; k++) gb[k] = (uint16_t)min(gb_limit, gb[k]); } return *diff; }
u_int32_t ar5416WowWakeUp(struct ath_hal *ah) { uint32_t wowStatus = 0; uint32_t val = 0, rval; /* * Read the WOW Status register to know the wakeup reason. */ rval = OS_REG_READ(ah, AR_WOW_PATTERN_REG); val = AR_WOW_STATUS(rval); /* * Mask only the WOW events that we have enabled. Sometimes, we have spurious * WOW events from the AR_WOW_PATTERN_REG register. This mask will clean it up. */ val &= AH_PRIVATE(ah)->ah_wow_event_mask; if (val) { if (val & AR_WOW_MAGIC_PAT_FOUND) { wowStatus |= AH_WOW_MAGIC_PATTERN_EN; } if (AR_WOW_PATTERN_FOUND(val)) { wowStatus |= AH_WOW_USER_PATTERN_EN; } if (val & AR_WOW_KEEP_ALIVE_FAIL) { wowStatus |= AH_WOW_LINK_CHANGE; } if (val & AR_WOW_BEACON_FAIL) { wowStatus |= AH_WOW_BEACON_MISS; } } /* * Set and clear WOW_PME_CLEAR registers for the chip to generate next wow signal. * Disable D3 before accessing other registers ? */ val = OS_REG_READ(ah, AR_PCIE_PM_CTRL); val &= ~AR_PMCTRL_PWR_STATE_D1D3; // Check the bit value 0x01000000 (7-10) ?? val |= AR_PMCTRL_WOW_PME_CLR; OS_REG_WRITE(ah, AR_PCIE_PM_CTRL, val); /* * Clear all events. */ OS_REG_WRITE(ah, AR_WOW_PATTERN_REG, AR_WOW_CLEAR_EVENTS(OS_REG_READ(ah, AR_WOW_PATTERN_REG))); /* * Tie reset register. * FIXME: Per David Quan not tieing it back might have some repurcussions. */ if (AR_SREV_MERLIN_10_OR_LATER(ah)) { OS_REG_WRITE(ah, AR_WA, OS_REG_READ(ah, AR_WA) | AR_WA_UNTIE_RESET_EN | AR_WA_POR_SHORT | AR_WA_RESET_EN); } /* Restore the Beacon Threshold to init value */ OS_REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); /* * Restore the way the PCI-E Reset, Power-On-Reset, external PCIE_POR_SHORT * pins are tied to its original value. Previously just before WOW sleep, * we untie the PCI-E Reset to our Chip's Power On Reset so that * any PCI-E reset from the bus will not reset our chip. */ if (AR_SREV_MERLIN_20_OR_LATER(ah) && (AH_PRIVATE(ah)->ah_is_pci_express == AH_TRUE)) { ar5416ConfigPciPowerSave(ah, 0, 0); } AH_PRIVATE(ah)->ah_wow_event_mask = 0; return (wowStatus); }
HAL_BOOL ar5416WowEnable(struct ath_hal *ah, u_int32_t pattern_enable, u_int32_t timeoutInSeconds, int clearbssid) { uint32_t init_val, val, rval=0; const int ka_delay = 4; /* Delay of 4 millisec between two KeepAlive's */ uint32_t wow_event_mask; /* * ah_wow_event_mask is a mask to the AR_WOW_PATTERN_REG register to indicate * which WOW events that we have enabled. The WOW Events are from the * pattern_enable in this function and pattern_count of ar5416WowApplyPattern() */ wow_event_mask = AH_PRIVATE(ah)->ah_wow_event_mask; /* * Untie Power-On-Reset from the PCI-E Reset. When we are in WOW sleep, * we do not want the Reset from the PCI-E to disturb our hw state. */ if (AR_SREV_MERLIN_20_OR_LATER(ah) && (AH_PRIVATE(ah)->ah_is_pci_express == AH_TRUE)) { /* * We need to untie the internal POR (power-on-reset) to the external * PCI-E reset. We also need to tie the PCI-E Phy reset to the PCI-E reset. */ u_int32_t wa_reg_val; if (AR_SREV_KITE(ah) || AR_SREV_KIWI(ah)) wa_reg_val = AR9285_WA_DEFAULT; else wa_reg_val = AR9280_WA_DEFAULT; /* * In Merlin and Kite, bit 14 in WA register (disable L1) should only * be set when device enters D3 and be cleared when device comes back to D0. */ if (AH_PRIVATE(ah)->ah_config.ath_hal_pcie_waen & AR_WA_D3_L1_DISABLE) wa_reg_val = wa_reg_val | AR_WA_D3_L1_DISABLE; wa_reg_val = wa_reg_val & ~(AR_WA_UNTIE_RESET_EN); wa_reg_val = wa_reg_val | AR_WA_RESET_EN | AR_WA_POR_SHORT; OS_REG_WRITE(ah, AR_WA, wa_reg_val); if (!AR_SREV_KITE(ah) || AR_SREV_KITE_12_OR_LATER(ah)) { /* s * For WOW sleep, we reprogram the SerDes so that the PLL and CHK REQ * are both enabled. This uses more power but the Maverick team reported * that otherwise, WOW sleep is unable and chip may disappears. */ ar928xConfigSerDes_WowSleep(ah); } } /* * Set the power states appropriately and enable pme. */ val = OS_REG_READ(ah, AR_PCIE_PM_CTRL); val |= AR_PMCTRL_HOST_PME_EN | \ AR_PMCTRL_PWR_PM_CTRL_ENA | AR_PMCTRL_AUX_PWR_DET; val &= ~AR_PMCTRL_WOW_PME_CLR; OS_REG_WRITE(ah, AR_PCIE_PM_CTRL, val); /* * Setup for for: * - beacon misses * - magic pattern * - keep alive timeout * - pattern matching */ /* * Program some default values for keep-alives, beacon misses, etc. */ init_val = OS_REG_READ(ah, AR_WOW_PATTERN_REG); val = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF) | init_val; OS_REG_WRITE(ah, AR_WOW_PATTERN_REG, val); rval = OS_REG_READ(ah, AR_WOW_PATTERN_REG); init_val = OS_REG_READ(ah, AR_WOW_COUNT_REG); val = AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) | \ AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) | \ AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT); OS_REG_WRITE(ah, AR_WOW_COUNT_REG, val); rval = OS_REG_READ(ah, AR_WOW_COUNT_REG); init_val = OS_REG_READ(ah, AR_WOW_BCN_TIMO_REG); if (pattern_enable & AH_WOW_BEACON_MISS) { val = AR_WOW_BEACON_TIMO; } else { /* We are not using the beacon miss. Program a large value. */ val = AR_WOW_BEACON_TIMO_MAX; } OS_REG_WRITE(ah, AR_WOW_BCN_TIMO_REG, val); rval = OS_REG_READ(ah, AR_WOW_BCN_TIMO_REG); init_val = OS_REG_READ(ah, AR_WOW_KEEP_ALIVE_TIMO_REG); /* * Keep Alive Timo in ms, except Merlin - see EV 62708 */ if (pattern_enable == 0 || AR_SREV_MERLIN(ah)) { val = AR_WOW_KEEP_ALIVE_NEVER; } else { val = AH_PRIVATE(ah)->ah_config.ath_hal_keep_alive_timeout * 32; } OS_REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO_REG, val); rval = OS_REG_READ(ah, AR_WOW_KEEP_ALIVE_TIMO_REG); init_val = OS_REG_READ(ah, AR_WOW_KEEP_ALIVE_DELAY_REG); /* * Keep Alive delay in us. Based on 'power on clock' , therefore in uSec */ val = ka_delay * 1000; OS_REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY_REG, val); rval = OS_REG_READ(ah, AR_WOW_KEEP_ALIVE_DELAY_REG); /* * Create KeepAlive Pattern to respond to beacons. */ ar5416WowCreateKeepAlivePattern(ah); /* * Configure Mac Wow Registers. */ val = OS_REG_READ(ah, AR_WOW_KEEP_ALIVE_REG); /* * Send keep alive timeouts anyway. */ val &= ~AR_WOW_KEEP_ALIVE_AUTO_DIS; if (pattern_enable & AH_WOW_LINK_CHANGE) { val &= ~ AR_WOW_KEEP_ALIVE_FAIL_DIS; wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL; } else { val |= AR_WOW_KEEP_ALIVE_FAIL_DIS; } OS_REG_WRITE(ah, AR_WOW_KEEP_ALIVE_REG, val); val = OS_REG_READ(ah, AR_WOW_KEEP_ALIVE_REG); val = OS_REG_READ(ah, AR_WOW_BCN_EN_REG); /* * We are relying on a bmiss failure. Ensure we have enough * threshold to prevent false positives. */ OS_REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, AR_WOW_BMISSTHRESHOLD); /* * Beacon miss & user pattern events are broken in Owl. * Enable only for Merlin. * The workaround is done at the ath_dev layer using the * sc->sc_wow_bmiss_intr field. * XXX: we need to cleanup this workaround before the next chip that * fixes this issue. */ if (!AR_SREV_MERLIN_10_OR_LATER(ah)) pattern_enable &= ~AH_WOW_BEACON_MISS; if (pattern_enable & AH_WOW_BEACON_MISS) { val |= AR_WOW_BEACON_FAIL_EN; wow_event_mask |= AR_WOW_BEACON_FAIL; } else { val &= ~AR_WOW_BEACON_FAIL_EN; } OS_REG_WRITE(ah, AR_WOW_BCN_EN_REG, val); val = OS_REG_READ(ah, AR_WOW_BCN_EN_REG); /* * Enable the magic packet registers. */ val = OS_REG_READ(ah, AR_WOW_PATTERN_REG); if (pattern_enable & AH_WOW_MAGIC_PATTERN_EN) { val |= AR_WOW_MAGIC_EN; wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND; } else { val &= ~AR_WOW_MAGIC_EN; } val |= AR_WOW_MAC_INTR_EN; OS_REG_WRITE(ah, AR_WOW_PATTERN_REG, val); val = OS_REG_READ(ah, AR_WOW_PATTERN_REG); /* For Kite and later version of the chips * enable wow pattern match for packets less than * 256 bytes for all patterns. */ if (AR_SREV_KITE_10_OR_LATER(ah)) { OS_REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B_REG, AR_WOW_PATTERN_SUPPORTED); } /* * Set the power states appropriately and enable pme. */ val = OS_REG_READ(ah, AR_PCIE_PM_CTRL); val |= AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN | AR_PMCTRL_PWR_PM_CTRL_ENA; OS_REG_WRITE(ah, AR_PCIE_PM_CTRL, val); if (timeoutInSeconds) { /* The clearbssid parameter is set only for the case where the wake needs to be on a timeout. The timeout mechanism, at this time, is specific to Maverick. For a manuf test, the system is put into sleep with a timer. On timer expiry, the chip interrupts(timer) and wakes the system. Clearbssid is specified as TRUE since we do not want a spurious beacon miss. If specified as true, we clear the bssid regs. */ // Setup the timer. OS_REG_WRITE(ah, AR_NEXT_NDP_TIMER, OS_REG_READ(ah, AR_TSF_L32) + timeoutInSeconds * 1000000 ); // convert Timeout to uSecs. OS_REG_WRITE(ah, AR_NDP_PERIOD, 30 * 1000000); // timer_period = 30 seconds always. OS_REG_WRITE(ah, AR_TIMER_MODE, OS_REG_READ(ah, AR_TIMER_MODE) | AR_NDP_TIMER_EN); // Enable the timer interrupt OS_REG_WRITE(ah, AR_IMR_S5, OS_REG_READ(ah, AR_IMR_S5) | AR_IMR_S5_GENTIMER7); OS_REG_WRITE(ah, AR_IMR, OS_REG_READ(ah, AR_IMR) | AR_IMR_GENTMR); if (clearbssid) { // If the bssid regs are set and all we want is a wake on timer, we run into an issue // with the wake coming in too early. OS_REG_WRITE(ah, AR_BSS_ID0, 0); OS_REG_WRITE(ah, AR_BSS_ID1, 0); } } /* * enable seq number generation in hw */ OS_REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM); ar5416SetPowerModeWowSleep(ah); AH_PRIVATE(ah)->ah_wow_event_mask = wow_event_mask; return (AH_TRUE); }
static void ar9280WriteIni(struct ath_hal *ah, const struct ieee80211_channel *chan) { u_int modesIndex, freqIndex; int regWrites = 0; int i; const HAL_INI_ARRAY *ia; /* Setup the indices for the next set of register array writes */ /* XXX Ignore 11n dynamic mode on the AR5416 for the moment */ if (IEEE80211_IS_CHAN_2GHZ(chan)) { freqIndex = 2; if (IEEE80211_IS_CHAN_HT40(chan)) modesIndex = 3; else if (IEEE80211_IS_CHAN_108G(chan)) modesIndex = 5; else modesIndex = 4; } else { freqIndex = 1; if (IEEE80211_IS_CHAN_HT40(chan) || IEEE80211_IS_CHAN_TURBO(chan)) modesIndex = 2; else modesIndex = 1; } /* Set correct Baseband to analog shift setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); OS_REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); /* * This is unwound because at the moment, there's a requirement * for Merlin (and later, perhaps) to have a specific bit fixed * in the AR_AN_TOP2 register before writing it. */ ia = &AH5212(ah)->ah_ini_modes; #if 0 regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_modes, modesIndex, regWrites); #endif HALASSERT(modesIndex < ia->cols); for (i = 0; i < ia->rows; i++) { uint32_t reg = HAL_INI_VAL(ia, i, 0); uint32_t val = HAL_INI_VAL(ia, i, modesIndex); if (reg == AR_AN_TOP2 && AH5416(ah)->ah_need_an_top2_fixup) val &= ~AR_AN_TOP2_PWDCLKIND; OS_REG_WRITE(ah, reg, val); /* Analog shift register delay seems needed for Merlin - PR kern/154220 */ if (reg >= 0x7800 && reg < 0x7900) OS_DELAY(100); DMA_YIELD(regWrites); } if (AR_SREV_MERLIN_20_OR_LATER(ah)) { regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_rxgain, modesIndex, regWrites); regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_txgain, modesIndex, regWrites); } /* XXX Merlin 100us delay for shift registers */ regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_common, 1, regWrites); if (AR_SREV_MERLIN_20(ah) && IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { /* 5GHz channels w/ Fast Clock use different modal values */ regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_xmodes, modesIndex, regWrites); } }
/* * Attach for an AR9280 part. */ static struct ath_hal * ar9280Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_STATUS *status) { struct ath_hal_9280 *ahp9280; struct ath_hal_5212 *ahp; struct ath_hal *ah; uint32_t val; HAL_STATUS ecode; HAL_BOOL rfStatus; int8_t pwr_table_offset; uint8_t pwr; HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ ahp9280 = ath_hal_malloc(sizeof (struct ath_hal_9280)); if (ahp9280 == AH_NULL) { HALDEBUG(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; } ahp = AH5212(ahp9280); ah = &ahp->ah_priv.h; ar5416InitState(AH5416(ah), devid, sc, st, sh, status); /* * Use the "local" EEPROM data given to us by the higher layers. * This is a private copy out of system flash. The Linux ath9k * commit for the initial AR9130 support mentions MMIO flash * access is "unreliable." -adrian */ if (eepromdata != AH_NULL) { AH_PRIVATE((ah))->ah_eepromRead = ath_hal_EepromDataRead; AH_PRIVATE((ah))->ah_eepromWrite = NULL; ah->ah_eepromdata = eepromdata; } /* XXX override with 9280 specific state */ /* override 5416 methods for our needs */ AH5416(ah)->ah_initPLL = ar9280InitPLL; ah->ah_setAntennaSwitch = ar9280SetAntennaSwitch; ah->ah_configPCIE = ar9280ConfigPCIE; AH5416(ah)->ah_cal.iqCalData.calData = &ar9280_iq_cal; AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9280_adc_gain_cal; AH5416(ah)->ah_cal.adcDcCalData.calData = &ar9280_adc_dc_cal; AH5416(ah)->ah_cal.adcDcCalInitData.calData = &ar9280_adc_init_dc_cal; AH5416(ah)->ah_cal.suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; AH5416(ah)->ah_spurMitigate = ar9280SpurMitigate; AH5416(ah)->ah_writeIni = ar9280WriteIni; AH5416(ah)->ah_olcInit = ar9280olcInit; AH5416(ah)->ah_olcTempCompensation = ar9280olcTemperatureCompensation; AH5416(ah)->ah_setPowerCalTable = ar9280SetPowerCalTable; AH5416(ah)->ah_rx_chainmask = AR9280_DEFAULT_RXCHAINMASK; AH5416(ah)->ah_tx_chainmask = AR9280_DEFAULT_TXCHAINMASK; if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n", __func__); ecode = HAL_EIO; goto bad; } if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't wakeup chip\n", __func__); ecode = HAL_EIO; goto bad; } /* Read Revisions from Chips before taking out of reset */ val = OS_REG_READ(ah, AR_SREV); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: ID 0x%x VERSION 0x%x TYPE 0x%x REVISION 0x%x\n", __func__, MS(val, AR_XSREV_ID), MS(val, AR_XSREV_VERSION), MS(val, AR_XSREV_TYPE), MS(val, AR_XSREV_REVISION)); /* NB: include chip type to differentiate from pre-Sowl versions */ AH_PRIVATE(ah)->ah_macVersion = (val & AR_XSREV_VERSION) >> AR_XSREV_TYPE_S; AH_PRIVATE(ah)->ah_macRev = MS(val, AR_XSREV_REVISION); AH_PRIVATE(ah)->ah_ispcie = (val & AR_XSREV_TYPE_HOST_MODE) == 0; /* setup common ini data; rf backends handle remainder */ if (AR_SREV_MERLIN_20_OR_LATER(ah)) { HAL_INI_INIT(&ahp->ah_ini_modes, ar9280Modes_v2, 6); HAL_INI_INIT(&ahp->ah_ini_common, ar9280Common_v2, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9280PciePhy_clkreq_always_on_L1_v2, 2); HAL_INI_INIT(&ahp9280->ah_ini_xmodes, ar9280Modes_fast_clock_v2, 3); } else { HAL_INI_INIT(&ahp->ah_ini_modes, ar9280Modes_v1, 6); HAL_INI_INIT(&ahp->ah_ini_common, ar9280Common_v1, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9280PciePhy_v1, 2); } ar5416AttachPCIE(ah); ecode = ath_hal_v14EepromAttach(ah); if (ecode != HAL_OK) goto bad; if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); ecode = HAL_EIO; goto bad; } AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); if (!ar5212ChipTest(ah)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n", __func__); ecode = HAL_ESELFTEST; goto bad; } /* * Set correct Baseband to analog shift * setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); /* Read Radio Chip Rev Extract */ AH_PRIVATE(ah)->ah_analog5GhzRev = ar5416GetRadioRev(ah); switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { case AR_RAD2133_SREV_MAJOR: /* Sowl: 2G/3x3 */ case AR_RAD5133_SREV_MAJOR: /* Sowl: 2+5G/3x3 */ break; default: if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { AH_PRIVATE(ah)->ah_analog5GhzRev = AR_RAD5133_SREV_MAJOR; break; } #ifdef AH_DEBUG HALDEBUG(ah, HAL_DEBUG_ANY, "%s: 5G Radio Chip Rev 0x%02X is not supported by " "this driver\n", __func__, AH_PRIVATE(ah)->ah_analog5GhzRev); ecode = HAL_ENOTSUPP; goto bad; #endif } rfStatus = ar9280RfAttach(ah, &ecode); if (!rfStatus) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n", __func__, ecode); goto bad; } /* Enable fixup for AR_AN_TOP2 if necessary */ /* * The v14 EEPROM layer returns HAL_EIO if PWDCLKIND isn't supported * by the EEPROM version. * * ath9k checks the EEPROM minor version is >= 0x0a here, instead of * the abstracted EEPROM access layer. */ ecode = ath_hal_eepromGet(ah, AR_EEP_PWDCLKIND, &pwr); if (AR_SREV_MERLIN_20_OR_LATER(ah) && ecode == HAL_OK && pwr == 0) { printf("[ath] enabling AN_TOP2_FIXUP\n"); AH5416(ah)->ah_need_an_top2_fixup = 1; } /* * Check whether the power table offset isn't the default. * This can occur with eeprom minor V21 or greater on Merlin. */ (void) ath_hal_eepromGet(ah, AR_EEP_PWR_TABLE_OFFSET, &pwr_table_offset); if (pwr_table_offset != AR5416_PWR_TABLE_OFFSET_DB) ath_hal_printf(ah, "[ath]: default pwr offset: %d dBm != EEPROM pwr offset: %d dBm; curves will be adjusted.\n", AR5416_PWR_TABLE_OFFSET_DB, (int) pwr_table_offset); /* XXX check for >= minor ver 17 */ if (AR_SREV_MERLIN_20(ah)) { /* setup rxgain table */ switch (ath_hal_eepromGet(ah, AR_EEP_RXGAIN_TYPE, AH_NULL)) { case AR5416_EEP_RXGAIN_13dB_BACKOFF: HAL_INI_INIT(&ahp9280->ah_ini_rxgain, ar9280Modes_backoff_13db_rxgain_v2, 6); break; case AR5416_EEP_RXGAIN_23dB_BACKOFF: HAL_INI_INIT(&ahp9280->ah_ini_rxgain, ar9280Modes_backoff_23db_rxgain_v2, 6); break; case AR5416_EEP_RXGAIN_ORIG: HAL_INI_INIT(&ahp9280->ah_ini_rxgain, ar9280Modes_original_rxgain_v2, 6); break; default: HALASSERT(AH_FALSE); goto bad; /* XXX ? try to continue */ } } /* XXX check for >= minor ver 19 */ if (AR_SREV_MERLIN_20(ah)) { /* setp txgain table */ switch (ath_hal_eepromGet(ah, AR_EEP_TXGAIN_TYPE, AH_NULL)) { case AR5416_EEP_TXGAIN_HIGH_POWER: HAL_INI_INIT(&ahp9280->ah_ini_txgain, ar9280Modes_high_power_tx_gain_v2, 6); break; case AR5416_EEP_TXGAIN_ORIG: HAL_INI_INIT(&ahp9280->ah_ini_txgain, ar9280Modes_original_tx_gain_v2, 6); break; default: HALASSERT(AH_FALSE); goto bad; /* XXX ? try to continue */ } } /* * Got everything we need now to setup the capabilities. */ if (!ar9280FillCapabilityInfo(ah)) { ecode = HAL_EEREAD; goto bad; } ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); if (ecode != HAL_OK) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error getting mac address from EEPROM\n", __func__); goto bad; } /* XXX How about the serial number ? */ /* Read Reg Domain */ AH_PRIVATE(ah)->ah_currentRD = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); AH_PRIVATE(ah)->ah_currentRDext = ath_hal_eepromGet(ah, AR_EEP_REGDMN_1, AH_NULL); /* * ah_miscMode is populated by ar5416FillCapabilityInfo() * starting from griffin. Set here to make sure that * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is * placed into hardware. */ if (ahp->ah_miscMode != 0) OS_REG_WRITE(ah, AR_MISC_MODE, OS_REG_READ(ah, AR_MISC_MODE) | ahp->ah_miscMode); ar9280AniSetup(ah); /* Anti Noise Immunity */ /* Setup noise floor min/max/nominal values */ AH5416(ah)->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9280_2GHZ; AH5416(ah)->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9280_2GHZ; AH5416(ah)->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9280_2GHZ; AH5416(ah)->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9280_5GHZ; AH5416(ah)->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9280_5GHZ; AH5416(ah)->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9280_5GHZ; ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__); return ah; bad: if (ah != AH_NULL) ah->ah_detach(ah); if (status) *status = ecode; return AH_NULL; }
/* * Attach for an AR9280 part. */ static struct ath_hal * ar9280Attach(uint16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status) { struct ath_hal_9280 *ahp9280; struct ath_hal_5212 *ahp; struct ath_hal *ah; uint32_t val; HAL_STATUS ecode; HAL_BOOL rfStatus; HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n", __func__, sc, (void*) st, (void*) sh); /* NB: memory is returned zero'd */ ahp9280 = ath_hal_malloc(sizeof (struct ath_hal_9280)); if (ahp9280 == AH_NULL) { HALDEBUG(AH_NULL, HAL_DEBUG_ANY, "%s: cannot allocate memory for state block\n", __func__); *status = HAL_ENOMEM; return AH_NULL; } ahp = AH5212(ahp9280); ah = &ahp->ah_priv.h; ar5416InitState(AH5416(ah), devid, sc, st, sh, status); /* XXX override with 9280 specific state */ /* override 5416 methods for our needs */ ah->ah_setAntennaSwitch = ar9280SetAntennaSwitch; ah->ah_configPCIE = ar9280ConfigPCIE; AH5416(ah)->ah_cal.iqCalData.calData = &ar9280_iq_cal; AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9280_adc_gain_cal; AH5416(ah)->ah_cal.adcDcCalData.calData = &ar9280_adc_dc_cal; AH5416(ah)->ah_cal.adcDcCalInitData.calData = &ar9280_adc_init_dc_cal; AH5416(ah)->ah_cal.suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; AH5416(ah)->ah_spurMitigate = ar9280SpurMitigate; AH5416(ah)->ah_writeIni = ar9280WriteIni; AH5416(ah)->ah_rx_chainmask = AR9280_DEFAULT_RXCHAINMASK; AH5416(ah)->ah_tx_chainmask = AR9280_DEFAULT_TXCHAINMASK; if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n", __func__); ecode = HAL_EIO; goto bad; } if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't wakeup chip\n", __func__); ecode = HAL_EIO; goto bad; } /* Read Revisions from Chips before taking out of reset */ val = OS_REG_READ(ah, AR_SREV); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: ID 0x%x VERSION 0x%x TYPE 0x%x REVISION 0x%x\n", __func__, MS(val, AR_XSREV_ID), MS(val, AR_XSREV_VERSION), MS(val, AR_XSREV_TYPE), MS(val, AR_XSREV_REVISION)); /* NB: include chip type to differentiate from pre-Sowl versions */ AH_PRIVATE(ah)->ah_macVersion = (val & AR_XSREV_VERSION) >> AR_XSREV_TYPE_S; AH_PRIVATE(ah)->ah_macRev = MS(val, AR_XSREV_REVISION); AH_PRIVATE(ah)->ah_ispcie = (val & AR_XSREV_TYPE_HOST_MODE) == 0; /* setup common ini data; rf backends handle remainder */ if (AR_SREV_MERLIN_20_OR_LATER(ah)) { HAL_INI_INIT(&ahp->ah_ini_modes, ar9280Modes_v2, 6); HAL_INI_INIT(&ahp->ah_ini_common, ar9280Common_v2, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9280PciePhy_clkreq_always_on_L1_v2, 2); HAL_INI_INIT(&ahp9280->ah_ini_xmodes, ar9280Modes_fast_clock_v2, 3); } else { HAL_INI_INIT(&ahp->ah_ini_modes, ar9280Modes_v1, 6); HAL_INI_INIT(&ahp->ah_ini_common, ar9280Common_v1, 2); HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, ar9280PciePhy_v1, 2); } ar5416AttachPCIE(ah); ecode = ath_hal_v14EepromAttach(ah); if (ecode != HAL_OK) goto bad; if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n", __func__); ecode = HAL_EIO; goto bad; } AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); if (!ar5212ChipTest(ah)) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n", __func__); ecode = HAL_ESELFTEST; goto bad; } /* * Set correct Baseband to analog shift * setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); /* Read Radio Chip Rev Extract */ AH_PRIVATE(ah)->ah_analog5GhzRev = ar5416GetRadioRev(ah); switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { case AR_RAD2133_SREV_MAJOR: /* Sowl: 2G/3x3 */ case AR_RAD5133_SREV_MAJOR: /* Sowl: 2+5G/3x3 */ break; default: if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { AH_PRIVATE(ah)->ah_analog5GhzRev = AR_RAD5133_SREV_MAJOR; break; } #ifdef AH_DEBUG HALDEBUG(ah, HAL_DEBUG_ANY, "%s: 5G Radio Chip Rev 0x%02X is not supported by " "this driver\n", __func__, AH_PRIVATE(ah)->ah_analog5GhzRev); ecode = HAL_ENOTSUPP; goto bad; #endif } rfStatus = ar9280RfAttach(ah, &ecode); if (!rfStatus) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n", __func__, ecode); goto bad; } if (AR_SREV_MERLIN_20_OR_LATER(ah)) { /* setup rxgain table */ switch (ath_hal_eepromGet(ah, AR_EEP_RXGAIN_TYPE, AH_NULL)) { case AR5416_EEP_RXGAIN_13dB_BACKOFF: HAL_INI_INIT(&ahp9280->ah_ini_rxgain, ar9280Modes_backoff_13db_rxgain_v2, 6); break; case AR5416_EEP_RXGAIN_23dB_BACKOFF: HAL_INI_INIT(&ahp9280->ah_ini_rxgain, ar9280Modes_backoff_23db_rxgain_v2, 6); break; case AR5416_EEP_RXGAIN_ORIG: HAL_INI_INIT(&ahp9280->ah_ini_rxgain, ar9280Modes_original_rxgain_v2, 6); break; default: HALASSERT(AH_FALSE); goto bad; /* XXX ? try to continue */ } } if (AR_SREV_MERLIN_20_OR_LATER(ah)) { /* setp txgain table */ switch (ath_hal_eepromGet(ah, AR_EEP_TXGAIN_TYPE, AH_NULL)) { case AR5416_EEP_TXGAIN_HIGH_POWER: HAL_INI_INIT(&ahp9280->ah_ini_txgain, ar9280Modes_high_power_tx_gain_v2, 6); break; case AR5416_EEP_TXGAIN_ORIG: HAL_INI_INIT(&ahp9280->ah_ini_txgain, ar9280Modes_original_tx_gain_v2, 6); break; default: HALASSERT(AH_FALSE); goto bad; /* XXX ? try to continue */ } } /* * Got everything we need now to setup the capabilities. */ if (!ar9280FillCapabilityInfo(ah)) { ecode = HAL_EEREAD; goto bad; } ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); if (ecode != HAL_OK) { HALDEBUG(ah, HAL_DEBUG_ANY, "%s: error getting mac address from EEPROM\n", __func__); goto bad; } /* XXX How about the serial number ? */ /* Read Reg Domain */ AH_PRIVATE(ah)->ah_currentRD = ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); /* * ah_miscMode is populated by ar5416FillCapabilityInfo() * starting from griffin. Set here to make sure that * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is * placed into hardware. */ if (ahp->ah_miscMode != 0) OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); ar9280AniSetup(ah); /* Anti Noise Immunity */ ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist); HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n", __func__); return ah; bad: if (ah != AH_NULL) ah->ah_detach(ah); if (status) *status = ecode; return AH_NULL; }
/************************************************************** * ar9280SetPowerCalTable * * Pull the PDADC piers from cal data and interpolate them across the given * points as well as from the nearest pier(s) to get a power detector * linear voltage to power level table. * * Handle OLC for Merlin where required. */ HAL_BOOL ar9280SetPowerCalTable(struct ath_hal *ah, struct ar5416eeprom *pEepData, const struct ieee80211_channel *chan, int16_t *pTxPowerIndexOffset) { CAL_DATA_PER_FREQ *pRawDataset; uint8_t *pCalBChans = AH_NULL; uint16_t pdGainOverlap_t2; static uint8_t pdadcValues[AR5416_NUM_PDADC_VALUES]; uint16_t gainBoundaries[AR5416_PD_GAINS_IN_MASK]; uint16_t numPiers, i; int16_t tMinCalPower; uint16_t numXpdGain, xpdMask; uint16_t xpdGainValues[AR5416_NUM_PD_GAINS]; uint32_t regChainOffset; int8_t pwr_table_offset; OS_MEMZERO(xpdGainValues, sizeof(xpdGainValues)); xpdMask = pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].xpdGain; (void) ath_hal_eepromGet(ah, AR_EEP_PWR_TABLE_OFFSET, &pwr_table_offset); if (IS_EEP_MINOR_V2(ah)) { pdGainOverlap_t2 = pEepData->modalHeader[IEEE80211_IS_CHAN_2GHZ(chan)].pdGainOverlap; } else { pdGainOverlap_t2 = (uint16_t)(MS(OS_REG_READ(ah, AR_PHY_TPCRG5), AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); } if (IEEE80211_IS_CHAN_2GHZ(chan)) { pCalBChans = pEepData->calFreqPier2G; numPiers = AR5416_NUM_2G_CAL_PIERS; } else { pCalBChans = pEepData->calFreqPier5G; numPiers = AR5416_NUM_5G_CAL_PIERS; } /* If OLC is being done, set the init PDADC value appropriately */ if (IEEE80211_IS_CHAN_2GHZ(chan) && AR_SREV_MERLIN_20_OR_LATER(ah) && ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) { struct calDataPerFreq *pRawDataset = pEepData->calPierData2G[0]; AH5416(ah)->initPDADC = ((struct calDataPerFreqOpLoop *) pRawDataset)->vpdPdg[0][0]; } else { /* * XXX ath9k doesn't clear this for 5ghz mode if * it were set in 2ghz mode before! * The Merlin OLC temperature compensation code * uses this to calculate the PDADC delta during * calibration ; 0 here effectively stops the * temperature compensation calibration from * occurring. */ AH5416(ah)->initPDADC = 0; } /* Calculate the value of xpdgains from the xpdGain Mask */ numXpdGain = ar5416GetXpdGainValues(ah, xpdMask, xpdGainValues); /* Write the detector gain biases and their number */ ar5416WriteDetectorGainBiases(ah, numXpdGain, xpdGainValues); for (i = 0; i < AR5416_MAX_CHAINS; i++) { regChainOffset = ar5416GetRegChainOffset(ah, i); if (pEepData->baseEepHeader.txMask & (1 << i)) { uint16_t diff; if (IEEE80211_IS_CHAN_2GHZ(chan)) { pRawDataset = pEepData->calPierData2G[i]; } else { pRawDataset = pEepData->calPierData5G[i]; } /* Fetch the gain boundaries and the PDADC values */ if (AR_SREV_MERLIN_20_OR_LATER(ah) && ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) { uint8_t pcdacIdx; uint8_t txPower; ar9280olcGetTxGainIndex(ah, chan, (struct calDataPerFreqOpLoop *) pRawDataset, pCalBChans, numPiers, &txPower, &pcdacIdx); ar9280olcGetPDADCs(ah, pcdacIdx, txPower / 2, pdadcValues); } else { ar5416GetGainBoundariesAndPdadcs(ah, chan, pRawDataset, pCalBChans, numPiers, pdGainOverlap_t2, &tMinCalPower, gainBoundaries, pdadcValues, numXpdGain); } /* * Prior to writing the boundaries or the pdadc vs. power table * into the chip registers the default starting point on the pdadc * vs. power table needs to be checked and the curve boundaries * adjusted accordingly */ diff = ar9280ChangeGainBoundarySettings(ah, gainBoundaries, numXpdGain, pdGainOverlap_t2, pwr_table_offset, &diff); if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { /* Set gain boundaries for either open- or closed-loop TPC */ if (AR_SREV_MERLIN_20_OR_LATER(ah) && ath_hal_eepromGetFlag(ah, AR_EEP_OL_PWRCTRL)) ar9280SetGainBoundariesOpenLoop(ah, i, pdGainOverlap_t2, gainBoundaries); else ar5416SetGainBoundariesClosedLoop(ah, i, pdGainOverlap_t2, gainBoundaries); } /* * If this is a board that has a pwrTableOffset that differs from * the default AR5416_PWR_TABLE_OFFSET_DB then the start of the * pdadc vs pwr table needs to be adjusted prior to writing to the * chip. */ ar9280AdjustPDADCValues(ah, pwr_table_offset, diff, pdadcValues); /* Write the power values into the baseband power table */ ar5416WritePdadcValues(ah, i, pdadcValues); } } *pTxPowerIndexOffset = 0; return AH_TRUE; }