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