1 /* 2 * Copyright (c) 2013 Qualcomm Atheros, 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 WITH 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 13 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 * PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include "opt_ah.h" 18 19 #include "ah.h" 20 #include "ah_internal.h" 21 22 #include "ar9300/ar9300.h" 23 #include "ar9300/ar9300reg.h" 24 #include "ar9300/ar9300phy.h" 25 26 /* chansel table, used by Hornet and Poseidon */ 27 static const u_int32_t ar9300_chansel_xtal_25M[] = { 28 0x101479e, /* Freq 2412 - (128 << 17) + 83870 */ 29 0x101d027, /* Freq 2417 - (128 << 17) + 118823 */ 30 0x10258af, /* Freq 2422 - (129 << 17) + 22703 */ 31 0x102e138, /* Freq 2427 - (129 << 17) + 57656 */ 32 0x10369c0, /* Freq 2432 - (129 << 17) + 92608 */ 33 0x103f249, /* Freq 2437 - (129 << 17) + 127561 */ 34 0x1047ad1, /* Freq 2442 - (130 << 17) + 31441 */ 35 0x105035a, /* Freq 2447 - (130 << 17) + 66394 */ 36 0x1058be2, /* Freq 2452 - (130 << 17) + 101346 */ 37 0x106146b, /* Freq 2457 - (131 << 17) + 5227 */ 38 0x1069cf3, /* Freq 2462 - (131 << 17) + 40179 */ 39 0x107257c, /* Freq 2467 - (131 << 17) + 75132 */ 40 0x107ae04, /* Freq 2472 - (131 << 17) + 110084 */ 41 0x108f5b2, /* Freq 2484 - (132 << 17) + 62898 */ 42 }; 43 44 static const u_int32_t ar9300_chansel_xtal_40M[] = { 45 0xa0ccbe, /* Freq 2412 - (80 << 17) + 52414 */ 46 0xa12213, /* Freq 2417 - (80 << 17) + 74259 */ 47 0xa17769, /* Freq 2422 - (80 << 17) + 96105 */ 48 0xa1ccbe, /* Freq 2427 - (80 << 17) + 117950 */ 49 0xa22213, /* Freq 2432 - (81 << 17) + 8723 */ 50 0xa27769, /* Freq 2437 - (81 << 17) + 30569 */ 51 0xa2ccbe, /* Freq 2442 - (81 << 17) + 52414 */ 52 0xa32213, /* Freq 2447 - (81 << 17) + 74259 */ 53 0xa37769, /* Freq 2452 - (81 << 17) + 96105 */ 54 0xa3ccbe, /* Freq 2457 - (81 << 17) + 117950 */ 55 0xa42213, /* Freq 2462 - (82 << 17) + 8723 */ 56 0xa47769, /* Freq 2467 - (82 << 17) + 30569 */ 57 0xa4ccbe, /* Freq 2472 - (82 << 17) + 52414 */ 58 0xa5998b, /* Freq 2484 - (82 << 17) + 104843 */ 59 }; 60 61 62 /* 63 * Take the MHz channel value and set the Channel value 64 * 65 * ASSUMES: Writes enabled to analog bus 66 * 67 * Actual Expression, 68 * 69 * For 2GHz channel, 70 * Channel Frequency = (3/4) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17) 71 * (freq_ref = 40MHz) 72 * 73 * For 5GHz channel, 74 * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^10) 75 * (freq_ref = 40MHz/(24>>amode_ref_sel)) 76 * 77 * For 5GHz channels which are 5MHz spaced, 78 * Channel Frequency = (3/2) * freq_ref * (chansel[8:0] + chanfrac[16:0]/2^17) 79 * (freq_ref = 40MHz) 80 */ 81 static HAL_BOOL 82 ar9300_set_channel(struct ath_hal *ah, struct ieee80211_channel *chan) 83 { 84 u_int16_t b_mode, frac_mode = 0, a_mode_ref_sel = 0; 85 u_int32_t freq, channel_sel, reg32; 86 u_int8_t clk_25mhz = AH9300(ah)->clk_25mhz; 87 CHAN_CENTERS centers; 88 int load_synth_channel; 89 #ifdef AH_DEBUG_ALQ 90 HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); 91 #endif 92 93 /* 94 * Put this behind AH_DEBUG_ALQ for now until the Hornet 95 * channel_sel code below is made to work. 96 */ 97 #ifdef AH_DEBUG_ALQ 98 OS_MARK(ah, AH_MARK_SETCHANNEL, ichan->channel); 99 #endif 100 101 ar9300_get_channel_centers(ah, chan, ¢ers); 102 freq = centers.synth_center; 103 104 if (freq < 4800) { /* 2 GHz, fractional mode */ 105 b_mode = 1; /* 2 GHz */ 106 107 if (AR_SREV_HORNET(ah)) { 108 #if 0 109 u_int32_t ichan = 110 ieee80211_mhz2ieee(ah, chan->ic_freq, chan->ic_flags); 111 HALASSERT(ichan > 0 && ichan <= 14); 112 if (clk_25mhz) { 113 channel_sel = ar9300_chansel_xtal_25M[ichan - 1]; 114 } else { 115 channel_sel = ar9300_chansel_xtal_40M[ichan - 1]; 116 } 117 #endif 118 uint32_t i; 119 120 /* 121 * Pay close attention to this bit! 122 * 123 * We need to map the actual desired synth frequency to 124 * one of the channel select array entries. 125 * 126 * For HT20, it'll align with the channel we select. 127 * 128 * For HT40 though it won't - the centre frequency 129 * will not be the frequency of chan->ic_freq or ichan->freq; 130 * it needs to be whatever frequency maps to 'freq'. 131 */ 132 i = ath_hal_mhz2ieee_2ghz(ah, freq); 133 HALASSERT(i > 0 && i <= 14); 134 if (clk_25mhz) { 135 channel_sel = ar9300_chansel_xtal_25M[i - 1]; 136 } else { 137 channel_sel = ar9300_chansel_xtal_40M[i - 1]; 138 } 139 } else if (AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) { 140 u_int32_t channel_frac; 141 /* 142 * freq_ref = (40 / (refdiva >> a_mode_ref_sel)); 143 * (where refdiva = 1 and amoderefsel = 0) 144 * ndiv = ((chan_mhz * 4) / 3) / freq_ref; 145 * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000 146 */ 147 channel_sel = (freq * 4) / 120; 148 channel_frac = (((freq * 4) % 120) * 0x20000) / 120; 149 channel_sel = (channel_sel << 17) | (channel_frac); 150 } else if (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah) || AR_SREV_HONEYBEE(ah)) { 151 u_int32_t channel_frac; 152 if (clk_25mhz) { 153 /* 154 * freq_ref = (50 / (refdiva >> a_mode_ref_sel)); 155 * (where refdiva = 1 and amoderefsel = 0) 156 * ndiv = ((chan_mhz * 4) / 3) / freq_ref; 157 * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000 158 */ 159 if (AR_SREV_SCORPION(ah) || AR_SREV_HONEYBEE(ah)) { 160 /* Doubler is off for Scorpion */ 161 channel_sel = (freq * 4) / 75; 162 channel_frac = (((freq * 4) % 75) * 0x20000) / 75; 163 } else { 164 channel_sel = (freq * 2) / 75; 165 channel_frac = (((freq * 2) % 75) * 0x20000) / 75; 166 } 167 } else { 168 /* 169 * freq_ref = (50 / (refdiva >> a_mode_ref_sel)); 170 * (where refdiva = 1 and amoderefsel = 0) 171 * ndiv = ((chan_mhz * 4) / 3) / freq_ref; 172 * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000 173 */ 174 if (AR_SREV_SCORPION(ah)) { 175 /* Doubler is off for Scorpion */ 176 channel_sel = (freq * 4) / 120; 177 channel_frac = (((freq * 4) % 120) * 0x20000) / 120; 178 } else { 179 channel_sel = (freq * 2) / 120; 180 channel_frac = (((freq * 2) % 120) * 0x20000) / 120; 181 } 182 } 183 channel_sel = (channel_sel << 17) | (channel_frac); 184 } else { 185 channel_sel = CHANSEL_2G(freq); 186 } 187 } else { 188 b_mode = 0; /* 5 GHz */ 189 if ((AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) && clk_25mhz){ 190 u_int32_t channel_frac; 191 /* 192 * freq_ref = (50 / (refdiva >> amoderefsel)); 193 * (refdiva = 1, amoderefsel = 0) 194 * ndiv = ((chan_mhz * 2) / 3) / freq_ref; 195 * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000 196 */ 197 channel_sel = freq / 75 ; 198 channel_frac = ((freq % 75) * 0x20000) / 75; 199 channel_sel = (channel_sel << 17) | (channel_frac); 200 } else { 201 channel_sel = CHANSEL_5G(freq); 202 /* Doubler is ON, so, divide channel_sel by 2. */ 203 channel_sel >>= 1; 204 } 205 } 206 207 208 /* Enable fractional mode for all channels */ 209 frac_mode = 1; 210 a_mode_ref_sel = 0; 211 load_synth_channel = 0; 212 213 reg32 = (b_mode << 29); 214 OS_REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32); 215 216 /* Enable Long shift Select for Synthesizer */ 217 OS_REG_RMW_FIELD(ah, 218 AR_PHY_65NM_CH0_SYNTH4, AR_PHY_SYNTH4_LONG_SHIFT_SELECT, 1); 219 220 /* program synth. setting */ 221 reg32 = 222 (channel_sel << 2) | 223 (a_mode_ref_sel << 28) | 224 (frac_mode << 30) | 225 (load_synth_channel << 31); 226 if (IEEE80211_IS_CHAN_QUARTER(chan)) { 227 reg32 += CHANSEL_5G_DOT5MHZ; 228 } 229 OS_REG_WRITE(ah, AR_PHY_65NM_CH0_SYNTH7, reg32); 230 /* Toggle Load Synth channel bit */ 231 load_synth_channel = 1; 232 reg32 |= load_synth_channel << 31; 233 OS_REG_WRITE(ah, AR_PHY_65NM_CH0_SYNTH7, reg32); 234 235 236 AH_PRIVATE(ah)->ah_curchan = chan; 237 238 return AH_TRUE; 239 } 240 241 242 #if 0 243 static HAL_BOOL 244 ar9300_get_chip_power_limits(struct ath_hal *ah, HAL_CHANNEL *chans, 245 u_int32_t nchans) 246 { 247 int i; 248 249 for (i = 0; i < nchans; i++) { 250 chans[i].max_tx_power = AR9300_MAX_RATE_POWER; 251 chans[i].min_tx_power = AR9300_MAX_RATE_POWER; 252 } 253 return AH_TRUE; 254 } 255 #endif 256 257 /* XXX FreeBSD */ 258 static HAL_BOOL 259 ar9300_get_chip_power_limits(struct ath_hal *ah, 260 struct ieee80211_channel *chan) 261 { 262 /* XXX ? */ 263 chan->ic_minpower = 0; 264 chan->ic_maxpower = AR9300_MAX_RATE_POWER; 265 266 return AH_TRUE; 267 } 268 269 HAL_BOOL 270 ar9300_rf_attach(struct ath_hal *ah, HAL_STATUS *status) 271 { 272 struct ath_hal_9300 *ahp = AH9300(ah); 273 274 ahp->ah_rf_hal.set_channel = ar9300_set_channel; 275 ahp->ah_rf_hal.get_chip_power_lim = ar9300_get_chip_power_limits; 276 277 *status = HAL_OK; 278 279 return AH_TRUE; 280 } 281