blob: 31706960157c904360650c7642dfc9ee36283e55 [file] [log] [blame]
Kshitiz Varshney8428a492022-12-22 09:50:27 +01001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * RNG driver for Freescale RNGC
4 *
5 * Copyright 2022 NXP
6 *
7 * Based on RNGC driver in drivers/char/hw_random/imx-rngc.c in Linux
8 */
9
10#include <common.h>
11#include <cpu_func.h>
12#include <dm.h>
13#include <rng.h>
14#include <asm/cache.h>
15#include <asm/io.h>
16#include <dm/root.h>
17#include <linux/delay.h>
18#include <linux/kernel.h>
19
20#define DCP_RNG_MAX_FIFO_STORE_SIZE 4
21#define RNGC_VER_ID 0x0
22#define RNGC_COMMAND 0x4
23#define RNGC_CONTROL 0x8
24#define RNGC_STATUS 0xC
25#define RNGC_ERROR 0x10
26#define RNGC_FIFO 0x14
27
28/* the fields in the ver id register */
29#define RNGC_TYPE_SHIFT 28
30
31/* the rng_type field */
32#define RNGC_TYPE_RNGB 0x1
33#define RNGC_TYPE_RNGC 0x2
34
35#define RNGC_CMD_CLR_ERR 0x20
36#define RNGC_CMD_SEED 0x2
37
38#define RNGC_CTRL_AUTO_SEED 0x10
39
40#define RNGC_STATUS_ERROR 0x10000
41#define RNGC_STATUS_FIFO_LEVEL_MASK 0xf00
42#define RNGC_STATUS_FIFO_LEVEL_SHIFT 8
43#define RNGC_STATUS_SEED_DONE 0x20
44#define RNGC_STATUS_ST_DONE 0x10
45
46#define RNGC_ERROR_STATUS_STAT_ERR 0x8
47
48#define RNGC_TIMEOUT 3000000U /* 3 sec */
49
50struct imx_rngc_priv {
51 unsigned long base;
52};
53
54static int rngc_read(struct udevice *dev, void *data, size_t len)
55{
56 struct imx_rngc_priv *priv = dev_get_priv(dev);
57 u8 buffer[DCP_RNG_MAX_FIFO_STORE_SIZE];
58 u32 status, level;
59 size_t size;
60
61 while (len) {
62 status = readl(priv->base + RNGC_STATUS);
63
64 /* is there some error while reading this random number? */
65 if (status & RNGC_STATUS_ERROR)
66 break;
67 /* how many random numbers are in FIFO? [0-16] */
68 level = (status & RNGC_STATUS_FIFO_LEVEL_MASK) >>
69 RNGC_STATUS_FIFO_LEVEL_SHIFT;
70
71 if (level) {
72 /* retrieve a random number from FIFO */
73 *(u32 *)buffer = readl(priv->base + RNGC_FIFO);
74 size = min(len, sizeof(u32));
75 memcpy(data, buffer, size);
76 data += size;
77 len -= size;
78 }
79 }
80
81 return len ? -EIO : 0;
82}
83
84static int rngc_init(struct imx_rngc_priv *priv)
85{
86 u32 cmd, ctrl, status, err_reg = 0;
87 unsigned long long timeval = 0;
88 unsigned long long timeout = RNGC_TIMEOUT;
89
90 /* clear error */
91 cmd = readl(priv->base + RNGC_COMMAND);
92 writel(cmd | RNGC_CMD_CLR_ERR, priv->base + RNGC_COMMAND);
93
94 /* create seed, repeat while there is some statistical error */
95 do {
96 /* seed creation */
97 cmd = readl(priv->base + RNGC_COMMAND);
98 writel(cmd | RNGC_CMD_SEED, priv->base + RNGC_COMMAND);
99
100 udelay(1);
101 timeval += 1;
102
103 status = readl(priv->base + RNGC_STATUS);
104 err_reg = readl(priv->base + RNGC_ERROR);
105
106 if (status & (RNGC_STATUS_SEED_DONE | RNGC_STATUS_ST_DONE))
107 break;
108
109 if (timeval > timeout) {
110 debug("rngc timed out\n");
111 return -ETIMEDOUT;
112 }
113 } while (err_reg == RNGC_ERROR_STATUS_STAT_ERR);
114
115 if (err_reg)
116 return -EIO;
117
118 /*
119 * enable automatic seeding, the rngc creates a new seed automatically
120 * after serving 2^20 random 160-bit words
121 */
122 ctrl = readl(priv->base + RNGC_CONTROL);
123 ctrl |= RNGC_CTRL_AUTO_SEED;
124 writel(ctrl, priv->base + RNGC_CONTROL);
125 return 0;
126}
127
128static int rngc_probe(struct udevice *dev)
129{
130 struct imx_rngc_priv *priv = dev_get_priv(dev);
131 fdt_addr_t addr;
132 u32 ver_id;
133 u8 rng_type;
134 int ret;
135
136 addr = dev_read_addr(dev);
137 if (addr == FDT_ADDR_T_NONE) {
138 ret = -EINVAL;
139 goto err;
140 }
141
142 priv->base = addr;
143 ver_id = readl(priv->base + RNGC_VER_ID);
144 rng_type = ver_id >> RNGC_TYPE_SHIFT;
145 /*
146 * This driver supports only RNGC and RNGB. (There's a different
147 * driver for RNGA.)
148 */
149 if (rng_type != RNGC_TYPE_RNGC && rng_type != RNGC_TYPE_RNGB) {
150 ret = -ENODEV;
151 goto err;
152 }
153
154 ret = rngc_init(priv);
155 if (ret)
156 goto err;
157
158 return 0;
159
160err:
161 printf("%s error = %d\n", __func__, ret);
162 return ret;
163}
164
165static const struct dm_rng_ops rngc_ops = {
166 .read = rngc_read,
167};
168
169static const struct udevice_id rngc_dt_ids[] = {
170 { .compatible = "fsl,imx25-rngb" },
171 { }
172};
173
174U_BOOT_DRIVER(dcp_rng) = {
175 .name = "dcp_rng",
176 .id = UCLASS_RNG,
177 .of_match = rngc_dt_ids,
178 .ops = &rngc_ops,
179 .probe = rngc_probe,
180 .priv_auto = sizeof(struct imx_rngc_priv),
181 .flags = DM_FLAG_ALLOC_PRIV_DMA,
182};