blob: eabfce50e690f5d851c7dbf3906a6e59d36ac874 [file] [log] [blame]
developer3abe1ad2022-01-24 11:13:32 +08001/* Copyright (C) 2021-2022 Mediatek Inc. */
2#include "atenl.h"
3
4#define CHAN(_ch, _freq, _ch_80, _ch_160, ...) { \
5 .ch = _ch, \
6 .freq = _freq, \
7 .ch_80 = _ch_80, \
8 .ch_160 = _ch_160, \
9 __VA_ARGS__ \
10}
11
12struct atenl_channel {
13 /* ctrl ch */
14 u16 ch;
15 u16 freq;
16 /* center ch */
17 u16 ch_80;
18 u16 ch_160;
19 /* only use for channels that don't have 80 but has 40 */
20 u16 ch_40;
21};
22
23static const struct atenl_channel atenl_channels_5ghz[] = {
24 CHAN(8, 5040, 0, 0),
25 CHAN(12, 5060, 0, 0),
26 CHAN(16, 5080, 0, 0),
27
28 CHAN(36, 5180, 42, 50),
29 CHAN(40, 5200, 42, 50),
30 CHAN(44, 5220, 42, 50),
31 CHAN(48, 5240, 42, 50),
32
33 CHAN(52, 5260, 58, 50),
34 CHAN(56, 5280, 58, 50),
35 CHAN(60, 5300, 58, 50),
36 CHAN(64, 5320, 58, 50),
37
38 CHAN(68, 5340, 0, 0),
39 CHAN(80, 5400, 0, 0),
40 CHAN(84, 5420, 0, 0),
41 CHAN(88, 5440, 0, 0),
42 CHAN(92, 5460, 0, 0),
43 CHAN(96, 5480, 0, 0),
44
45 CHAN(100, 5500, 106, 114),
46 CHAN(104, 5520, 106, 114),
47 CHAN(108, 5540, 106, 114),
48 CHAN(112, 5560, 106, 114),
49 CHAN(116, 5580, 122, 114),
50 CHAN(120, 5600, 122, 114),
51 CHAN(124, 5620, 122, 114),
52 CHAN(128, 5640, 122, 114),
53
54 CHAN(132, 5660, 138, 0),
55 CHAN(136, 5680, 138, 0),
56 CHAN(140, 5700, 138, 0),
57 CHAN(144, 5720, 138, 0),
58
59 CHAN(149, 5745, 155, 0),
60 CHAN(153, 5765, 155, 0),
61 CHAN(157, 5785, 155, 0),
62 CHAN(161, 5805, 155, 0),
63 CHAN(165, 5825, 0, 0, .ch_40 = 167),
64 CHAN(169, 5845, 0, 0, .ch_40 = 167),
65 CHAN(173, 5865, 0, 0),
66
67 CHAN(184, 4920, 0, 0),
68 CHAN(188, 4940, 0, 0),
69 CHAN(192, 4960, 0, 0),
70 CHAN(196, 4980, 0, 0),
71};
72
73static const struct atenl_channel atenl_channels_6ghz[] = {
74 /* UNII-5 */
75 CHAN(1, 5955, 7, 15),
76 CHAN(5, 5975, 7, 15),
77 CHAN(9, 5995, 7, 15),
78 CHAN(13, 6015, 7, 15),
79 CHAN(17, 6035, 23, 15),
80 CHAN(21, 6055, 23, 15),
81 CHAN(25, 6075, 23, 15),
82 CHAN(29, 6095, 23, 15),
83 CHAN(33, 6115, 39, 47),
84 CHAN(37, 6135, 39, 47),
85 CHAN(41, 6155, 39, 47),
86 CHAN(45, 6175, 39, 47),
87 CHAN(49, 6195, 55, 47),
88 CHAN(53, 6215, 55, 47),
89 CHAN(57, 6235, 55, 47),
90 CHAN(61, 6255, 55, 47),
91 CHAN(65, 6275, 71, 79),
92 CHAN(69, 6295, 71, 79),
93 CHAN(73, 6315, 71, 79),
94 CHAN(77, 6335, 71, 79),
95 CHAN(81, 6355, 87, 79),
96 CHAN(85, 6375, 87, 79),
97 CHAN(89, 6395, 87, 79),
98 CHAN(93, 6415, 87, 79),
99 /* UNII-6 */
100 CHAN(97, 6435, 103, 111),
101 CHAN(101, 6455, 103, 111),
102 CHAN(105, 6475, 103, 111),
103 CHAN(109, 6495, 103, 111),
104 CHAN(113, 6515, 119, 111),
105 CHAN(117, 6535, 119, 111),
106 /* UNII-7 */
107 CHAN(121, 6555, 119, 111),
108 CHAN(125, 6575, 119, 111),
109 CHAN(129, 6595, 135, 143),
110 CHAN(133, 6615, 135, 143),
111 CHAN(137, 6635, 135, 143),
112 CHAN(141, 6655, 135, 143),
113 CHAN(145, 6675, 151, 143),
114 CHAN(149, 6695, 151, 143),
115 CHAN(153, 6715, 151, 143),
116 CHAN(157, 6735, 151, 143),
117 CHAN(161, 6755, 167, 175),
118 CHAN(165, 6775, 167, 175),
119 CHAN(169, 6795, 167, 175),
120 CHAN(173, 6815, 167, 175),
121 CHAN(177, 6835, 183, 175),
122 CHAN(181, 6855, 183, 175),
123 CHAN(185, 6875, 183, 175),
124 /* UNII-8 */
125 CHAN(189, 6895, 183, 175),
126 CHAN(193, 6915, 199, 207),
127 CHAN(197, 6935, 199, 207),
128 CHAN(201, 6955, 199, 207),
129 CHAN(205, 6975, 199, 207),
130 CHAN(209, 6995, 215, 207),
131 CHAN(213, 7015, 215, 207),
132 CHAN(217, 7035, 215, 207),
133 CHAN(221, 7055, 215, 207),
134 CHAN(225, 7075, 0, 0, .ch_40 = 227),
135 CHAN(229, 7095, 0, 0, .ch_40 = 227),
136 CHAN(233, 7115, 0, 0),
137};
138
139static int
140atenl_hqa_adapter(struct atenl *an, struct atenl_data *data)
141{
142 char cmd[64];
143 u8 i;
144
145 for (i = 0; i < MAX_BAND_NUM; i++) {
146 u8 phy = get_band_val(an, i, phy_idx);
147
148 if (!get_band_val(an, i, valid))
149 continue;
150
151 if (data->cmd == HQA_CMD_OPEN_ADAPTER) {
152 sprintf(cmd, "iw phy phy%u interface add mon%u type monitor", phy, phy);
153 system(cmd);
154 sprintf(cmd, "iw dev wlan%u del", phy);
155 system(cmd);
156 sprintf(cmd, "ifconfig mon%u up", phy);
157 system(cmd);
158 /* set a special-defined country */
159 sprintf(cmd, "iw reg set VV");
160 system(cmd);
161 atenl_nl_set_state(an, i, MT76_TM_STATE_IDLE);
162 } else {
163 atenl_nl_set_state(an, i, MT76_TM_STATE_OFF);
164 sprintf(cmd, "iw reg set 00");
165 system(cmd);
166 sprintf(cmd, "iw dev mon%u del", phy);
167 system(cmd);
168 sprintf(cmd, "iw phy phy%u interface add wlan%u type managed", phy, phy);
169 system(cmd);
170 }
171 }
172
173 return 0;
174}
175
176static int
177atenl_hqa_set_rf_mode(struct atenl *an, struct atenl_data *data)
178{
179 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
180
181 /* The testmode rf mode change applies to all bands */
182 set_band_val(an, 0, rf_mode, ntohl(*(u32 *)hdr->data));
183 set_band_val(an, 1, rf_mode, ntohl(*(u32 *)hdr->data));
184
185 return 0;
186}
187
188static int
189atenl_hqa_get_chip_id(struct atenl *an, struct atenl_data *data)
190{
191 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
192
193 *(u32 *)(hdr->data + 2) = htonl(an->chip_id);
194
195 return 0;
196}
197
198static int
199atenl_hqa_get_sub_chip_id(struct atenl *an, struct atenl_data *data)
200{
201 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
202
developer5698c9c2022-05-30 16:40:23 +0800203 *(u32 *)(hdr->data + 2) = htonl(an->sub_chip_id);
developer3abe1ad2022-01-24 11:13:32 +0800204
205 return 0;
206}
207
208static int
209atenl_hqa_get_rf_cap(struct atenl *an, struct atenl_data *data)
210{
211 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
212 u32 band = ntohl(*(u32 *)hdr->data);
213 struct atenl_band *anb;
214
215 if (band >= MAX_BAND_NUM)
216 return -EINVAL;
217
218 anb = &an->anb[band];
219 /* fill tx and rx ant */
220 *(u32 *)(hdr->data + 2) = htonl(__builtin_popcount(anb->chainmask));
221 *(u32 *)(hdr->data + 2 + 4) = *(u32 *)(hdr->data + 2);
222
223 return 0;
224}
225
226static int
227atenl_hqa_reset_counter(struct atenl *an, struct atenl_data *data)
228{
229 struct atenl_band *anb = &an->anb[an->cur_band];
230
231 anb->reset_tx_cnt = true;
232 anb->reset_rx_cnt = true;
233
234 memset(&anb->rx_stat, 0, sizeof(anb->rx_stat));
235
236 return 0;
237}
238
239static int
240atenl_hqa_mac_bbp_reg(struct atenl *an, struct atenl_data *data)
241{
242 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
243 enum atenl_cmd cmd = data->cmd;
244 u32 *v = (u32 *)hdr->data;
developer5698c9c2022-05-30 16:40:23 +0800245 u32 offset = ntohl(v[0]), res;
developer3abe1ad2022-01-24 11:13:32 +0800246 int ret;
247
248 if (cmd == HQA_CMD_READ_MAC_BBP_REG) {
249 u16 num = ntohs(*(u16 *)(hdr->data + 4));
250 u32 *ptr = (u32 *)(hdr->data + 2);
developer3abe1ad2022-01-24 11:13:32 +0800251 int i;
252
253 if (num > SHRT_MAX) {
254 ret = -EINVAL;
255 goto out;
256 }
257
258 hdr->len = htons(2 + num * 4);
259 for (i = 0; i < num && i < sizeof(hdr->data) / 4; i++) {
260 ret = atenl_reg_read(an, offset + i * 4, &res);
261 if (ret)
262 goto out;
263
264 res = htonl(res);
265 memcpy(ptr + i, &res, 4);
266 }
developer5698c9c2022-05-30 16:40:23 +0800267 } else if (cmd == HQA_CMD_READ_MAC_BBP_REG_QA) {
268 ret = atenl_reg_read(an, offset, &res);
269 if (ret)
270 goto out;
271
272 res = htonl(res);
273 memcpy(hdr->data + 2, &res, 4);
developer3abe1ad2022-01-24 11:13:32 +0800274 } else {
275 u32 val = ntohl(v[1]);
276
277 ret = atenl_reg_write(an, offset, val);
278 if (ret)
279 goto out;
280 }
281
282 ret = 0;
283out:
284 memset(hdr->data, 0, 2);
285
286 return ret;
287}
288
289static int
developer5698c9c2022-05-30 16:40:23 +0800290atenl_hqa_rf_reg(struct atenl *an, struct atenl_data *data)
291{
292 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
293 enum atenl_cmd cmd = data->cmd;
294 u32 *v = (u32 *)hdr->data;
295 u32 wf_sel = ntohl(v[0]);
296 u32 offset = ntohl(v[1]);
297 u32 num = ntohl(v[2]);
298 int ret, i;
299
300 if (cmd == HQA_CMD_READ_RF_REG) {
301 u32 *ptr = (u32 *)(hdr->data + 2);
302 u32 res;
303
304 hdr->len = htons(2 + num * 4);
305 for (i = 0; i < num && i < sizeof(hdr->data) / 4; i++) {
306 ret = atenl_rf_read(an, wf_sel, offset + i * 4, &res);
307 if (ret)
308 goto out;
309
310 res = htonl(res);
311 memcpy(ptr + i, &res, 4);
312 }
313 } else {
314 u32 *ptr = (u32 *)(hdr->data + 12);
315
316 for (i = 0; i < num && i < sizeof(hdr->data) / 4; i++) {
317 u32 val = ntohl(ptr[i]);
318
319 ret = atenl_rf_write(an, wf_sel, offset + i * 4, val);
320 if (ret)
321 goto out;
322 }
323 }
324
325 ret = 0;
326out:
327 memset(hdr->data, 0, 2);
328
329 return ret;
330}
331
332static int
developer3abe1ad2022-01-24 11:13:32 +0800333atenl_hqa_eeprom_bulk(struct atenl *an, struct atenl_data *data)
334{
335 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
336 enum atenl_cmd cmd = data->cmd;
337
338 if (cmd == HQA_CMD_WRITE_BUFFER_DONE) {
339 u32 buf_mode = ntohl(*(u32 *)hdr->data);
340
341 switch (buf_mode) {
342 case E2P_EFUSE_MODE:
developer9b7cdad2022-03-10 14:24:55 +0800343 atenl_nl_write_efuse_all(an);
developer3abe1ad2022-01-24 11:13:32 +0800344 break;
345 default:
346 break;
347 }
348 } else {
349 u16 *v = (u16 *)hdr->data;
350 u16 offset = ntohs(v[0]), len = ntohs(v[1]);
351 u16 val;
352 size_t i;
353
354 if (offset >= an->eeprom_size || (len > sizeof(hdr->data) - 2))
355 return -EINVAL;
356
357 if (cmd == HQA_CMD_READ_EEPROM_BULK) {
358 hdr->len = htons(len + 2);
359 for (i = 0; i < len; i += 2) {
360 if (offset + i >= an->eeprom_size)
361 val = 0;
362 else
363 val = ntohs(*(u16 *)(an->eeprom_data + offset + i));
364 *(u16 *)(hdr->data + 2 + i) = val;
365 }
366 } else { /* write eeprom */
developer3abe1ad2022-01-24 11:13:32 +0800367 for (i = 0; i < DIV_ROUND_UP(len, 2); i++) {
368 val = ntohs(v[i + 2]);
369 memcpy(&an->eeprom_data[offset + i * 2], &val, 2);
370 }
developer3abe1ad2022-01-24 11:13:32 +0800371 }
372 }
373
374 return 0;
375}
376
377static int
378atenl_hqa_get_efuse_free_block(struct atenl *an, struct atenl_data *data)
379{
380 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
381 u32 free_block = htonl(0x14);
382
383 /* TODO */
384 *(u32 *)(hdr->data + 2) = free_block;
385
386 return 0;
387}
388
389static int
390atenl_hqa_get_band(struct atenl *an, struct atenl_data *data)
391{
392 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
393 u32 band = ntohl(*(u32 *)hdr->data);
394
395 if (band >= MAX_BAND_NUM)
396 return -EINVAL;
397
398 *(u32 *)(hdr->data + 2) = htonl(an->anb[band].cap);
399
400 return 0;
401}
402
403static int
404atenl_hqa_get_tx_power(struct atenl *an, struct atenl_data *data)
405{
406 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
407 u32 tx_power = htonl(28);
408
409 memcpy(hdr->data + 6, &tx_power, 4);
410
411 return 0;
412}
413
414static int
415atenl_hqa_get_freq_offset(struct atenl *an, struct atenl_data *data)
416{
417 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
418 u32 freq_offset = htonl(10);
419
420 /* TODO */
421 memcpy(hdr->data + 2, &freq_offset, 4);
422
423 return 0;
424}
425
426static int
427atenl_hqa_get_cfg(struct atenl *an, struct atenl_data *data)
428{
429 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
430 u32 val = htonl(1);
431
432 /* TODO */
433 memcpy(hdr->data + 2, &val, 4);
434
435 return 0;
436}
437
438static int
439atenl_hqa_read_temperature(struct atenl *an, struct atenl_data *data)
440{
441 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
442 char buf[64], *str;
443 int fd, ret;
444 u32 temp;
445 u8 phy_idx = get_band_val(an, an->cur_band, phy_idx);
446
447 ret = snprintf(buf, sizeof(buf),
448 "/sys/class/ieee80211/phy%u/hwmon%u/temp1_input",
449 phy_idx, phy_idx);
450 if (snprintf_error(sizeof(buf), ret))
451 return -1;
452
453 fd = open(buf, O_RDONLY);
454 if (fd < 0)
455 return fd;
456
457 ret = read(fd, buf, sizeof(buf) - 1);
458 if (ret < 0)
459 goto out;
460 buf[ret] = 0;
461
462 str = strchr(buf, ':');
463 str += 2;
464 temp = strtol(str, NULL, 10);
465 /* unit conversion */
466 *(u32 *)(hdr->data + 2) = htonl(temp / 1000);
467
468 ret = 0;
469out:
470 close(fd);
471
472 return ret;
473}
474
475static int
developer3abe1ad2022-01-24 11:13:32 +0800476atenl_hqa_check_efuse_mode(struct atenl *an, struct atenl_data *data)
477{
478 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
479 bool flash_mode = an->mtd_part != NULL;
480 enum atenl_cmd cmd = data->cmd;
481 u32 mode;
482
483 switch (cmd) {
484 case HQA_CMD_CHECK_EFUSE_MODE:
485 mode = flash_mode ? 0 : 1;
486 break;
487 case HQA_CMD_CHECK_EFUSE_MODE_TYPE:
488 mode = flash_mode ? E2P_FLASH_MODE : E2P_BIN_MODE;
489 break;
490 case HQA_CMD_CHECK_EFUSE_MODE_NATIVE:
491 mode = flash_mode ? E2P_FLASH_MODE : E2P_EFUSE_MODE;
492 break;
493 default:
494 mode = E2P_BIN_MODE;
495 break;
496 }
497
498 *(u32 *)(hdr->data + 2) = htonl(mode);
499
500 return 0;
501}
502
503static inline u16
504atenl_get_freq_by_channel(u8 ch_band, u16 ch)
505{
506 u16 base;
507
508 if (ch_band == CH_BAND_6GHZ) {
509 base = 5950;
510 } else if (ch_band == CH_BAND_5GHZ) {
511 if (ch >= 184)
512 return 4920 + (ch - 184) * 5;
513
514 base = 5000;
515 } else {
516 base = 2407;
517 }
518
519 return base + ch * 5;
520}
521
522u16 atenl_get_center_channel(u8 bw, u8 ch_band, u16 ctrl_ch)
523{
524 const struct atenl_channel *chan = NULL;
525 const struct atenl_channel *ch_list;
526 u16 center_ch;
527 u8 ch_num;
528 int i;
529
530 if (ch_band == CH_BAND_2GHZ || bw <= TEST_CBW_40MHZ)
531 return 0;
532
533 if (ch_band == CH_BAND_6GHZ) {
534 ch_list = atenl_channels_6ghz;
535 ch_num = ARRAY_SIZE(atenl_channels_6ghz);
536 } else {
537 ch_list = atenl_channels_5ghz;
538 ch_num = ARRAY_SIZE(atenl_channels_5ghz);
539 }
540
541 for (i = 0; i < ch_num; i++) {
542 if (ctrl_ch == ch_list[i].ch) {
543 chan = &ch_list[i];
544 break;
545 }
546 }
547
548 if (!chan)
549 return 0;
550
551 switch (bw) {
552 case TEST_CBW_160MHZ:
553 center_ch = chan->ch_160;
554 break;
555 case TEST_CBW_80MHZ:
556 center_ch = chan->ch_80;
557 break;
558 default:
559 center_ch = 0;
560 break;
561 }
562
563 return center_ch;
564}
565
566static void atenl_get_bw_string(u8 bw, char *buf)
567{
568 switch (bw) {
569 case TEST_CBW_160MHZ:
570 sprintf(buf, "160");
571 break;
572 case TEST_CBW_80MHZ:
573 sprintf(buf, "80");
574 break;
575 case TEST_CBW_40MHZ:
576 sprintf(buf, "40");
577 break;
578 default:
579 sprintf(buf, "20");
580 break;
581 }
582}
583
584void atenl_set_channel(struct atenl *an, u8 bw, u8 ch_band,
585 u16 ch, u16 center_ch1, u16 center_ch2)
586{
587 char bw_str[8] = {};
588 char cmd[128];
589 u16 freq = atenl_get_freq_by_channel(ch_band, ch);
590 u16 freq_center1 = atenl_get_freq_by_channel(ch_band, center_ch1);
591 int ret;
592
593 if (bw > TEST_CBW_MAX)
594 return;
595
596 atenl_get_bw_string(bw, bw_str);
597
598 if (bw == TEST_CBW_20MHZ)
599 ret = snprintf(cmd, sizeof(cmd), "iw dev mon%d set freq %u %s",
600 get_band_val(an, an->cur_band, phy_idx),
601 freq, bw_str);
602 else
603 ret = snprintf(cmd, sizeof(cmd), "iw dev mon%d set freq %u %s %u",
604 get_band_val(an, an->cur_band, phy_idx),
605 freq, bw_str, freq_center1);
606 if (snprintf_error(sizeof(cmd), ret))
607 return;
608
developer5698c9c2022-05-30 16:40:23 +0800609 atenl_dbg("%s: cmd: %s\n", __func__, cmd);
developer3abe1ad2022-01-24 11:13:32 +0800610
611 system(cmd);
612}
613
614static int
615atenl_hqa_set_channel(struct atenl *an, struct atenl_data *data)
616{
617 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
618 u32 *v = (u32 *)hdr->data;
619 u8 band = ntohl(v[2]);
620 u16 ch1 = ntohl(v[3]); /* center */
621 u16 ch2 = ntohl(v[4]);
622 u8 bw = ntohl(v[5]);
623 u8 pri_sel = ntohl(v[7]);
624 u8 ch_band = ntohl(v[9]);
625 u16 ctrl_ch = 0;
626
627 if (band >= MAX_BAND_NUM)
628 return -EINVAL;
629
630 if ((bw == TEST_CBW_160MHZ && pri_sel > 7) ||
631 (bw == TEST_CBW_80MHZ && pri_sel > 3) ||
632 (bw == TEST_CBW_40MHZ && pri_sel > 1)) {
633 atenl_err("%s: ctrl channel select error\n", __func__);
634 return -EINVAL;
635 }
636
637 an->cur_band = band;
638
639 if (ch_band == CH_BAND_2GHZ) {
640 ctrl_ch = ch1;
641 switch (bw) {
642 case TEST_CBW_40MHZ:
643 if (pri_sel == 1)
644 ctrl_ch += 2;
645 else
646 ctrl_ch -= 2;
647 break;
648 default:
649 break;
650 }
651
652 atenl_set_channel(an, bw, CH_BAND_2GHZ, ctrl_ch, ch1, 0);
653 } else {
654 const struct atenl_channel *chan = NULL;
655 const struct atenl_channel *ch_list;
656 u8 ch_num;
657 int i;
658
659 if (ch_band == CH_BAND_6GHZ) {
660 ch_list = atenl_channels_6ghz;
661 ch_num = ARRAY_SIZE(atenl_channels_6ghz);
662 } else {
663 ch_list = atenl_channels_5ghz;
664 ch_num = ARRAY_SIZE(atenl_channels_5ghz);
665 }
666
667 if (bw == TEST_CBW_160MHZ) {
668 for (i = 0; i < ch_num; i++) {
669 if (ch1 == ch_list[i].ch_160) {
670 chan = &ch_list[i];
671 break;
672 } else if (ch1 < ch_list[i].ch_160) {
673 chan = &ch_list[i - 1];
674 break;
675 }
676 }
677 } else if (bw == TEST_CBW_80MHZ) {
678 for (i = 0; i < ch_num; i++) {
679 if (ch1 == ch_list[i].ch_80) {
680 chan = &ch_list[i];
681 break;
682 } else if (ch1 < ch_list[i].ch_80) {
683 chan = &ch_list[i - 1];
684 break;
685 }
686 }
687 } else {
688 for (i = 0; i < ch_num; i++) {
689 if (ch1 <= ch_list[i].ch) {
690 if (ch1 == ch_list[i].ch)
691 chan = &ch_list[i];
692 else
693 chan = &ch_list[i - 1];
694 break;
695 }
696 }
697 }
698
699 if (!chan)
700 return -EINVAL;
701
702 if (bw != TEST_CBW_20MHZ) {
703 chan += pri_sel;
704 if (chan > &ch_list[ch_num - 1])
705 return -EINVAL;
706 }
707 ctrl_ch = chan->ch;
708
709 atenl_set_channel(an, bw, ch_band, ctrl_ch, ch1, ch2);
710 }
711
712 *(u32 *)(hdr->data + 2) = data->ext_id;
713
developer5698c9c2022-05-30 16:40:23 +0800714 atenl_nl_set_aid(an, band, 0);
715
developer3abe1ad2022-01-24 11:13:32 +0800716 return 0;
717}
718
719static int
720atenl_hqa_tx_time_option(struct atenl *an, struct atenl_data *data)
721{
722 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
723 u32 *v = (u32 *)hdr->data;
724 u8 band = ntohl(v[1]);
725 u32 option = ntohl(v[2]);
726
727 if (band >= MAX_BAND_NUM)
728 return -EINVAL;
729
730 set_band_val(an, band, use_tx_time, !!option);
731 *(u32 *)(hdr->data + 2) = data->ext_id;
732
733 return 0;
734}
735
developer5698c9c2022-05-30 16:40:23 +0800736/* should be placed in order for binary search */
737static const struct atenl_ops hqa_ops[] = {
738 {
739 .cmd = HQA_CMD_OPEN_ADAPTER,
740 .cmd_id = 0x1000,
741 .resp_len = 2,
742 .ops = atenl_hqa_adapter,
743 },
744 {
745 .cmd = HQA_CMD_CLOSE_ADAPTER,
746 .cmd_id = 0x1001,
747 .resp_len = 2,
748 .ops = atenl_hqa_adapter,
749 },
750 {
751 .cmd = HQA_CMD_SET_TX_PATH,
752 .cmd_id = 0x100b,
753 .resp_len = 2,
754 .ops = atenl_nl_process,
755 },
756 {
757 .cmd = HQA_CMD_SET_RX_PATH,
758 .cmd_id = 0x100c,
759 .resp_len = 2,
760 .ops = atenl_nl_process,
761 },
762 {
763 .cmd = HQA_CMD_LEGACY,
764 .cmd_id = 0x100d,
765 .resp_len = 2,
766 .flags = ATENL_OPS_FLAG_SKIP,
767 },
768 {
769 .cmd = HQA_CMD_SET_TX_POWER,
770 .cmd_id = 0x1011,
771 .resp_len = 2,
772 .ops = atenl_nl_process,
773 },
774 {
775 .cmd = HQA_CMD_SET_TX_POWER_MANUAL,
776 .cmd_id = 0x1018,
777 .resp_len = 2,
778 .flags = ATENL_OPS_FLAG_SKIP,
779 },
780 {
781 .cmd = HQA_CMD_LEGACY,
782 .cmd_id = 0x1101,
783 .resp_len = 2,
784 .flags = ATENL_OPS_FLAG_SKIP,
785 },
786 {
787 .cmd = HQA_CMD_LEGACY,
788 .cmd_id = 0x1102,
789 .resp_len = 2,
790 .flags = ATENL_OPS_FLAG_SKIP,
791 },
792 {
793 .cmd = HQA_CMD_SET_TX_BW,
794 .cmd_id = 0x1104,
795 .resp_len = 2,
796 .flags = ATENL_OPS_FLAG_SKIP,
797 },
798 {
799 .cmd = HQA_CMD_SET_TX_PKT_BW,
800 .cmd_id = 0x1105,
801 .resp_len = 2,
802 .flags = ATENL_OPS_FLAG_SKIP,
803 },
804 {
805 .cmd = HQA_CMD_SET_TX_PRI_BW,
806 .cmd_id = 0x1106,
807 .resp_len = 2,
808 .flags = ATENL_OPS_FLAG_SKIP,
809 },
810 {
811 .cmd = HQA_CMD_SET_FREQ_OFFSET,
812 .cmd_id = 0x1107,
813 .resp_len = 2,
814 .ops = atenl_nl_process,
815 },
816 {
817 .cmd = HQA_CMD_SET_TSSI,
818 .cmd_id = 0x1109,
819 .resp_len = 2,
820 .ops = atenl_nl_process,
821 },
822 {
823 .cmd = HQA_CMD_SET_EEPROM_TO_FW,
824 .cmd_id = 0x110c,
825 .resp_len = 2,
826 .flags = ATENL_OPS_FLAG_SKIP,
827 },
828 {
829 .cmd = HQA_CMD_ANT_SWAP_CAP,
830 .cmd_id = 0x110d,
831 .resp_len = 6,
832 .flags = ATENL_OPS_FLAG_SKIP,
833 },
834 {
835 .cmd = HQA_CMD_RESET_TX_RX_COUNTER,
836 .cmd_id = 0x1200,
837 .resp_len = 2,
838 .ops = atenl_hqa_reset_counter,
839 },
840 {
841 .cmd = HQA_CMD_READ_MAC_BBP_REG_QA,
842 .cmd_id = 0x1300,
843 .resp_len = 6,
844 .ops = atenl_hqa_mac_bbp_reg,
845 },
846 {
847 .cmd = HQA_CMD_WRITE_MAC_BBP_REG,
848 .cmd_id = 0x1301,
849 .resp_len = 2,
850 .ops = atenl_hqa_mac_bbp_reg,
851 },
852 {
853 .cmd = HQA_CMD_READ_MAC_BBP_REG,
854 .cmd_id = 0x1302,
855 .ops = atenl_hqa_mac_bbp_reg,
856 },
857 {
858 .cmd = HQA_CMD_READ_RF_REG,
859 .cmd_id = 0x1303,
860 .ops = atenl_hqa_rf_reg,
861 },
862 {
863 .cmd = HQA_CMD_WRITE_RF_REG,
864 .cmd_id = 0x1304,
865 .resp_len = 2,
866 .ops = atenl_hqa_rf_reg,
867 },
868 {
869 .cmd = HQA_CMD_WRITE_EEPROM_BULK,
870 .cmd_id = 0x1306,
871 .resp_len = 2,
872 .ops = atenl_hqa_eeprom_bulk,
873 },
874 {
875 .cmd = HQA_CMD_READ_EEPROM_BULK,
876 .cmd_id = 0x1307,
877 .ops = atenl_hqa_eeprom_bulk,
878 },
879 {
880 .cmd = HQA_CMD_WRITE_EEPROM_BULK,
881 .cmd_id = 0x1308,
882 .resp_len = 2,
883 .ops = atenl_hqa_eeprom_bulk,
884 },
885 {
886 .cmd = HQA_CMD_CHECK_EFUSE_MODE,
887 .cmd_id = 0x1309,
888 .resp_len = 6,
889 .ops = atenl_hqa_check_efuse_mode,
890 },
891 {
892 .cmd = HQA_CMD_GET_EFUSE_FREE_BLOCK,
893 .cmd_id = 0x130a,
894 .resp_len = 6,
895 .ops = atenl_hqa_get_efuse_free_block,
896 },
897 {
898 .cmd = HQA_CMD_GET_TX_POWER,
899 .cmd_id = 0x130d,
900 .resp_len = 10,
901 .ops = atenl_hqa_get_tx_power,
902 },
903 {
904 .cmd = HQA_CMD_SET_CFG,
905 .cmd_id = 0x130e,
906 .resp_len = 2,
907 .ops = atenl_nl_process,
908 },
909 {
910 .cmd = HQA_CMD_GET_FREQ_OFFSET,
911 .cmd_id = 0x130f,
912 .resp_len = 6,
913 .ops = atenl_hqa_get_freq_offset,
914 },
915 {
916 .cmd = HQA_CMD_CONTINUOUS_TX,
917 .cmd_id = 0x1311,
918 .resp_len = 6,
919 .ops = atenl_nl_process,
920 },
921 {
922 .cmd = HQA_CMD_SET_RX_PKT_LEN,
923 .cmd_id = 0x1312,
924 .resp_len = 2,
925 .flags = ATENL_OPS_FLAG_SKIP,
926 },
927 {
928 .cmd = HQA_CMD_GET_TX_INFO,
929 .cmd_id = 0x1313,
930 .resp_len = 10,
931 .ops = atenl_nl_process,
932 },
933 {
934 .cmd = HQA_CMD_GET_CFG,
935 .cmd_id = 0x1314,
936 .resp_len = 6,
937 .ops = atenl_hqa_get_cfg,
938 },
939 {
940 .cmd = HQA_CMD_GET_TX_TONE_POWER,
941 .cmd_id = 0x131a,
942 .resp_len = 6,
943 .flags = ATENL_OPS_FLAG_SKIP,
944 },
945 {
946 .cmd = HQA_CMD_UNKNOWN,
947 .cmd_id = 0x131f,
948 .resp_len = 1024,
949 .flags = ATENL_OPS_FLAG_SKIP,
950 },
951 {
952 .cmd = HQA_CMD_READ_TEMPERATURE,
953 .cmd_id = 0x1401,
954 .resp_len = 6,
955 .ops = atenl_hqa_read_temperature,
956 },
957 {
958 .cmd = HQA_CMD_GET_FW_INFO,
959 .cmd_id = 0x1500,
960 .resp_len = 32,
961 .flags = ATENL_OPS_FLAG_SKIP,
962 },
963 {
964 .cmd_id = 0x1502,
965 .flags = ATENL_OPS_FLAG_LEGACY,
966 },
967 {
968 .cmd = HQA_CMD_SET_TSSI,
969 .cmd_id = 0x1505,
970 .resp_len = 2,
971 .ops = atenl_nl_process,
972 },
973 {
974 .cmd = HQA_CMD_SET_RF_MODE,
975 .cmd_id = 0x1509,
976 .resp_len = 2,
977 .ops = atenl_hqa_set_rf_mode,
978 },
979 {
980 .cmd_id = 0x150b,
981 .flags = ATENL_OPS_FLAG_LEGACY,
982 },
983 {
984 .cmd = HQA_CMD_WRITE_BUFFER_DONE,
985 .cmd_id = 0x1511,
986 .resp_len = 2,
987 .ops = atenl_hqa_eeprom_bulk,
988 },
989 {
990 .cmd = HQA_CMD_GET_CHIP_ID,
991 .cmd_id = 0x1514,
992 .resp_len = 6,
993 .ops = atenl_hqa_get_chip_id,
994 },
995 {
996 .cmd = HQA_CMD_GET_SUB_CHIP_ID,
997 .cmd_id = 0x151b,
998 .resp_len = 6,
999 .ops = atenl_hqa_get_sub_chip_id,
1000 },
1001 {
1002 .cmd = HQA_CMD_GET_RX_INFO,
1003 .cmd_id = 0x151c,
1004 .ops = atenl_nl_process,
1005 },
1006 {
1007 .cmd = HQA_CMD_GET_RF_CAP,
1008 .cmd_id = 0x151e,
1009 .resp_len = 10,
1010 .ops = atenl_hqa_get_rf_cap,
1011 },
1012 {
1013 .cmd = HQA_CMD_CHECK_EFUSE_MODE_TYPE,
1014 .cmd_id = 0x1522,
1015 .resp_len = 6,
1016 .ops = atenl_hqa_check_efuse_mode,
1017 },
1018 {
1019 .cmd = HQA_CMD_CHECK_EFUSE_MODE_NATIVE,
1020 .cmd_id = 0x1523,
1021 .resp_len = 6,
1022 .ops = atenl_hqa_check_efuse_mode,
1023 },
1024 {
1025 .cmd = HQA_CMD_GET_BAND,
1026 .cmd_id = 0x152d,
1027 .resp_len = 6,
1028 .ops = atenl_hqa_get_band,
1029 },
1030 {
1031 .cmd = HQA_CMD_SET_RU,
1032 .cmd_id = 0x1594,
1033 .resp_len = 2,
1034 .ops = atenl_nl_process_many,
1035 },
developer3abe1ad2022-01-24 11:13:32 +08001036};
developer3abe1ad2022-01-24 11:13:32 +08001037
developer5698c9c2022-05-30 16:40:23 +08001038static const struct atenl_ops hqa_ops_ext[] = {
1039 {
1040 .cmd = HQA_EXT_CMD_SET_CHANNEL,
1041 .cmd_id = 0x01,
1042 .resp_len = 6,
1043 .ops = atenl_hqa_set_channel,
1044 .flags = ATENL_OPS_FLAG_EXT_CMD,
1045 },
1046 {
1047 .cmd = HQA_EXT_CMD_SET_TX,
1048 .cmd_id = 0x02,
1049 .resp_len = 6,
1050 .ops = atenl_nl_process,
1051 .flags = ATENL_OPS_FLAG_EXT_CMD,
1052 },
1053 {
1054 .cmd = HQA_EXT_CMD_START_TX,
1055 .cmd_id = 0x03,
1056 .resp_len = 6,
1057 .ops = atenl_nl_process,
1058 .flags = ATENL_OPS_FLAG_EXT_CMD,
1059 },
1060 {
1061 .cmd = HQA_EXT_CMD_START_RX,
1062 .cmd_id = 0x04,
1063 .resp_len = 6,
1064 .ops = atenl_nl_process,
1065 .flags = ATENL_OPS_FLAG_EXT_CMD,
1066 },
1067 {
1068 .cmd = HQA_EXT_CMD_STOP_TX,
1069 .cmd_id = 0x05,
1070 .resp_len = 6,
1071 .ops = atenl_nl_process,
1072 .flags = ATENL_OPS_FLAG_EXT_CMD,
1073 },
1074 {
1075 .cmd = HQA_EXT_CMD_STOP_RX,
1076 .cmd_id = 0x06,
1077 .resp_len = 6,
1078 .ops = atenl_nl_process,
1079 .flags = ATENL_OPS_FLAG_EXT_CMD,
1080 },
1081 {
1082 .cmd = HQA_EXT_CMD_IBF_SET_VAL,
1083 .cmd_id = 0x08,
1084 .resp_len = 6,
1085 .ops = atenl_nl_process,
1086 .flags = ATENL_OPS_FLAG_EXT_CMD,
1087 },
1088 {
1089 .cmd = HQA_EXT_CMD_IBF_GET_STATUS,
1090 .cmd_id = 0x09,
1091 .resp_len = 10,
1092 .ops = atenl_nl_process,
1093 .flags = ATENL_OPS_FLAG_EXT_CMD,
1094 },
1095 {
1096 .cmd = HQA_EXT_CMD_IBF_PROF_UPDATE_ALL,
1097 .cmd_id = 0x0c,
1098 .resp_len = 6,
1099 .ops = atenl_nl_process,
1100 .flags = ATENL_OPS_FLAG_EXT_CMD,
1101 },
1102 {
1103 .cmd = HQA_EXT_CMD_SET_TX_TIME_OPT,
1104 .cmd_id = 0x26,
1105 .resp_len = 6,
1106 .ops = atenl_hqa_tx_time_option,
1107 .flags = ATENL_OPS_FLAG_EXT_CMD,
1108 },
1109 {
1110 .cmd = HQA_EXT_CMD_OFF_CH_SCAN,
1111 .cmd_id = 0x27,
1112 .resp_len = 6,
1113 .ops = atenl_nl_process,
1114 .flags = ATENL_OPS_FLAG_EXT_CMD,
1115 },
developer3abe1ad2022-01-24 11:13:32 +08001116};
developer3abe1ad2022-01-24 11:13:32 +08001117
developer5698c9c2022-05-30 16:40:23 +08001118static const struct atenl_ops *
1119atenl_get_ops(struct atenl_data *data)
developer3abe1ad2022-01-24 11:13:32 +08001120{
developer5698c9c2022-05-30 16:40:23 +08001121 const struct atenl_ops *group;
developer3abe1ad2022-01-24 11:13:32 +08001122 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
developer5698c9c2022-05-30 16:40:23 +08001123 u16 cmd_id = ntohs(hdr->cmd_id), id = cmd_id;
1124 int size, low = 0, high;
developer3abe1ad2022-01-24 11:13:32 +08001125
developer5698c9c2022-05-30 16:40:23 +08001126 switch (cmd_id) {
1127 case 0x1600:
1128 group = hqa_ops_ext;
1129 size = ARRAY_SIZE(hqa_ops_ext);
1130 break;
1131 default:
1132 group = hqa_ops;
1133 size = ARRAY_SIZE(hqa_ops);
1134 break;
developer3abe1ad2022-01-24 11:13:32 +08001135 }
1136
developer5698c9c2022-05-30 16:40:23 +08001137 if (group[0].flags & ATENL_OPS_FLAG_EXT_CMD)
1138 id = ntohl(*(u32 *)hdr->data);
1139
1140 /* binary search */
1141 high = size - 1;
1142 while (low <= high) {
1143 int mid = low + (high - low) / 2;
developer3abe1ad2022-01-24 11:13:32 +08001144
developer5698c9c2022-05-30 16:40:23 +08001145 if (group[mid].cmd_id == id)
1146 return &group[mid];
1147 else if (group[mid].cmd_id > id)
1148 high = mid - 1;
1149 else
1150 low = mid + 1;
developer3abe1ad2022-01-24 11:13:32 +08001151 }
1152
developer5698c9c2022-05-30 16:40:23 +08001153 return NULL;
developer3abe1ad2022-01-24 11:13:32 +08001154}
1155
developer5698c9c2022-05-30 16:40:23 +08001156static int
1157atenl_hqa_handler(struct atenl *an, struct atenl_data *data)
developer3abe1ad2022-01-24 11:13:32 +08001158{
1159 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
developer5698c9c2022-05-30 16:40:23 +08001160 const struct atenl_ops *ops = NULL;
developer3abe1ad2022-01-24 11:13:32 +08001161 u16 cmd_id = ntohs(hdr->cmd_id);
1162 u16 status = 0;
1163
developer5698c9c2022-05-30 16:40:23 +08001164 atenl_dbg("handle command: 0x%x\n", cmd_id);
1165
1166 ops = atenl_get_ops(data);
1167 if (!ops || (!ops->ops && !ops->flags)) {
1168 atenl_err("Unknown command id: 0x%x\n", cmd_id);
developer3abe1ad2022-01-24 11:13:32 +08001169 goto done;
1170 }
1171
developer5698c9c2022-05-30 16:40:23 +08001172 data->cmd = ops->cmd;
1173 data->cmd_id = ops->cmd_id;
1174 if (ops->flags & ATENL_OPS_FLAG_EXT_CMD) {
1175 data->ext_cmd = ops->cmd;
1176 data->ext_id = ops->cmd_id;
developer3abe1ad2022-01-24 11:13:32 +08001177 }
1178
developer5698c9c2022-05-30 16:40:23 +08001179 if (ops->flags & ATENL_OPS_FLAG_SKIP)
1180 goto done;
1181
1182 atenl_dbg_print_data(data->buf, __func__,
developer3abe1ad2022-01-24 11:13:32 +08001183 ntohs(hdr->len) + ETH_HLEN + RACFG_HLEN);
1184 if (ops->ops)
1185 status = htons(ops->ops(an, data));
1186 if (ops->resp_len)
1187 hdr->len = htons(ops->resp_len);
1188
developer3abe1ad2022-01-24 11:13:32 +08001189done:
developer5698c9c2022-05-30 16:40:23 +08001190 *(u16 *)hdr->data = status;
developer3abe1ad2022-01-24 11:13:32 +08001191 data->len = ntohs(hdr->len) + ETH_HLEN + RACFG_HLEN;
1192 hdr->cmd_type |= ~htons(RACFG_CMD_TYPE_MASK);
1193
1194 return 0;
1195}
developer5698c9c2022-05-30 16:40:23 +08001196
1197int atenl_hqa_proc_cmd(struct atenl *an)
1198{
1199 struct atenl_data *data;
1200 struct atenl_cmd_hdr *hdr;
1201 u16 cmd_type;
1202 int ret = -EINVAL;
1203
1204 data = calloc(1, sizeof(struct atenl_data));
1205 if (!data)
1206 return -ENOMEM;
1207
1208 ret = atenl_eth_recv(an, data);
1209 if (ret)
1210 goto out;
1211
1212 hdr = atenl_hdr(data);
1213 if (ntohl(hdr->magic_no) != RACFG_MAGIC_NO)
1214 goto out;
1215
1216 cmd_type = ntohs(hdr->cmd_type);
1217 if (FIELD_GET(RACFG_CMD_TYPE_MASK, cmd_type) != RACFG_CMD_TYPE_ETHREQ &&
1218 FIELD_GET(RACFG_CMD_TYPE_MASK, cmd_type) != RACFG_CMD_TYPE_PLATFORM_MODULE) {
1219 atenl_err("cmd type error = 0x%x\n", cmd_type);
1220 goto out;
1221 }
1222
1223 ret = atenl_hqa_handler(an, data);
1224 if (ret)
1225 goto out;
1226
1227 ret = atenl_eth_send(an, data);
1228 if (ret)
1229 goto out;
1230
1231 ret = 0;
1232out:
1233 free(data);
1234
1235 return ret;
1236}