1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * Copyright (c) 2008 Atheros Communications Inc.
8 *
9 * Permission to use, copy, modify, and/or distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21
22 #include "arn_core.h"
23 #include "arn_hw.h"
24 #include "arn_reg.h"
25 #include "arn_phy.h"
26
27 /* ARGSUSED */
28 void
ath9k_hw_write_regs(struct ath_hal * ah,uint32_t modesIndex,uint32_t freqIndex,int regWrites)29 ath9k_hw_write_regs(struct ath_hal *ah, uint32_t modesIndex, uint32_t freqIndex,
30 int regWrites)
31 {
32 struct ath_hal_5416 *ahp = AH5416(ah);
33
34 /* LINTED: E_CONSTANT_CONDITION */
35 REG_WRITE_ARRAY(&ahp->ah_iniBB_RfGain, freqIndex, regWrites);
36 }
37
38 boolean_t
ath9k_hw_set_channel(struct ath_hal * ah,struct ath9k_channel * chan)39 ath9k_hw_set_channel(struct ath_hal *ah, struct ath9k_channel *chan)
40 {
41 uint32_t channelSel = 0;
42 uint32_t bModeSynth = 0;
43 uint32_t aModeRefSel = 0;
44 uint32_t reg32 = 0;
45 uint16_t freq;
46 struct chan_centers centers;
47
48 ath9k_hw_get_channel_centers(ah, chan, ¢ers);
49 freq = centers.synth_center;
50
51 if (freq < 4800) {
52 uint32_t txctl;
53
54 if (((freq - 2192) % 5) == 0) {
55 channelSel = ((freq - 672) * 2 - 3040) / 10;
56 bModeSynth = 0;
57 } else if (((freq - 2224) % 5) == 0) {
58 channelSel = ((freq - 704) * 2 - 3040) / 10;
59 bModeSynth = 1;
60 } else {
61 arn_problem("%s: invalid channel %u MHz\n",
62 __func__, freq);
63 return (B_FALSE);
64 }
65
66 channelSel = (channelSel << 2) & 0xff;
67 channelSel = ath9k_hw_reverse_bits(channelSel, 8);
68
69 txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL);
70 if (freq == 2484) {
71
72 REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
73 txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
74 } else {
75 REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
76 txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN);
77 }
78
79 } else if ((freq % 20) == 0 && freq >= 5120) {
80 channelSel =
81 ath9k_hw_reverse_bits(((freq - 4800) / 20 << 2), 8);
82 aModeRefSel = ath9k_hw_reverse_bits(1, 2);
83 } else if ((freq % 10) == 0) {
84 channelSel =
85 ath9k_hw_reverse_bits(((freq - 4800) / 10 << 1), 8);
86 if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah))
87 aModeRefSel = ath9k_hw_reverse_bits(2, 2);
88 else
89 aModeRefSel = ath9k_hw_reverse_bits(1, 2);
90 } else if ((freq % 5) == 0) {
91 channelSel = ath9k_hw_reverse_bits((freq - 4800) / 5, 8);
92 aModeRefSel = ath9k_hw_reverse_bits(1, 2);
93 } else {
94 arn_problem("%s: invalid channel %u MHz\n", __func__, freq);
95 return (B_FALSE);
96 }
97
98 reg32 =
99 (channelSel << 8) | (aModeRefSel << 2) | (bModeSynth << 1) |
100 (1 << 5) | 0x1;
101
102 REG_WRITE(ah, AR_PHY(0x37), reg32);
103
104 ah->ah_curchan = chan;
105
106 AH5416(ah)->ah_curchanRadIndex = -1;
107
108 return (B_TRUE);
109 }
110
111 boolean_t
ath9k_hw_ar9280_set_channel(struct ath_hal * ah,struct ath9k_channel * chan)112 ath9k_hw_ar9280_set_channel(struct ath_hal *ah,
113 struct ath9k_channel *chan)
114 {
115 uint16_t bMode, fracMode, aModeRefSel = 0;
116 uint32_t freq, ndiv, channelSel = 0, channelFrac = 0, reg32 = 0;
117 struct chan_centers centers;
118 uint32_t refDivA = 24;
119
120 ath9k_hw_get_channel_centers(ah, chan, ¢ers);
121 freq = centers.synth_center;
122
123 reg32 = REG_READ(ah, AR_PHY_SYNTH_CONTROL);
124 reg32 &= 0xc0000000;
125
126 if (freq < 4800) {
127 uint32_t txctl;
128
129 bMode = 1;
130 fracMode = 1;
131 aModeRefSel = 0;
132 channelSel = (freq * 0x10000) / 15;
133
134 txctl = REG_READ(ah, AR_PHY_CCK_TX_CTRL);
135 if (freq == 2484) {
136
137 REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
138 txctl | AR_PHY_CCK_TX_CTRL_JAPAN);
139 } else {
140 REG_WRITE(ah, AR_PHY_CCK_TX_CTRL,
141 txctl & ~AR_PHY_CCK_TX_CTRL_JAPAN);
142 }
143 } else {
144 bMode = 0;
145 fracMode = 0;
146
147 if ((freq % 20) == 0) {
148 aModeRefSel = 3;
149 } else if ((freq % 10) == 0) {
150 aModeRefSel = 2;
151 } else {
152 aModeRefSel = 0;
153
154 fracMode = 1;
155 refDivA = 1;
156 channelSel = (freq * 0x8000) / 15;
157
158 REG_RMW_FIELD(ah, AR_AN_SYNTH9,
159 AR_AN_SYNTH9_REFDIVA, refDivA);
160 }
161 if (!fracMode) {
162 ndiv = (freq * (refDivA >> aModeRefSel)) / 60;
163 channelSel = ndiv & 0x1ff;
164 channelFrac = (ndiv & 0xfffffe00) * 2;
165 channelSel = (channelSel << 17) | channelFrac;
166 }
167 }
168
169 reg32 = reg32 |
170 (bMode << 29) |
171 (fracMode << 28) | (aModeRefSel << 26) | (channelSel);
172
173 REG_WRITE(ah, AR_PHY_SYNTH_CONTROL, reg32);
174
175 ah->ah_curchan = chan;
176
177 AH5416(ah)->ah_curchanRadIndex = -1;
178
179 return (B_TRUE);
180 }
181
182 static void
ath9k_phy_modify_rx_buffer(uint32_t * rfBuf,uint32_t reg32,uint32_t numBits,uint32_t firstBit,uint32_t column)183 ath9k_phy_modify_rx_buffer(uint32_t *rfBuf, uint32_t reg32,
184 uint32_t numBits, uint32_t firstBit, uint32_t column)
185 {
186 uint32_t tmp32, mask, arrayEntry, lastBit;
187 int32_t bitPosition, bitsLeft;
188
189 tmp32 = ath9k_hw_reverse_bits(reg32, numBits);
190 arrayEntry = (firstBit - 1) / 8;
191 bitPosition = (firstBit - 1) % 8;
192 bitsLeft = numBits;
193 while (bitsLeft > 0) {
194 lastBit = (bitPosition + bitsLeft > 8) ?
195 8 : bitPosition + bitsLeft;
196 mask = (((1 << lastBit) - 1) ^ ((1 << bitPosition) - 1)) <<
197 (column * 8);
198 rfBuf[arrayEntry] &= ~mask;
199 rfBuf[arrayEntry] |= ((tmp32 << bitPosition) <<
200 (column * 8)) & mask;
201 bitsLeft -= 8 - bitPosition;
202 tmp32 = tmp32 >> (8 - bitPosition);
203 bitPosition = 0;
204 arrayEntry++;
205 }
206 }
207
208 boolean_t
ath9k_hw_set_rf_regs(struct ath_hal * ah,struct ath9k_channel * chan,uint16_t modesIndex)209 ath9k_hw_set_rf_regs(struct ath_hal *ah, struct ath9k_channel *chan,
210 uint16_t modesIndex)
211 {
212 struct ath_hal_5416 *ahp = AH5416(ah);
213
214 uint32_t eepMinorRev;
215 uint32_t ob5GHz = 0, db5GHz = 0;
216 uint32_t ob2GHz = 0, db2GHz = 0;
217 /* LINTED E_FUNC_SET_NOT_USED */
218 int regWrites = 0;
219
220 if (AR_SREV_9280_10_OR_LATER(ah))
221 return (B_TRUE);
222
223 eepMinorRev = ath9k_hw_get_eeprom(ah, EEP_MINOR_REV);
224
225 RF_BANK_SETUP(ahp->ah_analogBank0Data, &ahp->ah_iniBank0, 1);
226
227 RF_BANK_SETUP(ahp->ah_analogBank1Data, &ahp->ah_iniBank1, 1);
228
229 RF_BANK_SETUP(ahp->ah_analogBank2Data, &ahp->ah_iniBank2, 1);
230
231 RF_BANK_SETUP(ahp->ah_analogBank3Data, &ahp->ah_iniBank3,
232 modesIndex);
233 {
234 int i;
235 for (i = 0; i < ahp->ah_iniBank6TPC.ia_rows; i++) {
236 ahp->ah_analogBank6Data[i] =
237 INI_RA(&ahp->ah_iniBank6TPC, i, modesIndex);
238 }
239 }
240
241 if (eepMinorRev >= 2) {
242 if (IS_CHAN_2GHZ(chan)) {
243 ob2GHz = ath9k_hw_get_eeprom(ah, EEP_OB_2);
244 db2GHz = ath9k_hw_get_eeprom(ah, EEP_DB_2);
245 ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
246 ob2GHz, 3, 197, 0);
247 ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
248 db2GHz, 3, 194, 0);
249 } else {
250 ob5GHz = ath9k_hw_get_eeprom(ah, EEP_OB_5);
251 db5GHz = ath9k_hw_get_eeprom(ah, EEP_DB_5);
252 ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
253 ob5GHz, 3, 203, 0);
254 ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data,
255 db5GHz, 3, 200, 0);
256 }
257 }
258
259 RF_BANK_SETUP(ahp->ah_analogBank7Data, &ahp->ah_iniBank7, 1);
260
261 REG_WRITE_RF_ARRAY(&ahp->ah_iniBank0, ahp->ah_analogBank0Data,
262 regWrites);
263
264 REG_WRITE_RF_ARRAY(&ahp->ah_iniBank1, ahp->ah_analogBank1Data,
265 regWrites);
266
267 REG_WRITE_RF_ARRAY(&ahp->ah_iniBank2, ahp->ah_analogBank2Data,
268 regWrites);
269
270 REG_WRITE_RF_ARRAY(&ahp->ah_iniBank3, ahp->ah_analogBank3Data,
271 regWrites);
272
273 REG_WRITE_RF_ARRAY(&ahp->ah_iniBank6TPC, ahp->ah_analogBank6Data,
274 regWrites);
275
276 REG_WRITE_RF_ARRAY(&ahp->ah_iniBank7, ahp->ah_analogBank7Data,
277 regWrites);
278
279 return (B_TRUE);
280 }
281
282 void
ath9k_hw_rfdetach(struct ath_hal * ah)283 ath9k_hw_rfdetach(struct ath_hal *ah)
284 {
285 struct ath_hal_5416 *ahp = AH5416(ah);
286
287 if (ahp->ah_analogBank0Data != NULL) {
288 kmem_free(ahp->ah_analogBank0Data,
289 (sizeof (uint32_t) * ahp->ah_iniBank0.ia_rows));
290 ahp->ah_analogBank0Data = NULL;
291 }
292 if (ahp->ah_analogBank1Data != NULL) {
293 kmem_free(ahp->ah_analogBank1Data,
294 (sizeof (uint32_t) * ahp->ah_iniBank1.ia_rows));
295 ahp->ah_analogBank1Data = NULL;
296 }
297 if (ahp->ah_analogBank2Data != NULL) {
298 kmem_free(ahp->ah_analogBank2Data,
299 (sizeof (uint32_t) * ahp->ah_iniBank2.ia_rows));
300 ahp->ah_analogBank2Data = NULL;
301 }
302 if (ahp->ah_analogBank3Data != NULL) {
303 kmem_free(ahp->ah_analogBank3Data,
304 (sizeof (uint32_t) * ahp->ah_iniBank3.ia_rows));
305 ahp->ah_analogBank3Data = NULL;
306 }
307 if (ahp->ah_analogBank6Data != NULL) {
308 kmem_free(ahp->ah_analogBank6Data,
309 (sizeof (uint32_t) * ahp->ah_iniBank6.ia_rows));
310 ahp->ah_analogBank6Data = NULL;
311 }
312 if (ahp->ah_analogBank6TPCData != NULL) {
313 kmem_free(ahp->ah_analogBank6TPCData,
314 (sizeof (uint32_t) * ahp->ah_iniBank6TPC.ia_rows));
315 ahp->ah_analogBank6TPCData = NULL;
316 }
317 if (ahp->ah_analogBank7Data != NULL) {
318 kmem_free(ahp->ah_analogBank7Data,
319 (sizeof (uint32_t) * ahp->ah_iniBank7.ia_rows));
320 ahp->ah_analogBank7Data = NULL;
321 }
322 if (ahp->ah_addac5416_21 != NULL) {
323 kmem_free(ahp->ah_addac5416_21,
324 (sizeof (uint32_t) * ahp->ah_iniAddac.ia_rows *
325 ahp->ah_iniAddac.ia_columns));
326 ahp->ah_addac5416_21 = NULL;
327 }
328 if (ahp->ah_bank6Temp != NULL) {
329 kmem_free(ahp->ah_bank6Temp,
330 (sizeof (uint32_t) * ahp->ah_iniBank6.ia_rows));
331 ahp->ah_bank6Temp = NULL;
332 }
333 }
334
335 boolean_t
ath9k_hw_init_rf(struct ath_hal * ah,int * status)336 ath9k_hw_init_rf(struct ath_hal *ah, int *status)
337 {
338 struct ath_hal_5416 *ahp = AH5416(ah);
339
340 if (!AR_SREV_9280_10_OR_LATER(ah)) {
341
342 ahp->ah_analogBank0Data =
343 kmem_zalloc((sizeof (uint32_t) *
344 ahp->ah_iniBank0.ia_rows), KM_SLEEP);
345 ahp->ah_analogBank1Data =
346 kmem_zalloc((sizeof (uint32_t) *
347 ahp->ah_iniBank1.ia_rows), KM_SLEEP);
348 ahp->ah_analogBank2Data =
349 kmem_zalloc((sizeof (uint32_t) *
350 ahp->ah_iniBank2.ia_rows), KM_SLEEP);
351 ahp->ah_analogBank3Data =
352 kmem_zalloc((sizeof (uint32_t) *
353 ahp->ah_iniBank3.ia_rows), KM_SLEEP);
354 ahp->ah_analogBank6Data =
355 kmem_zalloc((sizeof (uint32_t) *
356 ahp->ah_iniBank6.ia_rows), KM_SLEEP);
357 ahp->ah_analogBank6TPCData =
358 kmem_zalloc((sizeof (uint32_t) *
359 ahp->ah_iniBank6TPC.ia_rows), KM_SLEEP);
360 ahp->ah_analogBank7Data =
361 kmem_zalloc((sizeof (uint32_t) *
362 ahp->ah_iniBank7.ia_rows), KM_SLEEP);
363
364 if (ahp->ah_analogBank0Data == NULL ||
365 ahp->ah_analogBank1Data == NULL ||
366 ahp->ah_analogBank2Data == NULL ||
367 ahp->ah_analogBank3Data == NULL ||
368 ahp->ah_analogBank6Data == NULL ||
369 ahp->ah_analogBank6TPCData == NULL ||
370 ahp->ah_analogBank7Data == NULL) {
371 ARN_DBG((ARN_DBG_FATAL, "arn: ath9k_hw_init_rf(): "
372 "cannot allocate RF banks\n"));
373 *status = ENOMEM;
374 return (B_FALSE);
375 }
376
377 ahp->ah_addac5416_21 =
378 kmem_zalloc((sizeof (uint32_t) *
379 ahp->ah_iniAddac.ia_rows *
380 ahp->ah_iniAddac.ia_columns), KM_SLEEP);
381 if (ahp->ah_addac5416_21 == NULL) {
382 ARN_DBG((ARN_DBG_FATAL, "arn: ath9k_hw_init_rf(): "
383 "cannot allocate ah_addac5416_21\n"));
384 *status = ENOMEM;
385 return (B_FALSE);
386 }
387
388 ahp->ah_bank6Temp =
389 kmem_zalloc((sizeof (uint32_t) *
390 ahp->ah_iniBank6.ia_rows), KM_SLEEP);
391 if (ahp->ah_bank6Temp == NULL) {
392 ARN_DBG((ARN_DBG_FATAL, "arn: ath9k_hw_init_rf(): "
393 "cannot allocate ah_bank6Temp\n"));
394 *status = ENOMEM;
395 return (B_FALSE);
396 }
397 }
398
399 return (B_TRUE);
400 }
401
402 /* ARGSUSED */
403 void
ath9k_hw_decrease_chain_power(struct ath_hal * ah,struct ath9k_channel * chan)404 ath9k_hw_decrease_chain_power(struct ath_hal *ah, struct ath9k_channel *chan)
405 {
406 /* LINTED E_FUNC_SET_NOT_USED */
407 int i, regWrites = 0;
408 struct ath_hal_5416 *ahp = AH5416(ah);
409 uint32_t bank6SelMask;
410 uint32_t *bank6Temp = ahp->ah_bank6Temp;
411
412 switch (ahp->ah_diversityControl) {
413 case ATH9K_ANT_FIXED_A:
414 bank6SelMask =
415 (ahp-> ah_antennaSwitchSwap & ANTSWAP_AB) ? REDUCE_CHAIN_0 :
416 REDUCE_CHAIN_1;
417 break;
418 case ATH9K_ANT_FIXED_B:
419 bank6SelMask =
420 (ahp-> ah_antennaSwitchSwap & ANTSWAP_AB) ? REDUCE_CHAIN_1 :
421 REDUCE_CHAIN_0;
422 break;
423 case ATH9K_ANT_VARIABLE:
424 default:
425 return;
426 }
427
428 for (i = 0; i < ahp->ah_iniBank6.ia_rows; i++)
429 bank6Temp[i] = ahp->ah_analogBank6Data[i];
430
431 REG_WRITE(ah, AR_PHY_BASE + 0xD8, bank6SelMask);
432
433 ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 189, 0);
434 ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 190, 0);
435 ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 191, 0);
436 ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 192, 0);
437 ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 193, 0);
438 ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 222, 0);
439 ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 245, 0);
440 ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 246, 0);
441 ath9k_phy_modify_rx_buffer(bank6Temp, 1, 1, 247, 0);
442
443 REG_WRITE_RF_ARRAY(&ahp->ah_iniBank6, bank6Temp, regWrites);
444
445 REG_WRITE(ah, AR_PHY_BASE + 0xD8, 0x00000053);
446 #ifdef ALTER_SWITCH
447 REG_WRITE(ah, PHY_SWITCH_CHAIN_0,
448 (REG_READ(ah, PHY_SWITCH_CHAIN_0) & ~0x38)
449 | ((REG_READ(ah, PHY_SWITCH_CHAIN_0) >> 3) & 0x38));
450 #endif
451 }
452