1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2020, Marvell Technology Group Ltd. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * Based on Linux kernel omap-rng.c - RNG driver for TI OMAP CPU family 5*91f16700Schasinglulu * 6*91f16700Schasinglulu * Author: Deepak Saxena <dsaxena@plexity.net> 7*91f16700Schasinglulu * 8*91f16700Schasinglulu * Copyright 2005 (c) MontaVista Software, Inc. 9*91f16700Schasinglulu * 10*91f16700Schasinglulu * Mostly based on original driver: 11*91f16700Schasinglulu * 12*91f16700Schasinglulu * Copyright (C) 2005 Nokia Corporation 13*91f16700Schasinglulu * Author: Juha Yrjölä <juha.yrjola@nokia.com> 14*91f16700Schasinglulu * 15*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 16*91f16700Schasinglulu */ 17*91f16700Schasinglulu 18*91f16700Schasinglulu #include <assert.h> 19*91f16700Schasinglulu #include <errno.h> 20*91f16700Schasinglulu #include <string.h> 21*91f16700Schasinglulu 22*91f16700Schasinglulu #include <common/debug.h> 23*91f16700Schasinglulu #include <drivers/delay_timer.h> 24*91f16700Schasinglulu #include <drivers/rambus/trng_ip_76.h> 25*91f16700Schasinglulu #include <lib/mmio.h> 26*91f16700Schasinglulu #include <lib/spinlock.h> 27*91f16700Schasinglulu #include <lib/utils.h> 28*91f16700Schasinglulu 29*91f16700Schasinglulu #define RNG_REG_STATUS_RDY (1 << 0) 30*91f16700Schasinglulu 31*91f16700Schasinglulu #define RNG_REG_INTACK_RDY_MASK (1 << 0) 32*91f16700Schasinglulu 33*91f16700Schasinglulu #define RNG_CONTROL_ENABLE_TRNG_MASK (1 << 10) 34*91f16700Schasinglulu 35*91f16700Schasinglulu #define RNG_CONFIG_NOISE_BLOCKS(val) ((0xff & (val)) << 0) 36*91f16700Schasinglulu #define RNG_CONFIG_NOISE_BLK_VAL 0x5 37*91f16700Schasinglulu 38*91f16700Schasinglulu #define RNG_CONFIG_SAMPLE_CYCLES(val) ((0xff & (val)) << 16) 39*91f16700Schasinglulu #define RNG_CONFIG_SAMPLE_CYCLES_VAL 0x22 40*91f16700Schasinglulu 41*91f16700Schasinglulu #define RNG_REG_FRO_ENABLE_MASK 0xffffff 42*91f16700Schasinglulu #define RNG_REG_FRO_DETUNE_MASK 0x0 43*91f16700Schasinglulu 44*91f16700Schasinglulu #define EIP76_RNG_OUTPUT_SIZE 0x10 45*91f16700Schasinglulu #define EIP76_RNG_WAIT_ROUNDS 10 46*91f16700Schasinglulu 47*91f16700Schasinglulu #define RNG_HW_IS_EIP76(ver) ((ver) & (0xff == 0x4C)) 48*91f16700Schasinglulu #define RNG_HW_VER_MAJOR(ver) (((ver) & (0xf << 24)) >> 24) 49*91f16700Schasinglulu #define RNG_HW_VER_MINOR(ver) (((ver) & (0xf << 20)) >> 20) 50*91f16700Schasinglulu #define RNG_HW_VER_PATCH(ver) (((ver) & (0xf << 16)) >> 16) 51*91f16700Schasinglulu 52*91f16700Schasinglulu 53*91f16700Schasinglulu enum { 54*91f16700Schasinglulu RNG_OUTPUT_0_REG = 0, 55*91f16700Schasinglulu RNG_OUTPUT_1_REG, 56*91f16700Schasinglulu RNG_OUTPUT_2_REG, 57*91f16700Schasinglulu RNG_OUTPUT_3_REG, 58*91f16700Schasinglulu RNG_STATUS_REG, 59*91f16700Schasinglulu RNG_INTMASK_REG, 60*91f16700Schasinglulu RNG_INTACK_REG, 61*91f16700Schasinglulu RNG_CONTROL_REG, 62*91f16700Schasinglulu RNG_CONFIG_REG, 63*91f16700Schasinglulu RNG_ALARMCNT_REG, 64*91f16700Schasinglulu RNG_FROENABLE_REG, 65*91f16700Schasinglulu RNG_FRODETUNE_REG, 66*91f16700Schasinglulu RNG_ALARMMASK_REG, 67*91f16700Schasinglulu RNG_ALARMSTOP_REG, 68*91f16700Schasinglulu RNG_REV_REG 69*91f16700Schasinglulu }; 70*91f16700Schasinglulu 71*91f16700Schasinglulu static uint16_t reg_map_eip76[] = { 72*91f16700Schasinglulu [RNG_OUTPUT_0_REG] = 0x0, 73*91f16700Schasinglulu [RNG_OUTPUT_1_REG] = 0x4, 74*91f16700Schasinglulu [RNG_OUTPUT_2_REG] = 0x8, 75*91f16700Schasinglulu [RNG_OUTPUT_3_REG] = 0xc, 76*91f16700Schasinglulu [RNG_STATUS_REG] = 0x10, 77*91f16700Schasinglulu [RNG_INTACK_REG] = 0x10, 78*91f16700Schasinglulu [RNG_CONTROL_REG] = 0x14, 79*91f16700Schasinglulu [RNG_CONFIG_REG] = 0x18, 80*91f16700Schasinglulu [RNG_ALARMCNT_REG] = 0x1c, 81*91f16700Schasinglulu [RNG_FROENABLE_REG] = 0x20, 82*91f16700Schasinglulu [RNG_FRODETUNE_REG] = 0x24, 83*91f16700Schasinglulu [RNG_ALARMMASK_REG] = 0x28, 84*91f16700Schasinglulu [RNG_ALARMSTOP_REG] = 0x2c, 85*91f16700Schasinglulu [RNG_REV_REG] = 0x7c, 86*91f16700Schasinglulu }; 87*91f16700Schasinglulu 88*91f16700Schasinglulu struct eip76_rng_dev { 89*91f16700Schasinglulu uintptr_t base; 90*91f16700Schasinglulu uint16_t *regs; 91*91f16700Schasinglulu }; 92*91f16700Schasinglulu 93*91f16700Schasinglulu /* Locals */ 94*91f16700Schasinglulu static struct eip76_rng_dev eip76_dev; 95*91f16700Schasinglulu static spinlock_t rng_lock; 96*91f16700Schasinglulu 97*91f16700Schasinglulu static inline uint32_t eip76_rng_read(struct eip76_rng_dev *dev, uint16_t reg) 98*91f16700Schasinglulu { 99*91f16700Schasinglulu return mmio_read_32(dev->base + dev->regs[reg]); 100*91f16700Schasinglulu } 101*91f16700Schasinglulu 102*91f16700Schasinglulu static inline void eip76_rng_write(struct eip76_rng_dev *dev, 103*91f16700Schasinglulu uint16_t reg, uint32_t val) 104*91f16700Schasinglulu { 105*91f16700Schasinglulu mmio_write_32(dev->base + dev->regs[reg], val); 106*91f16700Schasinglulu } 107*91f16700Schasinglulu 108*91f16700Schasinglulu static void eip76_rng_init(struct eip76_rng_dev *dev) 109*91f16700Schasinglulu { 110*91f16700Schasinglulu uint32_t val; 111*91f16700Schasinglulu 112*91f16700Schasinglulu /* Return if RNG is already running. */ 113*91f16700Schasinglulu if (eip76_rng_read(dev, RNG_CONTROL_REG) & 114*91f16700Schasinglulu RNG_CONTROL_ENABLE_TRNG_MASK) { 115*91f16700Schasinglulu return; 116*91f16700Schasinglulu } 117*91f16700Schasinglulu 118*91f16700Schasinglulu /* This field sets the number of 512-bit blocks of raw Noise Source 119*91f16700Schasinglulu * output data that must be processed by either the Conditioning 120*91f16700Schasinglulu * Function or the SP 800-90 DRBG ‘BC_DF’ functionality to yield 121*91f16700Schasinglulu * a ‘full entropy’ output value. As according to [SP 800-90B draft] 122*91f16700Schasinglulu * the amount of entropy input to this functionality must be twice 123*91f16700Schasinglulu * the amount that is output and the 8-bit samples output by the Noise 124*91f16700Schasinglulu * Source are supposed to have one bit of entropy each, the settings 125*91f16700Schasinglulu * for this field are as follows: 126*91f16700Schasinglulu * - SHA-1 Conditioning Function: 127*91f16700Schasinglulu * generates 160 bits output, requiring 2560 sample bits, 128*91f16700Schasinglulu * equivalent to 5 blocks of raw Noise Source input. 129*91f16700Schasinglulu * - SHA-256 Conditioning Function: 130*91f16700Schasinglulu * generates 256 bits output, requiring 4096 sample bits, equivalent 131*91f16700Schasinglulu * to 8 blocks of raw Noise Source input. Note that two blocks of 256 132*91f16700Schasinglulu * bits are needed to start or re-seed the SP 800-90 DRBG 133*91f16700Schasinglulu * (in the EIP-76d-*-SHA2 configurations) 134*91f16700Schasinglulu * - SP 800-90 DRBG ‘BC_DF’ functionality: 135*91f16700Schasinglulu * generates 384 bits output, requiring 6144 sample bits, equivalent 136*91f16700Schasinglulu * to 12 blocks of raw Noise Source input. 137*91f16700Schasinglulu * This field can only be modified when ‘enable_trng’ in TRNG_CONTROL 138*91f16700Schasinglulu * is ‘0’ or when either of the ‘test_known_noise’ or ‘test_cond_func’ 139*91f16700Schasinglulu * bits in TRNG_TEST is ‘1’. Value 0 in this field selects 256 blocks 140*91f16700Schasinglulu * of 512 bits to be processed. 141*91f16700Schasinglulu */ 142*91f16700Schasinglulu val = RNG_CONFIG_NOISE_BLOCKS(RNG_CONFIG_NOISE_BLK_VAL); 143*91f16700Schasinglulu 144*91f16700Schasinglulu /* This field sets the number of FRO samples that are XOR-ed together 145*91f16700Schasinglulu * into one bit to be shifted into the main shift register. 146*91f16700Schasinglulu * This value must be such that there is at least one bit of entropy 147*91f16700Schasinglulu * (in total) in each 8 bits that are shifted. 148*91f16700Schasinglulu * This field can only be modified when ‘enable_trng’ in TRNG_CONTROL 149*91f16700Schasinglulu * is ‘0’ or when either of the ‘test_known_noise’ or ‘test_cond_func’ 150*91f16700Schasinglulu * bits in TRNG_TEST is ‘1’. Value 0 in this field selects 65536 FRO 151*91f16700Schasinglulu * samples to be XOR-ed together 152*91f16700Schasinglulu */ 153*91f16700Schasinglulu val |= RNG_CONFIG_SAMPLE_CYCLES(RNG_CONFIG_SAMPLE_CYCLES_VAL); 154*91f16700Schasinglulu eip76_rng_write(dev, RNG_CONFIG_REG, val); 155*91f16700Schasinglulu 156*91f16700Schasinglulu /* Enable all available FROs */ 157*91f16700Schasinglulu eip76_rng_write(dev, RNG_FRODETUNE_REG, RNG_REG_FRO_DETUNE_MASK); 158*91f16700Schasinglulu eip76_rng_write(dev, RNG_FROENABLE_REG, RNG_REG_FRO_ENABLE_MASK); 159*91f16700Schasinglulu 160*91f16700Schasinglulu /* Enable TRNG */ 161*91f16700Schasinglulu eip76_rng_write(dev, RNG_CONTROL_REG, RNG_CONTROL_ENABLE_TRNG_MASK); 162*91f16700Schasinglulu } 163*91f16700Schasinglulu 164*91f16700Schasinglulu int32_t eip76_rng_read_rand_buf(void *data, bool wait) 165*91f16700Schasinglulu { 166*91f16700Schasinglulu uint32_t i, present; 167*91f16700Schasinglulu 168*91f16700Schasinglulu if (!eip76_dev.base) /* not initialized */ 169*91f16700Schasinglulu return -1; 170*91f16700Schasinglulu 171*91f16700Schasinglulu for (i = 0; i < EIP76_RNG_WAIT_ROUNDS; i++) { 172*91f16700Schasinglulu present = eip76_rng_read(&eip76_dev, RNG_STATUS_REG) & 173*91f16700Schasinglulu RNG_REG_STATUS_RDY; 174*91f16700Schasinglulu if (present || !wait) { 175*91f16700Schasinglulu break; 176*91f16700Schasinglulu } 177*91f16700Schasinglulu 178*91f16700Schasinglulu udelay(10); 179*91f16700Schasinglulu } 180*91f16700Schasinglulu 181*91f16700Schasinglulu if (present != 0U) { 182*91f16700Schasinglulu return 0; 183*91f16700Schasinglulu } 184*91f16700Schasinglulu 185*91f16700Schasinglulu memcpy(data, 186*91f16700Schasinglulu (void *)(eip76_dev.base + eip76_dev.regs[RNG_OUTPUT_0_REG]), 187*91f16700Schasinglulu EIP76_RNG_OUTPUT_SIZE); 188*91f16700Schasinglulu 189*91f16700Schasinglulu eip76_rng_write(&eip76_dev, RNG_INTACK_REG, RNG_REG_INTACK_RDY_MASK); 190*91f16700Schasinglulu 191*91f16700Schasinglulu return EIP76_RNG_OUTPUT_SIZE; 192*91f16700Schasinglulu } 193*91f16700Schasinglulu 194*91f16700Schasinglulu int32_t eip76_rng_probe(uintptr_t base_addr) 195*91f16700Schasinglulu { 196*91f16700Schasinglulu uint32_t ver; 197*91f16700Schasinglulu 198*91f16700Schasinglulu eip76_dev.base = base_addr; 199*91f16700Schasinglulu eip76_dev.regs = reg_map_eip76; 200*91f16700Schasinglulu 201*91f16700Schasinglulu eip76_rng_init(&eip76_dev); 202*91f16700Schasinglulu 203*91f16700Schasinglulu ver = eip76_rng_read(&eip76_dev, RNG_REV_REG); 204*91f16700Schasinglulu 205*91f16700Schasinglulu INFO("%s Random Number Generator HW ver. %01x.%01x.%01x\n", 206*91f16700Schasinglulu RNG_HW_IS_EIP76(ver) ? "TRNG-IP-76" : "Unknown", 207*91f16700Schasinglulu RNG_HW_VER_MAJOR(ver), RNG_HW_VER_MINOR(ver), 208*91f16700Schasinglulu RNG_HW_VER_PATCH(ver)); 209*91f16700Schasinglulu 210*91f16700Schasinglulu return 0; 211*91f16700Schasinglulu } 212*91f16700Schasinglulu 213*91f16700Schasinglulu int32_t eip76_rng_get_random(uint8_t *data, uint32_t len) 214*91f16700Schasinglulu { 215*91f16700Schasinglulu static uint8_t rand[EIP76_RNG_OUTPUT_SIZE]; 216*91f16700Schasinglulu static uint8_t pos; 217*91f16700Schasinglulu uint32_t i; 218*91f16700Schasinglulu int32_t ret = 0; 219*91f16700Schasinglulu 220*91f16700Schasinglulu if (!data) 221*91f16700Schasinglulu return -1; 222*91f16700Schasinglulu 223*91f16700Schasinglulu spin_lock(&rng_lock); 224*91f16700Schasinglulu 225*91f16700Schasinglulu for (i = 0; i < len; i++) { 226*91f16700Schasinglulu if (pos >= EIP76_RNG_OUTPUT_SIZE) { 227*91f16700Schasinglulu pos = 0; 228*91f16700Schasinglulu } 229*91f16700Schasinglulu 230*91f16700Schasinglulu if (pos != 0U) { 231*91f16700Schasinglulu ret = eip76_rng_read_rand_buf(rand, true); 232*91f16700Schasinglulu } 233*91f16700Schasinglulu 234*91f16700Schasinglulu /* Only advance FIFO index if it is non zero or 235*91f16700Schasinglulu * the update from TRNG HW was successful 236*91f16700Schasinglulu */ 237*91f16700Schasinglulu if (pos || ret > 0) { 238*91f16700Schasinglulu data[i] = rand[pos++]; 239*91f16700Schasinglulu ret = 0; 240*91f16700Schasinglulu } else { 241*91f16700Schasinglulu ret = -1; 242*91f16700Schasinglulu break; 243*91f16700Schasinglulu } 244*91f16700Schasinglulu } 245*91f16700Schasinglulu 246*91f16700Schasinglulu spin_unlock(&rng_lock); 247*91f16700Schasinglulu 248*91f16700Schasinglulu return ret; 249*91f16700Schasinglulu } 250