// 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; | |
} | |