blob: 165474fb8ad8d1dfa01e8d230f01f7e228f004e5 [file] [log] [blame]
Pankaj Gupta44392ea2020-12-09 14:02:38 +05301/*
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
23static 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
44static 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 */
74static 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. */
90static 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. */
113static 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 */
156static 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 */
207static 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
319out:
320 return ret;
321}
322
323/* This function program OSPR1 in fuse registers.
324 */
325static int prog_ospr1(struct fuse_hdr_t *fuse_hdr,
326 struct sfp_ccsr_regs_t *sfp_ccsr_regs)
327{
328 int ret;
Jiafei Panbdb16362021-09-27 11:47:11 +0800329 uint32_t mask = 0;
Pankaj Gupta44392ea2020-12-09 14:02:38 +0530330
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 */
353static 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 */
372int 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 }
460out:
461 return ret;
462}