• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 NXP
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <stdbool.h>
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include <caam.h>
15 #include <common/debug.h>
16 #include <dcfg.h>
17 #include <drivers/delay_timer.h>
18 #include <fuse_prov.h>
19 #include <sfp.h>
20 #include <sfp_error_codes.h>
21 
22 
write_a_fuse(uint32_t * fuse_addr,uint32_t * fuse_hdr_val,uint32_t mask)23 static int write_a_fuse(uint32_t *fuse_addr, uint32_t *fuse_hdr_val,
24 			uint32_t mask)
25 {
26 	uint32_t last_stored_val = sfp_read32(fuse_addr);
27 
28 	 /* Check if fuse already blown or not */
29 	if ((last_stored_val & mask) == mask) {
30 		return ERROR_ALREADY_BLOWN;
31 	}
32 
33 	 /* Write fuse in mirror registers */
34 	sfp_write32(fuse_addr, last_stored_val | (*fuse_hdr_val & mask));
35 
36 	 /* Read back to check if write success */
37 	if (sfp_read32(fuse_addr) != (last_stored_val | (*fuse_hdr_val & mask))) {
38 		return ERROR_WRITE;
39 	}
40 
41 	return 0;
42 }
43 
write_fuses(uint32_t * fuse_addr,uint32_t * fuse_hdr_val,uint8_t len)44 static int write_fuses(uint32_t *fuse_addr, uint32_t *fuse_hdr_val, uint8_t len)
45 {
46 	int i;
47 
48 	 /* Check if fuse already blown or not */
49 	for (i = 0; i < len; i++) {
50 		if (sfp_read32(&fuse_addr[i]) != 0) {
51 			return ERROR_ALREADY_BLOWN;
52 		}
53 	}
54 
55 	 /* Write fuse in mirror registers */
56 	for (i = 0; i < len; i++) {
57 		sfp_write32(&fuse_addr[i], fuse_hdr_val[i]);
58 	}
59 
60 	 /* Read back to check if write success */
61 	for (i = 0; i < len; i++) {
62 		if (sfp_read32(&fuse_addr[i]) != fuse_hdr_val[i]) {
63 			return ERROR_WRITE;
64 		}
65 	}
66 
67 	return 0;
68 }
69 
70 /*
71  * This function program Super Root Key Hash (SRKH) in fuse
72  * registers.
73  */
prog_srkh(struct fuse_hdr_t * fuse_hdr,struct sfp_ccsr_regs_t * sfp_ccsr_regs)74 static int prog_srkh(struct fuse_hdr_t *fuse_hdr,
75 		     struct sfp_ccsr_regs_t *sfp_ccsr_regs)
76 {
77 	int ret = 0;
78 
79 	ret = write_fuses(sfp_ccsr_regs->srk_hash, fuse_hdr->srkh, 8);
80 
81 	if (ret != 0) {
82 		ret = (ret == ERROR_ALREADY_BLOWN) ?
83 			ERROR_SRKH_ALREADY_BLOWN : ERROR_SRKH_WRITE;
84 	}
85 
86 	return ret;
87 }
88 
89 /* This function program OEMUID[0-4] in fuse registers. */
prog_oemuid(struct fuse_hdr_t * fuse_hdr,struct sfp_ccsr_regs_t * sfp_ccsr_regs)90 static int prog_oemuid(struct fuse_hdr_t *fuse_hdr,
91 		       struct sfp_ccsr_regs_t *sfp_ccsr_regs)
92 {
93 	int i, ret = 0;
94 
95 	for (i = 0; i < 5; i++) {
96 		 /* Check OEMUIDx to be blown or not */
97 		if (((fuse_hdr->flags >> (FLAG_OUID0_SHIFT + i)) & 0x1) != 0) {
98 			 /* Check if OEMUID[i] already blown or not */
99 			ret = write_fuses(&sfp_ccsr_regs->oem_uid[i],
100 					 &fuse_hdr->oem_uid[i], 1);
101 
102 			if (ret != 0) {
103 				ret = (ret == ERROR_ALREADY_BLOWN) ?
104 					ERROR_OEMUID_ALREADY_BLOWN
105 					: ERROR_OEMUID_WRITE;
106 			}
107 		}
108 	}
109 	return ret;
110 }
111 
112 /* This function program DCV[0-1], DRV[0-1] in fuse registers. */
prog_debug(struct fuse_hdr_t * fuse_hdr,struct sfp_ccsr_regs_t * sfp_ccsr_regs)113 static int prog_debug(struct fuse_hdr_t *fuse_hdr,
114 		      struct sfp_ccsr_regs_t *sfp_ccsr_regs)
115 {
116 	int ret;
117 
118 	 /* Check DCV to be blown or not */
119 	if (((fuse_hdr->flags >> (FLAG_DCV0_SHIFT)) & 0x3) != 0) {
120 		 /* Check if DCV[i] already blown or not */
121 		ret = write_fuses(sfp_ccsr_regs->dcv, fuse_hdr->dcv, 2);
122 
123 		if (ret != 0) {
124 			ret = (ret == ERROR_ALREADY_BLOWN) ?
125 				ERROR_DCV_ALREADY_BLOWN
126 				: ERROR_DCV_WRITE;
127 		}
128 	}
129 
130 	 /* Check DRV to be blown or not */
131 	if ((((fuse_hdr->flags >> (FLAG_DRV0_SHIFT)) & 0x3)) != 0) {
132 		 /* Check if DRV[i] already blown or not */
133 		ret = write_fuses(sfp_ccsr_regs->drv, fuse_hdr->drv, 2);
134 
135 		if (ret != 0) {
136 			ret = (ret == ERROR_ALREADY_BLOWN) ?
137 				ERROR_DRV_ALREADY_BLOWN
138 				: ERROR_DRV_WRITE;
139 		} else {
140 			 /* Check for DRV hamming error */
141 			if (sfp_read32((void *)(get_sfp_addr()
142 							+ SFP_SVHESR_OFFSET))
143 				& SFP_SVHESR_DRV_MASK) {
144 				return ERROR_DRV_HAMMING_ERROR;
145 			}
146 		}
147 	}
148 
149 	return 0;
150 }
151 
152  /*
153   * Turn a 256-bit random value (32 bytes) into an OTPMK code word
154   * modifying the input data array in place
155   */
otpmk_make_code_word_256(uint8_t * otpmk,bool minimal_flag)156 static void otpmk_make_code_word_256(uint8_t *otpmk, bool minimal_flag)
157 {
158 	int i;
159 	uint8_t parity_bit;
160 	uint8_t code_bit;
161 
162 	if (minimal_flag == true) {
163 		 /*
164 		  * Force bits 252, 253, 254 and 255 to 1
165 		  * This is because these fuses may have already been blown
166 		  * and the OTPMK cannot force them back to 0
167 		  */
168 		otpmk[252/8] |= (1 << (252%8));
169 		otpmk[253/8] |= (1 << (253%8));
170 		otpmk[254/8] |= (1 << (254%8));
171 		otpmk[255/8] |= (1 << (255%8));
172 	}
173 
174 	 /* Generate the hamming code for the code word */
175 	parity_bit = 0;
176 	code_bit = 0;
177 	for (i = 0; i < 256; i += 1) {
178 		if ((otpmk[i/8] & (1 << (i%8))) != 0) {
179 			parity_bit ^= 1;
180 			code_bit   ^= i;
181 		}
182 	}
183 
184 	 /* Inverting otpmk[code_bit] will cause the otpmk
185 	  * to become a valid code word (except for overall parity)
186 	  */
187 	if (code_bit < 252) {
188 		otpmk[code_bit/8] ^= (1 << (code_bit % 8));
189 		parity_bit  ^= 1;  // account for flipping a bit changing parity
190 	} else {
191 		 /* Invert two bits:  (code_bit - 4) and 4
192 		  * Because we invert two bits, no need to touch the parity bit
193 		  */
194 		otpmk[(code_bit - 4)/8] ^= (1 << ((code_bit - 4) % 8));
195 		otpmk[4/8] ^= (1 << (4 % 8));
196 	}
197 
198 	 /* Finally, adjust the overall parity of the otpmk
199 	  * otpmk bit 0
200 	  */
201 	otpmk[0] ^= parity_bit;
202 }
203 
204 /* This function program One Time Programmable Master Key (OTPMK)
205  *  in fuse registers.
206  */
prog_otpmk(struct fuse_hdr_t * fuse_hdr,struct sfp_ccsr_regs_t * sfp_ccsr_regs)207 static int prog_otpmk(struct fuse_hdr_t *fuse_hdr,
208 		      struct sfp_ccsr_regs_t *sfp_ccsr_regs)
209 {
210 	int ret = 0;
211 	uint32_t otpmk_flags;
212 	uint32_t otpmk_random[8] __aligned(CACHE_WRITEBACK_GRANULE);
213 
214 	otpmk_flags = (fuse_hdr->flags >> (FLAG_OTPMK_SHIFT)) & FLAG_OTPMK_MASK;
215 
216 	switch (otpmk_flags) {
217 	case PROG_OTPMK_MIN:
218 		memset(fuse_hdr->otpmk, 0, sizeof(fuse_hdr->otpmk));
219 
220 		 /* Minimal OTPMK value (252-255 bits set to 1) */
221 		fuse_hdr->otpmk[0] |= OTPMK_MIM_BITS_MASK;
222 		break;
223 
224 	case PROG_OTPMK_RANDOM:
225 		if (is_sec_enabled() == false) {
226 			ret = ERROR_OTPMK_SEC_DISABLED;
227 			goto out;
228 		}
229 
230 		 /* Generate Random number using CAAM for OTPMK */
231 		memset(otpmk_random, 0, sizeof(otpmk_random));
232 		if (get_rand_bytes_hw((uint8_t *)otpmk_random,
233 				      sizeof(otpmk_random)) != 0) {
234 			ret = ERROR_OTPMK_SEC_ERROR;
235 			goto out;
236 		}
237 
238 		 /* Run hamming over random no. to make OTPMK */
239 		otpmk_make_code_word_256((uint8_t *)otpmk_random, false);
240 
241 		 /* Swap OTPMK */
242 		fuse_hdr->otpmk[0] = otpmk_random[7];
243 		fuse_hdr->otpmk[1] = otpmk_random[6];
244 		fuse_hdr->otpmk[2] = otpmk_random[5];
245 		fuse_hdr->otpmk[3] = otpmk_random[4];
246 		fuse_hdr->otpmk[4] = otpmk_random[3];
247 		fuse_hdr->otpmk[5] = otpmk_random[2];
248 		fuse_hdr->otpmk[6] = otpmk_random[1];
249 		fuse_hdr->otpmk[7] = otpmk_random[0];
250 		break;
251 
252 	case PROG_OTPMK_USER:
253 		break;
254 
255 	case PROG_OTPMK_RANDOM_MIN:
256 		 /* Here assumption is that user is aware of minimal OTPMK
257 		  * already blown.
258 		  */
259 
260 		 /* Generate Random number using CAAM for OTPMK */
261 		if (is_sec_enabled() == false) {
262 			ret = ERROR_OTPMK_SEC_DISABLED;
263 			goto out;
264 		}
265 
266 		memset(otpmk_random, 0, sizeof(otpmk_random));
267 		if (get_rand_bytes_hw((uint8_t *)otpmk_random,
268 				      sizeof(otpmk_random)) != 0) {
269 			ret = ERROR_OTPMK_SEC_ERROR;
270 			goto out;
271 		}
272 
273 		 /* Run hamming over random no. to make OTPMK */
274 		otpmk_make_code_word_256((uint8_t *)otpmk_random, true);
275 
276 		 /* Swap OTPMK */
277 		fuse_hdr->otpmk[0] = otpmk_random[7];
278 		fuse_hdr->otpmk[1] = otpmk_random[6];
279 		fuse_hdr->otpmk[2] = otpmk_random[5];
280 		fuse_hdr->otpmk[3] = otpmk_random[4];
281 		fuse_hdr->otpmk[4] = otpmk_random[3];
282 		fuse_hdr->otpmk[5] = otpmk_random[2];
283 		fuse_hdr->otpmk[6] = otpmk_random[1];
284 		fuse_hdr->otpmk[7] = otpmk_random[0];
285 		break;
286 
287 	case PROG_OTPMK_USER_MIN:
288 		 /*
289 		  * Here assumption is that user is aware of minimal OTPMK
290 		  * already blown. Check if minimal bits are set in user
291 		  * supplied OTPMK.
292 		  */
293 		if ((fuse_hdr->otpmk[0] & OTPMK_MIM_BITS_MASK) !=
294 							OTPMK_MIM_BITS_MASK) {
295 			ret = ERROR_OTPMK_USER_MIN;
296 			goto out;
297 		}
298 		break;
299 
300 	default:
301 		ret = 0;
302 		goto out;
303 	}
304 
305 	ret = write_fuses(sfp_ccsr_regs->otpmk, fuse_hdr->otpmk, 8);
306 
307 	if (ret != 0) {
308 		ret = (ret == ERROR_ALREADY_BLOWN) ?
309 			ERROR_OTPMK_ALREADY_BLOWN
310 			: ERROR_OTPMK_WRITE;
311 	} else {
312 		 /* Check for DRV hamming error */
313 		if ((sfp_read32((void *)(get_sfp_addr() + SFP_SVHESR_OFFSET))
314 			& SFP_SVHESR_OTPMK_MASK) != 0) {
315 			ret = ERROR_OTPMK_HAMMING_ERROR;
316 		}
317 	}
318 
319 out:
320 	return ret;
321 }
322 
323 /* This function program OSPR1 in fuse registers.
324  */
prog_ospr1(struct fuse_hdr_t * fuse_hdr,struct sfp_ccsr_regs_t * sfp_ccsr_regs)325 static int prog_ospr1(struct fuse_hdr_t *fuse_hdr,
326 		      struct sfp_ccsr_regs_t *sfp_ccsr_regs)
327 {
328 	int ret;
329 	uint32_t mask = 0;
330 
331 #ifdef NXP_SFP_VER_3_4
332 	if (((fuse_hdr->flags >> FLAG_MC_SHIFT) & 0x1) != 0) {
333 		mask = OSPR1_MC_MASK;
334 	}
335 #endif
336 	if (((fuse_hdr->flags >> FLAG_DBG_LVL_SHIFT) & 0x1) != 0) {
337 		mask = mask | OSPR1_DBG_LVL_MASK;
338 	}
339 
340 	ret = write_a_fuse(&sfp_ccsr_regs->ospr1, &fuse_hdr->ospr1, mask);
341 
342 	if (ret != 0) {
343 		ret = (ret == ERROR_ALREADY_BLOWN) ?
344 				ERROR_OSPR1_ALREADY_BLOWN
345 				: ERROR_OSPR1_WRITE;
346 	}
347 
348 	return ret;
349 }
350 
351 /* This function program SYSCFG in fuse registers.
352  */
prog_syscfg(struct fuse_hdr_t * fuse_hdr,struct sfp_ccsr_regs_t * sfp_ccsr_regs)353 static int prog_syscfg(struct fuse_hdr_t *fuse_hdr,
354 		       struct sfp_ccsr_regs_t *sfp_ccsr_regs)
355 {
356 	int ret;
357 
358 	 /* Check if SYSCFG already blown or not */
359 	ret = write_a_fuse(&sfp_ccsr_regs->ospr, &fuse_hdr->sc, OSPR0_SC_MASK);
360 
361 	if (ret != 0) {
362 		ret = (ret == ERROR_ALREADY_BLOWN) ?
363 				ERROR_SC_ALREADY_BLOWN
364 				: ERROR_SC_WRITE;
365 	}
366 
367 	return ret;
368 }
369 
370 /* This function does fuse provisioning.
371  */
provision_fuses(unsigned long long fuse_scr_addr,bool en_povdd_status)372 int provision_fuses(unsigned long long fuse_scr_addr,
373 		    bool en_povdd_status)
374 {
375 	struct fuse_hdr_t *fuse_hdr = NULL;
376 	struct sfp_ccsr_regs_t *sfp_ccsr_regs = (void *)(get_sfp_addr()
377 							+ SFP_FUSE_REGS_OFFSET);
378 	int ret = 0;
379 
380 	fuse_hdr = (struct fuse_hdr_t *)fuse_scr_addr;
381 
382 	/*
383 	 * Check for Write Protect (WP) fuse. If blown then do
384 	 *  no fuse provisioning.
385 	 */
386 	if ((sfp_read32(&sfp_ccsr_regs->ospr) & 0x1) != 0) {
387 		goto out;
388 	}
389 
390 	 /* Check if SRKH to be blown or not */
391 	if (((fuse_hdr->flags >> FLAG_SRKH_SHIFT) & 0x1) != 0) {
392 		INFO("Fuse: Program SRKH\n");
393 		ret = prog_srkh(fuse_hdr, sfp_ccsr_regs);
394 		if (ret != 0) {
395 			error_handler(ret);
396 			goto out;
397 		}
398 	}
399 
400 	 /* Check if OEMUID to be blown or not */
401 	if (((fuse_hdr->flags >> FLAG_OUID0_SHIFT) & FLAG_OUID_MASK) != 0) {
402 		INFO("Fuse: Program OEMUIDs\n");
403 		ret = prog_oemuid(fuse_hdr, sfp_ccsr_regs);
404 		if (ret != 0) {
405 			error_handler(ret);
406 			goto out;
407 		}
408 	}
409 
410 	 /* Check if Debug values to be blown or not */
411 	if (((fuse_hdr->flags >> FLAG_DCV0_SHIFT) & FLAG_DEBUG_MASK) != 0) {
412 		INFO("Fuse: Program Debug values\n");
413 		ret = prog_debug(fuse_hdr, sfp_ccsr_regs);
414 		if (ret != 0) {
415 			error_handler(ret);
416 			goto out;
417 		}
418 	}
419 
420 	 /* Check if OTPMK values to be blown or not */
421 	if (((fuse_hdr->flags >> FLAG_OTPMK_SHIFT) & PROG_NO_OTPMK) !=
422 		PROG_NO_OTPMK) {
423 		INFO("Fuse: Program OTPMK\n");
424 		ret = prog_otpmk(fuse_hdr, sfp_ccsr_regs);
425 		if (ret != 0) {
426 			error_handler(ret);
427 			goto out;
428 		}
429 	}
430 
431 
432 	 /* Check if MC or DBG LVL to be blown or not */
433 	if ((((fuse_hdr->flags >> FLAG_MC_SHIFT) & 0x1) != 0) ||
434 		(((fuse_hdr->flags >> FLAG_DBG_LVL_SHIFT) & 0x1) != 0)) {
435 		INFO("Fuse: Program OSPR1\n");
436 		ret = prog_ospr1(fuse_hdr, sfp_ccsr_regs);
437 		if (ret != 0) {
438 			error_handler(ret);
439 			goto out;
440 		}
441 	}
442 
443 	 /* Check if SYSCFG to be blown or not */
444 	if (((fuse_hdr->flags >> FLAG_SYSCFG_SHIFT) & 0x1) != 0) {
445 		INFO("Fuse: Program SYSCFG\n");
446 		ret = prog_syscfg(fuse_hdr, sfp_ccsr_regs);
447 		if (ret != 0) {
448 			error_handler(ret);
449 			goto out;
450 		}
451 	}
452 
453 	if (en_povdd_status) {
454 		ret = sfp_program_fuses();
455 		if (ret != 0) {
456 			error_handler(ret);
457 			goto out;
458 		}
459 	}
460 out:
461 	return ret;
462 }
463