blob: 54d2da644c0152a56d65a5d25efb3b4d87b0f3b8 [file] [log] [blame]
developerd0c89452024-10-11 16:53:27 +08001From 47862d9e7019f0e7524beb819bc875404cf687bd Mon Sep 17 00:00:00 2001
2From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
3Date: Thu, 22 Aug 2024 23:22:46 +0800
4Subject: [PATCH 189/223] mtk: mt76: mt7996: add external eeprom support
5
6Add external eeprom support
7For Kite and Griffin, efuse mode is not supported due to the lack of
8space in efuse.
9So, an additional external eeprom is added for user to store their
10golden eeprom.
11
12Note that the FW currently has some issues with writing to the ext
13eeprom, so the write back function of ext eeprom is not yet linked
14to any command.
15A write back command will be added once the FW fixes the issue.
16
17Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
18Change-Id: Ie36469700f9620806e6513ffaf076338841ba7c3
19---
20 debugfs.c | 2 +
21 mt76.h | 1 +
22 mt76_connac_mcu.h | 1 +
23 mt7996/debugfs.c | 57 ++++++++++++++++++-
24 mt7996/eeprom.c | 35 +++++++-----
25 mt7996/eeprom.h | 7 ---
26 mt7996/init.c | 3 +-
27 mt7996/mcu.c | 130 ++++++++++++++++++++++++++++++++++---------
28 mt7996/mcu.h | 35 +++++++++++-
29 mt7996/mt7996.h | 30 +++++++++-
30 mt7996/mtk_debugfs.c | 3 +
31 mt7996/testmode.c | 39 ++++++++-----
32 testmode.h | 2 +
33 13 files changed, 277 insertions(+), 68 deletions(-)
34
35diff --git a/debugfs.c b/debugfs.c
36index ac5207e5..2ded5c03 100644
37--- a/debugfs.c
38+++ b/debugfs.c
39@@ -121,6 +121,8 @@ mt76_register_debugfs_fops(struct mt76_phy *phy,
40 debugfs_create_blob("eeprom", 0400, dir, &dev->eeprom);
41 if (dev->otp.data)
42 debugfs_create_blob("otp", 0400, dir, &dev->otp);
43+ if (dev->ext_eeprom.data)
44+ debugfs_create_blob("ext_eeprom", 0400, dir, &dev->ext_eeprom);
45 debugfs_create_devm_seqfile(dev->dev, "rx-queues", dir,
46 mt76_rx_queues_read);
47
48diff --git a/mt76.h b/mt76.h
49index a465785f..c319ba26 100644
50--- a/mt76.h
51+++ b/mt76.h
52@@ -1065,6 +1065,7 @@ struct mt76_dev {
53
54 struct debugfs_blob_wrapper eeprom;
55 struct debugfs_blob_wrapper otp;
56+ struct debugfs_blob_wrapper ext_eeprom;
57
58 char alpha2[3];
59 enum nl80211_dfs_regions region;
60diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
61index 68d7c31d..25d5f9f9 100644
62--- a/mt76_connac_mcu.h
63+++ b/mt76_connac_mcu.h
64@@ -1325,6 +1325,7 @@ enum {
65 MCU_UNI_CMD_PER_STA_INFO = 0x6d,
66 MCU_UNI_CMD_ALL_STA_INFO = 0x6e,
67 MCU_UNI_CMD_ASSERT_DUMP = 0x6f,
68+ MCU_UNI_CMD_EXT_EEPROM_CTRL = 0x74,
69 MCU_UNI_CMD_PTA_3WIRE_CTRL = 0x78,
70 MCU_UNI_CMD_MLD = 0x82,
71 MCU_UNI_CMD_PEER_MLD = 0x83,
72diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c
73index 240c6d46..d06fb587 100644
74--- a/mt7996/debugfs.c
75+++ b/mt7996/debugfs.c
76@@ -972,7 +972,9 @@ mt7996_efuse_get(struct file *file, char __user *user_buf,
77 block_num = DIV_ROUND_UP(mdev->otp.size, MT7996_EEPROM_BLOCK_SIZE);
78 for (i = 0; i < block_num; i++) {
79 buff = mdev->otp.data + i * MT7996_EEPROM_BLOCK_SIZE;
80- ret = mt7996_mcu_get_eeprom(dev, i * MT7996_EEPROM_BLOCK_SIZE, buff);
81+ ret = mt7996_mcu_get_eeprom(dev, i * MT7996_EEPROM_BLOCK_SIZE,
82+ buff, MT7996_EEPROM_BLOCK_SIZE,
83+ EFUSE_MODE);
84 if (ret && ret != -EINVAL)
85 return ret;
86 }
87@@ -989,6 +991,58 @@ static const struct file_operations mt7996_efuse_ops = {
88 .llseek = default_llseek,
89 };
90
91+static ssize_t
92+mt7996_ext_eeprom_get(struct file *file, char __user *user_buf,
93+ size_t count, loff_t *ppos)
94+{
95+ struct mt7996_dev *dev = file->private_data;
96+ struct mt76_dev *mdev = &dev->mt76;
97+ u8 *buff = mdev->ext_eeprom.data;
98+ u32 block_num, block_size = MT7996_EXT_EEPROM_BLOCK_SIZE;
99+ int i;
100+ ssize_t ret;
101+
102+ if (!mt7996_has_ext_eeprom(dev)) {
103+ dev_info(dev->mt76.dev, "No external eeprom device found\n");
104+ return 0;
105+ }
106+
107+ mdev->ext_eeprom.size = MT7996_EEPROM_SIZE;
108+
109+ if (!mdev->ext_eeprom.data) {
110+ mdev->ext_eeprom.data = devm_kzalloc(mdev->dev,
111+ mdev->ext_eeprom.size,
112+ GFP_KERNEL);
113+ if (!mdev->ext_eeprom.data)
114+ return -ENOMEM;
115+
116+ block_num = DIV_ROUND_UP(mdev->ext_eeprom.size, block_size);
117+ for (i = 0; i < block_num; i++) {
118+ u32 buf_len = block_size;
119+ u32 offset = i * block_size;
120+
121+ if (offset + block_size > mdev->ext_eeprom.size)
122+ buf_len = mdev->ext_eeprom.size % block_size;
123+ buff = mdev->ext_eeprom.data + offset;
124+ ret = mt7996_mcu_get_eeprom(dev, offset, buff, buf_len,
125+ EXT_EEPROM_MODE);
126+ if (ret && ret != -EINVAL)
127+ return ret;
128+ }
129+ }
130+
131+ ret = simple_read_from_buffer(user_buf, count, ppos,
132+ mdev->ext_eeprom.data, mdev->ext_eeprom.size);
133+
134+ return ret;
135+}
136+
137+static const struct file_operations mt7996_ext_eeprom_ops = {
138+ .read = mt7996_ext_eeprom_get,
139+ .open = simple_open,
140+ .llseek = default_llseek,
141+};
142+
143 static int
144 mt7996_vow_info_read(struct seq_file *s, void *data)
145 {
146@@ -1133,6 +1187,7 @@ int mt7996_init_dev_debugfs(struct mt7996_phy *phy)
147 mt7996_twt_stats);
148 debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval);
149 debugfs_create_file("otp", 0400, dir, dev, &mt7996_efuse_ops);
150+ debugfs_create_file("ext_eeprom", 0400, dir, dev, &mt7996_ext_eeprom_ops);
151 debugfs_create_devm_seqfile(dev->mt76.dev, "vow_info", dir,
152 mt7996_vow_info_read);
153 debugfs_create_devm_seqfile(dev->mt76.dev, "airtime", dir,
154diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
155index 327a36b2..db98db21 100644
156--- a/mt7996/eeprom.c
157+++ b/mt7996/eeprom.c
158@@ -315,43 +315,52 @@ static int mt7996_eeprom_load(struct mt7996_dev *dev)
159
160 /* flash or bin file mode eeprom is loaded before mcu init */
161 if (!dev->flash_mode) {
162- u32 eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE;
163- u32 block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size);
164+ u32 eeprom_blk_size, block_num;
165 u8 free_block_num;
166 int i;
167
168 memset(dev->mt76.eeprom.data, 0, MT7996_EEPROM_SIZE);
169- ret = mt7996_mcu_get_eeprom_free_block(dev, &free_block_num);
170- if (ret < 0)
171- return ret;
172-
173- /* efuse info isn't enough */
174- if (free_block_num >= 59) {
175- use_default = true;
176- goto out;
177+ if (!mt7996_has_ext_eeprom(dev)) {
178+ /* efuse mode */
179+ dev->eeprom_mode = EFUSE_MODE;
180+ eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE;
181+ ret = mt7996_mcu_get_efuse_free_block(dev, &free_block_num);
182+ if (ret < 0)
183+ return ret;
184+
185+ /* efuse info isn't enough */
186+ if (free_block_num >= 59) {
187+ use_default = true;
188+ goto out;
189+ }
190+ } else {
191+ /* external eeprom mode */
192+ dev->eeprom_mode = EXT_EEPROM_MODE;
193+ eeprom_blk_size = MT7996_EXT_EEPROM_BLOCK_SIZE;
194 }
195
196 /* check if eeprom data from fw is valid */
197- if (mt7996_mcu_get_eeprom(dev, 0, NULL, 0) ||
198+ if (mt7996_mcu_get_eeprom(dev, 0, NULL, eeprom_blk_size,
199+ dev->eeprom_mode) ||
200 mt7996_check_eeprom(dev)) {
201 use_default = true;
202 goto out;
203 }
204
205 /* read eeprom data from fw */
206+ block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size);
207 for (i = 1; i < block_num; i++) {
208 u32 len = eeprom_blk_size;
209
210 if (i == block_num - 1)
211 len = MT7996_EEPROM_SIZE % eeprom_blk_size;
212 ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size,
213- NULL, len);
214+ NULL, len, dev->eeprom_mode);
215 if (ret && ret != -EINVAL) {
216 use_default = true;
217 goto out;
218 }
219 }
220- dev->eeprom_mode = EFUSE_MODE;
221 }
222
223 out:
224diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h
225index 788c33c8..15b6620d 100644
226--- a/mt7996/eeprom.h
227+++ b/mt7996/eeprom.h
228@@ -151,13 +151,6 @@ enum mt7996_eeprom_band {
229 MT_EE_BAND_SEL_6GHZ,
230 };
231
232-enum mt7915_eeprom_mode {
233- DEFAULT_BIN_MODE,
234- EFUSE_MODE,
235- FLASH_MODE,
236- BIN_FILE_MODE,
237-};
238-
239 static inline int
240 mt7996_get_channel_group_5g(int channel)
241 {
242diff --git a/mt7996/init.c b/mt7996/init.c
243index ddceddff..f739afd2 100644
244--- a/mt7996/init.c
245+++ b/mt7996/init.c
246@@ -1238,7 +1238,8 @@ static int mt7996_variant_fem_init(struct mt7996_dev *dev)
247 if (ret)
248 return ret;
249
250- ret = mt7996_mcu_get_eeprom(dev, MT7976C_EFUSE_OFFSET, buf, sizeof(buf));
251+ ret = mt7996_mcu_get_eeprom(dev, MT7976C_EFUSE_OFFSET, buf, sizeof(buf),
252+ EFUSE_MODE);
253 if (ret && ret != -EINVAL)
254 return ret;
255
256diff --git a/mt7996/mcu.c b/mt7996/mcu.c
257index b0e9617d..01969464 100644
258--- a/mt7996/mcu.c
259+++ b/mt7996/mcu.c
260@@ -5259,7 +5259,7 @@ int mt7996_mcu_set_eeprom_flash(struct mt7996_dev *dev)
261 #define MAX_PAGE_IDX_MASK GENMASK(7, 5)
262 #define PAGE_IDX_MASK GENMASK(4, 2)
263 #define PER_PAGE_SIZE 0x400
264- struct mt7996_mcu_eeprom req = {
265+ struct mt7996_mcu_eeprom_update req = {
266 .tag = cpu_to_le16(UNI_EFUSE_BUFFER_MODE),
267 .buffer_mode = EE_MODE_BUFFER
268 };
269@@ -5301,7 +5301,7 @@ int mt7996_mcu_set_eeprom_flash(struct mt7996_dev *dev)
270
271 int mt7996_mcu_set_eeprom(struct mt7996_dev *dev)
272 {
273- struct mt7996_mcu_eeprom req = {
274+ struct mt7996_mcu_eeprom_update req = {
275 .tag = cpu_to_le16(UNI_EFUSE_BUFFER_MODE),
276 .len = cpu_to_le16(sizeof(req) - 4),
277 .buffer_mode = EE_MODE_EFUSE,
278@@ -5309,7 +5309,7 @@ int mt7996_mcu_set_eeprom(struct mt7996_dev *dev)
279 };
280 int ret;
281
282- if (dev->flash_mode)
283+ if (dev->flash_mode || mt7996_has_ext_eeprom(dev))
284 ret = mt7996_mcu_set_eeprom_flash(dev);
285 else
286 ret = mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(EFUSE_CTRL),
287@@ -5320,36 +5320,64 @@ int mt7996_mcu_set_eeprom(struct mt7996_dev *dev)
288 return mt7996_mcu_set_cal_free_data(dev);
289 }
290
291-int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len)
292+int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len,
293+ enum mt7996_eeprom_mode mode)
294 {
295- struct mt7996_mcu_eeprom_info req = {
296- .tag = cpu_to_le16(UNI_EFUSE_ACCESS),
297- .len = cpu_to_le16(sizeof(req) - 4),
298- .addr = cpu_to_le32(round_down(offset,
299- MT7996_EEPROM_BLOCK_SIZE)),
300- };
301+ struct mt7996_mcu_eeprom_access req;
302+ struct mt7996_mcu_eeprom_access_event *event;
303 struct sk_buff *skb;
304- bool valid;
305- int ret;
306+ int ret, cmd;
307
308- ret = mt76_mcu_send_and_get_msg(&dev->mt76,
309- MCU_WM_UNI_CMD_QUERY(EFUSE_CTRL),
310- &req, sizeof(req), true, &skb);
311+ switch (mode) {
312+ case EFUSE_MODE:
313+ req.info.tag = cpu_to_le16(UNI_EFUSE_ACCESS);
314+ req.info.len = cpu_to_le16(sizeof(req) - 4);
315+ req.info.addr = cpu_to_le32(round_down(offset, MT7996_EEPROM_BLOCK_SIZE));
316+ cmd = MCU_WM_UNI_CMD_QUERY(EFUSE_CTRL);
317+ break;
318+ case EXT_EEPROM_MODE:
319+ req.info.tag = cpu_to_le16(UNI_EXT_EEPROM_ACCESS);
320+ req.info.len = cpu_to_le16(sizeof(req) - 4);
321+ req.info.addr = cpu_to_le32(round_down(offset, MT7996_EXT_EEPROM_BLOCK_SIZE));
322+ req.eeprom.ext_eeprom.data_len = cpu_to_le32(buf_len);
323+ cmd = MCU_WM_UNI_CMD_QUERY(EXT_EEPROM_CTRL);
324+ break;
325+ default:
326+ return -EINVAL;
327+ }
328+
329+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, cmd, &req,
330+ sizeof(req), true, &skb);
331 if (ret)
332 return ret;
333
334- valid = le32_to_cpu(*(__le32 *)(skb->data + 16));
335- if (valid) {
336- u32 addr = le32_to_cpu(*(__le32 *)(skb->data + 12));
337-
338- if (!buf)
339- buf = (u8 *)dev->mt76.eeprom.data + addr;
340+ event = (struct mt7996_mcu_eeprom_access_event *)skb->data;
341+ if (event->valid) {
342+ u32 addr = le32_to_cpu(event->addr);
343+ u32 ret_len = le32_to_cpu(event->eeprom.ext_eeprom.data_len);
344
345- if (!buf_len || buf_len > MT7996_EEPROM_BLOCK_SIZE)
346- buf_len = MT7996_EEPROM_BLOCK_SIZE;
347+ switch (mode) {
348+ case EFUSE_MODE:
349+ if (!buf)
350+ buf = (u8 *)dev->mt76.eeprom.data + addr;
351+ if (!buf_len || buf_len > MT7996_EEPROM_BLOCK_SIZE)
352+ buf_len = MT7996_EEPROM_BLOCK_SIZE;
353
354- skb_pull(skb, 48);
355- memcpy(buf, skb->data, buf_len);
356+ memcpy(buf, event->eeprom.efuse, buf_len);
357+ break;
358+ case EXT_EEPROM_MODE:
359+ if (!buf)
360+ buf = (u8 *)dev->mt76.ext_eeprom.data + addr;
361+ if (!buf_len || buf_len > MT7996_EXT_EEPROM_BLOCK_SIZE)
362+ buf_len = MT7996_EXT_EEPROM_BLOCK_SIZE;
363+
364+ memcpy(buf, event->eeprom.ext_eeprom.data,
365+ ret_len < buf_len ? ret_len : buf_len);
366+ break;
367+ default:
368+ ret = -EINVAL;
369+ break;
370+ }
371 } else {
372 ret = -EINVAL;
373 }
374@@ -5359,7 +5387,57 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_l
375 return ret;
376 }
377
378-int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num)
379+int
380+mt7996_mcu_write_ext_eeprom(struct mt7996_dev *dev, u32 offset,
381+ u32 data_len, u8 *write_buf)
382+{
383+ struct mt7996_mcu_eeprom_access req = {
384+ .info.tag = cpu_to_le16(UNI_EXT_EEPROM_ACCESS),
385+ .info.len = cpu_to_le16(sizeof(req) - 4 +
386+ MT7996_EXT_EEPROM_BLOCK_SIZE),
387+ };
388+ u32 block_num, block_size = MT7996_EXT_EEPROM_BLOCK_SIZE;
389+ u8 *buf = write_buf;
390+ int i, ret = -EINVAL;
391+ int msg_len = sizeof(req) + block_size;
392+
393+ if (!mt7996_has_ext_eeprom(dev))
394+ return ret;
395+
396+ if (!buf)
397+ buf = (u8 *)dev->mt76.eeprom.data + offset;
398+
399+ block_num = DIV_ROUND_UP(data_len, block_size);
400+ for (i = 0; i < block_num; i++) {
401+ struct sk_buff *skb;
402+ u32 buf_len = block_size;
403+ u32 block_offs = i * block_size;
404+
405+ if (block_offs + block_size > data_len)
406+ buf_len = data_len % block_size;
407+
408+ req.info.addr = cpu_to_le32(offset + block_offs);
409+ req.eeprom.ext_eeprom.data_len = cpu_to_le32(buf_len);
410+
411+ skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, msg_len);
412+ if (!skb)
413+ return -ENOMEM;
414+
415+ skb_put_data(skb, &req, sizeof(req));
416+ skb_put_data(skb, buf, buf_len);
417+
418+ ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
419+ MCU_WM_UNI_CMD(EXT_EEPROM_CTRL), false);
420+ if (ret)
421+ return ret;
422+
423+ buf += buf_len;
424+ }
425+
426+ return 0;
427+}
428+
429+int mt7996_mcu_get_efuse_free_block(struct mt7996_dev *dev, u8 *block_num)
430 {
431 struct {
432 u8 _rsv[4];
433diff --git a/mt7996/mcu.h b/mt7996/mcu.h
434index 33ba3774..f405b0cd 100644
435--- a/mt7996/mcu.h
436+++ b/mt7996/mcu.h
437@@ -161,7 +161,7 @@ struct mt7996_mcu_background_chain_ctrl {
438 u8 rsv[2];
439 } __packed;
440
441-struct mt7996_mcu_eeprom {
442+struct mt7996_mcu_eeprom_update {
443 u8 _rsv[4];
444
445 __le16 tag;
446@@ -171,6 +171,14 @@ struct mt7996_mcu_eeprom {
447 __le16 buf_len;
448 } __packed;
449
450+union eeprom_data {
451+ struct {
452+ __le32 data_len;
453+ DECLARE_FLEX_ARRAY(u8, data);
454+ } ext_eeprom;
455+ DECLARE_FLEX_ARRAY(u8, efuse);
456+} __packed;
457+
458 struct mt7996_mcu_eeprom_info {
459 u8 _rsv[4];
460
461@@ -178,7 +186,26 @@ struct mt7996_mcu_eeprom_info {
462 __le16 len;
463 __le32 addr;
464 __le32 valid;
465- u8 data[MT7996_EEPROM_BLOCK_SIZE];
466+} __packed;
467+
468+struct mt7996_mcu_eeprom_access {
469+ struct mt7996_mcu_eeprom_info info;
470+ union eeprom_data eeprom;
471+} __packed;
472+
473+struct mt7996_mcu_eeprom_access_event {
474+ u8 _rsv[4];
475+
476+ __le16 tag;
477+ __le16 len;
478+ __le32 version;
479+ __le32 addr;
480+ __le32 valid;
481+ __le32 size;
482+ __le32 magic_no;
483+ __le32 type;
484+ __le32 rsv[4];
485+ union eeprom_data eeprom;
486 } __packed;
487
488 struct mt7996_mcu_phy_rx_info {
489@@ -1091,6 +1118,10 @@ enum {
490 UNI_EFUSE_PATCH,
491 };
492
493+enum {
494+ UNI_EXT_EEPROM_ACCESS = 1,
495+};
496+
497 enum {
498 UNI_VOW_DRR_CTRL,
499 UNI_VOW_FEATURE_CTRL,
500diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
501index b841cc2a..a0f2f251 100644
502--- a/mt7996/mt7996.h
503+++ b/mt7996/mt7996.h
504@@ -74,7 +74,8 @@
505 #define MT7992_EEPROM_DEFAULT_24 "mediatek/mt7996/mt7992_eeprom_24_2i5i.bin"
506
507 #define MT7996_EEPROM_SIZE 7680
508-#define MT7996_EEPROM_BLOCK_SIZE 16
509+#define MT7996_EEPROM_BLOCK_SIZE 16
510+#define MT7996_EXT_EEPROM_BLOCK_SIZE 1024
511 #define MT7996_TOKEN_SIZE 16384
512 #define MT7996_HW_TOKEN_SIZE 8192
513 #define MT7996_SW_TOKEN_SIZE 15360
514@@ -171,6 +172,14 @@ enum mt7996_fem_type {
515 MT7996_FEM_MIX,
516 };
517
518+enum mt7996_eeprom_mode {
519+ DEFAULT_BIN_MODE,
520+ EFUSE_MODE,
521+ FLASH_MODE,
522+ BIN_FILE_MODE,
523+ EXT_EEPROM_MODE,
524+};
525+
526 enum mt7996_coredump_state {
527 MT7996_COREDUMP_IDLE = 0,
528 MT7996_COREDUMP_MANUAL_WA,
529@@ -973,6 +982,18 @@ mt7996_has_background_radar(struct mt7996_dev *dev)
530 return true;
531 }
532
533+static inline bool
534+mt7996_has_ext_eeprom(struct mt7996_dev *dev)
535+{
536+ switch (mt76_chip(&dev->mt76)) {
537+ case 0x7990:
538+ return false;
539+ case 0x7992:
540+ default:
541+ return true;
542+ }
543+}
544+
545 static inline struct mt7996_phy *
546 mt7996_band_phy(struct ieee80211_hw *hw, enum nl80211_band band)
547 {
548@@ -1154,8 +1175,11 @@ int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev,
549 struct mt7996_link_sta *mlink, void *data,
550 u32 field);
551 int mt7996_mcu_set_eeprom(struct mt7996_dev *dev);
552-int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len);
553-int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num);
554+int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len,
555+ enum mt7996_eeprom_mode mode);
556+int mt7996_mcu_get_efuse_free_block(struct mt7996_dev *dev, u8 *block_num);
557+int mt7996_mcu_write_ext_eeprom(struct mt7996_dev *dev, u32 offset,
558+ u32 data_len, u8 *write_buf);
559 int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap);
560 int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 set, u8 band);
561 int mt7996_mcu_set_txbf(struct mt7996_dev *dev, u8 action);
562diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
563index 5338d0bd..4996774f 100644
564--- a/mt7996/mtk_debugfs.c
565+++ b/mt7996/mtk_debugfs.c
566@@ -2829,6 +2829,9 @@ static int mt7996_show_eeprom_mode(struct seq_file *s, void *data)
567 case BIN_FILE_MODE:
568 seq_printf(s, " bin file mode\n filename = %s\n", dev->mt76.bin_file_name);
569 break;
570+ case EXT_EEPROM_MODE:
571+ seq_printf(s, " external eeprom mode\n");
572+ break;
573 default:
574 break;
575 }
576diff --git a/mt7996/testmode.c b/mt7996/testmode.c
577index 1674e129..b3692637 100644
578--- a/mt7996/testmode.c
579+++ b/mt7996/testmode.c
580@@ -2138,37 +2138,43 @@ mt7996_tm_write_back_to_efuse(struct mt7996_dev *dev)
581 {
582 struct mt7996_mcu_eeprom_info req = {
583 .tag = cpu_to_le16(UNI_EFUSE_ACCESS),
584- .len = cpu_to_le16(sizeof(req) - 4),
585+ .len = cpu_to_le16(sizeof(req) - 4 +
586+ MT76_TM_EEPROM_BLOCK_SIZE),
587 };
588 u8 read_buf[MT76_TM_EEPROM_BLOCK_SIZE], *eeprom = dev->mt76.eeprom.data;
589+ int msg_len = sizeof(req) + MT76_TM_EEPROM_BLOCK_SIZE;
590 int i, ret = -EINVAL;
591
592 /* prevent from damaging chip id in efuse */
593 if (mt76_chip(&dev->mt76) != get_unaligned_le16(eeprom))
594- goto out;
595+ return ret;
596
597 for (i = 0; i < MT7996_EEPROM_SIZE; i += MT76_TM_EEPROM_BLOCK_SIZE) {
598- req.addr = cpu_to_le32(i);
599- memcpy(req.data, eeprom + i, MT76_TM_EEPROM_BLOCK_SIZE);
600+ struct sk_buff *skb;
601
602- ret = mt7996_mcu_get_eeprom(dev, i, read_buf, sizeof(read_buf));
603- if (ret) {
604- if (ret != -EINVAL)
605- return ret;
606-
607- memset(read_buf, 0, MT76_TM_EEPROM_BLOCK_SIZE);
608- }
609+ memset(read_buf, 0, MT76_TM_EEPROM_BLOCK_SIZE);
610+ ret = mt7996_mcu_get_eeprom(dev, i, read_buf, sizeof(read_buf),
611+ EFUSE_MODE);
612+ if (ret && ret != -EINVAL)
613+ return ret;
614
615- if (!memcmp(req.data, read_buf, MT76_TM_EEPROM_BLOCK_SIZE))
616+ if (!memcmp(eeprom + i, read_buf, MT76_TM_EEPROM_BLOCK_SIZE))
617 continue;
618
619- ret = mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(EFUSE_CTRL),
620- &req, sizeof(req), true);
621+ skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, msg_len);
622+ if (!skb)
623+ return -ENOMEM;
624+
625+ req.addr = cpu_to_le32(i);
626+ skb_put_data(skb, &req, sizeof(req));
627+ skb_put_data(skb, eeprom + i, MT76_TM_EEPROM_BLOCK_SIZE);
628+
629+ ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
630+ MCU_WM_UNI_CMD(EFUSE_CTRL), true);
631 if (ret)
632 return ret;
633 }
634
635-out:
636 return ret;
637 }
638
639@@ -2193,6 +2199,9 @@ mt7996_tm_set_eeprom(struct mt76_phy *mphy, u32 offset, u8 *val, u8 action)
640 case MT76_TM_EEPROM_ACTION_WRITE_TO_EFUSE:
641 ret = mt7996_tm_write_back_to_efuse(dev);
642 break;
643+ case MT76_TM_EEPROM_ACTION_WRITE_TO_EXT_EEPROM:
644+ ret = mt7996_mcu_write_ext_eeprom(dev, 0, MT7996_EEPROM_SIZE, NULL);
645+ break;
646 default:
647 break;
648 }
649diff --git a/testmode.h b/testmode.h
650index 44f9984c..8e751bbf 100644
651--- a/testmode.h
652+++ b/testmode.h
653@@ -281,11 +281,13 @@ enum mt76_testmode_tx_mode {
654 * eeprom data block
655 * @MT76_TM_EEPROM_ACTION_UPDATE_BUFFER_MODE: send updated eeprom data to fw
656 * @MT76_TM_EEPROM_ACTION_WRITE_TO_EFUSE: write eeprom data back to efuse
657+ * @MT76_TM_EEPROM_ACTION_WRITE_TO_EXT_EEPROM: write eeprom data back to external eeprom
658 */
659 enum mt76_testmode_eeprom_action {
660 MT76_TM_EEPROM_ACTION_UPDATE_DATA,
661 MT76_TM_EEPROM_ACTION_UPDATE_BUFFER_MODE,
662 MT76_TM_EEPROM_ACTION_WRITE_TO_EFUSE,
663+ MT76_TM_EEPROM_ACTION_WRITE_TO_EXT_EEPROM,
664
665 /* keep last */
666 NUM_MT76_TM_EEPROM_ACTION,
667--
6682.45.2
669