blob: c1e7434dbf39cfdc690390448db88c487e9c7cef [file] [log] [blame]
Ye Li77a57122021-08-07 16:01:05 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2020 NXP
4 */
5
Ye Li77a57122021-08-07 16:01:05 +08006#include <console.h>
7#include <errno.h>
8#include <fuse.h>
9#include <asm/arch/sys_proto.h>
10#include <asm/arch/imx-regs.h>
11#include <env.h>
Peng Fand5c31832023-06-15 18:09:05 +080012#include <asm/mach-imx/ele_api.h>
Ye Li77a57122021-08-07 16:01:05 +080013#include <asm/global_data.h>
Ye Li508809d2024-10-06 08:30:05 +080014#include <env.h>
Ye Li77a57122021-08-07 16:01:05 +080015
16DECLARE_GLOBAL_DATA_PTR;
17
Ye Li77a57122021-08-07 16:01:05 +080018#define WORDS_PER_BANKS 8
19
20struct fsb_map_entry {
21 s32 fuse_bank;
22 u32 fuse_words;
23 bool redundancy;
24};
25
Peng Fand5c31832023-06-15 18:09:05 +080026struct ele_map_entry {
Ye Li77a57122021-08-07 16:01:05 +080027 s32 fuse_bank;
28 u32 fuse_words;
29 u32 fuse_offset;
Peng Fand5c31832023-06-15 18:09:05 +080030 u32 ele_index;
Ye Li77a57122021-08-07 16:01:05 +080031};
32
Alice Guob93916d2022-07-26 16:40:59 +080033#if defined(CONFIG_IMX8ULP)
34#define FSB_OTP_SHADOW 0x800
Ye Li508809d2024-10-06 08:30:05 +080035#define IS_FSB_ALLOWED (true)
Alice Guob93916d2022-07-26 16:40:59 +080036
Ye Li77a57122021-08-07 16:01:05 +080037struct fsb_map_entry fsb_mapping_table[] = {
38 { 3, 8 },
39 { 4, 8 },
Peng Fan199fa602022-04-06 14:30:31 +080040 { -1, 48 }, /* Reserve 48 words */
Ye Li77a57122021-08-07 16:01:05 +080041 { 5, 8 },
42 { 6, 8 },
Ye Li77a57122021-08-07 16:01:05 +080043 { 8, 4, true },
44 { 24, 4, true },
45 { 26, 4, true },
46 { 27, 4, true },
47 { 28, 8 },
48 { 29, 8 },
49 { 30, 8 },
50 { 31, 8 },
51 { 37, 8 },
52 { 38, 8 },
53 { 39, 8 },
54 { 40, 8 },
55 { 41, 8 },
56 { 42, 8 },
57 { 43, 8 },
58 { 44, 8 },
59 { 45, 8 },
60 { 46, 8 },
61};
62
Ye Li1a6e3ca2023-01-31 16:42:28 +080063/* None ECC banks such like Redundancy or Bit protect */
64u32 nonecc_fuse_banks[] = {
65 0, 1, 8, 12, 16, 22, 24, 25, 26, 27, 36, 41, 51, 56
66};
67
Peng Fand5c31832023-06-15 18:09:05 +080068struct ele_map_entry ele_api_mapping_table[] = {
Ye Li77a57122021-08-07 16:01:05 +080069 { 1, 8 }, /* LOCK */
70 { 2, 8 }, /* ECID */
71 { 7, 4, 0, 1 }, /* OTP_UNIQ_ID */
Ye Li6469bc62022-04-06 14:30:16 +080072 { 15, 8 }, /* OEM SRK HASH */
Ye Li77a57122021-08-07 16:01:05 +080073 { 23, 1, 4, 2 }, /* OTFAD */
Peng Fan199fa602022-04-06 14:30:31 +080074 { 25, 8 }, /* Test config2 */
Ye Liaeecf402023-01-31 16:42:27 +080075 { 26, 8 }, /* PMU */
76 { 27, 8 }, /* Test flow/USB */
77 { 32, 8 }, /* GP1 */
78 { 33, 8 }, /* GP2 */
79 { 34, 8 }, /* GP3 */
80 { 35, 8 }, /* GP4 */
81 { 36, 8 }, /* GP5 */
82 { 49, 8 }, /* GP8 */
83 { 50, 8 }, /* GP9 */
84 { 51, 8 }, /* GP10 */
Ye Li77a57122021-08-07 16:01:05 +080085};
Alice Guob93916d2022-07-26 16:40:59 +080086#elif defined(CONFIG_ARCH_IMX9)
87#define FSB_OTP_SHADOW 0x8000
Ye Li508809d2024-10-06 08:30:05 +080088#define IS_FSB_ALLOWED (!IS_ENABLED(CONFIG_SCMI_FIRMWARE) && \
89 !(readl(BLK_CTRL_NS_ANOMIX_BASE_ADDR + 0x28) & BIT(0)))
Alice Guob93916d2022-07-26 16:40:59 +080090
91struct fsb_map_entry fsb_mapping_table[] = {
92 { 0, 8 },
93 { 1, 8 },
94 { 2, 8 },
Alice Guo8ee27642022-07-26 16:41:00 +080095 { 3, 8 },
Alice Guob93916d2022-07-26 16:40:59 +080096 { 4, 8 },
97 { 5, 8 },
Alice Guo8ee27642022-07-26 16:41:00 +080098 { 6, 4 },
99 { -1, 260 },
100 { 39, 8 },
101 { 40, 8 },
102 { 41, 8 },
103 { 42, 8 },
104 { 43, 8 },
105 { 44, 8 },
106 { 45, 8 },
107 { 46, 8 },
108 { 47, 8 },
109 { 48, 8 },
110 { 49, 8 },
111 { 50, 8 },
112 { 51, 8 },
113 { 52, 8 },
114 { 53, 8 },
115 { 54, 8 },
116 { 55, 8 },
117 { 56, 8 },
118 { 57, 8 },
119 { 58, 8 },
120 { 59, 8 },
121 { 60, 8 },
122 { 61, 8 },
123 { 62, 8 },
124 { 63, 8 },
Alice Guob93916d2022-07-26 16:40:59 +0800125};
126
Peng Fand5c31832023-06-15 18:09:05 +0800127struct ele_map_entry ele_api_mapping_table[] = {
Alice Guo8ee27642022-07-26 16:41:00 +0800128 { 7, 1, 7, 63 },
129 { 16, 8, },
130 { 17, 8, },
131 { 22, 1, 6 },
132 { 23, 1, 4 },
Alice Guob93916d2022-07-26 16:40:59 +0800133};
134#endif
Ye Li77a57122021-08-07 16:01:05 +0800135
136static s32 map_fsb_fuse_index(u32 bank, u32 word, bool *redundancy)
137{
138 s32 size = ARRAY_SIZE(fsb_mapping_table);
139 s32 i, word_pos = 0;
140
141 /* map the fuse from ocotp fuse map to FSB*/
142 for (i = 0; i < size; i++) {
143 if (fsb_mapping_table[i].fuse_bank != -1 &&
Ye Lia48556c2024-10-06 08:30:04 +0800144 fsb_mapping_table[i].fuse_bank == bank) {
Ye Li77a57122021-08-07 16:01:05 +0800145 break;
146 }
147
148 word_pos += fsb_mapping_table[i].fuse_words;
149 }
150
151 if (i == size)
152 return -1; /* Failed to find */
153
154 if (fsb_mapping_table[i].redundancy) {
Ye Lia48556c2024-10-06 08:30:04 +0800155 if ((fsb_mapping_table[i].fuse_words << 1) <= word)
156 return -2; /* Not valid word */
157
Ye Li77a57122021-08-07 16:01:05 +0800158 *redundancy = true;
159 return (word >> 1) + word_pos;
Ye Lia48556c2024-10-06 08:30:04 +0800160 } else if (fsb_mapping_table[i].fuse_words <= word) {
161 return -2; /* Not valid word */
Ye Li77a57122021-08-07 16:01:05 +0800162 }
163
164 *redundancy = false;
165 return word + word_pos;
166}
167
Peng Fand5c31832023-06-15 18:09:05 +0800168static s32 map_ele_fuse_index(u32 bank, u32 word)
Ye Li77a57122021-08-07 16:01:05 +0800169{
Peng Fand5c31832023-06-15 18:09:05 +0800170 s32 size = ARRAY_SIZE(ele_api_mapping_table);
Ye Li77a57122021-08-07 16:01:05 +0800171 s32 i;
172
173 /* map the fuse from ocotp fuse map to FSB*/
174 for (i = 0; i < size; i++) {
Peng Fand5c31832023-06-15 18:09:05 +0800175 if (ele_api_mapping_table[i].fuse_bank != -1 &&
176 ele_api_mapping_table[i].fuse_bank == bank) {
177 if (word >= ele_api_mapping_table[i].fuse_offset &&
178 word < (ele_api_mapping_table[i].fuse_offset +
179 ele_api_mapping_table[i].fuse_words))
Ye Li77a57122021-08-07 16:01:05 +0800180 break;
181 }
182 }
183
184 if (i == size)
185 return -1; /* Failed to find */
186
Peng Fand5c31832023-06-15 18:09:05 +0800187 if (ele_api_mapping_table[i].ele_index != 0)
188 return ele_api_mapping_table[i].ele_index;
Ye Li77a57122021-08-07 16:01:05 +0800189
Peng Fand5c31832023-06-15 18:09:05 +0800190 return ele_api_mapping_table[i].fuse_bank * 8 + word;
Ye Li77a57122021-08-07 16:01:05 +0800191}
192
Alice Guo8ee27642022-07-26 16:41:00 +0800193#if defined(CONFIG_IMX8ULP)
Ye Li77a57122021-08-07 16:01:05 +0800194int fuse_sense(u32 bank, u32 word, u32 *val)
195{
196 s32 word_index;
Ye Li77a57122021-08-07 16:01:05 +0800197
Ye Li508809d2024-10-06 08:30:05 +0800198 if (word >= WORDS_PER_BANKS || !val)
Ye Li77a57122021-08-07 16:01:05 +0800199 return -EINVAL;
200
Peng Fand5c31832023-06-15 18:09:05 +0800201 word_index = map_ele_fuse_index(bank, word);
Ye Li77a57122021-08-07 16:01:05 +0800202 if (word_index >= 0) {
203 u32 data[4];
Ye Lia48556c2024-10-06 08:30:04 +0800204 u32 res = 0, size = 4;
Ye Li77a57122021-08-07 16:01:05 +0800205 int ret;
206
207 /* Only UID return 4 words */
208 if (word_index != 1)
209 size = 1;
210
Peng Fand5c31832023-06-15 18:09:05 +0800211 ret = ele_read_common_fuse(word_index, data, size, &res);
Ye Li77a57122021-08-07 16:01:05 +0800212 if (ret) {
213 printf("ahab read fuse failed %d, 0x%x\n", ret, res);
214 return ret;
215 }
216
217 if (word_index == 1) {
218 *val = data[word]; /* UID */
219 } else if (word_index == 2) {
220 /*
221 * OTFAD 3 bits as follow:
222 * bit 0: OTFAD_ENABLE
223 * bit 1: OTFAD_DISABLE_OVERRIDE
224 * bit 2: KEY_BLOB_EN
225 */
226 *val = data[0] << 3;
227 } else {
228 *val = data[0];
229 }
230
231 return 0;
232 }
233
234 return -ENOENT;
235}
Ye Li508809d2024-10-06 08:30:05 +0800236
Alice Guo8ee27642022-07-26 16:41:00 +0800237#elif defined(CONFIG_ARCH_IMX9)
238int fuse_sense(u32 bank, u32 word, u32 *val)
239{
240 s32 word_index;
241 bool redundancy;
242
Ye Li508809d2024-10-06 08:30:05 +0800243 if (word >= WORDS_PER_BANKS || !val)
Alice Guo8ee27642022-07-26 16:41:00 +0800244 return -EINVAL;
245
Ye Li508809d2024-10-06 08:30:05 +0800246 if (!IS_ENABLED(CONFIG_SCMI_FIRMWARE)) {
247 word_index = map_fsb_fuse_index(bank, word, &redundancy);
Alice Guo8ee27642022-07-26 16:41:00 +0800248
Ye Li508809d2024-10-06 08:30:05 +0800249 /* ELE read common fuse API supports all FSB fuse. */
250 if (word_index < 0)
251 word_index = map_ele_fuse_index(bank, word);
252 } else {
253 word_index = bank * 8 + word;
Alice Guo8ee27642022-07-26 16:41:00 +0800254 }
255
Alice Guo8ee27642022-07-26 16:41:00 +0800256 if (word_index >= 0) {
257 u32 data;
Ye Lia48556c2024-10-06 08:30:04 +0800258 u32 res = 0, size = 1;
Alice Guo8ee27642022-07-26 16:41:00 +0800259 int ret;
260
Peng Fand5c31832023-06-15 18:09:05 +0800261 ret = ele_read_common_fuse(word_index, &data, size, &res);
Alice Guo8ee27642022-07-26 16:41:00 +0800262 if (ret) {
263 printf("ahab read fuse failed %d, 0x%x\n", ret, res);
264 return ret;
265 }
266
267 *val = data;
268
269 return 0;
270 }
271
272 return -ENOENT;
273}
274#endif
Ye Li77a57122021-08-07 16:01:05 +0800275
Ye Li508809d2024-10-06 08:30:05 +0800276static int fuse_read_default(u32 bank, u32 word, u32 *val)
Ye Li77a57122021-08-07 16:01:05 +0800277{
Ye Li508809d2024-10-06 08:30:05 +0800278 s32 word_index;
279 bool redundancy;
280
281 if (IS_FSB_ALLOWED) {
282 word_index = map_fsb_fuse_index(bank, word, &redundancy);
283 if (word_index >= 0) {
284 *val = readl((ulong)FSB_BASE_ADDR + FSB_OTP_SHADOW + (word_index << 2));
285 if (redundancy)
286 *val = (*val >> ((word % 2) * 16)) & 0xFFFF;
287
288 return 0;
289 }
290 }
291
Ye Li77a57122021-08-07 16:01:05 +0800292 return fuse_sense(bank, word, val);
293}
294
Ye Li508809d2024-10-06 08:30:05 +0800295static int fuse_read_ele_shd(u32 bank, u32 word, u32 *val)
296{
297 u32 res = 0;
298 int ret;
299 struct udevice *dev = gd->arch.ele_dev;
300
301 if (!dev)
302 return -ENODEV;
303
304 ret = ele_read_shadow_fuse((bank * 8 + word), val, &res);
305 if (ret) {
306 printf("ele read shadow fuse failed %d, 0x%x\n", ret, res);
307 return ret;
308 }
309
310 return 0;
311}
312
313int fuse_read(u32 bank, u32 word, u32 *val)
314{
315 if (word >= WORDS_PER_BANKS || !val)
316 return -EINVAL;
317
318 if (!IS_ENABLED(CONFIG_SPL_BUILD) &&
319 env_get_yesno("enable_ele_shd") == 1)
320 return fuse_read_ele_shd(bank, word, val);
321 else
322 return fuse_read_default(bank, word, val);
323}
324
Ye Li77a57122021-08-07 16:01:05 +0800325int fuse_prog(u32 bank, u32 word, u32 val)
326{
Ye Lia48556c2024-10-06 08:30:04 +0800327 u32 res = 0;
Ye Li77a57122021-08-07 16:01:05 +0800328 int ret;
Ye Li1a6e3ca2023-01-31 16:42:28 +0800329 bool lock = false;
Ye Li77a57122021-08-07 16:01:05 +0800330
Ye Li508809d2024-10-06 08:30:05 +0800331 if (word >= WORDS_PER_BANKS || !val)
Ye Li77a57122021-08-07 16:01:05 +0800332 return -EINVAL;
333
Ye Li1a6e3ca2023-01-31 16:42:28 +0800334 /* Lock 8ULP ECC fuse word, so second programming will return failure.
335 * iMX9 OTP can protect ECC fuse, so not need it
336 */
337#if defined(CONFIG_IMX8ULP)
338 u32 i;
339 for (i = 0; i < ARRAY_SIZE(nonecc_fuse_banks); i++) {
340 if (nonecc_fuse_banks[i] == bank)
341 break;
342 }
343
344 if (i == ARRAY_SIZE(nonecc_fuse_banks))
345 lock = true;
346#endif
347
Peng Fand5c31832023-06-15 18:09:05 +0800348 ret = ele_write_fuse((bank * 8 + word), val, lock, &res);
Ye Li77a57122021-08-07 16:01:05 +0800349 if (ret) {
350 printf("ahab write fuse failed %d, 0x%x\n", ret, res);
351 return ret;
352 }
353
354 return 0;
355}
356
357int fuse_override(u32 bank, u32 word, u32 val)
358{
Ye Li508809d2024-10-06 08:30:05 +0800359 u32 res = 0;
360 int ret;
361
362 if (word >= WORDS_PER_BANKS || !val)
363 return -EINVAL;
364
365 ret = ele_write_shadow_fuse((bank * 8 + word), val, &res);
366 if (ret) {
367 printf("ahab write shadow fuse failed %d, 0x%x\n", ret, res);
368 return ret;
369 }
370
371 return 0;
Ye Li77a57122021-08-07 16:01:05 +0800372}