1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright 2020 NXP
4  */
5 
6 #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>
12 #include <asm/mach-imx/ele_api.h>
13 #include <asm/global_data.h>
14 #include <env.h>
15 
16 DECLARE_GLOBAL_DATA_PTR;
17 
18 #define WORDS_PER_BANKS 8
19 
20 struct fsb_map_entry {
21 	s32 fuse_bank;
22 	u32 fuse_words;
23 	bool redundancy;
24 };
25 
26 struct ele_map_entry {
27 	s32 fuse_bank;
28 	u32 fuse_words;
29 	u32 fuse_offset;
30 	u32 ele_index;
31 };
32 
33 #if defined(CONFIG_IMX8ULP)
34 #define FSB_OTP_SHADOW	0x800
35 #define IS_FSB_ALLOWED (true)
36 
37 struct fsb_map_entry fsb_mapping_table[] = {
38 	{ 3, 8 },
39 	{ 4, 8 },
40 	{ -1, 48 }, /* Reserve 48 words */
41 	{ 5, 8 },
42 	{ 6, 8 },
43 	{ 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 
63 /* None ECC banks such like Redundancy or Bit protect */
64 u32 nonecc_fuse_banks[] = {
65 	0, 1, 8, 12, 16, 22, 24, 25, 26, 27, 36, 41, 51, 56
66 };
67 
68 struct ele_map_entry ele_api_mapping_table[] = {
69 	{ 1, 8 },	/* LOCK */
70 	{ 2, 8 },	/* ECID */
71 	{ 7, 4, 0, 1 },	/* OTP_UNIQ_ID */
72 	{ 15, 8 }, /* OEM SRK HASH */
73 	{ 23, 1, 4, 2 }, /* OTFAD */
74 	{ 25, 8 }, /* Test config2 */
75 	{ 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 */
85 };
86 #elif defined(CONFIG_ARCH_IMX9)
87 #define FSB_OTP_SHADOW	0x8000
88 #define IS_FSB_ALLOWED (!IS_ENABLED(CONFIG_SCMI_FIRMWARE) && \
89 	!(readl(BLK_CTRL_NS_ANOMIX_BASE_ADDR + 0x28) & BIT(0)))
90 
91 struct fsb_map_entry fsb_mapping_table[] = {
92 	{ 0, 8 },
93 	{ 1, 8 },
94 	{ 2, 8 },
95 	{ 3, 8 },
96 	{ 4, 8 },
97 	{ 5, 8 },
98 	{ 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 },
125 };
126 
127 struct ele_map_entry ele_api_mapping_table[] = {
128 	{ 7, 1, 7, 63 },
129 	{ 16, 8, },
130 	{ 17, 8, },
131 	{ 22, 1, 6 },
132 	{ 23, 1, 4 },
133 };
134 #endif
135 
map_fsb_fuse_index(u32 bank,u32 word,bool * redundancy)136 static 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 &&
144 		    fsb_mapping_table[i].fuse_bank == bank) {
145 			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) {
155 		if ((fsb_mapping_table[i].fuse_words << 1) <= word)
156 			return -2; /* Not valid word */
157 
158 		*redundancy = true;
159 		return (word >> 1) + word_pos;
160 	} else if (fsb_mapping_table[i].fuse_words <= word) {
161 		return -2; /* Not valid word */
162 	}
163 
164 	*redundancy = false;
165 	return word + word_pos;
166 }
167 
map_ele_fuse_index(u32 bank,u32 word)168 static s32 map_ele_fuse_index(u32 bank, u32 word)
169 {
170 	s32 size = ARRAY_SIZE(ele_api_mapping_table);
171 	s32 i;
172 
173 	/* map the fuse from ocotp fuse map to FSB*/
174 	for (i = 0; i < size; i++) {
175 		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))
180 				break;
181 		}
182 	}
183 
184 	if (i == size)
185 		return -1; /* Failed to find */
186 
187 	if (ele_api_mapping_table[i].ele_index != 0)
188 		return ele_api_mapping_table[i].ele_index;
189 
190 	return ele_api_mapping_table[i].fuse_bank * 8 + word;
191 }
192 
193 #if defined(CONFIG_IMX8ULP)
fuse_sense(u32 bank,u32 word,u32 * val)194 int fuse_sense(u32 bank, u32 word, u32 *val)
195 {
196 	s32 word_index;
197 
198 	if (word >= WORDS_PER_BANKS || !val)
199 		return -EINVAL;
200 
201 	word_index = map_ele_fuse_index(bank, word);
202 	if (word_index >= 0) {
203 		u32 data[4];
204 		u32 res = 0, size = 4;
205 		int ret;
206 
207 		/* Only UID return 4 words */
208 		if (word_index != 1)
209 			size = 1;
210 
211 		ret = ele_read_common_fuse(word_index, data, size, &res);
212 		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 }
236 
237 #elif defined(CONFIG_ARCH_IMX9)
fuse_sense(u32 bank,u32 word,u32 * val)238 int fuse_sense(u32 bank, u32 word, u32 *val)
239 {
240 	s32 word_index;
241 	bool redundancy;
242 
243 	if (word >= WORDS_PER_BANKS || !val)
244 		return -EINVAL;
245 
246 	if (!IS_ENABLED(CONFIG_SCMI_FIRMWARE)) {
247 		word_index = map_fsb_fuse_index(bank, word, &redundancy);
248 
249 		/* 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;
254 	}
255 
256 	if (word_index >= 0) {
257 		u32 data;
258 		u32 res = 0, size = 1;
259 		int ret;
260 
261 		ret = ele_read_common_fuse(word_index, &data, size, &res);
262 		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
275 
fuse_read_default(u32 bank,u32 word,u32 * val)276 static int fuse_read_default(u32 bank, u32 word, u32 *val)
277 {
278 	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 
292 	return fuse_sense(bank, word, val);
293 }
294 
fuse_read_ele_shd(u32 bank,u32 word,u32 * val)295 static 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 
fuse_read(u32 bank,u32 word,u32 * val)313 int 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 
fuse_prog(u32 bank,u32 word,u32 val)325 int fuse_prog(u32 bank, u32 word, u32 val)
326 {
327 	u32 res = 0;
328 	int ret;
329 	bool lock = false;
330 
331 	if (word >= WORDS_PER_BANKS || !val)
332 		return -EINVAL;
333 
334 	/* 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 
348 	ret = ele_write_fuse((bank * 8 + word), val, lock, &res);
349 	if (ret) {
350 		printf("ahab write fuse failed %d, 0x%x\n", ret, res);
351 		return ret;
352 	}
353 
354 	return 0;
355 }
356 
fuse_override(u32 bank,u32 word,u32 val)357 int fuse_override(u32 bank, u32 word, u32 val)
358 {
359 	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;
372 }
373