xref: /linux/drivers/net/wireless/mediatek/mt76/mt76x02_dfs.c (revision e6cb3291053fdf21e5caba68137b4bab112815fc)
1*e6cb3291SLorenzo Bianconi /*
2*e6cb3291SLorenzo Bianconi  * Copyright (C) 2016 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
3*e6cb3291SLorenzo Bianconi  *
4*e6cb3291SLorenzo Bianconi  * Permission to use, copy, modify, and/or distribute this software for any
5*e6cb3291SLorenzo Bianconi  * purpose with or without fee is hereby granted, provided that the above
6*e6cb3291SLorenzo Bianconi  * copyright notice and this permission notice appear in all copies.
7*e6cb3291SLorenzo Bianconi  *
8*e6cb3291SLorenzo Bianconi  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9*e6cb3291SLorenzo Bianconi  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10*e6cb3291SLorenzo Bianconi  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11*e6cb3291SLorenzo Bianconi  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12*e6cb3291SLorenzo Bianconi  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13*e6cb3291SLorenzo Bianconi  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14*e6cb3291SLorenzo Bianconi  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*e6cb3291SLorenzo Bianconi  */
16*e6cb3291SLorenzo Bianconi 
17*e6cb3291SLorenzo Bianconi #include "mt76x02.h"
18*e6cb3291SLorenzo Bianconi 
19*e6cb3291SLorenzo Bianconi #define RADAR_SPEC(m, len, el, eh, wl, wh,		\
20*e6cb3291SLorenzo Bianconi 		   w_tolerance, tl, th, t_tolerance,	\
21*e6cb3291SLorenzo Bianconi 		   bl, bh, event_exp, power_jmp)	\
22*e6cb3291SLorenzo Bianconi {							\
23*e6cb3291SLorenzo Bianconi 	.mode = m,					\
24*e6cb3291SLorenzo Bianconi 	.avg_len = len,					\
25*e6cb3291SLorenzo Bianconi 	.e_low = el,					\
26*e6cb3291SLorenzo Bianconi 	.e_high = eh,					\
27*e6cb3291SLorenzo Bianconi 	.w_low = wl,					\
28*e6cb3291SLorenzo Bianconi 	.w_high = wh,					\
29*e6cb3291SLorenzo Bianconi 	.w_margin = w_tolerance,			\
30*e6cb3291SLorenzo Bianconi 	.t_low = tl,					\
31*e6cb3291SLorenzo Bianconi 	.t_high = th,					\
32*e6cb3291SLorenzo Bianconi 	.t_margin = t_tolerance,			\
33*e6cb3291SLorenzo Bianconi 	.b_low = bl,					\
34*e6cb3291SLorenzo Bianconi 	.b_high = bh,					\
35*e6cb3291SLorenzo Bianconi 	.event_expiration = event_exp,			\
36*e6cb3291SLorenzo Bianconi 	.pwr_jmp = power_jmp				\
37*e6cb3291SLorenzo Bianconi }
38*e6cb3291SLorenzo Bianconi 
39*e6cb3291SLorenzo Bianconi static const struct mt76x02_radar_specs etsi_radar_specs[] = {
40*e6cb3291SLorenzo Bianconi 	/* 20MHz */
41*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0,
42*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x155cc0, 0x19cc),
43*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0,
44*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x155cc0, 0x19cc),
45*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0,
46*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x155cc0, 0x19dd),
47*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0,
48*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x2191c0, 0x15cc),
49*e6cb3291SLorenzo Bianconi 	/* 40MHz */
50*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0,
51*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x155cc0, 0x19cc),
52*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0,
53*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x155cc0, 0x19cc),
54*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0,
55*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x155cc0, 0x19dd),
56*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0,
57*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x2191c0, 0x15cc),
58*e6cb3291SLorenzo Bianconi 	/* 80MHz */
59*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0,
60*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x155cc0, 0x19cc),
61*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0,
62*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x155cc0, 0x19cc),
63*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0,
64*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x155cc0, 0x19dd),
65*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0,
66*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x2191c0, 0x15cc)
67*e6cb3291SLorenzo Bianconi };
68*e6cb3291SLorenzo Bianconi 
69*e6cb3291SLorenzo Bianconi static const struct mt76x02_radar_specs fcc_radar_specs[] = {
70*e6cb3291SLorenzo Bianconi 	/* 20MHz */
71*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 8, 2, 12, 106, 150, 5, 2900, 80100, 5, 0,
72*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0xfe808, 0x13dc),
73*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
74*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0xfe808, 0x19dd),
75*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0,
76*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0xfe808, 0x12cc),
77*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0,
78*e6cb3291SLorenzo Bianconi 		   0x3938700, 0x57bcf00, 0x1289),
79*e6cb3291SLorenzo Bianconi 	/* 40MHz */
80*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 8, 2, 12, 106, 150, 5, 2900, 80100, 5, 0,
81*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0xfe808, 0x13dc),
82*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
83*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0xfe808, 0x19dd),
84*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0,
85*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0xfe808, 0x12cc),
86*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0,
87*e6cb3291SLorenzo Bianconi 		   0x3938700, 0x57bcf00, 0x1289),
88*e6cb3291SLorenzo Bianconi 	/* 80MHz */
89*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 8, 2, 14, 106, 150, 15, 2900, 80100, 15, 0,
90*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0xfe808, 0x16cc),
91*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
92*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0xfe808, 0x19dd),
93*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0,
94*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0xfe808, 0x12cc),
95*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0,
96*e6cb3291SLorenzo Bianconi 		   0x3938700, 0x57bcf00, 0x1289)
97*e6cb3291SLorenzo Bianconi };
98*e6cb3291SLorenzo Bianconi 
99*e6cb3291SLorenzo Bianconi static const struct mt76x02_radar_specs jp_w56_radar_specs[] = {
100*e6cb3291SLorenzo Bianconi 	/* 20MHz */
101*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 8, 2, 7, 106, 150, 5, 2900, 80100, 5, 0,
102*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x14c080, 0x13dc),
103*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
104*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x14c080, 0x19dd),
105*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0,
106*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x14c080, 0x12cc),
107*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0,
108*e6cb3291SLorenzo Bianconi 		   0x3938700, 0X57bcf00, 0x1289),
109*e6cb3291SLorenzo Bianconi 	/* 40MHz */
110*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 8, 2, 7, 106, 150, 5, 2900, 80100, 5, 0,
111*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x14c080, 0x13dc),
112*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
113*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x14c080, 0x19dd),
114*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0,
115*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x14c080, 0x12cc),
116*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0,
117*e6cb3291SLorenzo Bianconi 		   0x3938700, 0X57bcf00, 0x1289),
118*e6cb3291SLorenzo Bianconi 	/* 80MHz */
119*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 8, 2, 9, 106, 150, 15, 2900, 80100, 15, 0,
120*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x14c080, 0x16cc),
121*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
122*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x14c080, 0x19dd),
123*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0,
124*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x14c080, 0x12cc),
125*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0,
126*e6cb3291SLorenzo Bianconi 		   0x3938700, 0X57bcf00, 0x1289)
127*e6cb3291SLorenzo Bianconi };
128*e6cb3291SLorenzo Bianconi 
129*e6cb3291SLorenzo Bianconi static const struct mt76x02_radar_specs jp_w53_radar_specs[] = {
130*e6cb3291SLorenzo Bianconi 	/* 20MHz */
131*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0,
132*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x14c080, 0x16cc),
133*e6cb3291SLorenzo Bianconi 	{ 0 },
134*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0,
135*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x14c080, 0x16cc),
136*e6cb3291SLorenzo Bianconi 	{ 0 },
137*e6cb3291SLorenzo Bianconi 	/* 40MHz */
138*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0,
139*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x14c080, 0x16cc),
140*e6cb3291SLorenzo Bianconi 	{ 0 },
141*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0,
142*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x14c080, 0x16cc),
143*e6cb3291SLorenzo Bianconi 	{ 0 },
144*e6cb3291SLorenzo Bianconi 	/* 80MHz */
145*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0,
146*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x14c080, 0x16cc),
147*e6cb3291SLorenzo Bianconi 	{ 0 },
148*e6cb3291SLorenzo Bianconi 	RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0,
149*e6cb3291SLorenzo Bianconi 		   0x7fffffff, 0x14c080, 0x16cc),
150*e6cb3291SLorenzo Bianconi 	{ 0 }
151*e6cb3291SLorenzo Bianconi };
152*e6cb3291SLorenzo Bianconi 
153*e6cb3291SLorenzo Bianconi static void
154*e6cb3291SLorenzo Bianconi mt76x02_dfs_set_capture_mode_ctrl(struct mt76x02_dev *dev, u8 enable)
155*e6cb3291SLorenzo Bianconi {
156*e6cb3291SLorenzo Bianconi 	u32 data;
157*e6cb3291SLorenzo Bianconi 
158*e6cb3291SLorenzo Bianconi 	data = (1 << 1) | enable;
159*e6cb3291SLorenzo Bianconi 	mt76_wr(dev, MT_BBP(DFS, 36), data);
160*e6cb3291SLorenzo Bianconi }
161*e6cb3291SLorenzo Bianconi 
162*e6cb3291SLorenzo Bianconi static void mt76x02_dfs_seq_pool_put(struct mt76x02_dev *dev,
163*e6cb3291SLorenzo Bianconi 				     struct mt76x02_dfs_sequence *seq)
164*e6cb3291SLorenzo Bianconi {
165*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
166*e6cb3291SLorenzo Bianconi 
167*e6cb3291SLorenzo Bianconi 	list_add(&seq->head, &dfs_pd->seq_pool);
168*e6cb3291SLorenzo Bianconi 
169*e6cb3291SLorenzo Bianconi 	dfs_pd->seq_stats.seq_pool_len++;
170*e6cb3291SLorenzo Bianconi 	dfs_pd->seq_stats.seq_len--;
171*e6cb3291SLorenzo Bianconi }
172*e6cb3291SLorenzo Bianconi 
173*e6cb3291SLorenzo Bianconi static struct mt76x02_dfs_sequence *
174*e6cb3291SLorenzo Bianconi mt76x02_dfs_seq_pool_get(struct mt76x02_dev *dev)
175*e6cb3291SLorenzo Bianconi {
176*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
177*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_sequence *seq;
178*e6cb3291SLorenzo Bianconi 
179*e6cb3291SLorenzo Bianconi 	if (list_empty(&dfs_pd->seq_pool)) {
180*e6cb3291SLorenzo Bianconi 		seq = devm_kzalloc(dev->mt76.dev, sizeof(*seq), GFP_ATOMIC);
181*e6cb3291SLorenzo Bianconi 	} else {
182*e6cb3291SLorenzo Bianconi 		seq = list_first_entry(&dfs_pd->seq_pool,
183*e6cb3291SLorenzo Bianconi 				       struct mt76x02_dfs_sequence,
184*e6cb3291SLorenzo Bianconi 				       head);
185*e6cb3291SLorenzo Bianconi 		list_del(&seq->head);
186*e6cb3291SLorenzo Bianconi 		dfs_pd->seq_stats.seq_pool_len--;
187*e6cb3291SLorenzo Bianconi 	}
188*e6cb3291SLorenzo Bianconi 	if (seq)
189*e6cb3291SLorenzo Bianconi 		dfs_pd->seq_stats.seq_len++;
190*e6cb3291SLorenzo Bianconi 
191*e6cb3291SLorenzo Bianconi 	return seq;
192*e6cb3291SLorenzo Bianconi }
193*e6cb3291SLorenzo Bianconi 
194*e6cb3291SLorenzo Bianconi static int mt76x02_dfs_get_multiple(int val, int frac, int margin)
195*e6cb3291SLorenzo Bianconi {
196*e6cb3291SLorenzo Bianconi 	int remainder, factor;
197*e6cb3291SLorenzo Bianconi 
198*e6cb3291SLorenzo Bianconi 	if (!frac)
199*e6cb3291SLorenzo Bianconi 		return 0;
200*e6cb3291SLorenzo Bianconi 
201*e6cb3291SLorenzo Bianconi 	if (abs(val - frac) <= margin)
202*e6cb3291SLorenzo Bianconi 		return 1;
203*e6cb3291SLorenzo Bianconi 
204*e6cb3291SLorenzo Bianconi 	factor = val / frac;
205*e6cb3291SLorenzo Bianconi 	remainder = val % frac;
206*e6cb3291SLorenzo Bianconi 
207*e6cb3291SLorenzo Bianconi 	if (remainder > margin) {
208*e6cb3291SLorenzo Bianconi 		if ((frac - remainder) <= margin)
209*e6cb3291SLorenzo Bianconi 			factor++;
210*e6cb3291SLorenzo Bianconi 		else
211*e6cb3291SLorenzo Bianconi 			factor = 0;
212*e6cb3291SLorenzo Bianconi 	}
213*e6cb3291SLorenzo Bianconi 	return factor;
214*e6cb3291SLorenzo Bianconi }
215*e6cb3291SLorenzo Bianconi 
216*e6cb3291SLorenzo Bianconi static void mt76x02_dfs_detector_reset(struct mt76x02_dev *dev)
217*e6cb3291SLorenzo Bianconi {
218*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
219*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_sequence *seq, *tmp_seq;
220*e6cb3291SLorenzo Bianconi 	int i;
221*e6cb3291SLorenzo Bianconi 
222*e6cb3291SLorenzo Bianconi 	/* reset hw detector */
223*e6cb3291SLorenzo Bianconi 	mt76_wr(dev, MT_BBP(DFS, 1), 0xf);
224*e6cb3291SLorenzo Bianconi 
225*e6cb3291SLorenzo Bianconi 	/* reset sw detector */
226*e6cb3291SLorenzo Bianconi 	for (i = 0; i < ARRAY_SIZE(dfs_pd->event_rb); i++) {
227*e6cb3291SLorenzo Bianconi 		dfs_pd->event_rb[i].h_rb = 0;
228*e6cb3291SLorenzo Bianconi 		dfs_pd->event_rb[i].t_rb = 0;
229*e6cb3291SLorenzo Bianconi 	}
230*e6cb3291SLorenzo Bianconi 
231*e6cb3291SLorenzo Bianconi 	list_for_each_entry_safe(seq, tmp_seq, &dfs_pd->sequences, head) {
232*e6cb3291SLorenzo Bianconi 		list_del_init(&seq->head);
233*e6cb3291SLorenzo Bianconi 		mt76x02_dfs_seq_pool_put(dev, seq);
234*e6cb3291SLorenzo Bianconi 	}
235*e6cb3291SLorenzo Bianconi }
236*e6cb3291SLorenzo Bianconi 
237*e6cb3291SLorenzo Bianconi static bool mt76x02_dfs_check_chirp(struct mt76x02_dev *dev)
238*e6cb3291SLorenzo Bianconi {
239*e6cb3291SLorenzo Bianconi 	bool ret = false;
240*e6cb3291SLorenzo Bianconi 	u32 current_ts, delta_ts;
241*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
242*e6cb3291SLorenzo Bianconi 
243*e6cb3291SLorenzo Bianconi 	current_ts = mt76_rr(dev, MT_PBF_LIFE_TIMER);
244*e6cb3291SLorenzo Bianconi 	delta_ts = current_ts - dfs_pd->chirp_pulse_ts;
245*e6cb3291SLorenzo Bianconi 	dfs_pd->chirp_pulse_ts = current_ts;
246*e6cb3291SLorenzo Bianconi 
247*e6cb3291SLorenzo Bianconi 	/* 12 sec */
248*e6cb3291SLorenzo Bianconi 	if (delta_ts <= (12 * (1 << 20))) {
249*e6cb3291SLorenzo Bianconi 		if (++dfs_pd->chirp_pulse_cnt > 8)
250*e6cb3291SLorenzo Bianconi 			ret = true;
251*e6cb3291SLorenzo Bianconi 	} else {
252*e6cb3291SLorenzo Bianconi 		dfs_pd->chirp_pulse_cnt = 1;
253*e6cb3291SLorenzo Bianconi 	}
254*e6cb3291SLorenzo Bianconi 
255*e6cb3291SLorenzo Bianconi 	return ret;
256*e6cb3291SLorenzo Bianconi }
257*e6cb3291SLorenzo Bianconi 
258*e6cb3291SLorenzo Bianconi static void mt76x02_dfs_get_hw_pulse(struct mt76x02_dev *dev,
259*e6cb3291SLorenzo Bianconi 				     struct mt76x02_dfs_hw_pulse *pulse)
260*e6cb3291SLorenzo Bianconi {
261*e6cb3291SLorenzo Bianconi 	u32 data;
262*e6cb3291SLorenzo Bianconi 
263*e6cb3291SLorenzo Bianconi 	/* select channel */
264*e6cb3291SLorenzo Bianconi 	data = (MT_DFS_CH_EN << 16) | pulse->engine;
265*e6cb3291SLorenzo Bianconi 	mt76_wr(dev, MT_BBP(DFS, 0), data);
266*e6cb3291SLorenzo Bianconi 
267*e6cb3291SLorenzo Bianconi 	/* reported period */
268*e6cb3291SLorenzo Bianconi 	pulse->period = mt76_rr(dev, MT_BBP(DFS, 19));
269*e6cb3291SLorenzo Bianconi 
270*e6cb3291SLorenzo Bianconi 	/* reported width */
271*e6cb3291SLorenzo Bianconi 	pulse->w1 = mt76_rr(dev, MT_BBP(DFS, 20));
272*e6cb3291SLorenzo Bianconi 	pulse->w2 = mt76_rr(dev, MT_BBP(DFS, 23));
273*e6cb3291SLorenzo Bianconi 
274*e6cb3291SLorenzo Bianconi 	/* reported burst number */
275*e6cb3291SLorenzo Bianconi 	pulse->burst = mt76_rr(dev, MT_BBP(DFS, 22));
276*e6cb3291SLorenzo Bianconi }
277*e6cb3291SLorenzo Bianconi 
278*e6cb3291SLorenzo Bianconi static bool mt76x02_dfs_check_hw_pulse(struct mt76x02_dev *dev,
279*e6cb3291SLorenzo Bianconi 				       struct mt76x02_dfs_hw_pulse *pulse)
280*e6cb3291SLorenzo Bianconi {
281*e6cb3291SLorenzo Bianconi 	bool ret = false;
282*e6cb3291SLorenzo Bianconi 
283*e6cb3291SLorenzo Bianconi 	if (!pulse->period || !pulse->w1)
284*e6cb3291SLorenzo Bianconi 		return false;
285*e6cb3291SLorenzo Bianconi 
286*e6cb3291SLorenzo Bianconi 	switch (dev->dfs_pd.region) {
287*e6cb3291SLorenzo Bianconi 	case NL80211_DFS_FCC:
288*e6cb3291SLorenzo Bianconi 		if (pulse->engine > 3)
289*e6cb3291SLorenzo Bianconi 			break;
290*e6cb3291SLorenzo Bianconi 
291*e6cb3291SLorenzo Bianconi 		if (pulse->engine == 3) {
292*e6cb3291SLorenzo Bianconi 			ret = mt76x02_dfs_check_chirp(dev);
293*e6cb3291SLorenzo Bianconi 			break;
294*e6cb3291SLorenzo Bianconi 		}
295*e6cb3291SLorenzo Bianconi 
296*e6cb3291SLorenzo Bianconi 		/* check short pulse*/
297*e6cb3291SLorenzo Bianconi 		if (pulse->w1 < 120)
298*e6cb3291SLorenzo Bianconi 			ret = (pulse->period >= 2900 &&
299*e6cb3291SLorenzo Bianconi 			       (pulse->period <= 4700 ||
300*e6cb3291SLorenzo Bianconi 				pulse->period >= 6400) &&
301*e6cb3291SLorenzo Bianconi 			       (pulse->period <= 6800 ||
302*e6cb3291SLorenzo Bianconi 				pulse->period >= 10200) &&
303*e6cb3291SLorenzo Bianconi 			       pulse->period <= 61600);
304*e6cb3291SLorenzo Bianconi 		else if (pulse->w1 < 130) /* 120 - 130 */
305*e6cb3291SLorenzo Bianconi 			ret = (pulse->period >= 2900 &&
306*e6cb3291SLorenzo Bianconi 			       pulse->period <= 61600);
307*e6cb3291SLorenzo Bianconi 		else
308*e6cb3291SLorenzo Bianconi 			ret = (pulse->period >= 3500 &&
309*e6cb3291SLorenzo Bianconi 			       pulse->period <= 10100);
310*e6cb3291SLorenzo Bianconi 		break;
311*e6cb3291SLorenzo Bianconi 	case NL80211_DFS_ETSI:
312*e6cb3291SLorenzo Bianconi 		if (pulse->engine >= 3)
313*e6cb3291SLorenzo Bianconi 			break;
314*e6cb3291SLorenzo Bianconi 
315*e6cb3291SLorenzo Bianconi 		ret = (pulse->period >= 4900 &&
316*e6cb3291SLorenzo Bianconi 		       (pulse->period <= 10200 ||
317*e6cb3291SLorenzo Bianconi 			pulse->period >= 12400) &&
318*e6cb3291SLorenzo Bianconi 		       pulse->period <= 100100);
319*e6cb3291SLorenzo Bianconi 		break;
320*e6cb3291SLorenzo Bianconi 	case NL80211_DFS_JP:
321*e6cb3291SLorenzo Bianconi 		if (dev->mt76.chandef.chan->center_freq >= 5250 &&
322*e6cb3291SLorenzo Bianconi 		    dev->mt76.chandef.chan->center_freq <= 5350) {
323*e6cb3291SLorenzo Bianconi 			/* JPW53 */
324*e6cb3291SLorenzo Bianconi 			if (pulse->w1 <= 130)
325*e6cb3291SLorenzo Bianconi 				ret = (pulse->period >= 28360 &&
326*e6cb3291SLorenzo Bianconi 				       (pulse->period <= 28700 ||
327*e6cb3291SLorenzo Bianconi 					pulse->period >= 76900) &&
328*e6cb3291SLorenzo Bianconi 				       pulse->period <= 76940);
329*e6cb3291SLorenzo Bianconi 			break;
330*e6cb3291SLorenzo Bianconi 		}
331*e6cb3291SLorenzo Bianconi 
332*e6cb3291SLorenzo Bianconi 		if (pulse->engine > 3)
333*e6cb3291SLorenzo Bianconi 			break;
334*e6cb3291SLorenzo Bianconi 
335*e6cb3291SLorenzo Bianconi 		if (pulse->engine == 3) {
336*e6cb3291SLorenzo Bianconi 			ret = mt76x02_dfs_check_chirp(dev);
337*e6cb3291SLorenzo Bianconi 			break;
338*e6cb3291SLorenzo Bianconi 		}
339*e6cb3291SLorenzo Bianconi 
340*e6cb3291SLorenzo Bianconi 		/* check short pulse*/
341*e6cb3291SLorenzo Bianconi 		if (pulse->w1 < 120)
342*e6cb3291SLorenzo Bianconi 			ret = (pulse->period >= 2900 &&
343*e6cb3291SLorenzo Bianconi 			       (pulse->period <= 4700 ||
344*e6cb3291SLorenzo Bianconi 				pulse->period >= 6400) &&
345*e6cb3291SLorenzo Bianconi 			       (pulse->period <= 6800 ||
346*e6cb3291SLorenzo Bianconi 				pulse->period >= 27560) &&
347*e6cb3291SLorenzo Bianconi 			       (pulse->period <= 27960 ||
348*e6cb3291SLorenzo Bianconi 				pulse->period >= 28360) &&
349*e6cb3291SLorenzo Bianconi 			       (pulse->period <= 28700 ||
350*e6cb3291SLorenzo Bianconi 				pulse->period >= 79900) &&
351*e6cb3291SLorenzo Bianconi 			       pulse->period <= 80100);
352*e6cb3291SLorenzo Bianconi 		else if (pulse->w1 < 130) /* 120 - 130 */
353*e6cb3291SLorenzo Bianconi 			ret = (pulse->period >= 2900 &&
354*e6cb3291SLorenzo Bianconi 			       (pulse->period <= 10100 ||
355*e6cb3291SLorenzo Bianconi 				pulse->period >= 27560) &&
356*e6cb3291SLorenzo Bianconi 			       (pulse->period <= 27960 ||
357*e6cb3291SLorenzo Bianconi 				pulse->period >= 28360) &&
358*e6cb3291SLorenzo Bianconi 			       (pulse->period <= 28700 ||
359*e6cb3291SLorenzo Bianconi 				pulse->period >= 79900) &&
360*e6cb3291SLorenzo Bianconi 			       pulse->period <= 80100);
361*e6cb3291SLorenzo Bianconi 		else
362*e6cb3291SLorenzo Bianconi 			ret = (pulse->period >= 3900 &&
363*e6cb3291SLorenzo Bianconi 			       pulse->period <= 10100);
364*e6cb3291SLorenzo Bianconi 		break;
365*e6cb3291SLorenzo Bianconi 	case NL80211_DFS_UNSET:
366*e6cb3291SLorenzo Bianconi 	default:
367*e6cb3291SLorenzo Bianconi 		return false;
368*e6cb3291SLorenzo Bianconi 	}
369*e6cb3291SLorenzo Bianconi 
370*e6cb3291SLorenzo Bianconi 	return ret;
371*e6cb3291SLorenzo Bianconi }
372*e6cb3291SLorenzo Bianconi 
373*e6cb3291SLorenzo Bianconi static bool mt76x02_dfs_fetch_event(struct mt76x02_dev *dev,
374*e6cb3291SLorenzo Bianconi 				    struct mt76x02_dfs_event *event)
375*e6cb3291SLorenzo Bianconi {
376*e6cb3291SLorenzo Bianconi 	u32 data;
377*e6cb3291SLorenzo Bianconi 
378*e6cb3291SLorenzo Bianconi 	/* 1st: DFS_R37[31]: 0 (engine 0) - 1 (engine 2)
379*e6cb3291SLorenzo Bianconi 	 * 2nd: DFS_R37[21:0]: pulse time
380*e6cb3291SLorenzo Bianconi 	 * 3rd: DFS_R37[11:0]: pulse width
381*e6cb3291SLorenzo Bianconi 	 * 3rd: DFS_R37[25:16]: phase
382*e6cb3291SLorenzo Bianconi 	 * 4th: DFS_R37[12:0]: current pwr
383*e6cb3291SLorenzo Bianconi 	 * 4th: DFS_R37[21:16]: pwr stable counter
384*e6cb3291SLorenzo Bianconi 	 *
385*e6cb3291SLorenzo Bianconi 	 * 1st: DFS_R37[31:0] set to 0xffffffff means no event detected
386*e6cb3291SLorenzo Bianconi 	 */
387*e6cb3291SLorenzo Bianconi 	data = mt76_rr(dev, MT_BBP(DFS, 37));
388*e6cb3291SLorenzo Bianconi 	if (!MT_DFS_CHECK_EVENT(data))
389*e6cb3291SLorenzo Bianconi 		return false;
390*e6cb3291SLorenzo Bianconi 
391*e6cb3291SLorenzo Bianconi 	event->engine = MT_DFS_EVENT_ENGINE(data);
392*e6cb3291SLorenzo Bianconi 	data = mt76_rr(dev, MT_BBP(DFS, 37));
393*e6cb3291SLorenzo Bianconi 	event->ts = MT_DFS_EVENT_TIMESTAMP(data);
394*e6cb3291SLorenzo Bianconi 	data = mt76_rr(dev, MT_BBP(DFS, 37));
395*e6cb3291SLorenzo Bianconi 	event->width = MT_DFS_EVENT_WIDTH(data);
396*e6cb3291SLorenzo Bianconi 
397*e6cb3291SLorenzo Bianconi 	return true;
398*e6cb3291SLorenzo Bianconi }
399*e6cb3291SLorenzo Bianconi 
400*e6cb3291SLorenzo Bianconi static bool mt76x02_dfs_check_event(struct mt76x02_dev *dev,
401*e6cb3291SLorenzo Bianconi 				    struct mt76x02_dfs_event *event)
402*e6cb3291SLorenzo Bianconi {
403*e6cb3291SLorenzo Bianconi 	if (event->engine == 2) {
404*e6cb3291SLorenzo Bianconi 		struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
405*e6cb3291SLorenzo Bianconi 		struct mt76x02_dfs_event_rb *event_buff = &dfs_pd->event_rb[1];
406*e6cb3291SLorenzo Bianconi 		u16 last_event_idx;
407*e6cb3291SLorenzo Bianconi 		u32 delta_ts;
408*e6cb3291SLorenzo Bianconi 
409*e6cb3291SLorenzo Bianconi 		last_event_idx = mt76_decr(event_buff->t_rb,
410*e6cb3291SLorenzo Bianconi 					   MT_DFS_EVENT_BUFLEN);
411*e6cb3291SLorenzo Bianconi 		delta_ts = event->ts - event_buff->data[last_event_idx].ts;
412*e6cb3291SLorenzo Bianconi 		if (delta_ts < MT_DFS_EVENT_TIME_MARGIN &&
413*e6cb3291SLorenzo Bianconi 		    event_buff->data[last_event_idx].width >= 200)
414*e6cb3291SLorenzo Bianconi 			return false;
415*e6cb3291SLorenzo Bianconi 	}
416*e6cb3291SLorenzo Bianconi 	return true;
417*e6cb3291SLorenzo Bianconi }
418*e6cb3291SLorenzo Bianconi 
419*e6cb3291SLorenzo Bianconi static void mt76x02_dfs_queue_event(struct mt76x02_dev *dev,
420*e6cb3291SLorenzo Bianconi 				    struct mt76x02_dfs_event *event)
421*e6cb3291SLorenzo Bianconi {
422*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
423*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_event_rb *event_buff;
424*e6cb3291SLorenzo Bianconi 
425*e6cb3291SLorenzo Bianconi 	/* add radar event to ring buffer */
426*e6cb3291SLorenzo Bianconi 	event_buff = event->engine == 2 ? &dfs_pd->event_rb[1]
427*e6cb3291SLorenzo Bianconi 					: &dfs_pd->event_rb[0];
428*e6cb3291SLorenzo Bianconi 	event_buff->data[event_buff->t_rb] = *event;
429*e6cb3291SLorenzo Bianconi 	event_buff->data[event_buff->t_rb].fetch_ts = jiffies;
430*e6cb3291SLorenzo Bianconi 
431*e6cb3291SLorenzo Bianconi 	event_buff->t_rb = mt76_incr(event_buff->t_rb, MT_DFS_EVENT_BUFLEN);
432*e6cb3291SLorenzo Bianconi 	if (event_buff->t_rb == event_buff->h_rb)
433*e6cb3291SLorenzo Bianconi 		event_buff->h_rb = mt76_incr(event_buff->h_rb,
434*e6cb3291SLorenzo Bianconi 					     MT_DFS_EVENT_BUFLEN);
435*e6cb3291SLorenzo Bianconi }
436*e6cb3291SLorenzo Bianconi 
437*e6cb3291SLorenzo Bianconi static int mt76x02_dfs_create_sequence(struct mt76x02_dev *dev,
438*e6cb3291SLorenzo Bianconi 				       struct mt76x02_dfs_event *event,
439*e6cb3291SLorenzo Bianconi 				       u16 cur_len)
440*e6cb3291SLorenzo Bianconi {
441*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
442*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_sw_detector_params *sw_params;
443*e6cb3291SLorenzo Bianconi 	u32 width_delta, with_sum, factor, cur_pri;
444*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_sequence seq, *seq_p;
445*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_event_rb *event_rb;
446*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_event *cur_event;
447*e6cb3291SLorenzo Bianconi 	int i, j, end, pri;
448*e6cb3291SLorenzo Bianconi 
449*e6cb3291SLorenzo Bianconi 	event_rb = event->engine == 2 ? &dfs_pd->event_rb[1]
450*e6cb3291SLorenzo Bianconi 				      : &dfs_pd->event_rb[0];
451*e6cb3291SLorenzo Bianconi 
452*e6cb3291SLorenzo Bianconi 	i = mt76_decr(event_rb->t_rb, MT_DFS_EVENT_BUFLEN);
453*e6cb3291SLorenzo Bianconi 	end = mt76_decr(event_rb->h_rb, MT_DFS_EVENT_BUFLEN);
454*e6cb3291SLorenzo Bianconi 
455*e6cb3291SLorenzo Bianconi 	while (i != end) {
456*e6cb3291SLorenzo Bianconi 		cur_event = &event_rb->data[i];
457*e6cb3291SLorenzo Bianconi 		with_sum = event->width + cur_event->width;
458*e6cb3291SLorenzo Bianconi 
459*e6cb3291SLorenzo Bianconi 		sw_params = &dfs_pd->sw_dpd_params;
460*e6cb3291SLorenzo Bianconi 		switch (dev->dfs_pd.region) {
461*e6cb3291SLorenzo Bianconi 		case NL80211_DFS_FCC:
462*e6cb3291SLorenzo Bianconi 		case NL80211_DFS_JP:
463*e6cb3291SLorenzo Bianconi 			if (with_sum < 600)
464*e6cb3291SLorenzo Bianconi 				width_delta = 8;
465*e6cb3291SLorenzo Bianconi 			else
466*e6cb3291SLorenzo Bianconi 				width_delta = with_sum >> 3;
467*e6cb3291SLorenzo Bianconi 			break;
468*e6cb3291SLorenzo Bianconi 		case NL80211_DFS_ETSI:
469*e6cb3291SLorenzo Bianconi 			if (event->engine == 2)
470*e6cb3291SLorenzo Bianconi 				width_delta = with_sum >> 6;
471*e6cb3291SLorenzo Bianconi 			else if (with_sum < 620)
472*e6cb3291SLorenzo Bianconi 				width_delta = 24;
473*e6cb3291SLorenzo Bianconi 			else
474*e6cb3291SLorenzo Bianconi 				width_delta = 8;
475*e6cb3291SLorenzo Bianconi 			break;
476*e6cb3291SLorenzo Bianconi 		case NL80211_DFS_UNSET:
477*e6cb3291SLorenzo Bianconi 		default:
478*e6cb3291SLorenzo Bianconi 			return -EINVAL;
479*e6cb3291SLorenzo Bianconi 		}
480*e6cb3291SLorenzo Bianconi 
481*e6cb3291SLorenzo Bianconi 		pri = event->ts - cur_event->ts;
482*e6cb3291SLorenzo Bianconi 		if (abs(event->width - cur_event->width) > width_delta ||
483*e6cb3291SLorenzo Bianconi 		    pri < sw_params->min_pri)
484*e6cb3291SLorenzo Bianconi 			goto next;
485*e6cb3291SLorenzo Bianconi 
486*e6cb3291SLorenzo Bianconi 		if (pri > sw_params->max_pri)
487*e6cb3291SLorenzo Bianconi 			break;
488*e6cb3291SLorenzo Bianconi 
489*e6cb3291SLorenzo Bianconi 		seq.pri = event->ts - cur_event->ts;
490*e6cb3291SLorenzo Bianconi 		seq.first_ts = cur_event->ts;
491*e6cb3291SLorenzo Bianconi 		seq.last_ts = event->ts;
492*e6cb3291SLorenzo Bianconi 		seq.engine = event->engine;
493*e6cb3291SLorenzo Bianconi 		seq.count = 2;
494*e6cb3291SLorenzo Bianconi 
495*e6cb3291SLorenzo Bianconi 		j = mt76_decr(i, MT_DFS_EVENT_BUFLEN);
496*e6cb3291SLorenzo Bianconi 		while (j != end) {
497*e6cb3291SLorenzo Bianconi 			cur_event = &event_rb->data[j];
498*e6cb3291SLorenzo Bianconi 			cur_pri = event->ts - cur_event->ts;
499*e6cb3291SLorenzo Bianconi 			factor = mt76x02_dfs_get_multiple(cur_pri, seq.pri,
500*e6cb3291SLorenzo Bianconi 						sw_params->pri_margin);
501*e6cb3291SLorenzo Bianconi 			if (factor > 0) {
502*e6cb3291SLorenzo Bianconi 				seq.first_ts = cur_event->ts;
503*e6cb3291SLorenzo Bianconi 				seq.count++;
504*e6cb3291SLorenzo Bianconi 			}
505*e6cb3291SLorenzo Bianconi 
506*e6cb3291SLorenzo Bianconi 			j = mt76_decr(j, MT_DFS_EVENT_BUFLEN);
507*e6cb3291SLorenzo Bianconi 		}
508*e6cb3291SLorenzo Bianconi 		if (seq.count <= cur_len)
509*e6cb3291SLorenzo Bianconi 			goto next;
510*e6cb3291SLorenzo Bianconi 
511*e6cb3291SLorenzo Bianconi 		seq_p = mt76x02_dfs_seq_pool_get(dev);
512*e6cb3291SLorenzo Bianconi 		if (!seq_p)
513*e6cb3291SLorenzo Bianconi 			return -ENOMEM;
514*e6cb3291SLorenzo Bianconi 
515*e6cb3291SLorenzo Bianconi 		*seq_p = seq;
516*e6cb3291SLorenzo Bianconi 		INIT_LIST_HEAD(&seq_p->head);
517*e6cb3291SLorenzo Bianconi 		list_add(&seq_p->head, &dfs_pd->sequences);
518*e6cb3291SLorenzo Bianconi next:
519*e6cb3291SLorenzo Bianconi 		i = mt76_decr(i, MT_DFS_EVENT_BUFLEN);
520*e6cb3291SLorenzo Bianconi 	}
521*e6cb3291SLorenzo Bianconi 	return 0;
522*e6cb3291SLorenzo Bianconi }
523*e6cb3291SLorenzo Bianconi 
524*e6cb3291SLorenzo Bianconi static u16 mt76x02_dfs_add_event_to_sequence(struct mt76x02_dev *dev,
525*e6cb3291SLorenzo Bianconi 					     struct mt76x02_dfs_event *event)
526*e6cb3291SLorenzo Bianconi {
527*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
528*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_sw_detector_params *sw_params;
529*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_sequence *seq, *tmp_seq;
530*e6cb3291SLorenzo Bianconi 	u16 max_seq_len = 0;
531*e6cb3291SLorenzo Bianconi 	u32 factor, pri;
532*e6cb3291SLorenzo Bianconi 
533*e6cb3291SLorenzo Bianconi 	sw_params = &dfs_pd->sw_dpd_params;
534*e6cb3291SLorenzo Bianconi 	list_for_each_entry_safe(seq, tmp_seq, &dfs_pd->sequences, head) {
535*e6cb3291SLorenzo Bianconi 		if (event->ts > seq->first_ts + MT_DFS_SEQUENCE_WINDOW) {
536*e6cb3291SLorenzo Bianconi 			list_del_init(&seq->head);
537*e6cb3291SLorenzo Bianconi 			mt76x02_dfs_seq_pool_put(dev, seq);
538*e6cb3291SLorenzo Bianconi 			continue;
539*e6cb3291SLorenzo Bianconi 		}
540*e6cb3291SLorenzo Bianconi 
541*e6cb3291SLorenzo Bianconi 		if (event->engine != seq->engine)
542*e6cb3291SLorenzo Bianconi 			continue;
543*e6cb3291SLorenzo Bianconi 
544*e6cb3291SLorenzo Bianconi 		pri = event->ts - seq->last_ts;
545*e6cb3291SLorenzo Bianconi 		factor = mt76x02_dfs_get_multiple(pri, seq->pri,
546*e6cb3291SLorenzo Bianconi 						  sw_params->pri_margin);
547*e6cb3291SLorenzo Bianconi 		if (factor > 0) {
548*e6cb3291SLorenzo Bianconi 			seq->last_ts = event->ts;
549*e6cb3291SLorenzo Bianconi 			seq->count++;
550*e6cb3291SLorenzo Bianconi 			max_seq_len = max_t(u16, max_seq_len, seq->count);
551*e6cb3291SLorenzo Bianconi 		}
552*e6cb3291SLorenzo Bianconi 	}
553*e6cb3291SLorenzo Bianconi 	return max_seq_len;
554*e6cb3291SLorenzo Bianconi }
555*e6cb3291SLorenzo Bianconi 
556*e6cb3291SLorenzo Bianconi static bool mt76x02_dfs_check_detection(struct mt76x02_dev *dev)
557*e6cb3291SLorenzo Bianconi {
558*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
559*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_sequence *seq;
560*e6cb3291SLorenzo Bianconi 
561*e6cb3291SLorenzo Bianconi 	if (list_empty(&dfs_pd->sequences))
562*e6cb3291SLorenzo Bianconi 		return false;
563*e6cb3291SLorenzo Bianconi 
564*e6cb3291SLorenzo Bianconi 	list_for_each_entry(seq, &dfs_pd->sequences, head) {
565*e6cb3291SLorenzo Bianconi 		if (seq->count > MT_DFS_SEQUENCE_TH) {
566*e6cb3291SLorenzo Bianconi 			dfs_pd->stats[seq->engine].sw_pattern++;
567*e6cb3291SLorenzo Bianconi 			return true;
568*e6cb3291SLorenzo Bianconi 		}
569*e6cb3291SLorenzo Bianconi 	}
570*e6cb3291SLorenzo Bianconi 	return false;
571*e6cb3291SLorenzo Bianconi }
572*e6cb3291SLorenzo Bianconi 
573*e6cb3291SLorenzo Bianconi static void mt76x02_dfs_add_events(struct mt76x02_dev *dev)
574*e6cb3291SLorenzo Bianconi {
575*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
576*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_event event;
577*e6cb3291SLorenzo Bianconi 	int i, seq_len;
578*e6cb3291SLorenzo Bianconi 
579*e6cb3291SLorenzo Bianconi 	/* disable debug mode */
580*e6cb3291SLorenzo Bianconi 	mt76x02_dfs_set_capture_mode_ctrl(dev, false);
581*e6cb3291SLorenzo Bianconi 	for (i = 0; i < MT_DFS_EVENT_LOOP; i++) {
582*e6cb3291SLorenzo Bianconi 		if (!mt76x02_dfs_fetch_event(dev, &event))
583*e6cb3291SLorenzo Bianconi 			break;
584*e6cb3291SLorenzo Bianconi 
585*e6cb3291SLorenzo Bianconi 		if (dfs_pd->last_event_ts > event.ts)
586*e6cb3291SLorenzo Bianconi 			mt76x02_dfs_detector_reset(dev);
587*e6cb3291SLorenzo Bianconi 		dfs_pd->last_event_ts = event.ts;
588*e6cb3291SLorenzo Bianconi 
589*e6cb3291SLorenzo Bianconi 		if (!mt76x02_dfs_check_event(dev, &event))
590*e6cb3291SLorenzo Bianconi 			continue;
591*e6cb3291SLorenzo Bianconi 
592*e6cb3291SLorenzo Bianconi 		seq_len = mt76x02_dfs_add_event_to_sequence(dev, &event);
593*e6cb3291SLorenzo Bianconi 		mt76x02_dfs_create_sequence(dev, &event, seq_len);
594*e6cb3291SLorenzo Bianconi 
595*e6cb3291SLorenzo Bianconi 		mt76x02_dfs_queue_event(dev, &event);
596*e6cb3291SLorenzo Bianconi 	}
597*e6cb3291SLorenzo Bianconi 	mt76x02_dfs_set_capture_mode_ctrl(dev, true);
598*e6cb3291SLorenzo Bianconi }
599*e6cb3291SLorenzo Bianconi 
600*e6cb3291SLorenzo Bianconi static void mt76x02_dfs_check_event_window(struct mt76x02_dev *dev)
601*e6cb3291SLorenzo Bianconi {
602*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
603*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_event_rb *event_buff;
604*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_event *event;
605*e6cb3291SLorenzo Bianconi 	int i;
606*e6cb3291SLorenzo Bianconi 
607*e6cb3291SLorenzo Bianconi 	for (i = 0; i < ARRAY_SIZE(dfs_pd->event_rb); i++) {
608*e6cb3291SLorenzo Bianconi 		event_buff = &dfs_pd->event_rb[i];
609*e6cb3291SLorenzo Bianconi 
610*e6cb3291SLorenzo Bianconi 		while (event_buff->h_rb != event_buff->t_rb) {
611*e6cb3291SLorenzo Bianconi 			event = &event_buff->data[event_buff->h_rb];
612*e6cb3291SLorenzo Bianconi 
613*e6cb3291SLorenzo Bianconi 			/* sorted list */
614*e6cb3291SLorenzo Bianconi 			if (time_is_after_jiffies(event->fetch_ts +
615*e6cb3291SLorenzo Bianconi 						  MT_DFS_EVENT_WINDOW))
616*e6cb3291SLorenzo Bianconi 				break;
617*e6cb3291SLorenzo Bianconi 			event_buff->h_rb = mt76_incr(event_buff->h_rb,
618*e6cb3291SLorenzo Bianconi 						     MT_DFS_EVENT_BUFLEN);
619*e6cb3291SLorenzo Bianconi 		}
620*e6cb3291SLorenzo Bianconi 	}
621*e6cb3291SLorenzo Bianconi }
622*e6cb3291SLorenzo Bianconi 
623*e6cb3291SLorenzo Bianconi static void mt76x02_dfs_tasklet(unsigned long arg)
624*e6cb3291SLorenzo Bianconi {
625*e6cb3291SLorenzo Bianconi 	struct mt76x02_dev *dev = (struct mt76x02_dev *)arg;
626*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
627*e6cb3291SLorenzo Bianconi 	u32 engine_mask;
628*e6cb3291SLorenzo Bianconi 	int i;
629*e6cb3291SLorenzo Bianconi 
630*e6cb3291SLorenzo Bianconi 	if (test_bit(MT76_SCANNING, &dev->mt76.state))
631*e6cb3291SLorenzo Bianconi 		goto out;
632*e6cb3291SLorenzo Bianconi 
633*e6cb3291SLorenzo Bianconi 	if (time_is_before_jiffies(dfs_pd->last_sw_check +
634*e6cb3291SLorenzo Bianconi 				   MT_DFS_SW_TIMEOUT)) {
635*e6cb3291SLorenzo Bianconi 		bool radar_detected;
636*e6cb3291SLorenzo Bianconi 
637*e6cb3291SLorenzo Bianconi 		dfs_pd->last_sw_check = jiffies;
638*e6cb3291SLorenzo Bianconi 
639*e6cb3291SLorenzo Bianconi 		mt76x02_dfs_add_events(dev);
640*e6cb3291SLorenzo Bianconi 		radar_detected = mt76x02_dfs_check_detection(dev);
641*e6cb3291SLorenzo Bianconi 		if (radar_detected) {
642*e6cb3291SLorenzo Bianconi 			/* sw detector rx radar pattern */
643*e6cb3291SLorenzo Bianconi 			ieee80211_radar_detected(dev->mt76.hw);
644*e6cb3291SLorenzo Bianconi 			mt76x02_dfs_detector_reset(dev);
645*e6cb3291SLorenzo Bianconi 
646*e6cb3291SLorenzo Bianconi 			return;
647*e6cb3291SLorenzo Bianconi 		}
648*e6cb3291SLorenzo Bianconi 		mt76x02_dfs_check_event_window(dev);
649*e6cb3291SLorenzo Bianconi 	}
650*e6cb3291SLorenzo Bianconi 
651*e6cb3291SLorenzo Bianconi 	engine_mask = mt76_rr(dev, MT_BBP(DFS, 1));
652*e6cb3291SLorenzo Bianconi 	if (!(engine_mask & 0xf))
653*e6cb3291SLorenzo Bianconi 		goto out;
654*e6cb3291SLorenzo Bianconi 
655*e6cb3291SLorenzo Bianconi 	for (i = 0; i < MT_DFS_NUM_ENGINES; i++) {
656*e6cb3291SLorenzo Bianconi 		struct mt76x02_dfs_hw_pulse pulse;
657*e6cb3291SLorenzo Bianconi 
658*e6cb3291SLorenzo Bianconi 		if (!(engine_mask & (1 << i)))
659*e6cb3291SLorenzo Bianconi 			continue;
660*e6cb3291SLorenzo Bianconi 
661*e6cb3291SLorenzo Bianconi 		pulse.engine = i;
662*e6cb3291SLorenzo Bianconi 		mt76x02_dfs_get_hw_pulse(dev, &pulse);
663*e6cb3291SLorenzo Bianconi 
664*e6cb3291SLorenzo Bianconi 		if (!mt76x02_dfs_check_hw_pulse(dev, &pulse)) {
665*e6cb3291SLorenzo Bianconi 			dfs_pd->stats[i].hw_pulse_discarded++;
666*e6cb3291SLorenzo Bianconi 			continue;
667*e6cb3291SLorenzo Bianconi 		}
668*e6cb3291SLorenzo Bianconi 
669*e6cb3291SLorenzo Bianconi 		/* hw detector rx radar pattern */
670*e6cb3291SLorenzo Bianconi 		dfs_pd->stats[i].hw_pattern++;
671*e6cb3291SLorenzo Bianconi 		ieee80211_radar_detected(dev->mt76.hw);
672*e6cb3291SLorenzo Bianconi 		mt76x02_dfs_detector_reset(dev);
673*e6cb3291SLorenzo Bianconi 
674*e6cb3291SLorenzo Bianconi 		return;
675*e6cb3291SLorenzo Bianconi 	}
676*e6cb3291SLorenzo Bianconi 
677*e6cb3291SLorenzo Bianconi 	/* reset hw detector */
678*e6cb3291SLorenzo Bianconi 	mt76_wr(dev, MT_BBP(DFS, 1), 0xf);
679*e6cb3291SLorenzo Bianconi 
680*e6cb3291SLorenzo Bianconi out:
681*e6cb3291SLorenzo Bianconi 	mt76x02_irq_enable(dev, MT_INT_GPTIMER);
682*e6cb3291SLorenzo Bianconi }
683*e6cb3291SLorenzo Bianconi 
684*e6cb3291SLorenzo Bianconi static void mt76x02_dfs_init_sw_detector(struct mt76x02_dev *dev)
685*e6cb3291SLorenzo Bianconi {
686*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
687*e6cb3291SLorenzo Bianconi 
688*e6cb3291SLorenzo Bianconi 	switch (dev->dfs_pd.region) {
689*e6cb3291SLorenzo Bianconi 	case NL80211_DFS_FCC:
690*e6cb3291SLorenzo Bianconi 		dfs_pd->sw_dpd_params.max_pri = MT_DFS_FCC_MAX_PRI;
691*e6cb3291SLorenzo Bianconi 		dfs_pd->sw_dpd_params.min_pri = MT_DFS_FCC_MIN_PRI;
692*e6cb3291SLorenzo Bianconi 		dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN;
693*e6cb3291SLorenzo Bianconi 		break;
694*e6cb3291SLorenzo Bianconi 	case NL80211_DFS_ETSI:
695*e6cb3291SLorenzo Bianconi 		dfs_pd->sw_dpd_params.max_pri = MT_DFS_ETSI_MAX_PRI;
696*e6cb3291SLorenzo Bianconi 		dfs_pd->sw_dpd_params.min_pri = MT_DFS_ETSI_MIN_PRI;
697*e6cb3291SLorenzo Bianconi 		dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN << 2;
698*e6cb3291SLorenzo Bianconi 		break;
699*e6cb3291SLorenzo Bianconi 	case NL80211_DFS_JP:
700*e6cb3291SLorenzo Bianconi 		dfs_pd->sw_dpd_params.max_pri = MT_DFS_JP_MAX_PRI;
701*e6cb3291SLorenzo Bianconi 		dfs_pd->sw_dpd_params.min_pri = MT_DFS_JP_MIN_PRI;
702*e6cb3291SLorenzo Bianconi 		dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN;
703*e6cb3291SLorenzo Bianconi 		break;
704*e6cb3291SLorenzo Bianconi 	case NL80211_DFS_UNSET:
705*e6cb3291SLorenzo Bianconi 	default:
706*e6cb3291SLorenzo Bianconi 		break;
707*e6cb3291SLorenzo Bianconi 	}
708*e6cb3291SLorenzo Bianconi }
709*e6cb3291SLorenzo Bianconi 
710*e6cb3291SLorenzo Bianconi static void mt76x02_dfs_set_bbp_params(struct mt76x02_dev *dev)
711*e6cb3291SLorenzo Bianconi {
712*e6cb3291SLorenzo Bianconi 	const struct mt76x02_radar_specs *radar_specs;
713*e6cb3291SLorenzo Bianconi 	u8 i, shift;
714*e6cb3291SLorenzo Bianconi 	u32 data;
715*e6cb3291SLorenzo Bianconi 
716*e6cb3291SLorenzo Bianconi 	switch (dev->mt76.chandef.width) {
717*e6cb3291SLorenzo Bianconi 	case NL80211_CHAN_WIDTH_40:
718*e6cb3291SLorenzo Bianconi 		shift = MT_DFS_NUM_ENGINES;
719*e6cb3291SLorenzo Bianconi 		break;
720*e6cb3291SLorenzo Bianconi 	case NL80211_CHAN_WIDTH_80:
721*e6cb3291SLorenzo Bianconi 		shift = 2 * MT_DFS_NUM_ENGINES;
722*e6cb3291SLorenzo Bianconi 		break;
723*e6cb3291SLorenzo Bianconi 	default:
724*e6cb3291SLorenzo Bianconi 		shift = 0;
725*e6cb3291SLorenzo Bianconi 		break;
726*e6cb3291SLorenzo Bianconi 	}
727*e6cb3291SLorenzo Bianconi 
728*e6cb3291SLorenzo Bianconi 	switch (dev->dfs_pd.region) {
729*e6cb3291SLorenzo Bianconi 	case NL80211_DFS_FCC:
730*e6cb3291SLorenzo Bianconi 		radar_specs = &fcc_radar_specs[shift];
731*e6cb3291SLorenzo Bianconi 		break;
732*e6cb3291SLorenzo Bianconi 	case NL80211_DFS_ETSI:
733*e6cb3291SLorenzo Bianconi 		radar_specs = &etsi_radar_specs[shift];
734*e6cb3291SLorenzo Bianconi 		break;
735*e6cb3291SLorenzo Bianconi 	case NL80211_DFS_JP:
736*e6cb3291SLorenzo Bianconi 		if (dev->mt76.chandef.chan->center_freq >= 5250 &&
737*e6cb3291SLorenzo Bianconi 		    dev->mt76.chandef.chan->center_freq <= 5350)
738*e6cb3291SLorenzo Bianconi 			radar_specs = &jp_w53_radar_specs[shift];
739*e6cb3291SLorenzo Bianconi 		else
740*e6cb3291SLorenzo Bianconi 			radar_specs = &jp_w56_radar_specs[shift];
741*e6cb3291SLorenzo Bianconi 		break;
742*e6cb3291SLorenzo Bianconi 	case NL80211_DFS_UNSET:
743*e6cb3291SLorenzo Bianconi 	default:
744*e6cb3291SLorenzo Bianconi 		return;
745*e6cb3291SLorenzo Bianconi 	}
746*e6cb3291SLorenzo Bianconi 
747*e6cb3291SLorenzo Bianconi 	data = (MT_DFS_VGA_MASK << 16) |
748*e6cb3291SLorenzo Bianconi 	       (MT_DFS_PWR_GAIN_OFFSET << 12) |
749*e6cb3291SLorenzo Bianconi 	       (MT_DFS_PWR_DOWN_TIME << 8) |
750*e6cb3291SLorenzo Bianconi 	       (MT_DFS_SYM_ROUND << 4) |
751*e6cb3291SLorenzo Bianconi 	       (MT_DFS_DELTA_DELAY & 0xf);
752*e6cb3291SLorenzo Bianconi 	mt76_wr(dev, MT_BBP(DFS, 2), data);
753*e6cb3291SLorenzo Bianconi 
754*e6cb3291SLorenzo Bianconi 	data = (MT_DFS_RX_PE_MASK << 16) | MT_DFS_PKT_END_MASK;
755*e6cb3291SLorenzo Bianconi 	mt76_wr(dev, MT_BBP(DFS, 3), data);
756*e6cb3291SLorenzo Bianconi 
757*e6cb3291SLorenzo Bianconi 	for (i = 0; i < MT_DFS_NUM_ENGINES; i++) {
758*e6cb3291SLorenzo Bianconi 		/* configure engine */
759*e6cb3291SLorenzo Bianconi 		mt76_wr(dev, MT_BBP(DFS, 0), i);
760*e6cb3291SLorenzo Bianconi 
761*e6cb3291SLorenzo Bianconi 		/* detection mode + avg_len */
762*e6cb3291SLorenzo Bianconi 		data = ((radar_specs[i].avg_len & 0x1ff) << 16) |
763*e6cb3291SLorenzo Bianconi 		       (radar_specs[i].mode & 0xf);
764*e6cb3291SLorenzo Bianconi 		mt76_wr(dev, MT_BBP(DFS, 4), data);
765*e6cb3291SLorenzo Bianconi 
766*e6cb3291SLorenzo Bianconi 		/* dfs energy */
767*e6cb3291SLorenzo Bianconi 		data = ((radar_specs[i].e_high & 0x0fff) << 16) |
768*e6cb3291SLorenzo Bianconi 		       (radar_specs[i].e_low & 0x0fff);
769*e6cb3291SLorenzo Bianconi 		mt76_wr(dev, MT_BBP(DFS, 5), data);
770*e6cb3291SLorenzo Bianconi 
771*e6cb3291SLorenzo Bianconi 		/* dfs period */
772*e6cb3291SLorenzo Bianconi 		mt76_wr(dev, MT_BBP(DFS, 7), radar_specs[i].t_low);
773*e6cb3291SLorenzo Bianconi 		mt76_wr(dev, MT_BBP(DFS, 9), radar_specs[i].t_high);
774*e6cb3291SLorenzo Bianconi 
775*e6cb3291SLorenzo Bianconi 		/* dfs burst */
776*e6cb3291SLorenzo Bianconi 		mt76_wr(dev, MT_BBP(DFS, 11), radar_specs[i].b_low);
777*e6cb3291SLorenzo Bianconi 		mt76_wr(dev, MT_BBP(DFS, 13), radar_specs[i].b_high);
778*e6cb3291SLorenzo Bianconi 
779*e6cb3291SLorenzo Bianconi 		/* dfs width */
780*e6cb3291SLorenzo Bianconi 		data = ((radar_specs[i].w_high & 0x0fff) << 16) |
781*e6cb3291SLorenzo Bianconi 		       (radar_specs[i].w_low & 0x0fff);
782*e6cb3291SLorenzo Bianconi 		mt76_wr(dev, MT_BBP(DFS, 14), data);
783*e6cb3291SLorenzo Bianconi 
784*e6cb3291SLorenzo Bianconi 		/* dfs margins */
785*e6cb3291SLorenzo Bianconi 		data = (radar_specs[i].w_margin << 16) |
786*e6cb3291SLorenzo Bianconi 		       radar_specs[i].t_margin;
787*e6cb3291SLorenzo Bianconi 		mt76_wr(dev, MT_BBP(DFS, 15), data);
788*e6cb3291SLorenzo Bianconi 
789*e6cb3291SLorenzo Bianconi 		/* dfs event expiration */
790*e6cb3291SLorenzo Bianconi 		mt76_wr(dev, MT_BBP(DFS, 17), radar_specs[i].event_expiration);
791*e6cb3291SLorenzo Bianconi 
792*e6cb3291SLorenzo Bianconi 		/* dfs pwr adj */
793*e6cb3291SLorenzo Bianconi 		mt76_wr(dev, MT_BBP(DFS, 30), radar_specs[i].pwr_jmp);
794*e6cb3291SLorenzo Bianconi 	}
795*e6cb3291SLorenzo Bianconi 
796*e6cb3291SLorenzo Bianconi 	/* reset status */
797*e6cb3291SLorenzo Bianconi 	mt76_wr(dev, MT_BBP(DFS, 1), 0xf);
798*e6cb3291SLorenzo Bianconi 	mt76_wr(dev, MT_BBP(DFS, 36), 0x3);
799*e6cb3291SLorenzo Bianconi 
800*e6cb3291SLorenzo Bianconi 	/* enable detection*/
801*e6cb3291SLorenzo Bianconi 	mt76_wr(dev, MT_BBP(DFS, 0), MT_DFS_CH_EN << 16);
802*e6cb3291SLorenzo Bianconi 	mt76_wr(dev, 0x212c, 0x0c350001);
803*e6cb3291SLorenzo Bianconi }
804*e6cb3291SLorenzo Bianconi 
805*e6cb3291SLorenzo Bianconi void mt76x02_dfs_init_params(struct mt76x02_dev *dev)
806*e6cb3291SLorenzo Bianconi {
807*e6cb3291SLorenzo Bianconi 	struct cfg80211_chan_def *chandef = &dev->mt76.chandef;
808*e6cb3291SLorenzo Bianconi 
809*e6cb3291SLorenzo Bianconi 	if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) &&
810*e6cb3291SLorenzo Bianconi 	    dev->dfs_pd.region != NL80211_DFS_UNSET) {
811*e6cb3291SLorenzo Bianconi 		mt76x02_dfs_init_sw_detector(dev);
812*e6cb3291SLorenzo Bianconi 		mt76x02_dfs_set_bbp_params(dev);
813*e6cb3291SLorenzo Bianconi 		/* enable debug mode */
814*e6cb3291SLorenzo Bianconi 		mt76x02_dfs_set_capture_mode_ctrl(dev, true);
815*e6cb3291SLorenzo Bianconi 
816*e6cb3291SLorenzo Bianconi 		mt76x02_irq_enable(dev, MT_INT_GPTIMER);
817*e6cb3291SLorenzo Bianconi 		mt76_rmw_field(dev, MT_INT_TIMER_EN,
818*e6cb3291SLorenzo Bianconi 			       MT_INT_TIMER_EN_GP_TIMER_EN, 1);
819*e6cb3291SLorenzo Bianconi 	} else {
820*e6cb3291SLorenzo Bianconi 		/* disable hw detector */
821*e6cb3291SLorenzo Bianconi 		mt76_wr(dev, MT_BBP(DFS, 0), 0);
822*e6cb3291SLorenzo Bianconi 		/* clear detector status */
823*e6cb3291SLorenzo Bianconi 		mt76_wr(dev, MT_BBP(DFS, 1), 0xf);
824*e6cb3291SLorenzo Bianconi 		mt76_wr(dev, 0x212c, 0);
825*e6cb3291SLorenzo Bianconi 
826*e6cb3291SLorenzo Bianconi 		mt76x02_irq_disable(dev, MT_INT_GPTIMER);
827*e6cb3291SLorenzo Bianconi 		mt76_rmw_field(dev, MT_INT_TIMER_EN,
828*e6cb3291SLorenzo Bianconi 			       MT_INT_TIMER_EN_GP_TIMER_EN, 0);
829*e6cb3291SLorenzo Bianconi 	}
830*e6cb3291SLorenzo Bianconi }
831*e6cb3291SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x02_dfs_init_params);
832*e6cb3291SLorenzo Bianconi 
833*e6cb3291SLorenzo Bianconi void mt76x02_dfs_init_detector(struct mt76x02_dev *dev)
834*e6cb3291SLorenzo Bianconi {
835*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
836*e6cb3291SLorenzo Bianconi 
837*e6cb3291SLorenzo Bianconi 	INIT_LIST_HEAD(&dfs_pd->sequences);
838*e6cb3291SLorenzo Bianconi 	INIT_LIST_HEAD(&dfs_pd->seq_pool);
839*e6cb3291SLorenzo Bianconi 	dfs_pd->region = NL80211_DFS_UNSET;
840*e6cb3291SLorenzo Bianconi 	dfs_pd->last_sw_check = jiffies;
841*e6cb3291SLorenzo Bianconi 	tasklet_init(&dfs_pd->dfs_tasklet, mt76x02_dfs_tasklet,
842*e6cb3291SLorenzo Bianconi 		     (unsigned long)dev);
843*e6cb3291SLorenzo Bianconi }
844*e6cb3291SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x02_dfs_init_detector);
845*e6cb3291SLorenzo Bianconi 
846*e6cb3291SLorenzo Bianconi static void
847*e6cb3291SLorenzo Bianconi mt76x02_dfs_set_domain(struct mt76x02_dev *dev,
848*e6cb3291SLorenzo Bianconi 		       enum nl80211_dfs_regions region)
849*e6cb3291SLorenzo Bianconi {
850*e6cb3291SLorenzo Bianconi 	struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
851*e6cb3291SLorenzo Bianconi 
852*e6cb3291SLorenzo Bianconi 	if (dfs_pd->region != region) {
853*e6cb3291SLorenzo Bianconi 		tasklet_disable(&dfs_pd->dfs_tasklet);
854*e6cb3291SLorenzo Bianconi 		dfs_pd->region = region;
855*e6cb3291SLorenzo Bianconi 		mt76x02_dfs_init_params(dev);
856*e6cb3291SLorenzo Bianconi 		tasklet_enable(&dfs_pd->dfs_tasklet);
857*e6cb3291SLorenzo Bianconi 	}
858*e6cb3291SLorenzo Bianconi }
859*e6cb3291SLorenzo Bianconi 
860*e6cb3291SLorenzo Bianconi void mt76x02_regd_notifier(struct wiphy *wiphy,
861*e6cb3291SLorenzo Bianconi 			   struct regulatory_request *request)
862*e6cb3291SLorenzo Bianconi {
863*e6cb3291SLorenzo Bianconi 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
864*e6cb3291SLorenzo Bianconi 	struct mt76x02_dev *dev = hw->priv;
865*e6cb3291SLorenzo Bianconi 
866*e6cb3291SLorenzo Bianconi 	mt76x02_dfs_set_domain(dev, request->dfs_region);
867*e6cb3291SLorenzo Bianconi }
868*e6cb3291SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x02_regd_notifier);
869