blob: 34a3e389fa45c9918e78e1595942b80ae8d283dc [file] [log] [blame]
Wilson Ding6d5fad82025-04-22 21:27:55 -07001/*
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
45static 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
59int 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}