| #include <Typedef.h> | |
| #include <predefines.h> | |
| #include <Errors.h> | |
| #include "GEU.h" | |
| #include "GEU_FuseReadMethods.h" | |
| #include "GEU_Provisioning.h" | |
| extern INT_T PlatformIsNezhac(void); | |
| // returns number of ones set in value | |
| UINT_T countOnes(UINT_T value) | |
| { | |
| UINT_T i=0; | |
| for(i=0;value;i++) | |
| value &=(value-1); | |
| return i; | |
| } | |
| UINT_T GEU_ReadApCpConfigFuseBits(UINT_T* pBuffer, UINT_T Size) | |
| { | |
| UINT_T temp[3]; | |
| if (Size < K_APCP_CONFIG_FUSE_SIZE) | |
| { | |
| return (FUSE_BufferTooSmall); | |
| } | |
| GEU_REG_READ(GEU_FUSE_VAL_APCFG1, temp[0]); | |
| GEU_REG_READ(GEU_FUSE_VAL_APCFG2, temp[1]); | |
| GEU_REG_READ(GEU_FUSE_VAL_APCFG3, temp[2]); | |
| //CP config[15:0] | |
| pBuffer[0] = (temp[2] >> 16) & 0xFFFF; | |
| //AP config[15:0] | |
| pBuffer[0] |= (temp[0] & 0xFFFF) << 16; | |
| //AP config[31:16] | |
| pBuffer[1] = (temp[0] >> 16)& 0xFFFF; | |
| //AP config[47:32] | |
| pBuffer[1] = (temp[1] & 0xFFFF)<< 16; | |
| //AP config[63:48] | |
| pBuffer[2] = (temp[1] >> 16)& 0xFFFF; | |
| //AP config[79:64] | |
| pBuffer[2] = (temp[2] & 0xFFFF)<< 16; | |
| return NoError; | |
| }; | |
| UINT_T GEU_ReadApConfigFuseBits(UINT_T* pBuffer, UINT_T Size) | |
| { | |
| UINT_T temp[3]; | |
| if (Size < K_AP_CONFIG_FUSE_SIZE) | |
| { | |
| return (FUSE_BufferTooSmall); | |
| } | |
| GEU_REG_READ(GEU_FUSE_VAL_APCFG1, temp[0]); | |
| GEU_REG_READ(GEU_FUSE_VAL_APCFG2, temp[1]); | |
| GEU_REG_READ(GEU_FUSE_VAL_APCFG3, temp[2]); | |
| //AP config[31:0] | |
| pBuffer[0] = temp[0]; | |
| //AP config[63:32] | |
| pBuffer[1] = temp[1]; | |
| //AP config[79:64] | |
| pBuffer[2] = temp[2] & 0xFFFF; | |
| return NoError; | |
| }; | |
| UINT_T GEU_ReadCpConfigFuseBits(UINT_T* pBuffer, UINT_T Size) | |
| { | |
| UINT_T temp; | |
| if (Size < K_CP_CONFIG_FUSE_SIZE) | |
| { | |
| return (FUSE_BufferTooSmall); | |
| } | |
| GEU_REG_READ(GEU_FUSE_VAL_APCFG3, temp); | |
| //CP config[15:0] | |
| pBuffer[0] = (temp >> 16) & 0xFFFF; | |
| return NoError; | |
| }; | |
| UINT_T GEU_ReadOemHashKeyFuseBits(UINT_T* pBuffer, UINT_T Size) | |
| { | |
| if (!((Size == K_SHA1_SIZE)||(Size == K_SHA256_SIZE))) | |
| { | |
| return (FUSE_InvalidBufferSize); | |
| } | |
| // return 20 bytes regardless of size | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_HASH_KEY+0, pBuffer[0]); | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_HASH_KEY+4, pBuffer[1]); | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_HASH_KEY+8, pBuffer[2]); | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_HASH_KEY+12, pBuffer[3]); | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_HASH_KEY+16, pBuffer[4]); | |
| if (Size == K_SHA256_SIZE) //32 | |
| { | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_HASH_KEY+20, pBuffer[5]); | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_HASH_KEY+24, pBuffer[6]); | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_HASH_KEY+28, pBuffer[7]); | |
| } | |
| return NoError; | |
| }; | |
| UINT_T GEU_ReadRkekFuseBits(UINT_T* pBuffer, UINT_T Size) | |
| { | |
| if (Size != K_FUSEBLOCK_SIZE) | |
| { | |
| return (FUSE_InvalidBufferSize); | |
| } | |
| // return 20 bytes regardless of size | |
| GEU_REG_READ(GEU_FUSE_VAL_ROOT_KEY1+0, pBuffer[0]); | |
| GEU_REG_READ(GEU_FUSE_VAL_ROOT_KEY1+4, pBuffer[1]); | |
| GEU_REG_READ(GEU_FUSE_VAL_ROOT_KEY1+8, pBuffer[2]); | |
| GEU_REG_READ(GEU_FUSE_VAL_ROOT_KEY1+12, pBuffer[3]); | |
| GEU_REG_READ(GEU_FUSE_VAL_ROOT_KEY1+16, pBuffer[4]); | |
| GEU_REG_READ(GEU_FUSE_VAL_ROOT_KEY1+20, pBuffer[5]); | |
| GEU_REG_READ(GEU_FUSE_VAL_ROOT_KEY1+24, pBuffer[6]); | |
| GEU_REG_READ(GEU_FUSE_VAL_ROOT_KEY1+28, pBuffer[7]); | |
| return NoError; | |
| }; | |
| UINT_T GEU_ReadUsbIdFuseBits(UINT_T* pBuffer, UINT_T Size) | |
| { | |
| if (Size != K_USBID_FUSE_SIZE) | |
| { | |
| return (FUSE_InvalidBufferSize); | |
| } | |
| // Bootrom only supports 32 bits so only read one register (32 bts of ID). | |
| GEU_REG_READ(GEU_FUSE_VAL_USB_VER_ID, pBuffer[0]); | |
| return NoError; | |
| }; | |
| /************************************ | |
| * Returns current Lifecycle | |
| ************************************/ | |
| UINT_T GEU_ReadLifeCycle() | |
| { | |
| UINT_T regValue, lifeCycleCount = 0; | |
| GEU_REG_READ(GEU_FUSE_VAL_LIFECYCLE_LCS, regValue); | |
| // Check CM | |
| //lifeCycleCount += countOnes((regValue & GEU_FUSE_VAL_LIFECYCLE_CM_MSK) >> GEU_FUSE_VAL_LIFECYCLE_CM_BASE); | |
| lifeCycleCount += PHYSICAL_TO_LOGICAL((regValue & GEU_FUSE_VAL_LIFECYCLE_CM_MSK) >> GEU_FUSE_VAL_LIFECYCLE_CM_BASE); | |
| // Check DM | |
| lifeCycleCount += PHYSICAL_TO_LOGICAL((regValue & GEU_FUSE_VAL_LIFECYCLE_DM_MSK) >> GEU_FUSE_VAL_LIFECYCLE_DM_BASE); | |
| // Check DD | |
| lifeCycleCount += PHYSICAL_TO_LOGICAL((regValue & GEU_FUSE_VAL_LIFECYCLE_DD_MSK) >> GEU_FUSE_VAL_LIFECYCLE_DD_BASE); | |
| // Check FA | |
| lifeCycleCount += PHYSICAL_TO_LOGICAL((regValue & GEU_FUSE_VAL_LIFECYCLE_FA_MSK) >> GEU_FUSE_VAL_LIFECYCLE_FA_BASE); | |
| // Check JPD | |
| lifeCycleCount += PHYSICAL_TO_LOGICAL((regValue & GEU_FUSE_VAL_LIFECYCLE_PD_MSK) >> GEU_FUSE_VAL_LIFECYCLE_PD_BASE); | |
| return lifeCycleCount; | |
| } | |
| UINT_T GEU_ReadLifeCycleState() | |
| { | |
| UINT_T lcs; | |
| GEU_REG_READ(GEU_FUSE_VAL_LIFECYCLE_LCS, lcs); | |
| lcs &= 0xFFFF; | |
| return lcs; | |
| } | |
| INT_T GEU_LifeCycleIsDD(void) | |
| { | |
| UINT_T lcs; | |
| lcs = GEU_ReadLifeCycleState(); | |
| lcs = PHYSICAL_TO_LOGICAL((lcs & GEU_FUSE_VAL_LIFECYCLE_DD_MSK) >> GEU_FUSE_VAL_LIFECYCLE_DD_BASE); | |
| return lcs; | |
| } | |
| UINT_T GEU_ReadOemUidFuseBits(UINT_T* pBuffer, UINT_T Size) | |
| { | |
| UINT_T scratch; | |
| if (Size != K_OEM_UNIQUE_ID_FUSE_SIZE) | |
| { | |
| return (FUSE_InvalidBufferSize); | |
| } | |
| #if NZAC || LAPW | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_UID_L, pBuffer[0]); | |
| GEU_REG_READ(GEU_FUSE_VAL_OEM_UID_H, pBuffer[1]); | |
| #else | |
| GEU_REG_READ(ASR1803GEU_FUSE_VAL_OEM_UID_L, pBuffer[0]); | |
| GEU_REG_READ(ASR1803GEU_FUSE_VAL_OEM_UID_H, pBuffer[1]); | |
| #endif | |
| return NoError; | |
| }; | |
| UINT_T GEU_JtagFuseDisabled(VOID) | |
| { | |
| UINT_T value; | |
| GEU_ReadCpConfigFuseBits(&value, K_CP_CONFIG_FUSE_SIZE); | |
| if((value & BIT_14) && GEU_LifeCycleIsDD()) | |
| return 1; | |
| return 0; | |
| } | |
| UINT_T GEU_ForceDownloadFuseDisabled(VOID) | |
| { | |
| UINT_T value; | |
| GEU_REG_READ(GEU_FUSE_VAL_APCFG3, value); | |
| if(value & BIT_13) | |
| return 1; | |
| return 0; | |
| } | |
| UINT_T GEU_RomLogDisabled(VOID) | |
| { | |
| UINT_T value; | |
| GEU_REG_READ(GEU_FUSE_VAL_APCFG3, value); | |
| if(value & BIT_3) | |
| return 1; | |
| return 0; | |
| } | |
| UINT_T GEU_ReadSoftwareVersion(VOID) | |
| { | |
| UINT_T value; | |
| GEU_REG_READ(GEU_FUSE_BANK0_239_208, value); | |
| return value; | |
| } | |
| INT GEU_MajorAntiRollBackEnabled(VOID) | |
| { | |
| UINT_T value = GEU_ReadSoftwareVersion(); | |
| return (value & 1); | |
| } | |
| INT_T GEU_ReadMajorVersion(VOID) | |
| { | |
| INT_T i, ones = 0; | |
| UINT_T value = GEU_ReadSoftwareVersion(); | |
| for(i = 0; i < 32; i++) | |
| { | |
| if(value & (1 << i)) | |
| ones++; | |
| } | |
| return (ones - 1); /* -1 means no major version burned */ | |
| } | |
| UINT_T GEU_ReadRNG(UINT_T *Data, UINT_T Len) | |
| { | |
| UINT_T RngCtrl; | |
| UINT_T UID[2]; | |
| UINT_T Val; | |
| GEU_ReadOemUidFuseBits(UID, K_OEM_UNIQUE_ID_FUSE_SIZE); | |
| GEU_REG_READ(GEU_RNG_CTRL, RngCtrl); | |
| if (!(RngCtrl & (1 << 24) )) { | |
| RngCtrl |= (1 << 24); | |
| GEU_REG_WRITE(GEU_RNG_CTRL, RngCtrl); | |
| /* Use UID as seed */ | |
| if (UID[0] == 0 && UID[1] == 0) | |
| obm_printf("Warning: UID is 0 and used as seed\n\r"); | |
| GEU_REG_WRITE(GEU_RNG_SEED_LO, UID[0]); | |
| GEU_REG_WRITE(GEU_RNG_SEED_HI, UID[1]); | |
| Delay(100); /* 70us is enough, set as 100us */ | |
| } | |
| while (Len) { | |
| Delay(5); /* enough delay to get a new rng */ | |
| GEU_REG_READ(GEU_HW_RANDOM_NUM_GEN, Val); | |
| if (Len < 4) { | |
| memcpy(Data, &Val, Len); | |
| break; | |
| } else { | |
| *Data++ = Val; | |
| Len -= 4; | |
| } | |
| } | |
| } | |
| INT GEU_RkekAccessDisabled(VOID) | |
| { | |
| UINT_T Val; | |
| GEU_REG_READ(GEU_FUSE_VAL_APCFG2, Val); | |
| if(Val & (1 << 29)) | |
| return 1; | |
| return 0; | |
| } | |
| INT GEU_RkekIsBurned(VOID) | |
| { | |
| INT_T i; | |
| UINT_T RKEK[8]; | |
| if (GEU_RkekAccessDisabled()) | |
| return 1; | |
| GEU_ReadRkekFuseBits(RKEK, K_FUSEBLOCK_SIZE); | |
| for (i = 0; i < 8; i++) { | |
| if(RKEK[i] != 0) | |
| return 1; | |
| } | |
| return 0; | |
| } | |
| UINT_T GEU_ReadFuseBank(UINT_T *pBuffer, UINT_T BankNum) | |
| { | |
| UINT_T Val1, Val2, Val3; | |
| switch(BankNum) | |
| { | |
| case 0: | |
| GEU_REG_READ(GEU_FUSE_VAL_APCFG1, Val1); | |
| GEU_REG_READ(GEU_FUSE_VAL_APCFG2, Val2); | |
| GEU_REG_READ(GEU_FUSE_VAL_APCFG3, Val3); | |
| pBuffer[0] = (Val3 >> 16) | (Val1 << 16); | |
| pBuffer[1] = (Val1 >> 16) | (Val2 << 16); | |
| pBuffer[2] = (Val2 >> 16) | (Val3 << 16); | |
| GEU_REG_READ(GEU_FUSE_BANK0_127_96, pBuffer[3]); | |
| GEU_REG_READ(ASR1803GEU_FUSE_VAL_OEM_UID_L, pBuffer[4]); | |
| GEU_REG_READ(ASR1803GEU_FUSE_VAL_OEM_UID_H, pBuffer[5]); | |
| GEU_REG_READ(GEU_FUSE_BANK0_239_208, Val1); | |
| GEU_REG_READ(GEU_FUSE_BANK0_207_192, Val2); | |
| GEU_REG_READ(GEU_FUSE_BANK0_255_240, Val3); | |
| pBuffer[6] = (Val1 << 16) | (Val2 & 0xFFFF); | |
| pBuffer[7] = (Val3 << 16) | (Val1 >> 16); | |
| break; | |
| case 1: | |
| for(int i = 0; i < 8; i++) | |
| GEU_REG_READ((GEU_FUSE_VAL_ROOT_KEY1 + (i * 4)), pBuffer[i]); | |
| break; | |
| case 2: | |
| for(int i = 0; i < 8; i++) | |
| GEU_REG_READ((GEU_FUSE_VAL_OEM_HASH_KEY + (i * 4)), pBuffer[i]); | |
| break; | |
| case 3: | |
| for(int i = 0; i < 6; i++) | |
| GEU_REG_READ((GEU_FUSE_BANK3_RESERVED + (i * 4)), pBuffer[i]); | |
| GEU_REG_READ(GEU_FUSE_BANK3_223_192, pBuffer[6]); | |
| GEU_REG_READ(GEU_FUSE_BANK3_255_224, pBuffer[7]); | |
| break; | |
| default: | |
| break; | |
| } | |
| return NoError; | |
| } | |
| #ifdef FUSE_TEST | |
| UINT_T GEU_RegisterDump(void) | |
| { | |
| GEU_UARTLOG("GEU_STATUS: 0x%x\n\r", GEU_REG(GEU_STATUS)); | |
| GEU_UARTLOG("GEU_CONFIG: 0x%x\n\r", GEU_REG(GEU_CONFIG)); | |
| GEU_UARTLOG("GEU_FUSE_STATUS: 0x%x\n\r", GEU_REG(GEU_FUSE_STATUS)); | |
| GEU_UARTLOG("GEU_FUSE_PROG_VAL1: 0x%x\n\r", GEU_REG(GEU_FUSE_PROG_VAL1 + 0)); | |
| GEU_UARTLOG("GEU_FUSE_PROG_VAL2: 0x%x\n\r", GEU_REG(GEU_FUSE_PROG_VAL1 + 4)); | |
| GEU_UARTLOG("GEU_FUSE_PROG_VAL3: 0x%x\n\r", GEU_REG(GEU_FUSE_PROG_VAL1 + 8)); | |
| GEU_UARTLOG("GEU_FUSE_PROG_VAL4: 0x%x\n\r", GEU_REG(GEU_FUSE_PROG_VAL1 + 12)); | |
| GEU_UARTLOG("GEU_FUSE_PROG_VAL5: 0x%x\n\r", GEU_REG(GEU_FUSE_PROG_VAL1 + 16)); | |
| GEU_UARTLOG("GEU_FUSE_PROG_VAL6: 0x%x\n\r", GEU_REG(GEU_FUSE_PROG_VAL1 + 20)); | |
| GEU_UARTLOG("GEU_FUSE_PROG_VAL7: 0x%x\n\r", GEU_REG(GEU_FUSE_PROG_VAL1 + 24)); | |
| GEU_UARTLOG("GEU_FUSE_PROG_VAL8: 0x%x\n\r", GEU_REG(GEU_FUSE_PROG_VAL1 + 28)); | |
| } | |
| UINT_T GEU_BankDump(UINT_T BankNum) | |
| { | |
| UINT_T pBuffer[8]; | |
| GEU_ReadFuseBank(pBuffer, BankNum); | |
| GEU_UARTLOG("Fuse bank values:%d\n\r", BankNum); | |
| for(int i = 7; i >= 0; i--) | |
| { | |
| GEU_UARTLOG("%08x ", pBuffer[i]); | |
| } | |
| GEU_UARTLOG("\n\r"); | |
| } | |
| UINT_T GEU_FuseBankBurnTest(UINT_T *pBuffer, UINT_T BankNum) | |
| { | |
| INT_T i, status; | |
| UINT_T pReadBuffer[8]; | |
| UINT_T pExpectBuffer[8]; | |
| GEU_EnableFuseBurnPower(); | |
| GEU_ReadFuseBank(pReadBuffer, BankNum); | |
| GEU_UARTLOG("Initial Value of bank%d\n\r", BankNum); | |
| for(i = 7; i >= 0; i--) | |
| GEU_UARTLOG("%08x ", pReadBuffer[i]); | |
| GEU_UARTLOG("\n\r"); | |
| for(i = 0; i < 8; i++) | |
| pExpectBuffer[i] = pBuffer[i] | pReadBuffer[i]; | |
| GEU_UARTLOG("Expected Value of bank%d\n\r", BankNum); | |
| for(i = 7; i >= 0; i--) | |
| GEU_UARTLOG("%08x ", pExpectBuffer[i]); | |
| GEU_UARTLOG("\n\r"); | |
| for(i = 0; i < 8; i++) | |
| { | |
| GEU_REG(GEU_FUSE_PROG_VAL1 + i*4) = pBuffer[i]; | |
| } | |
| _geuBurnFuse(BankNum, 0); | |
| GEU_ReadFuseBank(pReadBuffer, BankNum); | |
| GEU_UARTLOG("First Burn read back Value of bank%d\n\r", BankNum); | |
| for(i = 7; i >= 0; i--) | |
| GEU_UARTLOG("%08x ", pReadBuffer[i]); | |
| GEU_UARTLOG("\n\r"); | |
| status = _geu_compare(pReadBuffer, pExpectBuffer, 32); | |
| if(status != NoError) | |
| { | |
| GEU_UARTLOG("First Burning fails for bank%d\n\r", BankNum); | |
| GEU_UARTLOG("Try again\n\r"); | |
| _geuBurnFuse(BankNum, 0); | |
| GEU_ReadFuseBank(pReadBuffer, BankNum); | |
| GEU_UARTLOG("First Burn read back Value of bank%d\n\r", BankNum); | |
| for(i = 7; i >= 0; i--) | |
| GEU_UARTLOG("%08x ", pReadBuffer[i]); | |
| GEU_UARTLOG("\n\r"); | |
| status = _geu_compare(pReadBuffer, pExpectBuffer, 32); | |
| if(status != NoError){ | |
| GEU_UARTLOG("Second Burning fails for bank%d\n\r", BankNum); | |
| return FUSE_BurnError; | |
| } else { | |
| GEU_UARTLOG("Second Burning pass for bank%d\n\r", BankNum); | |
| } | |
| } else { | |
| GEU_UARTLOG("First Burning pass for bank%d\n\r", BankNum); | |
| return NoError; | |
| } | |
| } | |
| #endif |