Files
thead-uboot/drivers/trng/eip76_random.c
2022-09-13 11:04:33 +08:00

503 lines
14 KiB
C

/*
* Copyright (C) 2017-2020 Alibaba Group Holding Limited
*/
/* eip76_random.c
*
* Module implements the EIP-76 Driver Library Read Random Number API
*/
/*----------------------------------------------------------------------------
* This module implements (provides) the following interface(s):
*/
// EIP-76 Driver Library Read Random Number API
#include "eip76_read.h"
/*----------------------------------------------------------------------------
* This module uses (requires) the following interface(s):
*/
// Default configuration
#include "c_eip76.h"
// Driver Framework Basic Definitions API
#include "basic_defs.h" // uint32_t
// Driver Framework Device API
#include "device_types.h" // Device_Handle_t
// EIP-76 Driver Library Types API
#include "eip76_types.h" // EIP76_* types
// EIP-76 Driver Library Internal interfaces
#include "eip76_level0.h" // Level 0 macros
#include "eip76_fsm.h" // State machine
#include "eip76_internal.h" // Internal macros
/*----------------------------------------------------------------------------
* Definitions and macros
*/
extern uint32_t g_rb_trng_reseed_max;
extern uint32_t g_rb_trng_reseed_enable;
extern uint32_t g_rb_trng_reseed_cur;
#define ADAPTER_EIP76_PS_WORD32_COUNT 12
#define DEFAULT_TIMEOUT 1000U
extern uint32_t Adapter_EIP76_PS_Data[ADAPTER_EIP76_PS_WORD32_COUNT];
uint32_t trng_reseed(
EIP76_IOArea_t * const IOArea_p,
uint32_t block)
{
EIP76_Status_t res;
EIP76_EventStatus_t events = 0;
unsigned int actual = 0;
uint32_t timestart;
uint32_t rt = 0;
uint32_t ret = 0;
if (g_rb_trng_reseed_enable == 0) {
return 0;
}
g_rb_trng_reseed_cur += block;
if ((g_rb_trng_reseed_cur) >= g_rb_trng_reseed_max) {
/* do reseed*/
//timestart = csi_tick_get();
timestart = 0;//TODO
rt = timestart;
while ((rt - timestart) < DEFAULT_TIMEOUT) {
res = EIP76_PostProcessor_Reseed_Start(IOArea_p, &events);
if (res != EIP76_NO_ERROR) {
//rt = csi_tick_get();
rt = 0;
ret = -1;
continue;
}
/* set PS */
res = EIP76_PostProcessor_Reseed_Write(IOArea_p,
Adapter_EIP76_PS_Data,
ADAPTER_EIP76_PS_WORD32_COUNT,
&events);
if (res != EIP76_NO_ERROR) {
//rt = csi_tick_get();
rt = 0;
ret = -1;
continue;
}
g_rb_trng_reseed_cur = 0;
return 0;
}
}
return 0;
}
extern uint32_t g_rb_trng_reseed_max;
extern uint32_t g_long_request_mode;
/*----------------------------------------------------------------------------
* EIP76_Request_Random_Data
*
*/
EIP76_Status_t
EIP76_Request_Random_Data(
EIP76_IOArea_t * const IOArea_p,
unsigned int NumberOfBytes)
{
Device_Handle_t Device;
uint32_t ControlValue, StatusValue, NumberOfBlks, WriteValue;
volatile EIP76_True_IOArea_t * const TrueIOArea_p = IOAREA(IOArea_p);
EIP76_CHECK_POINTER(IOArea_p);
trng_reseed(IOArea_p, 1);
Device = TrueIOArea_p->Device;
ControlValue = EIP76_CONTROL_RD(Device);
// First check if number of data_bloacks is zero, else return
if ((ControlValue >> 20) & MASK_12_BITS)
return EIP76_BUSY_RETRY_LATER;
StatusValue = EIP76_STATUS_RD(Device);
// Count available data blocks
NumberOfBlks = (StatusValue & MASK_1_BIT) +
((StatusValue >> 16) & MASK_8_BITS);
if (NumberOfBlks * 16 < NumberOfBytes)
{
if (g_long_request_mode) {
printf("===%s, %d\n", __FUNCTION__, __LINE__);
NumberOfBlks = g_rb_trng_reseed_max;
}else {
printf("===%s, %d\n", __FUNCTION__, __LINE__);
NumberOfBlks = (NumberOfBytes + 15) / 16; // Round up
// Reduce blocks by the number of blocks already available
NumberOfBlks -= ((StatusValue & MASK_1_BIT) +
((StatusValue >> 16) & MASK_8_BITS));
}
EIP76_CHECK_INT_ATMOST(NumberOfBlks, EIP76_REQUEST_DATA_MAX_BLK_COUNT);
// Only data_blocks field is updated in register.
WriteValue = EIP76_REQUEST_DATA |
((NumberOfBlks & MASK_12_BITS) << 20);
EIP76_CONTROL_WR(Device, WriteValue);
#ifdef EIP76_BLOCKS_THRESHOLD_OPTION
// Do not write Threshold when in test mode
if (!(ControlValue & EIP76_ENABLE_TEST_MODE))
{
WriteValue = EIP76_BUFFER_SIZE_RD(Device);
if (WriteValue > 0)
{
NumberOfBlks += ((StatusValue & MASK_1_BIT) +
((StatusValue >> 16) & MASK_8_BITS));
if ( NumberOfBlks > WriteValue)
{
NumberOfBlks = WriteValue;
}
// Set threshold value one less then the needed number of blocks
WriteValue = NumberOfBlks - 1;
// Set the number of blocks in threshold register
EIP76_BLOCKS_THRESHOLD_WR(Device, WriteValue);
}
}
#endif // EIP76_BLOCKS_THRESHOLD_OPTION
}
return EIP76_NO_ERROR;
}
/*----------------------------------------------------------------------------
* EIP76Lib_PostProcessor_Random_Read
*
*/
static EIP76_Status_t
EIP76Lib_Random_Read(
const Device_Handle_t Device,
EIP76_Random128_t * Random128_p)
{
#if EIP76_READ_TIMEOUT > 0
EIP76_INTACK_WR(Device, 0);
Random128_p->word[0] = EIP76_OUTPUT_0_RD(Device);
Random128_p->word[1] = EIP76_OUTPUT_1_RD(Device);
Random128_p->word[2] = EIP76_OUTPUT_2_RD(Device);
Random128_p->word[3] = EIP76_OUTPUT_3_RD(Device);
#else
Random128_p->word[0] = EIP76_OUTPUT_0_RD(Device);
Random128_p->word[1] = EIP76_OUTPUT_1_RD(Device);
Random128_p->word[2] = EIP76_OUTPUT_2_RD(Device);
Random128_p->word[3] = EIP76_OUTPUT_3_RD(Device);
LOG_INFO("8 %s, %x\n", __FUNCTION__, Random128_p->word[0]);
LOG_INFO("8 %s, %x\n", __FUNCTION__, Random128_p->word[1]);
LOG_INFO("8 %s, %x\n", __FUNCTION__, Random128_p->word[2]);
LOG_INFO("8 %s, %x\n", __FUNCTION__, Random128_p->word[3]);
#endif // EIP76_READ_TIMEOUT
return EIP76_NO_ERROR;
}
/*----------------------------------------------------------------------------
* EIP76_Random_IsBusy
*
*/
EIP76_Status_t
EIP76_Random_IsBusy(
EIP76_IOArea_t * const IOArea_p,
EIP76_EventStatus_t * const Events_p)
{
Device_Handle_t Device;
uint32_t StatusRegVal;
EIP76_Status_t rv = EIP76_NO_ERROR;
volatile EIP76_True_IOArea_t * const TrueIOArea_p = IOAREA(IOArea_p);
EIP76_CHECK_POINTER(Events_p);
// No events detected yet
*Events_p = 0;
EIP76_CHECK_POINTER(IOArea_p);
Device = TrueIOArea_p->Device;
StatusRegVal = EIP76_STATUS_RD(Device);
// Store event status with the available random data 128-bit block count
*Events_p = StatusRegVal;
if ( EIP76_STATUS_IS_READY(StatusRegVal))
{
LOG_INFO("6 %s, %d\n", __FUNCTION__, __LINE__);
// Transit to a new state
rv = EIP76_State_Set((volatile EIP76_State_t*)&TrueIOArea_p->State,
EIP76_STATE_RANDOM_READY);
}
else
{
// Keep the state, no random data ready yet
rv = EIP76_BUSY_RETRY_LATER;
}
return rv;
}
/*----------------------------------------------------------------------------
* EIP76_Random_Get
*
*/
EIP76_Status_t
EIP76_Random_Get(
EIP76_IOArea_t * const IOArea_p,
EIP76_Random128_t * Data_p,
const unsigned int NumberCount,
unsigned int * const GeneratedNumberCount_p,
EIP76_EventStatus_t * const Events_p)
{
uint32_t StatusRegVal;
unsigned int i;
Device_Handle_t Device;
EIP76_Status_t rv = EIP76_NO_ERROR;
volatile EIP76_True_IOArea_t * const TrueIOArea_p = IOAREA(IOArea_p);
EIP76_CHECK_POINTER(Events_p);
// No events detected yet
*Events_p = 0;
EIP76_CHECK_POINTER(GeneratedNumberCount_p);
*GeneratedNumberCount_p = 0;
EIP76_CHECK_POINTER(IOArea_p);
EIP76_CHECK_POINTER(Data_p);
EIP76_CHECK_INT_ATLEAST(NumberCount, 1);
Device = TrueIOArea_p->Device;
for (i = 0; i < NumberCount; i++)
{
StatusRegVal = EIP76_STATUS_RD(Device);
// Store event status with the available random data 128-bit block count
*Events_p = StatusRegVal;
if (!EIP76_STATUS_IS_READY(StatusRegVal) )
{
if (i == 0)
{
// Keep the state, no random data ready yet
return EIP76_ILLEGAL_IN_STATE; // May never occur
}
else
{
// Transit to a new state
rv = EIP76_State_Set((volatile EIP76_State_t* const)&TrueIOArea_p->State,
EIP76_STATE_RANDOM_GENERATING);
if (rv != EIP76_NO_ERROR)
{
return EIP76_ILLEGAL_IN_STATE; // May never occur
}
else
{
*GeneratedNumberCount_p = i;
return EIP76_BUSY_RETRY_LATER;
}
}
}
else
{
// Random data is ready, transit to a new state
rv = EIP76_State_Set((volatile EIP76_State_t* const)&TrueIOArea_p->State,
EIP76_STATE_RANDOM_READING);
if (rv != EIP76_NO_ERROR)
{
return EIP76_ILLEGAL_IN_STATE;
}
}
// In the EIP76_STATE_RANDOM_READING state now, random data is ready
#ifdef EIP76_BLOCKS_THRESHOLD_OPTION
// Set Theshold back to 0 to get all data
EIP76_BLOCKS_THRESHOLD_WR(Device, 0);
#endif // EIP76_BLOCKS_THRESHOLD_OPTION
// Read the random number
rv = EIP76Lib_Random_Read(Device, Data_p++);
if (rv != EIP76_NO_ERROR)
{
// Failed to read a random number, transit to a new state
rv = EIP76_State_Set((volatile EIP76_State_t*)&TrueIOArea_p->State,
EIP76_STATE_RANDOM_GENERATING);
if (rv != EIP76_NO_ERROR)
{
return EIP76_ILLEGAL_IN_STATE; // May never occur
}
else
{
return EIP76_RANDOM_READ_ERROR;
}
}
// Acknowledge the read number
LOG_INFO("8 %s, %d\n", __FUNCTION__, __LINE__);
EIP76_INTACK_WR(Device, EIP76_STATUS_READY);
} // for
*GeneratedNumberCount_p = i;
// Transit to a new state
rv = EIP76_State_Set((volatile EIP76_State_t*)&TrueIOArea_p->State,
EIP76_STATE_RANDOM_GENERATING);
return rv;
}
/*----------------------------------------------------------------------------
* EIP76_Alarm_Handle
*
*/
EIP76_Status_t
EIP76_Alarm_Handle(
EIP76_IOArea_t * const IOArea_p,
EIP76_EventStatus_t * const Events_p,
uint32_t * FROAlarmMask_p)
{
uint32_t RegVal;
Device_Handle_t Device;
volatile EIP76_True_IOArea_t * const TrueIOArea_p = IOAREA(IOArea_p);
EIP76_CHECK_POINTER(IOArea_p);
EIP76_CHECK_POINTER(Events_p);
EIP76_CHECK_POINTER(FROAlarmMask_p);
Device = TrueIOArea_p->Device;
// No events detected yet
*Events_p = 0;
RegVal = EIP76_STATUS_RD(Device);
// Store detected events
*Events_p = (RegVal & EIP76_EVENTS_MASK);
#ifndef EIP76_AUTO_DETUNE_OPTION
// Determine what FRO's are stopped
*FROAlarmMask_p = EIP76_ALARMSTOP_RD(Device);
RegVal = ((*FROAlarmMask_p) & ((uint32_t)EIP76_FRO_ENABLED_MASK));
if( RegVal != 0 )
{
// Perform FRO de-tune operation for all the stopped FRO's,
// this must be done before the FRO's are enabled.
// This operations disables the FRO's
EIP76_FRO_DETUNE(Device, RegVal);
// Clear alarm mask
EIP76_ALARMMASK_WR(Device, 0);
// Clear alarm stop mask
EIP76_ALARMSTOP_WR(Device, 0);
// Enable the configured FRO's
EIP76_FROENABLE_WR(Device, EIP76_FRO_ENABLED_MASK);
}
#endif // EIP76_AUTO_DETUNE_OPTION
// Acknowledge the detected alarm events,
// Data ready status bit is not an alarm event
EIP76_INTACK_WR(Device, ((*Events_p) & (~EIP76_STATUS_READY)));
return EIP76_NO_ERROR;
}
/*----------------------------------------------------------------------------
* EIP76_FatalError_Handle
*
*/
EIP76_Status_t
EIP76_FatalError_Handle(
EIP76_IOArea_t * const IOArea_p)
{
uint32_t RegVal;
Device_Handle_t Device;
volatile EIP76_True_IOArea_t * const TrueIOArea_p = IOAREA(IOArea_p);
EIP76_CHECK_POINTER(IOArea_p);
// EIP76_CHECK_POINTER(Events_p);
Device = TrueIOArea_p->Device;
RegVal = EIP76_STATUS_RD(Device);
LOG_INFO("fatal %s, %d\n", __FUNCTION__, __LINE__);
// Check if fatal events are present
if ( (RegVal & (EIP76_STUCK_OUT_EVENT | EIP76_NOISE_FAIL_EVENT)) != 0 )
{
// Acknowledge all the fatal error events before disabling TRNG
EIP76_INTACK_WR(Device,
(EIP76_STUCK_OUT_EVENT |
EIP76_NOISE_FAIL_EVENT |
EIP76_SHUTDOWN_OFLO_EVENT) );
// Acknowledge all the fatal error events before disabling TRNG
EIP76_INTACK_WR(Device,
(EIP76_STUCK_OUT_EVENT |
EIP76_SHUTDOWN_OFLO_EVENT) );
// Disable TRNG
EIP76_CONTROL_WR(Device, 0);
// Transit to a new state
return EIP76_State_Set((volatile EIP76_State_t*)&TrueIOArea_p->State,
EIP76_STATE_RESET);
}
// #if (EIP76_SHUTDOWN_FATAL == 1)
// // Check if fatal events are present
// if ( (RegVal & EIP76_SHUTDOWN_OFLO_EVENT ) != 0 )
// {
// // Acknowledge all the fatal error events before disabling TRNG
// EIP76_INTACK_WR(Device,
// (EIP76_STUCK_OUT_EVENT |
// EIP76_NOISE_FAIL_EVENT |
// EIP76_SHUTDOWN_OFLO_EVENT) );
// // Disable TRNG
// EIP76_CONTROL_WR(Device, 0);
// // Transit to a new state
// return EIP76_State_Set((EIP76_State_t*)&TrueIOArea_p->State,
// EIP76_STATE_RESET);
// }
// #endif
return EIP76_NO_ERROR;
}
/* end of file eip76_random.c */