1 | /* |
2 | * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting |
3 | * Copyright (c) 2002-2004 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 | * $Id: ar5210_reset.c,v 1.7 2015/11/24 08:48:25 jklos Exp $ |
18 | */ |
19 | #include "opt_ah.h" |
20 | |
21 | #include "ah.h" |
22 | #include "ah_internal.h" |
23 | |
24 | #include "ar5210/ar5210.h" |
25 | #include "ar5210/ar5210reg.h" |
26 | #include "ar5210/ar5210phy.h" |
27 | |
28 | #include "ah_eeprom_v1.h" |
29 | |
30 | typedef struct { |
31 | uint32_t Offset; |
32 | uint32_t Value; |
33 | } REGISTER_VAL; |
34 | |
35 | static const REGISTER_VAL ar5k0007_init[] = { |
36 | #include "ar5210/ar5k_0007.ini" |
37 | }; |
38 | |
39 | /* Default Power Settings for channels outside of EEPROM range */ |
40 | static const uint8_t ar5k0007_pwrSettings[17] = { |
41 | /* gain delta pc dac */ |
42 | /* 54 48 36 24 18 12 9 54 48 36 24 18 12 9 6 ob db */ |
43 | 9, 9, 0, 0, 0, 0, 0, 2, 2, 6, 6, 6, 6, 6, 6, 2, 2 |
44 | }; |
45 | |
46 | /* |
47 | * The delay, in usecs, between writing AR_RC with a reset |
48 | * request and waiting for the chip to settle. If this is |
49 | * too short then the chip does not come out of sleep state. |
50 | * Note this value was empirically derived and may be dependent |
51 | * on the host machine (don't know--the problem was identified |
52 | * on an IBM 570e laptop; 10us delays worked on other systems). |
53 | */ |
54 | #define AR_RC_SETTLE_TIME 20000 |
55 | |
56 | static HAL_BOOL ar5210SetResetReg(struct ath_hal *, |
57 | uint32_t resetMask, u_int waitTime); |
58 | static HAL_BOOL ar5210SetChannel(struct ath_hal *, HAL_CHANNEL_INTERNAL *); |
59 | static void ar5210SetOperatingMode(struct ath_hal *, int opmode); |
60 | |
61 | /* |
62 | * Places the device in and out of reset and then places sane |
63 | * values in the registers based on EEPROM config, initialization |
64 | * vectors (as determined by the mode), and station configuration |
65 | * |
66 | * bChannelChange is used to preserve DMA/PCU registers across |
67 | * a HW Reset during channel change. |
68 | */ |
69 | HAL_BOOL |
70 | ar5210Reset(struct ath_hal *ah, HAL_OPMODE opmode, |
71 | HAL_CHANNEL *chan, HAL_BOOL bChannelChange, HAL_STATUS *status) |
72 | { |
73 | #define N(a) (sizeof (a) /sizeof (a[0])) |
74 | #define FAIL(_code) do { ecode = _code; goto bad; } while (0) |
75 | struct ath_hal_5210 *ahp = AH5210(ah); |
76 | const HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom; |
77 | HAL_CHANNEL_INTERNAL *ichan; |
78 | HAL_STATUS ecode; |
79 | uint32_t ledstate; |
80 | int i, q; |
81 | |
82 | HALDEBUG(ah, HAL_DEBUG_RESET, |
83 | "%s: opmode %u channel %u/0x%x %s channel\n" , __func__, |
84 | opmode, chan->channel, chan->channelFlags, |
85 | bChannelChange ? "change" : "same" ); |
86 | |
87 | if ((chan->channelFlags & CHANNEL_5GHZ) == 0) { |
88 | /* Only 11a mode */ |
89 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: channel not 5Ghz\n" , __func__); |
90 | FAIL(HAL_EINVAL); |
91 | } |
92 | /* |
93 | * Map public channel to private. |
94 | */ |
95 | ichan = ath_hal_checkchannel(ah, chan); |
96 | if (ichan == AH_NULL) { |
97 | HALDEBUG(ah, HAL_DEBUG_ANY, |
98 | "%s: invalid channel %u/0x%x; no mapping\n" , |
99 | __func__, chan->channel, chan->channelFlags); |
100 | FAIL(HAL_EINVAL); |
101 | } |
102 | switch (opmode) { |
103 | case HAL_M_STA: |
104 | case HAL_M_IBSS: |
105 | case HAL_M_HOSTAP: |
106 | case HAL_M_MONITOR: |
107 | break; |
108 | default: |
109 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid operating mode %u\n" , |
110 | __func__, opmode); |
111 | FAIL(HAL_EINVAL); |
112 | break; |
113 | } |
114 | |
115 | ledstate = OS_REG_READ(ah, AR_PCICFG) & |
116 | (AR_PCICFG_LED_PEND | AR_PCICFG_LED_ACT); |
117 | |
118 | if (!ar5210ChipReset(ah, chan)) { |
119 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: chip reset failed\n" , |
120 | __func__); |
121 | FAIL(HAL_EIO); |
122 | } |
123 | |
124 | OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr)); |
125 | OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4)); |
126 | ar5210SetOperatingMode(ah, opmode); |
127 | |
128 | switch (opmode) { |
129 | case HAL_M_HOSTAP: |
130 | OS_REG_WRITE(ah, AR_BCR, INIT_BCON_CNTRL_REG); |
131 | OS_REG_WRITE(ah, AR_PCICFG, |
132 | AR_PCICFG_LED_ACT | AR_PCICFG_LED_BCTL); |
133 | break; |
134 | case HAL_M_IBSS: |
135 | OS_REG_WRITE(ah, AR_BCR, INIT_BCON_CNTRL_REG | AR_BCR_BCMD); |
136 | OS_REG_WRITE(ah, AR_PCICFG, |
137 | AR_PCICFG_CLKRUNEN | AR_PCICFG_LED_PEND | AR_PCICFG_LED_BCTL); |
138 | break; |
139 | case HAL_M_STA: |
140 | OS_REG_WRITE(ah, AR_BCR, INIT_BCON_CNTRL_REG); |
141 | OS_REG_WRITE(ah, AR_PCICFG, |
142 | AR_PCICFG_CLKRUNEN | AR_PCICFG_LED_PEND | AR_PCICFG_LED_BCTL); |
143 | break; |
144 | case HAL_M_MONITOR: |
145 | OS_REG_WRITE(ah, AR_BCR, INIT_BCON_CNTRL_REG); |
146 | OS_REG_WRITE(ah, AR_PCICFG, |
147 | AR_PCICFG_LED_ACT | AR_PCICFG_LED_BCTL); |
148 | break; |
149 | } |
150 | |
151 | /* Restore previous led state */ |
152 | OS_REG_WRITE(ah, AR_PCICFG, OS_REG_READ(ah, AR_PCICFG) | ledstate); |
153 | |
154 | OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); |
155 | OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4)); |
156 | |
157 | OS_REG_WRITE(ah, AR_TXDP0, 0); |
158 | OS_REG_WRITE(ah, AR_TXDP1, 0); |
159 | OS_REG_WRITE(ah, AR_RXDP, 0); |
160 | |
161 | /* |
162 | * Initialize interrupt state. |
163 | */ |
164 | (void) OS_REG_READ(ah, AR_ISR); /* cleared on read */ |
165 | OS_REG_WRITE(ah, AR_IMR, 0); |
166 | OS_REG_WRITE(ah, AR_IER, AR_IER_DISABLE); |
167 | ahp->ah_maskReg = 0; |
168 | |
169 | (void) OS_REG_READ(ah, AR_BSR); /* cleared on read */ |
170 | OS_REG_WRITE(ah, AR_TXCFG, AR_DMASIZE_128B); |
171 | OS_REG_WRITE(ah, AR_RXCFG, AR_DMASIZE_128B); |
172 | |
173 | OS_REG_WRITE(ah, AR_TOPS, 8); /* timeout prescale */ |
174 | OS_REG_WRITE(ah, AR_RXNOFRM, 8); /* RX no frame timeout */ |
175 | OS_REG_WRITE(ah, AR_RPGTO, 0); /* RX frame gap timeout */ |
176 | OS_REG_WRITE(ah, AR_TXNOFRM, 0); /* TX no frame timeout */ |
177 | |
178 | OS_REG_WRITE(ah, AR_SFR, 0); |
179 | OS_REG_WRITE(ah, AR_MIBC, 0); /* unfreeze ctrs + clr state */ |
180 | OS_REG_WRITE(ah, AR_RSSI_THR, ahp->ah_rssiThr); |
181 | OS_REG_WRITE(ah, AR_CFP_DUR, 0); |
182 | |
183 | ar5210SetRxFilter(ah, 0); /* nothing for now */ |
184 | OS_REG_WRITE(ah, AR_MCAST_FIL0, 0); /* multicast filter */ |
185 | OS_REG_WRITE(ah, AR_MCAST_FIL1, 0); /* XXX was 2 */ |
186 | |
187 | OS_REG_WRITE(ah, AR_TX_MASK0, 0); |
188 | OS_REG_WRITE(ah, AR_TX_MASK1, 0); |
189 | OS_REG_WRITE(ah, AR_CLR_TMASK, 1); |
190 | OS_REG_WRITE(ah, AR_TRIG_LEV, 1); /* minimum */ |
191 | |
192 | OS_REG_WRITE(ah, AR_DIAG_SW, 0); |
193 | |
194 | OS_REG_WRITE(ah, AR_CFP_PERIOD, 0); |
195 | OS_REG_WRITE(ah, AR_TIMER0, 0); /* next beacon time */ |
196 | OS_REG_WRITE(ah, AR_TSF_L32, 0); /* local clock */ |
197 | OS_REG_WRITE(ah, AR_TIMER1, ~0); /* next DMA beacon alert */ |
198 | OS_REG_WRITE(ah, AR_TIMER2, ~0); /* next SW beacon alert */ |
199 | OS_REG_WRITE(ah, AR_TIMER3, 1); /* next ATIM window */ |
200 | |
201 | /* Write the INI values for PHYreg initialization */ |
202 | for (i = 0; i < N(ar5k0007_init); i++) { |
203 | uint32_t reg = ar5k0007_init[i].Offset; |
204 | /* On channel change, don't reset the PCU registers */ |
205 | if (!(bChannelChange && (0x8000 <= reg && reg < 0x9000))) |
206 | OS_REG_WRITE(ah, reg, ar5k0007_init[i].Value); |
207 | } |
208 | |
209 | /* Setup the transmit power values for cards since 0x0[0-2]05 */ |
210 | if (!ar5210SetTransmitPower(ah, chan)) { |
211 | HALDEBUG(ah, HAL_DEBUG_ANY, |
212 | "%s: error init'ing transmit power\n" , __func__); |
213 | FAIL(HAL_EIO); |
214 | } |
215 | |
216 | OS_REG_WRITE(ah, AR_PHY(10), |
217 | (OS_REG_READ(ah, AR_PHY(10)) & 0xFFFF00FF) | |
218 | (ee->ee_xlnaOn << 8)); |
219 | OS_REG_WRITE(ah, AR_PHY(13), |
220 | (ee->ee_xpaOff << 24) | (ee->ee_xpaOff << 16) | |
221 | (ee->ee_xpaOn << 8) | ee->ee_xpaOn); |
222 | OS_REG_WRITE(ah, AR_PHY(17), |
223 | (OS_REG_READ(ah, AR_PHY(17)) & 0xFFFFC07F) | |
224 | ((ee->ee_antenna >> 1) & 0x3F80)); |
225 | OS_REG_WRITE(ah, AR_PHY(18), |
226 | (OS_REG_READ(ah, AR_PHY(18)) & 0xFFFC0FFF) | |
227 | ((ee->ee_antenna << 10) & 0x3F000)); |
228 | OS_REG_WRITE(ah, AR_PHY(25), |
229 | (OS_REG_READ(ah, AR_PHY(25)) & 0xFFF80FFF) | |
230 | ((ee->ee_thresh62 << 12) & 0x7F000)); |
231 | OS_REG_WRITE(ah, AR_PHY(68), |
232 | (OS_REG_READ(ah, AR_PHY(68)) & 0xFFFFFFFC) | |
233 | (ee->ee_antenna & 0x3)); |
234 | |
235 | if (!ar5210SetChannel(ah, ichan)) { |
236 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: unable to set channel\n" , |
237 | __func__); |
238 | FAIL(HAL_EIO); |
239 | } |
240 | if (bChannelChange) { |
241 | if (!(ichan->privFlags & CHANNEL_DFS)) |
242 | ichan->privFlags &= ~CHANNEL_INTERFERENCE; |
243 | chan->channelFlags = ichan->channelFlags; |
244 | chan->privFlags = ichan->privFlags; |
245 | } |
246 | |
247 | /* Activate the PHY */ |
248 | OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ENABLE); |
249 | |
250 | OS_DELAY(1000); /* Wait a bit (1 msec) */ |
251 | |
252 | /* calibrate the HW and poll the bit going to 0 for completion */ |
253 | OS_REG_WRITE(ah, AR_PHY_AGCCTL, |
254 | OS_REG_READ(ah, AR_PHY_AGCCTL) | AR_PHY_AGC_CAL); |
255 | (void) ath_hal_wait(ah, AR_PHY_AGCCTL, AR_PHY_AGC_CAL, 0); |
256 | |
257 | /* Perform noise floor calibration and set status */ |
258 | if (!ar5210CalNoiseFloor(ah, ichan)) { |
259 | chan->channelFlags |= CHANNEL_CW_INT; |
260 | HALDEBUG(ah, HAL_DEBUG_ANY, |
261 | "%s: noise floor calibration failed\n" , __func__); |
262 | FAIL(HAL_EIO); |
263 | } |
264 | |
265 | for (q = 0; q < HAL_NUM_TX_QUEUES; q++) |
266 | ar5210ResetTxQueue(ah, q); |
267 | |
268 | if (AH_PRIVATE(ah)->ah_rfkillEnabled) |
269 | ar5210EnableRfKill(ah); |
270 | |
271 | /* |
272 | * Writing to AR_BEACON will start timers. Hence it should be |
273 | * the last register to be written. Do not reset tsf, do not |
274 | * enable beacons at this point, but preserve other values |
275 | * like beaconInterval. |
276 | */ |
277 | OS_REG_WRITE(ah, AR_BEACON, |
278 | (OS_REG_READ(ah, AR_BEACON) & |
279 | ~(AR_BEACON_EN | AR_BEACON_RESET_TSF))); |
280 | |
281 | /* Restore user-specified slot time and timeouts */ |
282 | if (ahp->ah_sifstime != (u_int) -1) |
283 | ar5210SetSifsTime(ah, ahp->ah_sifstime); |
284 | if (ahp->ah_slottime != (u_int) -1) |
285 | ar5210SetSlotTime(ah, ahp->ah_slottime); |
286 | if (ahp->ah_acktimeout != (u_int) -1) |
287 | ar5210SetAckTimeout(ah, ahp->ah_acktimeout); |
288 | if (ahp->ah_ctstimeout != (u_int) -1) |
289 | ar5210SetCTSTimeout(ah, ahp->ah_ctstimeout); |
290 | if (AH_PRIVATE(ah)->ah_diagreg != 0) |
291 | OS_REG_WRITE(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); |
292 | |
293 | AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */ |
294 | |
295 | HALDEBUG(ah, HAL_DEBUG_RESET, "%s: done\n" , __func__); |
296 | |
297 | return AH_TRUE; |
298 | bad: |
299 | if (status != AH_NULL) |
300 | *status = ecode; |
301 | return AH_FALSE; |
302 | #undef FAIL |
303 | #undef N |
304 | } |
305 | |
306 | static void |
307 | ar5210SetOperatingMode(struct ath_hal *ah, int opmode) |
308 | { |
309 | struct ath_hal_5210 *ahp = AH5210(ah); |
310 | uint32_t val; |
311 | |
312 | val = OS_REG_READ(ah, AR_STA_ID1) & 0xffff; |
313 | switch (opmode) { |
314 | case HAL_M_HOSTAP: |
315 | OS_REG_WRITE(ah, AR_STA_ID1, val |
316 | | AR_STA_ID1_AP |
317 | | AR_STA_ID1_NO_PSPOLL |
318 | | AR_STA_ID1_DESC_ANTENNA |
319 | | ahp->ah_staId1Defaults); |
320 | break; |
321 | case HAL_M_IBSS: |
322 | OS_REG_WRITE(ah, AR_STA_ID1, val |
323 | | AR_STA_ID1_ADHOC |
324 | | AR_STA_ID1_NO_PSPOLL |
325 | | AR_STA_ID1_DESC_ANTENNA |
326 | | ahp->ah_staId1Defaults); |
327 | break; |
328 | case HAL_M_STA: |
329 | OS_REG_WRITE(ah, AR_STA_ID1, val |
330 | | AR_STA_ID1_NO_PSPOLL |
331 | | AR_STA_ID1_PWR_SV |
332 | | ahp->ah_staId1Defaults); |
333 | break; |
334 | case HAL_M_MONITOR: |
335 | OS_REG_WRITE(ah, AR_STA_ID1, val |
336 | | AR_STA_ID1_NO_PSPOLL |
337 | | ahp->ah_staId1Defaults); |
338 | break; |
339 | } |
340 | } |
341 | |
342 | void |
343 | ar5210SetPCUConfig(struct ath_hal *ah) |
344 | { |
345 | ar5210SetOperatingMode(ah, AH_PRIVATE(ah)->ah_opmode); |
346 | } |
347 | |
348 | /* |
349 | * Places the PHY and Radio chips into reset. A full reset |
350 | * must be called to leave this state. The PCI/MAC/PCU are |
351 | * not placed into reset as we must receive interrupt to |
352 | * re-enable the hardware. |
353 | */ |
354 | HAL_BOOL |
355 | ar5210PhyDisable(struct ath_hal *ah) |
356 | { |
357 | return ar5210SetResetReg(ah, AR_RC_RPHY, 10); |
358 | } |
359 | |
360 | /* |
361 | * Places all of hardware into reset |
362 | */ |
363 | HAL_BOOL |
364 | ar5210Disable(struct ath_hal *ah) |
365 | { |
366 | #define AR_RC_HW (AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC) |
367 | if (!ar5210SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) |
368 | return AH_FALSE; |
369 | |
370 | /* |
371 | * Reset the HW - PCI must be reset after the rest of the |
372 | * device has been reset |
373 | */ |
374 | if (!ar5210SetResetReg(ah, AR_RC_HW, AR_RC_SETTLE_TIME)) |
375 | return AH_FALSE; |
376 | OS_DELAY(1000); |
377 | (void) ar5210SetResetReg(ah, AR_RC_HW | AR_RC_RPCI, AR_RC_SETTLE_TIME); |
378 | OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */ |
379 | |
380 | return AH_TRUE; |
381 | #undef AR_RC_HW |
382 | } |
383 | |
384 | /* |
385 | * Places the hardware into reset and then pulls it out of reset |
386 | */ |
387 | HAL_BOOL |
388 | ar5210ChipReset(struct ath_hal *ah, HAL_CHANNEL *chan) |
389 | { |
390 | #define AR_RC_HW (AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC) |
391 | |
392 | HALDEBUG(ah, HAL_DEBUG_RESET, "%s turbo %s\n" , __func__, |
393 | chan && IS_CHAN_TURBO(chan) ? "enabled" : "disabled" ); |
394 | |
395 | if (!ar5210SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) |
396 | return AH_FALSE; |
397 | |
398 | /* Place chip in turbo before reset to cleanly reset clocks */ |
399 | OS_REG_WRITE(ah, AR_PHY_FRCTL, |
400 | chan && IS_CHAN_TURBO(chan) ? AR_PHY_TURBO_MODE : 0); |
401 | |
402 | /* |
403 | * Reset the HW. |
404 | * PCI must be reset after the rest of the device has been reset. |
405 | */ |
406 | if (!ar5210SetResetReg(ah, AR_RC_HW, AR_RC_SETTLE_TIME)) |
407 | return AH_FALSE; |
408 | OS_DELAY(1000); |
409 | if (!ar5210SetResetReg(ah, AR_RC_HW | AR_RC_RPCI, AR_RC_SETTLE_TIME)) |
410 | return AH_FALSE; |
411 | OS_DELAY(2100); /* 8245 @ 96Mhz hangs with 2000us. */ |
412 | |
413 | /* |
414 | * Bring out of sleep mode (AGAIN) |
415 | * |
416 | * WARNING WARNING WARNING |
417 | * |
418 | * There is a problem with the chip where it doesn't always indicate |
419 | * that it's awake, so initializePowerUp() will fail. |
420 | */ |
421 | if (!ar5210SetPowerMode(ah, HAL_PM_AWAKE, AH_TRUE)) |
422 | return AH_FALSE; |
423 | |
424 | /* Clear warm reset reg */ |
425 | return ar5210SetResetReg(ah, 0, 10); |
426 | #undef AR_RC_HW |
427 | } |
428 | |
429 | enum { |
430 | FIRPWR_M = 0x03fc0000, |
431 | FIRPWR_S = 18, |
432 | KCOARSEHIGH_M = 0x003f8000, |
433 | KCOARSEHIGH_S = 15, |
434 | KCOARSELOW_M = 0x00007f80, |
435 | KCOARSELOW_S = 7, |
436 | ADCSAT_ICOUNT_M = 0x0001f800, |
437 | ADCSAT_ICOUNT_S = 11, |
438 | ADCSAT_THRESH_M = 0x000007e0, |
439 | ADCSAT_THRESH_S = 5 |
440 | }; |
441 | |
442 | /* |
443 | * Recalibrate the lower PHY chips to account for temperature/environment |
444 | * changes. |
445 | */ |
446 | HAL_BOOL |
447 | ar5210PerCalibrationN(struct ath_hal *ah, HAL_CHANNEL *chan, u_int chainMask, |
448 | HAL_BOOL longCal, HAL_BOOL *isCalDone) |
449 | { |
450 | uint32_t regBeacon; |
451 | uint32_t reg9858, reg985c, reg9868; |
452 | HAL_CHANNEL_INTERNAL *ichan; |
453 | |
454 | ichan = ath_hal_checkchannel(ah, chan); |
455 | if (ichan == AH_NULL) { |
456 | HALDEBUG(ah, HAL_DEBUG_ANY, |
457 | "%s: invalid channel %u/0x%x; no mapping\n" , |
458 | __func__, chan->channel, chan->channelFlags); |
459 | return AH_FALSE; |
460 | } |
461 | /* Disable tx and rx */ |
462 | OS_REG_WRITE(ah, AR_DIAG_SW, |
463 | OS_REG_READ(ah, AR_DIAG_SW) | (AR_DIAG_SW_DIS_TX | AR_DIAG_SW_DIS_RX)); |
464 | |
465 | /* Disable Beacon Enable */ |
466 | regBeacon = OS_REG_READ(ah, AR_BEACON); |
467 | OS_REG_WRITE(ah, AR_BEACON, regBeacon & ~AR_BEACON_EN); |
468 | |
469 | /* Delay 4ms to ensure that all tx and rx activity has ceased */ |
470 | OS_DELAY(4000); |
471 | |
472 | /* Disable AGC to radio traffic */ |
473 | OS_REG_WRITE(ah, 0x9808, OS_REG_READ(ah, 0x9808) | 0x08000000); |
474 | /* Wait for the AGC traffic to cease. */ |
475 | OS_DELAY(10); |
476 | |
477 | /* Change Channel to relock synth */ |
478 | if (!ar5210SetChannel(ah, ichan)) |
479 | return AH_FALSE; |
480 | |
481 | /* wait for the synthesizer lock to stabilize */ |
482 | OS_DELAY(1000); |
483 | |
484 | /* Re-enable AGC to radio traffic */ |
485 | OS_REG_WRITE(ah, 0x9808, OS_REG_READ(ah, 0x9808) & (~0x08000000)); |
486 | |
487 | /* |
488 | * Configure the AGC so that it is highly unlikely (if not |
489 | * impossible) for it to send any gain changes to the analog |
490 | * chip. We store off the current values so that they can |
491 | * be rewritten below. Setting the following values: |
492 | * firpwr = -1 |
493 | * Kcoursehigh = -1 |
494 | * Kcourselow = -127 |
495 | * ADCsat_icount = 2 |
496 | * ADCsat_thresh = 12 |
497 | */ |
498 | reg9858 = OS_REG_READ(ah, 0x9858); |
499 | reg985c = OS_REG_READ(ah, 0x985c); |
500 | reg9868 = OS_REG_READ(ah, 0x9868); |
501 | |
502 | OS_REG_WRITE(ah, 0x9858, (reg9858 & ~FIRPWR_M) | |
503 | ((~0U << FIRPWR_S) & FIRPWR_M)); |
504 | OS_REG_WRITE(ah, 0x985c, |
505 | (reg985c & ~(KCOARSEHIGH_M | KCOARSELOW_M)) | |
506 | ((~0U << KCOARSEHIGH_S) & KCOARSEHIGH_M) | |
507 | ((((~0U << 7) + 1) << KCOARSELOW_S) & KCOARSELOW_M)); |
508 | OS_REG_WRITE(ah, 0x9868, |
509 | (reg9868 & ~(ADCSAT_ICOUNT_M | ADCSAT_THRESH_M)) | |
510 | ((2 << ADCSAT_ICOUNT_S) & ADCSAT_ICOUNT_M) | |
511 | ((12 << ADCSAT_THRESH_S) & ADCSAT_THRESH_M)); |
512 | |
513 | /* Wait for AGC changes to be enacted */ |
514 | OS_DELAY(20); |
515 | |
516 | /* |
517 | * We disable RF mix/gain stages for the PGA to avoid a |
518 | * race condition that will occur with receiving a frame |
519 | * and performing the AGC calibration. This will be |
520 | * re-enabled at the end of offset cal. We turn off AGC |
521 | * writes during this write as it will go over the analog bus. |
522 | */ |
523 | OS_REG_WRITE(ah, 0x9808, OS_REG_READ(ah, 0x9808) | 0x08000000); |
524 | OS_DELAY(10); /* wait for the AGC traffic to cease */ |
525 | OS_REG_WRITE(ah, 0x98D4, 0x21); |
526 | OS_REG_WRITE(ah, 0x9808, OS_REG_READ(ah, 0x9808) & (~0x08000000)); |
527 | |
528 | /* wait to make sure that additional AGC traffic has quiesced */ |
529 | OS_DELAY(1000); |
530 | |
531 | /* AGC calibration (this was added to make the NF threshold check work) */ |
532 | OS_REG_WRITE(ah, AR_PHY_AGCCTL, |
533 | OS_REG_READ(ah, AR_PHY_AGCCTL) | AR_PHY_AGC_CAL); |
534 | if (!ath_hal_wait(ah, AR_PHY_AGCCTL, AR_PHY_AGC_CAL, 0)) { |
535 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: AGC calibration timeout\n" , |
536 | __func__); |
537 | } |
538 | |
539 | /* Rewrite our AGC values we stored off earlier (return AGC to normal operation) */ |
540 | OS_REG_WRITE(ah, 0x9858, reg9858); |
541 | OS_REG_WRITE(ah, 0x985c, reg985c); |
542 | OS_REG_WRITE(ah, 0x9868, reg9868); |
543 | |
544 | /* Perform noise floor and set status */ |
545 | if (!ar5210CalNoiseFloor(ah, ichan)) { |
546 | /* |
547 | * Delay 5ms before retrying the noise floor - |
548 | * just to make sure. We're in an error |
549 | * condition here |
550 | */ |
551 | HALDEBUG(ah, HAL_DEBUG_NFCAL | HAL_DEBUG_PERCAL, |
552 | "%s: Performing 2nd Noise Cal\n" , __func__); |
553 | OS_DELAY(5000); |
554 | if (!ar5210CalNoiseFloor(ah, ichan)) |
555 | chan->channelFlags |= CHANNEL_CW_INT; |
556 | } |
557 | |
558 | /* Clear tx and rx disable bit */ |
559 | OS_REG_WRITE(ah, AR_DIAG_SW, |
560 | OS_REG_READ(ah, AR_DIAG_SW) & ~(AR_DIAG_SW_DIS_TX | AR_DIAG_SW_DIS_RX)); |
561 | |
562 | /* Re-enable Beacons */ |
563 | OS_REG_WRITE(ah, AR_BEACON, regBeacon); |
564 | |
565 | *isCalDone = AH_TRUE; |
566 | |
567 | return AH_TRUE; |
568 | } |
569 | |
570 | HAL_BOOL |
571 | ar5210PerCalibration(struct ath_hal *ah, HAL_CHANNEL *chan, HAL_BOOL *isIQdone) |
572 | { |
573 | return ar5210PerCalibrationN(ah, chan, 0x1, AH_TRUE, isIQdone); |
574 | } |
575 | |
576 | HAL_BOOL |
577 | ar5210ResetCalValid(struct ath_hal *ah, HAL_CHANNEL *chan) |
578 | { |
579 | return AH_TRUE; |
580 | } |
581 | |
582 | /* |
583 | * Writes the given reset bit mask into the reset register |
584 | */ |
585 | static HAL_BOOL |
586 | ar5210SetResetReg(struct ath_hal *ah, uint32_t resetMask, u_int waitTime) |
587 | { |
588 | uint32_t mask = resetMask ? resetMask : ~0; |
589 | HAL_BOOL rt; |
590 | |
591 | OS_REG_WRITE(ah, AR_RC, resetMask); |
592 | /* need to wait at least 128 clocks when reseting PCI before read */ |
593 | OS_DELAY(waitTime); |
594 | |
595 | resetMask &= AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC; |
596 | mask &= AR_RC_RPCU | AR_RC_RDMA | AR_RC_RPHY | AR_RC_RMAC; |
597 | rt = ath_hal_wait(ah, AR_RC, mask, resetMask); |
598 | if ((resetMask & AR_RC_RMAC) == 0) { |
599 | if (isBigEndian()) { |
600 | /* |
601 | * Set CFG, little-endian for register |
602 | * and descriptor accesses. |
603 | */ |
604 | mask = INIT_CONFIG_STATUS | |
605 | AR_CFG_SWTD | AR_CFG_SWRD | AR_CFG_SWRG; |
606 | OS_REG_WRITE(ah, AR_CFG, LE_READ_4(&mask)); |
607 | } else |
608 | OS_REG_WRITE(ah, AR_CFG, INIT_CONFIG_STATUS); |
609 | } |
610 | return rt; |
611 | } |
612 | |
613 | |
614 | /* |
615 | * Returns: the pcdac value |
616 | */ |
617 | static uint8_t |
618 | getPcdac(struct ath_hal *ah, const struct tpcMap *pRD, uint8_t dBm) |
619 | { |
620 | int32_t i; |
621 | int useNextEntry = AH_FALSE; |
622 | uint32_t interp; |
623 | |
624 | for (i = AR_TP_SCALING_ENTRIES - 1; i >= 0; i--) { |
625 | /* Check for exact entry */ |
626 | if (dBm == AR_I2DBM(i)) { |
627 | if (pRD->pcdac[i] != 63) |
628 | return pRD->pcdac[i]; |
629 | useNextEntry = AH_TRUE; |
630 | } else if (dBm + 1 == AR_I2DBM(i) && i > 0) { |
631 | /* Interpolate for between entry with a logish scale */ |
632 | if (pRD->pcdac[i] != 63 && pRD->pcdac[i-1] != 63) { |
633 | interp = (350 * (pRD->pcdac[i] - pRD->pcdac[i-1])) + 999; |
634 | interp = (interp / 1000) + pRD->pcdac[i-1]; |
635 | return interp; |
636 | } |
637 | useNextEntry = AH_TRUE; |
638 | } else if (useNextEntry == AH_TRUE) { |
639 | /* Grab the next lowest */ |
640 | if (pRD->pcdac[i] != 63) |
641 | return pRD->pcdac[i]; |
642 | } |
643 | } |
644 | |
645 | /* Return the lowest Entry if we haven't returned */ |
646 | for (i = 0; i < AR_TP_SCALING_ENTRIES; i++) |
647 | if (pRD->pcdac[i] != 63) |
648 | return pRD->pcdac[i]; |
649 | |
650 | /* No value to return from table */ |
651 | #ifdef AH_DEBUG |
652 | ath_hal_printf(ah, "%s: empty transmit power table?\n" , __func__); |
653 | #endif |
654 | return 1; |
655 | } |
656 | |
657 | /* |
658 | * Find or interpolates the gainF value from the table ptr. |
659 | */ |
660 | static uint8_t |
661 | getGainF(struct ath_hal *ah, const struct tpcMap *pRD, |
662 | uint8_t pcdac, uint8_t *dBm) |
663 | { |
664 | uint32_t interp; |
665 | int low, high, i; |
666 | |
667 | low = high = -1; |
668 | |
669 | for (i = 0; i < AR_TP_SCALING_ENTRIES; i++) { |
670 | if(pRD->pcdac[i] == 63) |
671 | continue; |
672 | if (pcdac == pRD->pcdac[i]) { |
673 | *dBm = AR_I2DBM(i); |
674 | return pRD->gainF[i]; /* Exact Match */ |
675 | } |
676 | if (pcdac > pRD->pcdac[i]) |
677 | low = i; |
678 | if (pcdac < pRD->pcdac[i]) { |
679 | high = i; |
680 | if (low == -1) { |
681 | *dBm = AR_I2DBM(i); |
682 | /* PCDAC is lower than lowest setting */ |
683 | return pRD->gainF[i]; |
684 | } |
685 | break; |
686 | } |
687 | } |
688 | if (i >= AR_TP_SCALING_ENTRIES && low == -1) { |
689 | /* No settings were found */ |
690 | #ifdef AH_DEBUG |
691 | ath_hal_printf(ah, |
692 | "%s: no valid entries in the pcdac table: %d\n" , |
693 | __func__, pcdac); |
694 | #endif |
695 | return 63; |
696 | } |
697 | if (i >= AR_TP_SCALING_ENTRIES) { |
698 | /* PCDAC setting was above the max setting in the table */ |
699 | *dBm = AR_I2DBM(low); |
700 | return pRD->gainF[low]; |
701 | } |
702 | /* Only exact if table has no missing entries */ |
703 | *dBm = (low + high) + 3; |
704 | |
705 | /* |
706 | * Perform interpolation between low and high values to find gainF |
707 | * linearly scale the pcdac between low and high |
708 | */ |
709 | interp = ((pcdac - pRD->pcdac[low]) * 1000) / |
710 | (pRD->pcdac[high] - pRD->pcdac[low]); |
711 | /* |
712 | * Multiply the scale ratio by the gainF difference |
713 | * (plus a rnd up factor) |
714 | */ |
715 | interp = ((interp * (pRD->gainF[high] - pRD->gainF[low])) + 999) / 1000; |
716 | |
717 | /* Add ratioed gain_f to low gain_f value */ |
718 | return interp + pRD->gainF[low]; |
719 | } |
720 | |
721 | HAL_BOOL |
722 | ar5210SetTxPowerLimit(struct ath_hal *ah, uint32_t limit) |
723 | { |
724 | AH_PRIVATE(ah)->ah_powerLimit = AH_MIN(limit, AR5210_MAX_RATE_POWER); |
725 | /* XXX flush to h/w */ |
726 | return AH_TRUE; |
727 | } |
728 | |
729 | /* |
730 | * Get TXPower values and set them in the radio |
731 | */ |
732 | static HAL_BOOL |
733 | setupPowerSettings(struct ath_hal *ah, HAL_CHANNEL *chan, uint8_t cp[17]) |
734 | { |
735 | const HAL_EEPROM_v1 *ee = AH_PRIVATE(ah)->ah_eeprom; |
736 | uint8_t gainFRD, gainF36, gainF48, gainF54; |
737 | uint8_t dBmRD = 0, dBm36 = 0, dBm48 = 0, dBm54 = 0, dontcare; |
738 | uint32_t rd, group; |
739 | const struct tpcMap *pRD; |
740 | |
741 | /* Set OB/DB Values regardless of channel */ |
742 | cp[15] = (ee->ee_biasCurrents >> 4) & 0x7; |
743 | cp[16] = ee->ee_biasCurrents & 0x7; |
744 | |
745 | if (chan->channel < 5170 || chan->channel > 5320) { |
746 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: invalid channel %u\n" , |
747 | __func__, chan->channel); |
748 | return AH_FALSE; |
749 | } |
750 | |
751 | HALASSERT(ee->ee_version >= AR_EEPROM_VER1 && |
752 | ee->ee_version < AR_EEPROM_VER3); |
753 | |
754 | /* Match regulatory domain */ |
755 | for (rd = 0; rd < AR_REG_DOMAINS_MAX; rd++) |
756 | if (AH_PRIVATE(ah)->ah_currentRD == ee->ee_regDomain[rd]) |
757 | break; |
758 | if (rd == AR_REG_DOMAINS_MAX) { |
759 | #ifdef AH_DEBUG |
760 | ath_hal_printf(ah, |
761 | "%s: no calibrated regulatory domain matches the " |
762 | "current regularly domain (0x%0x)\n" , __func__, |
763 | AH_PRIVATE(ah)->ah_currentRD); |
764 | #endif |
765 | return AH_FALSE; |
766 | } |
767 | group = ((chan->channel - 5170) / 10); |
768 | |
769 | if (group > 11) { |
770 | /* Pull 5.29 into the 5.27 group */ |
771 | group--; |
772 | } |
773 | |
774 | /* Integer divide will set group from 0 to 4 */ |
775 | group = group / 3; |
776 | pRD = &ee->ee_tpc[group]; |
777 | |
778 | /* Set PC DAC Values */ |
779 | cp[14] = pRD->regdmn[rd]; |
780 | cp[9] = AH_MIN(pRD->regdmn[rd], pRD->rate36); |
781 | cp[8] = AH_MIN(pRD->regdmn[rd], pRD->rate48); |
782 | cp[7] = AH_MIN(pRD->regdmn[rd], pRD->rate54); |
783 | |
784 | /* Find Corresponding gainF values for RD, 36, 48, 54 */ |
785 | gainFRD = getGainF(ah, pRD, pRD->regdmn[rd], &dBmRD); |
786 | gainF36 = getGainF(ah, pRD, cp[9], &dBm36); |
787 | gainF48 = getGainF(ah, pRD, cp[8], &dBm48); |
788 | gainF54 = getGainF(ah, pRD, cp[7], &dBm54); |
789 | |
790 | /* Power Scale if requested */ |
791 | if (AH_PRIVATE(ah)->ah_tpScale != HAL_TP_SCALE_MAX) { |
792 | static const uint16_t tpcScaleReductionTable[5] = |
793 | { 0, 3, 6, 9, AR5210_MAX_RATE_POWER }; |
794 | uint16_t tpScale; |
795 | |
796 | tpScale = tpcScaleReductionTable[AH_PRIVATE(ah)->ah_tpScale]; |
797 | if (dBmRD < tpScale+3) |
798 | dBmRD = 3; /* min */ |
799 | else |
800 | dBmRD -= tpScale; |
801 | cp[14] = getPcdac(ah, pRD, dBmRD); |
802 | gainFRD = getGainF(ah, pRD, cp[14], &dontcare); |
803 | dBm36 = AH_MIN(dBm36, dBmRD); |
804 | cp[9] = getPcdac(ah, pRD, dBm36); |
805 | gainF36 = getGainF(ah, pRD, cp[9], &dontcare); |
806 | dBm48 = AH_MIN(dBm48, dBmRD); |
807 | cp[8] = getPcdac(ah, pRD, dBm48); |
808 | gainF48 = getGainF(ah, pRD, cp[8], &dontcare); |
809 | dBm54 = AH_MIN(dBm54, dBmRD); |
810 | cp[7] = getPcdac(ah, pRD, dBm54); |
811 | gainF54 = getGainF(ah, pRD, cp[7], &dontcare); |
812 | } |
813 | /* Record current dBm at rate 6 */ |
814 | AH_PRIVATE(ah)->ah_maxPowerLevel = 2*dBmRD; |
815 | |
816 | cp[13] = cp[12] = cp[11] = cp[10] = cp[14]; |
817 | |
818 | /* Set GainF Values */ |
819 | cp[0] = gainFRD - gainF54; |
820 | cp[1] = gainFRD - gainF48; |
821 | cp[2] = gainFRD - gainF36; |
822 | /* 9, 12, 18, 24 have no gain_delta from 6 */ |
823 | cp[3] = cp[4] = cp[5] = cp[6] = 0; |
824 | return AH_TRUE; |
825 | } |
826 | |
827 | /* |
828 | * Places the device in and out of reset and then places sane |
829 | * values in the registers based on EEPROM config, initialization |
830 | * vectors (as determined by the mode), and station configuration |
831 | */ |
832 | HAL_BOOL |
833 | ar5210SetTransmitPower(struct ath_hal *ah, HAL_CHANNEL *chan) |
834 | { |
835 | #define N(a) (sizeof (a) / sizeof (a[0])) |
836 | static const uint32_t pwr_regs_start[17] = { |
837 | 0x00000000, 0x00000000, 0x00000000, |
838 | 0x00000000, 0x00000000, 0xf0000000, |
839 | 0xcc000000, 0x00000000, 0x00000000, |
840 | 0x00000000, 0x0a000000, 0x000000e2, |
841 | 0x0a000020, 0x01000002, 0x01000018, |
842 | 0x40000000, 0x00000418 |
843 | }; |
844 | uint16_t i; |
845 | uint8_t cp[sizeof(ar5k0007_pwrSettings)]; |
846 | uint32_t pwr_regs[17]; |
847 | |
848 | OS_MEMCPY(pwr_regs, pwr_regs_start, sizeof(pwr_regs)); |
849 | OS_MEMCPY(cp, ar5k0007_pwrSettings, sizeof(cp)); |
850 | |
851 | /* Check the EEPROM tx power calibration settings */ |
852 | if (!setupPowerSettings(ah, chan, cp)) { |
853 | #ifdef AH_DEBUG |
854 | ath_hal_printf(ah, "%s: unable to setup power settings\n" , |
855 | __func__); |
856 | #endif |
857 | return AH_FALSE; |
858 | } |
859 | if (cp[15] < 1 || cp[15] > 5) { |
860 | #ifdef AH_DEBUG |
861 | ath_hal_printf(ah, "%s: OB out of range (%u)\n" , |
862 | __func__, cp[15]); |
863 | #endif |
864 | return AH_FALSE; |
865 | } |
866 | if (cp[16] < 1 || cp[16] > 5) { |
867 | #ifdef AH_DEBUG |
868 | ath_hal_printf(ah, "%s: DB out of range (%u)\n" , |
869 | __func__, cp[16]); |
870 | #endif |
871 | return AH_FALSE; |
872 | } |
873 | |
874 | /* reverse bits of the transmit power array */ |
875 | for (i = 0; i < 7; i++) |
876 | cp[i] = ath_hal_reverseBits(cp[i], 5); |
877 | for (i = 7; i < 15; i++) |
878 | cp[i] = ath_hal_reverseBits(cp[i], 6); |
879 | |
880 | /* merge transmit power values into the register - quite gross */ |
881 | pwr_regs[0] |= ((cp[1] << 5) & 0xE0) | (cp[0] & 0x1F); |
882 | pwr_regs[1] |= ((cp[3] << 7) & 0x80) | ((cp[2] << 2) & 0x7C) | |
883 | ((cp[1] >> 3) & 0x03); |
884 | pwr_regs[2] |= ((cp[4] << 4) & 0xF0) | ((cp[3] >> 1) & 0x0F); |
885 | pwr_regs[3] |= ((cp[6] << 6) & 0xC0) | ((cp[5] << 1) & 0x3E) | |
886 | ((cp[4] >> 4) & 0x01); |
887 | pwr_regs[4] |= ((cp[7] << 3) & 0xF8) | ((cp[6] >> 2) & 0x07); |
888 | pwr_regs[5] |= ((cp[9] << 7) & 0x80) | ((cp[8] << 1) & 0x7E) | |
889 | ((cp[7] >> 5) & 0x01); |
890 | pwr_regs[6] |= ((cp[10] << 5) & 0xE0) | ((cp[9] >> 1) & 0x1F); |
891 | pwr_regs[7] |= ((cp[11] << 3) & 0xF8) | ((cp[10] >> 3) & 0x07); |
892 | pwr_regs[8] |= ((cp[12] << 1) & 0x7E) | ((cp[11] >> 5) & 0x01); |
893 | pwr_regs[9] |= ((cp[13] << 5) & 0xE0); |
894 | pwr_regs[10] |= ((cp[14] << 3) & 0xF8) | ((cp[13] >> 3) & 0x07); |
895 | pwr_regs[11] |= ((cp[14] >> 5) & 0x01); |
896 | |
897 | /* Set OB */ |
898 | pwr_regs[8] |= (ath_hal_reverseBits(cp[15], 3) << 7) & 0x80; |
899 | pwr_regs[9] |= (ath_hal_reverseBits(cp[15], 3) >> 1) & 0x03; |
900 | |
901 | /* Set DB */ |
902 | pwr_regs[9] |= (ath_hal_reverseBits(cp[16], 3) << 2) & 0x1C; |
903 | |
904 | /* Write the registers */ |
905 | for (i = 0; i < N(pwr_regs)-1; i++) |
906 | OS_REG_WRITE(ah, 0x0000989c, pwr_regs[i]); |
907 | /* last write is a flush */ |
908 | OS_REG_WRITE(ah, 0x000098d4, pwr_regs[i]); |
909 | |
910 | return AH_TRUE; |
911 | #undef N |
912 | } |
913 | |
914 | /* |
915 | * Takes the MHz channel value and sets the Channel value |
916 | * |
917 | * ASSUMES: Writes enabled to analog bus before AGC is active |
918 | * or by disabling the AGC. |
919 | */ |
920 | static HAL_BOOL |
921 | ar5210SetChannel(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) |
922 | { |
923 | uint32_t data; |
924 | |
925 | /* Set the Channel */ |
926 | data = ath_hal_reverseBits((chan->channel - 5120)/10, 5); |
927 | data = (data << 1) | 0x41; |
928 | OS_REG_WRITE(ah, AR_PHY(0x27), data); |
929 | OS_REG_WRITE(ah, AR_PHY(0x30), 0); |
930 | AH_PRIVATE(ah)->ah_curchan = chan; |
931 | return AH_TRUE; |
932 | } |
933 | |
934 | int16_t |
935 | ar5210GetNoiseFloor(struct ath_hal *ah) |
936 | { |
937 | int16_t nf; |
938 | |
939 | nf = (OS_REG_READ(ah, AR_PHY(25)) >> 19) & 0x1ff; |
940 | if (nf & 0x100) |
941 | nf = 0 - ((nf ^ 0x1ff) + 1); |
942 | return nf; |
943 | } |
944 | |
945 | #define NORMAL_NF_THRESH (-72) |
946 | /* |
947 | * Peform the noisefloor calibration and check for |
948 | * any constant channel interference |
949 | * |
950 | * Returns: TRUE for a successful noise floor calibration; else FALSE |
951 | */ |
952 | HAL_BOOL |
953 | ar5210CalNoiseFloor(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan) |
954 | { |
955 | int32_t nf, nfLoops; |
956 | |
957 | /* Calibrate the noise floor */ |
958 | OS_REG_WRITE(ah, AR_PHY_AGCCTL, |
959 | OS_REG_READ(ah, AR_PHY_AGCCTL) | AR_PHY_AGC_NF); |
960 | |
961 | /* Do not read noise floor until it has done the first update */ |
962 | if (!ath_hal_wait(ah, AR_PHY_AGCCTL, AR_PHY_AGC_NF, 0)) { |
963 | #ifdef ATH_HAL_DEBUG |
964 | ath_hal_printf(ah, " -PHY NF Reg state: 0x%x\n" , |
965 | OS_REG_READ(ah, AR_PHY_AGCCTL)); |
966 | ath_hal_printf(ah, " -MAC Reset Reg state: 0x%x\n" , |
967 | OS_REG_READ(ah, AR_RC)); |
968 | ath_hal_printf(ah, " -PHY Active Reg state: 0x%x\n" , |
969 | OS_REG_READ(ah, AR_PHY_ACTIVE)); |
970 | #endif /* ATH_HAL_DEBUG */ |
971 | return AH_FALSE; |
972 | } |
973 | |
974 | nf = 0; |
975 | /* Keep checking until the floor is below the threshold or the nf is done */ |
976 | for (nfLoops = 0; ((nfLoops < 21) && (nf > NORMAL_NF_THRESH)); nfLoops++) { |
977 | OS_DELAY(1000); /* Sleep for 1 ms */ |
978 | nf = ar5210GetNoiseFloor(ah); |
979 | } |
980 | |
981 | if (nf > NORMAL_NF_THRESH) { |
982 | HALDEBUG(ah, HAL_DEBUG_ANY, "%s: Bad noise cal %d\n" , |
983 | __func__, nf); |
984 | chan->rawNoiseFloor = 0; |
985 | return AH_FALSE; |
986 | } |
987 | chan->rawNoiseFloor = nf; |
988 | return AH_TRUE; |
989 | } |
990 | |
991 | /* |
992 | * Adjust NF based on statistical values for 5GHz frequencies. |
993 | */ |
994 | int16_t |
995 | ar5210GetNfAdjust(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *c) |
996 | { |
997 | return 0; |
998 | } |
999 | |
1000 | HAL_RFGAIN |
1001 | ar5210GetRfgain(struct ath_hal *ah) |
1002 | { |
1003 | return HAL_RFGAIN_INACTIVE; |
1004 | } |
1005 | |