1*6d5fad8dSWilson Ding /* 2*6d5fad8dSWilson Ding * Copyright (c) 2025, Marvell Technology Group Ltd. All rights reserved. 3*6d5fad8dSWilson Ding * 4*6d5fad8dSWilson Ding * SPDX-License-Identifier: BSD-3-Clause 5*6d5fad8dSWilson Ding */ 6*6d5fad8dSWilson Ding 7*6d5fad8dSWilson Ding #include <common/debug.h> 8*6d5fad8dSWilson Ding #include <drivers/delay_timer.h> 9*6d5fad8dSWilson Ding #include <lib/mmio.h> 10*6d5fad8dSWilson Ding 11*6d5fad8dSWilson Ding #include <mvebu_def.h> 12*6d5fad8dSWilson Ding 13*6d5fad8dSWilson Ding /* Bind to first CP110's EIP-76 engine only */ 14*6d5fad8dSWilson Ding #define CP110_TRNG_REGS_BASE (MVEBU_CP_REGS_BASE(0) + 0x760000U) 15*6d5fad8dSWilson Ding 16*6d5fad8dSWilson Ding /* EIP-76 Register Definitions */ 17*6d5fad8dSWilson Ding #define CP110_TRNG_OUTPUT_REG(n) (CP110_TRNG_REGS_BASE + ((n) * 0x4U)) 18*6d5fad8dSWilson Ding #define CP110_TRNG_STAT_N_ACK_REG (CP110_TRNG_REGS_BASE + 0x10U) 19*6d5fad8dSWilson Ding #define CP110_TRNG_CONTROL_REG (CP110_TRNG_REGS_BASE + 0x14U) 20*6d5fad8dSWilson Ding #define CP110_TRNG_CONFIG_REG (CP110_TRNG_REGS_BASE + 0x18U) 21*6d5fad8dSWilson Ding #define CP110_TRNG_FRO_ENABLE_REG (CP110_TRNG_REGS_BASE + 0x20U) 22*6d5fad8dSWilson Ding #define CP110_TRNG_FRO_DETUNE_REG (CP110_TRNG_REGS_BASE + 0x24U) 23*6d5fad8dSWilson Ding 24*6d5fad8dSWilson Ding /* CP110_TRNG_STAT_N_ACK_REG */ 25*6d5fad8dSWilson Ding #define CP110_TRNG_READY BIT(0) 26*6d5fad8dSWilson Ding 27*6d5fad8dSWilson Ding /* CP110_TRNG_CONTROL_REG */ 28*6d5fad8dSWilson Ding #define CP110_TRNG_EN BIT(10) 29*6d5fad8dSWilson Ding 30*6d5fad8dSWilson Ding /* CP110_TRNG_CONFIG_REG */ 31*6d5fad8dSWilson Ding #define CP110_TRNG_NOISE_BLOCKS_SHIFT 0U 32*6d5fad8dSWilson Ding #define CP110_TRNG_NOISE_BLOCKS_MASK (0xFFU << CP110_TRNG_NOISE_BLOCKS_SHIFT) 33*6d5fad8dSWilson Ding #define CP110_TRNG_SAMPLE_CYCLES_SHIFT 16U 34*6d5fad8dSWilson Ding #define CP110_TRNG_SAMPLE_CYCLES_MASK (0xFFU << CP110_TRNG_SAMPLE_CYCLES_SHIFT) 35*6d5fad8dSWilson Ding 36*6d5fad8dSWilson Ding /* CP110_TRNG_FRO_ENABLE_REG */ 37*6d5fad8dSWilson Ding #define CP110_TRNG_FRO_EN_SHIFT 0U 38*6d5fad8dSWilson Ding #define CP110_TRNG_FRO_EN_MASK (0xFFFFFFU << CP110_TRNG_FRO_EN_SHIFT) 39*6d5fad8dSWilson Ding 40*6d5fad8dSWilson Ding #define CP110_TRNG_MAX_OUTPUTS 4U 41*6d5fad8dSWilson Ding 42*6d5fad8dSWilson Ding /* maximum busy wait */ 43*6d5fad8dSWilson Ding #define CP110_TRNG_MAX_RETRIES 3U 44*6d5fad8dSWilson Ding mv_trng_init(void)45*6d5fad8dSWilson Dingstatic void mv_trng_init(void) 46*6d5fad8dSWilson Ding { 47*6d5fad8dSWilson Ding uint32_t val; 48*6d5fad8dSWilson Ding 49*6d5fad8dSWilson Ding val = (0x5U << CP110_TRNG_NOISE_BLOCKS_SHIFT) & CP110_TRNG_NOISE_BLOCKS_MASK; 50*6d5fad8dSWilson Ding val |= (0x22U << CP110_TRNG_SAMPLE_CYCLES_SHIFT) & CP110_TRNG_SAMPLE_CYCLES_MASK; 51*6d5fad8dSWilson Ding mmio_write_32(CP110_TRNG_CONFIG_REG, val); 52*6d5fad8dSWilson Ding 53*6d5fad8dSWilson Ding mmio_write_32(CP110_TRNG_FRO_DETUNE_REG, 0U); 54*6d5fad8dSWilson Ding mmio_write_32(CP110_TRNG_FRO_ENABLE_REG, CP110_TRNG_FRO_EN_MASK); 55*6d5fad8dSWilson Ding 56*6d5fad8dSWilson Ding mmio_write_32(CP110_TRNG_CONTROL_REG, CP110_TRNG_EN); 57*6d5fad8dSWilson Ding } 58*6d5fad8dSWilson Ding mv_trng_get_random32(uint32_t * rand,uint8_t num)59*6d5fad8dSWilson Dingint mv_trng_get_random32(uint32_t *rand, uint8_t num) 60*6d5fad8dSWilson Ding { 61*6d5fad8dSWilson Ding uint32_t val; 62*6d5fad8dSWilson Ding uint8_t i; 63*6d5fad8dSWilson Ding 64*6d5fad8dSWilson Ding if (num > CP110_TRNG_MAX_OUTPUTS) { 65*6d5fad8dSWilson Ding return -1; 66*6d5fad8dSWilson Ding } 67*6d5fad8dSWilson Ding 68*6d5fad8dSWilson Ding val = mmio_read_32(CP110_TRNG_CONTROL_REG); 69*6d5fad8dSWilson Ding if ((val & CP110_TRNG_EN) != 0U) { 70*6d5fad8dSWilson Ding /* Flush the staled output data */ 71*6d5fad8dSWilson Ding val = mmio_read_32(CP110_TRNG_STAT_N_ACK_REG); 72*6d5fad8dSWilson Ding if ((val & CP110_TRNG_READY) != 0U) { 73*6d5fad8dSWilson Ding mmio_write_32(CP110_TRNG_STAT_N_ACK_REG, CP110_TRNG_READY); 74*6d5fad8dSWilson Ding } 75*6d5fad8dSWilson Ding } else { 76*6d5fad8dSWilson Ding mv_trng_init(); 77*6d5fad8dSWilson Ding /* Necessary delay for the warm-up */ 78*6d5fad8dSWilson Ding udelay(200U); 79*6d5fad8dSWilson Ding } 80*6d5fad8dSWilson Ding 81*6d5fad8dSWilson Ding 82*6d5fad8dSWilson Ding for (i = 0U; i < CP110_TRNG_MAX_RETRIES; i++) { 83*6d5fad8dSWilson Ding val = mmio_read_32(CP110_TRNG_STAT_N_ACK_REG); 84*6d5fad8dSWilson Ding if ((val & CP110_TRNG_READY) != 0U) { 85*6d5fad8dSWilson Ding break; 86*6d5fad8dSWilson Ding } 87*6d5fad8dSWilson Ding udelay(1U); 88*6d5fad8dSWilson Ding } 89*6d5fad8dSWilson Ding 90*6d5fad8dSWilson Ding if (i == CP110_TRNG_MAX_RETRIES) { 91*6d5fad8dSWilson Ding return -1; 92*6d5fad8dSWilson Ding } 93*6d5fad8dSWilson Ding 94*6d5fad8dSWilson Ding for (i = 0U; i < num; i++) { 95*6d5fad8dSWilson Ding rand[i] = mmio_read_32(CP110_TRNG_OUTPUT_REG(i)); 96*6d5fad8dSWilson Ding } 97*6d5fad8dSWilson Ding 98*6d5fad8dSWilson Ding return 0; 99*6d5fad8dSWilson Ding } 100