1250003Sadrian/*
2250003Sadrian * Copyright (c) 2013 Qualcomm Atheros, Inc.
3250003Sadrian *
4250003Sadrian * Permission to use, copy, modify, and/or distribute this software for any
5250003Sadrian * purpose with or without fee is hereby granted, provided that the above
6250003Sadrian * copyright notice and this permission notice appear in all copies.
7250003Sadrian *
8250003Sadrian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9250003Sadrian * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10250003Sadrian * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11250003Sadrian * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12250003Sadrian * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13250003Sadrian * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14250003Sadrian * PERFORMANCE OF THIS SOFTWARE.
15250003Sadrian */
16250003Sadrian#include "opt_ah.h"
17250003Sadrian
18291642Sadrian//#ifdef AH_SUPPORT_AR9300
19250003Sadrian
20250003Sadrian#include "ah.h"
21250003Sadrian#include "ah_desc.h"
22250003Sadrian#include "ah_internal.h"
23250003Sadrian
24291642Sadrian#include "ar9300_freebsd_inc.h"
25291642Sadrian
26250003Sadrian#include "ar9300/ar9300phy.h"
27250003Sadrian#include "ar9300/ar9300.h"
28250003Sadrian#include "ar9300/ar9300reg.h"
29250003Sadrian#include "ar9300/ar9300desc.h"
30250003Sadrian
31250003Sadrian#if ATH_SUPPORT_SPECTRAL
32250003Sadrian
33250003Sadrian/*
34250003Sadrian * Default 9300 spectral scan parameters
35250003Sadrian */
36250003Sadrian#define AR9300_SPECTRAL_SCAN_ENA                0
37250003Sadrian#define AR9300_SPECTRAL_SCAN_ACTIVE             0
38250003Sadrian#define AR9300_SPECTRAL_SCAN_FFT_PERIOD         8
39250003Sadrian#define AR9300_SPECTRAL_SCAN_PERIOD             1
40250003Sadrian#define AR9300_SPECTRAL_SCAN_COUNT              16 /* used to be 128 */
41250003Sadrian#define AR9300_SPECTRAL_SCAN_SHORT_REPEAT       1
42250003Sadrian
43250003Sadrian/* constants */
44250003Sadrian#define MAX_RADAR_DC_PWR_THRESH 127
45250003Sadrian#define MAX_RADAR_RSSI_THRESH 0x3f
46250003Sadrian#define MAX_RADAR_HEIGHT 0x3f
47250003Sadrian#define MAX_CCA_THRESH 127
48250003Sadrian#define ENABLE_ALL_PHYERR 0xffffffff
49250003Sadrian
50250003Sadrianvoid ar9300_disable_cck(struct ath_hal *ah);
51250003Sadrianvoid ar9300_disable_radar(struct ath_hal *ah);
52250003Sadrianvoid ar9300_disable_restart(struct ath_hal *ah);
53250003Sadrianvoid ar9300_set_radar_dc_thresh(struct ath_hal *ah);
54250003Sadrianvoid ar9300_disable_weak_signal(struct ath_hal *ah);
55250003Sadrianvoid ar9300_disable_strong_signal(struct ath_hal *ah);
56250003Sadrianvoid ar9300_prep_spectral_scan(struct ath_hal *ah);
57250003Sadrianvoid ar9300_disable_dc_offset(struct ath_hal *ah);
58250003Sadrianvoid ar9300_enable_cck_detect(struct ath_hal *ah);
59250003Sadrian
60250003Sadrianvoid
61250003Sadrianar9300_disable_cck(struct ath_hal *ah)
62250003Sadrian{
63250003Sadrian    u_int32_t val;
64250003Sadrian
65250003Sadrian    val = OS_REG_READ(ah, AR_PHY_MODE);
66250003Sadrian    val &= ~(AR_PHY_MODE_DYN_CCK_DISABLE);
67250003Sadrian
68250003Sadrian    OS_REG_WRITE(ah, AR_PHY_MODE, val);
69250003Sadrian}
70250003Sadrian
71250003Sadrianvoid
72250003Sadrianar9300_disable_radar(struct ath_hal *ah)
73250003Sadrian{
74250003Sadrian    u_int32_t val;
75250003Sadrian
76250003Sadrian    /* Enable radar FFT */
77250003Sadrian    val = OS_REG_READ(ah, AR_PHY_RADAR_0);
78250003Sadrian    val |= AR_PHY_RADAR_0_FFT_ENA;
79250003Sadrian
80250003Sadrian    /* set radar detect thresholds to max to effectively disable radar */
81250003Sadrian    val &= ~AR_PHY_RADAR_0_RRSSI;
82250003Sadrian    val |= SM(MAX_RADAR_RSSI_THRESH, AR_PHY_RADAR_0_RRSSI);
83250003Sadrian
84250003Sadrian    val &= ~AR_PHY_RADAR_0_HEIGHT;
85250003Sadrian    val |= SM(MAX_RADAR_HEIGHT, AR_PHY_RADAR_0_HEIGHT);
86250003Sadrian
87250003Sadrian    val &= ~(AR_PHY_RADAR_0_ENA);
88250003Sadrian    OS_REG_WRITE(ah, AR_PHY_RADAR_0, val);
89250003Sadrian
90250003Sadrian    /* disable extension radar detect */
91250003Sadrian    val = OS_REG_READ(ah, AR_PHY_RADAR_EXT);
92250003Sadrian    OS_REG_WRITE(ah, AR_PHY_RADAR_EXT, val & ~AR_PHY_RADAR_EXT_ENA);
93250003Sadrian
94250003Sadrian    val = OS_REG_READ(ah, AR_RX_FILTER);
95250003Sadrian    val |= (1 << 13);
96250003Sadrian    OS_REG_WRITE(ah, AR_RX_FILTER, val);
97250003Sadrian}
98250003Sadrian
99250003Sadrianvoid ar9300_disable_restart(struct ath_hal *ah)
100250003Sadrian{
101250003Sadrian    u_int32_t val;
102250003Sadrian    val = OS_REG_READ(ah, AR_PHY_RESTART);
103250003Sadrian    val &= ~AR_PHY_RESTART_ENA;
104250003Sadrian    OS_REG_WRITE(ah, AR_PHY_RESTART, val);
105250003Sadrian
106250003Sadrian    val = OS_REG_READ(ah, AR_PHY_RESTART);
107250003Sadrian}
108250003Sadrian
109250003Sadrianvoid ar9300_set_radar_dc_thresh(struct ath_hal *ah)
110250003Sadrian{
111250003Sadrian    u_int32_t val;
112250003Sadrian    val = OS_REG_READ(ah, AR_PHY_RADAR_EXT);
113250003Sadrian    val &= ~AR_PHY_RADAR_DC_PWR_THRESH;
114250003Sadrian    val |= SM(MAX_RADAR_DC_PWR_THRESH, AR_PHY_RADAR_DC_PWR_THRESH);
115250003Sadrian    OS_REG_WRITE(ah, AR_PHY_RADAR_EXT, val);
116250003Sadrian
117250003Sadrian    val = OS_REG_READ(ah, AR_PHY_RADAR_EXT);
118250003Sadrian}
119250003Sadrian
120250003Sadrianvoid
121250003Sadrianar9300_disable_weak_signal(struct ath_hal *ah)
122250003Sadrian{
123250003Sadrian    /* set firpwr to max (signed) */
124250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRPWR, 0x7f);
125250003Sadrian    OS_REG_CLR_BIT(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRPWR_SIGN_BIT);
126250003Sadrian
127250003Sadrian    /* set firstep to max */
128250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, 0x3f);
129250003Sadrian
130250003Sadrian    /* set relpwr to max (signed) */
131250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_RELPWR, 0x1f);
132250003Sadrian    OS_REG_CLR_BIT(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_RELPWR_SIGN_BIT);
133250003Sadrian
134250003Sadrian    /* set relstep to max (signed) */
135250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_RELSTEP, 0x1f);
136250003Sadrian    OS_REG_CLR_BIT(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_RELSTEP_SIGN_BIT);
137250003Sadrian
138250003Sadrian    /* set firpwr_low to max (signed) */
139250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_FIRPWR, 0x7f);
140250003Sadrian    OS_REG_CLR_BIT(
141250003Sadrian        ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_FIRPWR_SIGN_BIT);
142250003Sadrian
143250003Sadrian    /* set firstep_low to max */
144250003Sadrian    OS_REG_RMW_FIELD(
145250003Sadrian        ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, 0x3f);
146250003Sadrian
147250003Sadrian    /* set relstep_low to max (signed) */
148250003Sadrian    OS_REG_RMW_FIELD(
149250003Sadrian        ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_RELSTEP, 0x1f);
150250003Sadrian    OS_REG_CLR_BIT(
151250003Sadrian        ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_RELSTEP_SIGN_BIT);
152250003Sadrian}
153250003Sadrian
154250003Sadrianvoid
155250003Sadrianar9300_disable_strong_signal(struct ath_hal *ah)
156250003Sadrian{
157250003Sadrian    u_int32_t val;
158250003Sadrian
159250003Sadrian    val = OS_REG_READ(ah, AR_PHY_TIMING5);
160250003Sadrian    val |= AR_PHY_TIMING5_RSSI_THR1A_ENA;
161250003Sadrian    OS_REG_WRITE(ah, AR_PHY_TIMING5, val);
162250003Sadrian
163250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_RSSI_THR1A, 0x7f);
164250003Sadrian
165250003Sadrian}
166250003Sadrianvoid
167250003Sadrianar9300_set_cca_threshold(struct ath_hal *ah, u_int8_t thresh62)
168250003Sadrian{
169250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_CCA_0, AR_PHY_CCA_THRESH62, thresh62);
170250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, thresh62);
171250003Sadrian    /*
172250003Sadrian    OS_REG_RMW_FIELD(ah,
173250003Sadrian        AR_PHY_EXTCHN_PWRTHR1, AR_PHY_EXT_CCA0_THRESH62, thresh62);
174250003Sadrian     */
175250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CCA_THRESH62, thresh62);
176250003Sadrian}
177250003Sadrian
178250003Sadrianstatic void ar9300_classify_strong_bins(struct ath_hal *ah)
179250003Sadrian{
180250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_CF_BIN_THRESH, 0x1);
181250003Sadrian}
182250003Sadrian
183250003Sadrianvoid ar9300_disable_dc_offset(struct ath_hal *ah)
184250003Sadrian{
185250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_TIMING2, AR_PHY_TIMING2_DC_OFFSET, 0);
186250003Sadrian}
187250003Sadrian
188250003Sadrianvoid ar9300_enable_cck_detect(struct ath_hal *ah)
189250003Sadrian{
190250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_MODE, AR_PHY_MODE_DISABLE_CCK, 0);
191250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_MODE, AR_PHY_MODE_DYNAMIC, 1);
192250003Sadrian}
193250003Sadrian
194250003Sadrianvoid ar9300_prep_spectral_scan(struct ath_hal *ah)
195250003Sadrian{
196250003Sadrian    ar9300_disable_radar(ah);
197250003Sadrian    ar9300_classify_strong_bins(ah);
198250003Sadrian    ar9300_disable_dc_offset(ah);
199250003Sadrian    if (AH_PRIVATE(ah)->ah_curchan &&
200250003Sadrian        IS_5GHZ_FAST_CLOCK_EN(ah, AH_PRIVATE(ah)->ah_curchan))
201250003Sadrian    { /* fast clock */
202250003Sadrian        ar9300_enable_cck_detect(ah);
203250003Sadrian    }
204250003Sadrian#ifdef DEMO_MODE
205250003Sadrian    ar9300_disable_strong_signal(ah);
206250003Sadrian    ar9300_disable_weak_signal(ah);
207250003Sadrian    ar9300_set_radar_dc_thresh(ah);
208250003Sadrian    ar9300_set_cca_threshold(ah, MAX_CCA_THRESH);
209250003Sadrian    /*ar9300_disable_restart(ah);*/
210250003Sadrian#endif
211250003Sadrian    OS_REG_WRITE(ah, AR_PHY_ERR, HAL_PHYERR_SPECTRAL);
212250003Sadrian}
213250003Sadrian
214250003Sadrian
215250003Sadrian//#define TEST_NOISE_PWR_WITHOUT_EEPROM 1
216250003Sadrian#ifdef TEST_NOISE_PWR_WITHOUT_EEPROM
217250003Sadrianstruct nf_cal {
218250003Sadrian    int cal;
219250003Sadrian    int pwr;
220250003Sadrian};
221250003Sadrianstruct nf_cal_table_t {
222250003Sadrian    int freq;
223250003Sadrian    struct nf_cal chain[AH_MAX_CHAINS];
224250003Sadrian};
225250003Sadrian
226250003Sadrianstatic const struct nf_cal_table_t nf_cal_table[] =
227250003Sadrian{
228250003Sadrian/* ch 1  */ {2412, { {N2DBM(-101, 00),  N2DBM( -94, 25)},
229250003Sadrian                     {N2DBM(-107, 75),  N2DBM( -99, 75)},
230250003Sadrian                   } },
231250003Sadrian/* ch 6  */ {2437, { {N2DBM(-102, 25),  N2DBM( -94, 25)},
232250003Sadrian                     {N2DBM(-106, 00),  N2DBM( -97, 25)},
233250003Sadrian                   } },
234250003Sadrian/* ch 11 */ {2462, { {N2DBM(-101, 50),  N2DBM( -95, 00)},
235250003Sadrian                     {N2DBM(-105, 50),  N2DBM( -98, 00)},
236250003Sadrian                   } },
237250003Sadrian/* ch 36 */ {5180, { {N2DBM(-114, 25),  N2DBM( -95, 00)},
238250003Sadrian                     {N2DBM(-114, 75),  N2DBM( -94, 00)},
239250003Sadrian                   } },
240250003Sadrian/* ch 44 */ {5220, { {N2DBM(-113, 00),  N2DBM( -95, 00)},
241250003Sadrian                     {N2DBM(-115, 00),  N2DBM( -94, 50)},
242250003Sadrian                   } },
243250003Sadrian/* ch 64 */ {5320, { {N2DBM(-113, 00),  N2DBM( -95, 00)}, // not cal'ed
244250003Sadrian                     {N2DBM(-115, 00),  N2DBM( -94, 50)},
245250003Sadrian                   } },
246250003Sadrian/* ch 100*/ {5500, { {N2DBM(-111, 50),  N2DBM( -93, 75)},
247250003Sadrian                     {N2DBM(-112, 00),  N2DBM( -95, 25)},
248250003Sadrian                   } },
249250003Sadrian/* ch 120*/ {5600, { {N2DBM(-111, 50),  N2DBM( -93, 75)},
250250003Sadrian                     {N2DBM(-112, 00),  N2DBM( -95, 25)},
251250003Sadrian                   } },
252250003Sadrian/* ch 140*/ {5700, { {N2DBM(-111, 75),  N2DBM( -95, 00)},
253250003Sadrian                     {N2DBM(-111, 75),  N2DBM( -96, 00)},
254250003Sadrian                   } },
255250003Sadrian/* ch 157*/ {5785, { {N2DBM(-112, 50),  N2DBM( -94, 75)},
256250003Sadrian                     {N2DBM(-111, 75),  N2DBM( -95, 50)},
257250003Sadrian                   } },
258250003Sadrian/* ch 165*/ {5825, { {N2DBM(-111, 50),  N2DBM( -95, 00)},
259250003Sadrian                     {N2DBM(-112, 00),  N2DBM( -95, 00)},
260250003Sadrian                   } },
261250003Sadrian                   {0}
262250003Sadrian};
263250003Sadrian
264250003Sadrianstatic int
265250003Sadrianar9300_noise_floor_get(struct ath_hal *ah, int freq_mhz, int ch)
266250003Sadrian{
267250003Sadrian    int i;
268250003Sadrian    for (i = 0; nf_cal_table[i].freq != 0; i++) {
269250003Sadrian        if (nf_cal_table[i + 0].freq == freq_mhz ||
270250003Sadrian            nf_cal_table[i + 1].freq > freq_mhz ||
271250003Sadrian            nf_cal_table[i + 1].freq == 0) {
272250003Sadrian            return nf_cal_table[i].chain[ch].cal;
273250003Sadrian        }
274250003Sadrian    }
275250003Sadrian
276250003Sadrian    ath_hal_printf(ah,
277250003Sadrian        "%s: **Warning: device %d.%d: "
278250003Sadrian        "no nf cal offset found for freq %d chain %d\n",
279250003Sadrian        __func__, (AH_PRIVATE(ah))->ah_macVersion,
280250003Sadrian        (AH_PRIVATE(ah))->ah_macRev, freq_mhz, ch);
281250003Sadrian    return 0;
282250003Sadrian}
283250003Sadrian
284250003Sadrianstatic int
285250003Sadrianar9300_noise_floor_power_get(struct ath_hal *ah, int freq_mhz, int ch)
286250003Sadrian{
287250003Sadrian    int i;
288250003Sadrian    for (i = 0; nf_cal_table[i].freq != 0; i++) {
289250003Sadrian        if (nf_cal_table[i + 0].freq == freq_mhz ||
290250003Sadrian            nf_cal_table[i + 1].freq > freq_mhz ||
291250003Sadrian            nf_cal_table[i + 1].freq == 0) {
292250003Sadrian            return nf_cal_table[i].chain[ch].pwr;
293250003Sadrian        }
294250003Sadrian    }
295250003Sadrian
296250003Sadrian    ath_hal_printf(ah,
297250003Sadrian        "%s: **Warning: device %d.%d: "
298250003Sadrian        "no nf pwr offset found for freq %d chain %d\n",
299250003Sadrian        __func__, (AH_PRIVATE(ah))->ah_macVersion,
300250003Sadrian        (AH_PRIVATE(ah))->ah_macRev, freq_mhz, ch);
301250003Sadrian    return 0;
302250003Sadrian}
303250003Sadrian#else
304250003Sadrian#define ar9300_noise_floor_get(_ah,_f,_ich)          ar9300_noise_floor_cal_or_power_get((_ah), (_f), (_ich), 1/*use_cal*/)
305250003Sadrian#define ar9300_noise_floor_power_get(_ah,_f,_ich)    ar9300_noise_floor_cal_or_power_get((_ah), (_f), (_ich), 0/*use_cal*/)
306250003Sadrian#endif
307250003Sadrian
308250003Sadrian
309250003Sadrianvoid
310250003Sadrianar9300_configure_spectral_scan(struct ath_hal *ah, HAL_SPECTRAL_PARAM *ss)
311250003Sadrian{
312250003Sadrian    u_int32_t val, i;
313250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
314250003Sadrian    HAL_BOOL asleep = ahp->ah_chip_full_sleep;
315291642Sadrian    int16_t nf_buf[HAL_NUM_NF_READINGS];
316250003Sadrian
317250003Sadrian    if ((AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) && asleep) {
318250003Sadrian        ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE);
319250003Sadrian    }
320250003Sadrian
321250003Sadrian    ar9300_prep_spectral_scan(ah);
322250003Sadrian
323250003Sadrian    if (ss->ss_spectral_pri) {
324291642Sadrian        for (i = 0; i < HAL_NUM_NF_READINGS; i++) {
325250003Sadrian            nf_buf[i] = NOISE_PWR_DBM_2_INT(ss->ss_nf_cal[i]);
326250003Sadrian        }
327250003Sadrian        ar9300_load_nf(ah, nf_buf);
328250003Sadrian#ifdef DEMO_MODE
329250003Sadrian        ar9300_disable_strong_signal(ah);
330250003Sadrian        ar9300_disable_weak_signal(ah);
331250003Sadrian        ar9300_set_radar_dc_thresh(ah);
332250003Sadrian        ar9300_set_cca_threshold(ah, MAX_CCA_THRESH);
333250003Sadrian        /*ar9300_disable_restart(ah);*/
334250003Sadrian#endif
335250003Sadrian    }
336250003Sadrian
337250003Sadrian    val = OS_REG_READ(ah, AR_PHY_SPECTRAL_SCAN);
338250003Sadrian
339250003Sadrian    if (ss->ss_fft_period != HAL_SPECTRAL_PARAM_NOVAL) {
340250003Sadrian        val &= ~AR_PHY_SPECTRAL_SCAN_FFT_PERIOD;
341250003Sadrian        val |= SM(ss->ss_fft_period, AR_PHY_SPECTRAL_SCAN_FFT_PERIOD);
342250003Sadrian    }
343250003Sadrian
344250003Sadrian    if (ss->ss_period != HAL_SPECTRAL_PARAM_NOVAL) {
345250003Sadrian        val &= ~AR_PHY_SPECTRAL_SCAN_PERIOD;
346250003Sadrian        val |= SM(ss->ss_period, AR_PHY_SPECTRAL_SCAN_PERIOD);
347250003Sadrian    }
348250003Sadrian
349250003Sadrian    if (ss->ss_count != HAL_SPECTRAL_PARAM_NOVAL) {
350250003Sadrian        val &= ~AR_PHY_SPECTRAL_SCAN_COUNT;
351250003Sadrian        /* Remnants of a Merlin bug, 128 translates to 0 for
352250003Sadrian         * continuous scanning. Instead we do piecemeal captures
353250003Sadrian         * of 64 samples for Osprey.
354250003Sadrian         */
355250003Sadrian        if (ss->ss_count == 128) {
356250003Sadrian            val |= SM(0, AR_PHY_SPECTRAL_SCAN_COUNT);
357250003Sadrian        } else {
358250003Sadrian            val |= SM(ss->ss_count, AR_PHY_SPECTRAL_SCAN_COUNT);
359250003Sadrian        }
360250003Sadrian    }
361250003Sadrian
362250003Sadrian    if (ss->ss_period != HAL_SPECTRAL_PARAM_NOVAL) {
363250003Sadrian        val &= ~AR_PHY_SPECTRAL_SCAN_PERIOD;
364250003Sadrian        val |= SM(ss->ss_period, AR_PHY_SPECTRAL_SCAN_PERIOD);
365250003Sadrian    }
366250003Sadrian
367250003Sadrian    if (ss->ss_short_report == AH_TRUE) {
368250003Sadrian        val |= AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT;
369250003Sadrian    } else {
370250003Sadrian        val &= ~AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT;
371250003Sadrian    }
372250003Sadrian
373250003Sadrian    /* if noise power cal, force high priority */
374250003Sadrian    if (ss->ss_spectral_pri) {
375250003Sadrian        val |= AR_PHY_SPECTRAL_SCAN_PRIORITY_HI;
376250003Sadrian    } else {
377250003Sadrian        val &= ~AR_PHY_SPECTRAL_SCAN_PRIORITY_HI;
378250003Sadrian    }
379250003Sadrian
380250003Sadrian    /* enable spectral scan */
381250003Sadrian    OS_REG_WRITE(ah, AR_PHY_SPECTRAL_SCAN, val | AR_PHY_SPECTRAL_SCAN_ENABLE);
382250003Sadrian
383250003Sadrian    if ((AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) && asleep) {
384250003Sadrian        ar9300_set_power_mode(ah, HAL_PM_FULL_SLEEP, AH_TRUE);
385250003Sadrian    }
386250003Sadrian}
387250003Sadrian
388250003Sadrian/*
389250003Sadrian * Get the spectral parameter values and return them in the pe
390250003Sadrian * structure
391250003Sadrian */
392250003Sadrian
393250003Sadrianvoid
394250003Sadrianar9300_get_spectral_params(struct ath_hal *ah, HAL_SPECTRAL_PARAM *ss)
395250003Sadrian{
396250003Sadrian    u_int32_t val;
397291642Sadrian    HAL_CHANNEL_INTERNAL *chan = NULL;
398291642Sadrian    const struct ieee80211_channel *c;
399250003Sadrian    int i, ichain, rx_chain_status;
400250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
401250003Sadrian    HAL_BOOL asleep = ahp->ah_chip_full_sleep;
402250003Sadrian
403291642Sadrian    c = AH_PRIVATE(ah)->ah_curchan;
404291642Sadrian    if (c != NULL)
405291642Sadrian        chan = ath_hal_checkchannel(ah, c);
406291642Sadrian
407291642Sadrian    // XXX TODO: just always wake up all chips?
408250003Sadrian    if ((AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) && asleep) {
409250003Sadrian        ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE);
410250003Sadrian    }
411250003Sadrian
412250003Sadrian    val = OS_REG_READ(ah, AR_PHY_SPECTRAL_SCAN);
413250003Sadrian
414250003Sadrian    ss->ss_fft_period = MS(val, AR_PHY_SPECTRAL_SCAN_FFT_PERIOD);
415250003Sadrian    ss->ss_period = MS(val, AR_PHY_SPECTRAL_SCAN_PERIOD);
416250003Sadrian    ss->ss_count = MS(val, AR_PHY_SPECTRAL_SCAN_COUNT);
417250003Sadrian    ss->ss_short_report = (val & AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT) ? 1:0;
418250003Sadrian    ss->ss_spectral_pri = ( val & AR_PHY_SPECTRAL_SCAN_PRIORITY_HI) ? 1:0;
419250003Sadrian    OS_MEMZERO(ss->ss_nf_cal, sizeof(ss->ss_nf_cal));
420250003Sadrian    OS_MEMZERO(ss->ss_nf_pwr, sizeof(ss->ss_nf_cal));
421250003Sadrian    ss->ss_nf_temp_data = 0;
422250003Sadrian
423250003Sadrian    if (chan != NULL) {
424250003Sadrian        rx_chain_status = OS_REG_READ(ah, AR_PHY_RX_CHAINMASK) & 0x7;
425291642Sadrian        for (i = 0; i < HAL_NUM_NF_READINGS; i++) {
426250003Sadrian            ichain = i % 3;
427250003Sadrian            if (rx_chain_status & (1 << ichain)) {
428250003Sadrian                ss->ss_nf_cal[i] =
429250003Sadrian                    ar9300_noise_floor_get(ah, chan->channel, ichain);
430250003Sadrian                ss->ss_nf_pwr[i] =
431250003Sadrian                    ar9300_noise_floor_power_get(ah, chan->channel, ichain);
432250003Sadrian            }
433250003Sadrian        }
434250003Sadrian        ss->ss_nf_temp_data = OS_REG_READ_FIELD(ah, AR_PHY_BB_THERM_ADC_4, AR_PHY_BB_THERM_ADC_4_LATEST_THERM);
435250003Sadrian    } else {
436250003Sadrian        HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE,
437250003Sadrian            "%s: chan is NULL - no ss nf values\n", __func__);
438250003Sadrian    }
439250003Sadrian
440250003Sadrian    if ((AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) && asleep) {
441250003Sadrian        ar9300_set_power_mode(ah, HAL_PM_FULL_SLEEP, AH_TRUE);
442250003Sadrian    }
443250003Sadrian}
444250003Sadrian
445250003SadrianHAL_BOOL
446250003Sadrianar9300_is_spectral_active(struct ath_hal *ah)
447250003Sadrian{
448250003Sadrian    u_int32_t val;
449250003Sadrian
450250003Sadrian    val = OS_REG_READ(ah, AR_PHY_SPECTRAL_SCAN);
451250003Sadrian    return MS(val, AR_PHY_SPECTRAL_SCAN_ACTIVE);
452250003Sadrian}
453250003Sadrian
454250003SadrianHAL_BOOL
455250003Sadrianar9300_is_spectral_enabled(struct ath_hal *ah)
456250003Sadrian{
457250003Sadrian    u_int32_t val;
458250003Sadrian
459250003Sadrian    val = OS_REG_READ(ah, AR_PHY_SPECTRAL_SCAN);
460250003Sadrian    return MS(val, AR_PHY_SPECTRAL_SCAN_ENABLE);
461250003Sadrian}
462250003Sadrian
463250003Sadrianvoid ar9300_start_spectral_scan(struct ath_hal *ah)
464250003Sadrian{
465250003Sadrian    u_int32_t val;
466250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
467250003Sadrian    HAL_BOOL asleep = ahp->ah_chip_full_sleep;
468250003Sadrian
469250003Sadrian    if ((AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) && asleep) {
470250003Sadrian        ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE);
471250003Sadrian    }
472250003Sadrian
473250003Sadrian    ar9300_prep_spectral_scan(ah);
474250003Sadrian
475250003Sadrian    /* activate spectral scan */
476250003Sadrian    val = OS_REG_READ(ah, AR_PHY_SPECTRAL_SCAN);
477250003Sadrian    /* This is a hardware bug fix, the enable and active bits should
478250003Sadrian     * not be set/reset in the same write operation to the register
479250003Sadrian     */
480250003Sadrian    if (!(val & AR_PHY_SPECTRAL_SCAN_ENABLE)) {
481250003Sadrian        val |= AR_PHY_SPECTRAL_SCAN_ENABLE;
482250003Sadrian        OS_REG_WRITE(ah, AR_PHY_SPECTRAL_SCAN, val);
483250003Sadrian        val = OS_REG_READ(ah, AR_PHY_SPECTRAL_SCAN);
484250003Sadrian    }
485250003Sadrian    val |= AR_PHY_SPECTRAL_SCAN_ACTIVE;
486250003Sadrian    OS_REG_WRITE(ah, AR_PHY_SPECTRAL_SCAN, val);
487250003Sadrian
488250003Sadrian    /* Reset the PHY_ERR_MASK */
489250003Sadrian    val = OS_REG_READ(ah, AR_PHY_ERR_MASK_REG);
490250003Sadrian    OS_REG_WRITE(ah, AR_PHY_ERR_MASK_REG, val | AR_PHY_ERR_RADAR);
491250003Sadrian
492250003Sadrian    if ((AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) && asleep) {
493250003Sadrian        ar9300_set_power_mode(ah, HAL_PM_FULL_SLEEP, AH_TRUE);
494250003Sadrian    }
495250003Sadrian}
496250003Sadrian
497250003Sadrianvoid ar9300_stop_spectral_scan(struct ath_hal *ah)
498250003Sadrian{
499250003Sadrian    u_int32_t val;
500250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
501250003Sadrian    HAL_BOOL asleep = ahp->ah_chip_full_sleep;
502250003Sadrian
503250003Sadrian    if ((AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) && asleep) {
504250003Sadrian        ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE);
505250003Sadrian    }
506250003Sadrian    val = OS_REG_READ(ah, AR_PHY_SPECTRAL_SCAN);
507250003Sadrian
508250003Sadrian    /* deactivate spectral scan */
509250003Sadrian    /* HW Bug fix -- Do not disable the spectral scan
510250003Sadrian     * only turn off the active bit
511250003Sadrian     */
512250003Sadrian    //val &= ~AR_PHY_SPECTRAL_SCAN_ENABLE;
513250003Sadrian    val &= ~AR_PHY_SPECTRAL_SCAN_ACTIVE;
514250003Sadrian    OS_REG_WRITE(ah, AR_PHY_SPECTRAL_SCAN, val);
515250003Sadrian    val = OS_REG_READ(ah, AR_PHY_SPECTRAL_SCAN);
516250003Sadrian
517250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_CF_BIN_THRESH,
518250003Sadrian                     ahp->ah_radar1);
519250003Sadrian    OS_REG_RMW_FIELD(ah, AR_PHY_TIMING2, AR_PHY_TIMING2_DC_OFFSET,
520250003Sadrian                     ahp->ah_dc_offset);
521250003Sadrian    OS_REG_WRITE(ah, AR_PHY_ERR, 0);
522250003Sadrian
523250003Sadrian    if (AH_PRIVATE(ah)->ah_curchan &&
524250003Sadrian        IS_5GHZ_FAST_CLOCK_EN(ah, AH_PRIVATE(ah)->ah_curchan))
525250003Sadrian    { /* fast clock */
526250003Sadrian        OS_REG_RMW_FIELD(ah, AR_PHY_MODE, AR_PHY_MODE_DISABLE_CCK,
527250003Sadrian                         ahp->ah_disable_cck);
528250003Sadrian    }
529250003Sadrian
530250003Sadrian    val = OS_REG_READ(ah, AR_PHY_ERR);
531250003Sadrian
532250003Sadrian    val = OS_REG_READ(ah, AR_PHY_ERR_MASK_REG) & (~AR_PHY_ERR_RADAR);
533250003Sadrian    OS_REG_WRITE(ah, AR_PHY_ERR_MASK_REG, val);
534250003Sadrian
535250003Sadrian    if ((AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) && asleep) {
536250003Sadrian        ar9300_set_power_mode(ah, HAL_PM_FULL_SLEEP, AH_TRUE);
537250003Sadrian    }
538250003Sadrian}
539250003Sadrian
540250003Sadrianu_int32_t ar9300_get_spectral_config(struct ath_hal *ah)
541250003Sadrian{
542250003Sadrian    u_int32_t val;
543250003Sadrian    struct ath_hal_9300 *ahp = AH9300(ah);
544250003Sadrian    HAL_BOOL asleep = ahp->ah_chip_full_sleep;
545250003Sadrian
546250003Sadrian    if ((AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) && asleep) {
547250003Sadrian        ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE);
548250003Sadrian    }
549250003Sadrian
550250003Sadrian    val = OS_REG_READ(ah, AR_PHY_SPECTRAL_SCAN);
551250003Sadrian
552250003Sadrian    if ((AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) && asleep) {
553250003Sadrian        ar9300_set_power_mode(ah, HAL_PM_FULL_SLEEP, AH_TRUE);
554250003Sadrian    }
555250003Sadrian    return val;
556250003Sadrian}
557250003Sadrian
558250003Sadrianint16_t ar9300_get_ctl_chan_nf(struct ath_hal *ah)
559250003Sadrian{
560250003Sadrian    int16_t nf;
561291642Sadrian#if 0
562250003Sadrian    struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
563291642Sadrian#endif
564250003Sadrian
565250003Sadrian    if ( (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0) {
566250003Sadrian        /* Noise floor calibration value is ready */
567250003Sadrian        nf = MS(OS_REG_READ(ah, AR_PHY_CCA_0), AR_PHY_MINCCA_PWR);
568250003Sadrian    } else {
569250003Sadrian        /* NF calibration is not done, return nominal value */
570291642Sadrian        nf = AH9300(ah)->nfp->nominal;
571250003Sadrian    }
572250003Sadrian    if (nf & 0x100) {
573250003Sadrian        nf = (0 - ((nf ^ 0x1ff) + 1));
574250003Sadrian    }
575250003Sadrian    return nf;
576250003Sadrian}
577250003Sadrian
578250003Sadrianint16_t ar9300_get_ext_chan_nf(struct ath_hal *ah)
579250003Sadrian{
580250003Sadrian    int16_t nf;
581291642Sadrian#if 0
582250003Sadrian    struct ath_hal_private *ahpriv = AH_PRIVATE(ah);
583291642Sadrian#endif
584250003Sadrian
585250003Sadrian    if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0) {
586250003Sadrian        /* Noise floor calibration value is ready */
587250003Sadrian        nf = MS(OS_REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR);
588250003Sadrian    } else {
589250003Sadrian        /* NF calibration is not done, return nominal value */
590291642Sadrian        nf = AH9300(ah)->nfp->nominal;
591250003Sadrian    }
592250003Sadrian    if (nf & 0x100) {
593250003Sadrian        nf = (0 - ((nf ^ 0x1ff) + 1));
594250003Sadrian    }
595250003Sadrian    return nf;
596250003Sadrian}
597250003Sadrian
598250003Sadrian#endif /* ATH_SUPPORT_SPECTRAL */
599291642Sadrian//#endif
600250003Sadrian
601