| // GEU_FuseWriteMethods.c |
| // |
| /****************************************************************************** |
| * |
| * (C)Copyright 2022 ASR. All Rights Reserved. |
| * |
| |
| ******************************************************************************/ |
| #include <Typedef.h> |
| #include <predefines.h> |
| #include <geu_interface.h> |
| #include <Errors.h> |
| #include <timer.h> |
| #include <PMUA.h> |
| #include <GEU.h> |
| #include <platform_geu_fuse_internal.h> |
| #include <GEU_FuseReadMethods.h> |
| #include "GEU_Provisioning.h" |
| |
| 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; |
| |
| UINT_T GEU_EnableFuseBurnPower() |
| { |
| //UINT_T result = NoError; |
| UINT_T scratch, clock_divider; |
| static UINT_T check=0; |
| |
| if (check == 0) { |
| |
| scratch = (1 << 3) | 1; |
| //Enable clock |
| GEU_REG_WRITE(PMUA_AES_CLK_RES_CTRL, scratch); |
| } |
| check++; |
| return NoError; |
| } |
| |
| UINT_T GEU_DisablePowerForFuseBurning() |
| { |
| return NoError; |
| } |
| |
| UINT_T GEU_SetActiveFuseBlock(UINT_T n) |
| { |
| UINT_T scratch; |
| |
| if (pActiveFuseData->ActiveFuseBlock != n) |
| { |
| // Clear the Fuse Burn Status Block |
| _geuClearFuseBurnStatus(pFuseBurnStatus); |
| |
| // Clear the ActiveFuseData |
| _geuClearActiveFuseData(pActiveFuseData); |
| |
| // Clear VAL1 & VAL2 register sets |
| _geuClearVal1Val2RegisterSets(); |
| |
| pActiveFuseData->ActiveFuseBlock = n; |
| pActiveFuseData->ActiveFuseBlockField = K_UNDEFINED_FUSEBLOCK_FIELD; |
| }//EndIf BlockNotActive |
| return 0; |
| }//End Routine SetActiveFuseBlock |
| |
| UINT_T GEU_ReadActiveFuseBlockNumber() |
| { |
| return (pActiveFuseData->ActiveFuseBlock); |
| } |
| |
| UINT_T GEU_SetupApConfigFuseBits(UINT_T* pBuffer, UINT_T Size) |
| { |
| UINT_T scratch; |
| UINT_T temp[3]; |
| UINT_T read_back[3]; |
| |
| if (Size != K_AP_CONFIG_FUSE_SIZE) |
| { |
| return FUSE_BufferTooSmall; |
| } |
| |
| // Confirm this fuseblock is active |
| if (g_ActiveFuseData.ActiveFuseBlock != K_AP_CONFIG_FUSEBLOCK) |
| { |
| return (FUSE_FuseBlockNotActive); |
| } |
| |
| // Check and Set Active FuseBlock Field |
| if (!(pActiveFuseData->ActiveFuseBlockField & K_AP_FUSEBLOCK_FIELD)) |
| { |
| pActiveFuseData->ActiveFuseBlockField |= K_AP_FUSEBLOCK_FIELD; |
| } |
| |
| //Low16 bit is CP configs |
| temp[0] = (pBuffer[0] & 0xFFFF) << 16; |
| temp[1] = (pBuffer[0] >> 16) & 0xFFFF; |
| temp[1] |= (pBuffer[1] & 0xFFFF) << 16; |
| temp[2] = (pBuffer[1] >> 16) & 0xFFFF; |
| temp[2] |= (pBuffer[2] & 0xFFFF) << 16; |
| |
| //Save the setup data to GEU_FUSE_PROG_VAL1/VAL2/VAL3 |
| _geuUpdateRegister(GEU_FUSE_PROG_VAL1+0, temp[0], 0xFFFF0000); //bit 16-31 are AP config |
| _geuUpdateRegister(GEU_FUSE_PROG_VAL1+4, temp[1], 0xFFFFFFFF); |
| _geuUpdateRegister(GEU_FUSE_PROG_VAL1+8, temp[2], 0xFFFFFFFF); |
| |
| //In case that AP config is not empty |
| GEU_ReadApConfigFuseBits(&read_back[0], K_APCP_CONFIG_FUSE_SIZE); |
| |
| // Save to Active fuseblock for burn validation later |
| pActiveFuseData->ApConfigSave[0] = pBuffer[0] | read_back[0]; |
| pActiveFuseData->ApConfigSave[1] = pBuffer[1] | read_back[1]; |
| pActiveFuseData->ApConfigSave[2] = pBuffer[2] | read_back[2]; |
| |
| //Set Burn Request |
| pActiveFuseData->BurnRequest |= K_AP_CONFIG_BURN_REQUEST_MASK; |
| |
| return 0; |
| } |
| |
| UINT_T GEU_SetupCpConfigFuseBits(UINT_T* pBuffer, UINT_T Size) |
| { |
| UINT_T scratch; |
| UINT_T temp; |
| UINT_T read_back; |
| |
| if (Size != K_CP_CONFIG_FUSE_SIZE) |
| { |
| return FUSE_BufferTooSmall; |
| } |
| |
| // Confirm this fuseblock is active |
| if (g_ActiveFuseData.ActiveFuseBlock != K_CP_CONFIG_FUSEBLOCK) |
| { |
| return (FUSE_FuseBlockNotActive); |
| } |
| |
| // Check and Set Active FuseBlock Field |
| if (!(pActiveFuseData->ActiveFuseBlockField & K_CP_FUSEBLOCK_FIELD)) |
| { |
| pActiveFuseData->ActiveFuseBlockField |= K_CP_FUSEBLOCK_FIELD; |
| } |
| |
| // Clear Burn Data in the Active Fuse Data Structure |
| // JLC: _geuClearActiveFuseData(); |
| |
| //Low16 bit is CP configs |
| temp = pBuffer[0] & 0xFFFF; |
| |
| //Save the setup data to GEU_FUSE_PROG_VAL1 |
| _geuUpdateRegister(GEU_FUSE_PROG_VAL1+0, temp, 0x0000FFFF); |
| |
| //In case that AP config is not empty |
| GEU_ReadCpConfigFuseBits(&read_back, K_CP_CONFIG_FUSE_SIZE); |
| |
| // Save to Active fuseblock for burn validation later |
| pActiveFuseData->CpConfigSave[0] = pBuffer[0] | read_back; |
| |
| //Set Burn Request |
| pActiveFuseData->BurnRequest |= K_CP_CONFIG_BURN_REQUEST_MASK; |
| |
| return 0; |
| } |
| |
| UINT_T GEU_SetupLifeCycleFuseBits(UINT_T* pBuffer, UINT_T Size) |
| { |
| UINT_T lcs; |
| UINT_T read_back; |
| |
| if (Size != K_LCS_FUSE_SIZE) |
| { |
| return FUSE_BufferTooSmall; |
| } |
| |
| lcs = pBuffer[0]; |
| |
| // Confirm this fuseblock is active |
| if (g_ActiveFuseData.ActiveFuseBlock != K_LIFECYCLE_FUSEBLOCK) |
| { |
| return (FUSE_FuseBlockNotActive); |
| } |
| |
| // Check and Set Active FuseBlock Field |
| if (!(pActiveFuseData->ActiveFuseBlockField & K_LIFECYCLE_FUSEBLOCK_FIELD)) |
| { |
| pActiveFuseData->ActiveFuseBlockField |= K_LIFECYCLE_FUSEBLOCK_FIELD; |
| } |
| |
| read_back = GEU_ReadLifeCycleState(); |
| pActiveFuseData->LifeCycleSave = lcs | read_back; |
| |
| //Save the setup data to GEU_FUSE_PROG_VAL1 |
| _geuUpdateRegister(GEU_FUSE_PROG_VAL2+8, lcs, 0x0000FFFF); |
| |
| //Set Burn Request |
| pActiveFuseData->BurnRequest |= K_LIFECYCLE_BURN_REQUEST_MASK; |
| |
| return 0; |
| } |
| |
| 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 and Set Active FuseBlock Field |
| if (!(pActiveFuseData->ActiveFuseBlockField & K_OEM0_FUSEBLOCK_FIELD)) |
| { |
| pActiveFuseData->ActiveFuseBlockField |= K_OEM0_FUSEBLOCK_FIELD; |
| } |
| |
| // 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 |
| |
| UINT_T GEU_SetupRkekFuseBits(UINT_T* pBuffer, UINT_T Size) |
| { |
| UINT_T scratch; |
| |
| if (Size != K_RKEK_FUSE_SIZE) |
| { |
| return FUSE_InvalidBufferSize; |
| } |
| // Confirm this fuseblock is active |
| if (g_ActiveFuseData.ActiveFuseBlock != K_RKEK_FUSEBLOCK) |
| { |
| return (FUSE_FuseBlockNotActive); |
| } |
| |
| // Check and Set Active FuseBlock Field |
| if (!(pActiveFuseData->ActiveFuseBlockField & K_RKEK_FUSEBLOCK_FIELD)) |
| { |
| pActiveFuseData->ActiveFuseBlockField |= K_RKEK_FUSEBLOCK_FIELD; |
| } |
| |
| // 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_RKEK_BURN_REQUEST_MASK; |
| |
| return 0; |
| }//End Routine GEU_SetupOemHashFuseBits |
| |
| UINT_T GEU_SetupPlatVersionFuseBits(UINT_T* pBuffer, UINT_T Size) |
| { |
| UINT_T temp[2]; |
| UINT_T read_back; |
| |
| if (Size != K_PLAT_VERSION_FUSE_SIZE) |
| { |
| return FUSE_BufferTooSmall; |
| } |
| |
| // Confirm this fuseblock is active |
| if (g_ActiveFuseData.ActiveFuseBlock != K_PLAT_VERSION_FUSEBLOCK) |
| { |
| return (FUSE_FuseBlockNotActive); |
| } |
| |
| // Check and Set Active FuseBlock Field |
| if (!(pActiveFuseData->ActiveFuseBlockField & K_PLAT_VERSION_FUSEBLOCK_FIELD)) |
| { |
| pActiveFuseData->ActiveFuseBlockField |= K_PLAT_VERSION_FUSEBLOCK_FIELD; |
| } |
| |
| //Low16 bit is CP configs |
| temp[0] = (pBuffer[0] & 0xFFFF) << 16; |
| temp[1] = (pBuffer[0] >> 16) & 0xFFFF; |
| |
| //Save the setup data to GEU_FUSE_PROG_VAL6/VAL7 |
| _geuUpdateRegister(GEU_FUSE_PROG_VAL1+24, temp[0], 0xFFFF0000); |
| _geuUpdateRegister(GEU_FUSE_PROG_VAL1+28, temp[1], 0x0000FFFF); |
| |
| //In case that AP config is not empty |
| read_back = GEU_ReadSoftwareVersion(); |
| |
| // Save to Active fuseblock for burn validation later |
| pActiveFuseData->SoftwareVersionSave[0] = pBuffer[0] | read_back; |
| pActiveFuseData->SoftwareVersionSave[1] = 0; |
| |
| //Set Burn Request |
| pActiveFuseData->BurnRequest |= K_PLAT_VERSION_BURN_REQUEST_MASK; |
| |
| return 0; |
| } |
| |
| 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); |
| } |
| |
| // Save the burn request in the FuseBurnStatus |
| pFuseBurnStatus->SavedBurnRequest = pActiveFuseData->BurnRequest; |
| |
| if ((pActiveFuseData->BurnRequest & K_OEM_KEY0_BURN_REQUEST_MASK) == 0) |
| { |
| pFuseBurnStatus->FinalBurnStatus = FUSE_NoBurnRequest ; |
| return(_geuUpdateUserFuseBurnStatus(pUserFuseBurnStatus, pFuseBurnStatus)); |
| } |
| // Burn Count = 0 |
| pActiveFuseData->BurnCount = 0; |
| |
| while (pActiveFuseData->BurnRequest) |
| { |
| //++ ****** Burn ********** |
| status = _geuBurnFuse(K_OEM_FUSEBLOCK, 0); // 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)); |
| }// End Routine GEU_BurnFuseBlock_OEM_Platform_Hash |
| |
| UINT_T GEU_BurnFuseBlock_RKEK(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_RKEK_FUSEBLOCK) |
| { |
| return (FUSE_FuseBlockNotActive); |
| } |
| |
| // Save the burn request in the FuseBurnStatus |
| pFuseBurnStatus->SavedBurnRequest = pActiveFuseData->BurnRequest; |
| |
| if ((pActiveFuseData->BurnRequest & K_RKEK_BURN_REQUEST_MASK) == 0) |
| { |
| pFuseBurnStatus->FinalBurnStatus = FUSE_NoBurnRequest ; |
| return(_geuUpdateUserFuseBurnStatus(pUserFuseBurnStatus, pFuseBurnStatus)); |
| } |
| // Burn Count = 0 |
| pActiveFuseData->BurnCount = 0; |
| |
| while (pActiveFuseData->BurnRequest) |
| { |
| //++ ****** Burn ********** |
| status = _geuBurnFuse(K_RKEK_FUSEBLOCK, 0); // 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_RKEK_BURN_REQUEST_MASK) != 0) |
| { |
| //Compare Burned value with Saved value |
| status = GEU_ReadRkekFuseBits(&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_RKEK_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_RKEK_BURN_REQUEST_MASK; |
| // Set the AP Raw Burn Status to indicate Failure |
| pFuseBurnStatus->RawBurnStatus = pFuseBurnStatus->RawBurnStatus | |
| K_RKEK_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)); |
| }// End Routine GEU_BurnFuseBlock_OEM_Platform_Hash |
| |
| UINT_T GEU_BurnFuseBlock_SocConfig(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_SOC_CONFIG_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)); |
| } |
| |
| // Save the burn request in the FuseBurnStatus |
| pFuseBurnStatus->SavedBurnRequest = pActiveFuseData->BurnRequest; |
| if (pActiveFuseData->BurnRequest & K_SOC_COFNIG_BURN_REQUEST_MASK == 0) |
| { |
| pFuseBurnStatus->FinalBurnStatus = FUSE_IncompleteFuseFieldsSetup; |
| return(_geuUpdateUserFuseBurnStatus(pUserFuseBurnStatus, pFuseBurnStatus)); |
| } |
| |
| // Burn Count = 0 |
| pActiveFuseData->BurnCount = 0; |
| while (pActiveFuseData->BurnRequest) |
| { |
| //++ ****** Burn ********** |
| status = _geuBurnFuse(K_AP_CONFIG_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_AP_CONFIG_BURN_REQUEST_MASK) != 0) |
| { |
| //Compare Burned Security with Saved Security Config Bits |
| status = GEU_ReadApConfigFuseBits(&temp[0], |
| K_AP_CONFIG_FUSE_SIZE); |
| // Ignore status - whatever we read, we read |
| status = _geu_compare(&pActiveFuseData->ApConfigSave[0], |
| &temp[0], |
| K_AP_CONFIG_FUSE_SIZE); |
| if (status == 0) |
| { |
| // Security Config Burn Good - Clear the Burn Request |
| pActiveFuseData->BurnRequest &= ~K_AP_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_AP_CONFIG_BURN_REQUEST_MASK; |
| // Set the Security Raw Burn Status to indicate Failure |
| pFuseBurnStatus->RawBurnStatus |= K_AP_CONFIG_BURN_REQUEST_MASK; |
| } |
| }//EndIfElse |
| }//Endif |
| //-- Validate AP CONFIG Burn Request |
| if ((pActiveFuseData->BurnRequest & K_CP_CONFIG_BURN_REQUEST_MASK) != 0) |
| { |
| status = GEU_ReadCpConfigFuseBits(&temp[0], |
| K_CP_CONFIG_FUSE_SIZE); |
| // Ignore status - whatever we read, we read |
| status = _geu_compare(&pActiveFuseData->CpConfigSave[0], |
| &temp[0], |
| K_CP_CONFIG_FUSE_SIZE); |
| if (status == 0) |
| { |
| // CP Config Burn Good - Clear the Burn Request |
| pActiveFuseData->BurnRequest &= ~K_CP_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_CP_CONFIG_BURN_REQUEST_MASK; |
| // Set the Security Raw Burn Status to indicate Failure |
| pFuseBurnStatus->RawBurnStatus |= K_CP_CONFIG_BURN_REQUEST_MASK; |
| } |
| |
| }//EndIfElse |
| |
| }//Endif |
| //-- Validate CP CONFIG Burn Request |
| |
| #if CLOSE_JTAG |
| if ((pActiveFuseData->BurnRequest & K_LIFECYCLE_BURN_REQUEST_MASK) != 0) |
| { |
| //Compare Burned Security with Saved Security Config Bits |
| temp[0] = GEU_ReadLifeCycleState(); |
| // Ignore status - whatever we read, we read |
| status = _geu_compare(&pActiveFuseData->LifeCycleSave, |
| &temp[0], |
| K_LCS_FUSE_SIZE); |
| if (status == 0) |
| { |
| // LCS Burn Good - Clear the Burn Request |
| pActiveFuseData->BurnRequest &= ~K_LIFECYCLE_BURN_REQUEST_MASK; |
| |
| } |
| else |
| { |
| // If the BurnCount is 1, leave the burn request set |
| // for another try. |
| // Else |
| if (pActiveFuseData->BurnCount >= 2) |
| { |
| // LCS Burn Failed two times - Clear the burn Request |
| pActiveFuseData->BurnRequest &= ~K_LIFECYCLE_BURN_REQUEST_MASK; |
| // Set the Raw Burn Status to indicate Failure |
| pFuseBurnStatus->RawBurnStatus |= K_LIFECYCLE_BURN_REQUEST_MASK; |
| } |
| |
| }//EndIfElse |
| |
| }//Endif |
| //-- Validate LCS Burn Request |
| #endif //CLOSE_JTAG |
| if ((pActiveFuseData->BurnRequest & K_PLAT_VERSION_BURN_REQUEST_MASK) != 0 ) |
| { |
| //Compare Burned Security with Saved Security Config Bits |
| temp[0] = GEU_ReadSoftwareVersion(); |
| // Ignore status - whatever we read, we read |
| status = _geu_compare(&pActiveFuseData->SoftwareVersionSave[0], |
| &temp[0], |
| K_PLAT_VERSION_FUSE_SIZE); |
| if (status == 0) |
| { |
| pActiveFuseData->BurnRequest &= ~K_PLAT_VERSION_BURN_REQUEST_MASK; |
| } |
| else |
| { |
| if (pActiveFuseData->BurnCount >= 2) |
| { |
| // LCS Burn Failed two times - Clear the burn Request |
| pActiveFuseData->BurnRequest &= ~K_PLAT_VERSION_BURN_REQUEST_MASK; |
| // Set the Raw Burn Status to indicate Failure |
| pFuseBurnStatus->RawBurnStatus |= K_PLAT_VERSION_BURN_REQUEST_MASK; |
| } |
| }//EndIfElse |
| }//Endif |
| } |
| // Set status |
| pFuseBurnStatus->CorrectedBurnStatus = pFuseBurnStatus->RawBurnStatus; |
| if(pFuseBurnStatus->CorrectedBurnStatus != 0) |
| { |
| pFuseBurnStatus->FinalBurnStatus = FUSE_BurnError; |
| } |
| return(_geuUpdateUserFuseBurnStatus(pUserFuseBurnStatus, pFuseBurnStatus)); |
| }//End Routine GEU_BurnFuseBlock_SocConfig |
| |
| #if ENABLE_BITS_BURN |
| UINT_T GEU_FuseBankBitBurn(UINT_T BankNum, UINT_T StartBit, UINT_T BitCouts) |
| { |
| UINT_T result; |
| UINT_T status; |
| UINT_T BurnBuffer[8]; |
| UINT_T ReadBuffer[8]; |
| |
| if (((StartBit + BitCouts) > 256) || (StartBit > 255) || (BitCouts == 0)) { |
| return FUSE_InvalidFuseBlockField; |
| } |
| |
| /* make sure power supply required for fuse programming is enabled */ |
| result = GEU_EnableFuseBurnPower(); |
| if (result != NoError) { |
| return FUSE_FuseBurnPowerNotEnabled; |
| } |
| |
| result = GEU_SetActiveFuseBlock(BankNum); |
| if (result != NoError) { |
| return result; |
| } |
| |
| memset(BurnBuffer, 0, sizeof(BurnBuffer)); |
| |
| /* setup burn bits */ |
| for (UINT_T i = StartBit; i < (StartBit + BitCouts); i++) { |
| BurnBuffer[i/32] |= (1 << (i%32)); |
| } |
| |
| for (UINT_T i = 0; i < 8; i++) { |
| GEU_REG_WRITE(GEU_FUSE_PROG_VAL1 + i*4, BurnBuffer[i]); |
| } |
| |
| /* burn bits */ |
| status = _geuBurnFuse(BankNum, 0); |
| if (status != 0) { |
| return FUSE_BurnError; |
| } |
| |
| /* compare whether the burn is correct */ |
| memset(ReadBuffer, 0, sizeof(ReadBuffer)); |
| GEU_ReadFuseBank(ReadBuffer, BankNum); |
| for (UINT_T i = 0; i < 8; i++) { |
| if ((BurnBuffer[i] & ReadBuffer[i]) != BurnBuffer[i]) { |
| status = FUSE_BurnError; |
| break; |
| } |
| } |
| |
| if (status == FUSE_BurnError) { |
| /* second burn bits */ |
| status = _geuBurnFuse(BankNum, 0); |
| if (status != 0) { |
| return FUSE_BurnError; |
| } |
| |
| /* compare whether the second burn is correct */ |
| memset(ReadBuffer, 0, sizeof(ReadBuffer)); |
| GEU_ReadFuseBank(ReadBuffer, BankNum); |
| for (UINT_T i = 0; i < 8; i++) { |
| if ((BurnBuffer[i] & ReadBuffer[i]) != BurnBuffer[i]) { |
| return FUSE_BurnError; |
| } |
| } |
| } |
| |
| return NoError; |
| } |
| #endif |