embeddedsw/lib/sw_services/xilskey/src/xilskey_eps.c
Jagannadha Sutradharudu Teki 2c8f92039d embeddesw: Add initial code support
Added initial support Xilinx Embedded Software.

Signed-off-by: Jagannadha Sutradharudu Teki <jaganna@xilinx.com>
2014-06-24 16:45:01 +05:30

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