xref: /illumos-gate/usr/src/uts/common/io/arn/arn_phy.c (revision 2a6e99a0f1f7d22c0396e8b2ce9b9babbd1056cf)
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
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
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, &centers);
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
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, &centers);
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
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
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
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
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
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