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
ar9300_set_channel(struct ath_hal * ah,struct ieee80211_channel * chan)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
ar9300_get_chip_power_limits(struct ath_hal * ah,struct ieee80211_channel * chan)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
ar9300_rf_attach(struct ath_hal * ah,HAL_STATUS * status)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