blob: 5f060aa1c5a10fdf8b3edaa7e1237f512fa40465 [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>
developerf0677ad2024-11-15 19:28:25 +08006#include <sys/ioctl.h>
7#include <blkid/blkid.h>
developer22c7ab62022-01-24 11:13:32 +08008
9#include "atenl.h"
10
developer8e1f5142023-03-31 17:43:25 +080011#define EEPROM_PART_SIZE 0xFF000
developer2bf395f2022-01-26 20:50:22 +080012char *eeprom_file;
developer22c7ab62022-01-24 11:13:32 +080013
developer0296d8b2022-11-01 11:15:32 +080014static int
15atenl_create_file(struct atenl *an, bool flash_mode)
developer22c7ab62022-01-24 11:13:32 +080016{
developer0296d8b2022-11-01 11:15:32 +080017 char fname[64], buf[1024];
18 ssize_t w, len, max_len, total_len = 0;
19 int fd_ori, fd, ret;
developer22c7ab62022-01-24 11:13:32 +080020
developer0296d8b2022-11-01 11:15:32 +080021 /* reserve space for pre-cal data in flash mode */
22 if (flash_mode) {
developer1042c082023-10-27 19:57:13 +080023 atenl_dbg("%s: init eeprom with flash / binfile mode\n", __func__);
developer0296d8b2022-11-01 11:15:32 +080024 max_len = EEPROM_PART_SIZE;
25 } else {
developer1042c082023-10-27 19:57:13 +080026 atenl_dbg("%s: init eeprom with efuse / default bin mode\n", __func__);
developerbb73fa22022-12-28 22:40:23 +080027 max_len = 0x1e00;
developer22c7ab62022-01-24 11:13:32 +080028 }
developer22c7ab62022-01-24 11:13:32 +080029
developer0296d8b2022-11-01 11:15:32 +080030 snprintf(fname, sizeof(fname),
31 "/sys/kernel/debug/ieee80211/phy%d/mt76/eeprom",
developer86045992024-06-03 16:24:42 +080032 an->main_phy_idx);
developer0296d8b2022-11-01 11:15:32 +080033 fd_ori = open(fname, O_RDONLY);
34 if (fd_ori < 0)
developer22c7ab62022-01-24 11:13:32 +080035 return -1;
developer22c7ab62022-01-24 11:13:32 +080036
developer2bf395f2022-01-26 20:50:22 +080037 fd = open(eeprom_file, O_RDWR | O_CREAT | O_EXCL, 00644);
developer22c7ab62022-01-24 11:13:32 +080038 if (fd < 0)
39 goto out;
40
developer0296d8b2022-11-01 11:15:32 +080041 while ((len = read(fd_ori, buf, sizeof(buf))) > 0) {
developer22c7ab62022-01-24 11:13:32 +080042retry:
43 w = write(fd, buf, len);
developerf30d4472022-05-30 16:40:23 +080044 if (w > 0) {
developer0296d8b2022-11-01 11:15:32 +080045 total_len += len;
developer22c7ab62022-01-24 11:13:32 +080046 continue;
developerf30d4472022-05-30 16:40:23 +080047 }
developer22c7ab62022-01-24 11:13:32 +080048
49 if (errno == EINTR)
50 goto retry;
51
52 perror("write");
developer2bf395f2022-01-26 20:50:22 +080053 unlink(eeprom_file);
developer22c7ab62022-01-24 11:13:32 +080054 close(fd);
55 fd = -1;
56 goto out;
57 }
58
developer0296d8b2022-11-01 11:15:32 +080059 /* reserve space for pre-cal data in flash mode */
60 len = sizeof(buf);
61 memset(buf, 0, len);
62 while (total_len < max_len) {
developer22c7ab62022-01-24 11:13:32 +080063 w = write(fd, buf, len);
developer22c7ab62022-01-24 11:13:32 +080064
developer0296d8b2022-11-01 11:15:32 +080065 if (w > 0) {
66 total_len += len;
67 continue;
68 }
developer22c7ab62022-01-24 11:13:32 +080069
developer0296d8b2022-11-01 11:15:32 +080070 if (errno != EINTR) {
71 perror("write");
72 unlink(eeprom_file);
73 close(fd);
74 fd = -1;
75 goto out;
76 }
developer22c7ab62022-01-24 11:13:32 +080077 }
78
developer0296d8b2022-11-01 11:15:32 +080079
developer22c7ab62022-01-24 11:13:32 +080080 ret = lseek(fd, 0, SEEK_SET);
81 if (ret) {
82 close(fd_ori);
83 close(fd);
84 return ret;
85 }
86
87out:
88 close(fd_ori);
89 return fd;
90}
91
92static bool
93atenl_eeprom_file_exists(void)
94{
95 struct stat st;
96
developer2bf395f2022-01-26 20:50:22 +080097 return stat(eeprom_file, &st) == 0;
developer22c7ab62022-01-24 11:13:32 +080098}
99
100static int
101atenl_eeprom_init_file(struct atenl *an, bool flash_mode)
102{
103 int fd;
104
developer0296d8b2022-11-01 11:15:32 +0800105 if (!atenl_eeprom_file_exists())
106 return atenl_create_file(an, flash_mode);
developer22c7ab62022-01-24 11:13:32 +0800107
developer2bf395f2022-01-26 20:50:22 +0800108 fd = open(eeprom_file, O_RDWR);
developer22c7ab62022-01-24 11:13:32 +0800109 if (fd < 0)
110 perror("open");
111
developer22c7ab62022-01-24 11:13:32 +0800112 return fd;
113}
114
115static void
developerf30d4472022-05-30 16:40:23 +0800116atenl_eeprom_init_chip_id(struct atenl *an)
117{
118 an->chip_id = *(u16 *)an->eeprom_data;
119
120 if (is_mt7915(an)) {
121 an->adie_id = 0x7975;
developerae49e8a2023-10-31 16:53:21 +0800122 } else if (is_mt7916(an) || is_mt7981(an)) {
developerf30d4472022-05-30 16:40:23 +0800123 an->adie_id = 0x7976;
124 } else if (is_mt7986(an)) {
125 bool is_7975 = false;
126 u32 val;
127 u8 sub_id;
128
129 atenl_reg_read(an, 0x18050000, &val);
130
131 switch (val & 0xf) {
132 case MT7975_ONE_ADIE_SINGLE_BAND:
133 is_7975 = true;
134 /* fallthrough */
135 case MT7976_ONE_ADIE_SINGLE_BAND:
136 sub_id = 0xa;
137 break;
138 case MT7976_ONE_ADIE_DBDC:
139 sub_id = 0x7;
140 break;
141 case MT7975_DUAL_ADIE_DBDC:
142 is_7975 = true;
143 /* fallthrough */
144 case MT7976_DUAL_ADIE_DBDC:
145 default:
146 sub_id = 0xf;
147 break;
148 }
149
150 an->sub_chip_id = sub_id;
151 an->adie_id = is_7975 ? 0x7975 : 0x7976;
developerbb73fa22022-12-28 22:40:23 +0800152 } else if (is_mt7996(an)) {
153 /* TODO: parse info if required */
developere2e8ccc2023-10-13 18:41:57 +0800154 } else if (is_mt7992(an)) {
155 /* TODO: parse info if required */
developer9efec3f2024-09-23 13:43:05 +0800156 } else if (is_mt7990(an)) {
157 /* TODO: parse info if required */
developerf30d4472022-05-30 16:40:23 +0800158 }
159}
160
161static void
developer22c7ab62022-01-24 11:13:32 +0800162atenl_eeprom_init_max_size(struct atenl *an)
163{
164 switch (an->chip_id) {
developer9efec3f2024-09-23 13:43:05 +0800165 case MT7915_DEVICE_ID:
developer22c7ab62022-01-24 11:13:32 +0800166 an->eeprom_size = 3584;
developer454c4652022-08-31 20:39:29 +0800167 an->eeprom_prek_offs = 0x62;
developer22c7ab62022-01-24 11:13:32 +0800168 break;
developer9efec3f2024-09-23 13:43:05 +0800169 case MT7916_EEPROM_CHIP_ID:
170 case MT7916_DEVICE_ID:
171 case MT7981_DEVICE_ID:
172 case MT7986_DEVICE_ID:
developer22c7ab62022-01-24 11:13:32 +0800173 an->eeprom_size = 4096;
developer454c4652022-08-31 20:39:29 +0800174 an->eeprom_prek_offs = 0x19a;
developer22c7ab62022-01-24 11:13:32 +0800175 break;
developer9efec3f2024-09-23 13:43:05 +0800176 case MT7996_DEVICE_ID:
177 case MT7992_DEVICE_ID:
178 case MT7990_DEVICE_ID:
developerbb73fa22022-12-28 22:40:23 +0800179 an->eeprom_size = 7680;
180 an->eeprom_prek_offs = 0x1a5;
developer22c7ab62022-01-24 11:13:32 +0800181 default:
182 break;
183 }
184}
185
186static void
187atenl_eeprom_init_band_cap(struct atenl *an)
188{
developerbb73fa22022-12-28 22:40:23 +0800189#define EAGLE_BAND_SEL(index) MT_EE_WIFI_EAGLE_CONF##index##_BAND_SEL
developer22c7ab62022-01-24 11:13:32 +0800190 u8 *eeprom = an->eeprom_data;
191
192 if (is_mt7915(an)) {
193 u8 val = eeprom[MT_EE_WIFI_CONF];
194 u8 band_sel = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val);
195 struct atenl_band *anb = &an->anb[0];
196
197 /* MT7915A */
198 if (band_sel == MT_EE_BAND_SEL_DEFAULT) {
199 anb->valid = true;
200 anb->cap = BAND_TYPE_2G_5G;
201 return;
202 }
203
204 /* MT7915D */
205 if (band_sel == MT_EE_BAND_SEL_2GHZ) {
206 anb->valid = true;
207 anb->cap = BAND_TYPE_2G;
208 }
209
210 val = eeprom[MT_EE_WIFI_CONF + 1];
211 band_sel = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val);
212 anb++;
213
214 if (band_sel == MT_EE_BAND_SEL_5GHZ) {
215 anb->valid = true;
216 anb->cap = BAND_TYPE_5G;
217 }
developerae49e8a2023-10-31 16:53:21 +0800218 } else if (is_mt7916(an) || is_mt7981(an) || is_mt7986(an)) {
developer22c7ab62022-01-24 11:13:32 +0800219 struct atenl_band *anb;
220 u8 val, band_sel;
221 int i;
222
223 for (i = 0; i < 2; i++) {
224 val = eeprom[MT_EE_WIFI_CONF + i];
225 band_sel = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val);
226 anb = &an->anb[i];
227
228 anb->valid = true;
229 switch (band_sel) {
230 case MT_EE_BAND_SEL_2G:
231 anb->cap = BAND_TYPE_2G;
232 break;
233 case MT_EE_BAND_SEL_5G:
234 anb->cap = BAND_TYPE_5G;
235 break;
236 case MT_EE_BAND_SEL_6G:
237 anb->cap = BAND_TYPE_6G;
238 break;
239 case MT_EE_BAND_SEL_5G_6G:
240 anb->cap = BAND_TYPE_5G_6G;
241 break;
242 default:
243 break;
244 }
245 }
developerbb73fa22022-12-28 22:40:23 +0800246 } else if (is_mt7996(an)) {
247 struct atenl_band *anb;
248 u8 val, band_sel;
249 u8 band_sel_mask[3] = {EAGLE_BAND_SEL(0), EAGLE_BAND_SEL(1),
250 EAGLE_BAND_SEL(2)};
251 int i;
252
253 for (i = 0; i < 3; i++) {
254 val = eeprom[MT_EE_WIFI_CONF + i];
255 band_sel = FIELD_GET(band_sel_mask[i], val);
256 anb = &an->anb[i];
257
258 anb->valid = true;
259 switch (band_sel) {
260 case MT_EE_EAGLE_BAND_SEL_2GHZ:
261 anb->cap = BAND_TYPE_2G;
262 break;
developer9efec3f2024-09-23 13:43:05 +0800263 case MT_EE_EAGLE_BAND_SEL_5GHZ_LOW:
264 case MT_EE_EAGLE_BAND_SEL_5GHZ_HIGH:
developerbb73fa22022-12-28 22:40:23 +0800265 case MT_EE_EAGLE_BAND_SEL_5GHZ:
266 anb->cap = BAND_TYPE_5G;
267 break;
developer9efec3f2024-09-23 13:43:05 +0800268 case MT_EE_EAGLE_BAND_SEL_6GHZ_LOW:
269 case MT_EE_EAGLE_BAND_SEL_6GHZ_HIGH:
developerbb73fa22022-12-28 22:40:23 +0800270 case MT_EE_EAGLE_BAND_SEL_6GHZ:
271 anb->cap = BAND_TYPE_6G;
272 break;
developerbb73fa22022-12-28 22:40:23 +0800273 default:
274 break;
275 }
276 }
developer9efec3f2024-09-23 13:43:05 +0800277 } else if (is_mt7992(an) || is_mt7990(an)) {
developere2e8ccc2023-10-13 18:41:57 +0800278 struct atenl_band *anb;
279 u8 val, band_sel;
280 u8 band_sel_mask[2] = {EAGLE_BAND_SEL(0), EAGLE_BAND_SEL(1)};
281 int i;
282
283 for (i = 0; i < 2; i++) {
284 val = eeprom[MT_EE_WIFI_CONF + i];
285 band_sel = FIELD_GET(band_sel_mask[i], val);
286 anb = &an->anb[i];
287
288 anb->valid = true;
289 switch (band_sel) {
290 case MT_EE_EAGLE_BAND_SEL_2GHZ:
291 anb->cap = BAND_TYPE_2G;
292 break;
developer9efec3f2024-09-23 13:43:05 +0800293 case MT_EE_EAGLE_BAND_SEL_5GHZ_LOW:
294 case MT_EE_EAGLE_BAND_SEL_5GHZ_HIGH:
developere2e8ccc2023-10-13 18:41:57 +0800295 case MT_EE_EAGLE_BAND_SEL_5GHZ:
296 anb->cap = BAND_TYPE_5G;
297 break;
developer9efec3f2024-09-23 13:43:05 +0800298 case MT_EE_EAGLE_BAND_SEL_6GHZ_LOW:
299 case MT_EE_EAGLE_BAND_SEL_6GHZ_HIGH:
developere2e8ccc2023-10-13 18:41:57 +0800300 case MT_EE_EAGLE_BAND_SEL_6GHZ:
301 anb->cap = BAND_TYPE_6G;
302 break;
developere2e8ccc2023-10-13 18:41:57 +0800303 default:
304 break;
305 }
306 }
developer22c7ab62022-01-24 11:13:32 +0800307 }
308}
309
310static void
311atenl_eeprom_init_antenna_cap(struct atenl *an)
312{
developere2e8ccc2023-10-13 18:41:57 +0800313 switch (an->chip_id) {
developer9efec3f2024-09-23 13:43:05 +0800314 case MT7915_DEVICE_ID:
developer22c7ab62022-01-24 11:13:32 +0800315 if (an->anb[0].cap == BAND_TYPE_2G_5G)
316 an->anb[0].chainmask = 0xf;
317 else {
318 an->anb[0].chainmask = 0x3;
319 an->anb[1].chainmask = 0xc;
320 }
developere2e8ccc2023-10-13 18:41:57 +0800321 break;
developer9efec3f2024-09-23 13:43:05 +0800322 case MT7916_EEPROM_CHIP_ID:
323 case MT7916_DEVICE_ID:
developer22c7ab62022-01-24 11:13:32 +0800324 an->anb[0].chainmask = 0x3;
325 an->anb[1].chainmask = 0x3;
developere2e8ccc2023-10-13 18:41:57 +0800326 break;
developer9efec3f2024-09-23 13:43:05 +0800327 case MT7981_DEVICE_ID:
developerae49e8a2023-10-31 16:53:21 +0800328 an->anb[0].chainmask = 0x3;
329 an->anb[1].chainmask = 0x7;
330 break;
developer9efec3f2024-09-23 13:43:05 +0800331 case MT7986_DEVICE_ID:
developer22c7ab62022-01-24 11:13:32 +0800332 an->anb[0].chainmask = 0xf;
333 an->anb[1].chainmask = 0xf;
developere2e8ccc2023-10-13 18:41:57 +0800334 break;
developer9efec3f2024-09-23 13:43:05 +0800335 case MT7996_DEVICE_ID:
336 /* TODO: handle 4T5R */
developerbb73fa22022-12-28 22:40:23 +0800337 an->anb[0].chainmask = 0xf;
338 an->anb[1].chainmask = 0xf;
339 an->anb[2].chainmask = 0xf;
developere2e8ccc2023-10-13 18:41:57 +0800340 break;
developer9efec3f2024-09-23 13:43:05 +0800341 case MT7992_DEVICE_ID:
342 /* TODO: handle BE7200 2i5i 5T5R */
developere2e8ccc2023-10-13 18:41:57 +0800343 an->anb[0].chainmask = 0xf;
344 an->anb[1].chainmask = 0xf;
345 break;
developer9efec3f2024-09-23 13:43:05 +0800346 case MT7990_DEVICE_ID:
347 an->anb[0].chainmask = 0x3;
348 an->anb[1].chainmask = 0x7;
349 break;
developere2e8ccc2023-10-13 18:41:57 +0800350 default:
351 break;
developer22c7ab62022-01-24 11:13:32 +0800352 }
353}
354
355int atenl_eeprom_init(struct atenl *an, u8 phy_idx)
356{
357 bool flash_mode;
358 int eeprom_fd;
developer2bf395f2022-01-26 20:50:22 +0800359 char buf[30];
developer22c7ab62022-01-24 11:13:32 +0800360
361 set_band_val(an, 0, phy_idx, phy_idx);
developerf0677ad2024-11-15 19:28:25 +0800362 atenl_nl_check_flash(an);
363 flash_mode = an->flash_part != NULL;
developer22c7ab62022-01-24 11:13:32 +0800364
developerbb73fa22022-12-28 22:40:23 +0800365 // Get the first main phy index for this chip
developer86045992024-06-03 16:24:42 +0800366 an->main_phy_idx = phy_idx - an->band_idx;
367 snprintf(buf, sizeof(buf), "/tmp/atenl-eeprom-phy%u", an->main_phy_idx);
developer454c4652022-08-31 20:39:29 +0800368 eeprom_file = strdup(buf);
369
developer22c7ab62022-01-24 11:13:32 +0800370 eeprom_fd = atenl_eeprom_init_file(an, flash_mode);
371 if (eeprom_fd < 0)
372 return -1;
373
374 an->eeprom_data = mmap(NULL, EEPROM_PART_SIZE, PROT_READ | PROT_WRITE,
developer454c4652022-08-31 20:39:29 +0800375 MAP_SHARED, eeprom_fd, 0);
developer22c7ab62022-01-24 11:13:32 +0800376 if (!an->eeprom_data) {
377 perror("mmap");
378 close(eeprom_fd);
379 return -1;
380 }
381
382 an->eeprom_fd = eeprom_fd;
developerf30d4472022-05-30 16:40:23 +0800383 atenl_eeprom_init_chip_id(an);
developer22c7ab62022-01-24 11:13:32 +0800384 atenl_eeprom_init_max_size(an);
385 atenl_eeprom_init_band_cap(an);
386 atenl_eeprom_init_antenna_cap(an);
387
388 if (get_band_val(an, 1, valid))
389 set_band_val(an, 1, phy_idx, phy_idx + 1);
390
developer86869102023-05-15 13:52:35 +0800391 if (get_band_val(an, 2, valid))
392 set_band_val(an, 2, phy_idx, phy_idx + 2);
393
developer22c7ab62022-01-24 11:13:32 +0800394 return 0;
395}
396
397void atenl_eeprom_close(struct atenl *an)
398{
399 msync(an->eeprom_data, EEPROM_PART_SIZE, MS_SYNC);
400 munmap(an->eeprom_data, EEPROM_PART_SIZE);
401 close(an->eeprom_fd);
402
developerf30d4472022-05-30 16:40:23 +0800403 if (!an->cmd_mode) {
developer2bf395f2022-01-26 20:50:22 +0800404 if (remove(eeprom_file))
developer22c7ab62022-01-24 11:13:32 +0800405 perror("remove");
developer2bf395f2022-01-26 20:50:22 +0800406 }
407
408 free(eeprom_file);
developer22c7ab62022-01-24 11:13:32 +0800409}
410
developer454c4652022-08-31 20:39:29 +0800411int atenl_eeprom_update_precal(struct atenl *an, int write_offs, int size)
412{
413 u32 offs = an->eeprom_prek_offs;
414 u8 cal_indicator, *eeprom, *pre_cal;
415
416 if (!an->cal && !an->cal_info)
417 return 0;
418
419 eeprom = an->eeprom_data;
420 pre_cal = eeprom + an->eeprom_size;
421 cal_indicator = an->cal_info[4];
422
423 memcpy(eeprom + offs, &cal_indicator, sizeof(u8));
424 memcpy(pre_cal, an->cal_info, PRE_CAL_INFO);
425 pre_cal += (PRE_CAL_INFO + write_offs);
426
427 if (an->cal)
428 memcpy(pre_cal, an->cal, size);
429 else
430 memset(pre_cal, 0, size);
431
432 return 0;
433}
434
developerf0677ad2024-11-15 19:28:25 +0800435int atenl_mtd_open(struct atenl *an, int flags)
developer22c7ab62022-01-24 11:13:32 +0800436{
developerf0677ad2024-11-15 19:28:25 +0800437 char dev[128], buf[16];
438 char *part_num;
439 FILE *f;
440 int fd;
441
442 f = fopen("/proc/mtd", "r");
443 if (!f)
444 return -1;
445
446 while (fgets(dev, sizeof(dev), f)) {
447 if (!strcasestr(dev, an->flash_part))
448 continue;
449
450 part_num = strtok(dev, ":");
451 if (part_num)
452 break;
453 }
454
455 fclose(f);
456
457 if (!part_num)
458 return -1;
459
460 /* mtdblockX emulates an mtd device as a block device.
461 * Use mtdblockX instead of mtdX to avoid padding & buffer handling.
462 */
463 snprintf(buf, sizeof(buf), "/dev/mtdblock%s", part_num + 3);
464
465 fd = open(buf, flags);
466
467 return fd;
468}
469
470int atenl_mmc_open(struct atenl *an, int flags)
471{
472 const char *mmc_dev = "/dev/mmcblk0";
473 int nparts, part_num;
474 blkid_partlist plist;
475 blkid_probe probe;
476 int i, fd = -1;
477 char buf[16];
478
479 probe = blkid_new_probe_from_filename(mmc_dev);
480 if (!probe)
481 return -1;
482
483 plist = blkid_probe_get_partitions(probe);
484 if (!plist)
485 goto out;
486
487 nparts = blkid_partlist_numof_partitions(plist);
488 if (!nparts)
489 goto out;
490
491 for (i = 0; i < nparts; i++) {
492 blkid_partition part;
493 const char *name;
494
495 part = blkid_partlist_get_partition(plist, i);
496 if (!part)
497 continue;
498
499 name = blkid_partition_get_name(part);
500 if (!name)
501 continue;
502
503 if (strncasecmp(name, an->flash_part, strlen(an->flash_part)))
504 continue;
505
506 part_num = blkid_partition_get_partno(part);
507 snprintf(buf, sizeof(buf), "%sp%d", mmc_dev, part_num);
508
509 fd = open(buf, flags);
510 if (fd >= 0)
511 break;
512 }
513
514out:
515 blkid_free_probe(probe);
516 return fd;
517}
518
519void atenl_flash_write(struct atenl *an, int fd, u32 size, bool is_mtd)
520{
521 u32 flash_size, offs;
522 int ret;
523
524 flash_size = lseek(fd, 0, SEEK_END);
525 if (size > flash_size)
526 return;
527
528 offs = an->flash_offset;
529 ret = lseek(fd, offs, SEEK_SET);
530 if (ret < 0)
531 return;
532
533 ret = write(fd, an->eeprom_data, size);
534 if (ret < 0)
535 return;
536
537 atenl_info("write to %s partition %s offset 0x%x size 0x%x\n",
538 is_mtd ? "mtd" : "mmc", an->flash_part, offs, size);
539}
540
541int atenl_eeprom_write_flash(struct atenl *an)
542{
developer091f3342023-11-10 11:26:03 +0800543 u32 size = an->eeprom_size;
developerf0677ad2024-11-15 19:28:25 +0800544 u32 precal_size, *precal_info;
545 int fd;
developer22c7ab62022-01-24 11:13:32 +0800546
developerf0677ad2024-11-15 19:28:25 +0800547 /* flash_offset = -1 for binfile mode */
548 if (an->flash_part == NULL || !(~an->flash_offset)) {
549 atenl_err("Flash partition or offset is not specified\n");
developer22c7ab62022-01-24 11:13:32 +0800550 return 0;
developerf0677ad2024-11-15 19:28:25 +0800551 }
552
553 precal_info = (u32 *)(an->eeprom_data + size);
554 precal_size = precal_info[0] + precal_info[1];
developer22c7ab62022-01-24 11:13:32 +0800555
developer091f3342023-11-10 11:26:03 +0800556 if (precal_size)
557 size += PRE_CAL_INFO + precal_size;
558
developerf0677ad2024-11-15 19:28:25 +0800559 fd = atenl_mtd_open(an, O_RDWR | O_SYNC);
560 if (fd >= 0) {
561 atenl_flash_write(an, fd, size, true);
562 goto out;
563 }
developer091f3342023-11-10 11:26:03 +0800564
developerf0677ad2024-11-15 19:28:25 +0800565 fd = atenl_mmc_open(an, O_RDWR | O_SYNC);
566 if (fd >= 0) {
567 atenl_flash_write(an, fd, size, false);
568 goto out;
569 }
developer22c7ab62022-01-24 11:13:32 +0800570
developerf0677ad2024-11-15 19:28:25 +0800571 atenl_err("Fail to open %s\n", an->flash_part);
developer22c7ab62022-01-24 11:13:32 +0800572
developerf0677ad2024-11-15 19:28:25 +0800573out:
574 close(fd);
developer22c7ab62022-01-24 11:13:32 +0800575 return 0;
576}
577
developerf30d4472022-05-30 16:40:23 +0800578/* Directly read values from driver's eeprom.
developer22c7ab62022-01-24 11:13:32 +0800579 * It's usally used to get calibrated data from driver.
580 */
581int atenl_eeprom_read_from_driver(struct atenl *an, u32 offset, int len)
582{
583 u8 *eeprom_data = an->eeprom_data + offset;
584 char fname[64], buf[1024];
585 int fd_ori, ret;
586 ssize_t rd;
587
588 snprintf(fname, sizeof(fname),
589 "/sys/kernel/debug/ieee80211/phy%d/mt76/eeprom",
developer86045992024-06-03 16:24:42 +0800590 an->main_phy_idx);
developer22c7ab62022-01-24 11:13:32 +0800591 fd_ori = open(fname, O_RDONLY);
592 if (fd_ori < 0)
593 return -1;
594
595 ret = lseek(fd_ori, offset, SEEK_SET);
596 if (ret < 0)
597 goto out;
598
599 while ((rd = read(fd_ori, buf, sizeof(buf))) > 0 && len) {
600 if (len < rd) {
601 memcpy(eeprom_data, buf, len);
602 break;
603 } else {
604 memcpy(eeprom_data, buf, rd);
605 eeprom_data += rd;
606 len -= rd;
607 }
608 }
609
610 ret = 0;
611out:
612 close(fd_ori);
613 return ret;
614}
615
developerdcf5eb32024-09-03 17:06:32 +0800616/* Update all eeprom values to driver before writing efuse or ext eeprom */
developer22c7ab62022-01-24 11:13:32 +0800617static void
618atenl_eeprom_sync_to_driver(struct atenl *an)
619{
620 int i;
621
developer2bf395f2022-01-26 20:50:22 +0800622 for (i = 0; i < an->eeprom_size; i += 16)
developer22c7ab62022-01-24 11:13:32 +0800623 atenl_nl_write_eeprom(an, i, &an->eeprom_data[i], 16);
624}
625
626void atenl_eeprom_cmd_handler(struct atenl *an, u8 phy_idx, char *cmd)
627{
developer22c7ab62022-01-24 11:13:32 +0800628 an->cmd_mode = true;
629
630 atenl_eeprom_init(an, phy_idx);
developer22c7ab62022-01-24 11:13:32 +0800631
632 if (!strncmp(cmd, "sync eeprom all", 15)) {
developerf0677ad2024-11-15 19:28:25 +0800633 atenl_eeprom_write_flash(an);
developer22c7ab62022-01-24 11:13:32 +0800634 } else if (!strncmp(cmd, "eeprom", 6)) {
635 char *s = strchr(cmd, ' ');
636
637 if (!s) {
developerf30d4472022-05-30 16:40:23 +0800638 atenl_err("eeprom: please type a correct command\n");
developer22c7ab62022-01-24 11:13:32 +0800639 return;
640 }
641
642 s++;
643 if (!strncmp(s, "reset", 5)) {
developer2bf395f2022-01-26 20:50:22 +0800644 unlink(eeprom_file);
developer22c7ab62022-01-24 11:13:32 +0800645 } else if (!strncmp(s, "file", 4)) {
developer2bf395f2022-01-26 20:50:22 +0800646 atenl_info("%s\n", eeprom_file);
developerf0677ad2024-11-15 19:28:25 +0800647 if (an->flash_part != NULL)
developer1042c082023-10-27 19:57:13 +0800648 atenl_info("%s mode\n",
developerf0677ad2024-11-15 19:28:25 +0800649 ~an->flash_offset == 0 ? "Binfile" : "Flash");
developer1042c082023-10-27 19:57:13 +0800650 else
651 atenl_info("Efuse / Default bin mode\n");
developer22c7ab62022-01-24 11:13:32 +0800652 } else if (!strncmp(s, "set", 3)) {
653 u32 offset, val;
654
655 s = strchr(s, ' ');
656 if (!s)
657 return;
658 s++;
659
660 if (!sscanf(s, "%x=%x", &offset, &val) ||
661 offset > EEPROM_PART_SIZE)
662 return;
663
664 an->eeprom_data[offset] = val;
665 atenl_info("set offset 0x%x to 0x%x\n", offset, val);
developer48fbcb62022-03-10 14:24:55 +0800666 } else if (!strncmp(s, "update buffermode", 17)) {
developer2bf395f2022-01-26 20:50:22 +0800667 atenl_eeprom_sync_to_driver(an);
developer22c7ab62022-01-24 11:13:32 +0800668 atenl_nl_update_buffer_mode(an);
669 } else if (!strncmp(s, "write", 5)) {
670 s = strchr(s, ' ');
671 if (!s)
672 return;
673 s++;
674
developer48fbcb62022-03-10 14:24:55 +0800675 if (!strncmp(s, "flash", 5)) {
developerf0677ad2024-11-15 19:28:25 +0800676 atenl_eeprom_write_flash(an);
developere2e8ccc2023-10-13 18:41:57 +0800677 } else if (!strncmp(s, "to efuse", 8)) {
678 atenl_eeprom_sync_to_driver(an);
679 atenl_nl_write_efuse_all(an);
developerdcf5eb32024-09-03 17:06:32 +0800680 } else if (!strncmp(s, "to ext", 6)) {
681 atenl_eeprom_sync_to_driver(an);
682 atenl_nl_write_ext_eeprom_all(an);
developere2e8ccc2023-10-13 18:41:57 +0800683 }
developer22c7ab62022-01-24 11:13:32 +0800684 } else if (!strncmp(s, "read", 4)) {
685 u32 offset;
686
687 s = strchr(s, ' ');
688 if (!s)
689 return;
690 s++;
691
692 if (!sscanf(s, "%x", &offset) ||
693 offset > EEPROM_PART_SIZE)
694 return;
695
696 atenl_info("val = 0x%x (%u)\n", an->eeprom_data[offset],
697 an->eeprom_data[offset]);
developer454c4652022-08-31 20:39:29 +0800698 } else if (!strncmp(s, "precal", 6)) {
699 s = strchr(s, ' ');
700 if (!s)
701 return;
702 s++;
703
704 if (!strncmp(s, "sync group", 10)) {
705 atenl_nl_precal_sync_from_driver(an, PREK_SYNC_GROUP);
706 } else if (!strncmp(s, "sync dpd 2g", 11)) {
707 atenl_nl_precal_sync_from_driver(an, PREK_SYNC_DPD_2G);
708 } else if (!strncmp(s, "sync dpd 5g", 11)) {
709 atenl_nl_precal_sync_from_driver(an, PREK_SYNC_DPD_5G);
710 } else if (!strncmp(s, "sync dpd 6g", 11)) {
711 atenl_nl_precal_sync_from_driver(an, PREK_SYNC_DPD_6G);
712 } else if (!strncmp(s, "group clean", 11)) {
713 atenl_nl_precal_sync_from_driver(an, PREK_CLEAN_GROUP);
714 } else if (!strncmp(s, "dpd clean", 9)) {
715 atenl_nl_precal_sync_from_driver(an, PREK_CLEAN_DPD);
716 } else if (!strncmp(s, "sync", 4)) {
717 atenl_nl_precal_sync_from_driver(an, PREK_SYNC_ALL);
718 }
developer25a27292023-07-21 13:42:14 +0800719 } else if (!strncmp(s, "ibf sync", 8)) {
720 atenl_get_ibf_cal_result(an);
developer48fbcb62022-03-10 14:24:55 +0800721 } else {
developer25a27292023-07-21 13:42:14 +0800722 atenl_err("Unknown eeprom command: %s\n", cmd);
723 }
developer22c7ab62022-01-24 11:13:32 +0800724 } else {
725 atenl_err("Unknown command: %s\n", cmd);
726 }
727}