xref: /rk3399_ARM-atf/drivers/marvell/trng.c (revision 05d22c3045e2e972c2262b9ccd6c82cb7545bf83)
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