1 /* 2 * Copyright (c) 2008-2009 Atheros Communications Inc. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include "hw.h" 18 19 static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) 20 { 21 if (fbin == AR5416_BCHAN_UNUSED) 22 return fbin; 23 24 return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); 25 } 26 27 void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask, 28 u32 shift, u32 val) 29 { 30 u32 regVal; 31 32 regVal = REG_READ(ah, reg) & ~mask; 33 regVal |= (val << shift) & mask; 34 35 REG_WRITE(ah, reg, regVal); 36 37 if (ah->config.analog_shiftreg) 38 udelay(100); 39 40 return; 41 } 42 43 int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight, 44 int16_t targetLeft, int16_t targetRight) 45 { 46 int16_t rv; 47 48 if (srcRight == srcLeft) { 49 rv = targetLeft; 50 } else { 51 rv = (int16_t) (((target - srcLeft) * targetRight + 52 (srcRight - target) * targetLeft) / 53 (srcRight - srcLeft)); 54 } 55 return rv; 56 } 57 58 bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, u16 listSize, 59 u16 *indexL, u16 *indexR) 60 { 61 u16 i; 62 63 if (target <= pList[0]) { 64 *indexL = *indexR = 0; 65 return true; 66 } 67 if (target >= pList[listSize - 1]) { 68 *indexL = *indexR = (u16) (listSize - 1); 69 return true; 70 } 71 72 for (i = 0; i < listSize - 1; i++) { 73 if (pList[i] == target) { 74 *indexL = *indexR = i; 75 return true; 76 } 77 if (target < pList[i + 1]) { 78 *indexL = i; 79 *indexR = (u16) (i + 1); 80 return false; 81 } 82 } 83 return false; 84 } 85 86 bool ath9k_hw_nvram_read(struct ath_common *common, u32 off, u16 *data) 87 { 88 return common->bus_ops->eeprom_read(common, off, data); 89 } 90 91 void ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, 92 u8 *pVpdList, u16 numIntercepts, 93 u8 *pRetVpdList) 94 { 95 u16 i, k; 96 u8 currPwr = pwrMin; 97 u16 idxL = 0, idxR = 0; 98 99 for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { 100 ath9k_hw_get_lower_upper_index(currPwr, pPwrList, 101 numIntercepts, &(idxL), 102 &(idxR)); 103 if (idxR < 1) 104 idxR = 1; 105 if (idxL == numIntercepts - 1) 106 idxL = (u16) (numIntercepts - 2); 107 if (pPwrList[idxL] == pPwrList[idxR]) 108 k = pVpdList[idxL]; 109 else 110 k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] + 111 (pPwrList[idxR] - currPwr) * pVpdList[idxL]) / 112 (pPwrList[idxR] - pPwrList[idxL])); 113 pRetVpdList[i] = (u8) k; 114 currPwr += 2; 115 } 116 } 117 118 void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, 119 struct ath9k_channel *chan, 120 struct cal_target_power_leg *powInfo, 121 u16 numChannels, 122 struct cal_target_power_leg *pNewPower, 123 u16 numRates, bool isExtTarget) 124 { 125 struct chan_centers centers; 126 u16 clo, chi; 127 int i; 128 int matchIndex = -1, lowIndex = -1; 129 u16 freq; 130 131 ath9k_hw_get_channel_centers(ah, chan, ¢ers); 132 freq = (isExtTarget) ? centers.ext_center : centers.ctl_center; 133 134 if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, 135 IS_CHAN_2GHZ(chan))) { 136 matchIndex = 0; 137 } else { 138 for (i = 0; (i < numChannels) && 139 (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { 140 if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, 141 IS_CHAN_2GHZ(chan))) { 142 matchIndex = i; 143 break; 144 } else if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, 145 IS_CHAN_2GHZ(chan)) && i > 0 && 146 freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, 147 IS_CHAN_2GHZ(chan))) { 148 lowIndex = i - 1; 149 break; 150 } 151 } 152 if ((matchIndex == -1) && (lowIndex == -1)) 153 matchIndex = i - 1; 154 } 155 156 if (matchIndex != -1) { 157 *pNewPower = powInfo[matchIndex]; 158 } else { 159 clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, 160 IS_CHAN_2GHZ(chan)); 161 chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, 162 IS_CHAN_2GHZ(chan)); 163 164 for (i = 0; i < numRates; i++) { 165 pNewPower->tPow2x[i] = 166 (u8)ath9k_hw_interpolate(freq, clo, chi, 167 powInfo[lowIndex].tPow2x[i], 168 powInfo[lowIndex + 1].tPow2x[i]); 169 } 170 } 171 } 172 173 void ath9k_hw_get_target_powers(struct ath_hw *ah, 174 struct ath9k_channel *chan, 175 struct cal_target_power_ht *powInfo, 176 u16 numChannels, 177 struct cal_target_power_ht *pNewPower, 178 u16 numRates, bool isHt40Target) 179 { 180 struct chan_centers centers; 181 u16 clo, chi; 182 int i; 183 int matchIndex = -1, lowIndex = -1; 184 u16 freq; 185 186 ath9k_hw_get_channel_centers(ah, chan, ¢ers); 187 freq = isHt40Target ? centers.synth_center : centers.ctl_center; 188 189 if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { 190 matchIndex = 0; 191 } else { 192 for (i = 0; (i < numChannels) && 193 (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { 194 if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, 195 IS_CHAN_2GHZ(chan))) { 196 matchIndex = i; 197 break; 198 } else 199 if (freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, 200 IS_CHAN_2GHZ(chan)) && i > 0 && 201 freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, 202 IS_CHAN_2GHZ(chan))) { 203 lowIndex = i - 1; 204 break; 205 } 206 } 207 if ((matchIndex == -1) && (lowIndex == -1)) 208 matchIndex = i - 1; 209 } 210 211 if (matchIndex != -1) { 212 *pNewPower = powInfo[matchIndex]; 213 } else { 214 clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, 215 IS_CHAN_2GHZ(chan)); 216 chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, 217 IS_CHAN_2GHZ(chan)); 218 219 for (i = 0; i < numRates; i++) { 220 pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq, 221 clo, chi, 222 powInfo[lowIndex].tPow2x[i], 223 powInfo[lowIndex + 1].tPow2x[i]); 224 } 225 } 226 } 227 228 u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower, 229 bool is2GHz, int num_band_edges) 230 { 231 u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; 232 int i; 233 234 for (i = 0; (i < num_band_edges) && 235 (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) { 236 if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) { 237 twiceMaxEdgePower = pRdEdgesPower[i].tPower; 238 break; 239 } else if ((i > 0) && 240 (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, 241 is2GHz))) { 242 if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel, 243 is2GHz) < freq && 244 pRdEdgesPower[i - 1].flag) { 245 twiceMaxEdgePower = 246 pRdEdgesPower[i - 1].tPower; 247 } 248 break; 249 } 250 } 251 252 return twiceMaxEdgePower; 253 } 254 255 int ath9k_hw_eeprom_init(struct ath_hw *ah) 256 { 257 int status; 258 259 if (AR_SREV_9287(ah)) { 260 ah->eep_map = EEP_MAP_AR9287; 261 ah->eep_ops = &eep_AR9287_ops; 262 } else if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) { 263 ah->eep_map = EEP_MAP_4KBITS; 264 ah->eep_ops = &eep_4k_ops; 265 } else { 266 ah->eep_map = EEP_MAP_DEFAULT; 267 ah->eep_ops = &eep_def_ops; 268 } 269 270 if (!ah->eep_ops->fill_eeprom(ah)) 271 return -EIO; 272 273 status = ah->eep_ops->check_eeprom(ah); 274 275 return status; 276 } 277