blob: 8ea00e3e890c223e86864e68510b087021820c14 [file] [log] [blame]
Sughosh Ganu231ec902019-12-28 23:58:29 +05301// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2019, Linaro Limited
4 */
5
Heinrich Schuchardtcf0bf892020-09-17 16:49:02 +02006#define LOG_CATEGORY UCLASS_RNG
7
Sughosh Ganu231ec902019-12-28 23:58:29 +05308#include <common.h>
9#include <clk.h>
10#include <dm.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060011#include <log.h>
Sughosh Ganu231ec902019-12-28 23:58:29 +053012#include <reset.h>
13#include <rng.h>
Simon Glasscd93d622020-05-10 11:40:13 -060014#include <linux/bitops.h>
Simon Glassc05ed002020-05-10 11:40:11 -060015#include <linux/delay.h>
Sughosh Ganu231ec902019-12-28 23:58:29 +053016
17#include <asm/io.h>
18#include <linux/iopoll.h>
19#include <linux/kernel.h>
20
21#define RNG_CR 0x00
22#define RNG_CR_RNGEN BIT(2)
23#define RNG_CR_CED BIT(5)
24
25#define RNG_SR 0x04
26#define RNG_SR_SEIS BIT(6)
27#define RNG_SR_CEIS BIT(5)
28#define RNG_SR_SECS BIT(2)
29#define RNG_SR_DRDY BIT(0)
30
31#define RNG_DR 0x08
32
Simon Glass8a8d24b2020-12-03 16:55:23 -070033struct stm32_rng_plat {
Sughosh Ganu231ec902019-12-28 23:58:29 +053034 fdt_addr_t base;
35 struct clk clk;
36 struct reset_ctl rst;
37};
38
39static int stm32_rng_read(struct udevice *dev, void *data, size_t len)
40{
Heinrich Schuchardt250b3032020-02-16 10:11:18 +010041 int retval, i;
Sughosh Ganu231ec902019-12-28 23:58:29 +053042 u32 sr, count, reg;
43 size_t increment;
Simon Glass8a8d24b2020-12-03 16:55:23 -070044 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganu231ec902019-12-28 23:58:29 +053045
46 while (len > 0) {
47 retval = readl_poll_timeout(pdata->base + RNG_SR, sr,
48 sr & RNG_SR_DRDY, 10000);
49 if (retval)
50 return retval;
51
52 if (sr & (RNG_SR_SEIS | RNG_SR_SECS)) {
53 /* As per SoC TRM */
54 clrbits_le32(pdata->base + RNG_SR, RNG_SR_SEIS);
55 for (i = 0; i < 12; i++)
56 readl(pdata->base + RNG_DR);
57 if (readl(pdata->base + RNG_SR) & RNG_SR_SEIS) {
Heinrich Schuchardtcf0bf892020-09-17 16:49:02 +020058 log_err("RNG Noise");
Sughosh Ganu231ec902019-12-28 23:58:29 +053059 return -EIO;
60 }
61 /* start again */
62 continue;
63 }
64
65 /*
66 * Once the DRDY bit is set, the RNG_DR register can
67 * be read four consecutive times.
68 */
69 count = 4;
70 while (len && count) {
71 reg = readl(pdata->base + RNG_DR);
72 memcpy(data, &reg, min(len, sizeof(u32)));
73 increment = min(len, sizeof(u32));
74 data += increment;
75 len -= increment;
76 count--;
77 }
78 }
79
80 return 0;
81}
82
Simon Glass8a8d24b2020-12-03 16:55:23 -070083static int stm32_rng_init(struct stm32_rng_plat *pdata)
Sughosh Ganu231ec902019-12-28 23:58:29 +053084{
85 int err;
86
87 err = clk_enable(&pdata->clk);
88 if (err)
89 return err;
90
91 /* Disable CED */
92 writel(RNG_CR_RNGEN | RNG_CR_CED, pdata->base + RNG_CR);
93
94 /* clear error indicators */
95 writel(0, pdata->base + RNG_SR);
96
97 return 0;
98}
99
Simon Glass8a8d24b2020-12-03 16:55:23 -0700100static int stm32_rng_cleanup(struct stm32_rng_plat *pdata)
Sughosh Ganu231ec902019-12-28 23:58:29 +0530101{
102 writel(0, pdata->base + RNG_CR);
103
104 return clk_disable(&pdata->clk);
105}
106
107static int stm32_rng_probe(struct udevice *dev)
108{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700109 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganu231ec902019-12-28 23:58:29 +0530110
111 reset_assert(&pdata->rst);
112 udelay(20);
113 reset_deassert(&pdata->rst);
114
115 return stm32_rng_init(pdata);
116}
117
118static int stm32_rng_remove(struct udevice *dev)
119{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700120 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganu231ec902019-12-28 23:58:29 +0530121
122 return stm32_rng_cleanup(pdata);
123}
124
Simon Glassd1998a92020-12-03 16:55:21 -0700125static int stm32_rng_of_to_plat(struct udevice *dev)
Sughosh Ganu231ec902019-12-28 23:58:29 +0530126{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700127 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganu231ec902019-12-28 23:58:29 +0530128 int err;
129
130 pdata->base = dev_read_addr(dev);
131 if (!pdata->base)
132 return -ENOMEM;
133
134 err = clk_get_by_index(dev, 0, &pdata->clk);
135 if (err)
136 return err;
137
138 err = reset_get_by_index(dev, 0, &pdata->rst);
139 if (err)
140 return err;
141
142 return 0;
143}
144
145static const struct dm_rng_ops stm32_rng_ops = {
146 .read = stm32_rng_read,
147};
148
149static const struct udevice_id stm32_rng_match[] = {
150 {
151 .compatible = "st,stm32-rng",
152 },
153 {},
154};
155
156U_BOOT_DRIVER(stm32_rng) = {
157 .name = "stm32-rng",
158 .id = UCLASS_RNG,
159 .of_match = stm32_rng_match,
160 .ops = &stm32_rng_ops,
161 .probe = stm32_rng_probe,
162 .remove = stm32_rng_remove,
Simon Glass8a8d24b2020-12-03 16:55:23 -0700163 .plat_auto = sizeof(struct stm32_rng_plat),
Simon Glassd1998a92020-12-03 16:55:21 -0700164 .of_to_plat = stm32_rng_of_to_plat,
Sughosh Ganu231ec902019-12-28 23:58:29 +0530165};