blob: 08b99799f3ebdac91073328a3d40bc125fee48b2 [file] [log] [blame]
// 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;
}