
Added initial support Xilinx Embedded Software. Signed-off-by: Jagannadha Sutradharudu Teki <jaganna@xilinx.com>
1522 lines
42 KiB
C
Executable file
1522 lines
42 KiB
C
Executable file
/******************************************************************************
|
|
*
|
|
* Copyright (C) 2013 - 2014 Xilinx, Inc. All rights reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* Use of the Software is limited solely to applications:
|
|
* (a) running on a Xilinx device, or
|
|
* (b) that interact with a Xilinx device through a bus or interconnect.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
|
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
* Except as contained in this notice, the name of the Xilinx shall not be used
|
|
* in advertising or otherwise to promote the sale, use or other dealings in
|
|
* this Software without prior written authorization from Xilinx.
|
|
*
|
|
******************************************************************************/
|
|
/*****************************************************************************/
|
|
/**
|
|
* @file xilskey_eps.c
|
|
* This file contains the PS eFUSE API's to program/read the eFUSE array.
|
|
*
|
|
* @note None.
|
|
*
|
|
*
|
|
* MODIFICATION HISTORY:
|
|
*
|
|
* Ver Who Date Changes
|
|
* ----- ---- -------- --------------------------------------------------------
|
|
* 1.00a rpoolla 04/26/13 First release
|
|
* 1.02a hk 10/28/13 Added API to read status register.PR# 735957
|
|
* 2.00 hk 23/01/14 Changed PS efuse error codes for voltage out of range.
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
|
|
/***************************** Include Files *********************************/
|
|
#include "xil_io.h"
|
|
#include "xil_types.h"
|
|
#include "xstatus.h"
|
|
#include "xilskey_utils.h"
|
|
#include "xilskey_epshw.h"
|
|
#include "xilskey_eps.h"
|
|
/************************** Constant Definitions *****************************/
|
|
|
|
/**************************** Type Definitions ******************************/
|
|
|
|
/***************** Macros (Inline Functions) Definitions ********************/
|
|
|
|
/************************** Variable Definitions ****************************/
|
|
u8 Matrix[31][5]; /**< PS eFUSE Matrix*/
|
|
u8 ErrorCodeIndex[32]; /**< Error Code Array */
|
|
/************************** Function Prototypes *****************************/
|
|
static u32 XilSKey_EfusePs_WriteWithXadcCheckAndVerify(u32 EfuseAddress, u32 RefClk);
|
|
static u32 XilSKey_EfusePs_WriteRsaKeyHash(u8 *RsaKeyHashBuf, u32 RefClk);
|
|
static u32 XilSKey_EfusePs_ReadRsaKeyHash(u8 *RsaKeyHashBuf, u32 RefClk);
|
|
static u32 XilSKey_EfusePs_ReadWithXadcCheck(u32 EfuseAddress, u32 RefClk, u8 *Data);
|
|
static u32 XilSKey_EfusePs_VerifyWithXadcCheck(u32 EfuseAddress, u32 RefClk);
|
|
static u32 XilSKey_EfusePs_CheckRsaHashForAllZeros(u32 RefClk);
|
|
static void XilSKey_EfusePs_SetControllerMode (u8 Mode);
|
|
static void XilSKey_EfusePs_SetControllerReadMode (u8 ReadMode);
|
|
static u8 XilSKey_EfusePs_IsReadModeSupported (u8 ReadMode);
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* This function is used to write to the PS eFUSE.
|
|
*
|
|
* @param InstancePtr is the pointer to the PsEfuseHandle which describes
|
|
* which PS eFUSE bit should be burned.
|
|
*
|
|
* @return
|
|
* - XST_SUCCESS.
|
|
* - Incase of error, value is as defined in xeFUSE_error.h.
|
|
* Error value is a combination of Upper 8 bit value and
|
|
* Lower 8 bit value. For example, 0x8A03 should be checked
|
|
* in error.h as 0x8A00 and 0x03. Upper 8 bit value signifies
|
|
* the major error and lower 8 bit values tells more precisely.
|
|
*
|
|
****************************************************************************/
|
|
u32 XilSKey_EfusePs_Write(XilSKey_EPs *InstancePtr)
|
|
{
|
|
u32 Status, StatusRedundantBit, RetValue;
|
|
u32 RefClk;
|
|
u32 ArmPllFDiv,ArmClkDivisor;
|
|
|
|
RetValue = XST_SUCCESS;
|
|
|
|
|
|
if (NULL == InstancePtr) {
|
|
return XSK_EFUSEPS_ERROR_PS_STRUCT_NULL;
|
|
}
|
|
|
|
/**
|
|
* Extract PLL FDIV value from ARM PLL Control Register
|
|
*/
|
|
ArmPllFDiv = (Xil_In32(XSK_ARM_PLL_CTRL_REG)>>12 & 0x7F);
|
|
/**
|
|
* Extract Clock divisor value from ARM Clock Control Register
|
|
*/
|
|
ArmClkDivisor = (Xil_In32(XSK_ARM_CLK_CTRL_REG)>>8 & 0x3F);
|
|
|
|
/**
|
|
* Initialize the variables
|
|
*/
|
|
RefClk = ((XPAR_PS7_CORTEXA9_0_CPU_CLK_FREQ_HZ * ArmClkDivisor)/
|
|
ArmPllFDiv);
|
|
|
|
/**
|
|
* Check the variables
|
|
*/
|
|
|
|
if (((InstancePtr->EnableWriteProtect != TRUE) &&
|
|
(InstancePtr->EnableWriteProtect != FALSE)) ||
|
|
((InstancePtr->EnableRsaAuth != TRUE) &&
|
|
(InstancePtr->EnableRsaAuth != FALSE)) ||
|
|
((InstancePtr->EnableRom128Crc != TRUE) &&
|
|
(InstancePtr->EnableRom128Crc != FALSE)) ||
|
|
((InstancePtr->EnableRsaKeyHash != TRUE) &&
|
|
(InstancePtr->EnableRsaKeyHash != FALSE)) ) {
|
|
return XSK_EFUSEPS_ERROR_PS_PARAMETER_WRONG;
|
|
}
|
|
|
|
/**
|
|
* XAdc Initialization
|
|
*/
|
|
Status = XilSKey_EfusePs_XAdcInit();
|
|
if (Status != XST_SUCCESS) {
|
|
RetValue = XSK_EFUSEPS_ERROR_XADC_INIT;
|
|
goto ExitFinal;
|
|
}
|
|
|
|
xeFUSE_printf(XSK_EFUSE_DEBUG_GENERAL,"Writing PS EFUSE \n");
|
|
/**
|
|
* Unlock the eFUSE controller
|
|
*/
|
|
XSK_EFUSEPS_CONTROLER_UNLOCK();
|
|
|
|
/**
|
|
* Check if the controller is unlocked
|
|
*/
|
|
if (XSK_EFUSEPS_CONTROLER_LOCK_STATUS() == TRUE) {
|
|
RetValue = XSK_EFUSEPS_ERROR_CONTROLLER_LOCK;
|
|
goto ExitFinal;
|
|
}
|
|
|
|
/**
|
|
* If eFUSE Array is write protected
|
|
* no more writes are possible
|
|
*/
|
|
|
|
if (XilSKey_EfusePs_IsEfuseWriteProtected() == TRUE) {
|
|
RetValue = XSK_EFUSEPS_ERROR_EFUSE_WRITE_PROTECTED;
|
|
goto ExitCtrlLock;
|
|
}
|
|
|
|
/**
|
|
* Configure the eFUSE controller with mode, strobe width values.
|
|
*/
|
|
Status = XilSKey_EfusePs_ControllerConfig(XSK_EFUSEPS_SINGLE_MODE,
|
|
RefClk, XSK_EFUSEPS_READ_MODE_NORMAL);
|
|
if (Status != XST_SUCCESS) {
|
|
RetValue = XSK_EFUSEPS_ERROR_CONTROLLER_CONFIG + Status;
|
|
goto ExitCtrlResetStatus;
|
|
}
|
|
|
|
/**
|
|
* Enable Programming, write and read
|
|
*/
|
|
XilSKey_EfusePs_ControllerSetReadWriteEnable(XSK_EFUSEPS_ENABLE_PROGRAMMING |
|
|
XSK_EFUSEPS_ENABLE_READ | XSK_EFUSEPS_ENABLE_WRITE);
|
|
|
|
/**
|
|
* Initialize the timer for delay while programming the eFUSE
|
|
*/
|
|
XilSKey_Efuse_StartTimer(RefClk);
|
|
|
|
/**
|
|
* Program the eFUSE based
|
|
* on the structure values
|
|
*/
|
|
|
|
/**
|
|
* Program the eFUSE bit 0xA to enable
|
|
* ROM 128K CRC
|
|
*/
|
|
if (InstancePtr->EnableRom128Crc) {
|
|
Status = XilSKey_EfusePs_WriteWithXadcCheckAndVerify(
|
|
XSK_EFUSEPS_APB_ROM_128K_CRC_ENABLE, RefClk);
|
|
if (Status != XST_SUCCESS) {
|
|
RetValue = XSK_EFUSEPS_ERROR_WRITE_128K_CRC_BIT + Status;
|
|
goto ExitCtrlResetStatus;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Program the RSA key Hash value in eFUSE Array \
|
|
*/
|
|
if (InstancePtr->EnableRsaKeyHash) {
|
|
/**
|
|
* Check if all the hash eFUSE bits are zero or not
|
|
*/
|
|
/* NEW: Changed the ReadRsaKeyHash to new function
|
|
* XilSKey_EfusePs_CheckRsaHashForAllZeros because of 2 bugs
|
|
* 1. If we are using ReadRsaKeyHash function here, if only 1 bit is
|
|
* written it will correct it and allow to write
|
|
* 2. Controller is in SINGLE mode, so even if 2nd half is written
|
|
* we will continue to write
|
|
* */
|
|
Status = XilSKey_EfusePs_CheckRsaHashForAllZeros(RefClk);
|
|
if (Status != XST_SUCCESS) {
|
|
|
|
RetValue = XSK_EFUSEPS_ERROR_READ_HASH_BEFORE_PROGRAMMING + Status;
|
|
goto ExitCtrlResetStatus;
|
|
}
|
|
|
|
/**
|
|
* Program the RSA hash
|
|
*/
|
|
Status = XilSKey_EfusePs_WriteRsaKeyHash(
|
|
InstancePtr->RsaKeyHashValue, RefClk);
|
|
if (Status != XST_SUCCESS) {
|
|
RetValue = XSK_EFUSEPS_ERROR_WRITE_RSA_HASH + Status;
|
|
goto ExitCtrlResetStatus;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Program the eFUSE bit 0xB to enable
|
|
* RSA authentication
|
|
*/
|
|
if (InstancePtr->EnableRsaAuth) {
|
|
Status = XilSKey_EfusePs_WriteWithXadcCheckAndVerify(
|
|
XSK_EFUSEPS_APB_RSA_AUTH_ENABLE, RefClk);
|
|
if (Status != XST_SUCCESS) {
|
|
RetValue = XSK_EFUSEPS_ERROR_WRITE_RSA_AUTH_BIT + Status;
|
|
goto ExitCtrlResetStatus;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Program the eFUSE bit 0x8,0x9 to enable
|
|
* eFUSE Array Write Protection
|
|
*
|
|
* Once enabled the write protection, we will not be
|
|
* able to program any PS eFUSE afterwards
|
|
*/
|
|
|
|
/**
|
|
* SLCR reset is required for write protect
|
|
* to take into effect
|
|
*/
|
|
if (InstancePtr->EnableWriteProtect) {
|
|
Status = XilSKey_EfusePs_WriteWithXadcCheckAndVerify(
|
|
XSK_EFUSEPS_APB_WRITE_PROTECTION_ADDR_1, RefClk);
|
|
|
|
StatusRedundantBit = XilSKey_EfusePs_WriteWithXadcCheckAndVerify(
|
|
XSK_EFUSEPS_APB_WRITE_PROTECTION_ADDR_2, RefClk);
|
|
|
|
|
|
/* NEW: Error only if burning of the both the bits are not success */
|
|
if ((Status != XST_SUCCESS) && (StatusRedundantBit != XST_SUCCESS)) {
|
|
RetValue = XSK_EFUSEPS_ERROR_WRITE_WRITE_PROTECT_BIT + Status;
|
|
goto ExitCtrlResetStatus;
|
|
}
|
|
}
|
|
|
|
ExitCtrlResetStatus:
|
|
/**
|
|
* Disable Programming, write and read
|
|
*/
|
|
XilSKey_EfusePs_ControllerSetReadWriteEnable(0);
|
|
|
|
ExitCtrlLock:
|
|
/**
|
|
* Lock the eFUSE controller
|
|
*/
|
|
XSK_EFUSEPS_CONTROLER_LOCK();
|
|
|
|
ExitFinal:
|
|
return RetValue;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* This function is used to read the PS eFUSE.
|
|
*
|
|
* @param InstancePtr is the pointer to the PsEfuseHandle which describes
|
|
* which PS eFUSE should be burned.
|
|
*
|
|
* @return
|
|
* - XST_SUCCESS no errors occured.
|
|
* - Incase of error, value is as defined in xeFUSE_error.h.
|
|
* Error value is a combination of Upper 8 bit value and
|
|
* Lower 8 bit value. For example, 0x8A03 should be checked
|
|
* in error.h as 0x8A00 and 0x03. Upper 8 bit value signifies
|
|
* the major error and lower 8 bit values tells more precisely.
|
|
*
|
|
****************************************************************************/
|
|
u32 XilSKey_EfusePs_Read(XilSKey_EPs *InstancePtr)
|
|
{
|
|
|
|
u32 Status, RetValue;
|
|
u32 RefClk;
|
|
u32 ArmPllFDiv,ArmClkDivisor;
|
|
|
|
RetValue = XST_SUCCESS;
|
|
|
|
|
|
if (NULL == InstancePtr) {
|
|
return XSK_EFUSEPS_ERROR_PS_STRUCT_NULL;
|
|
}
|
|
|
|
/**
|
|
* Extract PLL FDIV value from ARM PLL Control Register
|
|
*/
|
|
ArmPllFDiv = (Xil_In32(XSK_ARM_PLL_CTRL_REG)>>12 & 0x7F);
|
|
/**
|
|
* Extract Clock divisor value from ARM Clock Control Register
|
|
*/
|
|
ArmClkDivisor = (Xil_In32(XSK_ARM_CLK_CTRL_REG)>>8 & 0x3F);
|
|
|
|
/**
|
|
* Initialize the variables
|
|
*/
|
|
RefClk = ((XPAR_PS7_CORTEXA9_0_CPU_CLK_FREQ_HZ * ArmClkDivisor)/
|
|
ArmPllFDiv);
|
|
|
|
/**
|
|
* Check the variables
|
|
*/
|
|
|
|
if ((InstancePtr->EnableRsaKeyHash != TRUE) &&
|
|
(InstancePtr->EnableRsaKeyHash != FALSE)) {
|
|
return XSK_EFUSEPS_ERROR_PS_PARAMETER_WRONG;
|
|
}
|
|
|
|
/**
|
|
* XAdc Initialization
|
|
*/
|
|
Status = XilSKey_EfusePs_XAdcInit();
|
|
if (Status != XST_SUCCESS) {
|
|
RetValue = XSK_EFUSEPS_ERROR_XADC_INIT;
|
|
goto ExitFinal;
|
|
}
|
|
|
|
/**
|
|
* Unlock the eFUSE controller
|
|
*/
|
|
XSK_EFUSEPS_CONTROLER_UNLOCK();
|
|
|
|
/**
|
|
* Check if the controller is unlocked
|
|
*/
|
|
if (XSK_EFUSEPS_CONTROLER_LOCK_STATUS() == TRUE) {
|
|
RetValue = XSK_EFUSEPS_ERROR_CONTROLLER_LOCK;
|
|
goto ExitFinal;
|
|
}
|
|
|
|
/**
|
|
* Configure the eFUSE controller with mode, strobe width values
|
|
*/
|
|
Status = XilSKey_EfusePs_ControllerConfig(XSK_EFUSEPS_REDUNDANCY_MODE,
|
|
RefClk, XSK_EFUSEPS_READ_MODE_NORMAL);
|
|
if (Status != XST_SUCCESS) {
|
|
RetValue = XSK_EFUSEPS_ERROR_CONTROLLER_CONFIG + Status;
|
|
goto ExitCtrlLock;
|
|
}
|
|
|
|
/**
|
|
* Enable eFUSE reading only
|
|
*/
|
|
XilSKey_EfusePs_ControllerSetReadWriteEnable(XSK_EFUSEPS_ENABLE_READ);
|
|
|
|
/**
|
|
* Read the eFUSE
|
|
*/
|
|
|
|
/**
|
|
* Read the RSA key Hash value from eFUSE Array
|
|
*/
|
|
if (InstancePtr->EnableRsaKeyHash) {
|
|
Status = XilSKey_EfusePs_ReadRsaKeyHash(
|
|
InstancePtr->RsaKeyReadback, RefClk);
|
|
if (Status != XST_SUCCESS) {
|
|
RetValue = XSK_EFUSEPS_ERROR_READ_RSA_HASH + Status;
|
|
goto ExitCtrlResetStatus;
|
|
}
|
|
}
|
|
|
|
ExitCtrlResetStatus:
|
|
/**
|
|
* Disable Programming, write and read
|
|
*/
|
|
XilSKey_EfusePs_ControllerSetReadWriteEnable(0);
|
|
|
|
ExitCtrlLock:
|
|
/**
|
|
* Lock the eFUSE controller
|
|
*/
|
|
XSK_EFUSEPS_CONTROLER_LOCK();
|
|
|
|
ExitFinal:
|
|
return RetValue;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* This function is used to check the RSA Hash for all zeros.
|
|
*
|
|
* @param RefClk is the reference clock frequency. Clock frequency can be
|
|
* between 20MHz to 60MHz specified in Hz
|
|
*
|
|
* @return
|
|
* - XST_SUCCESS if RSA Hash eFUSE bits are all zeros.
|
|
* - XSK_EFUSEPS_ERROR_RSA_HASH_ALREADY_PROGRAMMED if any RSA hash
|
|
* eFUSE bit is set
|
|
* - Other errors because of internal controller functions and
|
|
* can be checked in xeFUSE_error.h
|
|
*
|
|
****************************************************************************/
|
|
|
|
static u32 XilSKey_EfusePs_CheckRsaHashForAllZeros(u32 RefClk)
|
|
{
|
|
u32 EfuseAddress,Status,RetValue;
|
|
u32 LoopIndex;
|
|
u8 Data;
|
|
|
|
RetValue = XST_SUCCESS;
|
|
|
|
/**
|
|
* Set the controller to read in redundancy mode
|
|
*/
|
|
Status = XilSKey_EfusePs_ControllerConfig(XSK_EFUSEPS_REDUNDANCY_MODE,
|
|
RefClk, XSK_EFUSEPS_READ_MODE_NORMAL);
|
|
if (Status != XST_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
* Check the Hash eFUSE Bits for all Zero's
|
|
*/
|
|
LoopIndex = 0;
|
|
EfuseAddress=XSK_EFUSEPS_APB_CUSTOMER_KEY_FIRST_HALF_START_ADDR;
|
|
while (LoopIndex < (XSK_EFUSEPS_HAMMING_LOOPS*XSK_EFUSEPS_HAMMING_LENGTH)) {
|
|
/**
|
|
* Escape the Xilinx Reserved Bits
|
|
*/
|
|
while (XilSKey_EfusePs_IsAddressXilRestricted(EfuseAddress) == TRUE) {
|
|
EfuseAddress += 4;
|
|
}
|
|
Status = XilSKey_EfusePs_ReadWithXadcCheck(EfuseAddress, RefClk, &Data);
|
|
if (Status != XST_SUCCESS) {
|
|
RetValue = Status;
|
|
goto ExitControllerReset;
|
|
}
|
|
/**
|
|
* Data value of 1 indicates Hash is already written
|
|
*/
|
|
if (Data != 0) {
|
|
RetValue = XSK_EFUSEPS_ERROR_RSA_HASH_ALREADY_PROGRAMMED;
|
|
goto ExitControllerReset;
|
|
}
|
|
EfuseAddress += 4;
|
|
LoopIndex++;
|
|
} /* End of while (LoopIndex < (XSK_EFUSEPS_HAMMING_LOOPS* ....) */
|
|
|
|
ExitControllerReset:
|
|
/**
|
|
* Set the controller back to single mode
|
|
*/
|
|
Status = XilSKey_EfusePs_ControllerConfig(XSK_EFUSEPS_SINGLE_MODE,
|
|
RefClk, XSK_EFUSEPS_READ_MODE_NORMAL);
|
|
if (Status != XST_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
return RetValue;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* This function is used to to write the Single eFUSE which checks for
|
|
* XADC temperature and voltage and verifies the written bit in the eFUSE
|
|
* Verification of the bit is done by reading the bit in margin 1 mode and
|
|
* normal mode.
|
|
* Temperature and voltage are read from XADC and verified for the
|
|
* correct range
|
|
*
|
|
* @param EfuseAddress is the address of the eFUSE bit to be written
|
|
* @param RefClk is the reference clock frequency. Clock frequency can be
|
|
* between 20MHz to 60MHz specified in Hz
|
|
* @return
|
|
* - XST_SUCCESS no errors occured
|
|
* - an error XSK_EFUSEPS_ERROR_WRITE_VCCPAUX_VOLTAGE_OUT_OF_RANGE when
|
|
* voltage not in range
|
|
* - an error XSK_EFUSEPS_ERROR_WRITE_TEMPERATURE_OUT_OF_RANGE when
|
|
* temperature not in range
|
|
* - Other errors because of internal functions and
|
|
* can be checked in xeFUSE_error.h
|
|
****************************************************************************/
|
|
static u32
|
|
XilSKey_EfusePs_WriteWithXadcCheckAndVerify(u32 EfuseAddress, u32 RefClk)
|
|
{
|
|
XSKEfusePs_XAdc XAdcInstancePtr;
|
|
u32 Status, StatusLowerAddr, RedundantEfuseAddress;
|
|
|
|
/**
|
|
* If the eFUSE bit is already programmed, no need to program again.
|
|
* That is taken care in eFUSE controller write function
|
|
*/
|
|
XAdcInstancePtr.VType = XSK_EFUSEPS_VPAUX;
|
|
XilSKey_EfusePs_XAdcReadTemperatureAndVoltage(&XAdcInstancePtr);
|
|
|
|
/**
|
|
* Check the temperature and voltage
|
|
*/
|
|
if ((XAdcInstancePtr.Temp < XSK_EFUSEPS_TEMP_MIN_RAW) ||
|
|
((XAdcInstancePtr.Temp > XSK_EFUSEPS_TEMP_MAX_RAW))) {
|
|
return XSK_EFUSEPS_ERROR_WRITE_TEMPERATURE_OUT_OF_RANGE;
|
|
}
|
|
|
|
if ((XAdcInstancePtr.V < XSK_EFUSEPS_WRITE_VPAUX_MIN_RAW) ||
|
|
((XAdcInstancePtr.V > XSK_EFUSEPS_WRITE_VPAUX_MAX_RAW))) {
|
|
return XSK_EFUSEPS_ERROR_WRITE_VCCPAUX_VOLTAGE_OUT_OF_RANGE;
|
|
}
|
|
|
|
/**
|
|
* Write the eFUSE bit
|
|
*/
|
|
StatusLowerAddr = XilSKey_EfusePs_WriteEfuseBit(EfuseAddress);
|
|
|
|
/**
|
|
* verify only if programming is success
|
|
* verification of lower address is checked while
|
|
* higher address verification
|
|
*/
|
|
if (StatusLowerAddr == XST_SUCCESS) {
|
|
StatusLowerAddr = XilSKey_EfusePs_VerifyWithXadcCheck(EfuseAddress,
|
|
RefClk);
|
|
}
|
|
|
|
/**
|
|
* Write the Redundant eFUSE bit address
|
|
*/
|
|
RedundantEfuseAddress = XSK_EFUSEPS_APB_MIRROR_ADDRESS(EfuseAddress);
|
|
Status = XilSKey_EfusePs_WriteEfuseBit(RedundantEfuseAddress);
|
|
if (Status != XST_SUCCESS) {
|
|
/**
|
|
* if higher address is not success, check lower address and return
|
|
*/
|
|
if (StatusLowerAddr != XST_SUCCESS) {
|
|
return Status;
|
|
} else {
|
|
/**
|
|
* Successfully written lower address, so success
|
|
*/
|
|
return XST_SUCCESS;
|
|
}
|
|
}
|
|
|
|
Status = XilSKey_EfusePs_VerifyWithXadcCheck(RedundantEfuseAddress,
|
|
RefClk);
|
|
if (Status != XST_SUCCESS) {
|
|
/**
|
|
* if higher address is not success, check lower address and return
|
|
*/
|
|
if (StatusLowerAddr != XST_SUCCESS) {
|
|
return Status;
|
|
} else {
|
|
/**
|
|
* Succesfully written lower address, so success
|
|
*/
|
|
return XST_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Ideal case where lower and higher address is written properly
|
|
*/
|
|
return XST_SUCCESS;
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* This function is used to write the RSA hash in the eFUSE Array in Little
|
|
* Endian.
|
|
*
|
|
* @param RsaKeyHashBuf is the buffer containing the RSA hash to be written
|
|
* to the eFUSE array.
|
|
* @param RefClk is the reference clock frequency. Clock frequency can be
|
|
* between 20MHz to 60MHz specified in Hz
|
|
* @return
|
|
* - XST_SUCCESS no errors occurred.
|
|
* - Other errors because of internal controller functions and
|
|
* can be checked in xeFUSE_error.h
|
|
*
|
|
****************************************************************************/
|
|
static u32 XilSKey_EfusePs_WriteRsaKeyHash(u8 *RsaKeyHashBuf, u32 RefClk)
|
|
{
|
|
int LoopIndex,BitIndex;
|
|
u8 DataBytes[XSK_EFUSEPS_RSA_KEY_HASH_LEN_BITS], Ecc[32];
|
|
u32 EfuseAddress, Status;
|
|
|
|
|
|
/**
|
|
* Convert the RSA Key hash to bit data
|
|
*/
|
|
XilSKey_Efuse_ConvertBitsToBytes(RsaKeyHashBuf, DataBytes,
|
|
(XSK_EFUSEPS_RSA_KEY_HASH_LEN_IN_BYTES*8));
|
|
|
|
/**
|
|
* Prepare the hamming matrix for encoding the RSA Key hash
|
|
*/
|
|
XilSKey_EfusePs_GenerateMatrixMap();
|
|
|
|
/**
|
|
* Encode the RSA Key hash with (31,26) hamming and write into
|
|
* the eFUSE array
|
|
*/
|
|
LoopIndex=0;
|
|
EfuseAddress=XSK_EFUSEPS_APB_CUSTOMER_KEY_FIRST_HALF_START_ADDR;
|
|
while (LoopIndex < XSK_EFUSEPS_HAMMING_LOOPS) {
|
|
/**
|
|
* Encode the data
|
|
*/
|
|
XilSKey_EfusePs_EccEncode(DataBytes + (LoopIndex*26), Ecc);
|
|
/* Write 31 bit Row in eFUSE Array */
|
|
for (BitIndex=0;BitIndex<31;BitIndex++) {
|
|
/**
|
|
* Escape the Xilinx Reserved Bits
|
|
*/
|
|
if (XilSKey_EfusePs_IsAddressXilRestricted(EfuseAddress) == TRUE) {
|
|
xeFUSE_printf(XSK_EFUSE_DEBUG_GENERAL,
|
|
"Discarding eFUSE Address %0x\n",
|
|
EfuseAddress);
|
|
EfuseAddress = EfuseAddress+4;
|
|
}
|
|
|
|
/**
|
|
* Write the eFUSE bit only if the value is one
|
|
*/
|
|
if (Ecc[BitIndex] & 0x1) {
|
|
xeFUSE_printf(XSK_EFUSE_DEBUG_GENERAL,
|
|
"Writing eFUSE Addr %0x, LoopIndex %0x, "
|
|
"BitIndex %0x\n",
|
|
EfuseAddress, LoopIndex, BitIndex);
|
|
Status = XilSKey_EfusePs_WriteWithXadcCheckAndVerify(
|
|
EfuseAddress, RefClk);
|
|
if (Status != XST_SUCCESS) {
|
|
return Status;
|
|
}
|
|
} /* End of (Ecc[BitIndex] & 0x1) */
|
|
/**
|
|
* Ready for next eFUSE Bit
|
|
*/
|
|
EfuseAddress += 4;
|
|
|
|
} /* End of for(BitIndex=0;BitIndex<31;BitIndex++) */
|
|
LoopIndex++;
|
|
} /* End of while(LoopIndex < XSK_EFUSEPS_HAMMING_LOOPS) */
|
|
|
|
return XST_SUCCESS;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* This function is used to Read the RSA hash in the eFUSE Array in Little
|
|
* Endian.
|
|
*
|
|
* @param RsaKeyHashBuf is the output buffer where RSA hash is copied
|
|
* from the eFUSE array after hamming decode.
|
|
* @param RefClk is the reference clock frequency. Clock frequency can be
|
|
* between 20MHz to 60MHz specified in Hz
|
|
* @return
|
|
* - XST_SUCCESS no errors occurred.
|
|
* - Other errors because of internal controller functions and
|
|
* can be checked in xeFUSEutils.h
|
|
****************************************************************************/
|
|
static u32 XilSKey_EfusePs_ReadRsaKeyHash(u8 *RsaKeyHashBuf, u32 RefClk)
|
|
{
|
|
int LoopIndex, BitIndex, Index;
|
|
u8 DataBytes[260], Recover[32], Syndrome[5], Pos;
|
|
u32 EfuseAddress, Status;
|
|
|
|
/**
|
|
* Prepare the hamming matrix for encoding the RSA Key hash
|
|
*/
|
|
XilSKey_EfusePs_GenerateMatrixMap();
|
|
|
|
/**
|
|
* Encode the RSA Key hash with (31,26) hamming and write to
|
|
* the eFUSE array
|
|
*/
|
|
LoopIndex=0;
|
|
EfuseAddress=XSK_EFUSEPS_APB_CUSTOMER_KEY_FIRST_HALF_START_ADDR;
|
|
while (LoopIndex < XSK_EFUSEPS_HAMMING_LOOPS) {
|
|
/**
|
|
* Write 31 bit Row in eFUSE Array
|
|
*/
|
|
for (BitIndex=0;BitIndex<31;BitIndex++) {
|
|
/**
|
|
* Escape the Xilinx Reserved Bits
|
|
*/
|
|
if (XilSKey_EfusePs_IsAddressXilRestricted(EfuseAddress) == TRUE) {
|
|
xeFUSE_printf(XSK_EFUSE_DEBUG_GENERAL,
|
|
"Discarding eFUSE Address %0x\n",
|
|
EfuseAddress);
|
|
EfuseAddress += 4;
|
|
}
|
|
xeFUSE_printf(XSK_EFUSE_DEBUG_GENERAL,
|
|
"Reading eFUSE Addr %0x, LoopIndex %0x, "
|
|
"BitIndex %0x\n",
|
|
EfuseAddress, LoopIndex, BitIndex);
|
|
Status = XilSKey_EfusePs_ReadWithXadcCheck(
|
|
EfuseAddress,
|
|
RefClk,
|
|
Recover+BitIndex);
|
|
if (Status != XST_SUCCESS) {
|
|
return Status;
|
|
}
|
|
EfuseAddress += 4;
|
|
} /* End of for(BitIndex=0;BitIndex<31;BitIndex++) */
|
|
|
|
/**
|
|
* Decode the data
|
|
*/
|
|
Pos = XilSKey_EfusePs_EccDecode(Recover, Syndrome);
|
|
/**
|
|
* Repair the corrupt bit
|
|
*/
|
|
if(Pos < 31)
|
|
{
|
|
Recover[Pos] = (Recover[Pos] + 1)% 2;
|
|
}
|
|
/**
|
|
* Copy the data
|
|
*/
|
|
for(Index=0;Index<26;Index++)
|
|
{
|
|
*(DataBytes + (LoopIndex * 26) + Index) = Recover[Index];
|
|
}
|
|
LoopIndex++;
|
|
} /* End of while(LoopIndex < XSK_EFUSEPS_HAMMING_LOOPS) */
|
|
|
|
/**
|
|
* Convert the bit data to RSA key hash
|
|
*/
|
|
XilSKey_EfusePs_ConvertBytesToBits(DataBytes,
|
|
RsaKeyHashBuf,
|
|
(XSK_EFUSEPS_RSA_KEY_HASH_LEN_BITS));
|
|
|
|
return XST_SUCCESS;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* This function is used to read the PS eFUSE bit. Reading of the eFUSE bit
|
|
* is done in NORMAL read mode. Temperature and voltage must be in specified
|
|
* range for reading.
|
|
*
|
|
* @param EfuseAddress is the address of the eFUSE bit
|
|
* @param RefClk is the reference clock frequency. Clock frequency can be
|
|
* between 20MHz to 60MHz specified in Hz
|
|
* @param Data is where the read data is stored. It will have values 0 or 1
|
|
* @return
|
|
* - XST_SUCCESS no errors occurred.
|
|
* - an error XSK_EFUSEPS_ERROR_READ_VCCPAUX_VOLTAGE_OUT_OF_RANGE when
|
|
* voltage not in range
|
|
* - an error XSK_EFUSEPS_ERROR_READ_TMEPERATURE_OUT_OF_RANGE when
|
|
* temperature not in range
|
|
* - Other errors because of internal controller functions and
|
|
* can be checked in xeFUSE_error.h
|
|
****************************************************************************/
|
|
static u32
|
|
XilSKey_EfusePs_ReadWithXadcCheck(u32 EfuseAddress, u32 RefClk, u8 *Data)
|
|
{
|
|
XSKEfusePs_XAdc XAdcInstancePtr;
|
|
u32 Status;
|
|
|
|
XAdcInstancePtr.VType = XSK_EFUSEPS_VPAUX;
|
|
XilSKey_EfusePs_XAdcReadTemperatureAndVoltage(&XAdcInstancePtr);
|
|
|
|
/**
|
|
* Check the temperature and voltage
|
|
*/
|
|
if ((XAdcInstancePtr.Temp < XSK_EFUSEPS_TEMP_MIN_RAW) ||
|
|
((XAdcInstancePtr.Temp > XSK_EFUSEPS_TEMP_MAX_RAW))) {
|
|
return XSK_EFUSEPS_ERROR_READ_TMEPERATURE_OUT_OF_RANGE;
|
|
}
|
|
|
|
if ((XAdcInstancePtr.V < XSK_EFUSEPS_READ_VPAUX_MIN_RAW) ||
|
|
((XAdcInstancePtr.V > XSK_EFUSEPS_READ_VPAUX_MAX_RAW))) {
|
|
return XSK_EFUSEPS_ERROR_READ_VCCPAUX_VOLTAGE_OUT_OF_RANGE;
|
|
}
|
|
|
|
/**
|
|
* Read the eFUSE bit
|
|
*/
|
|
Status = XilSKey_EfusePs_ReadEfuseBit(EfuseAddress, Data);
|
|
if (Status != XST_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
return XST_SUCCESS;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* This function is used to verify the written eFUSE bit. It is checked
|
|
* against the value of 1 only. Verification of the eFUSE bit is done by reading
|
|
* in MARGIN 2 mode which was highest margin.
|
|
*
|
|
* @param EfuseAddress is the address of the eFUSE bit
|
|
* @param RefClk is the reference clock frequency. Clock frequency can be
|
|
* between 20MHz to 60MHz specified in Hz
|
|
* @return
|
|
* - XST_SUCCESS no errors occurred.
|
|
* - XST_FAILURE an error occurred during verifying the PS eFUSE.
|
|
* - an error XSK_EFUSEPS_ERROR_READ_VCCPAUX_VOLTAGE_OUT_OF_RANGE when
|
|
* voltage not in range
|
|
* - an error XSK_EFUSEPS_ERROR_READ_TMEPERATURE_OUT_OF_RANGE when
|
|
* temperature not in range
|
|
* - an error XSK_EFUSEPS_ERROR_VERIFICATION when verification fails
|
|
* - Other errors because of internal controller functions and
|
|
* can be checked in xeFUSE_error.h
|
|
****************************************************************************/
|
|
static u32 XilSKey_EfusePs_VerifyWithXadcCheck(u32 EfuseAddress, u32 RefClk)
|
|
{
|
|
XSKEfusePs_XAdc XAdcInstancePtr;
|
|
u32 Status;
|
|
u8 Data;
|
|
|
|
XAdcInstancePtr.VType = XSK_EFUSEPS_VPAUX;
|
|
XilSKey_EfusePs_XAdcReadTemperatureAndVoltage(&XAdcInstancePtr);
|
|
|
|
/**
|
|
* Check the temperature and voltage
|
|
*/
|
|
if ((XAdcInstancePtr.Temp < XSK_EFUSEPS_TEMP_MIN_RAW) ||
|
|
((XAdcInstancePtr.Temp > XSK_EFUSEPS_TEMP_MAX_RAW))) {
|
|
return XSK_EFUSEPS_ERROR_READ_TMEPERATURE_OUT_OF_RANGE;
|
|
}
|
|
|
|
if ((XAdcInstancePtr.V < XSK_EFUSEPS_READ_VPAUX_MIN_RAW) ||
|
|
((XAdcInstancePtr.V > XSK_EFUSEPS_READ_VPAUX_MAX_RAW))) {
|
|
return XSK_EFUSEPS_ERROR_READ_VCCPAUX_VOLTAGE_OUT_OF_RANGE;
|
|
}
|
|
|
|
|
|
/**
|
|
* Read the eFUSE bit in Margin_1 mode
|
|
*/
|
|
Status = XilSKey_EfusePs_ControllerConfig(XSK_EFUSEPS_SINGLE_MODE,
|
|
RefClk, XSK_EFUSEPS_READ_MODE_MARGIN_1);
|
|
if (Status != XST_SUCCESS) {
|
|
return Status;
|
|
}
|
|
Status = XilSKey_EfusePs_ReadEfuseBit(EfuseAddress, &Data);
|
|
if (Status != XST_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
if (0 == ((Data) & 0x1)) {
|
|
return XSK_EFUSEPS_ERROR_VERIFICATION;
|
|
}
|
|
|
|
|
|
/**
|
|
* Read the eFUSE bit in Normal Mode
|
|
*/
|
|
Status = XilSKey_EfusePs_ControllerConfig(XSK_EFUSEPS_SINGLE_MODE,
|
|
RefClk, XSK_EFUSEPS_READ_MODE_NORMAL);
|
|
if (Status != XST_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
Status = XilSKey_EfusePs_ReadEfuseBit(EfuseAddress, &Data);
|
|
if (Status != XST_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
if (0 == ((Data) & 0x1)) {
|
|
return XSK_EFUSEPS_ERROR_VERIFICATION;
|
|
}
|
|
|
|
return XST_SUCCESS;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
* This function is used to generate the matrix map of the G and H for
|
|
* hamming code (31,26). G is [31,5] and defined as [A|I], I is identity
|
|
* matrix of [5,5].
|
|
*
|
|
* @return None
|
|
*
|
|
* TDD Cases:
|
|
* Check the generated matrix
|
|
* Check the memory corruption of the generated matrix
|
|
*
|
|
****************************************************************************/
|
|
|
|
void XilSKey_EfusePs_GenerateMatrixMap()
|
|
{
|
|
|
|
u8 y, x, Index;
|
|
u8 DataIndex, ParityIndex;
|
|
|
|
/* Matrix[31][5]={0} */
|
|
for(y = 0; y < 5; y++) {
|
|
for(x = 0; x < 31; x++) {
|
|
Matrix[x][y] = 0;
|
|
}
|
|
}
|
|
|
|
/* Generate Hamming Code Matrix for both Encoding and Decoding */
|
|
for(y = 0; y < 5; y++) {
|
|
Index = 0;
|
|
for(x = 1; x < 32; x++) {
|
|
if ((x != 1) && (x != 2) && (x != 4) && (x != 8) && (x != 16)) {
|
|
if ( ((x & (1 << y)) >> y) == 1)
|
|
Matrix[Index++][y] = 1;
|
|
else
|
|
Matrix[Index++][y] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Fill Identity Matrix */
|
|
for(y = 0; y < 5; y++) {
|
|
for(x = 0; x < 5; x++) {
|
|
if (x == y) Matrix[26+x][y] = 1;
|
|
else Matrix[26+x][y] = 0;
|
|
}
|
|
}
|
|
#if 0
|
|
// Print out format index
|
|
for(x = 1; x < 27; x++) {
|
|
printf("%*dd", 3, x);
|
|
}
|
|
printf("\n");
|
|
|
|
for(y = 0; y < 5; y++) {
|
|
for(x = 0; x < 31; x++) {
|
|
printf("%*d", 4, Matrix[x][y]);
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
#endif
|
|
|
|
/* Create Error Code Map Index */
|
|
ErrorCodeIndex[0] = -1; /* No Error */
|
|
DataIndex = 0;
|
|
ParityIndex = 26;
|
|
for(x = 1; x < 32; x++) {
|
|
if ((x != 1) && (x!= 2) && (x!= 4) && (x!= 8) && (x != 16)) {
|
|
ErrorCodeIndex[x] = DataIndex;
|
|
DataIndex ++;
|
|
} else {
|
|
ErrorCodeIndex[x] = ParityIndex;
|
|
ParityIndex ++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* This function is used to encode the incoming data byte. It uses
|
|
* hamming (31,26) algorithm. 26 bits are encoded to 31 bits
|
|
*
|
|
* @param InData is 26 bit input data with each bit represented in one byte
|
|
*
|
|
* @param Ecc is the 31 bit encoded data with each bit represented in one byte
|
|
*
|
|
* @return None
|
|
*
|
|
* TDD Cases:
|
|
* Check the parameters
|
|
* Check the encoded data for different input data
|
|
* Check the input data for boundary cases
|
|
* Check for memory corruption
|
|
*
|
|
****************************************************************************/
|
|
void XilSKey_EfusePs_EccEncode(const u8 *InData, u8 *Ecc)
|
|
{
|
|
u8 x, y, Index;
|
|
|
|
for(x = 0; x < 26; x++)
|
|
Ecc[x] = InData[x];
|
|
for(y = 0; y < 5; y++) {
|
|
Ecc[y+26] = 0;
|
|
for( Index =0; Index < 26; Index++)
|
|
Ecc[y+26] += Matrix[Index][y] * InData[Index];
|
|
Ecc[y+26] %= 2;
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* This function is used to decode the incoming encoded byte.
|
|
*
|
|
* @param Corrupt is the input encoded data. It has 26 bit data with
|
|
* 5 bit parity data
|
|
*
|
|
* @param Syndrome is the output updated with the parity error
|
|
* information.
|
|
*
|
|
* @return position of the error in the data byte
|
|
*
|
|
* TDD Cases:
|
|
* Check the parameters
|
|
* Check the decode with out any error
|
|
* Check the decode with 1 bit error
|
|
* Check the decode with 2 bit error
|
|
* Check the decode for boundary cases
|
|
* Check for memory corruption
|
|
*
|
|
****************************************************************************/
|
|
u8 XilSKey_EfusePs_EccDecode(const u8 *Corrupt, u8 *Syndrome)
|
|
{
|
|
u8 x, y;
|
|
u8 Pos;
|
|
|
|
// Calculate Error Syndrome
|
|
for(y = 0; y < 5; y++) {
|
|
Syndrome[y] = 0;
|
|
for( x =0; x < 31; x++)
|
|
Syndrome[y] += Matrix[x][y] * Corrupt[x];
|
|
Syndrome[y] %= 2;
|
|
}
|
|
Pos = (Syndrome[4] << 4) + (Syndrome[3] << 3) +
|
|
(Syndrome[2] << 2) + (Syndrome[1] << 1) + Syndrome[0];
|
|
Pos = ErrorCodeIndex[Pos];
|
|
|
|
return Pos;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* This function is used to set the controller mode to Redundancy/Single mode.
|
|
*
|
|
* @param Mode is mode of the controller to the set.
|
|
* - REDUNDANCY_MODE
|
|
* - SINGLE_MODE
|
|
*
|
|
* @return None
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void XilSKey_EfusePs_SetControllerMode (u8 Mode)
|
|
{
|
|
u32 RegVal;
|
|
if(Mode == XSK_EFUSEPS_REDUNDANCY_MODE) {
|
|
/**
|
|
* Configuration Reg - Redundancy Mode
|
|
*/
|
|
RegVal = Xil_In32(XSK_EFUSEPS_CONFIG_REG);
|
|
RegVal |= XSK_EFUSEPS_CONFIG_REDUNDANCY;
|
|
Xil_Out32(XSK_EFUSEPS_CONFIG_REG, RegVal);
|
|
}
|
|
else if(Mode == XSK_EFUSEPS_SINGLE_MODE) {
|
|
/**
|
|
* Configuration Reg - Single Mode
|
|
*/
|
|
RegVal = Xil_In32(XSK_EFUSEPS_CONFIG_REG);
|
|
RegVal &= ~XSK_EFUSEPS_CONFIG_REDUNDANCY;
|
|
Xil_Out32(XSK_EFUSEPS_CONFIG_REG, RegVal);
|
|
}
|
|
return ;
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* This function is used to set the controller read mode to
|
|
* Normal/Margin 1/Margin 2.
|
|
*
|
|
* @param ReadMode is the read mode of the controller
|
|
* - XSK_EFUSEPS_READ_MODE_NORMAL
|
|
* - XSK_EFUSEPS_READ_MODE_MARGIN_1
|
|
* - XSK_EFUSEPS_READ_MODE_MARGIN_2
|
|
*
|
|
* @return None
|
|
*
|
|
****************************************************************************/
|
|
|
|
static void XilSKey_EfusePs_SetControllerReadMode (u8 ReadMode)
|
|
{
|
|
|
|
u32 RegVal;
|
|
|
|
/**
|
|
* Read Configuration Reg
|
|
*/
|
|
RegVal = Xil_In32(XSK_EFUSEPS_CONFIG_REG);
|
|
/**
|
|
* Reset the read mode
|
|
*/
|
|
RegVal &= ~XSK_EFUSEPS_CONFIG_MARGIN_RD;
|
|
if (ReadMode == XSK_EFUSEPS_READ_MODE_NORMAL) {
|
|
/**
|
|
* Set to Normal read mode
|
|
*/
|
|
RegVal |= XSK_EFUSEPS_CONFIG_RD_NORMAL;
|
|
}
|
|
else if (ReadMode == XSK_EFUSEPS_READ_MODE_MARGIN_1) {
|
|
/**
|
|
* Set to Margin 1 read mode
|
|
*/
|
|
RegVal |= XSK_EFUSEPS_CONFIG_RD_MARGIN_1;
|
|
}
|
|
else if (ReadMode == XSK_EFUSEPS_READ_MODE_MARGIN_2) {
|
|
/**
|
|
* Set to Margin 2 read mode
|
|
*/
|
|
RegVal |= XSK_EFUSEPS_CONFIG_RD_MARGIN_2;
|
|
}
|
|
Xil_Out32(XSK_EFUSEPS_CONFIG_REG, RegVal);
|
|
return ;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* This function is used to check the read mode supported
|
|
*
|
|
* @param ReadMode is input read mode to be checked against
|
|
*
|
|
* @return
|
|
* - XST_SUCCESS if read mode is supported
|
|
* - XST_FAILURE if read mode is not supported
|
|
*
|
|
****************************************************************************/
|
|
|
|
static u8 XilSKey_EfusePs_IsReadModeSupported (u8 ReadMode)
|
|
{
|
|
if ((ReadMode == XSK_EFUSEPS_READ_MODE_NORMAL) ||
|
|
(ReadMode == XSK_EFUSEPS_READ_MODE_MARGIN_1) ||
|
|
(ReadMode == XSK_EFUSEPS_READ_MODE_MARGIN_2)) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* This function is used to set the controller mode, read mode along with
|
|
* the read and program strobe width values based on the reference clock.
|
|
*
|
|
* @param CtrlMode is the mode of the controller
|
|
* - XSK_EFUSEPS_REDUNDANCY_MODE
|
|
* - XSK_EFUSEPS_SINGLE_MODE
|
|
*
|
|
* @param RefClk is the CPU 1x reference clock frequency. Clock frequency can be
|
|
* between 20MHz to 100MHz specified in Hz
|
|
*
|
|
* @param ReadMode is the read mode of the controller
|
|
* - XSK_EFUSEPS_READ_MODE_NORMAL
|
|
* - XSK_EFUSEPS_READ_MODE_MARGIN_1
|
|
* - XSK_EFUSEPS_READ_MODE_MARGIN_2
|
|
*
|
|
* @return
|
|
* - XST_SUCCESS no errors occured.
|
|
* - an error when controller mode is not supported
|
|
* - an error when reference clock is not supported
|
|
* - an error when read mode is not supported
|
|
*
|
|
* Test Cases:
|
|
Check single mode in CFG Reg
|
|
Check redundancy mode in CFG Reg
|
|
Check strobe width values for write mode
|
|
Check strobe width values for various read mode
|
|
Check Normal Read mode setting in CFG Reg
|
|
Check Margin 1 Read mode setting in CFG Reg
|
|
Check Margin 2 Read mode setting in CFG Reg
|
|
Boundary Conditions
|
|
|
|
*
|
|
****************************************************************************/
|
|
u32 XilSKey_EfusePs_ControllerConfig(u8 CtrlMode, u32 RefClk, u8 ReadMode)
|
|
{
|
|
u32 RdStrWdthVal=0, PrgmStrWdthVal=0;
|
|
|
|
/**
|
|
* Check the parameters
|
|
* Mode can be Single or Redundancy mode
|
|
*/
|
|
|
|
if ((CtrlMode != XSK_EFUSEPS_SINGLE_MODE) &&
|
|
(CtrlMode != XSK_EFUSEPS_REDUNDANCY_MODE)) {
|
|
return XSK_EFUSEPS_ERROR_CONTROLLER_MODE;
|
|
}
|
|
|
|
|
|
/**
|
|
* Ref Clock should be between 20MHz - 60MHz
|
|
*/
|
|
if ((RefClk < XSK_EFUSEPS_REFCLK_LOW_FREQ) ||
|
|
(RefClk > XSK_EFUSEPS_REFCLK_HIGH_FREQ)) {
|
|
return XSK_EFUSEPS_ERROR_REF_CLOCK;
|
|
}
|
|
|
|
/**
|
|
* 3 read modes are supported
|
|
*/
|
|
if (!XilSKey_EfusePs_IsReadModeSupported(ReadMode)) {
|
|
return XSK_EFUSEPS_ERROR_READ_MODE;
|
|
}
|
|
|
|
/**
|
|
* Set the controller mode
|
|
*/
|
|
XilSKey_EfusePs_SetControllerMode(CtrlMode);
|
|
|
|
/**
|
|
* Set the controller read mode
|
|
*/
|
|
XilSKey_EfusePs_SetControllerReadMode(ReadMode);
|
|
|
|
|
|
#if 0
|
|
u32 RegVal;
|
|
/* Commented as we are not supporting Reference Freq > 60MHz */
|
|
/**
|
|
* Set TSU_H_A to 1 if RefClk > 80MHz
|
|
*/
|
|
RegVal = Xil_In32(XSK_EFUSEPS_CONFIG_REG);
|
|
if (RefClk > 80000000) {
|
|
RegVal |= XSK_EFUSEPS_CONFIG_TSU_H_A;
|
|
}
|
|
Xil_Out32(XSK_EFUSEPS_CONFIG_REG, RegVal);
|
|
#endif
|
|
/**
|
|
* Program the Strobe width values for read and write
|
|
* 12ms is required for write and 150ns is required for read
|
|
* PGM_STBW = ceiling(12us/ref_clk period)
|
|
* RD_STBW = ceiling(150ns/ref_clk period)
|
|
*/
|
|
PrgmStrWdthVal = XSK_EFUSEPS_PRGM_STROBE_WIDTH(RefClk);
|
|
Xil_Out32(XSK_EFUSEPS_PGM_STBW_REG, PrgmStrWdthVal);
|
|
|
|
RdStrWdthVal = XSK_EFUSEPS_RD_STROBE_WIDTH(RefClk);
|
|
Xil_Out32(XSK_EFUSEPS_RD_STBW_REG, RdStrWdthVal);
|
|
|
|
return XST_SUCCESS;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* This function is used to check whether eFuse bit is xilinx reserved bit or
|
|
* not
|
|
*
|
|
* @param Addr is the address of the eFuse bit.
|
|
*
|
|
* @return
|
|
* - XST_SUCCESS if address corresponds to restricted eFuse bit.
|
|
* - XST_FAILURE is address corresponds to non-restricted eFuse bit.
|
|
*
|
|
* Test Cases:
|
|
* with different address values
|
|
* Boundary values for addr
|
|
*
|
|
****************************************************************************/
|
|
|
|
u8 XilSKey_EfusePs_IsAddressXilRestricted (u32 Addr)
|
|
{
|
|
/**
|
|
* Check for xilinx test bits
|
|
*/
|
|
if( (Addr == XSK_EFUSEPS_APB_XILINX_RSVD_TEST_BIT_x20) ||
|
|
(Addr == XSK_EFUSEPS_APB_XILINX_RSVD_TEST_BIT_x41) ||
|
|
(Addr == XSK_EFUSEPS_APB_XILINX_RSVD_TEST_BIT_x62) ||
|
|
(Addr == XSK_EFUSEPS_APB_XILINX_RSVD_TEST_BIT_x83) ||
|
|
(Addr == XSK_EFUSEPS_APB_XILINX_RSVD_TEST_BIT_xA4) ||
|
|
(Addr == XSK_EFUSEPS_APB_XILINX_RSVD_TEST_BIT_xC5) ||
|
|
(Addr == XSK_EFUSEPS_APB_XILINX_RSVD_TEST_BIT_xE6) ||
|
|
(Addr == XSK_EFUSEPS_APB_XILINX_RSVD_TEST_BIT_x107) ||
|
|
(Addr == XSK_EFUSEPS_APB_XILINX_RSVD_TEST_BIT_x128) ||
|
|
(Addr == XSK_EFUSEPS_APB_XILINX_RSVD_TEST_BIT_x149) ||
|
|
|
|
(Addr == XSK_EFUSEPS_APB_XILINX_RSVD_TEST_BIT_x23F) ||
|
|
(Addr == XSK_EFUSEPS_APB_XILINX_RSVD_TEST_BIT_x25E) ||
|
|
(Addr == XSK_EFUSEPS_APB_XILINX_RSVD_TEST_BIT_x27D) ||
|
|
(Addr == XSK_EFUSEPS_APB_XILINX_RSVD_TEST_BIT_x29C) ||
|
|
(Addr == XSK_EFUSEPS_APB_XILINX_RSVD_TEST_BIT_x2BB) ||
|
|
(Addr == XSK_EFUSEPS_APB_XILINX_RSVD_TEST_BIT_x2DA) ||
|
|
(Addr == XSK_EFUSEPS_APB_XILINX_RSVD_TEST_BIT_x2F9) ||
|
|
(Addr == XSK_EFUSEPS_APB_XILINX_RSVD_TEST_BIT_x318) ||
|
|
(Addr == XSK_EFUSEPS_APB_XILINX_RSVD_TEST_BIT_x337) ||
|
|
(Addr == XSK_EFUSEPS_APB_XILINX_RSVD_TEST_BIT_x356) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Check for xilinx reserved bits
|
|
*/
|
|
if ( ((Addr >= XSK_EFUSEPS_APB_TRIM_BITS_START_ADDR) &&
|
|
(Addr <= XSK_EFUSEPS_APB_TRIM_BITS_END_ADDR)) ||
|
|
((Addr >= XSK_EFUSEPS_APB_XILINX_RSVD_BITS_START_ADDR) &&
|
|
(Addr <= XSK_EFUSEPS_APB_XILINX_RSVD_BITS_END_ADDR)) ||
|
|
((Addr >= XSK_EFUSEPS_APB_BISR_BITS_START_ADDR) &&
|
|
(Addr <= XSK_EFUSEPS_APB_BISR_BITS_END_ADDR)) ||
|
|
((Addr >= XSK_EFUSEPS_APB_TRIM_BITS_START_ADDR_2ND_HALF) &&
|
|
(Addr <= XSK_EFUSEPS_APB_TRIM_BITS_END_ADDR_2ND_HALF)) ||
|
|
((Addr >= XSK_EFUSEPS_APB_XILINX_RSVD_BITS_START_ADDR_2ND_HALF) &&
|
|
(Addr <= XSK_EFUSEPS_APB_XILINX_RSVD_BITS_END_ADDR_2ND_HALF)) ||
|
|
((Addr >= XSK_EFUSEPS_APB_BISR_BITS_START_ADDR_2ND_HALF) &&
|
|
(Addr <= XSK_EFUSEPS_APB_BISR_BITS_END_ADDR_2ND_HALF))
|
|
) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* This function is used to enable the read/write/program the eFUSE
|
|
* array.
|
|
*
|
|
* @param ReadWriteEnable
|
|
* 0x1 - Enable programming
|
|
* 0x2 - Enable read
|
|
* 0x4 - Enable write
|
|
* @return
|
|
*
|
|
* Test Cases
|
|
*
|
|
****************************************************************************/
|
|
|
|
void XilSKey_EfusePs_ControllerSetReadWriteEnable(u32 ReadWriteEnable)
|
|
{
|
|
u32 RegVal;
|
|
|
|
RegVal = Xil_In32(XSK_EFUSEPS_CONTROL_REG);
|
|
|
|
/**
|
|
* Reset the values
|
|
* Disable programming
|
|
* Disable reading
|
|
* Disable writing
|
|
*/
|
|
RegVal &= ~XSK_EFUSEPS_CONTROL_PS_EN;
|
|
RegVal |= XSK_EFUSEPS_CONTROL_RD_DIS | XSK_EFUSEPS_CONTROL_WR_DIS;
|
|
|
|
if (ReadWriteEnable & XSK_EFUSEPS_ENABLE_PROGRAMMING) {
|
|
RegVal |= XSK_EFUSEPS_CONTROL_PS_EN;
|
|
}
|
|
|
|
if (ReadWriteEnable & XSK_EFUSEPS_ENABLE_READ) {
|
|
RegVal &= ~XSK_EFUSEPS_CONTROL_RD_DIS;
|
|
}
|
|
|
|
if (ReadWriteEnable & XSK_EFUSEPS_ENABLE_WRITE) {
|
|
RegVal &= ~XSK_EFUSEPS_CONTROL_WR_DIS;
|
|
}
|
|
|
|
Xil_Out32(XSK_EFUSEPS_CONTROL_REG, RegVal);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* This function is used to read the eFuse bit value. Before using this
|
|
* function set the controller mode and read mode as required. Also, strobe
|
|
* width values are to be set properly based on the reference clock for
|
|
* successful reading
|
|
*
|
|
* @param Addr is the address of the eFuse bit.
|
|
*
|
|
* @param Data has the read eFuse value stored in it.
|
|
*
|
|
* @return
|
|
* - XST_SUCCESS for succesfully reading the value.
|
|
* - an error when addr is restricted
|
|
*
|
|
* Test Cases
|
|
Read in Single mode
|
|
Read in redundancy mode
|
|
Read for restricted address
|
|
Boundary Checks for address
|
|
*
|
|
****************************************************************************/
|
|
|
|
u32 XilSKey_EfusePs_ReadEfuseBit(u32 Addr, u8 *Data)
|
|
{
|
|
if(XilSKey_EfusePs_IsAddressXilRestricted(Addr) != FALSE) {
|
|
return XSK_EFUSEPS_ERROR_ADDRESS_XIL_RESTRICTED;
|
|
}
|
|
|
|
*Data = Xil_In32(Addr) & 0x1;
|
|
|
|
xeFUSE_printf(XSK_EFUSE_DEBUG_GENERAL,"Reading Addr %0x, Data %0x\n", Addr, *Data);
|
|
|
|
return XST_SUCCESS;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* This function is used to program the eFuse bit value. Before using this
|
|
* function set the controller mode and read mode as required. Also, strobe
|
|
* width values are to be set properly based on the reference clock for
|
|
* successful programming
|
|
*
|
|
* @param Addr is the address of the eFuse bit.
|
|
*
|
|
* @return
|
|
* - XST_SUCCESS after successful writing.
|
|
* - an error when addr is restricted
|
|
*
|
|
* Test Cases
|
|
Write in Single mode
|
|
Write in redundancy mode
|
|
Write for restricted address
|
|
Boundary Checks for address
|
|
Strobe width are not proper (Check if it makes sense)
|
|
*
|
|
****************************************************************************/
|
|
|
|
u32 XilSKey_EfusePs_WriteEfuseBit(u32 Addr)
|
|
{
|
|
|
|
u64 time = 0;
|
|
|
|
/**
|
|
* Check if Address is restricted
|
|
*/
|
|
|
|
if(XilSKey_EfusePs_IsAddressXilRestricted(Addr) != FALSE) {
|
|
return XSK_EFUSEPS_ERROR_ADDRESS_XIL_RESTRICTED;
|
|
}
|
|
|
|
/**
|
|
* Send success when bit is already programmed
|
|
*/
|
|
if ((Xil_In32(Addr)&0x1) == 1) {
|
|
xeFUSE_printf(XSK_EFUSE_DEBUG_GENERAL,
|
|
"Addr %0x already programmed\n", Addr);
|
|
return XST_SUCCESS;
|
|
}
|
|
|
|
Xil_Out32(Addr, 0x1);
|
|
|
|
/**
|
|
* Providing 15us delay
|
|
* Timer takes 100ns as slice. 15us = 150 * 100ns
|
|
*/
|
|
XilSKey_Efuse_SetTimeOut(&time, 150);
|
|
while(1) {
|
|
if(XilSKey_Efuse_IsTimerExpired(time) == 1)
|
|
break;
|
|
}
|
|
|
|
xeFUSE_printf(XSK_EFUSE_DEBUG_GENERAL,
|
|
"Writing Addr %0x, Data %0x\n", Addr, Xil_In32(Addr));
|
|
|
|
return XST_SUCCESS;
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/**
|
|
* This function is used to read the PS efuse status register.
|
|
*
|
|
* @param InstancePtr is the pointer to the PsEfuseHandle which describes
|
|
* which PS eFUSE bit should be burned.
|
|
* @param StatusBits - variable to store the status register read.
|
|
*
|
|
* @return
|
|
* - XST_SUCCESS.
|
|
* - XST_FAILURE
|
|
*
|
|
****************************************************************************/
|
|
u32 XilSKey_EfusePs_ReadStatus(XilSKey_EPs *InstancePtr, u32 *StatusBits)
|
|
{
|
|
u32 RetValue;
|
|
|
|
RetValue = XST_SUCCESS;
|
|
|
|
/**
|
|
* Unlock the eFUSE controller
|
|
*/
|
|
XSK_EFUSEPS_CONTROLER_UNLOCK();
|
|
|
|
/**
|
|
* Check if the controller is unlocked
|
|
*/
|
|
if (XSK_EFUSEPS_CONTROLER_LOCK_STATUS() == TRUE) {
|
|
RetValue = XSK_EFUSEPS_ERROR_CONTROLLER_LOCK;
|
|
goto ExitFinal;
|
|
}
|
|
|
|
/**
|
|
* Read the eFUSE status
|
|
*/
|
|
*StatusBits = Xil_In32(XSK_EFUSEPS_STATUS_REG);
|
|
|
|
ExitFinal:
|
|
return RetValue;
|
|
}
|
|
|