Commit | Line | Data |
---|---|---|
f078f209 LR |
1 | /* |
2 | * Copyright (c) 2008 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 | ||
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 | ||
135 | if ((freq % 20) == 0) { | |
136 | aModeRefSel = 3; | |
137 | } else if ((freq % 10) == 0) { | |
138 | aModeRefSel = 2; | |
139 | } else { | |
140 | aModeRefSel = 0; | |
141 | ||
142 | fracMode = 1; | |
143 | refDivA = 1; | |
144 | channelSel = (freq * 0x8000) / 15; | |
145 | ||
146 | REG_RMW_FIELD(ah, AR_AN_SYNTH9, | |
147 | AR_AN_SYNTH9_REFDIVA, refDivA); | |
148 | } | |
149 | if (!fracMode) { | |
150 | ndiv = (freq * (refDivA >> aModeRefSel)) / 60; | |
151 | channelSel = ndiv & 0x1ff; | |
152 | channelFrac = (ndiv & 0xfffffe00) * 2; | |
153 | channelSel = (channelSel << 17) | channelFrac; | |
154 | } | |
155 | } | |
156 | ||
157 | reg32 = reg32 | | |
158 | (bMode << 29) | | |
159 | (fracMode << 28) | (aModeRefSel << 26) | (channelSel); | |
160 | ||
161 | REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32); | |
162 | ||
2660b81a S |
163 | ah->curchan = chan; |
164 | ah->curchan_rad_index = -1; | |
f078f209 LR |
165 | |
166 | return true; | |
167 | } | |
168 | ||
169 | static void | |
170 | ath9k_phy_modify_rx_buffer(u32 *rfBuf, u32 reg32, | |
171 | u32 numBits, u32 firstBit, | |
172 | u32 column) | |
173 | { | |
174 | u32 tmp32, mask, arrayEntry, lastBit; | |
175 | int32_t bitPosition, bitsLeft; | |
176 | ||
177 | tmp32 = ath9k_hw_reverse_bits(reg32, numBits); | |
178 | arrayEntry = (firstBit - 1) / 8; | |
179 | bitPosition = (firstBit - 1) % 8; | |
180 | bitsLeft = numBits; | |
181 | while (bitsLeft > 0) { | |
182 | lastBit = (bitPosition + bitsLeft > 8) ? | |
183 | 8 : bitPosition + bitsLeft; | |
184 | mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) << | |
185 | (column * 8); | |
186 | rfBuf[arrayEntry] &= ~mask; | |
187 | rfBuf[arrayEntry] |= ((tmp32 << bitPosition) << | |
188 | (column * 8)) & mask; | |
189 | bitsLeft -= 8 - bitPosition; | |
190 | tmp32 = tmp32 >> (8 - bitPosition); | |
191 | bitPosition = 0; | |
192 | arrayEntry++; | |
193 | } | |
194 | } | |
195 | ||
196 | bool | |
cbe61d8a | 197 | ath9k_hw_set_rf_regs(struct ath_hw *ah, struct ath9k_channel *chan, |
f078f209 LR |
198 | u16 modesIndex) |
199 | { | |
f078f209 LR |
200 | u32 eepMinorRev; |
201 | u32 ob5GHz = 0, db5GHz = 0; | |
202 | u32 ob2GHz = 0, db2GHz = 0; | |
203 | int regWrites = 0; | |
204 | ||
205 | if (AR_SREV_9280_10_OR_LATER(ah)) | |
206 | return true; | |
207 | ||
f74df6fb | 208 | eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV); |
f078f209 | 209 | |
2660b81a | 210 | RF_BANK_SETUP(ah->analogBank0Data, &ah->iniBank0, 1); |
f078f209 | 211 | |
2660b81a | 212 | RF_BANK_SETUP(ah->analogBank1Data, &ah->iniBank1, 1); |
f078f209 | 213 | |
2660b81a | 214 | RF_BANK_SETUP(ah->analogBank2Data, &ah->iniBank2, 1); |
f078f209 | 215 | |
2660b81a | 216 | RF_BANK_SETUP(ah->analogBank3Data, &ah->iniBank3, |
f078f209 LR |
217 | modesIndex); |
218 | { | |
219 | int i; | |
2660b81a S |
220 | for (i = 0; i < ah->iniBank6TPC.ia_rows; i++) { |
221 | ah->analogBank6Data[i] = | |
222 | INI_RA(&ah->iniBank6TPC, i, modesIndex); | |
f078f209 LR |
223 | } |
224 | } | |
225 | ||
226 | if (eepMinorRev >= 2) { | |
227 | if (IS_CHAN_2GHZ(chan)) { | |
f74df6fb S |
228 | ob2GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_2); |
229 | db2GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_2); | |
2660b81a | 230 | ath9k_phy_modify_rx_buffer(ah->analogBank6Data, |
f078f209 | 231 | ob2GHz, 3, 197, 0); |
2660b81a | 232 | ath9k_phy_modify_rx_buffer(ah->analogBank6Data, |
f078f209 LR |
233 | db2GHz, 3, 194, 0); |
234 | } else { | |
f74df6fb S |
235 | ob5GHz = ah->eep_ops->get_eeprom(ah, EEP_OB_5); |
236 | db5GHz = ah->eep_ops->get_eeprom(ah, EEP_DB_5); | |
2660b81a | 237 | ath9k_phy_modify_rx_buffer(ah->analogBank6Data, |
f078f209 | 238 | ob5GHz, 3, 203, 0); |
2660b81a | 239 | ath9k_phy_modify_rx_buffer(ah->analogBank6Data, |
f078f209 LR |
240 | db5GHz, 3, 200, 0); |
241 | } | |
242 | } | |
243 | ||
2660b81a | 244 | RF_BANK_SETUP(ah->analogBank7Data, &ah->iniBank7, 1); |
f078f209 | 245 | |
2660b81a | 246 | REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data, |
f078f209 | 247 | regWrites); |
2660b81a | 248 | REG_WRITE_RF_ARRAY(&ah->iniBank1, ah->analogBank1Data, |
f078f209 | 249 | regWrites); |
2660b81a | 250 | REG_WRITE_RF_ARRAY(&ah->iniBank2, ah->analogBank2Data, |
f078f209 | 251 | regWrites); |
2660b81a | 252 | REG_WRITE_RF_ARRAY(&ah->iniBank3, ah->analogBank3Data, |
f078f209 | 253 | regWrites); |
2660b81a | 254 | REG_WRITE_RF_ARRAY(&ah->iniBank6TPC, ah->analogBank6Data, |
f078f209 | 255 | regWrites); |
2660b81a | 256 | REG_WRITE_RF_ARRAY(&ah->iniBank7, ah->analogBank7Data, |
f078f209 LR |
257 | regWrites); |
258 | ||
259 | return true; | |
260 | } | |
261 | ||
262 | void | |
cbe61d8a | 263 | ath9k_hw_rfdetach(struct ath_hw *ah) |
f078f209 | 264 | { |
2660b81a S |
265 | if (ah->analogBank0Data != NULL) { |
266 | kfree(ah->analogBank0Data); | |
267 | ah->analogBank0Data = NULL; | |
f078f209 | 268 | } |
2660b81a S |
269 | if (ah->analogBank1Data != NULL) { |
270 | kfree(ah->analogBank1Data); | |
271 | ah->analogBank1Data = NULL; | |
f078f209 | 272 | } |
2660b81a S |
273 | if (ah->analogBank2Data != NULL) { |
274 | kfree(ah->analogBank2Data); | |
275 | ah->analogBank2Data = NULL; | |
f078f209 | 276 | } |
2660b81a S |
277 | if (ah->analogBank3Data != NULL) { |
278 | kfree(ah->analogBank3Data); | |
279 | ah->analogBank3Data = NULL; | |
f078f209 | 280 | } |
2660b81a S |
281 | if (ah->analogBank6Data != NULL) { |
282 | kfree(ah->analogBank6Data); | |
283 | ah->analogBank6Data = NULL; | |
f078f209 | 284 | } |
2660b81a S |
285 | if (ah->analogBank6TPCData != NULL) { |
286 | kfree(ah->analogBank6TPCData); | |
287 | ah->analogBank6TPCData = NULL; | |
f078f209 | 288 | } |
2660b81a S |
289 | if (ah->analogBank7Data != NULL) { |
290 | kfree(ah->analogBank7Data); | |
291 | ah->analogBank7Data = NULL; | |
f078f209 | 292 | } |
2660b81a S |
293 | if (ah->addac5416_21 != NULL) { |
294 | kfree(ah->addac5416_21); | |
295 | ah->addac5416_21 = NULL; | |
f078f209 | 296 | } |
2660b81a S |
297 | if (ah->bank6Temp != NULL) { |
298 | kfree(ah->bank6Temp); | |
299 | ah->bank6Temp = NULL; | |
f078f209 LR |
300 | } |
301 | } | |
302 | ||
cbe61d8a | 303 | bool ath9k_hw_init_rf(struct ath_hw *ah, int *status) |
f078f209 | 304 | { |
f078f209 | 305 | if (!AR_SREV_9280_10_OR_LATER(ah)) { |
2660b81a | 306 | ah->analogBank0Data = |
f078f209 | 307 | kzalloc((sizeof(u32) * |
2660b81a S |
308 | ah->iniBank0.ia_rows), GFP_KERNEL); |
309 | ah->analogBank1Data = | |
f078f209 | 310 | kzalloc((sizeof(u32) * |
2660b81a S |
311 | ah->iniBank1.ia_rows), GFP_KERNEL); |
312 | ah->analogBank2Data = | |
f078f209 | 313 | kzalloc((sizeof(u32) * |
2660b81a S |
314 | ah->iniBank2.ia_rows), GFP_KERNEL); |
315 | ah->analogBank3Data = | |
f078f209 | 316 | kzalloc((sizeof(u32) * |
2660b81a S |
317 | ah->iniBank3.ia_rows), GFP_KERNEL); |
318 | ah->analogBank6Data = | |
f078f209 | 319 | kzalloc((sizeof(u32) * |
2660b81a S |
320 | ah->iniBank6.ia_rows), GFP_KERNEL); |
321 | ah->analogBank6TPCData = | |
f078f209 | 322 | kzalloc((sizeof(u32) * |
2660b81a S |
323 | ah->iniBank6TPC.ia_rows), GFP_KERNEL); |
324 | ah->analogBank7Data = | |
f078f209 | 325 | kzalloc((sizeof(u32) * |
2660b81a S |
326 | ah->iniBank7.ia_rows), GFP_KERNEL); |
327 | ||
328 | if (ah->analogBank0Data == NULL | |
329 | || ah->analogBank1Data == NULL | |
330 | || ah->analogBank2Data == NULL | |
331 | || ah->analogBank3Data == NULL | |
332 | || ah->analogBank6Data == NULL | |
333 | || ah->analogBank6TPCData == NULL | |
334 | || ah->analogBank7Data == NULL) { | |
f078f209 | 335 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, |
04bd4638 | 336 | "Cannot allocate RF banks\n"); |
f078f209 LR |
337 | *status = -ENOMEM; |
338 | return false; | |
339 | } | |
340 | ||
2660b81a | 341 | ah->addac5416_21 = |
f078f209 | 342 | kzalloc((sizeof(u32) * |
2660b81a S |
343 | ah->iniAddac.ia_rows * |
344 | ah->iniAddac.ia_columns), GFP_KERNEL); | |
345 | if (ah->addac5416_21 == NULL) { | |
f078f209 | 346 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, |
2660b81a | 347 | "Cannot allocate addac5416_21\n"); |
f078f209 LR |
348 | *status = -ENOMEM; |
349 | return false; | |
350 | } | |
351 | ||
2660b81a | 352 | ah->bank6Temp = |
f078f209 | 353 | kzalloc((sizeof(u32) * |
2660b81a S |
354 | ah->iniBank6.ia_rows), GFP_KERNEL); |
355 | if (ah->bank6Temp == NULL) { | |
f078f209 | 356 | DPRINTF(ah->ah_sc, ATH_DBG_FATAL, |
2660b81a | 357 | "Cannot allocate bank6Temp\n"); |
f078f209 LR |
358 | *status = -ENOMEM; |
359 | return false; | |
360 | } | |
361 | } | |
362 | ||
363 | return true; | |
364 | } | |
365 | ||
366 | void | |
cbe61d8a | 367 | ath9k_hw_decrease_chain_power(struct ath_hw *ah, struct ath9k_channel *chan) |
f078f209 LR |
368 | { |
369 | int i, regWrites = 0; | |
f078f209 | 370 | u32 bank6SelMask; |
2660b81a | 371 | u32 *bank6Temp = ah->bank6Temp; |
f078f209 | 372 | |
2660b81a | 373 | switch (ah->diversity_control) { |
f078f209 LR |
374 | case ATH9K_ANT_FIXED_A: |
375 | bank6SelMask = | |
cbe61d8a | 376 | (ah-> |
2660b81a | 377 | antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_0 : |
f078f209 LR |
378 | REDUCE_CHAIN_1; |
379 | break; | |
380 | case ATH9K_ANT_FIXED_B: | |
381 | bank6SelMask = | |
cbe61d8a | 382 | (ah-> |
2660b81a | 383 | antenna_switch_swap & ANTSWAP_AB) ? REDUCE_CHAIN_1 : |
f078f209 LR |
384 | REDUCE_CHAIN_0; |
385 | break; | |
386 | case ATH9K_ANT_VARIABLE: | |
387 | return; | |
388 | break; | |
389 | default: | |
390 | return; | |
391 | break; | |
392 | } | |
393 | ||
2660b81a S |
394 | for (i = 0; i < ah->iniBank6.ia_rows; i++) |
395 | bank6Temp[i] = ah->analogBank6Data[i]; | |
f078f209 LR |
396 | |
397 | REG_WRITE(ah, AR_PHY_BASE + 0xD8, bank6SelMask); | |
398 | ||
399 | ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 189, 0); | |
400 | ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 190, 0); | |
401 | ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 191, 0); | |
402 | ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 192, 0); | |
403 | ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 193, 0); | |
404 | ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 222, 0); | |
405 | ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 245, 0); | |
406 | ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 246, 0); | |
407 | ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 247, 0); | |
408 | ||
2660b81a | 409 | REG_WRITE_RF_ARRAY(&ah->iniBank6, bank6Temp, regWrites); |
f078f209 LR |
410 | |
411 | REG_WRITE(ah, AR_PHY_BASE + 0xD8, 0x00000053); | |
412 | #ifdef ALTER_SWITCH | |
413 | REG_WRITE(ah, PHY_SWITCH_CHAIN_0, | |
414 | (REG_READ(ah, PHY_SWITCH_CHAIN_0) & ~0x38) | |
415 | | ((REG_READ(ah, PHY_SWITCH_CHAIN_0) >> 3) & 0x38)); | |
416 | #endif | |
417 | } |