| // GEU_FuseWriteMethods.c | |
| // | |
| /****************************************************************************** | |
| * | |
| * (C)Copyright 2005 - 2011 Marvell. All Rights Reserved. | |
| * | |
| * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MARVELL. | |
| * The copyright notice above does not evidence any actual or intended | |
| * publication of such source code. | |
| * This Module contains Proprietary Information of Marvell and should be | |
| * treated as Confidential. | |
| * The information in this file is provided for the exclusive use of the | |
| * licensees of Marvell. | |
| * Such users have the right to use, modify, and incorporate this code into | |
| * products for purposes authorized by the license agreement provided they | |
| * include this notice and the associated copyright notice with any such | |
| * product. | |
| * The information in this file is provided "AS IS" without warranty. | |
| ******************************************************************************/ | |
| #include <Typedef.h> | |
| #include <predefines.h> | |
| #include <geu_interface.h> | |
| #include <Errors.h> | |
| #include <timer.h> | |
| //#include <platform_timer.h> | |
| #include <PMUA.h> | |
| //#include <usbPal.h> | |
| #include <GEU.h> | |
| #include <platform_geu_fuse_internal.h> | |
| #include <USB_controller.h> | |
| #include <USB_PHY.h> | |
| #include <GEU_FuseReadMethods.h> | |
| // Comment out the following #define for debug to disable write protection checks | |
| // (Sticky bit set, lock bit set, or ECC programmed)in SetActiveFuseblock or SETUP... calls | |
| #define ENABLE_FUSEBLOCK_WRITE_PROTECT_CHECK 1 // Define for RELEASE | |
| //#define ENABLE_FUSEBLOCK_WRITE_PROTECT_CHECK 0 // Define for DEBUG | |
| //++ | |
| //************************************************************ | |
| // Unit Test Support | |
| // Reassigns GEU_REG_READ and GEU_REG_WRITE macros to emulator | |
| // function calls. | |
| #ifdef _GEU_EM | |
| #include "em_platform_geu_fuse_internal.h" | |
| #endif | |
| //************************************************************ | |
| //-- | |
| static struct GEU_FuseGlobalData g_ActiveFuseData = {0xF /*ActiveFuseBlock*/ }; | |
| struct GEU_FuseGlobalData *pActiveFuseData = &g_ActiveFuseData; | |
| static struct GEU_FuseBurnStatus g_FuseBurnStatus; | |
| struct GEU_FuseBurnStatus *pFuseBurnStatus = &g_FuseBurnStatus; | |
| /*********************************************************** | |
| * Function: | |
| * _geu_get_clock_divider | |
| * | |
| * Description: | |
| * Get the GEU clock divider by GEU HCLK. | |
| * GEU HCLK is the same as AXI ACLK | |
| * Input: | |
| * void | |
| * Output: | |
| * none | |
| * Returns: | |
| * clock divider | |
| ************************************************************ | |
| */ | |
| static UINT_T _geu_get_clock_divider(void) | |
| { | |
| UINT_T geu_clk_divider = 0x7; /* set default value */ | |
| UINT_T axi_clock_selection; | |
| UINT_T aclk_divider_selection; | |
| UINT_T aclk_freq; | |
| /* Get Clock Selection for ACLK */ | |
| GEU_REG_READ(PMUM_FCCR, axi_clock_selection); /* get AXI clock selection*/ | |
| axi_clock_selection = ((axi_clock_selection & PMUM_FCCR_ACLKSEL_BIT1)>>24) /* FCCR[25]: AXI clock selection bit[1] */ | |
| | ((axi_clock_selection & PMUM_FCCR_ACLKSEL_BIT0)>>19); /* FCCR[19]: AXI clock selection bit[0] */ | |
| switch(axi_clock_selection) | |
| { | |
| case 0x0: | |
| axi_clock_selection = 416; /* this */ | |
| break; | |
| case 0x1: | |
| axi_clock_selection = 624; | |
| break; | |
| case 0x3: | |
| axi_clock_selection = 312; | |
| break; | |
| default: | |
| axi_clock_selection = 0; | |
| break; | |
| } | |
| /* Get Clock Divider Selection for ACLK */ | |
| GEU_REG_READ(PMUA_CC_AP, aclk_divider_selection); /* 0xFD9219 for Nezha3 */ | |
| aclk_divider_selection = (aclk_divider_selection & PMUA_CC_AP_BUS_CLK_DIV_MSK) >> PMUA_CC_AP_BUS_CLK_DIV_BASE; | |
| aclk_freq = axi_clock_selection / (aclk_divider_selection + 1); | |
| /* GEU HCLK is the same clock source as ACLK, so it should be 208, 156, 104 or 74. | |
| Some case if ACLK is not in this range, it's consider a abnormal clock. | |
| On this abnormal case either we set GEU_CONFIG[27:25]=7 and set FUSE_SCLK_DIV_CNTR = HCLK/SCLK, | |
| or return a error status because something wrong with the clock setting. */ | |
| switch(aclk_freq) | |
| { | |
| case 208: | |
| geu_clk_divider = 0x2; /* 1 is also a coorect value */ | |
| break; | |
| case 156: | |
| geu_clk_divider = 0x3; | |
| break; | |
| case 104: | |
| geu_clk_divider = 0x4; /* this */ | |
| break; | |
| case 74: | |
| geu_clk_divider = 0x5; /* 6 is also a correct value */ | |
| break; | |
| default: | |
| geu_clk_divider = 0x7; | |
| break; | |
| } | |
| return geu_clk_divider; | |
| } | |
| /*********************************************************** | |
| * Function: | |
| * _geuClearFuseBurnStatus(struct GEU_FuseBurnStatus *ptrFBS) | |
| * | |
| * Description: | |
| * Clears(zeros)all fields in a FuseBurnStatus structure. | |
| * Input: | |
| * Pointer to a Fuse Burn Status Structure. | |
| * Output: | |
| * none | |
| * Returns: | |
| * void | |
| ************************************************************ | |
| */ | |
| void _geuClearFuseBurnStatus(struct GEU_FuseBurnStatus *ptrFBS) | |
| { | |
| INT i; | |
| INT * ptr; | |
| ptr = (INT*) ptrFBS; | |
| for (i=0; i<(sizeof(struct GEU_FuseBurnStatus)/4); i++) | |
| { | |
| ptr[i] = 0x0; | |
| } | |
| return; | |
| } | |
| /*********************************************************** | |
| * Function: | |
| * _geuClearActiveFuseData | |
| * | |
| * Description: | |
| * Clears fields in the ActiveFuseData structure used during a fuse burn. | |
| * Input: | |
| * None. | |
| * Output: | |
| * none | |
| * Returns: | |
| * void | |
| ************************************************************ | |
| */ | |
| void _geuClearActiveFuseData() | |
| { | |
| INT i; | |
| //struct GEU_FuseGlobalData * ptr; | |
| UINT_T * ptr; | |
| // Clear the ActiveFuseData | |
| ptr = (UINT_T *) &g_ActiveFuseData; | |
| for (i=0; i<(sizeof(g_ActiveFuseData)/4); i++) | |
| {*ptr = 0; ptr++;} | |
| return; | |
| } | |
| /*********************************************************** | |
| * Function: | |
| * _geuConfirmPowerEnabledForFuseBurning | |
| * | |
| * Description: | |
| * Confirms the USB PHY Bandgap is enabled for the Fuse Power Regulator. | |
| * This is shared with the USB. | |
| * Input: | |
| * None. | |
| * Output: | |
| * none | |
| * Returns: | |
| * 0 - if Bandgap is disabled | |
| * 1 - if Bandgap is enabled | |
| ************************************************************ | |
| */ | |
| UINT_T _geuConfirmPowerEnabledForFuseBurning() | |
| { | |
| return 1; | |
| } | |
| UINT_T GEU_EnableFuseBurnPower() //Changed from GEU_EnableUsbPhyBandgap | |
| { | |
| //UINT_T result = NoError; | |
| UINT_T scratch, clock_divider; | |
| static UINT_T check=0; | |
| if (check == 0) { | |
| // According to Wei Ma turn wtm clk enable: REG32(0xd4282868) = 0xff; // wtm clk enable | |
| GEU_REG_READ(PMUA_AES_CLK_RES_CTRL, scratch); | |
| scratch |= (0xff); | |
| GEU_REG_WRITE(PMUA_AES_CLK_RES_CTRL, scratch); | |
| clock_divider = _geu_get_clock_divider(); | |
| GEU_REG_READ(GEU_CONFIG, scratch); | |
| scratch &= (~GEU_CONFIG_FUSE_CLOCK_DIVIDER_MSK); | |
| scratch = scratch | ((clock_divider) << GEU_CONFIG_FUSE_CLOCK_DIVIDER_BASE); | |
| GEU_REG_WRITE(GEU_CONFIG, scratch); | |
| GEU_REG_READ(PMUA_AES_CLK_RES_CTRL, scratch); | |
| scratch |= PMUA_AES_CLK_RES_CTRL_AES_AXICLK_EN; //JML look into this, do we need to update it? It was WTMCLK | |
| scratch |= PMUA_AES_CLK_RES_CTRL_AES_AXI_RST; | |
| GEU_REG_WRITE(PMUA_AES_CLK_RES_CTRL, scratch); | |
| Delay(1000); | |
| GEU_REG_READ(REGULATOR_CNT_REG, scratch); | |
| scratch |= 0x00f00205; //JML - sample code from Wei Ma, need to check this | |
| GEU_REG_WRITE(REGULATOR_CNT_REG, scratch); | |
| Delay(1000); | |
| GEU_REG_READ(FUSE_SCLK_DIV_CNTR, scratch); | |
| scratch = 0xe0; //0x340; //JML - sample code from Wei Ma, need to check this | |
| GEU_REG_WRITE(FUSE_SCLK_DIV_CNTR, scratch); | |
| Delay(1000); | |
| } | |
| check++; | |
| return NoError; | |
| } | |
| UINT_T GEU_DisablePowerForFuseBurning() | |
| { | |
| return NoError; | |
| } | |
| /*********************************************************** | |
| * Function: | |
| * _geuUpdateUserFuseBurnStatus | |
| * | |
| * Description: | |
| * Copies the internal GEU_FuseBurnStatus structure to the user specified buffer. | |
| * Returns the status passed in as this is generally called to return from a fuse burn | |
| * function | |
| * Input: | |
| * pUserFuseBurnStatus - Pointer to a buffer large enough to contain the FuseBurnStatus structure. | |
| * status - status to return | |
| * Output: | |
| * none | |
| * Returns: | |
| * status passed by the calling routine | |
| ************************************************************ | |
| */ | |
| UINT_T _geuUpdateUserFuseBurnStatus(struct GEU_FuseBurnStatus *pUserFuseBurnStatus, UINT_T status) | |
| { | |
| UINT_T i; | |
| UINT_T * dptr, * sptr; | |
| pFuseBurnStatus->FinalBurnStatus = status ; | |
| // copy Fuse Burn Status to Users Fuse Burn Status | |
| dptr = (UINT_T *) pUserFuseBurnStatus; | |
| sptr = (UINT_T *) pFuseBurnStatus; | |
| for (i=0; i<(sizeof(struct GEU_FuseBurnStatus)/4); i++) | |
| { | |
| *dptr = *sptr; | |
| dptr++; | |
| sptr++; | |
| } | |
| return (status); | |
| }//End Routine _geuUpdateUserFuseBurnStatus | |
| /*********************************************************** | |
| * Function: | |
| * _getCopyOfActiveFuseData | |
| * | |
| * Description: | |
| * Copies the internal GEU_FuseGlobalData structure to the specified buffer. | |
| * | |
| * Input: | |
| * pUserFuseData - Pointer to a buffer large enough to contain the FuseGlobalData structure. | |
| * | |
| * Output: | |
| * none | |
| * Returns: | |
| * NoError | |
| * WriteError - pUserFuseData = 0 | |
| * | |
| ************************************************************/ | |
| //UINT_T _getCopyOfActiveFuseData(struct GEU_FuseGlobalData *pUserFuseData); | |
| //UINT_T _getCopyOfActiveFuseData(struct GEU_FuseGlobalData *pUserFuseData) | |
| UINT _getCopyOfActiveFuseData(struct GEU_FuseGlobalData *pUserFuseData) | |
| { | |
| UINT_T i, return_status; | |
| UINT_T * dptr, * sptr; | |
| if (pUserFuseData == 0) | |
| {return_status = WriteError;} | |
| else | |
| { | |
| // copy Fuse Data to User Area | |
| dptr = (UINT_T *) pUserFuseData; //Destination Pointer | |
| sptr = (UINT_T *) pActiveFuseData; //Source Pointer | |
| for (i=0; i<(sizeof(g_ActiveFuseData)/4); i++) | |
| { | |
| *dptr = *sptr; | |
| dptr++; | |
| sptr++; | |
| } | |
| return_status = NoError; | |
| } | |
| return (return_status); | |
| } | |
| /*********************************************************** | |
| * Function: | |
| * _geuClearVal1Val2RegisterSets() | |
| * | |
| * Description: | |
| * Clears the GEU_FUSE_PROG_VAL1 and GEU_FUSE_PROG_VAL2 register sets. | |
| * | |
| * Input: | |
| * none | |
| * | |
| * Output: | |
| * none | |
| * Returns: | |
| * void | |
| * | |
| * | |
| ************************************************************/ | |
| void _geuClearVal1Val2RegisterSets() | |
| { | |
| // Clear VAL1 & VAL2 register sets | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL1+0, 0); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL1+4, 0); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL1+8, 0); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL1+12, 0); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL2+0, 0); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL2+4, 0); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL2+8, 0); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL2+12, 0); | |
| return; | |
| } | |
| /*********************************************************** | |
| * Function: | |
| * _geuFuseSoftwareReset | |
| * | |
| * Description: | |
| * Implements a Fuse Software Reset | |
| * | |
| * Input: | |
| * none | |
| * | |
| * Output: | |
| * none | |
| * Returns: | |
| * void | |
| * | |
| * | |
| ************************************************************/ | |
| UINT_T _geuFuseSoftwareReset() | |
| { | |
| UINT_T scratch, return_status, status; | |
| return_status = 0; | |
| // Toggle Fuse Software Reset | |
| // - Must be done to enable fuse block reads | |
| // Clear the Fuse Software Reset Bit (It should alread by zero) | |
| GEU_REG_READ(GEU_CONFIG, scratch); | |
| scratch = scratch & ~GEU_CONFIG_FUSE_SOFTWARE_RESET; | |
| GEU_REG_WRITE(GEU_CONFIG, scratch); | |
| Delay(5); | |
| // Set the Fuse Software Reset Bit | |
| GEU_REG_READ(GEU_CONFIG, scratch); | |
| scratch = scratch | GEU_CONFIG_FUSE_SOFTWARE_RESET; | |
| GEU_REG_WRITE(GEU_CONFIG, scratch); | |
| Delay(5); | |
| // Clear the Fuse Software Reset Bit | |
| GEU_REG_READ(GEU_CONFIG, scratch); | |
| scratch = scratch & ~GEU_CONFIG_FUSE_SOFTWARE_RESET; | |
| GEU_REG_WRITE(GEU_CONFIG, scratch); | |
| // Wait for FUSE_READY | |
| status = _geuWaitForFuseOperationComplete(GEU_FUSE_STATUS_FUSE_READY, 10); | |
| if (status !=0) | |
| { | |
| return_status |= K_FUSE_READY_TIMEOUT; | |
| } | |
| return return_status; | |
| } | |
| UINT_T _geuReadFuseBlockLockStatus(UINT_T fuseblock) | |
| { | |
| UINT_T scratch = 0; | |
| GEU_REG_READ(GEU_FUSE_STATUS, scratch); | |
| switch(fuseblock) | |
| { | |
| case(0): | |
| { | |
| scratch &= GEU_FUSEBLOCK_0_LOCK_BIT_MASK; | |
| break; | |
| } | |
| case(1): | |
| { | |
| scratch &= GEU_FUSEBLOCK_1_LOCK_BIT_MASK; | |
| break; | |
| } | |
| case(2): | |
| { | |
| scratch &= GEU_FUSEBLOCK_2_LOCK_BIT_MASK; | |
| break; | |
| } | |
| case(3): | |
| { | |
| scratch &= GEU_FUSEBLOCK_3_LOCK_BIT_MASK; | |
| break; | |
| } | |
| case(4): | |
| { | |
| scratch &= GEU_FUSEBLOCK_4_LOCK_BIT_MASK; | |
| break; | |
| } | |
| case(5): | |
| { | |
| scratch &= GEU_FUSEBLOCK_5_LOCK_BIT_MASK; | |
| break; | |
| } | |
| case(6): | |
| { | |
| scratch &= GEU_FUSEBLOCK_6_LOCK_BIT_MASK; | |
| break; | |
| } | |
| case(7): | |
| { | |
| scratch &= GEU_FUSEBLOCK_7_LOCK_BIT_MASK; | |
| break; | |
| } | |
| case(8): | |
| { | |
| scratch &= GEU_FUSEBLOCK_8_LOCK_BIT_MASK; | |
| break; | |
| } | |
| case(9): | |
| { | |
| scratch &= GEU_FUSEBLOCK_9_LOCK_BIT_MASK; | |
| break; | |
| } | |
| case(10): | |
| { | |
| scratch &= GEU_FUSEBLOCK_10_LOCK_BIT_MASK; | |
| break; | |
| } | |
| case(11): | |
| { | |
| scratch &= GEU_FUSEBLOCK_11_LOCK_BIT_MASK; | |
| break; | |
| } | |
| default: | |
| {break;} | |
| }//EndSwitch | |
| if (scratch) | |
| { | |
| return 1; | |
| } | |
| else | |
| { | |
| return 0; | |
| } | |
| }//EndRoutine _geuReadFuseBlockLockStatus | |
| /*********************************************************** | |
| * Function: | |
| * _geuFuseBurn | |
| * | |
| * Description: | |
| * Implements a Fuse Burn. | |
| * Upon completeion of the burn: | |
| * - Does a Fuse Software Reset (enables reading fuse registers) | |
| * - Saves the GEU_ECC_CAL register (ECC value) to the GlobalFuseData structure | |
| * | |
| * Input: | |
| * n - Fuse Block Number | |
| * Lock - Burns the Lock bit for the fuse block | |
| * | |
| * Output: | |
| * Always saves the EU_ECC_CAL value in the ActiveFuseData structure even thought | |
| * it may not apply to the particular fuse block field being burned. | |
| * Returns: | |
| * void | |
| * | |
| * | |
| ************************************************************/ | |
| UINT_T _geuBurnFuse(UINT_T n, UINT_T Lock) | |
| { | |
| UINT_T scratch, config_save, status, return_status, geu_clk_divider; | |
| return_status = 0; | |
| status = _geuFuseSoftwareReset(); | |
| if (status != 0) { | |
| return_status |= status; | |
| } | |
| //Save the current GEU_CONFIG state | |
| GEU_REG_READ(GEU_CONFIG, config_save); | |
| // Enable High Voltage | |
| GEU_REG_READ(GEU_CONFIG, scratch); | |
| scratch = scratch | GEU_CONFIG_HIGH_VOLT_ENABLE; | |
| GEU_REG_WRITE(GEU_CONFIG, scratch); | |
| // Wait 1 msec for High Voltage to stabilize | |
| Delay(K_FuseHighVoltEnableDelay); | |
| // refer from ULC1, 20150211 set geu clock divider value | |
| // 0x3 - aclk@156Mhz, 0x4 - aclk@104Mhz | |
| geu_clk_divider = _geu_get_clock_divider(); | |
| // consider 0b111 is a wrong setting | |
| if (geu_clk_divider == (GEU_CONFIG_FUSE_CLOCK_DIVIDER_MSK >> GEU_CONFIG_FUSE_CLOCK_DIVIDER_BASE) ) | |
| { | |
| return K_FUSE_WRONG_ACLK_SETTING; | |
| } | |
| scratch = scratch & (~GEU_CONFIG_FUSE_CLOCK_DIVIDER_MSK); | |
| scratch = scratch | ((geu_clk_divider) << GEU_CONFIG_FUSE_CLOCK_DIVIDER_BASE); | |
| //Build a burn command | |
| // Set the clock divider to zero [27:25] | |
| //scratch = scratch & (~GEU_CONFIG_FUSE_CLOCK_DIVIDER_MSK); | |
| // Clear Fuse Block Number field [20:18] | |
| scratch = scratch & (~GEU_CONFIG_FUSE_BLOCK_NUMBER_MSK); | |
| // Set Fuse Block number[20:18] | |
| scratch = scratch |((n & 0x7)<< GEU_CONFIG_FUSE_BLOCK_NUMBER_BASE); | |
| // Set BURN_FUSE_ENABLE[16] and ENABLE_SOFT_FUSE_PROG[14] | |
| scratch = scratch |(GEU_CONFIG_BURN_FUSE_ENABLE | GEU_CONFIG_ENABLE_SOFT_FUSE_PROG); | |
| // Set FuseLock if requested | |
| if (Lock) { | |
| scratch = scratch | (GEU_CONFIG_FUSE_LOCK); | |
| } | |
| // BURN FUSE - Update GEU_CONFIG with burn parameters | |
| GEU_REG_WRITE(GEU_CONFIG, scratch); | |
| // Wait for Burn Complete status | |
| status = _geuWaitForFuseOperationComplete(GEU_FUSE_STATUS_FUSE_BURN_DONE, 10); | |
| if (status != 0) { | |
| return_status |= K_FUSE_BURN_TIMEOUT; | |
| } | |
| scratch = config_save; //| GEU_CONFIG_BURN_FUSE_ENABLE; | |
| GEU_REG_WRITE(GEU_CONFIG, scratch); | |
| status = _geuFuseSoftwareReset(); | |
| if (status != 0) { | |
| return_status |= status; | |
| } | |
| GEU_REG_WRITE(GEU_CONFIG, config_save); | |
| // Save the ECC CAL value | |
| GEU_REG_READ(GEU_ECC_CAL, pActiveFuseData->EccCalRegSave); | |
| return return_status; | |
| } | |
| /*********************************************************** | |
| * Function: | |
| * GEU_SetActiveFuseBlock | |
| * | |
| * Description: | |
| * Sets the active fuse block for a set of operations. | |
| * This restricts operations to the specifed fuseblock. | |
| * Operations not targeted to the active fuseblock will fail. | |
| * Notes: | |
| * 1. The specified fuseblock must not be locked. | |
| * 2. The sticky bit must not be set. | |
| * 3. The GlobalFuseData structure (*pActveFuseBlock) is initialized. | |
| * 4. The FuseBurnStatus structure (*pFuseBurnStatus) is initialized. | |
| * 5. The SQU0, SQU1, and SQU2 fuseblocks are not supported. | |
| * 6. Fuseblock numbers below are also supported | |
| * K_NO_FUSEBLOCK | |
| * K_UNDEFINED_FUSEBLOCK | |
| * to allow clearing the internal data structures without specifying | |
| * a legitimate fuseblock. | |
| * 7. The ActiveFuseBlockField is initialize to K_UNDEFINED_FUSEBLOCK_FIELD | |
| * | |
| * Input: | |
| * n - Fuse Block Number | |
| * K_AP_CONFIG_FUSEBLOCK | |
| * K_CP_CONFIG_FUSEBLOCK | |
| * K_USBID_FUSEBLOCK | |
| * K_APCPUSB_FUSEBLOCK | |
| * K_LIFECYCLE_FUSEBLOCK | |
| * K_SOFTWARE_VERSION_FUSEBLOCK | |
| * K_RKEK_FUSEBLOCK | |
| * K_OEM_FUSEBLOCK | |
| * K_JTAG_FUSEBLOCK | |
| * K_ECC_FUSEBLOCK | |
| * K_NO_FUSEBLOCK | |
| * K_UNDEFINED_FUSEBLOCK | |
| * Output: | |
| * none | |
| * Returns: | |
| * NoError | |
| * FUSE_FuseBlockLocked | |
| * FUSE_UnsupportedFuseBlock | |
| * | |
| * | |
| ************************************************************/ | |
| UINT_T GEU_SetActiveFuseBlock(UINT_T n) | |
| { | |
| UINT_T scratch; | |
| if (pActiveFuseData->ActiveFuseBlock != n) | |
| { | |
| // check if fuseblock locked (sticky or permanent) | |
| switch (n) | |
| { | |
| #if 0 | |
| case(K_AP_CONFIG_FUSEBLOCK): | |
| // K_CP_CONFIG_FUSEBLOCK | |
| // K_USBID_FUSEBLOCK | |
| // K_APCPUSB_FUSEBLOCK | |
| // K_LIFECYCLE_FUSEBLOCK | |
| // K_SOFTWARE_VERSION_FUSEBLOCK | |
| // K_ECC_FUSEBLOCK | |
| { | |
| // Check Sticky Bit | |
| GEU_REG_READ(GEU_CONFIG, scratch); | |
| if ((scratch & GEU_CONFIG_STICKY_CONTROL_BIT) != 0) | |
| { | |
| return(FUSE_FuseBlockStickyBitSet); | |
| } | |
| // Check Lock Bit | |
| #if ENABLE_FUSEBLOCK_WRITE_PROTECT_CHECK | |
| GEU_REG_READ(GEU_FUSE_STATUS, scratch); | |
| scratch = (scratch & GEU_FUSE_STATUS_LOCK_BIT_MSK)>>GEU_FUSE_STATUS_LOCK_BIT_BASE; | |
| if (scratch & K_FB0_FUSE_LOCK_BIT_MASK) | |
| { | |
| return(FUSE_FuseBlockLocked); | |
| } | |
| #endif | |
| break; | |
| } | |
| case(K_RKEK_FUSEBLOCK): | |
| { | |
| // Check Lock Bit | |
| #if ENABLE_FUSEBLOCK_WRITE_PROTECT_CHECK | |
| GEU_REG_READ(GEU_FUSE_STATUS, scratch); | |
| scratch = (scratch & GEU_FUSE_STATUS_LOCK_BIT_MSK)>>GEU_FUSE_STATUS_LOCK_BIT_BASE; | |
| if (scratch & K_RKEK_FUSE_LOCK_BIT_MASK) | |
| { | |
| return(FUSE_FuseBlockLocked); | |
| } | |
| #endif | |
| break; | |
| } | |
| case(K_SQU0_FUSE_LOCK_BIT_MASK): | |
| case(K_SQU1_FUSE_LOCK_BIT_MASK): | |
| case(K_SQU2_FUSE_LOCK_BIT_MASK): | |
| { | |
| return(FUSE_UnsupportedFuseBlock); | |
| //break; //JML - Compiled complained statement unreachable | |
| } | |
| case(K_OEM_FUSEBLOCK): | |
| { | |
| // Check Lock Bit | |
| #if ENABLE_FUSEBLOCK_WRITE_PROTECT_CHECK | |
| GEU_REG_READ(GEU_FUSE_STATUS, scratch); | |
| scratch = (scratch & GEU_FUSE_STATUS_LOCK_BIT_MSK)>>GEU_FUSE_STATUS_LOCK_BIT_BASE; | |
| if (scratch & K_OEM_FUSE_LOCK_BIT_MASK) | |
| { | |
| return(FUSE_FuseBlockLocked); | |
| } | |
| #endif | |
| break; | |
| } | |
| #endif | |
| case(K_JTAG_FUSEBLOCK): | |
| { | |
| // Check Lock Bit | |
| #if ENABLE_FUSEBLOCK_WRITE_PROTECT_CHECK | |
| GEU_REG_READ(GEU_FUSE_STATUS, scratch); | |
| scratch = (scratch & GEU_FUSE_STATUS_LOCK_BIT_MSK)>>GEU_FUSE_STATUS_LOCK_BIT_BASE; | |
| if (scratch & K_JTAG_FUSE_LOCK_BIT_MASK) | |
| { | |
| return(FUSE_FuseBlockLocked); | |
| } | |
| #endif | |
| break; | |
| } | |
| case(K_FB7_FUSEBLOCK): | |
| { | |
| // Check Lock Bit | |
| #if ENABLE_FUSEBLOCK_WRITE_PROTECT_CHECK | |
| GEU_REG_READ(GEU_FUSE_STATUS, scratch); | |
| scratch = (scratch & GEU_FUSE_STATUS_LOCK_BIT_MSK)>>GEU_FUSE_STATUS_LOCK_BIT_BASE; | |
| if (scratch & K_FB7_FUSE_LOCK_BIT_MASK) | |
| { | |
| return(FUSE_FuseBlockLocked); | |
| } | |
| #endif | |
| break; | |
| } | |
| default: | |
| // Invalid or NO_FUSEBLOCK(as opposed to UNSUPPORTED)is OK | |
| break; | |
| } | |
| // Clear the Fuse Burn Status Block | |
| _geuClearFuseBurnStatus(pFuseBurnStatus); | |
| // Clear the ActiveFuseData | |
| _geuClearActiveFuseData(); | |
| // Clear VAL1 & VAL2 register sets | |
| _geuClearVal1Val2RegisterSets(); | |
| pActiveFuseData->ActiveFuseBlock = n; | |
| pActiveFuseData->ActiveFuseBlockField = K_UNDEFINED_FUSEBLOCK_FIELD; | |
| pActiveFuseData->FuseLockBitMask = 0x01 << n; | |
| }//EndIf BlockNotActive | |
| return 0; | |
| }//End Routine SetActiveFuseBlock | |
| /*********************************************************** | |
| * Function: | |
| * GEU_ReadActiveFuseBlockNumber | |
| * | |
| * Description: | |
| * Returns the Active Fuse Block number | |
| * Input: | |
| * none | |
| * | |
| * Output: | |
| * none | |
| * Returns: | |
| * Active Fuse Block Number | |
| * | |
| * | |
| ************************************************************/ | |
| UINT_T GEU_ReadActiveFuseBlockNumber() | |
| { | |
| return (pActiveFuseData->ActiveFuseBlock); | |
| } | |
| /*********************************************************** | |
| * Function: | |
| * GEU_SetupSecurityConfigFuseBits | |
| * | |
| * Description: | |
| * - Confirms the Active FuseBlock and FuseBlockField conform to the | |
| * Security Usb fuseblock field. | |
| * - Copies the caller supplied Security Config data(32 bits/4 bytes) to | |
| * the appropriate offset in the GEU_FUSE_PROG_VALn register set. | |
| * - Sets the CpC Burn Request. | |
| * | |
| * Input: | |
| * pBuffer - pointer to a buffer containing the 32 bits of USB ID data | |
| * Size - Size (in bytes) of the data to copy (Must be K_USBID_FUSE_SIZE). | |
| * | |
| * Output: | |
| * none | |
| * Returns: | |
| * NoError | |
| * FUSE_FuseBlockNotActive | |
| * FUSE_FuseBlockFieldNotActive | |
| * FUSE_BufferTooSmall | |
| * | |
| ************************************************************/ | |
| UINT_T GEU_SetupSecurityConfigFuseBits(UINT_T* pBuffer, UINT_T Size) | |
| { | |
| UINT_T scratch; | |
| if (Size != K_SECURITY_CONFIG_FUSE_SIZE) | |
| { | |
| return FUSE_BufferTooSmall; | |
| } | |
| // Confirm this fuseblock is active | |
| if (g_ActiveFuseData.ActiveFuseBlock != K_SECURITYCONFIG_FUSEBLOCK) | |
| { | |
| return (FUSE_FuseBlockNotActive); | |
| } | |
| // Check Active FuseBlock Field | |
| //If not set, set it to ApCpUsb | |
| if (pActiveFuseData->ActiveFuseBlockField == K_UNDEFINED_FUSEBLOCK_FIELD) | |
| { | |
| //Set ActiveFuseBlockField - this is first one | |
| pActiveFuseData->ActiveFuseBlockField = K_SECURITY_USBID_FUSEBLOCK_FIELD; | |
| } | |
| else | |
| { | |
| // If the Active FuseBlock Field is NOT Security USB return error | |
| if (pActiveFuseData->ActiveFuseBlockField != K_SECURITY_USBID_FUSEBLOCK_FIELD) | |
| { | |
| return (FUSE_FuseBlockFieldNotActive); | |
| } | |
| } | |
| #if ENABLE_FUSEBLOCK_WRITE_PROTECT_CHECK | |
| // Sticky bit only for block 0. Remove | |
| GEU_REG_READ(GEU_CONFIG, scratch); | |
| // if ((scratch & GEU_CONFIG_STICKY_CONTROL_BIT) != 0) | |
| // { | |
| // return(FUSE_FuseBlockStickyBitSet); | |
| // } | |
| // Check Lock Bit | |
| GEU_REG_READ(GEU_FUSE_STATUS, scratch); | |
| scratch = (scratch & GEU_FUSE_STATUS_LOCK_BIT_MSK)>>GEU_FUSE_STATUS_LOCK_BIT_BASE; | |
| if (scratch & K_FB7_FUSE_LOCK_BIT_MASK) | |
| { | |
| return(FUSE_FuseBlockLocked); | |
| } | |
| // Check if ECC protected | |
| GEU_REG_READ(GEU_FUSE_VAL_SECURITY_USB_ECC, scratch); | |
| if ((scratch & GEU_SECURITY_USB_ECC_MASK) != 0) | |
| { | |
| return(FUSE_FieldWriteProtectedByEcc); | |
| } | |
| #endif | |
| // Clear Burn Data in the Active Fuse Data Structure | |
| // JLC: _geuClearActiveFuseData(); | |
| //Save the setup data to GEU_FUSE_PROG_VAL1/VAL2 | |
| // Bytes 3-0 | |
| scratch = pBuffer[0]; | |
| _geuUpdateRegister(GEU_FUSE_PROG_VAL1+0, scratch, 0xFFFFFFFF); | |
| // Save to Active fuseblock for burn validation later | |
| pActiveFuseData->SecurityConfigSave[0] = scratch; | |
| //Set Burn Request | |
| pActiveFuseData->BurnRequest |= K_SECURITY_CONFIG_BURN_REQUEST_MASK; | |
| return 0; | |
| } | |
| /********************************************************** | |
| * Function: | |
| * GEU_SetupOemHashKeyFuseBits | |
| * | |
| * Description: | |
| * - Confirms the Active FuseBlock and FuseBlockField conform to the | |
| * OEM Hash fuseblock field. | |
| * - Copies the caller supplied OEM Hash data(32 bytes) to | |
| * the appropriate offset in the GEU_FUSE_PROG_VALn register set. | |
| * - Sets the OEM Burn Request. | |
| * | |
| * Input: | |
| * pBuffer - pointer to a buffer containing the 32 bytes of OEM Hash data | |
| * Size - Size (in bytes) of the data to copy (Must be K_OEM_HASH_FUSE_SIZE). | |
| * | |
| * Output: | |
| * none | |
| * Returns: | |
| * NoError | |
| * FUSE_FuseBlockNotActive | |
| * FUSE_FuseBlockFieldNotActive | |
| * FUSE_InvalidBufferSize | |
| * | |
| ************************************************************/ | |
| UINT_T GEU_SetupOemHashKeyFuseBits(UINT_T* pBuffer, UINT_T Size) | |
| { | |
| UINT_T scratch; | |
| if (Size != K_OEM_HASH_FUSE_SIZE) | |
| { | |
| return FUSE_InvalidBufferSize; | |
| } | |
| // Confirm this fuseblock is active | |
| if (g_ActiveFuseData.ActiveFuseBlock != K_OEM_FUSEBLOCK) | |
| { | |
| return (FUSE_FuseBlockNotActive); | |
| } | |
| // Check Active FuseBlock Field | |
| //If not set, set it. | |
| if (pActiveFuseData->ActiveFuseBlockField == K_UNDEFINED_FUSEBLOCK_FIELD) | |
| { | |
| //Set ActiveFuseBlockField - this is first one | |
| pActiveFuseData->ActiveFuseBlockField = K_OEM0_FUSEBLOCK_FIELD; | |
| } | |
| else | |
| { | |
| // If the Active FuseBlock Field is NOT OEM HASH KEY return error | |
| if (pActiveFuseData->ActiveFuseBlockField != K_OEM0_FUSEBLOCK_FIELD) | |
| { | |
| return (FUSE_FuseBlockFieldNotActive); | |
| } | |
| } | |
| #if ENABLE_FUSEBLOCK_WRITE_PROTECT_CHECK | |
| // Check Lock Bit | |
| GEU_REG_READ(GEU_FUSE_STATUS, scratch); | |
| scratch = (scratch & GEU_FUSE_STATUS_LOCK_BIT_MSK)>>GEU_FUSE_STATUS_LOCK_BIT_BASE; | |
| if (scratch & K_OEM_FUSE_LOCK_BIT_MASK) | |
| { | |
| return(FUSE_FuseBlockLocked); | |
| } | |
| // Check ECC programmed | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_KEY0_HASH_ECC, scratch); | |
| if (scratch != 0) | |
| { | |
| return(FUSE_FieldWriteProtectedByEcc); | |
| } | |
| #endif | |
| // Clear Burn Data in the Active Fuse Data Structure | |
| // JLC: _geuClearActiveFuseData(); | |
| // Save to Active fuseblock for burn validation later | |
| pActiveFuseData->FuseBlockSave[0] = pBuffer[0]; | |
| pActiveFuseData->FuseBlockSave[1] = pBuffer[1]; | |
| pActiveFuseData->FuseBlockSave[2] = pBuffer[2]; | |
| pActiveFuseData->FuseBlockSave[3] = pBuffer[3]; | |
| pActiveFuseData->FuseBlockSave[4] = pBuffer[4]; | |
| pActiveFuseData->FuseBlockSave[5] = pBuffer[5]; | |
| pActiveFuseData->FuseBlockSave[6] = pBuffer[6]; | |
| pActiveFuseData->FuseBlockSave[7] = pBuffer[7]; | |
| //Save the setup data to GEU_FUSE_PROG_VAL1/VAL2 | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL1+0, pBuffer[0]); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL1+4, pBuffer[1]); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL1+8, pBuffer[2]); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL1+12, pBuffer[3]); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL2+0, pBuffer[4]); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL2+4, pBuffer[5]); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL2+8, pBuffer[6]); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL2+12, pBuffer[7]); | |
| //Set Burn Request | |
| pActiveFuseData->BurnRequest |= K_OEM_KEY0_BURN_REQUEST_MASK; | |
| return 0; | |
| }//End Routine GEU_SetupOemHashFuseBits | |
| /********************************************************** | |
| * Function: | |
| * GEU_SetupOemJtagHashKeyFuseBits | |
| * | |
| * Description: | |
| * - Confirms the Active FuseBlock and FuseBlockField conform to the | |
| * JTAG fuseblock field. | |
| * - Copies the caller supplied JTAG Hash data(32 bytes) to | |
| * the appropriate offset in the GEU_FUSE_PROG_VALn register set. | |
| * - Sets the JTAG Burn Request. | |
| * | |
| * Input: | |
| * pBuffer - pointer to a buffer containing the 32 bytes of JTAG Hash data | |
| * Size - Size (in bytes) of the data to copy (Must be K_JTAG_FUSE_SIZE). | |
| * | |
| * Output: | |
| * none | |
| * Returns: | |
| * NoError | |
| * FUSE_FuseBlockNotActive | |
| * FUSE_FuseBlockFieldNotActive | |
| * FUSE_InvalidBufferSize | |
| * | |
| ************************************************************/ | |
| UINT_T GEU_SetupOemJtagHashKeyFuseBits(UINT_T* pBuffer, UINT_T Size) | |
| { | |
| UINT_T scratch; | |
| if (Size != K_JTAG_HASH_FUSE_SIZE) | |
| { | |
| return FUSE_InvalidBufferSize; | |
| } | |
| // Confirm this fuseblock is active | |
| if (g_ActiveFuseData.ActiveFuseBlock != K_JTAG_FUSEBLOCK) | |
| { | |
| return (FUSE_FuseBlockNotActive); | |
| } | |
| // Check Active FuseBlock Field | |
| //If not set, set it. | |
| if (pActiveFuseData->ActiveFuseBlockField == K_UNDEFINED_FUSEBLOCK_FIELD) | |
| { | |
| //Set ActiveFuseBlockField - this is first one | |
| pActiveFuseData->ActiveFuseBlockField = K_JTAG0_FUSEBLOCK_FIELD; | |
| } | |
| else | |
| { | |
| // If the Active FuseBlock Field is NOT JTAG Hash Key, return error | |
| if (pActiveFuseData->ActiveFuseBlockField != K_JTAG0_FUSEBLOCK_FIELD) | |
| { | |
| return (FUSE_FuseBlockFieldNotActive); | |
| } | |
| } | |
| #if ENABLE_FUSEBLOCK_WRITE_PROTECT_CHECK | |
| // Check Lock Bit | |
| GEU_REG_READ(GEU_FUSE_STATUS, scratch); | |
| scratch = (scratch & GEU_FUSE_STATUS_LOCK_BIT_MSK)>>GEU_FUSE_STATUS_LOCK_BIT_BASE; | |
| if (scratch & K_JTAG_FUSE_LOCK_BIT_MASK) | |
| { | |
| return(FUSE_FuseBlockLocked); | |
| } | |
| // Check if ECC programmed | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_JTAG_KEY_HASH_ECC, scratch); | |
| if (scratch != 0) | |
| { | |
| return(FUSE_FieldWriteProtectedByEcc); | |
| } | |
| #endif | |
| // Clear Burn Data in the Active Fuse Data Structure | |
| // JLC: _geuClearActiveFuseData(); | |
| // Save to Active fuseblock for burn validation later | |
| pActiveFuseData->FuseBlockSave[0] = pBuffer[0]; | |
| pActiveFuseData->FuseBlockSave[1] = pBuffer[1]; | |
| pActiveFuseData->FuseBlockSave[2] = pBuffer[2]; | |
| pActiveFuseData->FuseBlockSave[3] = pBuffer[3]; | |
| pActiveFuseData->FuseBlockSave[4] = pBuffer[4]; | |
| pActiveFuseData->FuseBlockSave[5] = pBuffer[5]; | |
| pActiveFuseData->FuseBlockSave[6] = pBuffer[6]; | |
| pActiveFuseData->FuseBlockSave[7] = pBuffer[7]; | |
| //Save the setup data to GEU_FUSE_PROG_VAL1/VAL2 | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL1+0, pBuffer[0]); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL1+4, pBuffer[1]); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL1+8, pBuffer[2]); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL1+12, pBuffer[3]); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL2+0, pBuffer[4]); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL2+4, pBuffer[5]); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL2+8, pBuffer[6]); | |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL2+12, pBuffer[7]); | |
| //Set Burn Request | |
| pActiveFuseData->BurnRequest |= K_JTAG_KEY0_BURN_REQUEST_MASK; | |
| return 0; | |
| } | |
| /********************************************************** | |
| * Function: | |
| * GEU_BurnFuseBlock_OemHashKey | |
| * | |
| * Description: | |
| * Burns the OEM Hash Key field in the OEM Hash Key Fuseblock. | |
| * | |
| * - Confirms that a OEM Hash Key burn request exists | |
| * - Burns the fuseblock | |
| * Validates the burned OEM Hash Key equals the requested OEM Hash key | |
| * Retries if compare fails | |
| * | |
| * Input: | |
| * pUserFuseBurnStatus - pointer to a buffer containing a FuseBurnStatus structure | |
| * | |
| * Output: | |
| * none | |
| * Returns: | |
| * NoError | |
| * FUSE_BurnError | |
| * | |
| ************************************************************/ | |
| UINT_T GEU_BurnFuseBlock_OemHashKey(struct GEU_FuseBurnStatus * pUserFuseBurnStatus) | |
| { | |
| UINT_T temp[8]; // temp buffer for fuse block compares | |
| UINT_T status; | |
| // Confirm this fuseblock is active | |
| if (pActiveFuseData->ActiveFuseBlock != K_OEM_FUSEBLOCK) | |
| { | |
| return (FUSE_FuseBlockNotActive); | |
| } | |
| // Confirm bandgap from USB PHY is enabled for the fuse power regulator | |
| if( _geuConfirmPowerEnabledForFuseBurning() == 0) | |
| { | |
| pFuseBurnStatus->FinalBurnStatus = FUSE_FuseBurnPowerNotEnabled; | |
| return(_geuUpdateUserFuseBurnStatus(pUserFuseBurnStatus, pFuseBurnStatus->FinalBurnStatus)); | |
| } | |
| // Save the burn request in the FuseBurnStatus | |
| pFuseBurnStatus->SavedBurnRequest = pActiveFuseData->BurnRequest; | |
| if ((pActiveFuseData->BurnRequest & K_OEM_KEY0_BURN_REQUEST_MASK) == 0) | |
| { | |
| return(_geuUpdateUserFuseBurnStatus(pUserFuseBurnStatus, FUSE_NoBurnRequest)); | |
| } | |
| // Burn Count = 0 | |
| pActiveFuseData->BurnCount = 0; | |
| while (pActiveFuseData->BurnRequest) | |
| { | |
| //++ ****** Burn ********** | |
| status = _geuBurnFuse(K_OEM_FUSEBLOCK, K_DO_NOT_LOCK_FUSEBLOCK); // Burn and NOT Lock OEM Key Hash | |
| //-- ****** Burn ********** | |
| if (status != 0) | |
| { | |
| pFuseBurnStatus->DebugStatus = status; | |
| } | |
| // Burn Count++ | |
| pActiveFuseData->BurnCount++; | |
| if (pActiveFuseData->BurnCount > 1) | |
| { | |
| pFuseBurnStatus->DebugStatus |= K_MULTIPLE_BURN_COUNT; | |
| } | |
| //******************************************************************** | |
| // Validate the OEM Hash Burn | |
| //******************************************************************** | |
| if ((pActiveFuseData->BurnRequest & K_OEM_KEY0_BURN_REQUEST_MASK) != 0) | |
| { | |
| //Compare Burned value with Saved value | |
| status = GEU_ReadOemHashKeyFuseBits(&temp[0], K_FUSEBLOCK_SIZE); | |
| status = _geu_compare(&pActiveFuseData->FuseBlockSave[0], | |
| &temp[0], | |
| K_FUSEBLOCK_SIZE); | |
| if (status == 0) | |
| { | |
| // AP Burn Good - Clear the Burn Request | |
| pActiveFuseData->BurnRequest = pActiveFuseData->BurnRequest | |
| & ~K_OEM_KEY0_BURN_REQUEST_MASK; | |
| } | |
| else | |
| { | |
| // If the BurnCount is 1, leave the burn request set | |
| // for another try. | |
| // Else | |
| if (pActiveFuseData->BurnCount >= 2) | |
| { | |
| // Burn Failed two times - Clear the burn Request | |
| pActiveFuseData->BurnRequest = pActiveFuseData->BurnRequest | |
| & ~K_OEM_KEY0_BURN_REQUEST_MASK; | |
| // Set the AP Raw Burn Status to indicate Failure | |
| pFuseBurnStatus->RawBurnStatus = pFuseBurnStatus->RawBurnStatus | | |
| K_OEM_KEY0_STATUS_BIT_MASK; | |
| } | |
| }//EndIfElse | |
| }//Endif | |
| }//End While | |
| // Set status | |
| pFuseBurnStatus->CorrectedBurnStatus = pFuseBurnStatus->RawBurnStatus; | |
| pFuseBurnStatus->FinalBurnStatus = NoError; | |
| if(pFuseBurnStatus->CorrectedBurnStatus != 0) | |
| { | |
| pFuseBurnStatus->FinalBurnStatus = FUSE_BurnError; | |
| } | |
| return(_geuUpdateUserFuseBurnStatus(pUserFuseBurnStatus, pFuseBurnStatus->FinalBurnStatus)); | |
| }// End Routine GEU_BurnFuseBlock_OEM_Platform_Hash | |
| /********************************************************** | |
| * Function: | |
| * GEU_BurnFuseBlock_OemJtagHashKey | |
| * | |
| * Description: | |
| * Burns the OEM JTAG Hash Key field in the OEM JTAG Hash Key Fuseblock. | |
| * | |
| * - Confirms that a OEM JTAG Hash Key burn request exists | |
| * - Burns the fuseblock | |
| * Validates the burned OEM JTAG Hash Key equals the | |
| * requested OEM JTAG Hash key | |
| * Retries if compare fails | |
| * | |
| * Input: | |
| * pUserFuseBurnStatus - pointer to a buffer containing a FuseBurnStatus structure | |
| * | |
| * Output: | |
| * none | |
| * Returns: | |
| * NoError | |
| * FUSE_BurnError | |
| * | |
| ************************************************************/ | |
| UINT_T GEU_BurnFuseBlock_OemJtagHashKey(struct GEU_FuseBurnStatus * pUserFuseBurnStatus) | |
| { | |
| UINT_T temp[8]; // temp buffer for fuse block compares | |
| UINT_T status; | |
| // Confirm this fuseblock is active | |
| if (pActiveFuseData->ActiveFuseBlock != K_JTAG_FUSEBLOCK) | |
| { | |
| return (FUSE_FuseBlockNotActive); | |
| } | |
| // Confirm bandgap from USB PHY is enabled for the fuse power regulator | |
| if( _geuConfirmPowerEnabledForFuseBurning() == 0) | |
| { | |
| pFuseBurnStatus->FinalBurnStatus = FUSE_FuseBurnPowerNotEnabled; | |
| return(_geuUpdateUserFuseBurnStatus(pUserFuseBurnStatus, pFuseBurnStatus->FinalBurnStatus)); | |
| } | |
| // Save the burn request in the FuseBurnStatus | |
| pFuseBurnStatus->SavedBurnRequest = pActiveFuseData->BurnRequest; | |
| if ((pActiveFuseData->BurnRequest & K_JTAG_KEY0_BURN_REQUEST_MASK) == 0) | |
| { | |
| return(_geuUpdateUserFuseBurnStatus(pUserFuseBurnStatus, FUSE_NoBurnRequest)); | |
| } | |
| // Burn Count = 0 | |
| pActiveFuseData->BurnCount = 0; | |
| while (pActiveFuseData->BurnRequest) | |
| { | |
| //++ ****** Burn ********** | |
| status = _geuBurnFuse(K_JTAG_FUSEBLOCK, K_DO_NOT_LOCK_FUSEBLOCK); // Burn and NOT Lock JTAG Key Hash | |
| //-- ****** Burn ********** | |
| if (status != 0) | |
| { | |
| pFuseBurnStatus->DebugStatus = status; | |
| } | |
| // Burn Count++ | |
| pActiveFuseData->BurnCount++; | |
| if (pActiveFuseData->BurnCount > 1) | |
| { | |
| pFuseBurnStatus->DebugStatus |= K_MULTIPLE_BURN_COUNT; | |
| } | |
| //******************************************************************** | |
| // Validate the JTAG Hash Burn | |
| //******************************************************************** | |
| if ((pActiveFuseData->BurnRequest & K_JTAG_KEY0_BURN_REQUEST_MASK) != 0) | |
| { | |
| //Compare Burned value with Saved value | |
| status = GEU_ReadOemJtagHashKeyFuseBits(&temp[0], K_FUSEBLOCK_SIZE); | |
| status = _geu_compare(&pActiveFuseData->FuseBlockSave[0], | |
| &temp[0], | |
| K_FUSEBLOCK_SIZE); | |
| if (status == 0) | |
| { | |
| // AP Burn Good - Clear the Burn Request | |
| pActiveFuseData->BurnRequest = pActiveFuseData->BurnRequest | |
| & ~K_JTAG_KEY0_BURN_REQUEST_MASK; | |
| } | |
| else | |
| { | |
| // If the BurnCount is 1, leave the burn request set | |
| // for another try. | |
| // Else | |
| if (pActiveFuseData->BurnCount >= 2) | |
| { | |
| // Burn Failed two times - Clear the burn Request | |
| pActiveFuseData->BurnRequest = pActiveFuseData->BurnRequest | |
| & ~K_JTAG_KEY0_BURN_REQUEST_MASK; | |
| // Set the AP Raw Burn Status to indicate Failure | |
| pFuseBurnStatus->RawBurnStatus = pFuseBurnStatus->RawBurnStatus | | |
| K_JTAG_KEY0_STATUS_BIT_MASK; | |
| } | |
| }//EndIfElse | |
| }//Endif | |
| }//End While | |
| // Set status | |
| pFuseBurnStatus->CorrectedBurnStatus = pFuseBurnStatus->RawBurnStatus; | |
| pFuseBurnStatus->FinalBurnStatus = NoError; | |
| if(pFuseBurnStatus->CorrectedBurnStatus != 0) | |
| { | |
| pFuseBurnStatus->FinalBurnStatus = FUSE_BurnError; | |
| } | |
| return(_geuUpdateUserFuseBurnStatus(pUserFuseBurnStatus, pFuseBurnStatus->FinalBurnStatus)); | |
| }//End Routine GEU_BurnFuseBlock_JTAG_Hash | |
| /********************************************************** | |
| * Function: | |
| * GEU_BurnEcc | |
| * | |
| * Description: | |
| * This function burns an ECC value for an ECC protected field. | |
| * This function must be called immediately after burning an ECC protected field. | |
| * Notes: | |
| * - GEU_SetActiveFuseblock must not be called between burning the ECC protected | |
| * field and burning the ECC. | |
| * - A read of any fuseblock field may occur between burning the ECC protected | |
| * field and burning the ECC. | |
| * | |
| * This function first determines which ECC field must be burned based | |
| * on the saved burn request in the FuseData structure. | |
| * | |
| * - Clears GEU_FUSE_PROG_VAL1 and VAL2 register sets. | |
| * - Retrieves the saved ECC value from the last burn | |
| * - and stores the ECC value in the appropriate field. | |
| * - Burns the fuseblock | |
| * - Validates all ECC fields using GEU_ECC_STATUS and checking | |
| * for uncorrectable errors. | |
| * - Retries the burn if compare fails | |
| * | |
| * Input: | |
| * pUserFuseBurnStatus - pointer to a buffer containing a FuseBurnStatus structure | |
| * | |
| * Output: | |
| * none | |
| * Returns: | |
| * NoError | |
| * FUSE_BurnError | |
| * | |
| ************************************************************/ | |
| UINT_T GEU_BurnECC(struct GEU_FuseBurnStatus * pUserFuseBurnStatus) | |
| { | |
| UINT_T scratch, status; | |
| if( _geuConfirmPowerEnabledForFuseBurning() == 0) | |
| { | |
| pFuseBurnStatus->FinalBurnStatus = FUSE_FuseBurnPowerNotEnabled; | |
| return(_geuUpdateUserFuseBurnStatus(pUserFuseBurnStatus, pFuseBurnStatus->FinalBurnStatus)); | |
| } | |
| // Do common chores for all ECC burns | |
| // Clear the FinalBurnStatus | |
| pFuseBurnStatus->FinalBurnStatus = NoError; | |
| //Identify which ECC field to burn and set the ECC burn request for that field | |
| //++ Check first for ApCpUsb - all three burn requests must have been set | |
| // if ((pFuseBurnStatus->SavedBurnRequest & K_APCPUSB_BURN_REQUEST_MASK) != 0) | |
| // { | |
| // // Must have all three AP/CP/USB fields burned to proceed with ECC burn request | |
| // if ((pFuseBurnStatus->SavedBurnRequest & K_APCPUSB_BURN_REQUEST_MASK) != K_APCPUSB_BURN_REQUEST_MASK) | |
| // { | |
| // // All three fields not burned | |
| // return(_geuUpdateUserFuseBurnStatus(pUserFuseBurnStatus, FUSE_IncompleteBurnRequest)); | |
| // } | |
| // else | |
| // { | |
| // // Set ApCpUsb ECC burn request | |
| // pActiveFuseData->BurnRequest = pActiveFuseData->BurnRequest | | |
| // K_APCPUSB_ECC_BURN_REQUEST_MASK; | |
| // } | |
| // }//--Endif ApCpUsb burn check | |
| //++ Check if OEM burn request was set | |
| if ((pFuseBurnStatus->SavedBurnRequest & K_OEM_KEY0_BURN_REQUEST_MASK) == | |
| K_OEM_KEY0_BURN_REQUEST_MASK) | |
| { | |
| // Set OEM ECC burn request | |
| pActiveFuseData->BurnRequest = pActiveFuseData->BurnRequest | | |
| K_OEM_KEY0_ECC_BURN_REQUEST_MASK; | |
| }//--Endif OEM burn check | |
| //++ Check if JTAG burn request was set | |
| if ((pFuseBurnStatus->SavedBurnRequest & K_JTAG_KEY0_BURN_REQUEST_MASK) == | |
| K_JTAG_KEY0_BURN_REQUEST_MASK) | |
| { | |
| // Set JTAG ECC burn request | |
| pActiveFuseData->BurnRequest = pActiveFuseData->BurnRequest | | |
| K_JTAG_KEY0_ECC_BURN_REQUEST_MASK; | |
| }//-- Endif JTAG burn check | |
| // Save the burn request in the FuseBurnStatus | |
| // This clears out the previous burn request | |
| pFuseBurnStatus->SavedBurnRequest = pActiveFuseData->BurnRequest; | |
| if ((pActiveFuseData->BurnRequest & (//K_APCPMP0_ECC_BURN_REQUEST_MASK | | |
| K_OEM_KEY0_ECC_BURN_REQUEST_MASK | | |
| K_JTAG_KEY0_ECC_BURN_REQUEST_MASK)) == 0) | |
| { | |
| return(_geuUpdateUserFuseBurnStatus(pUserFuseBurnStatus, FUSE_NoBurnRequest)); | |
| } | |
| // We have a legitimate ECC burn request | |
| // Clear VAL1/VAL2 regster sets | |
| _geuClearVal1Val2RegisterSets(); | |
| // _geuSaveAllFieldsInFuseBlock0NotBeingBurned(); | |
| // Move ECC to VAL1/VAL2 in proper offset | |
| // Only ONE burn request should be set as the EccCal register | |
| // is only valid for ONE fuseblock at a time | |
| // // If ApCpUsb ECC burn request | |
| // if ((pActiveFuseData->BurnRequest & K_APCPUSB_ECC_BURN_REQUEST_MASK)!= 0) | |
| // { | |
| // // Save ApCpUsb ECC value to Val1/Val2 | |
| // //_geuUpdateRegister(GEU_FUSE_PROG_VAL1+8, pActiveFuseData->EccCalRegSave, 0x0000FFFF); | |
| // scratch = pActiveFuseData->EccCalRegSave & 0x0000FFFF; | |
| // scratch = scratch << 16; // Shift ECC value to upper 16 bits | |
| // _geuUpdateRegister(GEU_FUSE_PROG_VAL2+12, scratch, 0XFFFF0000); // write to upper 16 bits of fuse block | |
| // } | |
| // If OEM ECC burn request | |
| if ((pActiveFuseData->BurnRequest & K_OEM_KEY0_ECC_BURN_REQUEST_MASK)!= 0) | |
| { | |
| // Save OEM ECC value to Val1/Val2 | |
| _geuUpdateRegister(GEU_FUSE_PROG_VAL1+12, pActiveFuseData->EccCalRegSave, 0xFFFFFFFF); | |
| pActiveFuseData->OemEccSave = pActiveFuseData->EccCalRegSave; // saved ECC value. | |
| } | |
| // If JTAG ECC burn request | |
| if ((pActiveFuseData->BurnRequest & K_JTAG_KEY0_ECC_BURN_REQUEST_MASK)!= 0) | |
| { | |
| // Save JTAG ECC value to Val1/Val2 | |
| _geuUpdateRegister(GEU_FUSE_PROG_VAL2+0, pActiveFuseData->EccCalRegSave, 0xFFFFFFFF); | |
| pActiveFuseData->JtagEccSave = pActiveFuseData->EccCalRegSave; // saved ECC value. | |
| } | |
| // VAL1/VAL2 Registers updated | |
| // Burn Count = 0 | |
| pActiveFuseData->EccBurnCount = 0; | |
| _geuSaveAllFieldsInFuseBlock7NotBeingBurned(); | |
| while (pActiveFuseData->BurnRequest) | |
| { | |
| //++ ****** Burn ********** | |
| status = _geuBurnFuse(K_FB7_FUSEBLOCK, 0); | |
| //-- ****** Burn ********** | |
| if (status != 0) | |
| { | |
| pFuseBurnStatus->DebugStatus = status; | |
| } | |
| // Burn Count++ | |
| pActiveFuseData->EccBurnCount++; | |
| if (pActiveFuseData->BurnCount > 1) | |
| { | |
| pFuseBurnStatus->DebugStatus |= K_MULTIPLE_BURN_COUNT; | |
| } | |
| //******************************************************************** | |
| // Validate the component burned (one with a burn request) | |
| //******************************************************************** | |
| // Validate Ecc Burn Request | |
| //******************************************************************** | |
| //++ | |
| // if ((pActiveFuseData->BurnRequest & K_APCPUSB_ECC_BURN_REQUEST_MASK) != 0) | |
| // { | |
| // // Check for ApCpUsb ECC Errors | |
| // GEU_REG_READ(GEU_ECC_STATUS, scratch); | |
| // pFuseBurnStatus->ApCpUsb_EccStatus = scratch & | |
| // K_APCPUSB_UNCORRECTABLE_ECC_ERROR_MASK; | |
| // if (pFuseBurnStatus->ApCpUsb_EccStatus == 0) | |
| // { | |
| // // ApCpUsb ECC Burn Good (No Errors or 1 Correctable error) | |
| // // - Clear the Burn Request | |
| // pActiveFuseData->BurnRequest &= ~K_APCPUSB_ECC_BURN_REQUEST_MASK; | |
| // // Clear any error reported in the CorrectedBurnStatus | |
| // pFuseBurnStatus->CorrectedBurnStatus &= ~K_APCPUSB_BURN_REQUEST_MASK; | |
| // } | |
| // else | |
| // { | |
| // // If the BurnCount is 1, leave the burn request set | |
| // // for another try. | |
| // // Else | |
| // if (pActiveFuseData->BurnCount >= 2) | |
| // { | |
| // // Ecc Burn Failed two times - Clear the burn Request | |
| // pActiveFuseData->BurnRequest = pActiveFuseData->BurnRequest | |
| // & ~K_APCPUSB_ECC_BURN_REQUEST_MASK; | |
| // // Set the Corrected Burn Status to indicate Failure | |
| // pFuseBurnStatus->CorrectedBurnStatus = pFuseBurnStatus->CorrectedBurnStatus | | |
| // K_APCPUSB_ECC_STATUS_BIT_MASK; | |
| // } | |
| // }//EndIfElse | |
| // }//Endif | |
| // //-- Validate ApCpUsb ECC Burn Request | |
| //******************************************************************** | |
| // Validate OEM ECC Burn Request | |
| //******************************************************************** | |
| //++ | |
| if ((pActiveFuseData->BurnRequest & K_OEM_KEY0_ECC_BURN_REQUEST_MASK) != 0) | |
| { | |
| // Check for ApCpUsb ECC Errors | |
| GEU_REG_READ(GEU_ECC_STATUS, scratch); | |
| pFuseBurnStatus->Oem_EccStatus = scratch & | |
| K_OEM_KEY_HASH0_UNCORRECTABLE_ECC_ERROR_MASK; | |
| if (pFuseBurnStatus->Oem_EccStatus == 0) | |
| { | |
| // OEM Platform Hash Key ECC Burn Good (No Errors or 1 Correctable error) | |
| // - Clear the Burn Request | |
| pActiveFuseData->BurnRequest = pActiveFuseData->BurnRequest | |
| & ~K_OEM_KEY0_ECC_BURN_REQUEST_MASK; | |
| // Clear any error in the CorrectedBurnStatus | |
| pFuseBurnStatus->CorrectedBurnStatus = pFuseBurnStatus->CorrectedBurnStatus | |
| & ~K_OEM_KEY0_BURN_REQUEST_MASK; | |
| // Save OEM KEY ECC | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_KEY_ECC, pActiveFuseData->OemEccSave); | |
| } | |
| else | |
| { | |
| // If the EccBurnCount is 1, leave the burn request set | |
| // for another try. | |
| // Else | |
| if (pActiveFuseData->EccBurnCount >= 2) | |
| { | |
| // Ecc Burn Failed two times - Clear the burn Request | |
| pActiveFuseData->BurnRequest = pActiveFuseData->BurnRequest | |
| & ~K_OEM_KEY0_ECC_BURN_REQUEST_MASK; | |
| // Set the Corrected Burn Status to indicate Failure | |
| pFuseBurnStatus->CorrectedBurnStatus = pFuseBurnStatus->CorrectedBurnStatus | | |
| K_OEM_KEY0_ECC_STATUS_BIT_MASK; | |
| } | |
| }//EndIfElse | |
| }//Endif | |
| //-- Validate OEM ECC Burn Request | |
| //******************************************************************** | |
| // Validate JTAG ECC Burn Request | |
| //******************************************************************** | |
| //++ | |
| if ((pActiveFuseData->BurnRequest & K_JTAG_KEY0_ECC_BURN_REQUEST_MASK) != 0) | |
| { | |
| // Check for JTAG ECC Errors | |
| GEU_REG_READ(GEU_ECC_STATUS, scratch); | |
| pFuseBurnStatus->Jtag_EccStatus = scratch & | |
| K_JTAG_KEY_HASH0_UNCORRECTABLE_ECC_ERROR_MASK; | |
| if (pFuseBurnStatus->Jtag_EccStatus == 0) | |
| { | |
| // JTAG ECC Burn Good (No Errors or 1 Correctable error) | |
| // - Clear the Burn Request | |
| pActiveFuseData->BurnRequest = pActiveFuseData->BurnRequest | |
| & ~K_JTAG_KEY0_ECC_BURN_REQUEST_MASK; | |
| // Clear any error in the CorrectedBurnStatus | |
| pFuseBurnStatus->CorrectedBurnStatus = pFuseBurnStatus->CorrectedBurnStatus | |
| & ~K_JTAG_KEY0_BURN_REQUEST_MASK; | |
| // Save JTAG ECC | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_JTAG_KEY_HASH_ECC,pActiveFuseData->JtagEccSave); | |
| } | |
| else | |
| { | |
| // If the EccBurnCount is 1, leave the burn request set | |
| // for another try. | |
| // Else | |
| if (pActiveFuseData->EccBurnCount >= 2) | |
| { | |
| // Ecc Burn Failed two times - Clear the burn Request | |
| pActiveFuseData->BurnRequest = pActiveFuseData->BurnRequest | |
| & ~K_JTAG_KEY0_ECC_BURN_REQUEST_MASK; | |
| // Set the Corrected Burn Status to indicate Failure | |
| pFuseBurnStatus->CorrectedBurnStatus = pFuseBurnStatus->CorrectedBurnStatus | | |
| K_JTAG_KEY0_ECC_STATUS_BIT_MASK; | |
| } | |
| }//EndIfElse | |
| }//Endif | |
| //-- Validate JTAG ECC Burn Request | |
| }//End while | |
| // //******************************************************************** | |
| // // Validate fields NOT burned - Make sure they didn't change | |
| // //******************************************************************** | |
| // //++ ApCpUsb ECC | |
| // if ((pFuseBurnStatus->SavedBurnRequest & K_APCPUSB_ECC_BURN_REQUEST_MASK) == 0) | |
| // { | |
| // status = _geuValidate_ApCpUsbId_ECC_FuseBits(); | |
| // } | |
| //++ OEM ECC | |
| if ((pFuseBurnStatus->SavedBurnRequest & K_OEM_KEY0_ECC_BURN_REQUEST_MASK) == 0) | |
| { | |
| status = _geuValidate_OEMHashKey_ECC_FuseBits(); | |
| } | |
| //++ JTAG ECC | |
| if ((pFuseBurnStatus->SavedBurnRequest & K_JTAG_KEY0_ECC_BURN_REQUEST_MASK) == 0) | |
| { | |
| status = _geuValidate_JTAGHashKey_ECC_FuseBits(); | |
| } | |
| // status = _geuValidateApConfigFuseBits(); | |
| // status = _geuValidateCpConfigFuseBits(); | |
| status = _geuValidateUsbIdFuseBits(); | |
| status = _geuValidateSecurityConfigFuseBits(); | |
| // status = _geuValidateLifeCycleFuseBits(); | |
| // status = _geuValidateSoftwareVersionFuseBits(); | |
| if(pFuseBurnStatus->CorrectedBurnStatus != 0) | |
| { | |
| pFuseBurnStatus->FinalBurnStatus = FUSE_BurnError; | |
| } | |
| else | |
| { | |
| pFuseBurnStatus->FinalBurnStatus = NoError; | |
| } | |
| return(_geuUpdateUserFuseBurnStatus(pUserFuseBurnStatus, pFuseBurnStatus->FinalBurnStatus)); | |
| }//End Routine GEU_BURN_ECC | |
| /********************************************************** | |
| * Function: | |
| * GEU_LockFuseBlock | |
| * | |
| * Description: | |
| * Wrapper for individual fuse block lock burn routines. | |
| * Sets the active fuse block to the specified fuse block | |
| * and calls the generic lock routine | |
| * | |
| * Input: | |
| * n- Fuse block to be locked | |
| pUserFuseBurnStatus - pointer to a buffer containing a FuseBurnStatus structure | |
| * | |
| * Output: | |
| * none | |
| * Returns: | |
| * NoError | |
| * FUSE_BurnError | |
| * FUSE_UnsupportedFuseBlock | |
| * | |
| ************************************************************/ | |
| UINT_T GEU_LockFuseBlock(UINT_T n, struct GEU_FuseBurnStatus * pUserFuseBurnStatus) | |
| { | |
| UINT_T status; | |
| if( _geuConfirmPowerEnabledForFuseBurning() == 0) | |
| { | |
| pFuseBurnStatus->FinalBurnStatus = FUSE_FuseBurnPowerNotEnabled; | |
| return(_geuUpdateUserFuseBurnStatus(pUserFuseBurnStatus, pFuseBurnStatus->FinalBurnStatus)); | |
| } | |
| switch (n) | |
| { | |
| default: | |
| case (K_AP_CONFIG_FUSEBLOCK): | |
| { | |
| // Lock on FB0 not supported (although it should be there in hardware | |
| // - use sticky bit instead | |
| status = FUSE_UnsupportedFuseBlock; | |
| break; | |
| } | |
| case (K_OEM_FUSEBLOCK): | |
| case (K_JTAG_FUSEBLOCK): | |
| case (K_RKEK_FUSEBLOCK): | |
| case (K_FB7_FUSEBLOCK): | |
| { | |
| status = GEU_SetActiveFuseBlock(n); | |
| status = _geuLockActiveFuseblock(pUserFuseBurnStatus); | |
| break; | |
| } | |
| }//End Switch | |
| return status; | |
| }//End Routine GEU_LOCK_FUSEBLOCK | |
| UINT_T GEU_SetupSecurityConfigUsbIdEccFuseBits(void) | |
| { | |
| UINT_T ecc_cal; | |
| /* Confirm this fuseblock is active */ | |
| if (pActiveFuseData->ActiveFuseBlock != K_USBID_FUSEBLOCK) { | |
| return (FUSE_FuseBlockNotActive); | |
| } | |
| if (pActiveFuseData->ActiveFuseBlockField != K_SECURITY_USBID_FUSEBLOCK_FIELD) { | |
| return (FUSE_FuseBlockFieldNotActive); | |
| } | |
| //if ((pActiveFuseData->BurnRequest & K_SECURITY_USBID_BURN_REQUEST_MASK) != K_SECURITY_USBID_BURN_REQUEST_MASK) { | |
| // return FUSE_IncompleteFuseFieldsSetup; | |
| //} | |
| GEU_REG_READ(GEU_ECC_CAL, ecc_cal); | |
| _geuUpdateRegister(GEU_FUSE_PROG_VAL1 + 8, ecc_cal, 0xFF); | |
| // Save to Active fuseblock for burn validation later | |
| pActiveFuseData->SecurityUsbEccSave = (ecc_cal & 0xFF); | |
| pActiveFuseData->BurnRequest |= K_SECURITY_USBID_ECC_BURN_REQUEST_MASK; | |
| return NoError; | |
| } | |
| /********************************************************** | |
| * Function: | |
| * GEU_BurnFuseBlock_SecurityUSBIDECC | |
| * | |
| * Description: | |
| * Burns the Security config and USB ID field, and SecurityUSBECC in Fuseblock 7. This may burn one | |
| * or more of the Security Config, and USB Id subfields and ECC | |
| * | |
| * - Confirms that a burn request exists for one or more of the | |
| * Security or USB Id subfields or ECC. | |
| * - Saves other state (for post burn validation). | |
| * - Saves any of the the Security Config or USB Id subfields that are not being burned. | |
| * - Burns the fuseblock | |
| * Validates burned subfields and retries if burn not successful. | |
| * - Validates all subfields that were not burned to ensure no changes from the burn. | |
| * | |
| * Input: | |
| * pUserFuseBurnStatus - pointer to a buffer containing a FuseBurnStatus structure | |
| * | |
| * Output: | |
| * none | |
| * Returns: | |
| * NoError | |
| * FUSE_FuseBlockNotActive | |
| * FUSE_FuseBurnPowerNotEnabled | |
| * FUSE_NoBurnRequest | |
| * FUSE_BurnError | |
| * | |
| ************************************************************/ | |
| UINT_T GEU_BurnFuseBlock_SecurityUSBIDECC(struct GEU_FuseBurnStatus * pUserFuseBurnStatus) | |
| { | |
| UINT_T temp[8]; // temp buffer for fuse block compares | |
| UINT_T status; | |
| // Confirm this fuseblock is active | |
| if (pActiveFuseData->ActiveFuseBlock != K_USBID_FUSEBLOCK) | |
| { | |
| return (FUSE_FuseBlockNotActive); | |
| } | |
| // Confirm bandgap from USB PHY is enabled for the fuse power regulator | |
| if( _geuConfirmPowerEnabledForFuseBurning() == 0) | |
| { | |
| pFuseBurnStatus->FinalBurnStatus = FUSE_FuseBurnPowerNotEnabled; | |
| return(_geuUpdateUserFuseBurnStatus(pUserFuseBurnStatus, pFuseBurnStatus->FinalBurnStatus)); | |
| } | |
| // Save the burn request in the FuseBurnStatus | |
| pFuseBurnStatus->SavedBurnRequest = pActiveFuseData->BurnRequest; | |
| if (pActiveFuseData->BurnRequest & (K_SECURITY_USBID_BURN_REQUEST_MASK | K_SECURITY_USBID_ECC_BURN_REQUEST_MASK) == 0) | |
| { | |
| return(_geuUpdateUserFuseBurnStatus(pUserFuseBurnStatus, FUSE_IncompleteFuseFieldsSetup)); | |
| } | |
| // _geuSaveAllFieldsInFuseBlock7NotBeingBurned(); | |
| // Burn Count = 0 | |
| //pActiveFuseData->ApCpUsbBurnCount = 0; | |
| pActiveFuseData->BurnCount = 0; | |
| while (pActiveFuseData->BurnRequest) | |
| { | |
| //++ ****** Burn ********** | |
| status = _geuBurnFuse(K_USBID_FUSEBLOCK, 0); | |
| //-- ****** Burn ********** | |
| if (status != 0) | |
| { | |
| pFuseBurnStatus->DebugStatus = status; | |
| } | |
| // Burn Count++ | |
| pActiveFuseData->BurnCount++; | |
| if (pActiveFuseData->BurnCount > 1) | |
| { | |
| pFuseBurnStatus->DebugStatus |= K_MULTIPLE_BURN_COUNT; | |
| } | |
| //******************************************************************** | |
| // Validate the components burned (ones with a burn request) | |
| //******************************************************************** | |
| // Validate Security CONFIG Burn Request | |
| //******************************************************************** | |
| //++ | |
| if ((pActiveFuseData->BurnRequest & K_SECURITY_CONFIG_BURN_REQUEST_MASK) != 0) | |
| { | |
| //Compare Burned Security with Saved Security Config Bits | |
| status = GEU_ReadSecurityConfigFuseBits(&temp[0], | |
| K_SECURITY_CONFIG_FUSE_SIZE); | |
| // Ignore status - whatever we read, we read | |
| status = _geu_compare(&pActiveFuseData->SecurityConfigSave[0], | |
| &temp[0], | |
| K_SECURITY_CONFIG_FUSE_SIZE); | |
| if (status == 0) | |
| { | |
| // Security Config Burn Good - Clear the Burn Request | |
| pActiveFuseData->BurnRequest &= ~K_SECURITY_CONFIG_BURN_REQUEST_MASK; | |
| } | |
| else | |
| { | |
| // If the BurnCount is 1, leave the burn request set | |
| // for another try. | |
| // Else | |
| if (pActiveFuseData->BurnCount >= 2) | |
| { | |
| // Security Burn Failed two times - Clear the burn Request | |
| pActiveFuseData->BurnRequest &= ~K_SECURITY_CONFIG_BURN_REQUEST_MASK; | |
| // Set the Security Raw Burn Status to indicate Failure | |
| pFuseBurnStatus->RawBurnStatus |= K_SECURITY_CONFIG_BURN_REQUEST_MASK; | |
| } | |
| }//EndIfElse | |
| }//Endif | |
| //-- Validate Security CONFIG Burn Request | |
| //******************************************************************** | |
| // Validate USB ID Burn Request | |
| //******************************************************************** | |
| //++ | |
| if ((pActiveFuseData->BurnRequest & K_USBID_BURN_REQUEST_MASK) != 0) | |
| { | |
| //Compare Burned USB with Saved USB Config Bits | |
| status = GEU_ReadUsbIdFuseBits(&temp[0], | |
| K_USBID_FUSE_SIZE); | |
| status = _geu_compare(&pActiveFuseData->UsbIdSave[0], | |
| &temp[0], | |
| K_USBID_FUSE_SIZE); | |
| if (status == 0) | |
| { | |
| // USB Burn Good - Clear the Burn Request | |
| pActiveFuseData->BurnRequest &= ~K_USBID_BURN_REQUEST_MASK; | |
| } | |
| else | |
| { | |
| // If the BurnCount is 1, leave the burn request set | |
| // for another try. | |
| // Else | |
| if (pActiveFuseData->BurnCount >= 2) | |
| { | |
| // USB ID Burn Failed two times - Clear the Burn Request | |
| pActiveFuseData->BurnRequest &= ~K_USBID_BURN_REQUEST_MASK; | |
| // Set theUSB ID Raw Burn Status to indicate Failure | |
| pFuseBurnStatus->RawBurnStatus |= K_USBID_STATUS_BIT_MASK; | |
| } | |
| }//EndIfElse | |
| }//Endif | |
| // Validate Security USB ECC | |
| if ((pActiveFuseData->BurnRequest & K_SECURITY_USBID_ECC_BURN_REQUEST_MASK) != 0) | |
| { | |
| UINT_T ecc; | |
| GEU_REG_READ(GEU_FUSE_VAL_SECURITY_USB_ECC, ecc); | |
| status = _geu_compare(&pActiveFuseData->SecurityUsbEccSave, | |
| &ecc, | |
| K_SECURITY_USB_ECC_FUSE_SIZE); | |
| if (status == 0) | |
| { | |
| // Security USB Ecc Burn Good - Clear the Burn Request | |
| pActiveFuseData->BurnRequest &= ~K_SECURITY_USBID_ECC_BURN_REQUEST_MASK; | |
| } | |
| else | |
| { | |
| // If the BurnCount is 1, leave the burn request set | |
| // for another try. | |
| // Else | |
| if (pActiveFuseData->BurnCount >= 2) | |
| { | |
| // Security USB Ecc Burn Failed two times - Clear the Burn Request | |
| pActiveFuseData->BurnRequest &= ~K_SECURITY_USBID_ECC_BURN_REQUEST_MASK; | |
| // Set the Security USB Ecc Raw Burn Status to indicate Failure | |
| pFuseBurnStatus->RawBurnStatus |= K_SECURITY_USBID_ECC_BURN_REQUEST_MASK; | |
| } | |
| }//EndIfElse | |
| } | |
| //-- Validate Security USB Ecc Request | |
| }//End While | |
| // | |
| // All of the components of the Security Config and USB ID fields that were SETUP, have been burned. | |
| // we are done Burning Fuse Block 7. | |
| // | |
| // Now Validate components in the Fuse Block 7 (AP/CP/MP/LC/etc group without burn request | |
| // to verify that they did not change. | |
| // The BurnRequest bits in the ActiveFuseData have been cleared by now so use the saved copy | |
| // of the Burn Request in the FuseBurnStatus. | |
| // Security Config | |
| if ((pFuseBurnStatus->SavedBurnRequest & K_SECURITY_CONFIG_BURN_REQUEST_MASK) == 0) | |
| { | |
| //Compare FuseBlock Security Config bits with Saved Security Config Bits | |
| status = _geuValidateSecurityConfigFuseBits(); | |
| } | |
| // USB ID | |
| if ((pFuseBurnStatus->SavedBurnRequest & K_USBID_BURN_REQUEST_MASK) == 0) | |
| { | |
| //Compare FuseBlock USB ID bits with Saved USB ID Bits | |
| status = _geuValidateUsbIdFuseBits(); | |
| } | |
| //++ OEM ECC | |
| if ((pFuseBurnStatus->SavedBurnRequest & K_OEM_KEY0_ECC_BURN_REQUEST_MASK) == 0) | |
| { | |
| status = _geuValidate_OEMHashKey_ECC_FuseBits(); | |
| } | |
| //++ JTAG ECC | |
| if ((pFuseBurnStatus->SavedBurnRequest & K_JTAG_KEY0_ECC_BURN_REQUEST_MASK) == 0) | |
| { | |
| status = _geuValidate_JTAGHashKey_ECC_FuseBits(); | |
| } | |
| // Set status | |
| pFuseBurnStatus->CorrectedBurnStatus = pFuseBurnStatus->RawBurnStatus; | |
| if(pFuseBurnStatus->CorrectedBurnStatus != 0) | |
| { | |
| pFuseBurnStatus->FinalBurnStatus = FUSE_BurnError; | |
| } | |
| return(_geuUpdateUserFuseBurnStatus(pUserFuseBurnStatus, pFuseBurnStatus->FinalBurnStatus)); | |
| }//End Routine GEU_BurnFuseBlock_SecurityUSBID | |
| /********************************************************** | |
| * Function: | |
| * _geuLockActiveFuseBlock | |
| * | |
| * Description: | |
| * Generic fuse block lock routines. | |
| * | |
| * - Saves the active fuse block data | |
| * - Clears VAL1 and VAL2 register sets | |
| * - Sets the Lock burn request | |
| * - Burns the fuse block with the Fuse Lock set | |
| * - Validates the lock gets set | |
| * - Will retry if necessary | |
| * - Validates fuse block data did not change | |
| * | |
| * Input: | |
| * pUserFuseBurnStatus - pointer to a buffer containing a FuseBurnStatus structure | |
| * | |
| * Output: | |
| * none | |
| * Returns: | |
| * NoError | |
| * FUSE_BurnError | |
| * FUSE_UnsupportedFuseBlock | |
| * | |
| ************************************************************/ | |
| UINT_T _geuLockActiveFuseblock(struct GEU_FuseBurnStatus * pUserFuseBurnStatus) | |
| { | |
| UINT_T temp[8]; // temp buffer for fuse block compare | |
| UINT_T scratch; | |
| UINT_T status; | |
| UINT_T RawFailureBitMask; | |
| switch(pActiveFuseData->ActiveFuseBlock) | |
| { | |
| case(K_OEM_FUSEBLOCK): | |
| {// Save OEM Hash | |
| status = GEU_ReadOemHashKeyFuseBits(&pActiveFuseData->FuseBlockSave[0], K_FUSEBLOCK_SIZE); | |
| break; | |
| } | |
| case(K_JTAG_FUSEBLOCK): | |
| {// Save JTAG Hash | |
| status = GEU_ReadOemJtagHashKeyFuseBits(&pActiveFuseData->FuseBlockSave[0], K_FUSEBLOCK_SIZE); | |
| break; | |
| } | |
| case(K_RKEK_FUSEBLOCK): | |
| {// Save RKEK Hash | |
| //status = GEU_ReadRkekFuseBits(&pActiveFuseData->FuseBlockSave[0], K_FUSEBLOCK_SIZE); | |
| break; | |
| } | |
| case(K_ECC_FUSEBLOCK): | |
| {// Save ECC values | |
| GEU_REG_READ(GEU_FUSE_VAL_APCP_ECC, pActiveFuseData->ApCpMpEccSave); | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_KEY_ECC, pActiveFuseData->OemEccSave); | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_JTAG_KEY_HASH_ECC,pActiveFuseData->JtagEccSave); | |
| break; | |
| } | |
| default: | |
| { | |
| return (FUSE_UnsupportedFuseBlock); | |
| } | |
| }//End switch | |
| // Clear VAL1 & VAL2 register sets | |
| _geuClearVal1Val2RegisterSets(); | |
| //Set the burn request | |
| pActiveFuseData->BurnRequest = pActiveFuseData->BurnRequest | K_FUSEBLOCK_LOCK_BURN_REQUEST_MASK; | |
| pActiveFuseData->BurnCount = 0; | |
| while (pActiveFuseData->BurnRequest) | |
| { | |
| //++ ****** Burn ********** | |
| status = _geuBurnFuse(pActiveFuseData->ActiveFuseBlock, K_LOCK_FUSEBLOCK); | |
| //-- ****** Burn ********** | |
| if (status != 0) | |
| { | |
| pFuseBurnStatus->DebugStatus = status; | |
| } | |
| // Burn Count++ | |
| pActiveFuseData->BurnCount++; // BurnCount or LockBurnCount? | |
| if (pActiveFuseData->BurnCount > 1) | |
| { | |
| pFuseBurnStatus->DebugStatus |= K_MULTIPLE_BURN_COUNT; | |
| } | |
| // Validate block locked | |
| GEU_REG_READ(GEU_FUSE_STATUS, scratch); | |
| scratch = (scratch & GEU_FUSE_STATUS_LOCK_BIT_MSK)>>GEU_FUSE_STATUS_LOCK_BIT_BASE; | |
| scratch = scratch & pActiveFuseData->FuseLockBitMask; | |
| if (scratch != 0) | |
| { | |
| // Burn Good - Clear the Burn Request | |
| pActiveFuseData->BurnRequest = pActiveFuseData->BurnRequest | |
| & ~K_FUSEBLOCK_LOCK_BURN_REQUEST_MASK; | |
| } | |
| else | |
| { | |
| // Burn failed | |
| // If the BurnCount is 1, leave the burn request set | |
| // for another try. | |
| // Else | |
| if (pActiveFuseData->BurnCount >= 2) | |
| { | |
| // Burn Failed two times - Clear the burn Request | |
| pActiveFuseData->BurnRequest = pActiveFuseData->BurnRequest | |
| & ~K_FUSEBLOCK_LOCK_BURN_REQUEST_MASK; | |
| // Set the AP Raw Burn Status to indicate Failure | |
| pFuseBurnStatus->RawBurnStatus = pFuseBurnStatus->RawBurnStatus | | |
| K_LOCK_STATUS_BIT_MASK; | |
| } | |
| }//EndIfElse | |
| }//End while | |
| switch(pActiveFuseData->ActiveFuseBlock) | |
| { | |
| case(K_OEM_FUSEBLOCK): | |
| {// Save OEM Hash | |
| status = GEU_ReadOemHashKeyFuseBits(&temp[0], K_FUSEBLOCK_SIZE); | |
| status = _geu_compare(&pActiveFuseData->FuseBlockSave[0], | |
| &temp[0], | |
| K_FUSEBLOCK_SIZE); | |
| RawFailureBitMask = K_OEM_KEY0_STATUS_BIT_MASK; | |
| break; | |
| } | |
| case(K_JTAG_FUSEBLOCK): | |
| {// Save JTAG Hash | |
| status = GEU_ReadOemJtagHashKeyFuseBits(&temp[0], K_FUSEBLOCK_SIZE); | |
| status = _geu_compare(&pActiveFuseData->FuseBlockSave[0], | |
| &temp[0], | |
| K_FUSEBLOCK_SIZE); | |
| RawFailureBitMask = K_JTAG_KEY0_STATUS_BIT_MASK; | |
| break; | |
| } | |
| case(K_RKEK_FUSEBLOCK): | |
| {// Save RKEK Hash | |
| //status = GEU_ReadRkekFuseBits(&temp[0], K_FUSEBLOCK_SIZE); | |
| //status = _geu_compare(&pActiveFuseData->FuseBlockSave[0], | |
| // &temp[0], | |
| // K_FUSEBLOCK_SIZE); | |
| //RawFailureBitMask = K_RKEK_STATUS_BIT_MASK; | |
| break; | |
| } | |
| case(K_ECC_FUSEBLOCK): | |
| {// Save ECC values | |
| status = 0; | |
| GEU_REG_READ(GEU_FUSE_VAL_APCP_ECC, temp[0]); | |
| if (pActiveFuseData->ApCpMpEccSave != temp[0]) | |
| { | |
| status = FUSE_FuseBlockCompareFailed ; | |
| RawFailureBitMask = K_APCPMP0_ECC_STATUS_BIT_MASK; | |
| } | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_KEY_ECC, temp[0]); | |
| if (pActiveFuseData->OemEccSave != temp[0]) | |
| { | |
| status = FUSE_FuseBlockCompareFailed ; | |
| RawFailureBitMask = K_OEM_KEY0_ECC_STATUS_BIT_MASK; | |
| } | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_JTAG_KEY_HASH_ECC, temp[0]); | |
| if (pActiveFuseData->JtagEccSave != temp[0]) | |
| { | |
| status = FUSE_FuseBlockCompareFailed ; | |
| RawFailureBitMask = K_JTAG_KEY0_ECC_STATUS_BIT_MASK; | |
| } | |
| break; | |
| }//End Case | |
| default: | |
| { | |
| return (FUSE_UnsupportedFuseBlock); | |
| } | |
| }//End switch | |
| if (status != 0) | |
| { | |
| pFuseBurnStatus->RawBurnStatus = pFuseBurnStatus->RawBurnStatus | | |
| RawFailureBitMask; | |
| } | |
| pFuseBurnStatus->CorrectedBurnStatus = pFuseBurnStatus->RawBurnStatus; | |
| if(pFuseBurnStatus->CorrectedBurnStatus != 0) | |
| { | |
| pFuseBurnStatus->FinalBurnStatus = FUSE_BurnError; | |
| } | |
| return(_geuUpdateUserFuseBurnStatus(pUserFuseBurnStatus, pFuseBurnStatus->FinalBurnStatus)); | |
| }// End Routine _geuLockActiveFuseblock | |
| UINT_T _geuValidateUsbIdFuseBits() | |
| { | |
| UINT_T temp[8]; // temp buffer for fuse block compares | |
| UINT_T status = NoError; | |
| //++ ***** Validate USB Id bits did not change ****************** | |
| //Compare FuseBlock USB ID bits with Saved USB ID Bits | |
| status = GEU_ReadUsbIdFuseBits(&temp[0], | |
| K_USBID_FUSE_SIZE); | |
| status = _geu_compare(&pActiveFuseData->UsbIdSave[0], | |
| &temp[0], | |
| K_USBID_FUSE_SIZE); | |
| if (status != 0) | |
| { | |
| // Set the USB Raw Burn Status to indicate Failure | |
| pFuseBurnStatus->RawBurnStatus = pFuseBurnStatus->RawBurnStatus | | |
| K_USBID_STATUS_BIT_MASK; | |
| } | |
| return status; | |
| } | |
| UINT_T _geuValidateSecurityConfigFuseBits() | |
| { | |
| UINT_T temp[8]; // temp buffer for fuse block compares | |
| UINT_T status = NoError; | |
| //++ ***** Validate Security Config bits did not change ****************** | |
| //Compare FuseBlock Security ID bits with Saved USB ID Bits | |
| status = GEU_ReadSecurityConfigFuseBits(&temp[0], | |
| K_SECURITY_CONFIG_FUSE_SIZE); | |
| status = _geu_compare(&pActiveFuseData->SecurityConfigSave[0], | |
| &temp[0], | |
| K_SECURITY_CONFIG_FUSE_SIZE); | |
| if (status != 0) | |
| { | |
| // Set the USB Raw Burn Status to indicate Failure | |
| pFuseBurnStatus->RawBurnStatus = pFuseBurnStatus->RawBurnStatus | | |
| K_SECURITY_CONFIG_STATUS_BIT_MASK; | |
| } | |
| return status; | |
| } | |
| UINT_T _geuValidate_OEMHashKey_ECC_FuseBits() | |
| { | |
| UINT_T status = NoError; | |
| UINT_T CurrentEcc, EccStatus; | |
| // OEM Hash Key ECC | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_KEY_ECC, CurrentEcc); | |
| if (pActiveFuseData->OemEccSave == 0) | |
| { | |
| // No ECC was burned so make sure it'still 0 | |
| if (CurrentEcc !=0) | |
| { | |
| // Ecc Burn of some other field corrupted this ECC field | |
| // Set the Corrected Burn Status to indicate Failure | |
| pFuseBurnStatus->CorrectedBurnStatus |= K_OEM_KEY_HASH0_UNCORRECTABLE_ECC_ERROR_MASK; | |
| status = FUSE_FuseBlockCompareFailed; | |
| } | |
| } | |
| else | |
| { | |
| // Saved ECC value NOT zero | |
| // Confirm it didn't change | |
| if (pActiveFuseData->OemEccSave != CurrentEcc) | |
| { | |
| // Check the ECC status and see if it's still correctable | |
| GEU_REG_READ(GEU_ECC_STATUS, EccStatus); | |
| pFuseBurnStatus->Oem_EccStatus = EccStatus & | |
| K_OEM_KEY_HASH0_UNCORRECTABLE_ECC_ERROR_MASK; | |
| if (pFuseBurnStatus->Oem_EccStatus != 0) | |
| { | |
| // Ecc Burn Corrupted this ECC field with uncorrectable errors | |
| // Set the Corrected Burn Status to indicate Failure | |
| pFuseBurnStatus->CorrectedBurnStatus |= K_OEM_KEY0_ECC_STATUS_BIT_MASK; | |
| status = FUSE_FuseBlockCompareFailed; | |
| }//EndIf | |
| } | |
| } | |
| return status; | |
| } | |
| UINT_T _geuValidate_JTAGHashKey_ECC_FuseBits() | |
| { | |
| UINT_T status = NoError; | |
| UINT_T CurrentEcc, EccStatus; | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_JTAG_KEY_HASH_ECC, CurrentEcc); | |
| if (pActiveFuseData->JtagEccSave == 0) | |
| { | |
| // No ECC was burned so make sure it'still 0 | |
| if (CurrentEcc !=0) | |
| { | |
| // Ecc Burn of some other field corrupted this ECC field | |
| // Set the Corrected Burn Status to indicate Failure | |
| pFuseBurnStatus->CorrectedBurnStatus |= K_JTAG_KEY_HASH0_UNCORRECTABLE_ECC_ERROR_MASK; | |
| status = FUSE_FuseBlockCompareFailed; | |
| } | |
| } | |
| else | |
| { | |
| // Saved ECC value NOT zero | |
| // Confirm it didn't change | |
| if (pActiveFuseData->JtagEccSave != CurrentEcc) | |
| { | |
| // Check the ECC status and see if it's still correctable | |
| GEU_REG_READ(GEU_ECC_STATUS, EccStatus); | |
| pFuseBurnStatus->Jtag_EccStatus = EccStatus & | |
| K_JTAG_KEY_HASH0_UNCORRECTABLE_ECC_ERROR_MASK; | |
| if (pFuseBurnStatus->Jtag_EccStatus != 0) | |
| { | |
| // Ecc Burn Corrupted this ECC field with uncorrectable errors | |
| // Set the Corrected Burn Status to indicate Failure | |
| pFuseBurnStatus->CorrectedBurnStatus |= K_JTAG_KEY0_ECC_STATUS_BIT_MASK; | |
| status = FUSE_FuseBlockCompareFailed; | |
| }//EndIf | |
| } | |
| } | |
| return status; | |
| } | |
| void _geuSaveAllFieldsInFuseBlock7NotBeingBurned() | |
| { | |
| volatile UINT_T status = NoError; | |
| // Save everything in the fuseblock(ApCpMpId ECC, JTAG ECC,OEM ECC,UsbId) | |
| // Save LifeCycle | |
| pActiveFuseData->LifeCycleSave = GEU_ReadLifeCycle(); | |
| //Save USB ID Bits | |
| if ((pActiveFuseData->BurnRequest & K_USBID_BURN_REQUEST_MASK) == 0) | |
| { | |
| status = GEU_ReadUsbIdFuseBits(&pActiveFuseData->UsbIdSave[0], K_USBID_FUSE_SIZE); | |
| } | |
| //Save Security Config ID Bits | |
| if ((pActiveFuseData->BurnRequest & K_SECURITY_USBID_BURN_REQUEST_MASK) == 0) | |
| { | |
| status = GEU_ReadSecurityConfigFuseBits(&pActiveFuseData->SecurityConfigSave[0], K_SECURITY_CONFIG_FUSE_SIZE); | |
| } | |
| //Save OEM UID Bits | |
| if ((pActiveFuseData->BurnRequest & K_OEM_UID_BURN_REQUEST_MASK) == 0) | |
| { | |
| status = GEU_ReadOemUidFuseBits(&pActiveFuseData->OemUidSave[0], K_OEM_UNIQUE_ID_FUSE_SIZE); | |
| } | |
| // Save JTAG ECC | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_JTAG_KEY_HASH_ECC,pActiveFuseData->JtagEccSave); | |
| // Save OEM KEY ECC | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_KEY_ECC, pActiveFuseData->OemEccSave); | |
| // Save ApCpMpId ECC | |
| GEU_REG_READ(GEU_FUSE_VAL_APCP_ECC, pActiveFuseData->ApCpMpEccSave); | |
| // Save LCS (JPD, FA, DD) and OEM UID ECC | |
| GEU_REG_READ(GEU_FUSE_VAL_LIFECYCLE_JPD_FA_DD_OEM_UID_ECC, pActiveFuseData->OemUidEccSave); | |
| return; | |
| } | |