Commit | Line | Data |
---|---|---|
f078f209 | 1 | /* |
cee075a2 | 2 | * Copyright (c) 2008-2009 Atheros Communications Inc. |
f078f209 LR |
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 | ||
394cf0a1 | 17 | #include "ath9k.h" |
f078f209 LR |
18 | |
19 | void | |
cbe61d8a | 20 | ath9k_hw_write_regs(struct ath_hw *ah, u32 modesIndex, u32 freqIndex, |
f078f209 LR |
21 | int regWrites) |
22 | { | |
2660b81a | 23 | REG_WRITE_ARRAY(&ah->iniBB_RfGain, freqIndex, regWrites); |
f078f209 LR |
24 | } |
25 | ||
26 | bool | |
cbe61d8a | 27 | ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) |
f078f209 LR |
28 | { |
29 | u32 channelSel = 0; | |
30 | u32 bModeSynth = 0; | |
31 | u32 aModeRefSel = 0; | |
32 | u32 reg32 = 0; | |
33 | u16 freq; | |
34 | struct chan_centers centers; | |
35 | ||
36 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | |
37 | freq = centers.synth_center; | |
38 | ||
39 | if (freq < 4800) { | |
40 | u32 txctl; | |
41 | ||
42 | if (((freq - 2192) % 5) == 0) { | |
43 | channelSel = ((freq - 672) * 2 - 3040) / 10; | |
44 | bModeSynth = 0; | |
45 | } else if (((freq - 2224) % 5) == 0) { | |
46 | channelSel = ((freq - 704) * 2 - 3040) / 10; | |
47 | bModeSynth = 1; | |
48 | } else { | |
49 | DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, | |
04bd4638 | 50 | "Invalid channel %u MHz\n", freq); |
f078f209 LR |
51 | return false; |
52 | } | |
53 | ||
54 | channelSel = (channelSel << 2) & 0xff; | |
55 | channelSel = ath9k_hw_reverse_bits(channelSel, 8); | |
56 | ||
57 | txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL); | |
58 | if (freq == 2484) { | |
59 | ||
60 | REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, | |
61 | txctl | AR_PHY_CCK_TX_CTRL_JAPAN); | |
62 | } else { | |
63 | REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, | |
64 | txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN); | |
65 | } | |
66 | ||
67 | } else if ((freq % 20) == 0 && freq >= 5120) { | |
68 | channelSel = | |
69 | ath9k_hw_reverse_bits(((freq - 4800) / 20 << 2), 8); | |
70 | aModeRefSel = ath9k_hw_reverse_bits(1, 2); | |
71 | } else if ((freq % 10) == 0) { | |
72 | channelSel = | |
73 | ath9k_hw_reverse_bits(((freq - 4800) / 10 << 1), 8); | |
74 | if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) | |
75 | aModeRefSel = ath9k_hw_reverse_bits(2, 2); | |
76 | else | |
77 | aModeRefSel = ath9k_hw_reverse_bits(1, 2); | |
78 | } else if ((freq % 5) == 0) { | |
79 | channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8); | |
80 | aModeRefSel = ath9k_hw_reverse_bits(1, 2); | |
81 | } else { | |
82 | DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, | |
04bd4638 | 83 | "Invalid channel %u MHz\n", freq); |
f078f209 LR |
84 | return false; |
85 | } | |
86 | ||
87 | reg32 = | |
88 | (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) | | |
89 | (1 << 5) | 0x1; | |
90 | ||
91 | REG_WRITE(ah, AR_PHY(0x37), reg32); | |
92 | ||
2660b81a S |
93 | ah->curchan = chan; |
94 | ah->curchan_rad_index = -1; | |
f078f209 LR |
95 | |
96 | return true; | |
97 | } | |
98 | ||
99 | bool | |
cbe61d8a | 100 | ath9k_hw_ar9280_set_channel(struct ath_hw *ah, |
f078f209 LR |
101 | struct ath9k_channel *chan) |
102 | { | |
103 | u16 bMode, fracMode, aModeRefSel = 0; | |
104 | u32 freq, ndiv, channelSel = 0, channelFrac = 0, reg32 = 0; | |
105 | struct chan_centers centers; | |
106 | u32 refDivA = 24; | |
107 | ||
108 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | |
109 | freq = centers.synth_center; | |
110 | ||
111 | reg32 = REG_READ(ah, AR_PHY_SYNTH_CONTROL); | |
112 | reg32 &= 0xc0000000; | |
113 | ||
114 | if (freq < 4800) { | |
115 | u32 txctl; | |
116 | ||
117 | bMode = 1; | |
118 | fracMode = 1; | |
119 | aModeRefSel = 0; | |
120 | channelSel = (freq * 0x10000) / 15; | |
121 | ||
122 | txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL); | |
123 | if (freq == 2484) { | |
124 | ||
125 | REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, | |
126 | txctl | AR_PHY_CCK_TX_CTRL_JAPAN); | |
127 | } else { | |
128 | REG_WRITE(ah, AR_PHY_CCK_TX_CTRL, | |
129 | txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN); | |
130 | } | |
131 | } else { | |
132 | bMode = 0; | |
133 | fracMode = 0; | |
134 | ||
06d0f066 S |
135 | switch(ah->eep_ops->get_eeprom(ah, EEP_FRAC_N_5G)) { |
136 | case 0: | |
137 | if ((freq % 20) == 0) { | |
138 | aModeRefSel = 3; | |
139 | } else if ((freq % 10) == 0) { | |
140 | aModeRefSel = 2; | |
141 | } | |
142 | if (aModeRefSel) | |
143 | break; | |
144 | case 1: | |
145 | default: | |
f078f209 | 146 | aModeRefSel = 0; |
f078f209 LR |
147 | fracMode = 1; |
148 | refDivA = 1; | |
149 | channelSel = (freq * 0x8000) / 15; | |
150 | ||
151 | REG_RMW_FIELD(ah, AR_AN_SYNTH9, | |
152 | AR_AN_SYNTH9_REFDIVA, refDivA); | |
06d0f066 | 153 | |
f078f209 | 154 | } |
06d0f066 | 155 | |
f078f209 LR |
156 | if (!fracMode) { |
157 | ndiv = (freq * (refDivA >> aModeRefSel)) / 60; | |
158 | channelSel = ndiv & 0x1ff; | |
159 | channelFrac = (ndiv & 0xfffffe00) * 2; | |
160 | channelSel = (channelSel << 17) | channelFrac; | |
161 | } | |
162 | } | |
163 | ||
164 | reg32 = reg32 | | |
165 | (bMode << 29) | | |
166 | (fracMode << 28) | (aModeRefSel << 26) | (channelSel); | |
167 | ||
168 | REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32); | |
169 | ||
2660b81a S |
170 | ah->curchan = chan; |
171 | ah->curchan_rad_index = -1; | |
f078f209 LR |
172 | |
173 | return true; | |
174 | } | |
175 | ||
176 | static void | |
177 | ath9k_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32, | |
178 | u32 numBits, u32 firstBit, | |
179 | u32 column) | |
180 | { | |
181 | u32 tmp32, mask, arrayEntry, lastBit; | |
182 | int32_t bitPosition, bitsLeft; | |
183 | ||
184 | tmp32 = ath9k_hw_reverse_bits(reg32, numBits); | |
185 | arrayEntry = (firstBit - 1) / 8; | |
186 | bitPosition = (firstBit - 1) % 8; | |
187 | bitsLeft = numBits; | |
188 | while (bitsLeft > 0) { | |
189 | lastBit = (bitPosition + bitsLeft > 8) ? | |
190 | 8 : bitPosition + bitsLeft; | |
191 | mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) << | |
192 | (column * 8); | |
193 | rfBuf[arrayEntry] &= ~mask; | |
194 | rfBuf[arrayEntry] |= ((tmp32 << bitPosition) << | |
195 | (column * 8)) & mask; | |
196 | bitsLeft -= 8 - bitPosition; | |
197 | tmp32 = tmp32 >> (8 - bitPosition); | |
198 | bitPosition = 0; | |
199 | arrayEntry++; | |
200 | } | |
201 | } | |
202 | ||
203 | bool | |
cbe61d8a | 204 | ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, |
f078f209 LR |
205 | u16 modesIndex) |
206 | { | |
f078f209 LR |
207 | u32 eepMinorRev; |
208 | u32 ob5GHz = 0, db5GHz = 0; | |
209 | u32 ob2GHz = 0, db2GHz = 0; | |
210 | int regWrites = 0; | |
211 | ||
212 | if (AR_SREV_9280_10_OR_LATER(ah)) | |
213 | return true; | |
214 | ||
f74df6fb | 215 | eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV); |
f078f209 | 216 | |
2660b81a | 217 | RF_BANK_SETUP(ah->analogBank0Data, &ah->iniBank0, 1); |
f078f209 | 218 | |
2660b81a | 219 | RF_BANK_SETUP(ah->analogBank1Data, &ah->iniBank1, 1); |
f078f209 | 220 | |
2660b81a | 221 | RF_BANK_SETUP(ah->analogBank2Data, &ah->iniBank2, 1); |
f078f209 | 222 | |
2660b81a | 223 | RF_BANK_SETUP(ah->analogBank3Data, &ah->iniBank3, |
f078f209 LR |
224 | modesIndex); |
225 | { | |
226 | int i; | |
2660b81a S |
227 | for (i = 0; i < ah->iniBank6TPC.ia_rows; i++) { |
228 | ah->analogBank6Data[i] = | |
229 | INI_RA(&ah->iniBank6TPC, i, modesIndex); | |
f078f209 LR |
230 | } |
231 | } | |
232 | ||
233 | if (eepMinorRev >= 2) { | |
234 | if (IS_CHAN_2GHZ(chan)) { | |
f74df6fb S |
235 | ob2GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_2); |
236 | db2GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_2); | |
2660b81a | 237 | ath9k_phy_modify_rx_buffer(ah->analogBank6Data, |
f078f209 | 238 | ob2GHz, 3, 197, 0); |
2660b81a | 239 | ath9k_phy_modify_rx_buffer(ah->analogBank6Data, |
f078f209 LR |
240 | db2GHz, 3, 194, 0); |
241 | } else { | |
f74df6fb S |
242 | ob5GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_5); |
243 | db5GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_5); | |
2660b81a | 244 | ath9k_phy_modify_rx_buffer(ah->analogBank6Data, |
f078f209 | 245 | ob5GHz, 3, 203, 0); |
2660b81a | 246 | ath9k_phy_modify_rx_buffer(ah->analogBank6Data, |
f078f209 LR |
247 | db5GHz, 3, 200, 0); |
248 | } | |
249 | } | |
250 | ||
2660b81a | 251 | RF_BANK_SETUP(ah->analogBank7Data, &ah->iniBank7, 1); |
f078f209 | 252 | |
2660b81a | 253 | REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data, |
f078f209 | 254 | regWrites); |
2660b81a | 255 | REG_WRITE_RF_ARRAY(&ah->iniBank1, ah->analogBank1Data, |
f078f209 | 256 | regWrites); |
2660b81a | 257 | REG_WRITE_RF_ARRAY(&ah->iniBank2, ah->analogBank2Data, |
f078f209 | 258 | regWrites); |
2660b81a | 259 | REG_WRITE_RF_ARRAY(&ah->iniBank3, ah->analogBank3Data, |
f078f209 | 260 | regWrites); |
2660b81a | 261 | REG_WRITE_RF_ARRAY(&ah->iniBank6TPC, ah->analogBank6Data, |
f078f209 | 262 | regWrites); |
2660b81a | 263 | REG_WRITE_RF_ARRAY(&ah->iniBank7, ah->analogBank7Data, |
f078f209 LR |
264 | regWrites); |
265 | ||
266 | return true; | |
267 | } | |
268 | ||
269 | void | |
cbe61d8a | 270 | ath9k_hw_rfdetach(struct ath_hw *ah) |
f078f209 | 271 | { |
2660b81a S |
272 | if (ah->analogBank0Data != NULL) { |
273 | kfree(ah->analogBank0Data); | |
274 | ah->analogBank0Data = NULL; | |
f078f209 | 275 | } |
2660b81a S |
276 | if (ah->analogBank1Data != NULL) { |
277 | kfree(ah->analogBank1Data); | |
278 | ah->analogBank1Data = NULL; | |
f078f209 | 279 | } |
2660b81a S |
280 | if (ah->analogBank2Data != NULL) { |
281 | kfree(ah->analogBank2Data); | |
282 | ah->analogBank2Data = NULL; | |
f078f209 | 283 | } |
2660b81a S |
284 | if (ah->analogBank3Data != NULL) { |
285 | kfree(ah->analogBank3Data); | |
286 | ah->analogBank3Data = NULL; | |
f078f209 | 287 | } |
2660b81a S |
288 | if (ah->analogBank6Data != NULL) { |
289 | kfree(ah->analogBank6Data); | |
290 | ah->analogBank6Data = NULL; | |
f078f209 | 291 | } |
2660b81a S |
292 | if (ah->analogBank6TPCData != NULL) { |
293 | kfree(ah->analogBank6TPCData); | |
294 | ah->analogBank6TPCData = NULL; | |
f078f209 | 295 | } |
2660b81a S |
296 | if (ah->analogBank7Data != NULL) { |
297 | kfree(ah->analogBank7Data); | |
298 | ah->analogBank7Data = NULL; | |
f078f209 | 299 | } |
2660b81a S |
300 | if (ah->addac5416_21 != NULL) { |
301 | kfree(ah->addac5416_21); | |
302 | ah->addac5416_21 = NULL; | |
f078f209 | 303 | } |
2660b81a S |
304 | if (ah->bank6Temp != NULL) { |
305 | kfree(ah->bank6Temp); | |
306 | ah->bank6Temp = NULL; | |
f078f209 LR |
307 | } |
308 | } | |
309 | ||
cbe61d8a | 310 | bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) |
f078f209 | 311 | { |
f078f209 | 312 | if (!AR_SREV_9280_10_OR_LATER(ah)) { |
2660b81a | 313 | ah->analogBank0Data = |
f078f209 | 314 | kzalloc((sizeof(u32) * |
2660b81a S |
315 | ah->iniBank0.ia_rows), GFP_KERNEL); |
316 | ah->analogBank1Data = | |
f078f209 | 317 | kzalloc((sizeof(u32) * |
2660b81a S |
318 | ah->iniBank1.ia_rows), GFP_KERNEL); |
319 | ah->analogBank2Data = | |
f078f209 | 320 | kzalloc((sizeof(u32) * |
2660b81a S |
321 | ah->iniBank2.ia_rows), GFP_KERNEL); |
322 | ah->analogBank3Data = | |
f078f209 | 323 | kzalloc((sizeof(u32) * |
2660b81a S |
324 | ah->iniBank3.ia_rows), GFP_KERNEL); |
325 | ah->analogBank6Data = | |
f078f209 | 326 | kzalloc((sizeof(u32) * |
2660b81a S |
327 | ah->iniBank6.ia_rows), GFP_KERNEL); |
328 | ah->analogBank6TPCData = | |
f078f209 | 329 | kzalloc((sizeof(u32) * |
2660b81a S |
330 | ah->iniBank6TPC.ia_rows), GFP_KERNEL); |
331 | ah->analogBank7Data = | |
f078f209 | 332 | kzalloc((sizeof(u32) * |
2660b81a S |
333 | ah->iniBank7.ia_rows), GFP_KERNEL); |
334 | ||
335 | if (ah->analogBank0Data == NULL | |
336 | || ah->analogBank1Data == NULL | |
337 | || ah->analogBank2Data == NULL | |
338 | || ah->analogBank3Data == NULL | |
339 | || ah->analogBank6Data == NULL | |
340 | || ah->analogBank6TPCData == NULL | |
341 | || ah->analogBank7Data == NULL) { | |
f078f209 | 342 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, |
04bd4638 | 343 | "Cannot allocate RF banks\n"); |
f078f209 LR |
344 | *status = -ENOMEM; |
345 | return false; | |
346 | } | |
347 | ||
2660b81a | 348 | ah->addac5416_21 = |
f078f209 | 349 | kzalloc((sizeof(u32) * |
2660b81a S |
350 | ah->iniAddac.ia_rows * |
351 | ah->iniAddac.ia_columns), GFP_KERNEL); | |
352 | if (ah->addac5416_21 == NULL) { | |
f078f209 | 353 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, |
2660b81a | 354 | "Cannot allocate addac5416_21\n"); |
f078f209 LR |
355 | *status = -ENOMEM; |
356 | return false; | |
357 | } | |
358 | ||
2660b81a | 359 | ah->bank6Temp = |
f078f209 | 360 | kzalloc((sizeof(u32) * |
2660b81a S |
361 | ah->iniBank6.ia_rows), GFP_KERNEL); |
362 | if (ah->bank6Temp == NULL) { | |
f078f209 | 363 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, |
2660b81a | 364 | "Cannot allocate bank6Temp\n"); |
f078f209 LR |
365 | *status = -ENOMEM; |
366 | return false; | |
367 | } | |
368 | } | |
369 | ||
370 | return true; | |
371 | } | |
372 | ||
373 | void | |
cbe61d8a | 374 | ath9k_hw_decrease_chain_power(struct ath_hw *ah, struct ath9k_channel *chan) |
f078f209 LR |
375 | { |
376 | int i, regWrites = 0; | |
f078f209 | 377 | u32 bank6SelMask; |
2660b81a | 378 | u32 *bank6Temp = ah->bank6Temp; |
f078f209 | 379 | |
2660b81a | 380 | switch (ah->diversity_control) { |
f078f209 LR |
381 | case ATH9K_ANT_FIXED_A: |
382 | bank6SelMask = | |
cbe61d8a | 383 | (ah-> |
2660b81a | 384 | antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_0 : |
f078f209 LR |
385 | REDUCE_CHAIN_1; |
386 | break; | |
387 | case ATH9K_ANT_FIXED_B: | |
388 | bank6SelMask = | |
cbe61d8a | 389 | (ah-> |
2660b81a | 390 | antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_1 : |
f078f209 LR |
391 | REDUCE_CHAIN_0; |
392 | break; | |
393 | case ATH9K_ANT_VARIABLE: | |
394 | return; | |
395 | break; | |
396 | default: | |
397 | return; | |
398 | break; | |
399 | } | |
400 | ||
2660b81a S |
401 | for (i = 0; i < ah->iniBank6.ia_rows; i++) |
402 | bank6Temp[i] = ah->analogBank6Data[i]; | |
f078f209 LR |
403 | |
404 | REG_WRITE(ah, AR_PHY_BASE + 0xD8, bank6SelMask); | |
405 | ||
406 | ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 189, 0); | |
407 | ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 190, 0); | |
408 | ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 191, 0); | |
409 | ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 192, 0); | |
410 | ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 193, 0); | |
411 | ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 222, 0); | |
412 | ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 245, 0); | |
413 | ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 246, 0); | |
414 | ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 247, 0); | |
415 | ||
2660b81a | 416 | REG_WRITE_RF_ARRAY(&ah->iniBank6, bank6Temp, regWrites); |
f078f209 LR |
417 | |
418 | REG_WRITE(ah, AR_PHY_BASE + 0xD8, 0x00000053); | |
419 | #ifdef ALTER_SWITCH | |
420 | REG_WRITE(ah, PHY_SWITCH_CHAIN_0, | |
421 | (REG_READ(ah, PHY_SWITCH_CHAIN_0) & ~0x38) | |
422 | | ((REG_READ(ah, PHY_SWITCH_CHAIN_0) >> 3) & 0x38)); | |
423 | #endif | |
424 | } |