blob: 72a2d92f9231fbb5f34eaa0b474ea5d09f981fd6 [file] [log] [blame]
developerd0c89452024-10-11 16:53:27 +08001From 617b4824df541129e545daa0015d43d2e625350b Mon Sep 17 00:00:00 2001
2From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
3Date: Thu, 29 Aug 2024 09:47:44 +0800
4Subject: [PATCH 190/223] mtk: mt76: mt7996: add efuse write protection
5
6Add efuse write protection in case that the user overwritten
7the FT value stored in efuse.
8Reference change list (Logan):
9https://gerrit.mediatek.inc/c/neptune/wlan_driver/logan/+/9473737
10https://gerrit.mediatek.inc/c/neptune/wlan_driver/logan/+/9497426
11
12Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
13Change-Id: If50d6965da8d9488d44c9da77a4bfca9906da9bc
14---
15 mt7996/mcu.c | 11 +---
16 mt7996/mt7996.h | 23 ++++++++
17 mt7996/testmode.c | 135 ++++++++++++++++++++++++++++++++++++++++++----
18 mt7996/testmode.h | 6 +++
19 4 files changed, 157 insertions(+), 18 deletions(-)
20
21diff --git a/mt7996/mcu.c b/mt7996/mcu.c
22index 01969464..b27b74d3 100644
23--- a/mt7996/mcu.c
24+++ b/mt7996/mcu.c
25@@ -5115,13 +5115,6 @@ static int mt7996_mcu_set_cal_free_data(struct mt7996_dev *dev)
26 #define MT_EE_CAL_FREE_MAX_SIZE 30
27 #define MT_EE_7977BN_OFFSET (0x1200 - 0x500)
28 #define MT_EE_END_OFFSET 0xffff
29- enum adie_type {
30- ADIE_7975,
31- ADIE_7976,
32- ADIE_7977,
33- ADIE_7978,
34- ADIE_7979,
35- };
36 static const u16 adie_offs_list[][MT_EE_CAL_FREE_MAX_SIZE] = {
37 [ADIE_7975] = {0x5cd, 0x5cf, 0x5d1, 0x5d3, 0x6c0, 0x6c1, 0x6c2, 0x6c3,
38 0x7a1, 0x7a6, 0x7a8, 0x7aa, -1},
39@@ -5151,10 +5144,10 @@ static int mt7996_mcu_set_cal_free_data(struct mt7996_dev *dev)
40 0x127a, 0x127b, 0x127c, 0x127e, 0x1280, -1},
41 };
42 static const u16 adie_base_7996[] = {
43- 0x400, 0x1e00, 0x1200
44+ EFUSE_BASE_OFFS_ADIE0, EFUSE_BASE_OFFS_ADIE1, EFUSE_BASE_OFFS_ADIE2
45 };
46 static const u16 adie_base_7992[] = {
47- 0x400, 0x1200, 0x0
48+ EFUSE_BASE_OFFS_ADIE0, EFUSE_BASE_OFFS_ADIE1_7992, 0x0
49 };
50 static const u16 *adie_offs[__MT_MAX_BAND];
51 static const u16 *eep_offs[__MT_MAX_BAND];
52diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
53index a0f2f251..592b3673 100644
54--- a/mt7996/mt7996.h
55+++ b/mt7996/mt7996.h
56@@ -180,6 +180,29 @@ enum mt7996_eeprom_mode {
57 EXT_EEPROM_MODE,
58 };
59
60+enum mt7996_ddie_type {
61+ DDIE_7996,
62+ DDIE_7992,
63+ DDIE_TYPE_NUM,
64+};
65+
66+enum mt7996_adie_type {
67+ ADIE_7975,
68+ ADIE_7976,
69+ ADIE_7977,
70+ ADIE_7978,
71+ ADIE_7979,
72+ ADIE_TYPE_NUM,
73+};
74+
75+enum mt7996_efuse_base_offs {
76+ EFUSE_BASE_OFFS_DDIE = 0x0,
77+ EFUSE_BASE_OFFS_ADIE0 = 0x400,
78+ EFUSE_BASE_OFFS_ADIE2 = 0x1200,
79+ EFUSE_BASE_OFFS_ADIE1_7992 = 0x1200,
80+ EFUSE_BASE_OFFS_ADIE1 = 0x1e00,
81+};
82+
83 enum mt7996_coredump_state {
84 MT7996_COREDUMP_IDLE = 0,
85 MT7996_COREDUMP_MANUAL_WA,
86diff --git a/mt7996/testmode.c b/mt7996/testmode.c
87index b3692637..6f9900a6 100644
88--- a/mt7996/testmode.c
89+++ b/mt7996/testmode.c
90@@ -2133,6 +2133,127 @@ mt7996_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg)
91 return 0;
92 }
93
94+static bool
95+mt7996_tm_efuse_update_is_valid(struct mt7996_dev *dev, u32 offset, u8 *write_buf)
96+{
97+#define PROT_OFFS_MAX_SIZE 8
98+#define EFUSE_PROT_END_OFFSET 0xffff
99+#define EFUSE_PROT_ALL_MASK GENMASK(15, 0)
100+ static const struct efuse_region ddie_prot_offs[][PROT_OFFS_MAX_SIZE] = {
101+ [DDIE_7996] = {{.start = 0x10, .end = 0x18f, .prot_mask = -1},
102+ {.start = 0x1b0, .end = 0x2bf, .prot_mask = -1},
103+ {.start = 0x2c0, .end = 0x2cf, .prot_mask = GENMASK(15, 6)},
104+ {.start = 0x2d0, .end = 0x2ff, .prot_mask = -1},
105+ {.start = 0x300, .end = 0x30f, .prot_mask = GENMASK(15, 1)},
106+ {.start = 0x310, .end = 0x31f, .prot_mask = GENMASK(15, 1)},
107+ {.start = 0x320, .end = 0x3ff, .prot_mask = -1},
108+ {.start = -1}},
109+ [DDIE_7992] = {{.start = 0x10, .end = 0x18f, .prot_mask = -1},
110+ {.start = 0x1b0, .end = 0x3ff, .prot_mask = -1},
111+ {.start = -1}},
112+ };
113+ static const struct efuse_region adie_prot_offs[][PROT_OFFS_MAX_SIZE] = {
114+ [ADIE_7975] = {{.start = 0x5c0, .end = 0x62f, .prot_mask = -1},
115+ {.start = 0x6c0, .end = 0x6ff, .prot_mask = -1},
116+ {.start = 0x7a0, .end = 0x7af, .prot_mask = BIT(1) | BIT(9)},
117+ {.start = 0x7b0, .end = 0x7bf, .prot_mask = -1},
118+ {.start = -1}},
119+ [ADIE_7976] = {{.start = 0x0, .end = 0x7f, .prot_mask = -1},
120+ {.start = 0x790, .end = 0x79f,
121+ .prot_mask = GENMASK(15, 10) | GENMASK(8, 0)},
122+ {.start = 0x7a0, .end = 0x7af,
123+ .prot_mask = BIT(6) | BIT(8) | BIT(10)},
124+ {.start = 0x7b0, .end = 0x7bf, .prot_mask = -1},
125+ {.start = -1}},
126+ [ADIE_7977] = {{.start = 0x0, .end = 0x5f, .prot_mask = -1},
127+ {.start = 0x60, .end = 0x6f, .prot_mask = GENMASK(14, 0)},
128+ {.start = 0x70, .end = 0x7f,
129+ .prot_mask = GENMASK(15, 14) | GENMASK(12, 0)},
130+ {.start = 0x80, .end = 0x10f, .prot_mask = -1},
131+ {.start = -1}},
132+ };
133+ static const struct efuse_region *prot_offs;
134+ u8 read_buf[MT76_TM_EEPROM_BLOCK_SIZE], *eeprom = dev->mt76.eeprom.data;
135+ int ret, i = 0;
136+ u16 base;
137+
138+ if (!write_buf)
139+ return false;
140+
141+ memset(read_buf, 0, MT76_TM_EEPROM_BLOCK_SIZE);
142+ ret = mt7996_mcu_get_eeprom(dev, offset, read_buf,
143+ MT76_TM_EEPROM_BLOCK_SIZE, EFUSE_MODE);
144+ if (ret && ret != -EINVAL)
145+ return false;
146+
147+ /* no change in this block, so skip it */
148+ if (!memcmp(eeprom + offset, read_buf, MT76_TM_EEPROM_BLOCK_SIZE))
149+ return false;
150+
151+ memcpy(write_buf, eeprom + offset, MT76_TM_EEPROM_BLOCK_SIZE);
152+
153+ switch (mt76_chip(&dev->mt76)) {
154+ case 0x7990:
155+ if (offset < EFUSE_BASE_OFFS_ADIE0) {
156+ base = EFUSE_BASE_OFFS_DDIE;
157+ prot_offs = ddie_prot_offs[DDIE_7996];
158+ } else if (offset >= EFUSE_BASE_OFFS_ADIE0 &&
159+ offset < EFUSE_BASE_OFFS_ADIE2) {
160+ base = EFUSE_BASE_OFFS_ADIE0;
161+ if (dev->chip_sku == MT7996_VAR_TYPE_233 ||
162+ dev->fem_type == MT7996_FEM_EXT)
163+ prot_offs = adie_prot_offs[ADIE_7976];
164+ else
165+ prot_offs = adie_prot_offs[ADIE_7975];
166+ } else if (offset >= EFUSE_BASE_OFFS_ADIE2 &&
167+ offset < EFUSE_BASE_OFFS_ADIE1) {
168+ base = EFUSE_BASE_OFFS_ADIE2;
169+ prot_offs = adie_prot_offs[ADIE_7977];
170+ } else {
171+ base = EFUSE_BASE_OFFS_ADIE1;
172+ prot_offs = adie_prot_offs[ADIE_7977];
173+ }
174+ break;
175+ case 0x7992:
176+ /* block all the adie region in efuse for kite */
177+ if (offset >= EFUSE_BASE_OFFS_ADIE0)
178+ return false;
179+ base = EFUSE_BASE_OFFS_DDIE;
180+ prot_offs = ddie_prot_offs[DDIE_7992];
181+ break;
182+ default:
183+ return false;
184+ }
185+
186+ /* check efuse protection */
187+ while (prot_offs[i].start != EFUSE_PROT_END_OFFSET) {
188+ if (offset >= prot_offs[i].start + base &&
189+ offset <= prot_offs[i].end + base) {
190+ unsigned long prot_mask = prot_offs[i].prot_mask;
191+ int j;
192+
193+ if (prot_mask == EFUSE_PROT_ALL_MASK)
194+ return false;
195+
196+ for_each_set_bit(j, &prot_mask, MT76_TM_EEPROM_BLOCK_SIZE) {
197+ if (write_buf[j] != read_buf[j]) {
198+ write_buf[j] = read_buf[j];
199+ dev_warn(dev->mt76.dev,
200+ "offset %x is invalid to write\n",
201+ offset + j);
202+ }
203+ }
204+ break;
205+ }
206+ i++;
207+ }
208+
209+ if (!memcmp(read_buf, write_buf, MT76_TM_EEPROM_BLOCK_SIZE))
210+ return false;
211+
212+ return true;
213+}
214+
215 static int
216 mt7996_tm_write_back_to_efuse(struct mt7996_dev *dev)
217 {
218@@ -2141,8 +2262,9 @@ mt7996_tm_write_back_to_efuse(struct mt7996_dev *dev)
219 .len = cpu_to_le16(sizeof(req) - 4 +
220 MT76_TM_EEPROM_BLOCK_SIZE),
221 };
222- u8 read_buf[MT76_TM_EEPROM_BLOCK_SIZE], *eeprom = dev->mt76.eeprom.data;
223 int msg_len = sizeof(req) + MT76_TM_EEPROM_BLOCK_SIZE;
224+ u8 *eeprom = dev->mt76.eeprom.data;
225+ u8 write_buf[MT76_TM_EEPROM_BLOCK_SIZE];
226 int i, ret = -EINVAL;
227
228 /* prevent from damaging chip id in efuse */
229@@ -2152,13 +2274,8 @@ mt7996_tm_write_back_to_efuse(struct mt7996_dev *dev)
230 for (i = 0; i < MT7996_EEPROM_SIZE; i += MT76_TM_EEPROM_BLOCK_SIZE) {
231 struct sk_buff *skb;
232
233- memset(read_buf, 0, MT76_TM_EEPROM_BLOCK_SIZE);
234- ret = mt7996_mcu_get_eeprom(dev, i, read_buf, sizeof(read_buf),
235- EFUSE_MODE);
236- if (ret && ret != -EINVAL)
237- return ret;
238-
239- if (!memcmp(eeprom + i, read_buf, MT76_TM_EEPROM_BLOCK_SIZE))
240+ memset(write_buf, 0, MT76_TM_EEPROM_BLOCK_SIZE);
241+ if (!mt7996_tm_efuse_update_is_valid(dev, i, write_buf))
242 continue;
243
244 skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, msg_len);
245@@ -2167,7 +2284,7 @@ mt7996_tm_write_back_to_efuse(struct mt7996_dev *dev)
246
247 req.addr = cpu_to_le32(i);
248 skb_put_data(skb, &req, sizeof(req));
249- skb_put_data(skb, eeprom + i, MT76_TM_EEPROM_BLOCK_SIZE);
250+ skb_put_data(skb, write_buf, MT76_TM_EEPROM_BLOCK_SIZE);
251
252 ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
253 MCU_WM_UNI_CMD(EFUSE_CTRL), true);
254diff --git a/mt7996/testmode.h b/mt7996/testmode.h
255index 5c720da7..154392dc 100644
256--- a/mt7996/testmode.h
257+++ b/mt7996/testmode.h
258@@ -363,4 +363,10 @@ struct mt7996_tm_rdd_ipi_ctrl {
259 __le32 tx_assert_time; /* unit: us */
260 } __packed;
261
262+struct efuse_region {
263+ u16 start;
264+ u16 end;
265+ u16 prot_mask;
266+};
267+
268 #endif
269--
2702.45.2
271