1572ff6f6SMatthew Dillon /*
2572ff6f6SMatthew Dillon  * Copyright (c) 2012 Qualcomm Atheros, All Rights Reserved.
3572ff6f6SMatthew Dillon  *
4572ff6f6SMatthew Dillon  * Permission to use, copy, modify, and/or distribute this software for any
5572ff6f6SMatthew Dillon  * purpose with or without fee is hereby granted, provided that the above
6572ff6f6SMatthew Dillon  * copyright notice and this permission notice appear in all copies.
7572ff6f6SMatthew Dillon  *
8572ff6f6SMatthew Dillon  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9572ff6f6SMatthew Dillon  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10572ff6f6SMatthew Dillon  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11572ff6f6SMatthew Dillon  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12572ff6f6SMatthew Dillon  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13572ff6f6SMatthew Dillon  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14572ff6f6SMatthew Dillon  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15572ff6f6SMatthew Dillon  *
16572ff6f6SMatthew Dillon  * $FreeBSD$
17572ff6f6SMatthew Dillon  */
18572ff6f6SMatthew Dillon #include "opt_ah.h"
19572ff6f6SMatthew Dillon 
20572ff6f6SMatthew Dillon #include "ah.h"
21572ff6f6SMatthew Dillon #include "ah_internal.h"
22572ff6f6SMatthew Dillon #include "ah_devid.h"
23572ff6f6SMatthew Dillon #include "ah_desc.h"                    /* NB: for HAL_PHYERR* */
24572ff6f6SMatthew Dillon 
25572ff6f6SMatthew Dillon #include "ar5416/ar5416.h"
26572ff6f6SMatthew Dillon #include "ar5416/ar5416reg.h"
27572ff6f6SMatthew Dillon #include "ar5416/ar5416phy.h"
28572ff6f6SMatthew Dillon 
29572ff6f6SMatthew Dillon /*
30572ff6f6SMatthew Dillon  * Default AR9280 spectral scan parameters
31572ff6f6SMatthew Dillon  */
32572ff6f6SMatthew Dillon #define	AR5416_SPECTRAL_SCAN_ENA		0
33572ff6f6SMatthew Dillon #define	AR5416_SPECTRAL_SCAN_ACTIVE		0
34572ff6f6SMatthew Dillon #define	AR5416_SPECTRAL_SCAN_FFT_PERIOD		8
35572ff6f6SMatthew Dillon #define	AR5416_SPECTRAL_SCAN_PERIOD		1
36572ff6f6SMatthew Dillon #define	AR5416_SPECTRAL_SCAN_COUNT		16 //used to be 128
37572ff6f6SMatthew Dillon #define	AR5416_SPECTRAL_SCAN_SHORT_REPEAT	1
38572ff6f6SMatthew Dillon 
39572ff6f6SMatthew Dillon /* constants */
40572ff6f6SMatthew Dillon #define	MAX_RADAR_RSSI_THRESH	0x3f
41572ff6f6SMatthew Dillon #define	MAX_RADAR_HEIGHT	0x3f
42572ff6f6SMatthew Dillon #define	ENABLE_ALL_PHYERR	0xffffffff
43572ff6f6SMatthew Dillon 
44572ff6f6SMatthew Dillon static void ar5416DisableRadar(struct ath_hal *ah);
45572ff6f6SMatthew Dillon static void ar5416PrepSpectralScan(struct ath_hal *ah);
46572ff6f6SMatthew Dillon 
47572ff6f6SMatthew Dillon static void
ar5416DisableRadar(struct ath_hal * ah)48572ff6f6SMatthew Dillon ar5416DisableRadar(struct ath_hal *ah)
49572ff6f6SMatthew Dillon {
50572ff6f6SMatthew Dillon 	uint32_t val;
51572ff6f6SMatthew Dillon 
52572ff6f6SMatthew Dillon 	// Enable radar FFT
53572ff6f6SMatthew Dillon 	val = OS_REG_READ(ah, AR_PHY_RADAR_0);
54572ff6f6SMatthew Dillon 	val |= AR_PHY_RADAR_0_FFT_ENA;
55572ff6f6SMatthew Dillon 
56572ff6f6SMatthew Dillon 	// set radar detect thresholds to max to effectively disable radar
57572ff6f6SMatthew Dillon 	val &= ~AR_PHY_RADAR_0_RRSSI;
58572ff6f6SMatthew Dillon 	val |= SM(MAX_RADAR_RSSI_THRESH, AR_PHY_RADAR_0_RRSSI);
59572ff6f6SMatthew Dillon 
60572ff6f6SMatthew Dillon 	val &= ~AR_PHY_RADAR_0_HEIGHT;
61572ff6f6SMatthew Dillon 	val |= SM(MAX_RADAR_HEIGHT, AR_PHY_RADAR_0_HEIGHT);
62572ff6f6SMatthew Dillon 
63572ff6f6SMatthew Dillon 	val &= ~(AR_PHY_RADAR_0_ENA);
64572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_PHY_RADAR_0, val);
65572ff6f6SMatthew Dillon 
66572ff6f6SMatthew Dillon 	// disable extension radar detect
67572ff6f6SMatthew Dillon 	val = OS_REG_READ(ah, AR_PHY_RADAR_EXT);
68572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_PHY_RADAR_EXT, val & ~AR_PHY_RADAR_EXT_ENA);
69572ff6f6SMatthew Dillon 
70572ff6f6SMatthew Dillon 	val = OS_REG_READ(ah, AR_RX_FILTER);
71572ff6f6SMatthew Dillon 	val |= (1<<13);
72572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_RX_FILTER, val);
73572ff6f6SMatthew Dillon }
74572ff6f6SMatthew Dillon 
75572ff6f6SMatthew Dillon static void
ar5416PrepSpectralScan(struct ath_hal * ah)76572ff6f6SMatthew Dillon ar5416PrepSpectralScan(struct ath_hal *ah)
77572ff6f6SMatthew Dillon {
78572ff6f6SMatthew Dillon 
79572ff6f6SMatthew Dillon 	ar5416DisableRadar(ah);
80572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_PHY_ERR, ENABLE_ALL_PHYERR);
81572ff6f6SMatthew Dillon }
82572ff6f6SMatthew Dillon 
83572ff6f6SMatthew Dillon void
ar5416ConfigureSpectralScan(struct ath_hal * ah,HAL_SPECTRAL_PARAM * ss)84572ff6f6SMatthew Dillon ar5416ConfigureSpectralScan(struct ath_hal *ah, HAL_SPECTRAL_PARAM *ss)
85572ff6f6SMatthew Dillon {
86572ff6f6SMatthew Dillon 	uint32_t val;
87572ff6f6SMatthew Dillon 
88572ff6f6SMatthew Dillon 	ar5416PrepSpectralScan(ah);
89572ff6f6SMatthew Dillon 
90572ff6f6SMatthew Dillon 	val = OS_REG_READ(ah, AR_PHY_SPECTRAL_SCAN);
91572ff6f6SMatthew Dillon 
92572ff6f6SMatthew Dillon 	if (ss->ss_fft_period != HAL_SPECTRAL_PARAM_NOVAL) {
93572ff6f6SMatthew Dillon 		val &= ~AR_PHY_SPECTRAL_SCAN_FFT_PERIOD;
94572ff6f6SMatthew Dillon 		val |= SM(ss->ss_fft_period, AR_PHY_SPECTRAL_SCAN_FFT_PERIOD);
95572ff6f6SMatthew Dillon 	}
96572ff6f6SMatthew Dillon 
97572ff6f6SMatthew Dillon 	if (ss->ss_period != HAL_SPECTRAL_PARAM_NOVAL) {
98572ff6f6SMatthew Dillon 		val &= ~AR_PHY_SPECTRAL_SCAN_PERIOD;
99572ff6f6SMatthew Dillon 		val |= SM(ss->ss_period, AR_PHY_SPECTRAL_SCAN_PERIOD);
100572ff6f6SMatthew Dillon 	}
101572ff6f6SMatthew Dillon 
102572ff6f6SMatthew Dillon 	if (ss->ss_period != HAL_SPECTRAL_PARAM_NOVAL) {
103572ff6f6SMatthew Dillon 		val &= ~AR_PHY_SPECTRAL_SCAN_PERIOD;
104572ff6f6SMatthew Dillon 		val |= SM(ss->ss_period, AR_PHY_SPECTRAL_SCAN_PERIOD);
105572ff6f6SMatthew Dillon 	}
106572ff6f6SMatthew Dillon 
107572ff6f6SMatthew Dillon 	/* This section is different for Kiwi and Merlin */
108572ff6f6SMatthew Dillon 	if (AR_SREV_MERLIN(ah) ) {
109572ff6f6SMatthew Dillon 		if (ss->ss_count != HAL_SPECTRAL_PARAM_NOVAL) {
110572ff6f6SMatthew Dillon 			val &= ~AR_PHY_SPECTRAL_SCAN_COUNT;
111572ff6f6SMatthew Dillon 			val |= SM(ss->ss_count, AR_PHY_SPECTRAL_SCAN_COUNT);
112572ff6f6SMatthew Dillon 		}
113572ff6f6SMatthew Dillon 
114572ff6f6SMatthew Dillon 		if (ss->ss_short_report == AH_TRUE) {
115572ff6f6SMatthew Dillon 			val |= AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT;
116572ff6f6SMatthew Dillon 		} else if (ss->ss_short_report != HAL_SPECTRAL_PARAM_NOVAL) {
117572ff6f6SMatthew Dillon 			val &= ~AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT;
118572ff6f6SMatthew Dillon 		}
119572ff6f6SMatthew Dillon 	} else {
120572ff6f6SMatthew Dillon 		if (ss->ss_count != HAL_SPECTRAL_PARAM_NOVAL) {
121572ff6f6SMatthew Dillon 			/*
122*b14ca477SMatthew Dillon 			 * In Merlin, for continuous scan, scan_count = 128.
123572ff6f6SMatthew Dillon 			 * In case of Kiwi, this value should be 0
124572ff6f6SMatthew Dillon 			 */
125572ff6f6SMatthew Dillon 			if (ss->ss_count == 128)
126572ff6f6SMatthew Dillon 				ss->ss_count = 0;
127572ff6f6SMatthew Dillon 			val &= ~AR_PHY_SPECTRAL_SCAN_COUNT_KIWI;
128572ff6f6SMatthew Dillon 			val |= SM(ss->ss_count, AR_PHY_SPECTRAL_SCAN_COUNT_KIWI);
129572ff6f6SMatthew Dillon 		}
130572ff6f6SMatthew Dillon 
131572ff6f6SMatthew Dillon 		if (ss->ss_short_report == AH_TRUE) {
132572ff6f6SMatthew Dillon 			val |= AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_KIWI;
133572ff6f6SMatthew Dillon 		} else if (ss->ss_short_report != HAL_SPECTRAL_PARAM_NOVAL) {
134572ff6f6SMatthew Dillon 			val &= ~AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_KIWI;
135572ff6f6SMatthew Dillon 		}
136572ff6f6SMatthew Dillon 
137572ff6f6SMatthew Dillon 		//Select the mask to be same as before
138572ff6f6SMatthew Dillon 		val |= AR_PHY_SPECTRAL_SCAN_PHYERR_MASK_SELECT_KIWI;
139572ff6f6SMatthew Dillon 	}
140572ff6f6SMatthew Dillon 	// Enable spectral scan
141572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_PHY_SPECTRAL_SCAN, val | AR_PHY_SPECTRAL_SCAN_ENA);
142572ff6f6SMatthew Dillon 
143572ff6f6SMatthew Dillon 	ar5416GetSpectralParams(ah, ss);
144572ff6f6SMatthew Dillon }
145572ff6f6SMatthew Dillon 
146572ff6f6SMatthew Dillon /*
147572ff6f6SMatthew Dillon  * Get the spectral parameter values and return them in the pe
148572ff6f6SMatthew Dillon  * structure
149572ff6f6SMatthew Dillon  */
150572ff6f6SMatthew Dillon void
ar5416GetSpectralParams(struct ath_hal * ah,HAL_SPECTRAL_PARAM * ss)151572ff6f6SMatthew Dillon ar5416GetSpectralParams(struct ath_hal *ah, HAL_SPECTRAL_PARAM *ss)
152572ff6f6SMatthew Dillon {
153572ff6f6SMatthew Dillon 	uint32_t val;
154572ff6f6SMatthew Dillon 
155572ff6f6SMatthew Dillon 	val = OS_REG_READ(ah, AR_PHY_SPECTRAL_SCAN);
156572ff6f6SMatthew Dillon 
157572ff6f6SMatthew Dillon 	ss->ss_fft_period = MS(val, AR_PHY_SPECTRAL_SCAN_FFT_PERIOD);
158572ff6f6SMatthew Dillon 	ss->ss_period = MS(val, AR_PHY_SPECTRAL_SCAN_PERIOD);
159572ff6f6SMatthew Dillon 	if (AR_SREV_MERLIN(ah) ) {
160572ff6f6SMatthew Dillon 		ss->ss_count = MS(val, AR_PHY_SPECTRAL_SCAN_COUNT);
161572ff6f6SMatthew Dillon 		ss->ss_short_report = MS(val, AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT);
162572ff6f6SMatthew Dillon 	} else {
163572ff6f6SMatthew Dillon 		ss->ss_count = MS(val, AR_PHY_SPECTRAL_SCAN_COUNT_KIWI);
164572ff6f6SMatthew Dillon 		ss->ss_short_report = MS(val, AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_KIWI);
165572ff6f6SMatthew Dillon 	}
166572ff6f6SMatthew Dillon 	val = OS_REG_READ(ah, AR_PHY_RADAR_1);
167572ff6f6SMatthew Dillon 	ss->radar_bin_thresh_sel = MS(val, AR_PHY_RADAR_1_BIN_THRESH_SELECT);
168572ff6f6SMatthew Dillon }
169572ff6f6SMatthew Dillon 
170572ff6f6SMatthew Dillon HAL_BOOL
ar5416IsSpectralActive(struct ath_hal * ah)171572ff6f6SMatthew Dillon ar5416IsSpectralActive(struct ath_hal *ah)
172572ff6f6SMatthew Dillon {
173572ff6f6SMatthew Dillon 	uint32_t val;
174572ff6f6SMatthew Dillon 
175572ff6f6SMatthew Dillon 	val = OS_REG_READ(ah, AR_PHY_SPECTRAL_SCAN);
176572ff6f6SMatthew Dillon 	return MS(val, AR_PHY_SPECTRAL_SCAN_ACTIVE);
177572ff6f6SMatthew Dillon }
178572ff6f6SMatthew Dillon 
179572ff6f6SMatthew Dillon HAL_BOOL
ar5416IsSpectralEnabled(struct ath_hal * ah)180572ff6f6SMatthew Dillon ar5416IsSpectralEnabled(struct ath_hal *ah)
181572ff6f6SMatthew Dillon {
182572ff6f6SMatthew Dillon 	uint32_t val;
183572ff6f6SMatthew Dillon 
184572ff6f6SMatthew Dillon 	val = OS_REG_READ(ah, AR_PHY_SPECTRAL_SCAN);
185572ff6f6SMatthew Dillon 	return MS(val,AR_PHY_SPECTRAL_SCAN_ENA);
186572ff6f6SMatthew Dillon }
187572ff6f6SMatthew Dillon 
188572ff6f6SMatthew Dillon void
ar5416StartSpectralScan(struct ath_hal * ah)189572ff6f6SMatthew Dillon ar5416StartSpectralScan(struct ath_hal *ah)
190572ff6f6SMatthew Dillon {
191572ff6f6SMatthew Dillon 	uint32_t val;
192572ff6f6SMatthew Dillon 
193572ff6f6SMatthew Dillon 	ar5416PrepSpectralScan(ah);
194572ff6f6SMatthew Dillon 
195572ff6f6SMatthew Dillon 	// Activate spectral scan
196572ff6f6SMatthew Dillon 	val = OS_REG_READ(ah, AR_PHY_SPECTRAL_SCAN);
197572ff6f6SMatthew Dillon 	val |= AR_PHY_SPECTRAL_SCAN_ENA;
198572ff6f6SMatthew Dillon 	val |= AR_PHY_SPECTRAL_SCAN_ACTIVE;
199572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_PHY_SPECTRAL_SCAN, val);
200572ff6f6SMatthew Dillon 	val = OS_REG_READ(ah, AR_PHY_SPECTRAL_SCAN);
201572ff6f6SMatthew Dillon 	val = OS_REG_READ(ah, AR_PHY_ERR_MASK_REG);
202572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_PHY_ERR_MASK_REG, val | AR_PHY_ERR_RADAR);
203572ff6f6SMatthew Dillon }
204572ff6f6SMatthew Dillon 
205572ff6f6SMatthew Dillon void
ar5416StopSpectralScan(struct ath_hal * ah)206572ff6f6SMatthew Dillon ar5416StopSpectralScan(struct ath_hal *ah)
207572ff6f6SMatthew Dillon {
208572ff6f6SMatthew Dillon 	uint32_t val;
209572ff6f6SMatthew Dillon 	val = OS_REG_READ(ah, AR_PHY_SPECTRAL_SCAN);
210572ff6f6SMatthew Dillon 
211572ff6f6SMatthew Dillon 	// Deactivate spectral scan
212572ff6f6SMatthew Dillon 	val &= ~AR_PHY_SPECTRAL_SCAN_ENA;
213572ff6f6SMatthew Dillon 	val &= ~AR_PHY_SPECTRAL_SCAN_ACTIVE;
214572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_PHY_SPECTRAL_SCAN, val);
215572ff6f6SMatthew Dillon 	val = OS_REG_READ(ah, AR_PHY_SPECTRAL_SCAN);
216572ff6f6SMatthew Dillon 	val = OS_REG_READ(ah, AR_PHY_ERR_MASK_REG) & (~AR_PHY_ERR_RADAR);
217572ff6f6SMatthew Dillon 	OS_REG_WRITE(ah, AR_PHY_ERR_MASK_REG, val);
218572ff6f6SMatthew Dillon }
219572ff6f6SMatthew Dillon 
220572ff6f6SMatthew Dillon uint32_t
ar5416GetSpectralConfig(struct ath_hal * ah)221572ff6f6SMatthew Dillon ar5416GetSpectralConfig(struct ath_hal *ah)
222572ff6f6SMatthew Dillon {
223572ff6f6SMatthew Dillon 	uint32_t val;
224572ff6f6SMatthew Dillon 
225572ff6f6SMatthew Dillon 	val = OS_REG_READ(ah, AR_PHY_SPECTRAL_SCAN);
226572ff6f6SMatthew Dillon 	return val;
227572ff6f6SMatthew Dillon }
228572ff6f6SMatthew Dillon 
229572ff6f6SMatthew Dillon void
ar5416RestoreSpectralConfig(struct ath_hal * ah,uint32_t restoreval)230572ff6f6SMatthew Dillon ar5416RestoreSpectralConfig(struct ath_hal *ah, uint32_t restoreval)
231572ff6f6SMatthew Dillon {
232572ff6f6SMatthew Dillon 	uint32_t curval;
233572ff6f6SMatthew Dillon 
234572ff6f6SMatthew Dillon 	ar5416PrepSpectralScan(ah);
235572ff6f6SMatthew Dillon 
236572ff6f6SMatthew Dillon 	curval = OS_REG_READ(ah, AR_PHY_SPECTRAL_SCAN);
237572ff6f6SMatthew Dillon 
238572ff6f6SMatthew Dillon 	if (restoreval != curval) {
239572ff6f6SMatthew Dillon 		restoreval |= AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT;
240572ff6f6SMatthew Dillon 		OS_REG_WRITE(ah, AR_PHY_SPECTRAL_SCAN, restoreval);
241572ff6f6SMatthew Dillon 	}
242572ff6f6SMatthew Dillon 	return;
243572ff6f6SMatthew Dillon }
244572ff6f6SMatthew Dillon 
245