xref: /rk3399_ARM-atf/drivers/marvell/trng.c (revision 4301798db0966aeddfa3b97cd637bdbae10e0919)
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 Ding static 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 Ding int 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