1 | /* |
2 | * Copyright (c) 2008-2009 Sam Leffler, Errno Consulting |
3 | * Copyright (c) 2008 Atheros Communications, Inc. |
4 | * |
5 | * Permission to use, copy, modify, and/or distribute this software for any |
6 | * purpose with or without fee is hereby granted, provided that the above |
7 | * copyright notice and this permission notice appear in all copies. |
8 | * |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 | * |
17 | * $FreeBSD$ |
18 | */ |
19 | #include "opt_ah.h" |
20 | |
21 | #include "ah.h" |
22 | #include "ah_internal.h" |
23 | #include "ah_devid.h" |
24 | |
25 | #include "ah_eeprom_v14.h" /* XXX for tx/rx gain */ |
26 | |
27 | #include "ar5416/ar9280.h" |
28 | #include "ar5416/ar5416reg.h" |
29 | #include "ar5416/ar5416phy.h" |
30 | |
31 | #include "ar5416/ar9280v1.ini" |
32 | #include "ar5416/ar9280v2.ini" |
33 | |
34 | static const HAL_PERCAL_DATA ar9280_iq_cal = { /* single sample */ |
35 | .calName = "IQ" , .calType = IQ_MISMATCH_CAL, |
36 | .calNumSamples = MIN_CAL_SAMPLES, |
37 | .calCountMax = PER_MAX_LOG_COUNT, |
38 | .calCollect = ar5416IQCalCollect, |
39 | .calPostProc = ar5416IQCalibration |
40 | }; |
41 | static const HAL_PERCAL_DATA ar9280_adc_gain_cal = { /* single sample */ |
42 | .calName = "ADC Gain" , .calType = ADC_GAIN_CAL, |
43 | .calNumSamples = MIN_CAL_SAMPLES, |
44 | .calCountMax = PER_MIN_LOG_COUNT, |
45 | .calCollect = ar5416AdcGainCalCollect, |
46 | .calPostProc = ar5416AdcGainCalibration |
47 | }; |
48 | static const HAL_PERCAL_DATA ar9280_adc_dc_cal = { /* single sample */ |
49 | .calName = "ADC DC" , .calType = ADC_DC_CAL, |
50 | .calNumSamples = MIN_CAL_SAMPLES, |
51 | .calCountMax = PER_MIN_LOG_COUNT, |
52 | .calCollect = ar5416AdcDcCalCollect, |
53 | .calPostProc = ar5416AdcDcCalibration |
54 | }; |
55 | static const HAL_PERCAL_DATA ar9280_adc_init_dc_cal = { |
56 | .calName = "ADC Init DC" , .calType = ADC_DC_INIT_CAL, |
57 | .calNumSamples = MIN_CAL_SAMPLES, |
58 | .calCountMax = INIT_LOG_COUNT, |
59 | .calCollect = ar5416AdcDcCalCollect, |
60 | .calPostProc = ar5416AdcDcCalibration |
61 | }; |
62 | |
63 | static void ar9280ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore); |
64 | static HAL_BOOL ar9280FillCapabilityInfo(struct ath_hal *ah); |
65 | static void ar9280WriteIni(struct ath_hal *ah, |
66 | HAL_CHANNEL_INTERNAL *chan); |
67 | |
68 | static void |
69 | ar9280AniSetup(struct ath_hal *ah) |
70 | { |
71 | /* NB: disable ANI for reliable RIFS rx */ |
72 | ar5212AniAttach(ah, AH_NULL, AH_NULL, AH_FALSE); |
73 | } |
74 | |
75 | /* |
76 | * Attach for an AR9280 part. |
77 | */ |
78 | static struct ath_hal * |
79 | ar9280Attach(uint16_t devid, HAL_SOFTC sc, |
80 | HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status) |
81 | { |
82 | struct ath_hal_9280 *ahp9280; |
83 | struct ath_hal_5212 *ahp; |
84 | struct ath_hal *ah; |
85 | uint32_t val; |
86 | HAL_STATUS ecode; |
87 | HAL_BOOL rfStatus; |
88 | |
89 | HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n" , |
90 | __func__, sc, (void*) st, (void*) sh); |
91 | |
92 | /* NB: memory is returned zero'd */ |
93 | ahp9280 = ath_hal_malloc(sizeof (struct ath_hal_9280)); |
94 | if (ahp9280 == AH_NULL) { |
95 | HALDEBUG(AH_NULL, HAL_DEBUG_ANY, |
96 | "%s: cannot allocate memory for state block\n" , __func__); |
97 | *status = HAL_ENOMEM; |
98 | return AH_NULL; |
99 | } |
100 | ahp = AH5212(ahp9280); |
101 | ah = &ahp->ah_priv.h; |
102 | |
103 | ar5416InitState(AH5416(ah), devid, sc, st, sh, status); |
104 | |
105 | /* XXX override with 9280 specific state */ |
106 | /* override 5416 methods for our needs */ |
107 | ah->ah_setAntennaSwitch = ar9280SetAntennaSwitch; |
108 | ah->ah_configPCIE = ar9280ConfigPCIE; |
109 | |
110 | AH5416(ah)->ah_cal.iqCalData.calData = &ar9280_iq_cal; |
111 | AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9280_adc_gain_cal; |
112 | AH5416(ah)->ah_cal.adcDcCalData.calData = &ar9280_adc_dc_cal; |
113 | AH5416(ah)->ah_cal.adcDcCalInitData.calData = &ar9280_adc_init_dc_cal; |
114 | AH5416(ah)->ah_cal.suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; |
115 | |
116 | AH5416(ah)->ah_spurMitigate = ar9280SpurMitigate; |
117 | AH5416(ah)->ah_writeIni = ar9280WriteIni; |
118 | AH5416(ah)->ah_rx_chainmask = AR9280_DEFAULT_RXCHAINMASK; |
119 | AH5416(ah)->ah_tx_chainmask = AR9280_DEFAULT_TXCHAINMASK; |
120 | |
121 | if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) { |
122 | /* reset chip */ |
123 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n" , |
124 | __func__); |
125 | ecode = HAL_EIO; |
126 | goto bad; |
127 | } |
128 | |
129 | if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { |
130 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't wakeup chip\n" , |
131 | __func__); |
132 | ecode = HAL_EIO; |
133 | goto bad; |
134 | } |
135 | /* Read Revisions from Chips before taking out of reset */ |
136 | val = OS_REG_READ(ah, AR_SREV); |
137 | HALDEBUG(ah, HAL_DEBUG_ATTACH, |
138 | "%s: ID 0x%x VERSION 0x%x TYPE 0x%x REVISION 0x%x\n" , |
139 | __func__, MS(val, AR_XSREV_ID), MS(val, AR_XSREV_VERSION), |
140 | MS(val, AR_XSREV_TYPE), MS(val, AR_XSREV_REVISION)); |
141 | /* NB: include chip type to differentiate from pre-Sowl versions */ |
142 | AH_PRIVATE(ah)->ah_macVersion = |
143 | (val & AR_XSREV_VERSION) >> AR_XSREV_TYPE_S; |
144 | AH_PRIVATE(ah)->ah_macRev = MS(val, AR_XSREV_REVISION); |
145 | AH_PRIVATE(ah)->ah_ispcie = (val & AR_XSREV_TYPE_HOST_MODE) == 0; |
146 | |
147 | /* setup common ini data; rf backends handle remainder */ |
148 | if (AR_SREV_MERLIN_20_OR_LATER(ah)) { |
149 | HAL_INI_INIT(&ahp->ah_ini_modes, ar9280Modes_v2, 6); |
150 | HAL_INI_INIT(&ahp->ah_ini_common, ar9280Common_v2, 2); |
151 | HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, |
152 | ar9280PciePhy_clkreq_always_on_L1_v2, 2); |
153 | HAL_INI_INIT(&ahp9280->ah_ini_xmodes, |
154 | ar9280Modes_fast_clock_v2, 3); |
155 | } else { |
156 | HAL_INI_INIT(&ahp->ah_ini_modes, ar9280Modes_v1, 6); |
157 | HAL_INI_INIT(&ahp->ah_ini_common, ar9280Common_v1, 2); |
158 | HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, |
159 | ar9280PciePhy_v1, 2); |
160 | } |
161 | ar5416AttachPCIE(ah); |
162 | |
163 | ecode = ath_hal_v14EepromAttach(ah); |
164 | if (ecode != HAL_OK) |
165 | goto bad; |
166 | |
167 | if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ |
168 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n" , __func__); |
169 | ecode = HAL_EIO; |
170 | goto bad; |
171 | } |
172 | |
173 | AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); |
174 | |
175 | if (!ar5212ChipTest(ah)) { |
176 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n" , |
177 | __func__); |
178 | ecode = HAL_ESELFTEST; |
179 | goto bad; |
180 | } |
181 | |
182 | /* |
183 | * Set correct Baseband to analog shift |
184 | * setting to access analog chips. |
185 | */ |
186 | OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); |
187 | |
188 | /* Read Radio Chip Rev Extract */ |
189 | AH_PRIVATE(ah)->ah_analog5GhzRev = ar5416GetRadioRev(ah); |
190 | switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { |
191 | case AR_RAD2133_SREV_MAJOR: /* Sowl: 2G/3x3 */ |
192 | case AR_RAD5133_SREV_MAJOR: /* Sowl: 2+5G/3x3 */ |
193 | break; |
194 | default: |
195 | if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { |
196 | AH_PRIVATE(ah)->ah_analog5GhzRev = |
197 | AR_RAD5133_SREV_MAJOR; |
198 | break; |
199 | } |
200 | #ifdef AH_DEBUG |
201 | HALDEBUG(ah, HAL_DEBUG_ANY, |
202 | "%s: 5G Radio Chip Rev 0x%02X is not supported by " |
203 | "this driver\n" , __func__, |
204 | AH_PRIVATE(ah)->ah_analog5GhzRev); |
205 | ecode = HAL_ENOTSUPP; |
206 | goto bad; |
207 | #endif |
208 | } |
209 | rfStatus = ar9280RfAttach(ah, &ecode); |
210 | if (!rfStatus) { |
211 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n" , |
212 | __func__, ecode); |
213 | goto bad; |
214 | } |
215 | |
216 | if (AR_SREV_MERLIN_20_OR_LATER(ah)) { |
217 | /* setup rxgain table */ |
218 | switch (ath_hal_eepromGet(ah, AR_EEP_RXGAIN_TYPE, AH_NULL)) { |
219 | case AR5416_EEP_RXGAIN_13dB_BACKOFF: |
220 | HAL_INI_INIT(&ahp9280->ah_ini_rxgain, |
221 | ar9280Modes_backoff_13db_rxgain_v2, 6); |
222 | break; |
223 | case AR5416_EEP_RXGAIN_23dB_BACKOFF: |
224 | HAL_INI_INIT(&ahp9280->ah_ini_rxgain, |
225 | ar9280Modes_backoff_23db_rxgain_v2, 6); |
226 | break; |
227 | case AR5416_EEP_RXGAIN_ORIG: |
228 | HAL_INI_INIT(&ahp9280->ah_ini_rxgain, |
229 | ar9280Modes_original_rxgain_v2, 6); |
230 | break; |
231 | default: |
232 | HALASSERT(AH_FALSE); |
233 | goto bad; /* XXX ? try to continue */ |
234 | } |
235 | } |
236 | if (AR_SREV_MERLIN_20_OR_LATER(ah)) { |
237 | /* setp txgain table */ |
238 | switch (ath_hal_eepromGet(ah, AR_EEP_TXGAIN_TYPE, AH_NULL)) { |
239 | case AR5416_EEP_TXGAIN_HIGH_POWER: |
240 | HAL_INI_INIT(&ahp9280->ah_ini_txgain, |
241 | ar9280Modes_high_power_tx_gain_v2, 6); |
242 | break; |
243 | case AR5416_EEP_TXGAIN_ORIG: |
244 | HAL_INI_INIT(&ahp9280->ah_ini_txgain, |
245 | ar9280Modes_original_tx_gain_v2, 6); |
246 | break; |
247 | default: |
248 | HALASSERT(AH_FALSE); |
249 | goto bad; /* XXX ? try to continue */ |
250 | } |
251 | } |
252 | |
253 | /* |
254 | * Got everything we need now to setup the capabilities. |
255 | */ |
256 | if (!ar9280FillCapabilityInfo(ah)) { |
257 | ecode = HAL_EEREAD; |
258 | goto bad; |
259 | } |
260 | |
261 | ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); |
262 | if (ecode != HAL_OK) { |
263 | HALDEBUG(ah, HAL_DEBUG_ANY, |
264 | "%s: error getting mac address from EEPROM\n" , __func__); |
265 | goto bad; |
266 | } |
267 | /* XXX How about the serial number ? */ |
268 | /* Read Reg Domain */ |
269 | AH_PRIVATE(ah)->ah_currentRD = |
270 | ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); |
271 | |
272 | /* |
273 | * ah_miscMode is populated by ar5416FillCapabilityInfo() |
274 | * starting from griffin. Set here to make sure that |
275 | * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is |
276 | * placed into hardware. |
277 | */ |
278 | if (ahp->ah_miscMode != 0) |
279 | OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); |
280 | |
281 | ar9280AniSetup(ah); /* Anti Noise Immunity */ |
282 | ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist); |
283 | |
284 | HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n" , __func__); |
285 | |
286 | return ah; |
287 | bad: |
288 | if (ah != AH_NULL) |
289 | ah->ah_detach(ah); |
290 | if (status) |
291 | *status = ecode; |
292 | return AH_NULL; |
293 | } |
294 | |
295 | static void |
296 | ar9280ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore) |
297 | { |
298 | if (AH_PRIVATE(ah)->ah_ispcie && !restore) { |
299 | ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_pcieserdes, 1, 0); |
300 | OS_DELAY(1000); |
301 | OS_REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); |
302 | OS_REG_WRITE(ah, AR_WA, AR9280_WA_DEFAULT); |
303 | } |
304 | } |
305 | |
306 | static void |
307 | ar9280WriteIni(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) |
308 | { |
309 | u_int modesIndex; |
310 | int regWrites = 0; |
311 | |
312 | /* Setup the indices for the next set of register array writes */ |
313 | /* XXX Ignore 11n dynamic mode on the AR5416 for the moment */ |
314 | if (IS_CHAN_2GHZ(chan)) { |
315 | if (IS_CHAN_HT40(chan)) |
316 | modesIndex = 3; |
317 | else if (IS_CHAN_108G(chan)) |
318 | modesIndex = 5; |
319 | else |
320 | modesIndex = 4; |
321 | } else { |
322 | if (IS_CHAN_HT40(chan) || |
323 | IS_CHAN_TURBO(chan)) |
324 | modesIndex = 2; |
325 | else |
326 | modesIndex = 1; |
327 | } |
328 | |
329 | /* Set correct Baseband to analog shift setting to access analog chips. */ |
330 | OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); |
331 | OS_REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); |
332 | |
333 | /* XXX Merlin ini fixups */ |
334 | /* XXX Merlin 100us delay for shift registers */ |
335 | regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_modes, |
336 | modesIndex, regWrites); |
337 | if (AR_SREV_MERLIN_20_OR_LATER(ah)) { |
338 | regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_rxgain, |
339 | modesIndex, regWrites); |
340 | regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_txgain, |
341 | modesIndex, regWrites); |
342 | } |
343 | /* XXX Merlin 100us delay for shift registers */ |
344 | regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_common, |
345 | 1, regWrites); |
346 | |
347 | if (AR_SREV_MERLIN_20(ah) && IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { |
348 | /* 5GHz channels w/ Fast Clock use different modal values */ |
349 | regWrites = ath_hal_ini_write(ah, &AH9280(ah)->ah_ini_xmodes, |
350 | modesIndex, regWrites); |
351 | } |
352 | } |
353 | |
354 | #define AR_BASE_FREQ_2GHZ 2300 |
355 | #define AR_BASE_FREQ_5GHZ 4900 |
356 | #define AR_SPUR_FEEQ_BOUND_HT40 19 |
357 | #define AR_SPUR_FEEQ_BOUND_HT20 10 |
358 | |
359 | void |
360 | ar9280SpurMitigate(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) |
361 | { |
362 | static const int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, |
363 | AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 }; |
364 | static const int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, |
365 | AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 }; |
366 | static int inc[4] = { 0, 100, 0, 0 }; |
367 | |
368 | int bb_spur = AR_NO_SPUR; |
369 | int freq; |
370 | int bin, cur_bin; |
371 | int bb_spur_off, spur_subchannel_sd; |
372 | int spur_freq_sd; |
373 | int spur_delta_phase; |
374 | int denominator; |
375 | int upper, lower, cur_vit_mask; |
376 | int tmp, newVal; |
377 | int i; |
378 | CHAN_CENTERS centers; |
379 | |
380 | int8_t mask_m[123]; |
381 | int8_t mask_p[123]; |
382 | int8_t mask_amt; |
383 | int tmp_mask; |
384 | int cur_bb_spur; |
385 | HAL_BOOL is2GHz = IS_CHAN_2GHZ(chan); |
386 | |
387 | OS_MEMZERO(&mask_m, sizeof(int8_t) * 123); |
388 | OS_MEMZERO(&mask_p, sizeof(int8_t) * 123); |
389 | |
390 | ar5416GetChannelCenters(ah, chan, ¢ers); |
391 | freq = centers.synth_center; |
392 | |
393 | /* |
394 | * Need to verify range +/- 9.38 for static ht20 and +/- 18.75 for ht40, |
395 | * otherwise spur is out-of-band and can be ignored. |
396 | */ |
397 | for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { |
398 | cur_bb_spur = ath_hal_getSpurChan(ah, i, is2GHz); |
399 | /* Get actual spur freq in MHz from EEPROM read value */ |
400 | if (is2GHz) { |
401 | cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; |
402 | } else { |
403 | cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; |
404 | } |
405 | |
406 | if (AR_NO_SPUR == cur_bb_spur) |
407 | break; |
408 | cur_bb_spur = cur_bb_spur - freq; |
409 | |
410 | if (IS_CHAN_HT40(chan)) { |
411 | if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) && |
412 | (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) { |
413 | bb_spur = cur_bb_spur; |
414 | break; |
415 | } |
416 | } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) && |
417 | (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) { |
418 | bb_spur = cur_bb_spur; |
419 | break; |
420 | } |
421 | } |
422 | |
423 | if (AR_NO_SPUR == bb_spur) { |
424 | #if 1 |
425 | /* |
426 | * MRC CCK can interfere with beacon detection and cause deaf/mute. |
427 | * Disable MRC CCK for now. |
428 | */ |
429 | OS_REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); |
430 | #else |
431 | /* Enable MRC CCK if no spur is found in this channel. */ |
432 | OS_REG_SET_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); |
433 | #endif |
434 | return; |
435 | } else { |
436 | /* |
437 | * For Merlin, spur can break CCK MRC algorithm. Disable CCK MRC if spur |
438 | * is found in this channel. |
439 | */ |
440 | OS_REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); |
441 | } |
442 | |
443 | bin = bb_spur * 320; |
444 | |
445 | tmp = OS_REG_READ(ah, AR_PHY_TIMING_CTRL4_CHAIN(0)); |
446 | |
447 | newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | |
448 | AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | |
449 | AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | |
450 | AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); |
451 | OS_REG_WRITE(ah, AR_PHY_TIMING_CTRL4_CHAIN(0), newVal); |
452 | |
453 | newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | |
454 | AR_PHY_SPUR_REG_ENABLE_MASK_PPM | |
455 | AR_PHY_SPUR_REG_MASK_RATE_SELECT | |
456 | AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | |
457 | SM(AR5416_SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); |
458 | OS_REG_WRITE(ah, AR_PHY_SPUR_REG, newVal); |
459 | |
460 | /* Pick control or extn channel to cancel the spur */ |
461 | if (IS_CHAN_HT40(chan)) { |
462 | if (bb_spur < 0) { |
463 | spur_subchannel_sd = 1; |
464 | bb_spur_off = bb_spur + 10; |
465 | } else { |
466 | spur_subchannel_sd = 0; |
467 | bb_spur_off = bb_spur - 10; |
468 | } |
469 | } else { |
470 | spur_subchannel_sd = 0; |
471 | bb_spur_off = bb_spur; |
472 | } |
473 | |
474 | /* |
475 | * spur_delta_phase = bb_spur/40 * 2**21 for static ht20, |
476 | * /80 for dyn2040. |
477 | */ |
478 | if (IS_CHAN_HT40(chan)) |
479 | spur_delta_phase = ((bb_spur * 262144) / 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; |
480 | else |
481 | spur_delta_phase = ((bb_spur * 524288) / 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; |
482 | |
483 | /* |
484 | * in 11A mode the denominator of spur_freq_sd should be 40 and |
485 | * it should be 44 in 11G |
486 | */ |
487 | denominator = IS_CHAN_2GHZ(chan) ? 44 : 40; |
488 | spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff; |
489 | |
490 | newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | |
491 | SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | |
492 | SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); |
493 | OS_REG_WRITE(ah, AR_PHY_TIMING11, newVal); |
494 | |
495 | /* Choose to cancel between control and extension channels */ |
496 | newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; |
497 | OS_REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal); |
498 | |
499 | /* |
500 | * ============================================ |
501 | * Set Pilot and Channel Masks |
502 | * |
503 | * pilot mask 1 [31:0] = +6..-26, no 0 bin |
504 | * pilot mask 2 [19:0] = +26..+7 |
505 | * |
506 | * channel mask 1 [31:0] = +6..-26, no 0 bin |
507 | * channel mask 2 [19:0] = +26..+7 |
508 | */ |
509 | cur_bin = -6000; |
510 | upper = bin + 100; |
511 | lower = bin - 100; |
512 | |
513 | for (i = 0; i < 4; i++) { |
514 | int pilot_mask = 0; |
515 | int chan_mask = 0; |
516 | int bp = 0; |
517 | for (bp = 0; bp < 30; bp++) { |
518 | if ((cur_bin > lower) && (cur_bin < upper)) { |
519 | pilot_mask = pilot_mask | 0x1 << bp; |
520 | chan_mask = chan_mask | 0x1 << bp; |
521 | } |
522 | cur_bin += 100; |
523 | } |
524 | cur_bin += inc[i]; |
525 | OS_REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); |
526 | OS_REG_WRITE(ah, chan_mask_reg[i], chan_mask); |
527 | } |
528 | |
529 | /* ================================================= |
530 | * viterbi mask 1 based on channel magnitude |
531 | * four levels 0-3 |
532 | * - mask (-27 to 27) (reg 64,0x9900 to 67,0x990c) |
533 | * [1 2 2 1] for -9.6 or [1 2 1] for +16 |
534 | * - enable_mask_ppm, all bins move with freq |
535 | * |
536 | * - mask_select, 8 bits for rates (reg 67,0x990c) |
537 | * - mask_rate_cntl, 8 bits for rates (reg 67,0x990c) |
538 | * choose which mask to use mask or mask2 |
539 | */ |
540 | |
541 | /* |
542 | * viterbi mask 2 2nd set for per data rate puncturing |
543 | * four levels 0-3 |
544 | * - mask_select, 8 bits for rates (reg 67) |
545 | * - mask (-27 to 27) (reg 98,0x9988 to 101,0x9994) |
546 | * [1 2 2 1] for -9.6 or [1 2 1] for +16 |
547 | */ |
548 | cur_vit_mask = 6100; |
549 | upper = bin + 120; |
550 | lower = bin - 120; |
551 | |
552 | for (i = 0; i < 123; i++) { |
553 | if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { |
554 | if ((abs(cur_vit_mask - bin)) < 75) { |
555 | mask_amt = 1; |
556 | } else { |
557 | mask_amt = 0; |
558 | } |
559 | if (cur_vit_mask < 0) { |
560 | mask_m[abs(cur_vit_mask / 100)] = mask_amt; |
561 | } else { |
562 | mask_p[cur_vit_mask / 100] = mask_amt; |
563 | } |
564 | } |
565 | cur_vit_mask -= 100; |
566 | } |
567 | |
568 | tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) |
569 | | (mask_m[48] << 26) | (mask_m[49] << 24) |
570 | | (mask_m[50] << 22) | (mask_m[51] << 20) |
571 | | (mask_m[52] << 18) | (mask_m[53] << 16) |
572 | | (mask_m[54] << 14) | (mask_m[55] << 12) |
573 | | (mask_m[56] << 10) | (mask_m[57] << 8) |
574 | | (mask_m[58] << 6) | (mask_m[59] << 4) |
575 | | (mask_m[60] << 2) | (mask_m[61] << 0); |
576 | OS_REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); |
577 | OS_REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); |
578 | |
579 | tmp_mask = (mask_m[31] << 28) |
580 | | (mask_m[32] << 26) | (mask_m[33] << 24) |
581 | | (mask_m[34] << 22) | (mask_m[35] << 20) |
582 | | (mask_m[36] << 18) | (mask_m[37] << 16) |
583 | | (mask_m[48] << 14) | (mask_m[39] << 12) |
584 | | (mask_m[40] << 10) | (mask_m[41] << 8) |
585 | | (mask_m[42] << 6) | (mask_m[43] << 4) |
586 | | (mask_m[44] << 2) | (mask_m[45] << 0); |
587 | OS_REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); |
588 | OS_REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); |
589 | |
590 | tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) |
591 | | (mask_m[18] << 26) | (mask_m[18] << 24) |
592 | | (mask_m[20] << 22) | (mask_m[20] << 20) |
593 | | (mask_m[22] << 18) | (mask_m[22] << 16) |
594 | | (mask_m[24] << 14) | (mask_m[24] << 12) |
595 | | (mask_m[25] << 10) | (mask_m[26] << 8) |
596 | | (mask_m[27] << 6) | (mask_m[28] << 4) |
597 | | (mask_m[29] << 2) | (mask_m[30] << 0); |
598 | OS_REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); |
599 | OS_REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); |
600 | |
601 | tmp_mask = (mask_m[ 0] << 30) | (mask_m[ 1] << 28) |
602 | | (mask_m[ 2] << 26) | (mask_m[ 3] << 24) |
603 | | (mask_m[ 4] << 22) | (mask_m[ 5] << 20) |
604 | | (mask_m[ 6] << 18) | (mask_m[ 7] << 16) |
605 | | (mask_m[ 8] << 14) | (mask_m[ 9] << 12) |
606 | | (mask_m[10] << 10) | (mask_m[11] << 8) |
607 | | (mask_m[12] << 6) | (mask_m[13] << 4) |
608 | | (mask_m[14] << 2) | (mask_m[15] << 0); |
609 | OS_REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); |
610 | OS_REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); |
611 | |
612 | tmp_mask = (mask_p[15] << 28) |
613 | | (mask_p[14] << 26) | (mask_p[13] << 24) |
614 | | (mask_p[12] << 22) | (mask_p[11] << 20) |
615 | | (mask_p[10] << 18) | (mask_p[ 9] << 16) |
616 | | (mask_p[ 8] << 14) | (mask_p[ 7] << 12) |
617 | | (mask_p[ 6] << 10) | (mask_p[ 5] << 8) |
618 | | (mask_p[ 4] << 6) | (mask_p[ 3] << 4) |
619 | | (mask_p[ 2] << 2) | (mask_p[ 1] << 0); |
620 | OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); |
621 | OS_REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); |
622 | |
623 | tmp_mask = (mask_p[30] << 28) |
624 | | (mask_p[29] << 26) | (mask_p[28] << 24) |
625 | | (mask_p[27] << 22) | (mask_p[26] << 20) |
626 | | (mask_p[25] << 18) | (mask_p[24] << 16) |
627 | | (mask_p[23] << 14) | (mask_p[22] << 12) |
628 | | (mask_p[21] << 10) | (mask_p[20] << 8) |
629 | | (mask_p[19] << 6) | (mask_p[18] << 4) |
630 | | (mask_p[17] << 2) | (mask_p[16] << 0); |
631 | OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); |
632 | OS_REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); |
633 | |
634 | tmp_mask = (mask_p[45] << 28) |
635 | | (mask_p[44] << 26) | (mask_p[43] << 24) |
636 | | (mask_p[42] << 22) | (mask_p[41] << 20) |
637 | | (mask_p[40] << 18) | (mask_p[39] << 16) |
638 | | (mask_p[38] << 14) | (mask_p[37] << 12) |
639 | | (mask_p[36] << 10) | (mask_p[35] << 8) |
640 | | (mask_p[34] << 6) | (mask_p[33] << 4) |
641 | | (mask_p[32] << 2) | (mask_p[31] << 0); |
642 | OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); |
643 | OS_REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); |
644 | |
645 | tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) |
646 | | (mask_p[59] << 26) | (mask_p[58] << 24) |
647 | | (mask_p[57] << 22) | (mask_p[56] << 20) |
648 | | (mask_p[55] << 18) | (mask_p[54] << 16) |
649 | | (mask_p[53] << 14) | (mask_p[52] << 12) |
650 | | (mask_p[51] << 10) | (mask_p[50] << 8) |
651 | | (mask_p[49] << 6) | (mask_p[48] << 4) |
652 | | (mask_p[47] << 2) | (mask_p[46] << 0); |
653 | OS_REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); |
654 | OS_REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); |
655 | } |
656 | |
657 | /* |
658 | * Fill all software cached or static hardware state information. |
659 | * Return failure if capabilities are to come from EEPROM and |
660 | * cannot be read. |
661 | */ |
662 | static HAL_BOOL |
663 | ar9280FillCapabilityInfo(struct ath_hal *ah) |
664 | { |
665 | HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; |
666 | |
667 | if (!ar5416FillCapabilityInfo(ah)) |
668 | return AH_FALSE; |
669 | pCap->halNumGpioPins = 10; |
670 | pCap->halWowSupport = AH_TRUE; |
671 | pCap->halWowMatchPatternExact = AH_TRUE; |
672 | #if 0 |
673 | pCap->halWowMatchPatternDword = AH_TRUE; |
674 | #endif |
675 | pCap->halCSTSupport = AH_TRUE; |
676 | pCap->halRifsRxSupport = AH_TRUE; |
677 | pCap->halRifsTxSupport = AH_TRUE; |
678 | pCap->halRtsAggrLimit = 64*1024; /* 802.11n max */ |
679 | pCap->halExtChanDfsSupport = AH_TRUE; |
680 | #if 0 |
681 | /* XXX bluetooth */ |
682 | pCap->halBtCoexSupport = AH_TRUE; |
683 | #endif |
684 | pCap->halAutoSleepSupport = AH_FALSE; /* XXX? */ |
685 | #if 0 |
686 | pCap->hal4kbSplitTransSupport = AH_FALSE; |
687 | #endif |
688 | pCap->halRxStbcSupport = 1; |
689 | pCap->halTxStbcSupport = 1; |
690 | |
691 | return AH_TRUE; |
692 | } |
693 | |
694 | HAL_BOOL |
695 | ar9280SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) |
696 | { |
697 | #define ANTENNA0_CHAINMASK 0x1 |
698 | #define ANTENNA1_CHAINMASK 0x2 |
699 | struct ath_hal_5416 *ahp = AH5416(ah); |
700 | |
701 | /* Antenna selection is done by setting the tx/rx chainmasks approp. */ |
702 | switch (settings) { |
703 | case HAL_ANT_FIXED_A: |
704 | /* Enable first antenna only */ |
705 | ahp->ah_tx_chainmask = ANTENNA0_CHAINMASK; |
706 | ahp->ah_rx_chainmask = ANTENNA0_CHAINMASK; |
707 | break; |
708 | case HAL_ANT_FIXED_B: |
709 | /* Enable second antenna only, after checking capability */ |
710 | if (AH_PRIVATE(ah)->ah_caps.halTxChainMask > ANTENNA1_CHAINMASK) |
711 | ahp->ah_tx_chainmask = ANTENNA1_CHAINMASK; |
712 | ahp->ah_rx_chainmask = ANTENNA1_CHAINMASK; |
713 | break; |
714 | case HAL_ANT_VARIABLE: |
715 | /* Restore original chainmask settings */ |
716 | /* XXX */ |
717 | ahp->ah_tx_chainmask = AR5416_DEFAULT_TXCHAINMASK; |
718 | ahp->ah_rx_chainmask = AR5416_DEFAULT_RXCHAINMASK; |
719 | break; |
720 | } |
721 | return AH_TRUE; |
722 | #undef ANTENNA0_CHAINMASK |
723 | #undef ANTENNA1_CHAINMASK |
724 | } |
725 | |
726 | static const char* |
727 | ar9280Probe(uint16_t vendorid, uint16_t devid) |
728 | { |
729 | if (vendorid == ATHEROS_VENDOR_ID && |
730 | (devid == AR9280_DEVID_PCI || devid == AR9280_DEVID_PCIE)) |
731 | return "Atheros 9280" ; |
732 | return AH_NULL; |
733 | } |
734 | AH_CHIP(AR9280, ar9280Probe, ar9280Attach); |
735 | |