13979c6d9SPankaj Gupta /*
23979c6d9SPankaj Gupta * Copyright 2021 NXP
33979c6d9SPankaj Gupta *
43979c6d9SPankaj Gupta * SPDX-License-Identifier: BSD-3-Clause
53979c6d9SPankaj Gupta *
63979c6d9SPankaj Gupta */
73979c6d9SPankaj Gupta
83979c6d9SPankaj Gupta #include <stdbool.h>
93979c6d9SPankaj Gupta #include <stdint.h>
103979c6d9SPankaj Gupta #include <stdio.h>
113979c6d9SPankaj Gupta #include <stdlib.h>
123979c6d9SPankaj Gupta #include <string.h>
133979c6d9SPankaj Gupta
143979c6d9SPankaj Gupta #include <caam.h>
153979c6d9SPankaj Gupta #include <common/debug.h>
163979c6d9SPankaj Gupta #include <dcfg.h>
173979c6d9SPankaj Gupta #include <drivers/delay_timer.h>
183979c6d9SPankaj Gupta #include <fuse_prov.h>
193979c6d9SPankaj Gupta #include <sfp.h>
203979c6d9SPankaj Gupta #include <sfp_error_codes.h>
213979c6d9SPankaj Gupta
223979c6d9SPankaj Gupta
write_a_fuse(uint32_t * fuse_addr,uint32_t * fuse_hdr_val,uint32_t mask)233979c6d9SPankaj Gupta static int write_a_fuse(uint32_t *fuse_addr, uint32_t *fuse_hdr_val,
243979c6d9SPankaj Gupta uint32_t mask)
253979c6d9SPankaj Gupta {
263979c6d9SPankaj Gupta uint32_t last_stored_val = sfp_read32(fuse_addr);
273979c6d9SPankaj Gupta
283979c6d9SPankaj Gupta /* Check if fuse already blown or not */
293979c6d9SPankaj Gupta if ((last_stored_val & mask) == mask) {
303979c6d9SPankaj Gupta return ERROR_ALREADY_BLOWN;
313979c6d9SPankaj Gupta }
323979c6d9SPankaj Gupta
333979c6d9SPankaj Gupta /* Write fuse in mirror registers */
343979c6d9SPankaj Gupta sfp_write32(fuse_addr, last_stored_val | (*fuse_hdr_val & mask));
353979c6d9SPankaj Gupta
363979c6d9SPankaj Gupta /* Read back to check if write success */
373979c6d9SPankaj Gupta if (sfp_read32(fuse_addr) != (last_stored_val | (*fuse_hdr_val & mask))) {
383979c6d9SPankaj Gupta return ERROR_WRITE;
393979c6d9SPankaj Gupta }
403979c6d9SPankaj Gupta
413979c6d9SPankaj Gupta return 0;
423979c6d9SPankaj Gupta }
433979c6d9SPankaj Gupta
write_fuses(uint32_t * fuse_addr,uint32_t * fuse_hdr_val,uint8_t len)443979c6d9SPankaj Gupta static int write_fuses(uint32_t *fuse_addr, uint32_t *fuse_hdr_val, uint8_t len)
453979c6d9SPankaj Gupta {
463979c6d9SPankaj Gupta int i;
473979c6d9SPankaj Gupta
483979c6d9SPankaj Gupta /* Check if fuse already blown or not */
493979c6d9SPankaj Gupta for (i = 0; i < len; i++) {
503979c6d9SPankaj Gupta if (sfp_read32(&fuse_addr[i]) != 0) {
513979c6d9SPankaj Gupta return ERROR_ALREADY_BLOWN;
523979c6d9SPankaj Gupta }
533979c6d9SPankaj Gupta }
543979c6d9SPankaj Gupta
553979c6d9SPankaj Gupta /* Write fuse in mirror registers */
563979c6d9SPankaj Gupta for (i = 0; i < len; i++) {
573979c6d9SPankaj Gupta sfp_write32(&fuse_addr[i], fuse_hdr_val[i]);
583979c6d9SPankaj Gupta }
593979c6d9SPankaj Gupta
603979c6d9SPankaj Gupta /* Read back to check if write success */
613979c6d9SPankaj Gupta for (i = 0; i < len; i++) {
623979c6d9SPankaj Gupta if (sfp_read32(&fuse_addr[i]) != fuse_hdr_val[i]) {
633979c6d9SPankaj Gupta return ERROR_WRITE;
643979c6d9SPankaj Gupta }
653979c6d9SPankaj Gupta }
663979c6d9SPankaj Gupta
673979c6d9SPankaj Gupta return 0;
683979c6d9SPankaj Gupta }
693979c6d9SPankaj Gupta
703979c6d9SPankaj Gupta /*
713979c6d9SPankaj Gupta * This function program Super Root Key Hash (SRKH) in fuse
723979c6d9SPankaj Gupta * registers.
733979c6d9SPankaj Gupta */
prog_srkh(struct fuse_hdr_t * fuse_hdr,struct sfp_ccsr_regs_t * sfp_ccsr_regs)743979c6d9SPankaj Gupta static int prog_srkh(struct fuse_hdr_t *fuse_hdr,
753979c6d9SPankaj Gupta struct sfp_ccsr_regs_t *sfp_ccsr_regs)
763979c6d9SPankaj Gupta {
773979c6d9SPankaj Gupta int ret = 0;
783979c6d9SPankaj Gupta
793979c6d9SPankaj Gupta ret = write_fuses(sfp_ccsr_regs->srk_hash, fuse_hdr->srkh, 8);
803979c6d9SPankaj Gupta
813979c6d9SPankaj Gupta if (ret != 0) {
823979c6d9SPankaj Gupta ret = (ret == ERROR_ALREADY_BLOWN) ?
833979c6d9SPankaj Gupta ERROR_SRKH_ALREADY_BLOWN : ERROR_SRKH_WRITE;
843979c6d9SPankaj Gupta }
853979c6d9SPankaj Gupta
863979c6d9SPankaj Gupta return ret;
873979c6d9SPankaj Gupta }
883979c6d9SPankaj Gupta
893979c6d9SPankaj Gupta /* 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)903979c6d9SPankaj Gupta static int prog_oemuid(struct fuse_hdr_t *fuse_hdr,
913979c6d9SPankaj Gupta struct sfp_ccsr_regs_t *sfp_ccsr_regs)
923979c6d9SPankaj Gupta {
933979c6d9SPankaj Gupta int i, ret = 0;
943979c6d9SPankaj Gupta
953979c6d9SPankaj Gupta for (i = 0; i < 5; i++) {
963979c6d9SPankaj Gupta /* Check OEMUIDx to be blown or not */
973979c6d9SPankaj Gupta if (((fuse_hdr->flags >> (FLAG_OUID0_SHIFT + i)) & 0x1) != 0) {
983979c6d9SPankaj Gupta /* Check if OEMUID[i] already blown or not */
993979c6d9SPankaj Gupta ret = write_fuses(&sfp_ccsr_regs->oem_uid[i],
1003979c6d9SPankaj Gupta &fuse_hdr->oem_uid[i], 1);
1013979c6d9SPankaj Gupta
1023979c6d9SPankaj Gupta if (ret != 0) {
1033979c6d9SPankaj Gupta ret = (ret == ERROR_ALREADY_BLOWN) ?
1043979c6d9SPankaj Gupta ERROR_OEMUID_ALREADY_BLOWN
1053979c6d9SPankaj Gupta : ERROR_OEMUID_WRITE;
1063979c6d9SPankaj Gupta }
1073979c6d9SPankaj Gupta }
1083979c6d9SPankaj Gupta }
1093979c6d9SPankaj Gupta return ret;
1103979c6d9SPankaj Gupta }
1113979c6d9SPankaj Gupta
1123979c6d9SPankaj Gupta /* 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)1133979c6d9SPankaj Gupta static int prog_debug(struct fuse_hdr_t *fuse_hdr,
1143979c6d9SPankaj Gupta struct sfp_ccsr_regs_t *sfp_ccsr_regs)
1153979c6d9SPankaj Gupta {
1163979c6d9SPankaj Gupta int ret;
1173979c6d9SPankaj Gupta
1183979c6d9SPankaj Gupta /* Check DCV to be blown or not */
1193979c6d9SPankaj Gupta if (((fuse_hdr->flags >> (FLAG_DCV0_SHIFT)) & 0x3) != 0) {
1203979c6d9SPankaj Gupta /* Check if DCV[i] already blown or not */
1213979c6d9SPankaj Gupta ret = write_fuses(sfp_ccsr_regs->dcv, fuse_hdr->dcv, 2);
1223979c6d9SPankaj Gupta
1233979c6d9SPankaj Gupta if (ret != 0) {
1243979c6d9SPankaj Gupta ret = (ret == ERROR_ALREADY_BLOWN) ?
1253979c6d9SPankaj Gupta ERROR_DCV_ALREADY_BLOWN
1263979c6d9SPankaj Gupta : ERROR_DCV_WRITE;
1273979c6d9SPankaj Gupta }
1283979c6d9SPankaj Gupta }
1293979c6d9SPankaj Gupta
1303979c6d9SPankaj Gupta /* Check DRV to be blown or not */
1313979c6d9SPankaj Gupta if ((((fuse_hdr->flags >> (FLAG_DRV0_SHIFT)) & 0x3)) != 0) {
1323979c6d9SPankaj Gupta /* Check if DRV[i] already blown or not */
1333979c6d9SPankaj Gupta ret = write_fuses(sfp_ccsr_regs->drv, fuse_hdr->drv, 2);
1343979c6d9SPankaj Gupta
1353979c6d9SPankaj Gupta if (ret != 0) {
1363979c6d9SPankaj Gupta ret = (ret == ERROR_ALREADY_BLOWN) ?
1373979c6d9SPankaj Gupta ERROR_DRV_ALREADY_BLOWN
1383979c6d9SPankaj Gupta : ERROR_DRV_WRITE;
1393979c6d9SPankaj Gupta } else {
1403979c6d9SPankaj Gupta /* Check for DRV hamming error */
1413979c6d9SPankaj Gupta if (sfp_read32((void *)(get_sfp_addr()
1423979c6d9SPankaj Gupta + SFP_SVHESR_OFFSET))
1433979c6d9SPankaj Gupta & SFP_SVHESR_DRV_MASK) {
1443979c6d9SPankaj Gupta return ERROR_DRV_HAMMING_ERROR;
1453979c6d9SPankaj Gupta }
1463979c6d9SPankaj Gupta }
1473979c6d9SPankaj Gupta }
1483979c6d9SPankaj Gupta
1493979c6d9SPankaj Gupta return 0;
1503979c6d9SPankaj Gupta }
1513979c6d9SPankaj Gupta
1523979c6d9SPankaj Gupta /*
1533979c6d9SPankaj Gupta * Turn a 256-bit random value (32 bytes) into an OTPMK code word
1543979c6d9SPankaj Gupta * modifying the input data array in place
1553979c6d9SPankaj Gupta */
otpmk_make_code_word_256(uint8_t * otpmk,bool minimal_flag)1563979c6d9SPankaj Gupta static void otpmk_make_code_word_256(uint8_t *otpmk, bool minimal_flag)
1573979c6d9SPankaj Gupta {
1583979c6d9SPankaj Gupta int i;
1593979c6d9SPankaj Gupta uint8_t parity_bit;
1603979c6d9SPankaj Gupta uint8_t code_bit;
1613979c6d9SPankaj Gupta
1623979c6d9SPankaj Gupta if (minimal_flag == true) {
1633979c6d9SPankaj Gupta /*
1643979c6d9SPankaj Gupta * Force bits 252, 253, 254 and 255 to 1
1653979c6d9SPankaj Gupta * This is because these fuses may have already been blown
1663979c6d9SPankaj Gupta * and the OTPMK cannot force them back to 0
1673979c6d9SPankaj Gupta */
1683979c6d9SPankaj Gupta otpmk[252/8] |= (1 << (252%8));
1693979c6d9SPankaj Gupta otpmk[253/8] |= (1 << (253%8));
1703979c6d9SPankaj Gupta otpmk[254/8] |= (1 << (254%8));
1713979c6d9SPankaj Gupta otpmk[255/8] |= (1 << (255%8));
1723979c6d9SPankaj Gupta }
1733979c6d9SPankaj Gupta
1743979c6d9SPankaj Gupta /* Generate the hamming code for the code word */
1753979c6d9SPankaj Gupta parity_bit = 0;
1763979c6d9SPankaj Gupta code_bit = 0;
1773979c6d9SPankaj Gupta for (i = 0; i < 256; i += 1) {
1783979c6d9SPankaj Gupta if ((otpmk[i/8] & (1 << (i%8))) != 0) {
1793979c6d9SPankaj Gupta parity_bit ^= 1;
1803979c6d9SPankaj Gupta code_bit ^= i;
1813979c6d9SPankaj Gupta }
1823979c6d9SPankaj Gupta }
1833979c6d9SPankaj Gupta
1843979c6d9SPankaj Gupta /* Inverting otpmk[code_bit] will cause the otpmk
1853979c6d9SPankaj Gupta * to become a valid code word (except for overall parity)
1863979c6d9SPankaj Gupta */
1873979c6d9SPankaj Gupta if (code_bit < 252) {
1883979c6d9SPankaj Gupta otpmk[code_bit/8] ^= (1 << (code_bit % 8));
1893979c6d9SPankaj Gupta parity_bit ^= 1; // account for flipping a bit changing parity
1903979c6d9SPankaj Gupta } else {
1913979c6d9SPankaj Gupta /* Invert two bits: (code_bit - 4) and 4
1923979c6d9SPankaj Gupta * Because we invert two bits, no need to touch the parity bit
1933979c6d9SPankaj Gupta */
1943979c6d9SPankaj Gupta otpmk[(code_bit - 4)/8] ^= (1 << ((code_bit - 4) % 8));
1953979c6d9SPankaj Gupta otpmk[4/8] ^= (1 << (4 % 8));
1963979c6d9SPankaj Gupta }
1973979c6d9SPankaj Gupta
1983979c6d9SPankaj Gupta /* Finally, adjust the overall parity of the otpmk
1993979c6d9SPankaj Gupta * otpmk bit 0
2003979c6d9SPankaj Gupta */
2013979c6d9SPankaj Gupta otpmk[0] ^= parity_bit;
2023979c6d9SPankaj Gupta }
2033979c6d9SPankaj Gupta
2043979c6d9SPankaj Gupta /* This function program One Time Programmable Master Key (OTPMK)
2053979c6d9SPankaj Gupta * in fuse registers.
2063979c6d9SPankaj Gupta */
prog_otpmk(struct fuse_hdr_t * fuse_hdr,struct sfp_ccsr_regs_t * sfp_ccsr_regs)2073979c6d9SPankaj Gupta static int prog_otpmk(struct fuse_hdr_t *fuse_hdr,
2083979c6d9SPankaj Gupta struct sfp_ccsr_regs_t *sfp_ccsr_regs)
2093979c6d9SPankaj Gupta {
2103979c6d9SPankaj Gupta int ret = 0;
2113979c6d9SPankaj Gupta uint32_t otpmk_flags;
2123979c6d9SPankaj Gupta uint32_t otpmk_random[8] __aligned(CACHE_WRITEBACK_GRANULE);
2133979c6d9SPankaj Gupta
2143979c6d9SPankaj Gupta otpmk_flags = (fuse_hdr->flags >> (FLAG_OTPMK_SHIFT)) & FLAG_OTPMK_MASK;
2153979c6d9SPankaj Gupta
2163979c6d9SPankaj Gupta switch (otpmk_flags) {
2173979c6d9SPankaj Gupta case PROG_OTPMK_MIN:
2183979c6d9SPankaj Gupta memset(fuse_hdr->otpmk, 0, sizeof(fuse_hdr->otpmk));
2193979c6d9SPankaj Gupta
2203979c6d9SPankaj Gupta /* Minimal OTPMK value (252-255 bits set to 1) */
2213979c6d9SPankaj Gupta fuse_hdr->otpmk[0] |= OTPMK_MIM_BITS_MASK;
2223979c6d9SPankaj Gupta break;
2233979c6d9SPankaj Gupta
2243979c6d9SPankaj Gupta case PROG_OTPMK_RANDOM:
2253979c6d9SPankaj Gupta if (is_sec_enabled() == false) {
2263979c6d9SPankaj Gupta ret = ERROR_OTPMK_SEC_DISABLED;
2273979c6d9SPankaj Gupta goto out;
2283979c6d9SPankaj Gupta }
2293979c6d9SPankaj Gupta
2303979c6d9SPankaj Gupta /* Generate Random number using CAAM for OTPMK */
2313979c6d9SPankaj Gupta memset(otpmk_random, 0, sizeof(otpmk_random));
2323979c6d9SPankaj Gupta if (get_rand_bytes_hw((uint8_t *)otpmk_random,
2333979c6d9SPankaj Gupta sizeof(otpmk_random)) != 0) {
2343979c6d9SPankaj Gupta ret = ERROR_OTPMK_SEC_ERROR;
2353979c6d9SPankaj Gupta goto out;
2363979c6d9SPankaj Gupta }
2373979c6d9SPankaj Gupta
2383979c6d9SPankaj Gupta /* Run hamming over random no. to make OTPMK */
2393979c6d9SPankaj Gupta otpmk_make_code_word_256((uint8_t *)otpmk_random, false);
2403979c6d9SPankaj Gupta
2413979c6d9SPankaj Gupta /* Swap OTPMK */
2423979c6d9SPankaj Gupta fuse_hdr->otpmk[0] = otpmk_random[7];
2433979c6d9SPankaj Gupta fuse_hdr->otpmk[1] = otpmk_random[6];
2443979c6d9SPankaj Gupta fuse_hdr->otpmk[2] = otpmk_random[5];
2453979c6d9SPankaj Gupta fuse_hdr->otpmk[3] = otpmk_random[4];
2463979c6d9SPankaj Gupta fuse_hdr->otpmk[4] = otpmk_random[3];
2473979c6d9SPankaj Gupta fuse_hdr->otpmk[5] = otpmk_random[2];
2483979c6d9SPankaj Gupta fuse_hdr->otpmk[6] = otpmk_random[1];
2493979c6d9SPankaj Gupta fuse_hdr->otpmk[7] = otpmk_random[0];
2503979c6d9SPankaj Gupta break;
2513979c6d9SPankaj Gupta
2523979c6d9SPankaj Gupta case PROG_OTPMK_USER:
2533979c6d9SPankaj Gupta break;
2543979c6d9SPankaj Gupta
2553979c6d9SPankaj Gupta case PROG_OTPMK_RANDOM_MIN:
2563979c6d9SPankaj Gupta /* Here assumption is that user is aware of minimal OTPMK
2573979c6d9SPankaj Gupta * already blown.
2583979c6d9SPankaj Gupta */
2593979c6d9SPankaj Gupta
2603979c6d9SPankaj Gupta /* Generate Random number using CAAM for OTPMK */
2613979c6d9SPankaj Gupta if (is_sec_enabled() == false) {
2623979c6d9SPankaj Gupta ret = ERROR_OTPMK_SEC_DISABLED;
2633979c6d9SPankaj Gupta goto out;
2643979c6d9SPankaj Gupta }
2653979c6d9SPankaj Gupta
2663979c6d9SPankaj Gupta memset(otpmk_random, 0, sizeof(otpmk_random));
2673979c6d9SPankaj Gupta if (get_rand_bytes_hw((uint8_t *)otpmk_random,
2683979c6d9SPankaj Gupta sizeof(otpmk_random)) != 0) {
2693979c6d9SPankaj Gupta ret = ERROR_OTPMK_SEC_ERROR;
2703979c6d9SPankaj Gupta goto out;
2713979c6d9SPankaj Gupta }
2723979c6d9SPankaj Gupta
2733979c6d9SPankaj Gupta /* Run hamming over random no. to make OTPMK */
2743979c6d9SPankaj Gupta otpmk_make_code_word_256((uint8_t *)otpmk_random, true);
2753979c6d9SPankaj Gupta
2763979c6d9SPankaj Gupta /* Swap OTPMK */
2773979c6d9SPankaj Gupta fuse_hdr->otpmk[0] = otpmk_random[7];
2783979c6d9SPankaj Gupta fuse_hdr->otpmk[1] = otpmk_random[6];
2793979c6d9SPankaj Gupta fuse_hdr->otpmk[2] = otpmk_random[5];
2803979c6d9SPankaj Gupta fuse_hdr->otpmk[3] = otpmk_random[4];
2813979c6d9SPankaj Gupta fuse_hdr->otpmk[4] = otpmk_random[3];
2823979c6d9SPankaj Gupta fuse_hdr->otpmk[5] = otpmk_random[2];
2833979c6d9SPankaj Gupta fuse_hdr->otpmk[6] = otpmk_random[1];
2843979c6d9SPankaj Gupta fuse_hdr->otpmk[7] = otpmk_random[0];
2853979c6d9SPankaj Gupta break;
2863979c6d9SPankaj Gupta
2873979c6d9SPankaj Gupta case PROG_OTPMK_USER_MIN:
2883979c6d9SPankaj Gupta /*
2893979c6d9SPankaj Gupta * Here assumption is that user is aware of minimal OTPMK
2903979c6d9SPankaj Gupta * already blown. Check if minimal bits are set in user
2913979c6d9SPankaj Gupta * supplied OTPMK.
2923979c6d9SPankaj Gupta */
2933979c6d9SPankaj Gupta if ((fuse_hdr->otpmk[0] & OTPMK_MIM_BITS_MASK) !=
2943979c6d9SPankaj Gupta OTPMK_MIM_BITS_MASK) {
2953979c6d9SPankaj Gupta ret = ERROR_OTPMK_USER_MIN;
2963979c6d9SPankaj Gupta goto out;
2973979c6d9SPankaj Gupta }
2983979c6d9SPankaj Gupta break;
2993979c6d9SPankaj Gupta
3003979c6d9SPankaj Gupta default:
3013979c6d9SPankaj Gupta ret = 0;
3023979c6d9SPankaj Gupta goto out;
3033979c6d9SPankaj Gupta }
3043979c6d9SPankaj Gupta
3053979c6d9SPankaj Gupta ret = write_fuses(sfp_ccsr_regs->otpmk, fuse_hdr->otpmk, 8);
3063979c6d9SPankaj Gupta
3073979c6d9SPankaj Gupta if (ret != 0) {
3083979c6d9SPankaj Gupta ret = (ret == ERROR_ALREADY_BLOWN) ?
3093979c6d9SPankaj Gupta ERROR_OTPMK_ALREADY_BLOWN
3103979c6d9SPankaj Gupta : ERROR_OTPMK_WRITE;
3113979c6d9SPankaj Gupta } else {
3123979c6d9SPankaj Gupta /* Check for DRV hamming error */
3133979c6d9SPankaj Gupta if ((sfp_read32((void *)(get_sfp_addr() + SFP_SVHESR_OFFSET))
3143979c6d9SPankaj Gupta & SFP_SVHESR_OTPMK_MASK) != 0) {
3153979c6d9SPankaj Gupta ret = ERROR_OTPMK_HAMMING_ERROR;
3163979c6d9SPankaj Gupta }
3173979c6d9SPankaj Gupta }
3183979c6d9SPankaj Gupta
3193979c6d9SPankaj Gupta out:
3203979c6d9SPankaj Gupta return ret;
3213979c6d9SPankaj Gupta }
3223979c6d9SPankaj Gupta
3233979c6d9SPankaj Gupta /* This function program OSPR1 in fuse registers.
3243979c6d9SPankaj Gupta */
prog_ospr1(struct fuse_hdr_t * fuse_hdr,struct sfp_ccsr_regs_t * sfp_ccsr_regs)3253979c6d9SPankaj Gupta static int prog_ospr1(struct fuse_hdr_t *fuse_hdr,
3263979c6d9SPankaj Gupta struct sfp_ccsr_regs_t *sfp_ccsr_regs)
3273979c6d9SPankaj Gupta {
3283979c6d9SPankaj Gupta int ret;
329*3239a175SJiafei Pan uint32_t mask = 0;
3303979c6d9SPankaj Gupta
3313979c6d9SPankaj Gupta #ifdef NXP_SFP_VER_3_4
3323979c6d9SPankaj Gupta if (((fuse_hdr->flags >> FLAG_MC_SHIFT) & 0x1) != 0) {
3333979c6d9SPankaj Gupta mask = OSPR1_MC_MASK;
3343979c6d9SPankaj Gupta }
3353979c6d9SPankaj Gupta #endif
3363979c6d9SPankaj Gupta if (((fuse_hdr->flags >> FLAG_DBG_LVL_SHIFT) & 0x1) != 0) {
3373979c6d9SPankaj Gupta mask = mask | OSPR1_DBG_LVL_MASK;
3383979c6d9SPankaj Gupta }
3393979c6d9SPankaj Gupta
3403979c6d9SPankaj Gupta ret = write_a_fuse(&sfp_ccsr_regs->ospr1, &fuse_hdr->ospr1, mask);
3413979c6d9SPankaj Gupta
3423979c6d9SPankaj Gupta if (ret != 0) {
3433979c6d9SPankaj Gupta ret = (ret == ERROR_ALREADY_BLOWN) ?
3443979c6d9SPankaj Gupta ERROR_OSPR1_ALREADY_BLOWN
3453979c6d9SPankaj Gupta : ERROR_OSPR1_WRITE;
3463979c6d9SPankaj Gupta }
3473979c6d9SPankaj Gupta
3483979c6d9SPankaj Gupta return ret;
3493979c6d9SPankaj Gupta }
3503979c6d9SPankaj Gupta
3513979c6d9SPankaj Gupta /* This function program SYSCFG in fuse registers.
3523979c6d9SPankaj Gupta */
prog_syscfg(struct fuse_hdr_t * fuse_hdr,struct sfp_ccsr_regs_t * sfp_ccsr_regs)3533979c6d9SPankaj Gupta static int prog_syscfg(struct fuse_hdr_t *fuse_hdr,
3543979c6d9SPankaj Gupta struct sfp_ccsr_regs_t *sfp_ccsr_regs)
3553979c6d9SPankaj Gupta {
3563979c6d9SPankaj Gupta int ret;
3573979c6d9SPankaj Gupta
3583979c6d9SPankaj Gupta /* Check if SYSCFG already blown or not */
3593979c6d9SPankaj Gupta ret = write_a_fuse(&sfp_ccsr_regs->ospr, &fuse_hdr->sc, OSPR0_SC_MASK);
3603979c6d9SPankaj Gupta
3613979c6d9SPankaj Gupta if (ret != 0) {
3623979c6d9SPankaj Gupta ret = (ret == ERROR_ALREADY_BLOWN) ?
3633979c6d9SPankaj Gupta ERROR_SC_ALREADY_BLOWN
3643979c6d9SPankaj Gupta : ERROR_SC_WRITE;
3653979c6d9SPankaj Gupta }
3663979c6d9SPankaj Gupta
3673979c6d9SPankaj Gupta return ret;
3683979c6d9SPankaj Gupta }
3693979c6d9SPankaj Gupta
3703979c6d9SPankaj Gupta /* This function does fuse provisioning.
3713979c6d9SPankaj Gupta */
provision_fuses(unsigned long long fuse_scr_addr,bool en_povdd_status)3723979c6d9SPankaj Gupta int provision_fuses(unsigned long long fuse_scr_addr,
3733979c6d9SPankaj Gupta bool en_povdd_status)
3743979c6d9SPankaj Gupta {
3753979c6d9SPankaj Gupta struct fuse_hdr_t *fuse_hdr = NULL;
3763979c6d9SPankaj Gupta struct sfp_ccsr_regs_t *sfp_ccsr_regs = (void *)(get_sfp_addr()
3773979c6d9SPankaj Gupta + SFP_FUSE_REGS_OFFSET);
3783979c6d9SPankaj Gupta int ret = 0;
3793979c6d9SPankaj Gupta
3803979c6d9SPankaj Gupta fuse_hdr = (struct fuse_hdr_t *)fuse_scr_addr;
3813979c6d9SPankaj Gupta
3823979c6d9SPankaj Gupta /*
3833979c6d9SPankaj Gupta * Check for Write Protect (WP) fuse. If blown then do
3843979c6d9SPankaj Gupta * no fuse provisioning.
3853979c6d9SPankaj Gupta */
3863979c6d9SPankaj Gupta if ((sfp_read32(&sfp_ccsr_regs->ospr) & 0x1) != 0) {
3873979c6d9SPankaj Gupta goto out;
3883979c6d9SPankaj Gupta }
3893979c6d9SPankaj Gupta
3903979c6d9SPankaj Gupta /* Check if SRKH to be blown or not */
3913979c6d9SPankaj Gupta if (((fuse_hdr->flags >> FLAG_SRKH_SHIFT) & 0x1) != 0) {
3923979c6d9SPankaj Gupta INFO("Fuse: Program SRKH\n");
3933979c6d9SPankaj Gupta ret = prog_srkh(fuse_hdr, sfp_ccsr_regs);
3943979c6d9SPankaj Gupta if (ret != 0) {
3953979c6d9SPankaj Gupta error_handler(ret);
3963979c6d9SPankaj Gupta goto out;
3973979c6d9SPankaj Gupta }
3983979c6d9SPankaj Gupta }
3993979c6d9SPankaj Gupta
4003979c6d9SPankaj Gupta /* Check if OEMUID to be blown or not */
4013979c6d9SPankaj Gupta if (((fuse_hdr->flags >> FLAG_OUID0_SHIFT) & FLAG_OUID_MASK) != 0) {
4023979c6d9SPankaj Gupta INFO("Fuse: Program OEMUIDs\n");
4033979c6d9SPankaj Gupta ret = prog_oemuid(fuse_hdr, sfp_ccsr_regs);
4043979c6d9SPankaj Gupta if (ret != 0) {
4053979c6d9SPankaj Gupta error_handler(ret);
4063979c6d9SPankaj Gupta goto out;
4073979c6d9SPankaj Gupta }
4083979c6d9SPankaj Gupta }
4093979c6d9SPankaj Gupta
4103979c6d9SPankaj Gupta /* Check if Debug values to be blown or not */
4113979c6d9SPankaj Gupta if (((fuse_hdr->flags >> FLAG_DCV0_SHIFT) & FLAG_DEBUG_MASK) != 0) {
4123979c6d9SPankaj Gupta INFO("Fuse: Program Debug values\n");
4133979c6d9SPankaj Gupta ret = prog_debug(fuse_hdr, sfp_ccsr_regs);
4143979c6d9SPankaj Gupta if (ret != 0) {
4153979c6d9SPankaj Gupta error_handler(ret);
4163979c6d9SPankaj Gupta goto out;
4173979c6d9SPankaj Gupta }
4183979c6d9SPankaj Gupta }
4193979c6d9SPankaj Gupta
4203979c6d9SPankaj Gupta /* Check if OTPMK values to be blown or not */
4213979c6d9SPankaj Gupta if (((fuse_hdr->flags >> FLAG_OTPMK_SHIFT) & PROG_NO_OTPMK) !=
4223979c6d9SPankaj Gupta PROG_NO_OTPMK) {
4233979c6d9SPankaj Gupta INFO("Fuse: Program OTPMK\n");
4243979c6d9SPankaj Gupta ret = prog_otpmk(fuse_hdr, sfp_ccsr_regs);
4253979c6d9SPankaj Gupta if (ret != 0) {
4263979c6d9SPankaj Gupta error_handler(ret);
4273979c6d9SPankaj Gupta goto out;
4283979c6d9SPankaj Gupta }
4293979c6d9SPankaj Gupta }
4303979c6d9SPankaj Gupta
4313979c6d9SPankaj Gupta
4323979c6d9SPankaj Gupta /* Check if MC or DBG LVL to be blown or not */
4333979c6d9SPankaj Gupta if ((((fuse_hdr->flags >> FLAG_MC_SHIFT) & 0x1) != 0) ||
4343979c6d9SPankaj Gupta (((fuse_hdr->flags >> FLAG_DBG_LVL_SHIFT) & 0x1) != 0)) {
4353979c6d9SPankaj Gupta INFO("Fuse: Program OSPR1\n");
4363979c6d9SPankaj Gupta ret = prog_ospr1(fuse_hdr, sfp_ccsr_regs);
4373979c6d9SPankaj Gupta if (ret != 0) {
4383979c6d9SPankaj Gupta error_handler(ret);
4393979c6d9SPankaj Gupta goto out;
4403979c6d9SPankaj Gupta }
4413979c6d9SPankaj Gupta }
4423979c6d9SPankaj Gupta
4433979c6d9SPankaj Gupta /* Check if SYSCFG to be blown or not */
4443979c6d9SPankaj Gupta if (((fuse_hdr->flags >> FLAG_SYSCFG_SHIFT) & 0x1) != 0) {
4453979c6d9SPankaj Gupta INFO("Fuse: Program SYSCFG\n");
4463979c6d9SPankaj Gupta ret = prog_syscfg(fuse_hdr, sfp_ccsr_regs);
4473979c6d9SPankaj Gupta if (ret != 0) {
4483979c6d9SPankaj Gupta error_handler(ret);
4493979c6d9SPankaj Gupta goto out;
4503979c6d9SPankaj Gupta }
4513979c6d9SPankaj Gupta }
4523979c6d9SPankaj Gupta
4533979c6d9SPankaj Gupta if (en_povdd_status) {
4543979c6d9SPankaj Gupta ret = sfp_program_fuses();
4553979c6d9SPankaj Gupta if (ret != 0) {
4563979c6d9SPankaj Gupta error_handler(ret);
4573979c6d9SPankaj Gupta goto out;
4583979c6d9SPankaj Gupta }
4593979c6d9SPankaj Gupta }
4603979c6d9SPankaj Gupta out:
4613979c6d9SPankaj Gupta return ret;
4623979c6d9SPankaj Gupta }
463