diff options
author | Senthil Balasubramanian <senthilkumar@atheros.com> | 2009-02-12 03:27:03 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-02-27 14:51:46 -0500 |
commit | 8bd1d07f9345750bd4d767e6c1600919672f98ba (patch) | |
tree | 42b201403637888b4c5cde5e1fd096c373d4ca05 /drivers/net/wireless/ath9k/eeprom.c | |
parent | 81cb7623ad3b408f871fa36b774fc20d8dfccac0 (diff) |
ath9k: Add open loop control support
This patch adds Open Loop Control support for Atheros chipsets that
supports open loop power control.
Signed-off-by: Senthil Balasubramanian <senthilkumar@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath9k/eeprom.c')
-rw-r--r-- | drivers/net/wireless/ath9k/eeprom.c | 210 |
1 files changed, 175 insertions, 35 deletions
diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c index b6f9c31ddfcf..fff7a1b6fbf2 100644 --- a/drivers/net/wireless/ath9k/eeprom.c +++ b/drivers/net/wireless/ath9k/eeprom.c | |||
@@ -179,6 +179,69 @@ static void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, | |||
179 | } | 179 | } |
180 | } | 180 | } |
181 | 181 | ||
182 | static void ath9k_get_txgain_index(struct ath_hw *ah, | ||
183 | struct ath9k_channel *chan, | ||
184 | struct calDataPerFreqOpLoop *rawDatasetOpLoop, | ||
185 | u8 *calChans, u16 availPiers, u8 *pwr, u8 *pcdacIdx) | ||
186 | { | ||
187 | u8 pcdac, i = 0; | ||
188 | u16 idxL = 0, idxR = 0, numPiers; | ||
189 | bool match; | ||
190 | struct chan_centers centers; | ||
191 | |||
192 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
193 | |||
194 | for (numPiers = 0; numPiers < availPiers; numPiers++) | ||
195 | if (calChans[numPiers] == AR5416_BCHAN_UNUSED) | ||
196 | break; | ||
197 | |||
198 | match = ath9k_hw_get_lower_upper_index( | ||
199 | (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), | ||
200 | calChans, numPiers, &idxL, &idxR); | ||
201 | if (match) { | ||
202 | pcdac = rawDatasetOpLoop[idxL].pcdac[0][0]; | ||
203 | *pwr = rawDatasetOpLoop[idxL].pwrPdg[0][0]; | ||
204 | } else { | ||
205 | pcdac = rawDatasetOpLoop[idxR].pcdac[0][0]; | ||
206 | *pwr = (rawDatasetOpLoop[idxL].pwrPdg[0][0] + | ||
207 | rawDatasetOpLoop[idxR].pwrPdg[0][0])/2; | ||
208 | } | ||
209 | |||
210 | while (pcdac > ah->originalGain[i] && | ||
211 | i < (AR9280_TX_GAIN_TABLE_SIZE - 1)) | ||
212 | i++; | ||
213 | |||
214 | *pcdacIdx = i; | ||
215 | return; | ||
216 | } | ||
217 | |||
218 | static void ath9k_olc_get_pdadcs(struct ath_hw *ah, | ||
219 | u32 initTxGain, | ||
220 | int txPower, | ||
221 | u8 *pPDADCValues) | ||
222 | { | ||
223 | u32 i; | ||
224 | u32 offset; | ||
225 | |||
226 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_0, | ||
227 | AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); | ||
228 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_1, | ||
229 | AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); | ||
230 | |||
231 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL7, | ||
232 | AR_PHY_TX_PWRCTRL_INIT_TX_GAIN, initTxGain); | ||
233 | |||
234 | offset = txPower; | ||
235 | for (i = 0; i < AR5416_NUM_PDADC_VALUES; i++) | ||
236 | if (i < offset) | ||
237 | pPDADCValues[i] = 0x0; | ||
238 | else | ||
239 | pPDADCValues[i] = 0xFF; | ||
240 | } | ||
241 | |||
242 | |||
243 | |||
244 | |||
182 | static void ath9k_hw_get_target_powers(struct ath_hw *ah, | 245 | static void ath9k_hw_get_target_powers(struct ath_hw *ah, |
183 | struct ath9k_channel *chan, | 246 | struct ath9k_channel *chan, |
184 | struct cal_target_power_ht *powInfo, | 247 | struct cal_target_power_ht *powInfo, |
@@ -1596,6 +1659,16 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, | |||
1596 | return pBase->rxGainType; | 1659 | return pBase->rxGainType; |
1597 | case EEP_TXGAIN_TYPE: | 1660 | case EEP_TXGAIN_TYPE: |
1598 | return pBase->txGainType; | 1661 | return pBase->txGainType; |
1662 | case EEP_OL_PWRCTRL: | ||
1663 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) | ||
1664 | return pBase->openLoopPwrCntl ? true : false; | ||
1665 | else | ||
1666 | return false; | ||
1667 | case EEP_RC_CHAIN_MASK: | ||
1668 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) | ||
1669 | return pBase->rcChainMask; | ||
1670 | else | ||
1671 | return 0; | ||
1599 | case EEP_DAC_HPWR_5G: | 1672 | case EEP_DAC_HPWR_5G: |
1600 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) | 1673 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) |
1601 | return pBase->dacHiPwrMode_5G; | 1674 | return pBase->dacHiPwrMode_5G; |
@@ -1839,8 +1912,15 @@ static bool ath9k_hw_def_set_board_values(struct ath_hw *ah, | |||
1839 | pModal->swSettleHt40); | 1912 | pModal->swSettleHt40); |
1840 | } | 1913 | } |
1841 | 1914 | ||
1915 | if (AR_SREV_9280_20_OR_LATER(ah) && | ||
1916 | AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) | ||
1917 | REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL, | ||
1918 | AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK, | ||
1919 | pModal->miscBits); | ||
1920 | |||
1921 | |||
1842 | if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) { | 1922 | if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) { |
1843 | if (IS_CHAN_HT20(chan)) | 1923 | if (IS_CHAN_2GHZ(chan)) |
1844 | REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, | 1924 | REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, |
1845 | eep->baseEepHeader.dacLpMode); | 1925 | eep->baseEepHeader.dacLpMode); |
1846 | else if (eep->baseEepHeader.dacHiPwrMode_5G) | 1926 | else if (eep->baseEepHeader.dacHiPwrMode_5G) |
@@ -1851,6 +1931,10 @@ static bool ath9k_hw_def_set_board_values(struct ath_hw *ah, | |||
1851 | 1931 | ||
1852 | REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP, | 1932 | REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP, |
1853 | pModal->miscBits >> 2); | 1933 | pModal->miscBits >> 2); |
1934 | |||
1935 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL9, | ||
1936 | AR_PHY_TX_DESIRED_SCALE_CCK, | ||
1937 | eep->baseEepHeader.desiredScaleCCK); | ||
1854 | } | 1938 | } |
1855 | 1939 | ||
1856 | return true; | 1940 | return true; |
@@ -2080,6 +2164,12 @@ static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, | |||
2080 | struct ath9k_channel *chan, | 2164 | struct ath9k_channel *chan, |
2081 | int16_t *pTxPowerIndexOffset) | 2165 | int16_t *pTxPowerIndexOffset) |
2082 | { | 2166 | { |
2167 | #define OLC_FOR_AR9280_20_LATER (AR_SREV_9280_20_OR_LATER(ah) && \ | ||
2168 | ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) | ||
2169 | #define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x) | ||
2170 | #define SM_PDGAIN_B(x, y) \ | ||
2171 | SM((gainBoundaries[x]), AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##y) | ||
2172 | |||
2083 | struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; | 2173 | struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; |
2084 | struct cal_data_per_freq *pRawDataset; | 2174 | struct cal_data_per_freq *pRawDataset; |
2085 | u8 *pCalBChans = NULL; | 2175 | u8 *pCalBChans = NULL; |
@@ -2113,6 +2203,12 @@ static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, | |||
2113 | numPiers = AR5416_NUM_5G_CAL_PIERS; | 2203 | numPiers = AR5416_NUM_5G_CAL_PIERS; |
2114 | } | 2204 | } |
2115 | 2205 | ||
2206 | if (OLC_FOR_AR9280_20_LATER && IS_CHAN_2GHZ(chan)) { | ||
2207 | pRawDataset = pEepData->calPierData2G[0]; | ||
2208 | ah->initPDADC = ((struct calDataPerFreqOpLoop *) | ||
2209 | pRawDataset)->vpdPdg[0][0]; | ||
2210 | } | ||
2211 | |||
2116 | numXpdGain = 0; | 2212 | numXpdGain = 0; |
2117 | 2213 | ||
2118 | for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { | 2214 | for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { |
@@ -2148,25 +2244,45 @@ static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, | |||
2148 | else | 2244 | else |
2149 | pRawDataset = pEepData->calPierData5G[i]; | 2245 | pRawDataset = pEepData->calPierData5G[i]; |
2150 | 2246 | ||
2151 | ath9k_hw_get_def_gain_boundaries_pdadcs(ah, chan, | 2247 | |
2152 | pRawDataset, pCalBChans, | 2248 | if (OLC_FOR_AR9280_20_LATER) { |
2153 | numPiers, pdGainOverlap_t2, | 2249 | u8 pcdacIdx; |
2154 | &tMinCalPower, gainBoundaries, | 2250 | u8 txPower; |
2155 | pdadcValues, numXpdGain); | 2251 | |
2252 | ath9k_get_txgain_index(ah, chan, | ||
2253 | (struct calDataPerFreqOpLoop *)pRawDataset, | ||
2254 | pCalBChans, numPiers, &txPower, &pcdacIdx); | ||
2255 | ath9k_olc_get_pdadcs(ah, pcdacIdx, | ||
2256 | txPower/2, pdadcValues); | ||
2257 | } else { | ||
2258 | ath9k_hw_get_def_gain_boundaries_pdadcs(ah, | ||
2259 | chan, pRawDataset, | ||
2260 | pCalBChans, numPiers, | ||
2261 | pdGainOverlap_t2, | ||
2262 | &tMinCalPower, | ||
2263 | gainBoundaries, | ||
2264 | pdadcValues, | ||
2265 | numXpdGain); | ||
2266 | } | ||
2156 | 2267 | ||
2157 | if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { | 2268 | if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { |
2158 | REG_WRITE(ah, | 2269 | if (OLC_FOR_AR9280_20_LATER) { |
2159 | AR_PHY_TPCRG5 + regChainOffset, | 2270 | REG_WRITE(ah, |
2160 | SM(pdGainOverlap_t2, | 2271 | AR_PHY_TPCRG5 + regChainOffset, |
2161 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | 2272 | SM(0x6, |
2162 | | SM(gainBoundaries[0], | 2273 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | |
2163 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) | 2274 | SM_PD_GAIN(1) | SM_PD_GAIN(2) | |
2164 | | SM(gainBoundaries[1], | 2275 | SM_PD_GAIN(3) | SM_PD_GAIN(4)); |
2165 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) | 2276 | } else { |
2166 | | SM(gainBoundaries[2], | 2277 | REG_WRITE(ah, |
2167 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) | 2278 | AR_PHY_TPCRG5 + regChainOffset, |
2168 | | SM(gainBoundaries[3], | 2279 | SM(pdGainOverlap_t2, |
2169 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); | 2280 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP)| |
2281 | SM_PDGAIN_B(0, 1) | | ||
2282 | SM_PDGAIN_B(1, 2) | | ||
2283 | SM_PDGAIN_B(2, 3) | | ||
2284 | SM_PDGAIN_B(3, 4)); | ||
2285 | } | ||
2170 | } | 2286 | } |
2171 | 2287 | ||
2172 | regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; | 2288 | regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; |
@@ -2200,6 +2316,8 @@ static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, | |||
2200 | *pTxPowerIndexOffset = 0; | 2316 | *pTxPowerIndexOffset = 0; |
2201 | 2317 | ||
2202 | return true; | 2318 | return true; |
2319 | #undef SM_PD_GAIN | ||
2320 | #undef SM_PDGAIN_B | ||
2203 | } | 2321 | } |
2204 | 2322 | ||
2205 | static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, | 2323 | static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, |
@@ -2500,13 +2618,14 @@ static int ath9k_hw_def_set_txpower(struct ath_hw *ah, | |||
2500 | u8 twiceMaxRegulatoryPower, | 2618 | u8 twiceMaxRegulatoryPower, |
2501 | u8 powerLimit) | 2619 | u8 powerLimit) |
2502 | { | 2620 | { |
2621 | #define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta) | ||
2503 | struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; | 2622 | struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; |
2504 | struct modal_eep_header *pModal = | 2623 | struct modal_eep_header *pModal = |
2505 | &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); | 2624 | &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); |
2506 | int16_t ratesArray[Ar5416RateSize]; | 2625 | int16_t ratesArray[Ar5416RateSize]; |
2507 | int16_t txPowerIndexOffset = 0; | 2626 | int16_t txPowerIndexOffset = 0; |
2508 | u8 ht40PowerIncForPdadc = 2; | 2627 | u8 ht40PowerIncForPdadc = 2; |
2509 | int i; | 2628 | int i, cck_ofdm_delta = 0; |
2510 | 2629 | ||
2511 | memset(ratesArray, 0, sizeof(ratesArray)); | 2630 | memset(ratesArray, 0, sizeof(ratesArray)); |
2512 | 2631 | ||
@@ -2555,16 +2674,30 @@ static int ath9k_hw_def_set_txpower(struct ath_hw *ah, | |||
2555 | | ATH9K_POW_SM(ratesArray[rate24mb], 0)); | 2674 | | ATH9K_POW_SM(ratesArray[rate24mb], 0)); |
2556 | 2675 | ||
2557 | if (IS_CHAN_2GHZ(chan)) { | 2676 | if (IS_CHAN_2GHZ(chan)) { |
2558 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, | 2677 | if (OLC_FOR_AR9280_20_LATER) { |
2559 | ATH9K_POW_SM(ratesArray[rate2s], 24) | 2678 | cck_ofdm_delta = 2; |
2560 | | ATH9K_POW_SM(ratesArray[rate2l], 16) | 2679 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, |
2561 | | ATH9K_POW_SM(ratesArray[rateXr], 8) | 2680 | ATH9K_POW_SM(RT_AR_DELTA(rate2s), 24) |
2562 | | ATH9K_POW_SM(ratesArray[rate1l], 0)); | 2681 | | ATH9K_POW_SM(RT_AR_DELTA(rate2l), 16) |
2563 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, | 2682 | | ATH9K_POW_SM(ratesArray[rateXr], 8) |
2564 | ATH9K_POW_SM(ratesArray[rate11s], 24) | 2683 | | ATH9K_POW_SM(RT_AR_DELTA(rate1l), 0)); |
2565 | | ATH9K_POW_SM(ratesArray[rate11l], 16) | 2684 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, |
2566 | | ATH9K_POW_SM(ratesArray[rate5_5s], 8) | 2685 | ATH9K_POW_SM(RT_AR_DELTA(rate11s), 24) |
2567 | | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); | 2686 | | ATH9K_POW_SM(RT_AR_DELTA(rate11l), 16) |
2687 | | ATH9K_POW_SM(RT_AR_DELTA(rate5_5s), 8) | ||
2688 | | ATH9K_POW_SM(RT_AR_DELTA(rate5_5l), 0)); | ||
2689 | } else { | ||
2690 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, | ||
2691 | ATH9K_POW_SM(ratesArray[rate2s], 24) | ||
2692 | | ATH9K_POW_SM(ratesArray[rate2l], 16) | ||
2693 | | ATH9K_POW_SM(ratesArray[rateXr], 8) | ||
2694 | | ATH9K_POW_SM(ratesArray[rate1l], 0)); | ||
2695 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, | ||
2696 | ATH9K_POW_SM(ratesArray[rate11s], 24) | ||
2697 | | ATH9K_POW_SM(ratesArray[rate11l], 16) | ||
2698 | | ATH9K_POW_SM(ratesArray[rate5_5s], 8) | ||
2699 | | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); | ||
2700 | } | ||
2568 | } | 2701 | } |
2569 | 2702 | ||
2570 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, | 2703 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, |
@@ -2597,12 +2730,19 @@ static int ath9k_hw_def_set_txpower(struct ath_hw *ah, | |||
2597 | ht40PowerIncForPdadc, 8) | 2730 | ht40PowerIncForPdadc, 8) |
2598 | | ATH9K_POW_SM(ratesArray[rateHt40_4] + | 2731 | | ATH9K_POW_SM(ratesArray[rateHt40_4] + |
2599 | ht40PowerIncForPdadc, 0)); | 2732 | ht40PowerIncForPdadc, 0)); |
2600 | 2733 | if (OLC_FOR_AR9280_20_LATER) { | |
2601 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, | 2734 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, |
2602 | ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | 2735 | ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) |
2603 | | ATH9K_POW_SM(ratesArray[rateExtCck], 16) | 2736 | | ATH9K_POW_SM(RT_AR_DELTA(rateExtCck), 16) |
2604 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | 2737 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) |
2605 | | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); | 2738 | | ATH9K_POW_SM(RT_AR_DELTA(rateDupCck), 0)); |
2739 | } else { | ||
2740 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, | ||
2741 | ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | ||
2742 | | ATH9K_POW_SM(ratesArray[rateExtCck], 16) | ||
2743 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ||
2744 | | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); | ||
2745 | } | ||
2606 | } | 2746 | } |
2607 | 2747 | ||
2608 | REG_WRITE(ah, AR_PHY_POWER_TX_SUB, | 2748 | REG_WRITE(ah, AR_PHY_POWER_TX_SUB, |