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: src/sys/dev/ath/ath_hal/ar5416/ar9285_attach.c,v 1.5 2010/06/01 15:33:10 rpaulo Exp $ |
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_v4k.h" /* XXX for tx/rx gain */ |
26 | |
27 | #include "ar5416/ar9280.h" |
28 | #include "ar5416/ar9285.h" |
29 | #include "ar5416/ar5416reg.h" |
30 | #include "ar5416/ar5416phy.h" |
31 | |
32 | #include "ar5416/ar9285.ini" |
33 | #include "ar5416/ar9285v2.ini" |
34 | #include "ar5416/ar9280v2.ini" /* XXX ini for tx/rx gain */ |
35 | |
36 | static const HAL_PERCAL_DATA ar9280_iq_cal = { /* single sample */ |
37 | .calName = "IQ" , .calType = IQ_MISMATCH_CAL, |
38 | .calNumSamples = MIN_CAL_SAMPLES, |
39 | .calCountMax = PER_MAX_LOG_COUNT, |
40 | .calCollect = ar5416IQCalCollect, |
41 | .calPostProc = ar5416IQCalibration |
42 | }; |
43 | static const HAL_PERCAL_DATA ar9280_adc_gain_cal = { /* single sample */ |
44 | .calName = "ADC Gain" , .calType = ADC_GAIN_CAL, |
45 | .calNumSamples = MIN_CAL_SAMPLES, |
46 | .calCountMax = PER_MIN_LOG_COUNT, |
47 | .calCollect = ar5416AdcGainCalCollect, |
48 | .calPostProc = ar5416AdcGainCalibration |
49 | }; |
50 | static const HAL_PERCAL_DATA ar9280_adc_dc_cal = { /* single sample */ |
51 | .calName = "ADC DC" , .calType = ADC_DC_CAL, |
52 | .calNumSamples = MIN_CAL_SAMPLES, |
53 | .calCountMax = PER_MIN_LOG_COUNT, |
54 | .calCollect = ar5416AdcDcCalCollect, |
55 | .calPostProc = ar5416AdcDcCalibration |
56 | }; |
57 | static const HAL_PERCAL_DATA ar9280_adc_init_dc_cal = { |
58 | .calName = "ADC Init DC" , .calType = ADC_DC_INIT_CAL, |
59 | .calNumSamples = MIN_CAL_SAMPLES, |
60 | .calCountMax = INIT_LOG_COUNT, |
61 | .calCollect = ar5416AdcDcCalCollect, |
62 | .calPostProc = ar5416AdcDcCalibration |
63 | }; |
64 | |
65 | static void ar9285ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore); |
66 | static HAL_BOOL ar9285FillCapabilityInfo(struct ath_hal *ah); |
67 | static void ar9285WriteIni(struct ath_hal *ah, |
68 | HAL_CHANNEL_INTERNAL *chan); |
69 | |
70 | static void |
71 | ar9285AniSetup(struct ath_hal *ah) |
72 | { |
73 | /* NB: disable ANI for reliable RIFS rx */ |
74 | ar5212AniAttach(ah, AH_NULL, AH_NULL, AH_FALSE); |
75 | } |
76 | |
77 | /* |
78 | * Attach for an AR9285 part. |
79 | */ |
80 | static struct ath_hal * |
81 | ar9285Attach(uint16_t devid, HAL_SOFTC sc, |
82 | HAL_BUS_TAG st, HAL_BUS_HANDLE sh, HAL_STATUS *status) |
83 | { |
84 | struct ath_hal_9285 *ahp9285; |
85 | struct ath_hal_5212 *ahp; |
86 | struct ath_hal *ah; |
87 | uint32_t val; |
88 | HAL_STATUS ecode; |
89 | HAL_BOOL rfStatus; |
90 | |
91 | HALDEBUG(AH_NULL, HAL_DEBUG_ATTACH, "%s: sc %p st %p sh %p\n" , |
92 | __func__, sc, (void*) st, (void*) sh); |
93 | |
94 | /* NB: memory is returned zero'd */ |
95 | ahp9285 = ath_hal_malloc(sizeof (struct ath_hal_9285)); |
96 | if (ahp9285 == AH_NULL) { |
97 | HALDEBUG(AH_NULL, HAL_DEBUG_ANY, |
98 | "%s: cannot allocate memory for state block\n" , __func__); |
99 | *status = HAL_ENOMEM; |
100 | return AH_NULL; |
101 | } |
102 | ahp = AH5212(ahp9285); |
103 | ah = &ahp->ah_priv.h; |
104 | |
105 | ar5416InitState(AH5416(ah), devid, sc, st, sh, status); |
106 | |
107 | /* XXX override with 9285 specific state */ |
108 | /* override 5416 methods for our needs */ |
109 | ah->ah_setAntennaSwitch = ar9285SetAntennaSwitch; |
110 | ah->ah_configPCIE = ar9285ConfigPCIE; |
111 | ah->ah_setTxPower = ar9285SetTransmitPower; |
112 | ah->ah_setBoardValues = ar9285SetBoardValues; |
113 | |
114 | AH5416(ah)->ah_cal.iqCalData.calData = &ar9280_iq_cal; |
115 | AH5416(ah)->ah_cal.adcGainCalData.calData = &ar9280_adc_gain_cal; |
116 | AH5416(ah)->ah_cal.adcDcCalData.calData = &ar9280_adc_dc_cal; |
117 | AH5416(ah)->ah_cal.adcDcCalInitData.calData = &ar9280_adc_init_dc_cal; |
118 | AH5416(ah)->ah_cal.suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; |
119 | |
120 | AH5416(ah)->ah_spurMitigate = ar9280SpurMitigate; |
121 | AH5416(ah)->ah_writeIni = ar9285WriteIni; |
122 | AH5416(ah)->ah_rx_chainmask = AR9285_DEFAULT_RXCHAINMASK; |
123 | AH5416(ah)->ah_tx_chainmask = AR9285_DEFAULT_TXCHAINMASK; |
124 | |
125 | ahp->ah_maxTxTrigLev = MAX_TX_FIFO_THRESHOLD >> 1; |
126 | |
127 | if (!ar5416SetResetReg(ah, HAL_RESET_POWER_ON)) { |
128 | /* reset chip */ |
129 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't reset chip\n" , |
130 | __func__); |
131 | ecode = HAL_EIO; |
132 | goto bad; |
133 | } |
134 | |
135 | if (!ar5416SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) { |
136 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: couldn't wakeup chip\n" , |
137 | __func__); |
138 | ecode = HAL_EIO; |
139 | goto bad; |
140 | } |
141 | /* Read Revisions from Chips before taking out of reset */ |
142 | val = OS_REG_READ(ah, AR_SREV); |
143 | HALDEBUG(ah, HAL_DEBUG_ATTACH, |
144 | "%s: ID 0x%x VERSION 0x%x TYPE 0x%x REVISION 0x%x\n" , |
145 | __func__, MS(val, AR_XSREV_ID), MS(val, AR_XSREV_VERSION), |
146 | MS(val, AR_XSREV_TYPE), MS(val, AR_XSREV_REVISION)); |
147 | /* NB: include chip type to differentiate from pre-Sowl versions */ |
148 | AH_PRIVATE(ah)->ah_macVersion = |
149 | (val & AR_XSREV_VERSION) >> AR_XSREV_TYPE_S; |
150 | AH_PRIVATE(ah)->ah_macRev = MS(val, AR_XSREV_REVISION); |
151 | AH_PRIVATE(ah)->ah_ispcie = (val & AR_XSREV_TYPE_HOST_MODE) == 0; |
152 | |
153 | /* setup common ini data; rf backends handle remainder */ |
154 | if (AR_SREV_KITE_12_OR_LATER(ah)) { |
155 | HAL_INI_INIT(&ahp->ah_ini_modes, ar9285Modes_v2, 6); |
156 | HAL_INI_INIT(&ahp->ah_ini_common, ar9285Common_v2, 2); |
157 | HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, |
158 | ar9285PciePhy_clkreq_always_on_L1_v2, 2); |
159 | } else { |
160 | HAL_INI_INIT(&ahp->ah_ini_modes, ar9285Modes, 6); |
161 | HAL_INI_INIT(&ahp->ah_ini_common, ar9285Common, 2); |
162 | HAL_INI_INIT(&AH5416(ah)->ah_ini_pcieserdes, |
163 | ar9285PciePhy_clkreq_always_on_L1, 2); |
164 | } |
165 | ar5416AttachPCIE(ah); |
166 | |
167 | ecode = ath_hal_v4kEepromAttach(ah); |
168 | if (ecode != HAL_OK) |
169 | goto bad; |
170 | |
171 | if (!ar5416ChipReset(ah, AH_NULL)) { /* reset chip */ |
172 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n" , |
173 | __func__); |
174 | ecode = HAL_EIO; |
175 | goto bad; |
176 | } |
177 | |
178 | AH_PRIVATE(ah)->ah_phyRev = OS_REG_READ(ah, AR_PHY_CHIP_ID); |
179 | |
180 | if (!ar5212ChipTest(ah)) { |
181 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: hardware self-test failed\n" , |
182 | __func__); |
183 | ecode = HAL_ESELFTEST; |
184 | goto bad; |
185 | } |
186 | |
187 | /* |
188 | * Set correct Baseband to analog shift |
189 | * setting to access analog chips. |
190 | */ |
191 | OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); |
192 | |
193 | /* Read Radio Chip Rev Extract */ |
194 | AH_PRIVATE(ah)->ah_analog5GhzRev = ar5416GetRadioRev(ah); |
195 | switch (AH_PRIVATE(ah)->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR) { |
196 | case AR_RAD2133_SREV_MAJOR: /* Sowl: 2G/3x3 */ |
197 | case AR_RAD5133_SREV_MAJOR: /* Sowl: 2+5G/3x3 */ |
198 | break; |
199 | default: |
200 | if (AH_PRIVATE(ah)->ah_analog5GhzRev == 0) { |
201 | AH_PRIVATE(ah)->ah_analog5GhzRev = |
202 | AR_RAD5133_SREV_MAJOR; |
203 | break; |
204 | } |
205 | #ifdef AH_DEBUG |
206 | HALDEBUG(ah, HAL_DEBUG_ANY, |
207 | "%s: 5G Radio Chip Rev 0x%02X is not supported by " |
208 | "this driver\n" , __func__, |
209 | AH_PRIVATE(ah)->ah_analog5GhzRev); |
210 | ecode = HAL_ENOTSUPP; |
211 | goto bad; |
212 | #endif |
213 | } |
214 | rfStatus = ar9285RfAttach(ah, &ecode); |
215 | if (!rfStatus) { |
216 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: RF setup failed, status %u\n" , |
217 | __func__, ecode); |
218 | goto bad; |
219 | } |
220 | |
221 | HAL_INI_INIT(&ahp9285->ah_ini_rxgain, ar9280Modes_original_rxgain_v2, |
222 | 6); |
223 | /* setup txgain table */ |
224 | switch (ath_hal_eepromGet(ah, AR_EEP_TXGAIN_TYPE, AH_NULL)) { |
225 | case AR5416_EEP_TXGAIN_HIGH_POWER: |
226 | HAL_INI_INIT(&ahp9285->ah_ini_txgain, |
227 | ar9285Modes_high_power_tx_gain_v2, 6); |
228 | break; |
229 | case AR5416_EEP_TXGAIN_ORIG: |
230 | HAL_INI_INIT(&ahp9285->ah_ini_txgain, |
231 | ar9285Modes_original_tx_gain_v2, 6); |
232 | break; |
233 | default: |
234 | HALASSERT(AH_FALSE); |
235 | goto bad; /* XXX ? try to continue */ |
236 | } |
237 | |
238 | /* |
239 | * Got everything we need now to setup the capabilities. |
240 | */ |
241 | if (!ar9285FillCapabilityInfo(ah)) { |
242 | ecode = HAL_EEREAD; |
243 | goto bad; |
244 | } |
245 | |
246 | ecode = ath_hal_eepromGet(ah, AR_EEP_MACADDR, ahp->ah_macaddr); |
247 | if (ecode != HAL_OK) { |
248 | HALDEBUG(ah, HAL_DEBUG_ANY, |
249 | "%s: error getting mac address from EEPROM\n" , __func__); |
250 | goto bad; |
251 | } |
252 | /* XXX How about the serial number ? */ |
253 | /* Read Reg Domain */ |
254 | AH_PRIVATE(ah)->ah_currentRD = |
255 | ath_hal_eepromGet(ah, AR_EEP_REGDMN_0, AH_NULL); |
256 | |
257 | /* |
258 | * ah_miscMode is populated by ar5416FillCapabilityInfo() |
259 | * starting from griffin. Set here to make sure that |
260 | * AR_MISC_MODE_MIC_NEW_LOC_ENABLE is set before a GTK is |
261 | * placed into hardware. |
262 | */ |
263 | if (ahp->ah_miscMode != 0) |
264 | OS_REG_WRITE(ah, AR_MISC_MODE, ahp->ah_miscMode); |
265 | |
266 | ar9285AniSetup(ah); /* Anti Noise Immunity */ |
267 | ar5416InitNfHistBuff(AH5416(ah)->ah_cal.nfCalHist); |
268 | |
269 | HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s: return\n" , __func__); |
270 | |
271 | return ah; |
272 | bad: |
273 | if (ah != AH_NULL) |
274 | ah->ah_detach(ah); |
275 | if (status) |
276 | *status = ecode; |
277 | return AH_NULL; |
278 | } |
279 | |
280 | static void |
281 | ar9285ConfigPCIE(struct ath_hal *ah, HAL_BOOL restore) |
282 | { |
283 | if (AH_PRIVATE(ah)->ah_ispcie && !restore) { |
284 | ath_hal_ini_write(ah, &AH5416(ah)->ah_ini_pcieserdes, 1, 0); |
285 | OS_DELAY(1000); |
286 | OS_REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); |
287 | OS_REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT); |
288 | } |
289 | } |
290 | |
291 | static void |
292 | ar9285WriteIni(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) |
293 | { |
294 | u_int modesIndex; |
295 | int regWrites = 0; |
296 | |
297 | /* Setup the indices for the next set of register array writes */ |
298 | /* XXX Ignore 11n dynamic mode on the AR5416 for the moment */ |
299 | if (IS_CHAN_HT40(chan)) |
300 | modesIndex = 3; |
301 | else if (IS_CHAN_108G(chan)) |
302 | modesIndex = 5; |
303 | else |
304 | modesIndex = 4; |
305 | |
306 | /* Set correct Baseband to analog shift setting to access analog chips. */ |
307 | OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); |
308 | OS_REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); |
309 | regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_modes, |
310 | modesIndex, regWrites); |
311 | if (AR_SREV_KITE_12_OR_LATER(ah)) { |
312 | regWrites = ath_hal_ini_write(ah, &AH9285(ah)->ah_ini_txgain, |
313 | modesIndex, regWrites); |
314 | } |
315 | regWrites = ath_hal_ini_write(ah, &AH5212(ah)->ah_ini_common, |
316 | 1, regWrites); |
317 | |
318 | OS_REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); |
319 | |
320 | if (AR_SREV_MERLIN_10_OR_LATER(ah)) { |
321 | uint32_t val; |
322 | val = OS_REG_READ(ah, AR_PCU_MISC_MODE2) & |
323 | (~AR_PCU_MISC_MODE2_HWWAR1); |
324 | OS_REG_WRITE(ah, AR_PCU_MISC_MODE2, val); |
325 | OS_REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); |
326 | } |
327 | |
328 | } |
329 | |
330 | /* |
331 | * Fill all software cached or static hardware state information. |
332 | * Return failure if capabilities are to come from EEPROM and |
333 | * cannot be read. |
334 | */ |
335 | static HAL_BOOL |
336 | ar9285FillCapabilityInfo(struct ath_hal *ah) |
337 | { |
338 | HAL_CAPABILITIES *pCap = &AH_PRIVATE(ah)->ah_caps; |
339 | |
340 | if (!ar5416FillCapabilityInfo(ah)) |
341 | return AH_FALSE; |
342 | pCap->halNumGpioPins = 12; |
343 | pCap->halWowSupport = AH_TRUE; |
344 | pCap->halWowMatchPatternExact = AH_TRUE; |
345 | #if 0 |
346 | pCap->halWowMatchPatternDword = AH_TRUE; |
347 | #endif |
348 | pCap->halCSTSupport = AH_TRUE; |
349 | pCap->halRifsRxSupport = AH_TRUE; |
350 | pCap->halRifsTxSupport = AH_TRUE; |
351 | pCap->halRtsAggrLimit = 64*1024; /* 802.11n max */ |
352 | pCap->halExtChanDfsSupport = AH_TRUE; |
353 | #if 0 |
354 | /* XXX bluetooth */ |
355 | pCap->halBtCoexSupport = AH_TRUE; |
356 | #endif |
357 | pCap->halAutoSleepSupport = AH_FALSE; /* XXX? */ |
358 | #if 0 |
359 | pCap->hal4kbSplitTransSupport = AH_FALSE; |
360 | #endif |
361 | pCap->halRxStbcSupport = 1; |
362 | pCap->halTxStbcSupport = 1; |
363 | |
364 | return AH_TRUE; |
365 | } |
366 | |
367 | HAL_BOOL |
368 | ar9285SetAntennaSwitch(struct ath_hal *ah, HAL_ANT_SETTING settings) |
369 | { |
370 | #define ANTENNA0_CHAINMASK 0x1 |
371 | #define ANTENNA1_CHAINMASK 0x2 |
372 | struct ath_hal_5416 *ahp = AH5416(ah); |
373 | |
374 | /* Antenna selection is done by setting the tx/rx chainmasks approp. */ |
375 | switch (settings) { |
376 | case HAL_ANT_FIXED_A: |
377 | /* Enable first antenna only */ |
378 | ahp->ah_tx_chainmask = ANTENNA0_CHAINMASK; |
379 | ahp->ah_rx_chainmask = ANTENNA0_CHAINMASK; |
380 | break; |
381 | case HAL_ANT_FIXED_B: |
382 | /* Enable second antenna only, after checking capability */ |
383 | if (AH_PRIVATE(ah)->ah_caps.halTxChainMask > ANTENNA1_CHAINMASK) |
384 | ahp->ah_tx_chainmask = ANTENNA1_CHAINMASK; |
385 | ahp->ah_rx_chainmask = ANTENNA1_CHAINMASK; |
386 | break; |
387 | case HAL_ANT_VARIABLE: |
388 | /* Restore original chainmask settings */ |
389 | /* XXX */ |
390 | ahp->ah_tx_chainmask = AR9285_DEFAULT_TXCHAINMASK; |
391 | ahp->ah_rx_chainmask = AR9285_DEFAULT_RXCHAINMASK; |
392 | break; |
393 | } |
394 | return AH_TRUE; |
395 | #undef ANTENNA0_CHAINMASK |
396 | #undef ANTENNA1_CHAINMASK |
397 | } |
398 | |
399 | static const char* |
400 | ar9285Probe(uint16_t vendorid, uint16_t devid) |
401 | { |
402 | if (vendorid == ATHEROS_VENDOR_ID && devid == AR9285_DEVID_PCIE) |
403 | return "Atheros 9285" ; |
404 | return AH_NULL; |
405 | } |
406 | AH_CHIP(AR9285, ar9285Probe, ar9285Attach); |
407 | |