blob: d18262ebd9aa2cbcebfd0611400df46e6a522e9a [file] [log] [blame]
developer22c7ab62022-01-24 11:13:32 +08001#define _GNU_SOURCE
2#include <fcntl.h>
3#include <sys/mman.h>
4#include <sys/stat.h>
5#include <sys/wait.h>
6
7#include "atenl.h"
8
developer454c4652022-08-31 20:39:29 +08009#define EEPROM_PART_SIZE 0x64000
developer2bf395f2022-01-26 20:50:22 +080010char *eeprom_file;
developer22c7ab62022-01-24 11:13:32 +080011
developer0296d8b2022-11-01 11:15:32 +080012static int
13atenl_create_file(struct atenl *an, bool flash_mode)
developer22c7ab62022-01-24 11:13:32 +080014{
developer0296d8b2022-11-01 11:15:32 +080015 char fname[64], buf[1024];
16 ssize_t w, len, max_len, total_len = 0;
17 int fd_ori, fd, ret;
developer22c7ab62022-01-24 11:13:32 +080018
developer0296d8b2022-11-01 11:15:32 +080019 /* reserve space for pre-cal data in flash mode */
20 if (flash_mode) {
21 atenl_dbg("%s: init eeprom with flash mode\n", __func__);
22 max_len = EEPROM_PART_SIZE;
23 } else {
24 atenl_dbg("%s: init eeprom with efuse mode\n", __func__);
25 max_len = 0x1000;
developer22c7ab62022-01-24 11:13:32 +080026 }
developer22c7ab62022-01-24 11:13:32 +080027
developer0296d8b2022-11-01 11:15:32 +080028 snprintf(fname, sizeof(fname),
29 "/sys/kernel/debug/ieee80211/phy%d/mt76/eeprom",
30 get_band_val(an, 0, phy_idx));
31 fd_ori = open(fname, O_RDONLY);
32 if (fd_ori < 0)
developer22c7ab62022-01-24 11:13:32 +080033 return -1;
developer22c7ab62022-01-24 11:13:32 +080034
developer2bf395f2022-01-26 20:50:22 +080035 fd = open(eeprom_file, O_RDWR | O_CREAT | O_EXCL, 00644);
developer22c7ab62022-01-24 11:13:32 +080036 if (fd < 0)
37 goto out;
38
developer0296d8b2022-11-01 11:15:32 +080039 while ((len = read(fd_ori, buf, sizeof(buf))) > 0) {
developer22c7ab62022-01-24 11:13:32 +080040retry:
41 w = write(fd, buf, len);
developerf30d4472022-05-30 16:40:23 +080042 if (w > 0) {
developer0296d8b2022-11-01 11:15:32 +080043 total_len += len;
developer22c7ab62022-01-24 11:13:32 +080044 continue;
developerf30d4472022-05-30 16:40:23 +080045 }
developer22c7ab62022-01-24 11:13:32 +080046
47 if (errno == EINTR)
48 goto retry;
49
50 perror("write");
developer2bf395f2022-01-26 20:50:22 +080051 unlink(eeprom_file);
developer22c7ab62022-01-24 11:13:32 +080052 close(fd);
53 fd = -1;
54 goto out;
55 }
56
developer0296d8b2022-11-01 11:15:32 +080057 /* reserve space for pre-cal data in flash mode */
58 len = sizeof(buf);
59 memset(buf, 0, len);
60 while (total_len < max_len) {
developer22c7ab62022-01-24 11:13:32 +080061 w = write(fd, buf, len);
developer22c7ab62022-01-24 11:13:32 +080062
developer0296d8b2022-11-01 11:15:32 +080063 if (w > 0) {
64 total_len += len;
65 continue;
66 }
developer22c7ab62022-01-24 11:13:32 +080067
developer0296d8b2022-11-01 11:15:32 +080068 if (errno != EINTR) {
69 perror("write");
70 unlink(eeprom_file);
71 close(fd);
72 fd = -1;
73 goto out;
74 }
developer22c7ab62022-01-24 11:13:32 +080075 }
76
developer0296d8b2022-11-01 11:15:32 +080077
developer22c7ab62022-01-24 11:13:32 +080078 ret = lseek(fd, 0, SEEK_SET);
79 if (ret) {
80 close(fd_ori);
81 close(fd);
82 return ret;
83 }
84
85out:
86 close(fd_ori);
87 return fd;
88}
89
90static bool
91atenl_eeprom_file_exists(void)
92{
93 struct stat st;
94
developer2bf395f2022-01-26 20:50:22 +080095 return stat(eeprom_file, &st) == 0;
developer22c7ab62022-01-24 11:13:32 +080096}
97
98static int
99atenl_eeprom_init_file(struct atenl *an, bool flash_mode)
100{
101 int fd;
102
developer0296d8b2022-11-01 11:15:32 +0800103 if (!atenl_eeprom_file_exists())
104 return atenl_create_file(an, flash_mode);
developer22c7ab62022-01-24 11:13:32 +0800105
developer2bf395f2022-01-26 20:50:22 +0800106 fd = open(eeprom_file, O_RDWR);
developer22c7ab62022-01-24 11:13:32 +0800107 if (fd < 0)
108 perror("open");
109
developer22c7ab62022-01-24 11:13:32 +0800110 return fd;
111}
112
113static void
developerf30d4472022-05-30 16:40:23 +0800114atenl_eeprom_init_chip_id(struct atenl *an)
115{
116 an->chip_id = *(u16 *)an->eeprom_data;
117
118 if (is_mt7915(an)) {
119 an->adie_id = 0x7975;
120 } else if (is_mt7916(an)) {
121 an->adie_id = 0x7976;
122 } else if (is_mt7986(an)) {
123 bool is_7975 = false;
124 u32 val;
125 u8 sub_id;
126
127 atenl_reg_read(an, 0x18050000, &val);
128
129 switch (val & 0xf) {
130 case MT7975_ONE_ADIE_SINGLE_BAND:
131 is_7975 = true;
132 /* fallthrough */
133 case MT7976_ONE_ADIE_SINGLE_BAND:
134 sub_id = 0xa;
135 break;
136 case MT7976_ONE_ADIE_DBDC:
137 sub_id = 0x7;
138 break;
139 case MT7975_DUAL_ADIE_DBDC:
140 is_7975 = true;
141 /* fallthrough */
142 case MT7976_DUAL_ADIE_DBDC:
143 default:
144 sub_id = 0xf;
145 break;
146 }
147
148 an->sub_chip_id = sub_id;
149 an->adie_id = is_7975 ? 0x7975 : 0x7976;
150 }
151}
152
153static void
developer22c7ab62022-01-24 11:13:32 +0800154atenl_eeprom_init_max_size(struct atenl *an)
155{
156 switch (an->chip_id) {
157 case 0x7915:
158 an->eeprom_size = 3584;
developer454c4652022-08-31 20:39:29 +0800159 an->eeprom_prek_offs = 0x62;
developer22c7ab62022-01-24 11:13:32 +0800160 break;
161 case 0x7906:
162 case 0x7916:
163 case 0x7986:
164 an->eeprom_size = 4096;
developer454c4652022-08-31 20:39:29 +0800165 an->eeprom_prek_offs = 0x19a;
developer22c7ab62022-01-24 11:13:32 +0800166 break;
167 default:
168 break;
169 }
170}
171
172static void
173atenl_eeprom_init_band_cap(struct atenl *an)
174{
175 u8 *eeprom = an->eeprom_data;
176
177 if (is_mt7915(an)) {
178 u8 val = eeprom[MT_EE_WIFI_CONF];
179 u8 band_sel = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val);
180 struct atenl_band *anb = &an->anb[0];
181
182 /* MT7915A */
183 if (band_sel == MT_EE_BAND_SEL_DEFAULT) {
184 anb->valid = true;
185 anb->cap = BAND_TYPE_2G_5G;
186 return;
187 }
188
189 /* MT7915D */
190 if (band_sel == MT_EE_BAND_SEL_2GHZ) {
191 anb->valid = true;
192 anb->cap = BAND_TYPE_2G;
193 }
194
195 val = eeprom[MT_EE_WIFI_CONF + 1];
196 band_sel = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val);
197 anb++;
198
199 if (band_sel == MT_EE_BAND_SEL_5GHZ) {
200 anb->valid = true;
201 anb->cap = BAND_TYPE_5G;
202 }
203 } else if (is_mt7916(an) || is_mt7986(an)) {
204 struct atenl_band *anb;
205 u8 val, band_sel;
206 int i;
207
208 for (i = 0; i < 2; i++) {
209 val = eeprom[MT_EE_WIFI_CONF + i];
210 band_sel = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val);
211 anb = &an->anb[i];
212
213 anb->valid = true;
214 switch (band_sel) {
215 case MT_EE_BAND_SEL_2G:
216 anb->cap = BAND_TYPE_2G;
217 break;
218 case MT_EE_BAND_SEL_5G:
219 anb->cap = BAND_TYPE_5G;
220 break;
221 case MT_EE_BAND_SEL_6G:
222 anb->cap = BAND_TYPE_6G;
223 break;
224 case MT_EE_BAND_SEL_5G_6G:
225 anb->cap = BAND_TYPE_5G_6G;
226 break;
227 default:
228 break;
229 }
230 }
231 }
232}
233
234static void
235atenl_eeprom_init_antenna_cap(struct atenl *an)
236{
237 if (is_mt7915(an)) {
238 if (an->anb[0].cap == BAND_TYPE_2G_5G)
239 an->anb[0].chainmask = 0xf;
240 else {
241 an->anb[0].chainmask = 0x3;
242 an->anb[1].chainmask = 0xc;
243 }
244 } else if (is_mt7916(an)) {
245 an->anb[0].chainmask = 0x3;
246 an->anb[1].chainmask = 0x3;
247 } else if (is_mt7986(an)) {
248 an->anb[0].chainmask = 0xf;
249 an->anb[1].chainmask = 0xf;
250 }
251}
252
253int atenl_eeprom_init(struct atenl *an, u8 phy_idx)
254{
255 bool flash_mode;
256 int eeprom_fd;
developer2bf395f2022-01-26 20:50:22 +0800257 char buf[30];
developer454c4652022-08-31 20:39:29 +0800258 u8 main_phy_idx = phy_idx;
developer22c7ab62022-01-24 11:13:32 +0800259
260 set_band_val(an, 0, phy_idx, phy_idx);
developer22c7ab62022-01-24 11:13:32 +0800261 atenl_nl_check_mtd(an);
262 flash_mode = an->mtd_part != NULL;
263
developer454c4652022-08-31 20:39:29 +0800264 if (flash_mode)
265 main_phy_idx = an->is_main_phy ? main_phy_idx : (main_phy_idx - 1);
266
267 snprintf(buf, sizeof(buf), "/tmp/atenl-eeprom-phy%u", main_phy_idx);
268 eeprom_file = strdup(buf);
269
developer22c7ab62022-01-24 11:13:32 +0800270 eeprom_fd = atenl_eeprom_init_file(an, flash_mode);
271 if (eeprom_fd < 0)
272 return -1;
273
274 an->eeprom_data = mmap(NULL, EEPROM_PART_SIZE, PROT_READ | PROT_WRITE,
developer454c4652022-08-31 20:39:29 +0800275 MAP_SHARED, eeprom_fd, 0);
developer22c7ab62022-01-24 11:13:32 +0800276 if (!an->eeprom_data) {
277 perror("mmap");
278 close(eeprom_fd);
279 return -1;
280 }
281
282 an->eeprom_fd = eeprom_fd;
developerf30d4472022-05-30 16:40:23 +0800283 atenl_eeprom_init_chip_id(an);
developer22c7ab62022-01-24 11:13:32 +0800284 atenl_eeprom_init_max_size(an);
285 atenl_eeprom_init_band_cap(an);
286 atenl_eeprom_init_antenna_cap(an);
287
288 if (get_band_val(an, 1, valid))
289 set_band_val(an, 1, phy_idx, phy_idx + 1);
290
291 return 0;
292}
293
294void atenl_eeprom_close(struct atenl *an)
295{
296 msync(an->eeprom_data, EEPROM_PART_SIZE, MS_SYNC);
297 munmap(an->eeprom_data, EEPROM_PART_SIZE);
298 close(an->eeprom_fd);
299
developerf30d4472022-05-30 16:40:23 +0800300 if (!an->cmd_mode) {
developer2bf395f2022-01-26 20:50:22 +0800301 if (remove(eeprom_file))
developer22c7ab62022-01-24 11:13:32 +0800302 perror("remove");
developer2bf395f2022-01-26 20:50:22 +0800303 }
304
305 free(eeprom_file);
developer22c7ab62022-01-24 11:13:32 +0800306}
307
developer454c4652022-08-31 20:39:29 +0800308int atenl_eeprom_update_precal(struct atenl *an, int write_offs, int size)
309{
310 u32 offs = an->eeprom_prek_offs;
311 u8 cal_indicator, *eeprom, *pre_cal;
312
313 if (!an->cal && !an->cal_info)
314 return 0;
315
316 eeprom = an->eeprom_data;
317 pre_cal = eeprom + an->eeprom_size;
318 cal_indicator = an->cal_info[4];
319
320 memcpy(eeprom + offs, &cal_indicator, sizeof(u8));
321 memcpy(pre_cal, an->cal_info, PRE_CAL_INFO);
322 pre_cal += (PRE_CAL_INFO + write_offs);
323
324 if (an->cal)
325 memcpy(pre_cal, an->cal, size);
326 else
327 memset(pre_cal, 0, size);
328
329 return 0;
330}
331
developer22c7ab62022-01-24 11:13:32 +0800332int atenl_eeprom_write_mtd(struct atenl *an)
333{
334 bool flash_mode = an->mtd_part != NULL;
335 pid_t pid;
developer454c4652022-08-31 20:39:29 +0800336 char offset[10];
developer22c7ab62022-01-24 11:13:32 +0800337
338 if (!flash_mode)
339 return 0;
340
341 pid = fork();
342 if (pid < 0) {
343 perror("Fork");
344 return EXIT_FAILURE;
345 } else if (pid == 0) {
developer22c7ab62022-01-24 11:13:32 +0800346 int ret;
developer454c4652022-08-31 20:39:29 +0800347 char *part = strdup(an->mtd_part);
348 snprintf(offset, sizeof(offset), "%d", an->mtd_offset);
349 char *cmd[] = {"mtd", "-p", offset, "write", eeprom_file, part, NULL};
developer22c7ab62022-01-24 11:13:32 +0800350
351 ret = execvp("mtd", cmd);
352 if (ret < 0) {
developerf30d4472022-05-30 16:40:23 +0800353 atenl_err("%s: exec error\n", __func__);
developer22c7ab62022-01-24 11:13:32 +0800354 exit(0);
355 }
356 } else {
357 wait(&pid);
358 }
359
360 return 0;
361}
362
developerf30d4472022-05-30 16:40:23 +0800363/* Directly read values from driver's eeprom.
developer22c7ab62022-01-24 11:13:32 +0800364 * It's usally used to get calibrated data from driver.
365 */
366int atenl_eeprom_read_from_driver(struct atenl *an, u32 offset, int len)
367{
368 u8 *eeprom_data = an->eeprom_data + offset;
369 char fname[64], buf[1024];
370 int fd_ori, ret;
371 ssize_t rd;
372
373 snprintf(fname, sizeof(fname),
374 "/sys/kernel/debug/ieee80211/phy%d/mt76/eeprom",
375 get_band_val(an, 0, phy_idx));
376 fd_ori = open(fname, O_RDONLY);
377 if (fd_ori < 0)
378 return -1;
379
380 ret = lseek(fd_ori, offset, SEEK_SET);
381 if (ret < 0)
382 goto out;
383
384 while ((rd = read(fd_ori, buf, sizeof(buf))) > 0 && len) {
385 if (len < rd) {
386 memcpy(eeprom_data, buf, len);
387 break;
388 } else {
389 memcpy(eeprom_data, buf, rd);
390 eeprom_data += rd;
391 len -= rd;
392 }
393 }
394
395 ret = 0;
396out:
397 close(fd_ori);
398 return ret;
399}
400
401/* Update all eeprom values to driver before writing efuse */
402static void
403atenl_eeprom_sync_to_driver(struct atenl *an)
404{
405 int i;
406
developer2bf395f2022-01-26 20:50:22 +0800407 for (i = 0; i < an->eeprom_size; i += 16)
developer22c7ab62022-01-24 11:13:32 +0800408 atenl_nl_write_eeprom(an, i, &an->eeprom_data[i], 16);
409}
410
411void atenl_eeprom_cmd_handler(struct atenl *an, u8 phy_idx, char *cmd)
412{
413 bool flash_mode;
414
415 an->cmd_mode = true;
416
417 atenl_eeprom_init(an, phy_idx);
418 flash_mode = an->mtd_part != NULL;
419
420 if (!strncmp(cmd, "sync eeprom all", 15)) {
421 atenl_eeprom_write_mtd(an);
422 } else if (!strncmp(cmd, "eeprom", 6)) {
423 char *s = strchr(cmd, ' ');
424
425 if (!s) {
developerf30d4472022-05-30 16:40:23 +0800426 atenl_err("eeprom: please type a correct command\n");
developer22c7ab62022-01-24 11:13:32 +0800427 return;
428 }
429
430 s++;
431 if (!strncmp(s, "reset", 5)) {
developer2bf395f2022-01-26 20:50:22 +0800432 unlink(eeprom_file);
developer22c7ab62022-01-24 11:13:32 +0800433 } else if (!strncmp(s, "file", 4)) {
developer2bf395f2022-01-26 20:50:22 +0800434 atenl_info("%s\n", eeprom_file);
developer22c7ab62022-01-24 11:13:32 +0800435 atenl_info("Flash mode: %d\n", flash_mode);
436 } else if (!strncmp(s, "set", 3)) {
437 u32 offset, val;
438
439 s = strchr(s, ' ');
440 if (!s)
441 return;
442 s++;
443
444 if (!sscanf(s, "%x=%x", &offset, &val) ||
445 offset > EEPROM_PART_SIZE)
446 return;
447
448 an->eeprom_data[offset] = val;
449 atenl_info("set offset 0x%x to 0x%x\n", offset, val);
developer48fbcb62022-03-10 14:24:55 +0800450 } else if (!strncmp(s, "update buffermode", 17)) {
developer2bf395f2022-01-26 20:50:22 +0800451 atenl_eeprom_sync_to_driver(an);
developer22c7ab62022-01-24 11:13:32 +0800452 atenl_nl_update_buffer_mode(an);
453 } else if (!strncmp(s, "write", 5)) {
454 s = strchr(s, ' ');
455 if (!s)
456 return;
457 s++;
458
developer48fbcb62022-03-10 14:24:55 +0800459 if (!strncmp(s, "flash", 5)) {
developer22c7ab62022-01-24 11:13:32 +0800460 atenl_eeprom_write_mtd(an);
developer48fbcb62022-03-10 14:24:55 +0800461 } else if (!strncmp(s, "to efuse", 8)) {
462 atenl_eeprom_sync_to_driver(an);
463 atenl_nl_write_efuse_all(an);
464 }
developer22c7ab62022-01-24 11:13:32 +0800465 } else if (!strncmp(s, "read", 4)) {
466 u32 offset;
467
468 s = strchr(s, ' ');
469 if (!s)
470 return;
471 s++;
472
473 if (!sscanf(s, "%x", &offset) ||
474 offset > EEPROM_PART_SIZE)
475 return;
476
477 atenl_info("val = 0x%x (%u)\n", an->eeprom_data[offset],
478 an->eeprom_data[offset]);
developer454c4652022-08-31 20:39:29 +0800479 } else if (!strncmp(s, "precal", 6)) {
480 s = strchr(s, ' ');
481 if (!s)
482 return;
483 s++;
484
485 if (!strncmp(s, "sync group", 10)) {
486 atenl_nl_precal_sync_from_driver(an, PREK_SYNC_GROUP);
487 } else if (!strncmp(s, "sync dpd 2g", 11)) {
488 atenl_nl_precal_sync_from_driver(an, PREK_SYNC_DPD_2G);
489 } else if (!strncmp(s, "sync dpd 5g", 11)) {
490 atenl_nl_precal_sync_from_driver(an, PREK_SYNC_DPD_5G);
491 } else if (!strncmp(s, "sync dpd 6g", 11)) {
492 atenl_nl_precal_sync_from_driver(an, PREK_SYNC_DPD_6G);
493 } else if (!strncmp(s, "group clean", 11)) {
494 atenl_nl_precal_sync_from_driver(an, PREK_CLEAN_GROUP);
495 } else if (!strncmp(s, "dpd clean", 9)) {
496 atenl_nl_precal_sync_from_driver(an, PREK_CLEAN_DPD);
497 } else if (!strncmp(s, "sync", 4)) {
498 atenl_nl_precal_sync_from_driver(an, PREK_SYNC_ALL);
499 }
developer48fbcb62022-03-10 14:24:55 +0800500 } else {
501 atenl_err("Unknown eeprom command: %s\n", cmd);
502 }
developer22c7ab62022-01-24 11:13:32 +0800503 } else {
504 atenl_err("Unknown command: %s\n", cmd);
505 }
506}