10e3d6777SRyder Lee // SPDX-License-Identifier: ISC
27bc04215SFelix Fietkau /*
37bc04215SFelix Fietkau * Copyright (C) 2016 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
47bc04215SFelix Fietkau */
57bc04215SFelix Fietkau
6e6cb3291SLorenzo Bianconi #include "mt76x02.h"
77bc04215SFelix Fietkau
87bc04215SFelix Fietkau #define RADAR_SPEC(m, len, el, eh, wl, wh, \
97bc04215SFelix Fietkau w_tolerance, tl, th, t_tolerance, \
107bc04215SFelix Fietkau bl, bh, event_exp, power_jmp) \
117bc04215SFelix Fietkau { \
127bc04215SFelix Fietkau .mode = m, \
137bc04215SFelix Fietkau .avg_len = len, \
147bc04215SFelix Fietkau .e_low = el, \
157bc04215SFelix Fietkau .e_high = eh, \
167bc04215SFelix Fietkau .w_low = wl, \
177bc04215SFelix Fietkau .w_high = wh, \
187bc04215SFelix Fietkau .w_margin = w_tolerance, \
197bc04215SFelix Fietkau .t_low = tl, \
207bc04215SFelix Fietkau .t_high = th, \
217bc04215SFelix Fietkau .t_margin = t_tolerance, \
227bc04215SFelix Fietkau .b_low = bl, \
237bc04215SFelix Fietkau .b_high = bh, \
247bc04215SFelix Fietkau .event_expiration = event_exp, \
257bc04215SFelix Fietkau .pwr_jmp = power_jmp \
267bc04215SFelix Fietkau }
277bc04215SFelix Fietkau
28e40803f2SLorenzo Bianconi static const struct mt76x02_radar_specs etsi_radar_specs[] = {
297bc04215SFelix Fietkau /* 20MHz */
307bc04215SFelix Fietkau RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0,
317bc04215SFelix Fietkau 0x7fffffff, 0x155cc0, 0x19cc),
327bc04215SFelix Fietkau RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0,
337bc04215SFelix Fietkau 0x7fffffff, 0x155cc0, 0x19cc),
347bc04215SFelix Fietkau RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0,
357bc04215SFelix Fietkau 0x7fffffff, 0x155cc0, 0x19dd),
367bc04215SFelix Fietkau RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0,
377bc04215SFelix Fietkau 0x7fffffff, 0x2191c0, 0x15cc),
387bc04215SFelix Fietkau /* 40MHz */
397bc04215SFelix Fietkau RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0,
407bc04215SFelix Fietkau 0x7fffffff, 0x155cc0, 0x19cc),
417bc04215SFelix Fietkau RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0,
427bc04215SFelix Fietkau 0x7fffffff, 0x155cc0, 0x19cc),
437bc04215SFelix Fietkau RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0,
447bc04215SFelix Fietkau 0x7fffffff, 0x155cc0, 0x19dd),
457bc04215SFelix Fietkau RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0,
467bc04215SFelix Fietkau 0x7fffffff, 0x2191c0, 0x15cc),
477bc04215SFelix Fietkau /* 80MHz */
487bc04215SFelix Fietkau RADAR_SPEC(0, 8, 2, 15, 106, 150, 10, 4900, 100096, 10, 0,
497bc04215SFelix Fietkau 0x7fffffff, 0x155cc0, 0x19cc),
507bc04215SFelix Fietkau RADAR_SPEC(0, 40, 4, 59, 96, 380, 150, 4900, 100096, 40, 0,
517bc04215SFelix Fietkau 0x7fffffff, 0x155cc0, 0x19cc),
527bc04215SFelix Fietkau RADAR_SPEC(3, 60, 20, 46, 300, 640, 80, 4900, 10100, 80, 0,
537bc04215SFelix Fietkau 0x7fffffff, 0x155cc0, 0x19dd),
547bc04215SFelix Fietkau RADAR_SPEC(8, 8, 2, 9, 106, 150, 32, 4900, 296704, 32, 0,
557bc04215SFelix Fietkau 0x7fffffff, 0x2191c0, 0x15cc)
567bc04215SFelix Fietkau };
577bc04215SFelix Fietkau
58e40803f2SLorenzo Bianconi static const struct mt76x02_radar_specs fcc_radar_specs[] = {
597bc04215SFelix Fietkau /* 20MHz */
607bc04215SFelix Fietkau RADAR_SPEC(0, 8, 2, 12, 106, 150, 5, 2900, 80100, 5, 0,
617bc04215SFelix Fietkau 0x7fffffff, 0xfe808, 0x13dc),
627bc04215SFelix Fietkau RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
637bc04215SFelix Fietkau 0x7fffffff, 0xfe808, 0x19dd),
647bc04215SFelix Fietkau RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0,
657bc04215SFelix Fietkau 0x7fffffff, 0xfe808, 0x12cc),
667bc04215SFelix Fietkau RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0,
677bc04215SFelix Fietkau 0x3938700, 0x57bcf00, 0x1289),
687bc04215SFelix Fietkau /* 40MHz */
697bc04215SFelix Fietkau RADAR_SPEC(0, 8, 2, 12, 106, 150, 5, 2900, 80100, 5, 0,
707bc04215SFelix Fietkau 0x7fffffff, 0xfe808, 0x13dc),
717bc04215SFelix Fietkau RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
727bc04215SFelix Fietkau 0x7fffffff, 0xfe808, 0x19dd),
737bc04215SFelix Fietkau RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0,
747bc04215SFelix Fietkau 0x7fffffff, 0xfe808, 0x12cc),
757bc04215SFelix Fietkau RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0,
767bc04215SFelix Fietkau 0x3938700, 0x57bcf00, 0x1289),
777bc04215SFelix Fietkau /* 80MHz */
787bc04215SFelix Fietkau RADAR_SPEC(0, 8, 2, 14, 106, 150, 15, 2900, 80100, 15, 0,
797bc04215SFelix Fietkau 0x7fffffff, 0xfe808, 0x16cc),
807bc04215SFelix Fietkau RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
817bc04215SFelix Fietkau 0x7fffffff, 0xfe808, 0x19dd),
827bc04215SFelix Fietkau RADAR_SPEC(0, 40, 4, 54, 96, 480, 150, 2900, 80100, 40, 0,
837bc04215SFelix Fietkau 0x7fffffff, 0xfe808, 0x12cc),
847bc04215SFelix Fietkau RADAR_SPEC(2, 60, 15, 63, 640, 2080, 32, 19600, 40200, 32, 0,
857bc04215SFelix Fietkau 0x3938700, 0x57bcf00, 0x1289)
867bc04215SFelix Fietkau };
877bc04215SFelix Fietkau
88e40803f2SLorenzo Bianconi static const struct mt76x02_radar_specs jp_w56_radar_specs[] = {
897bc04215SFelix Fietkau /* 20MHz */
907bc04215SFelix Fietkau RADAR_SPEC(0, 8, 2, 7, 106, 150, 5, 2900, 80100, 5, 0,
917bc04215SFelix Fietkau 0x7fffffff, 0x14c080, 0x13dc),
927bc04215SFelix Fietkau RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
937bc04215SFelix Fietkau 0x7fffffff, 0x14c080, 0x19dd),
947bc04215SFelix Fietkau RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0,
957bc04215SFelix Fietkau 0x7fffffff, 0x14c080, 0x12cc),
967bc04215SFelix Fietkau RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0,
977bc04215SFelix Fietkau 0x3938700, 0X57bcf00, 0x1289),
987bc04215SFelix Fietkau /* 40MHz */
997bc04215SFelix Fietkau RADAR_SPEC(0, 8, 2, 7, 106, 150, 5, 2900, 80100, 5, 0,
1007bc04215SFelix Fietkau 0x7fffffff, 0x14c080, 0x13dc),
1017bc04215SFelix Fietkau RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
1027bc04215SFelix Fietkau 0x7fffffff, 0x14c080, 0x19dd),
1037bc04215SFelix Fietkau RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0,
1047bc04215SFelix Fietkau 0x7fffffff, 0x14c080, 0x12cc),
1057bc04215SFelix Fietkau RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0,
1067bc04215SFelix Fietkau 0x3938700, 0X57bcf00, 0x1289),
1077bc04215SFelix Fietkau /* 80MHz */
1087bc04215SFelix Fietkau RADAR_SPEC(0, 8, 2, 9, 106, 150, 15, 2900, 80100, 15, 0,
1097bc04215SFelix Fietkau 0x7fffffff, 0x14c080, 0x16cc),
1107bc04215SFelix Fietkau RADAR_SPEC(0, 8, 2, 7, 106, 140, 5, 27600, 27900, 5, 0,
1117bc04215SFelix Fietkau 0x7fffffff, 0x14c080, 0x19dd),
1127bc04215SFelix Fietkau RADAR_SPEC(0, 40, 4, 44, 96, 480, 150, 2900, 80100, 40, 0,
1137bc04215SFelix Fietkau 0x7fffffff, 0x14c080, 0x12cc),
1147bc04215SFelix Fietkau RADAR_SPEC(2, 60, 15, 48, 940, 2080, 32, 19600, 40200, 32, 0,
1157bc04215SFelix Fietkau 0x3938700, 0X57bcf00, 0x1289)
1167bc04215SFelix Fietkau };
1177bc04215SFelix Fietkau
118e40803f2SLorenzo Bianconi static const struct mt76x02_radar_specs jp_w53_radar_specs[] = {
1197bc04215SFelix Fietkau /* 20MHz */
1207bc04215SFelix Fietkau RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0,
1217bc04215SFelix Fietkau 0x7fffffff, 0x14c080, 0x16cc),
1227bc04215SFelix Fietkau { 0 },
1237bc04215SFelix Fietkau RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0,
1247bc04215SFelix Fietkau 0x7fffffff, 0x14c080, 0x16cc),
1257bc04215SFelix Fietkau { 0 },
1267bc04215SFelix Fietkau /* 40MHz */
1277bc04215SFelix Fietkau RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0,
1287bc04215SFelix Fietkau 0x7fffffff, 0x14c080, 0x16cc),
1297bc04215SFelix Fietkau { 0 },
1307bc04215SFelix Fietkau RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0,
1317bc04215SFelix Fietkau 0x7fffffff, 0x14c080, 0x16cc),
1327bc04215SFelix Fietkau { 0 },
1337bc04215SFelix Fietkau /* 80MHz */
1347bc04215SFelix Fietkau RADAR_SPEC(0, 8, 2, 9, 106, 150, 20, 28400, 77000, 20, 0,
1357bc04215SFelix Fietkau 0x7fffffff, 0x14c080, 0x16cc),
1367bc04215SFelix Fietkau { 0 },
1377bc04215SFelix Fietkau RADAR_SPEC(0, 40, 4, 44, 96, 200, 150, 28400, 77000, 60, 0,
1387bc04215SFelix Fietkau 0x7fffffff, 0x14c080, 0x16cc),
1397bc04215SFelix Fietkau { 0 }
1407bc04215SFelix Fietkau };
1417bc04215SFelix Fietkau
142e40803f2SLorenzo Bianconi static void
mt76x02_dfs_set_capture_mode_ctrl(struct mt76x02_dev * dev,u8 enable)143e6cb3291SLorenzo Bianconi mt76x02_dfs_set_capture_mode_ctrl(struct mt76x02_dev *dev, u8 enable)
1447bc04215SFelix Fietkau {
1457bc04215SFelix Fietkau u32 data;
1467bc04215SFelix Fietkau
1477bc04215SFelix Fietkau data = (1 << 1) | enable;
1487bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 36), data);
1497bc04215SFelix Fietkau }
1507bc04215SFelix Fietkau
mt76x02_dfs_seq_pool_put(struct mt76x02_dev * dev,struct mt76x02_dfs_sequence * seq)151e6cb3291SLorenzo Bianconi static void mt76x02_dfs_seq_pool_put(struct mt76x02_dev *dev,
152e40803f2SLorenzo Bianconi struct mt76x02_dfs_sequence *seq)
153b7384e4eSLorenzo Bianconi {
154e40803f2SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
155b7384e4eSLorenzo Bianconi
156b7384e4eSLorenzo Bianconi list_add(&seq->head, &dfs_pd->seq_pool);
1574a07ed51SLorenzo Bianconi
1584a07ed51SLorenzo Bianconi dfs_pd->seq_stats.seq_pool_len++;
1594a07ed51SLorenzo Bianconi dfs_pd->seq_stats.seq_len--;
160b7384e4eSLorenzo Bianconi }
161b7384e4eSLorenzo Bianconi
162e40803f2SLorenzo Bianconi static struct mt76x02_dfs_sequence *
mt76x02_dfs_seq_pool_get(struct mt76x02_dev * dev)163e6cb3291SLorenzo Bianconi mt76x02_dfs_seq_pool_get(struct mt76x02_dev *dev)
164b7384e4eSLorenzo Bianconi {
165e40803f2SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
166e40803f2SLorenzo Bianconi struct mt76x02_dfs_sequence *seq;
167b7384e4eSLorenzo Bianconi
168b7384e4eSLorenzo Bianconi if (list_empty(&dfs_pd->seq_pool)) {
169b7384e4eSLorenzo Bianconi seq = devm_kzalloc(dev->mt76.dev, sizeof(*seq), GFP_ATOMIC);
170b7384e4eSLorenzo Bianconi } else {
171b7384e4eSLorenzo Bianconi seq = list_first_entry(&dfs_pd->seq_pool,
172e40803f2SLorenzo Bianconi struct mt76x02_dfs_sequence,
173b7384e4eSLorenzo Bianconi head);
174b7384e4eSLorenzo Bianconi list_del(&seq->head);
1754a07ed51SLorenzo Bianconi dfs_pd->seq_stats.seq_pool_len--;
176b7384e4eSLorenzo Bianconi }
1774a07ed51SLorenzo Bianconi if (seq)
1784a07ed51SLorenzo Bianconi dfs_pd->seq_stats.seq_len++;
1794a07ed51SLorenzo Bianconi
180b7384e4eSLorenzo Bianconi return seq;
181b7384e4eSLorenzo Bianconi }
182b7384e4eSLorenzo Bianconi
mt76x02_dfs_get_multiple(int val,int frac,int margin)183e6cb3291SLorenzo Bianconi static int mt76x02_dfs_get_multiple(int val, int frac, int margin)
184b7384e4eSLorenzo Bianconi {
185b7384e4eSLorenzo Bianconi int remainder, factor;
186b7384e4eSLorenzo Bianconi
187b7384e4eSLorenzo Bianconi if (!frac)
188b7384e4eSLorenzo Bianconi return 0;
189b7384e4eSLorenzo Bianconi
190b7384e4eSLorenzo Bianconi if (abs(val - frac) <= margin)
191b7384e4eSLorenzo Bianconi return 1;
192b7384e4eSLorenzo Bianconi
193b7384e4eSLorenzo Bianconi factor = val / frac;
194b7384e4eSLorenzo Bianconi remainder = val % frac;
195b7384e4eSLorenzo Bianconi
196b7384e4eSLorenzo Bianconi if (remainder > margin) {
197b7384e4eSLorenzo Bianconi if ((frac - remainder) <= margin)
198b7384e4eSLorenzo Bianconi factor++;
199b7384e4eSLorenzo Bianconi else
200b7384e4eSLorenzo Bianconi factor = 0;
201b7384e4eSLorenzo Bianconi }
202b7384e4eSLorenzo Bianconi return factor;
203b7384e4eSLorenzo Bianconi }
204b7384e4eSLorenzo Bianconi
mt76x02_dfs_detector_reset(struct mt76x02_dev * dev)205e6cb3291SLorenzo Bianconi static void mt76x02_dfs_detector_reset(struct mt76x02_dev *dev)
2061fc9bc9aSLorenzo Bianconi {
207e40803f2SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
208e40803f2SLorenzo Bianconi struct mt76x02_dfs_sequence *seq, *tmp_seq;
2091fc9bc9aSLorenzo Bianconi int i;
2101fc9bc9aSLorenzo Bianconi
2111fc9bc9aSLorenzo Bianconi /* reset hw detector */
2121fc9bc9aSLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 1), 0xf);
2131fc9bc9aSLorenzo Bianconi
2141fc9bc9aSLorenzo Bianconi /* reset sw detector */
2151fc9bc9aSLorenzo Bianconi for (i = 0; i < ARRAY_SIZE(dfs_pd->event_rb); i++) {
2161fc9bc9aSLorenzo Bianconi dfs_pd->event_rb[i].h_rb = 0;
2171fc9bc9aSLorenzo Bianconi dfs_pd->event_rb[i].t_rb = 0;
2181fc9bc9aSLorenzo Bianconi }
219b7384e4eSLorenzo Bianconi
220b7384e4eSLorenzo Bianconi list_for_each_entry_safe(seq, tmp_seq, &dfs_pd->sequences, head) {
221b7384e4eSLorenzo Bianconi list_del_init(&seq->head);
222e6cb3291SLorenzo Bianconi mt76x02_dfs_seq_pool_put(dev, seq);
223b7384e4eSLorenzo Bianconi }
2241fc9bc9aSLorenzo Bianconi }
2251fc9bc9aSLorenzo Bianconi
mt76x02_dfs_check_chirp(struct mt76x02_dev * dev)226e6cb3291SLorenzo Bianconi static bool mt76x02_dfs_check_chirp(struct mt76x02_dev *dev)
2277bc04215SFelix Fietkau {
2287bc04215SFelix Fietkau bool ret = false;
2297bc04215SFelix Fietkau u32 current_ts, delta_ts;
230e40803f2SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
2317bc04215SFelix Fietkau
2327bc04215SFelix Fietkau current_ts = mt76_rr(dev, MT_PBF_LIFE_TIMER);
2337bc04215SFelix Fietkau delta_ts = current_ts - dfs_pd->chirp_pulse_ts;
2347bc04215SFelix Fietkau dfs_pd->chirp_pulse_ts = current_ts;
2357bc04215SFelix Fietkau
2367bc04215SFelix Fietkau /* 12 sec */
2377bc04215SFelix Fietkau if (delta_ts <= (12 * (1 << 20))) {
2387bc04215SFelix Fietkau if (++dfs_pd->chirp_pulse_cnt > 8)
2397bc04215SFelix Fietkau ret = true;
2407bc04215SFelix Fietkau } else {
2417bc04215SFelix Fietkau dfs_pd->chirp_pulse_cnt = 1;
2427bc04215SFelix Fietkau }
2437bc04215SFelix Fietkau
2447bc04215SFelix Fietkau return ret;
2457bc04215SFelix Fietkau }
2467bc04215SFelix Fietkau
mt76x02_dfs_get_hw_pulse(struct mt76x02_dev * dev,struct mt76x02_dfs_hw_pulse * pulse)247e6cb3291SLorenzo Bianconi static void mt76x02_dfs_get_hw_pulse(struct mt76x02_dev *dev,
248e40803f2SLorenzo Bianconi struct mt76x02_dfs_hw_pulse *pulse)
2497bc04215SFelix Fietkau {
2507bc04215SFelix Fietkau u32 data;
2517bc04215SFelix Fietkau
2527bc04215SFelix Fietkau /* select channel */
2537bc04215SFelix Fietkau data = (MT_DFS_CH_EN << 16) | pulse->engine;
2547bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 0), data);
2557bc04215SFelix Fietkau
2567bc04215SFelix Fietkau /* reported period */
2577bc04215SFelix Fietkau pulse->period = mt76_rr(dev, MT_BBP(DFS, 19));
2587bc04215SFelix Fietkau
2597bc04215SFelix Fietkau /* reported width */
2607bc04215SFelix Fietkau pulse->w1 = mt76_rr(dev, MT_BBP(DFS, 20));
2617bc04215SFelix Fietkau pulse->w2 = mt76_rr(dev, MT_BBP(DFS, 23));
2627bc04215SFelix Fietkau
2637bc04215SFelix Fietkau /* reported burst number */
2647bc04215SFelix Fietkau pulse->burst = mt76_rr(dev, MT_BBP(DFS, 22));
2657bc04215SFelix Fietkau }
2667bc04215SFelix Fietkau
mt76x02_dfs_check_hw_pulse(struct mt76x02_dev * dev,struct mt76x02_dfs_hw_pulse * pulse)267e6cb3291SLorenzo Bianconi static bool mt76x02_dfs_check_hw_pulse(struct mt76x02_dev *dev,
268e40803f2SLorenzo Bianconi struct mt76x02_dfs_hw_pulse *pulse)
2697bc04215SFelix Fietkau {
2707bc04215SFelix Fietkau bool ret = false;
2717bc04215SFelix Fietkau
2727bc04215SFelix Fietkau if (!pulse->period || !pulse->w1)
2737bc04215SFelix Fietkau return false;
2747bc04215SFelix Fietkau
275d8b8890dSLorenzo Bianconi switch (dev->mt76.region) {
2767bc04215SFelix Fietkau case NL80211_DFS_FCC:
2777bc04215SFelix Fietkau if (pulse->engine > 3)
2787bc04215SFelix Fietkau break;
2797bc04215SFelix Fietkau
2807bc04215SFelix Fietkau if (pulse->engine == 3) {
281e6cb3291SLorenzo Bianconi ret = mt76x02_dfs_check_chirp(dev);
2827bc04215SFelix Fietkau break;
2837bc04215SFelix Fietkau }
2847bc04215SFelix Fietkau
2857bc04215SFelix Fietkau /* check short pulse*/
2867bc04215SFelix Fietkau if (pulse->w1 < 120)
2877bc04215SFelix Fietkau ret = (pulse->period >= 2900 &&
2887bc04215SFelix Fietkau (pulse->period <= 4700 ||
2897bc04215SFelix Fietkau pulse->period >= 6400) &&
2907bc04215SFelix Fietkau (pulse->period <= 6800 ||
2917bc04215SFelix Fietkau pulse->period >= 10200) &&
2927bc04215SFelix Fietkau pulse->period <= 61600);
2937bc04215SFelix Fietkau else if (pulse->w1 < 130) /* 120 - 130 */
2947bc04215SFelix Fietkau ret = (pulse->period >= 2900 &&
2957bc04215SFelix Fietkau pulse->period <= 61600);
2967bc04215SFelix Fietkau else
2977bc04215SFelix Fietkau ret = (pulse->period >= 3500 &&
2987bc04215SFelix Fietkau pulse->period <= 10100);
2997bc04215SFelix Fietkau break;
3007bc04215SFelix Fietkau case NL80211_DFS_ETSI:
3017bc04215SFelix Fietkau if (pulse->engine >= 3)
3027bc04215SFelix Fietkau break;
3037bc04215SFelix Fietkau
3047bc04215SFelix Fietkau ret = (pulse->period >= 4900 &&
3057bc04215SFelix Fietkau (pulse->period <= 10200 ||
3067bc04215SFelix Fietkau pulse->period >= 12400) &&
3077bc04215SFelix Fietkau pulse->period <= 100100);
3087bc04215SFelix Fietkau break;
3097bc04215SFelix Fietkau case NL80211_DFS_JP:
31096747a51SFelix Fietkau if (dev->mphy.chandef.chan->center_freq >= 5250 &&
31196747a51SFelix Fietkau dev->mphy.chandef.chan->center_freq <= 5350) {
3127bc04215SFelix Fietkau /* JPW53 */
3137bc04215SFelix Fietkau if (pulse->w1 <= 130)
3147bc04215SFelix Fietkau ret = (pulse->period >= 28360 &&
3157bc04215SFelix Fietkau (pulse->period <= 28700 ||
3167bc04215SFelix Fietkau pulse->period >= 76900) &&
3177bc04215SFelix Fietkau pulse->period <= 76940);
3187bc04215SFelix Fietkau break;
3197bc04215SFelix Fietkau }
3207bc04215SFelix Fietkau
3217bc04215SFelix Fietkau if (pulse->engine > 3)
3227bc04215SFelix Fietkau break;
3237bc04215SFelix Fietkau
3247bc04215SFelix Fietkau if (pulse->engine == 3) {
325e6cb3291SLorenzo Bianconi ret = mt76x02_dfs_check_chirp(dev);
3267bc04215SFelix Fietkau break;
3277bc04215SFelix Fietkau }
3287bc04215SFelix Fietkau
3297bc04215SFelix Fietkau /* check short pulse*/
3307bc04215SFelix Fietkau if (pulse->w1 < 120)
3317bc04215SFelix Fietkau ret = (pulse->period >= 2900 &&
3327bc04215SFelix Fietkau (pulse->period <= 4700 ||
3337bc04215SFelix Fietkau pulse->period >= 6400) &&
3347bc04215SFelix Fietkau (pulse->period <= 6800 ||
3357bc04215SFelix Fietkau pulse->period >= 27560) &&
3367bc04215SFelix Fietkau (pulse->period <= 27960 ||
3377bc04215SFelix Fietkau pulse->period >= 28360) &&
3387bc04215SFelix Fietkau (pulse->period <= 28700 ||
3397bc04215SFelix Fietkau pulse->period >= 79900) &&
3407bc04215SFelix Fietkau pulse->period <= 80100);
3417bc04215SFelix Fietkau else if (pulse->w1 < 130) /* 120 - 130 */
3427bc04215SFelix Fietkau ret = (pulse->period >= 2900 &&
3437bc04215SFelix Fietkau (pulse->period <= 10100 ||
3447bc04215SFelix Fietkau pulse->period >= 27560) &&
3457bc04215SFelix Fietkau (pulse->period <= 27960 ||
3467bc04215SFelix Fietkau pulse->period >= 28360) &&
3477bc04215SFelix Fietkau (pulse->period <= 28700 ||
3487bc04215SFelix Fietkau pulse->period >= 79900) &&
3497bc04215SFelix Fietkau pulse->period <= 80100);
3507bc04215SFelix Fietkau else
3517bc04215SFelix Fietkau ret = (pulse->period >= 3900 &&
3527bc04215SFelix Fietkau pulse->period <= 10100);
3537bc04215SFelix Fietkau break;
3547bc04215SFelix Fietkau case NL80211_DFS_UNSET:
3557bc04215SFelix Fietkau default:
3567bc04215SFelix Fietkau return false;
3577bc04215SFelix Fietkau }
3587bc04215SFelix Fietkau
3597bc04215SFelix Fietkau return ret;
3607bc04215SFelix Fietkau }
3617bc04215SFelix Fietkau
mt76x02_dfs_fetch_event(struct mt76x02_dev * dev,struct mt76x02_dfs_event * event)362e6cb3291SLorenzo Bianconi static bool mt76x02_dfs_fetch_event(struct mt76x02_dev *dev,
363e40803f2SLorenzo Bianconi struct mt76x02_dfs_event *event)
3641fc9bc9aSLorenzo Bianconi {
3651fc9bc9aSLorenzo Bianconi u32 data;
3661fc9bc9aSLorenzo Bianconi
3671fc9bc9aSLorenzo Bianconi /* 1st: DFS_R37[31]: 0 (engine 0) - 1 (engine 2)
3681fc9bc9aSLorenzo Bianconi * 2nd: DFS_R37[21:0]: pulse time
3691fc9bc9aSLorenzo Bianconi * 3rd: DFS_R37[11:0]: pulse width
3701fc9bc9aSLorenzo Bianconi * 3rd: DFS_R37[25:16]: phase
3711fc9bc9aSLorenzo Bianconi * 4th: DFS_R37[12:0]: current pwr
3721fc9bc9aSLorenzo Bianconi * 4th: DFS_R37[21:16]: pwr stable counter
3731fc9bc9aSLorenzo Bianconi *
3741fc9bc9aSLorenzo Bianconi * 1st: DFS_R37[31:0] set to 0xffffffff means no event detected
3751fc9bc9aSLorenzo Bianconi */
3761fc9bc9aSLorenzo Bianconi data = mt76_rr(dev, MT_BBP(DFS, 37));
3771fc9bc9aSLorenzo Bianconi if (!MT_DFS_CHECK_EVENT(data))
3781fc9bc9aSLorenzo Bianconi return false;
3791fc9bc9aSLorenzo Bianconi
3801fc9bc9aSLorenzo Bianconi event->engine = MT_DFS_EVENT_ENGINE(data);
3811fc9bc9aSLorenzo Bianconi data = mt76_rr(dev, MT_BBP(DFS, 37));
3821fc9bc9aSLorenzo Bianconi event->ts = MT_DFS_EVENT_TIMESTAMP(data);
3831fc9bc9aSLorenzo Bianconi data = mt76_rr(dev, MT_BBP(DFS, 37));
3841fc9bc9aSLorenzo Bianconi event->width = MT_DFS_EVENT_WIDTH(data);
3851fc9bc9aSLorenzo Bianconi
3861fc9bc9aSLorenzo Bianconi return true;
3871fc9bc9aSLorenzo Bianconi }
3881fc9bc9aSLorenzo Bianconi
mt76x02_dfs_check_event(struct mt76x02_dev * dev,struct mt76x02_dfs_event * event)389e6cb3291SLorenzo Bianconi static bool mt76x02_dfs_check_event(struct mt76x02_dev *dev,
390e40803f2SLorenzo Bianconi struct mt76x02_dfs_event *event)
3911fc9bc9aSLorenzo Bianconi {
3921fc9bc9aSLorenzo Bianconi if (event->engine == 2) {
393e40803f2SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
394e40803f2SLorenzo Bianconi struct mt76x02_dfs_event_rb *event_buff = &dfs_pd->event_rb[1];
3951fc9bc9aSLorenzo Bianconi u16 last_event_idx;
3961fc9bc9aSLorenzo Bianconi u32 delta_ts;
3971fc9bc9aSLorenzo Bianconi
3981fc9bc9aSLorenzo Bianconi last_event_idx = mt76_decr(event_buff->t_rb,
3991fc9bc9aSLorenzo Bianconi MT_DFS_EVENT_BUFLEN);
4001fc9bc9aSLorenzo Bianconi delta_ts = event->ts - event_buff->data[last_event_idx].ts;
4011fc9bc9aSLorenzo Bianconi if (delta_ts < MT_DFS_EVENT_TIME_MARGIN &&
4021fc9bc9aSLorenzo Bianconi event_buff->data[last_event_idx].width >= 200)
4031fc9bc9aSLorenzo Bianconi return false;
4041fc9bc9aSLorenzo Bianconi }
4051fc9bc9aSLorenzo Bianconi return true;
4061fc9bc9aSLorenzo Bianconi }
4071fc9bc9aSLorenzo Bianconi
mt76x02_dfs_queue_event(struct mt76x02_dev * dev,struct mt76x02_dfs_event * event)408e6cb3291SLorenzo Bianconi static void mt76x02_dfs_queue_event(struct mt76x02_dev *dev,
409e40803f2SLorenzo Bianconi struct mt76x02_dfs_event *event)
4101fc9bc9aSLorenzo Bianconi {
411e40803f2SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
412e40803f2SLorenzo Bianconi struct mt76x02_dfs_event_rb *event_buff;
4131fc9bc9aSLorenzo Bianconi
4141fc9bc9aSLorenzo Bianconi /* add radar event to ring buffer */
4151fc9bc9aSLorenzo Bianconi event_buff = event->engine == 2 ? &dfs_pd->event_rb[1]
4161fc9bc9aSLorenzo Bianconi : &dfs_pd->event_rb[0];
4171fc9bc9aSLorenzo Bianconi event_buff->data[event_buff->t_rb] = *event;
4181fc9bc9aSLorenzo Bianconi event_buff->data[event_buff->t_rb].fetch_ts = jiffies;
4191fc9bc9aSLorenzo Bianconi
4201fc9bc9aSLorenzo Bianconi event_buff->t_rb = mt76_incr(event_buff->t_rb, MT_DFS_EVENT_BUFLEN);
4211fc9bc9aSLorenzo Bianconi if (event_buff->t_rb == event_buff->h_rb)
4221fc9bc9aSLorenzo Bianconi event_buff->h_rb = mt76_incr(event_buff->h_rb,
4231fc9bc9aSLorenzo Bianconi MT_DFS_EVENT_BUFLEN);
4241fc9bc9aSLorenzo Bianconi }
4251fc9bc9aSLorenzo Bianconi
mt76x02_dfs_create_sequence(struct mt76x02_dev * dev,struct mt76x02_dfs_event * event,u16 cur_len)426e6cb3291SLorenzo Bianconi static int mt76x02_dfs_create_sequence(struct mt76x02_dev *dev,
427e40803f2SLorenzo Bianconi struct mt76x02_dfs_event *event,
428b7384e4eSLorenzo Bianconi u16 cur_len)
429b7384e4eSLorenzo Bianconi {
430e40803f2SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
431e40803f2SLorenzo Bianconi struct mt76x02_dfs_sw_detector_params *sw_params;
43200257508SYe Bin u32 width_delta, with_sum;
433e40803f2SLorenzo Bianconi struct mt76x02_dfs_sequence seq, *seq_p;
434e40803f2SLorenzo Bianconi struct mt76x02_dfs_event_rb *event_rb;
435e40803f2SLorenzo Bianconi struct mt76x02_dfs_event *cur_event;
43600257508SYe Bin int i, j, end, pri, factor, cur_pri;
437b7384e4eSLorenzo Bianconi
438b7384e4eSLorenzo Bianconi event_rb = event->engine == 2 ? &dfs_pd->event_rb[1]
439b7384e4eSLorenzo Bianconi : &dfs_pd->event_rb[0];
440b7384e4eSLorenzo Bianconi
441b7384e4eSLorenzo Bianconi i = mt76_decr(event_rb->t_rb, MT_DFS_EVENT_BUFLEN);
442b7384e4eSLorenzo Bianconi end = mt76_decr(event_rb->h_rb, MT_DFS_EVENT_BUFLEN);
443b7384e4eSLorenzo Bianconi
444b7384e4eSLorenzo Bianconi while (i != end) {
445b7384e4eSLorenzo Bianconi cur_event = &event_rb->data[i];
446b7384e4eSLorenzo Bianconi with_sum = event->width + cur_event->width;
447b7384e4eSLorenzo Bianconi
448b7384e4eSLorenzo Bianconi sw_params = &dfs_pd->sw_dpd_params;
449d8b8890dSLorenzo Bianconi switch (dev->mt76.region) {
450b7384e4eSLorenzo Bianconi case NL80211_DFS_FCC:
451b7384e4eSLorenzo Bianconi case NL80211_DFS_JP:
452b7384e4eSLorenzo Bianconi if (with_sum < 600)
453b7384e4eSLorenzo Bianconi width_delta = 8;
454b7384e4eSLorenzo Bianconi else
455b7384e4eSLorenzo Bianconi width_delta = with_sum >> 3;
456b7384e4eSLorenzo Bianconi break;
457b7384e4eSLorenzo Bianconi case NL80211_DFS_ETSI:
458b7384e4eSLorenzo Bianconi if (event->engine == 2)
459b7384e4eSLorenzo Bianconi width_delta = with_sum >> 6;
460b7384e4eSLorenzo Bianconi else if (with_sum < 620)
461b7384e4eSLorenzo Bianconi width_delta = 24;
462b7384e4eSLorenzo Bianconi else
463b7384e4eSLorenzo Bianconi width_delta = 8;
464b7384e4eSLorenzo Bianconi break;
465b7384e4eSLorenzo Bianconi case NL80211_DFS_UNSET:
466b7384e4eSLorenzo Bianconi default:
467b7384e4eSLorenzo Bianconi return -EINVAL;
468b7384e4eSLorenzo Bianconi }
469b7384e4eSLorenzo Bianconi
470b7384e4eSLorenzo Bianconi pri = event->ts - cur_event->ts;
471b7384e4eSLorenzo Bianconi if (abs(event->width - cur_event->width) > width_delta ||
472b7384e4eSLorenzo Bianconi pri < sw_params->min_pri)
473b7384e4eSLorenzo Bianconi goto next;
474b7384e4eSLorenzo Bianconi
475b7384e4eSLorenzo Bianconi if (pri > sw_params->max_pri)
476b7384e4eSLorenzo Bianconi break;
477b7384e4eSLorenzo Bianconi
478b7384e4eSLorenzo Bianconi seq.pri = event->ts - cur_event->ts;
479b7384e4eSLorenzo Bianconi seq.first_ts = cur_event->ts;
480b7384e4eSLorenzo Bianconi seq.last_ts = event->ts;
481b7384e4eSLorenzo Bianconi seq.engine = event->engine;
482b7384e4eSLorenzo Bianconi seq.count = 2;
483b7384e4eSLorenzo Bianconi
484b7384e4eSLorenzo Bianconi j = mt76_decr(i, MT_DFS_EVENT_BUFLEN);
485b7384e4eSLorenzo Bianconi while (j != end) {
486b7384e4eSLorenzo Bianconi cur_event = &event_rb->data[j];
487b7384e4eSLorenzo Bianconi cur_pri = event->ts - cur_event->ts;
488e6cb3291SLorenzo Bianconi factor = mt76x02_dfs_get_multiple(cur_pri, seq.pri,
489b7384e4eSLorenzo Bianconi sw_params->pri_margin);
490b7384e4eSLorenzo Bianconi if (factor > 0) {
491b7384e4eSLorenzo Bianconi seq.first_ts = cur_event->ts;
492b7384e4eSLorenzo Bianconi seq.count++;
493b7384e4eSLorenzo Bianconi }
494b7384e4eSLorenzo Bianconi
495b7384e4eSLorenzo Bianconi j = mt76_decr(j, MT_DFS_EVENT_BUFLEN);
496b7384e4eSLorenzo Bianconi }
497b7384e4eSLorenzo Bianconi if (seq.count <= cur_len)
498b7384e4eSLorenzo Bianconi goto next;
499b7384e4eSLorenzo Bianconi
500e6cb3291SLorenzo Bianconi seq_p = mt76x02_dfs_seq_pool_get(dev);
501b7384e4eSLorenzo Bianconi if (!seq_p)
502b7384e4eSLorenzo Bianconi return -ENOMEM;
503b7384e4eSLorenzo Bianconi
504b7384e4eSLorenzo Bianconi *seq_p = seq;
505b7384e4eSLorenzo Bianconi INIT_LIST_HEAD(&seq_p->head);
506b7384e4eSLorenzo Bianconi list_add(&seq_p->head, &dfs_pd->sequences);
507b7384e4eSLorenzo Bianconi next:
508b7384e4eSLorenzo Bianconi i = mt76_decr(i, MT_DFS_EVENT_BUFLEN);
509b7384e4eSLorenzo Bianconi }
510b7384e4eSLorenzo Bianconi return 0;
511b7384e4eSLorenzo Bianconi }
512b7384e4eSLorenzo Bianconi
mt76x02_dfs_add_event_to_sequence(struct mt76x02_dev * dev,struct mt76x02_dfs_event * event)513e6cb3291SLorenzo Bianconi static u16 mt76x02_dfs_add_event_to_sequence(struct mt76x02_dev *dev,
514e40803f2SLorenzo Bianconi struct mt76x02_dfs_event *event)
515b7384e4eSLorenzo Bianconi {
516e40803f2SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
517e40803f2SLorenzo Bianconi struct mt76x02_dfs_sw_detector_params *sw_params;
518e40803f2SLorenzo Bianconi struct mt76x02_dfs_sequence *seq, *tmp_seq;
519b7384e4eSLorenzo Bianconi u16 max_seq_len = 0;
52000257508SYe Bin int factor, pri;
521b7384e4eSLorenzo Bianconi
522b7384e4eSLorenzo Bianconi sw_params = &dfs_pd->sw_dpd_params;
523b7384e4eSLorenzo Bianconi list_for_each_entry_safe(seq, tmp_seq, &dfs_pd->sequences, head) {
524b7384e4eSLorenzo Bianconi if (event->ts > seq->first_ts + MT_DFS_SEQUENCE_WINDOW) {
525b7384e4eSLorenzo Bianconi list_del_init(&seq->head);
526e6cb3291SLorenzo Bianconi mt76x02_dfs_seq_pool_put(dev, seq);
527b7384e4eSLorenzo Bianconi continue;
528b7384e4eSLorenzo Bianconi }
529b7384e4eSLorenzo Bianconi
530b7384e4eSLorenzo Bianconi if (event->engine != seq->engine)
531b7384e4eSLorenzo Bianconi continue;
532b7384e4eSLorenzo Bianconi
533b7384e4eSLorenzo Bianconi pri = event->ts - seq->last_ts;
534e6cb3291SLorenzo Bianconi factor = mt76x02_dfs_get_multiple(pri, seq->pri,
535b7384e4eSLorenzo Bianconi sw_params->pri_margin);
536b7384e4eSLorenzo Bianconi if (factor > 0) {
537b7384e4eSLorenzo Bianconi seq->last_ts = event->ts;
538b7384e4eSLorenzo Bianconi seq->count++;
539b7384e4eSLorenzo Bianconi max_seq_len = max_t(u16, max_seq_len, seq->count);
540b7384e4eSLorenzo Bianconi }
541b7384e4eSLorenzo Bianconi }
542b7384e4eSLorenzo Bianconi return max_seq_len;
543b7384e4eSLorenzo Bianconi }
544b7384e4eSLorenzo Bianconi
mt76x02_dfs_check_detection(struct mt76x02_dev * dev)545e6cb3291SLorenzo Bianconi static bool mt76x02_dfs_check_detection(struct mt76x02_dev *dev)
546b7384e4eSLorenzo Bianconi {
547e40803f2SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
548e40803f2SLorenzo Bianconi struct mt76x02_dfs_sequence *seq;
549b7384e4eSLorenzo Bianconi
550b7384e4eSLorenzo Bianconi if (list_empty(&dfs_pd->sequences))
551b7384e4eSLorenzo Bianconi return false;
552b7384e4eSLorenzo Bianconi
553b7384e4eSLorenzo Bianconi list_for_each_entry(seq, &dfs_pd->sequences, head) {
5544a07ed51SLorenzo Bianconi if (seq->count > MT_DFS_SEQUENCE_TH) {
5554a07ed51SLorenzo Bianconi dfs_pd->stats[seq->engine].sw_pattern++;
556b7384e4eSLorenzo Bianconi return true;
557b7384e4eSLorenzo Bianconi }
5584a07ed51SLorenzo Bianconi }
559b7384e4eSLorenzo Bianconi return false;
560b7384e4eSLorenzo Bianconi }
561b7384e4eSLorenzo Bianconi
mt76x02_dfs_add_events(struct mt76x02_dev * dev)562e6cb3291SLorenzo Bianconi static void mt76x02_dfs_add_events(struct mt76x02_dev *dev)
5631fc9bc9aSLorenzo Bianconi {
564e40803f2SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
565e40803f2SLorenzo Bianconi struct mt76x02_dfs_event event;
566b7384e4eSLorenzo Bianconi int i, seq_len;
5671fc9bc9aSLorenzo Bianconi
5681fc9bc9aSLorenzo Bianconi /* disable debug mode */
569e6cb3291SLorenzo Bianconi mt76x02_dfs_set_capture_mode_ctrl(dev, false);
5701fc9bc9aSLorenzo Bianconi for (i = 0; i < MT_DFS_EVENT_LOOP; i++) {
571e6cb3291SLorenzo Bianconi if (!mt76x02_dfs_fetch_event(dev, &event))
5721fc9bc9aSLorenzo Bianconi break;
5731fc9bc9aSLorenzo Bianconi
5741fc9bc9aSLorenzo Bianconi if (dfs_pd->last_event_ts > event.ts)
575e6cb3291SLorenzo Bianconi mt76x02_dfs_detector_reset(dev);
5761fc9bc9aSLorenzo Bianconi dfs_pd->last_event_ts = event.ts;
5771fc9bc9aSLorenzo Bianconi
578e6cb3291SLorenzo Bianconi if (!mt76x02_dfs_check_event(dev, &event))
5791fc9bc9aSLorenzo Bianconi continue;
5801fc9bc9aSLorenzo Bianconi
581e6cb3291SLorenzo Bianconi seq_len = mt76x02_dfs_add_event_to_sequence(dev, &event);
582e6cb3291SLorenzo Bianconi mt76x02_dfs_create_sequence(dev, &event, seq_len);
583b7384e4eSLorenzo Bianconi
584e6cb3291SLorenzo Bianconi mt76x02_dfs_queue_event(dev, &event);
5851fc9bc9aSLorenzo Bianconi }
586e6cb3291SLorenzo Bianconi mt76x02_dfs_set_capture_mode_ctrl(dev, true);
5871fc9bc9aSLorenzo Bianconi }
5881fc9bc9aSLorenzo Bianconi
mt76x02_dfs_check_event_window(struct mt76x02_dev * dev)589e6cb3291SLorenzo Bianconi static void mt76x02_dfs_check_event_window(struct mt76x02_dev *dev)
5901fc9bc9aSLorenzo Bianconi {
591e40803f2SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
592e40803f2SLorenzo Bianconi struct mt76x02_dfs_event_rb *event_buff;
593e40803f2SLorenzo Bianconi struct mt76x02_dfs_event *event;
5941fc9bc9aSLorenzo Bianconi int i;
5951fc9bc9aSLorenzo Bianconi
5961fc9bc9aSLorenzo Bianconi for (i = 0; i < ARRAY_SIZE(dfs_pd->event_rb); i++) {
5971fc9bc9aSLorenzo Bianconi event_buff = &dfs_pd->event_rb[i];
5981fc9bc9aSLorenzo Bianconi
5991fc9bc9aSLorenzo Bianconi while (event_buff->h_rb != event_buff->t_rb) {
6001fc9bc9aSLorenzo Bianconi event = &event_buff->data[event_buff->h_rb];
6011fc9bc9aSLorenzo Bianconi
6021fc9bc9aSLorenzo Bianconi /* sorted list */
6031fc9bc9aSLorenzo Bianconi if (time_is_after_jiffies(event->fetch_ts +
6041fc9bc9aSLorenzo Bianconi MT_DFS_EVENT_WINDOW))
6051fc9bc9aSLorenzo Bianconi break;
6061fc9bc9aSLorenzo Bianconi event_buff->h_rb = mt76_incr(event_buff->h_rb,
6071fc9bc9aSLorenzo Bianconi MT_DFS_EVENT_BUFLEN);
6081fc9bc9aSLorenzo Bianconi }
6091fc9bc9aSLorenzo Bianconi }
6101fc9bc9aSLorenzo Bianconi }
6111fc9bc9aSLorenzo Bianconi
mt76x02_dfs_tasklet(struct tasklet_struct * t)6125ee3e780SAllen Pais static void mt76x02_dfs_tasklet(struct tasklet_struct *t)
6137bc04215SFelix Fietkau {
6145ee3e780SAllen Pais struct mt76x02_dfs_pattern_detector *dfs_pd = from_tasklet(dfs_pd, t,
6155ee3e780SAllen Pais dfs_tasklet);
6165ee3e780SAllen Pais struct mt76x02_dev *dev = container_of(dfs_pd, typeof(*dev), dfs_pd);
6177bc04215SFelix Fietkau u32 engine_mask;
6187bc04215SFelix Fietkau int i;
6197bc04215SFelix Fietkau
620011849e0SFelix Fietkau if (test_bit(MT76_SCANNING, &dev->mphy.state))
6217bc04215SFelix Fietkau goto out;
6227bc04215SFelix Fietkau
6231fc9bc9aSLorenzo Bianconi if (time_is_before_jiffies(dfs_pd->last_sw_check +
6241fc9bc9aSLorenzo Bianconi MT_DFS_SW_TIMEOUT)) {
625b7384e4eSLorenzo Bianconi bool radar_detected;
626b7384e4eSLorenzo Bianconi
6271fc9bc9aSLorenzo Bianconi dfs_pd->last_sw_check = jiffies;
6281fc9bc9aSLorenzo Bianconi
629e6cb3291SLorenzo Bianconi mt76x02_dfs_add_events(dev);
630e6cb3291SLorenzo Bianconi radar_detected = mt76x02_dfs_check_detection(dev);
631b7384e4eSLorenzo Bianconi if (radar_detected) {
632b7384e4eSLorenzo Bianconi /* sw detector rx radar pattern */
633bca8bc03SAditya Kumar Singh ieee80211_radar_detected(dev->mt76.hw, NULL);
634e6cb3291SLorenzo Bianconi mt76x02_dfs_detector_reset(dev);
635b7384e4eSLorenzo Bianconi
636b7384e4eSLorenzo Bianconi return;
637b7384e4eSLorenzo Bianconi }
638e6cb3291SLorenzo Bianconi mt76x02_dfs_check_event_window(dev);
6391fc9bc9aSLorenzo Bianconi }
6401fc9bc9aSLorenzo Bianconi
6417bc04215SFelix Fietkau engine_mask = mt76_rr(dev, MT_BBP(DFS, 1));
6427bc04215SFelix Fietkau if (!(engine_mask & 0xf))
6437bc04215SFelix Fietkau goto out;
6447bc04215SFelix Fietkau
6457bc04215SFelix Fietkau for (i = 0; i < MT_DFS_NUM_ENGINES; i++) {
646e40803f2SLorenzo Bianconi struct mt76x02_dfs_hw_pulse pulse;
6477bc04215SFelix Fietkau
6487bc04215SFelix Fietkau if (!(engine_mask & (1 << i)))
6497bc04215SFelix Fietkau continue;
6507bc04215SFelix Fietkau
6517bc04215SFelix Fietkau pulse.engine = i;
652e6cb3291SLorenzo Bianconi mt76x02_dfs_get_hw_pulse(dev, &pulse);
6537bc04215SFelix Fietkau
654e6cb3291SLorenzo Bianconi if (!mt76x02_dfs_check_hw_pulse(dev, &pulse)) {
6557bc04215SFelix Fietkau dfs_pd->stats[i].hw_pulse_discarded++;
6567bc04215SFelix Fietkau continue;
6577bc04215SFelix Fietkau }
6587bc04215SFelix Fietkau
6597bc04215SFelix Fietkau /* hw detector rx radar pattern */
6607bc04215SFelix Fietkau dfs_pd->stats[i].hw_pattern++;
661bca8bc03SAditya Kumar Singh ieee80211_radar_detected(dev->mt76.hw, NULL);
662e6cb3291SLorenzo Bianconi mt76x02_dfs_detector_reset(dev);
6637bc04215SFelix Fietkau
6647bc04215SFelix Fietkau return;
6657bc04215SFelix Fietkau }
6667bc04215SFelix Fietkau
6677bc04215SFelix Fietkau /* reset hw detector */
6687bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 1), 0xf);
6697bc04215SFelix Fietkau
6707bc04215SFelix Fietkau out:
671a23fde09SLorenzo Bianconi mt76x02_irq_enable(dev, MT_INT_GPTIMER);
6727bc04215SFelix Fietkau }
6737bc04215SFelix Fietkau
mt76x02_dfs_init_sw_detector(struct mt76x02_dev * dev)674e6cb3291SLorenzo Bianconi static void mt76x02_dfs_init_sw_detector(struct mt76x02_dev *dev)
675b7384e4eSLorenzo Bianconi {
676e40803f2SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
677b7384e4eSLorenzo Bianconi
678d8b8890dSLorenzo Bianconi switch (dev->mt76.region) {
679b7384e4eSLorenzo Bianconi case NL80211_DFS_FCC:
680b7384e4eSLorenzo Bianconi dfs_pd->sw_dpd_params.max_pri = MT_DFS_FCC_MAX_PRI;
681b7384e4eSLorenzo Bianconi dfs_pd->sw_dpd_params.min_pri = MT_DFS_FCC_MIN_PRI;
682b7384e4eSLorenzo Bianconi dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN;
683b7384e4eSLorenzo Bianconi break;
684b7384e4eSLorenzo Bianconi case NL80211_DFS_ETSI:
685b7384e4eSLorenzo Bianconi dfs_pd->sw_dpd_params.max_pri = MT_DFS_ETSI_MAX_PRI;
686b7384e4eSLorenzo Bianconi dfs_pd->sw_dpd_params.min_pri = MT_DFS_ETSI_MIN_PRI;
687b7384e4eSLorenzo Bianconi dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN << 2;
688b7384e4eSLorenzo Bianconi break;
689b7384e4eSLorenzo Bianconi case NL80211_DFS_JP:
690b7384e4eSLorenzo Bianconi dfs_pd->sw_dpd_params.max_pri = MT_DFS_JP_MAX_PRI;
691b7384e4eSLorenzo Bianconi dfs_pd->sw_dpd_params.min_pri = MT_DFS_JP_MIN_PRI;
692b7384e4eSLorenzo Bianconi dfs_pd->sw_dpd_params.pri_margin = MT_DFS_PRI_MARGIN;
693b7384e4eSLorenzo Bianconi break;
694b7384e4eSLorenzo Bianconi case NL80211_DFS_UNSET:
695b7384e4eSLorenzo Bianconi default:
696b7384e4eSLorenzo Bianconi break;
697b7384e4eSLorenzo Bianconi }
698b7384e4eSLorenzo Bianconi }
699b7384e4eSLorenzo Bianconi
mt76x02_dfs_set_bbp_params(struct mt76x02_dev * dev)700e6cb3291SLorenzo Bianconi static void mt76x02_dfs_set_bbp_params(struct mt76x02_dev *dev)
7017bc04215SFelix Fietkau {
702e40803f2SLorenzo Bianconi const struct mt76x02_radar_specs *radar_specs;
7037bc04215SFelix Fietkau u8 i, shift;
704e40803f2SLorenzo Bianconi u32 data;
7057bc04215SFelix Fietkau
70696747a51SFelix Fietkau switch (dev->mphy.chandef.width) {
7077bc04215SFelix Fietkau case NL80211_CHAN_WIDTH_40:
7087bc04215SFelix Fietkau shift = MT_DFS_NUM_ENGINES;
7097bc04215SFelix Fietkau break;
7107bc04215SFelix Fietkau case NL80211_CHAN_WIDTH_80:
7117bc04215SFelix Fietkau shift = 2 * MT_DFS_NUM_ENGINES;
7127bc04215SFelix Fietkau break;
7137bc04215SFelix Fietkau default:
7147bc04215SFelix Fietkau shift = 0;
7157bc04215SFelix Fietkau break;
7167bc04215SFelix Fietkau }
7177bc04215SFelix Fietkau
718d8b8890dSLorenzo Bianconi switch (dev->mt76.region) {
7197bc04215SFelix Fietkau case NL80211_DFS_FCC:
7207bc04215SFelix Fietkau radar_specs = &fcc_radar_specs[shift];
7217bc04215SFelix Fietkau break;
7227bc04215SFelix Fietkau case NL80211_DFS_ETSI:
7237bc04215SFelix Fietkau radar_specs = &etsi_radar_specs[shift];
7247bc04215SFelix Fietkau break;
7257bc04215SFelix Fietkau case NL80211_DFS_JP:
72696747a51SFelix Fietkau if (dev->mphy.chandef.chan->center_freq >= 5250 &&
72796747a51SFelix Fietkau dev->mphy.chandef.chan->center_freq <= 5350)
7287bc04215SFelix Fietkau radar_specs = &jp_w53_radar_specs[shift];
7297bc04215SFelix Fietkau else
7307bc04215SFelix Fietkau radar_specs = &jp_w56_radar_specs[shift];
7317bc04215SFelix Fietkau break;
7327bc04215SFelix Fietkau case NL80211_DFS_UNSET:
7337bc04215SFelix Fietkau default:
7347bc04215SFelix Fietkau return;
7357bc04215SFelix Fietkau }
7367bc04215SFelix Fietkau
7377bc04215SFelix Fietkau data = (MT_DFS_VGA_MASK << 16) |
7387bc04215SFelix Fietkau (MT_DFS_PWR_GAIN_OFFSET << 12) |
7397bc04215SFelix Fietkau (MT_DFS_PWR_DOWN_TIME << 8) |
7407bc04215SFelix Fietkau (MT_DFS_SYM_ROUND << 4) |
7417bc04215SFelix Fietkau (MT_DFS_DELTA_DELAY & 0xf);
7427bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 2), data);
7437bc04215SFelix Fietkau
7447bc04215SFelix Fietkau data = (MT_DFS_RX_PE_MASK << 16) | MT_DFS_PKT_END_MASK;
7457bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 3), data);
7467bc04215SFelix Fietkau
7477bc04215SFelix Fietkau for (i = 0; i < MT_DFS_NUM_ENGINES; i++) {
7487bc04215SFelix Fietkau /* configure engine */
7497bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 0), i);
7507bc04215SFelix Fietkau
7517bc04215SFelix Fietkau /* detection mode + avg_len */
7527bc04215SFelix Fietkau data = ((radar_specs[i].avg_len & 0x1ff) << 16) |
7537bc04215SFelix Fietkau (radar_specs[i].mode & 0xf);
7547bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 4), data);
7557bc04215SFelix Fietkau
7567bc04215SFelix Fietkau /* dfs energy */
7577bc04215SFelix Fietkau data = ((radar_specs[i].e_high & 0x0fff) << 16) |
7587bc04215SFelix Fietkau (radar_specs[i].e_low & 0x0fff);
7597bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 5), data);
7607bc04215SFelix Fietkau
7617bc04215SFelix Fietkau /* dfs period */
7627bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 7), radar_specs[i].t_low);
7637bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 9), radar_specs[i].t_high);
7647bc04215SFelix Fietkau
7657bc04215SFelix Fietkau /* dfs burst */
7667bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 11), radar_specs[i].b_low);
7677bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 13), radar_specs[i].b_high);
7687bc04215SFelix Fietkau
7697bc04215SFelix Fietkau /* dfs width */
7707bc04215SFelix Fietkau data = ((radar_specs[i].w_high & 0x0fff) << 16) |
7717bc04215SFelix Fietkau (radar_specs[i].w_low & 0x0fff);
7727bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 14), data);
7737bc04215SFelix Fietkau
7747bc04215SFelix Fietkau /* dfs margins */
7757bc04215SFelix Fietkau data = (radar_specs[i].w_margin << 16) |
7767bc04215SFelix Fietkau radar_specs[i].t_margin;
7777bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 15), data);
7787bc04215SFelix Fietkau
7797bc04215SFelix Fietkau /* dfs event expiration */
7807bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 17), radar_specs[i].event_expiration);
7817bc04215SFelix Fietkau
7827bc04215SFelix Fietkau /* dfs pwr adj */
7837bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 30), radar_specs[i].pwr_jmp);
7847bc04215SFelix Fietkau }
7857bc04215SFelix Fietkau
7867bc04215SFelix Fietkau /* reset status */
7877bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 1), 0xf);
7887bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 36), 0x3);
7897bc04215SFelix Fietkau
7907bc04215SFelix Fietkau /* enable detection*/
7917bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 0), MT_DFS_CH_EN << 16);
7926bf4a8e9SLorenzo Bianconi mt76_wr(dev, MT_BBP(IBI, 11), 0x0c350001);
7937bc04215SFelix Fietkau }
7947bc04215SFelix Fietkau
mt76x02_phy_dfs_adjust_agc(struct mt76x02_dev * dev)795801ccc8aSLorenzo Bianconi void mt76x02_phy_dfs_adjust_agc(struct mt76x02_dev *dev)
796801ccc8aSLorenzo Bianconi {
797801ccc8aSLorenzo Bianconi u32 agc_r8, agc_r4, val_r8, val_r4, dfs_r31;
798801ccc8aSLorenzo Bianconi
799801ccc8aSLorenzo Bianconi agc_r8 = mt76_rr(dev, MT_BBP(AGC, 8));
800801ccc8aSLorenzo Bianconi agc_r4 = mt76_rr(dev, MT_BBP(AGC, 4));
801801ccc8aSLorenzo Bianconi
802801ccc8aSLorenzo Bianconi val_r8 = (agc_r8 & 0x00007e00) >> 9;
803801ccc8aSLorenzo Bianconi val_r4 = agc_r4 & ~0x1f000000;
804801ccc8aSLorenzo Bianconi val_r4 += (((val_r8 + 1) >> 1) << 24);
805801ccc8aSLorenzo Bianconi mt76_wr(dev, MT_BBP(AGC, 4), val_r4);
806801ccc8aSLorenzo Bianconi
807801ccc8aSLorenzo Bianconi dfs_r31 = FIELD_GET(MT_BBP_AGC_LNA_HIGH_GAIN, val_r4);
808801ccc8aSLorenzo Bianconi dfs_r31 += val_r8;
809801ccc8aSLorenzo Bianconi dfs_r31 -= (agc_r8 & 0x00000038) >> 3;
810801ccc8aSLorenzo Bianconi dfs_r31 = (dfs_r31 << 16) | 0x00000307;
811801ccc8aSLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 31), dfs_r31);
812801ccc8aSLorenzo Bianconi
813801ccc8aSLorenzo Bianconi if (is_mt76x2(dev)) {
814801ccc8aSLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 32), 0x00040071);
815801ccc8aSLorenzo Bianconi } else {
816801ccc8aSLorenzo Bianconi /* disable hw detector */
817801ccc8aSLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 0), 0);
818801ccc8aSLorenzo Bianconi /* enable hw detector */
819801ccc8aSLorenzo Bianconi mt76_wr(dev, MT_BBP(DFS, 0), MT_DFS_CH_EN << 16);
820801ccc8aSLorenzo Bianconi }
821801ccc8aSLorenzo Bianconi }
822801ccc8aSLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x02_phy_dfs_adjust_agc);
823801ccc8aSLorenzo Bianconi
mt76x02_dfs_init_params(struct mt76x02_dev * dev)824e6cb3291SLorenzo Bianconi void mt76x02_dfs_init_params(struct mt76x02_dev *dev)
8257bc04215SFelix Fietkau {
8265b7cc6d1SFelix Fietkau if (mt76_phy_dfs_state(&dev->mphy) > MT_DFS_STATE_DISABLED) {
827e6cb3291SLorenzo Bianconi mt76x02_dfs_init_sw_detector(dev);
828e6cb3291SLorenzo Bianconi mt76x02_dfs_set_bbp_params(dev);
8297bc04215SFelix Fietkau /* enable debug mode */
830e6cb3291SLorenzo Bianconi mt76x02_dfs_set_capture_mode_ctrl(dev, true);
8317bc04215SFelix Fietkau
832a23fde09SLorenzo Bianconi mt76x02_irq_enable(dev, MT_INT_GPTIMER);
8337bc04215SFelix Fietkau mt76_rmw_field(dev, MT_INT_TIMER_EN,
8347bc04215SFelix Fietkau MT_INT_TIMER_EN_GP_TIMER_EN, 1);
8357bc04215SFelix Fietkau } else {
8367bc04215SFelix Fietkau /* disable hw detector */
8377bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 0), 0);
8387bc04215SFelix Fietkau /* clear detector status */
8397bc04215SFelix Fietkau mt76_wr(dev, MT_BBP(DFS, 1), 0xf);
8406bf4a8e9SLorenzo Bianconi if (mt76_chip(&dev->mt76) == 0x7610 ||
8416bf4a8e9SLorenzo Bianconi mt76_chip(&dev->mt76) == 0x7630)
8426bf4a8e9SLorenzo Bianconi mt76_wr(dev, MT_BBP(IBI, 11), 0xfde8081);
8436bf4a8e9SLorenzo Bianconi else
8446bf4a8e9SLorenzo Bianconi mt76_wr(dev, MT_BBP(IBI, 11), 0);
8457bc04215SFelix Fietkau
846a23fde09SLorenzo Bianconi mt76x02_irq_disable(dev, MT_INT_GPTIMER);
8477bc04215SFelix Fietkau mt76_rmw_field(dev, MT_INT_TIMER_EN,
8487bc04215SFelix Fietkau MT_INT_TIMER_EN_GP_TIMER_EN, 0);
8497bc04215SFelix Fietkau }
8507bc04215SFelix Fietkau }
851e6cb3291SLorenzo Bianconi EXPORT_SYMBOL_GPL(mt76x02_dfs_init_params);
8527bc04215SFelix Fietkau
mt76x02_dfs_init_detector(struct mt76x02_dev * dev)853e6cb3291SLorenzo Bianconi void mt76x02_dfs_init_detector(struct mt76x02_dev *dev)
8547bc04215SFelix Fietkau {
855e40803f2SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
8567bc04215SFelix Fietkau
857b7384e4eSLorenzo Bianconi INIT_LIST_HEAD(&dfs_pd->sequences);
858b7384e4eSLorenzo Bianconi INIT_LIST_HEAD(&dfs_pd->seq_pool);
859d8b8890dSLorenzo Bianconi dev->mt76.region = NL80211_DFS_UNSET;
8601fc9bc9aSLorenzo Bianconi dfs_pd->last_sw_check = jiffies;
8615ee3e780SAllen Pais tasklet_setup(&dfs_pd->dfs_tasklet, mt76x02_dfs_tasklet);
8627bc04215SFelix Fietkau }
8637bc04215SFelix Fietkau
864e6cb3291SLorenzo Bianconi static void
mt76x02_dfs_set_domain(struct mt76x02_dev * dev,enum nl80211_dfs_regions region)865e6cb3291SLorenzo Bianconi mt76x02_dfs_set_domain(struct mt76x02_dev *dev,
8662070f3ccSLorenzo Bianconi enum nl80211_dfs_regions region)
8672070f3ccSLorenzo Bianconi {
868e40803f2SLorenzo Bianconi struct mt76x02_dfs_pattern_detector *dfs_pd = &dev->dfs_pd;
8692070f3ccSLorenzo Bianconi
87035c57281SLorenzo Bianconi mutex_lock(&dev->mt76.mutex);
871d8b8890dSLorenzo Bianconi if (dev->mt76.region != region) {
8722070f3ccSLorenzo Bianconi tasklet_disable(&dfs_pd->dfs_tasklet);
873f82ce8d9SLorenzo Bianconi
874643749d4SFelix Fietkau dev->ed_monitor = dev->ed_monitor_enabled &&
875643749d4SFelix Fietkau region == NL80211_DFS_ETSI;
876a78f1547SLorenzo Bianconi mt76x02_edcca_init(dev);
877f82ce8d9SLorenzo Bianconi
878d8b8890dSLorenzo Bianconi dev->mt76.region = region;
879e6cb3291SLorenzo Bianconi mt76x02_dfs_init_params(dev);
8802070f3ccSLorenzo Bianconi tasklet_enable(&dfs_pd->dfs_tasklet);
8812070f3ccSLorenzo Bianconi }
88235c57281SLorenzo Bianconi mutex_unlock(&dev->mt76.mutex);
8832070f3ccSLorenzo Bianconi }
8842070f3ccSLorenzo Bianconi
mt76x02_regd_notifier(struct wiphy * wiphy,struct regulatory_request * request)885e6cb3291SLorenzo Bianconi void mt76x02_regd_notifier(struct wiphy *wiphy,
886e6cb3291SLorenzo Bianconi struct regulatory_request *request)
887e6cb3291SLorenzo Bianconi {
888e6cb3291SLorenzo Bianconi struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
889e6cb3291SLorenzo Bianconi struct mt76x02_dev *dev = hw->priv;
890e6cb3291SLorenzo Bianconi
891e6cb3291SLorenzo Bianconi mt76x02_dfs_set_domain(dev, request->dfs_region);
892e6cb3291SLorenzo Bianconi }
893