blob: f943acd7d22b1665d1129459125e11c922a9af26 [file] [log] [blame]
Sughosh Ganucd9a2f92019-12-28 23:58:29 +05301// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2019, Linaro Limited
4 */
5
Heinrich Schuchardtd909bab2020-09-17 16:49:02 +02006#define LOG_CATEGORY UCLASS_RNG
7
Sughosh Ganucd9a2f92019-12-28 23:58:29 +05308#include <common.h>
9#include <clk.h>
10#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053012#include <reset.h>
13#include <rng.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060014#include <linux/bitops.h>
Simon Glassdbd79542020-05-10 11:40:11 -060015#include <linux/delay.h>
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053016
17#include <asm/io.h>
18#include <linux/iopoll.h>
19#include <linux/kernel.h>
20
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +020021#define RNG_CR 0x00
22#define RNG_CR_RNGEN BIT(2)
23#define RNG_CR_CED BIT(5)
24#define RNG_CR_CLKDIV_SHIFT 16
25#define RNG_CR_CONDRST BIT(30)
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053026
Lionel Debieve71f44212022-06-30 10:20:15 +020027#define RNG_SR 0x04
28#define RNG_SR_SEIS BIT(6)
29#define RNG_SR_CEIS BIT(5)
30#define RNG_SR_SECS BIT(2)
31#define RNG_SR_DRDY BIT(0)
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053032
Lionel Debieve71f44212022-06-30 10:20:15 +020033#define RNG_DR 0x08
34
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +020035/*
36 * struct stm32_rng_data - RNG compat data
37 *
38 * @max_clock_rate: Max RNG clock frequency, in Hertz
39 * @has_cond_reset: True if conditionnal reset is supported
40 *
41 */
Lionel Debieve71f44212022-06-30 10:20:15 +020042struct stm32_rng_data {
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +020043 uint max_clock_rate;
Lionel Debieve71f44212022-06-30 10:20:15 +020044 bool has_cond_reset;
45};
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053046
Simon Glassb75b15b2020-12-03 16:55:23 -070047struct stm32_rng_plat {
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053048 fdt_addr_t base;
49 struct clk clk;
50 struct reset_ctl rst;
Lionel Debieve71f44212022-06-30 10:20:15 +020051 const struct stm32_rng_data *data;
Gatien Chevalliere2acc952023-09-19 17:27:55 +020052 bool ced;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053053};
54
55static int stm32_rng_read(struct udevice *dev, void *data, size_t len)
56{
Heinrich Schuchardt2b39a032020-02-16 10:11:18 +010057 int retval, i;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053058 u32 sr, count, reg;
59 size_t increment;
Simon Glassb75b15b2020-12-03 16:55:23 -070060 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053061
62 while (len > 0) {
63 retval = readl_poll_timeout(pdata->base + RNG_SR, sr,
64 sr & RNG_SR_DRDY, 10000);
65 if (retval)
66 return retval;
67
68 if (sr & (RNG_SR_SEIS | RNG_SR_SECS)) {
69 /* As per SoC TRM */
70 clrbits_le32(pdata->base + RNG_SR, RNG_SR_SEIS);
71 for (i = 0; i < 12; i++)
72 readl(pdata->base + RNG_DR);
73 if (readl(pdata->base + RNG_SR) & RNG_SR_SEIS) {
Heinrich Schuchardtd909bab2020-09-17 16:49:02 +020074 log_err("RNG Noise");
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053075 return -EIO;
76 }
77 /* start again */
78 continue;
79 }
80
81 /*
82 * Once the DRDY bit is set, the RNG_DR register can
83 * be read four consecutive times.
84 */
85 count = 4;
86 while (len && count) {
87 reg = readl(pdata->base + RNG_DR);
88 memcpy(data, &reg, min(len, sizeof(u32)));
89 increment = min(len, sizeof(u32));
90 data += increment;
91 len -= increment;
92 count--;
93 }
94 }
95
96 return 0;
97}
98
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +020099static uint stm32_rng_clock_freq_restrain(struct stm32_rng_plat *pdata)
100{
101 ulong clock_rate = 0;
102 uint clock_div = 0;
103
104 clock_rate = clk_get_rate(&pdata->clk);
105
106 /*
107 * Get the exponent to apply on the CLKDIV field in RNG_CR register.
108 * No need to handle the case when clock-div > 0xF as it is physically
109 * impossible.
110 */
111 while ((clock_rate >> clock_div) > pdata->data->max_clock_rate)
112 clock_div++;
113
114 log_debug("RNG clk rate : %lu\n", clk_get_rate(&pdata->clk) >> clock_div);
115
116 return clock_div;
117}
118
Simon Glassb75b15b2020-12-03 16:55:23 -0700119static int stm32_rng_init(struct stm32_rng_plat *pdata)
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530120{
121 int err;
Lionel Debieve71f44212022-06-30 10:20:15 +0200122 u32 cr, sr;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530123
124 err = clk_enable(&pdata->clk);
125 if (err)
126 return err;
127
Lionel Debieve71f44212022-06-30 10:20:15 +0200128 cr = readl(pdata->base + RNG_CR);
129
Lionel Debieve71f44212022-06-30 10:20:15 +0200130 if (pdata->data->has_cond_reset) {
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +0200131 uint clock_div = stm32_rng_clock_freq_restrain(pdata);
132
133 cr |= RNG_CR_CONDRST | (clock_div << RNG_CR_CLKDIV_SHIFT);
Gatien Chevalliere2acc952023-09-19 17:27:55 +0200134 if (pdata->ced)
135 cr &= ~RNG_CR_CED;
136 else
137 cr |= RNG_CR_CED;
Lionel Debieve71f44212022-06-30 10:20:15 +0200138 writel(cr, pdata->base + RNG_CR);
139 cr &= ~RNG_CR_CONDRST;
Gatien Chevalliere2acc952023-09-19 17:27:55 +0200140 cr |= RNG_CR_RNGEN;
Lionel Debieve71f44212022-06-30 10:20:15 +0200141 writel(cr, pdata->base + RNG_CR);
142 err = readl_poll_timeout(pdata->base + RNG_CR, cr,
143 (!(cr & RNG_CR_CONDRST)), 10000);
144 if (err)
145 return err;
Gatien Chevalliere2acc952023-09-19 17:27:55 +0200146 } else {
147 if (pdata->ced)
148 cr &= ~RNG_CR_CED;
149 else
150 cr |= RNG_CR_CED;
151
152 cr |= RNG_CR_RNGEN;
153
154 writel(cr, pdata->base + RNG_CR);
Lionel Debieve71f44212022-06-30 10:20:15 +0200155 }
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530156
157 /* clear error indicators */
158 writel(0, pdata->base + RNG_SR);
159
Lionel Debieve71f44212022-06-30 10:20:15 +0200160 err = readl_poll_timeout(pdata->base + RNG_SR, sr,
161 sr & RNG_SR_DRDY, 10000);
162 return err;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530163}
164
Simon Glassb75b15b2020-12-03 16:55:23 -0700165static int stm32_rng_cleanup(struct stm32_rng_plat *pdata)
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530166{
167 writel(0, pdata->base + RNG_CR);
168
169 return clk_disable(&pdata->clk);
170}
171
172static int stm32_rng_probe(struct udevice *dev)
173{
Simon Glassb75b15b2020-12-03 16:55:23 -0700174 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530175
Lionel Debieve71f44212022-06-30 10:20:15 +0200176 pdata->data = (struct stm32_rng_data *)dev_get_driver_data(dev);
177
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530178 reset_assert(&pdata->rst);
179 udelay(20);
180 reset_deassert(&pdata->rst);
181
182 return stm32_rng_init(pdata);
183}
184
185static int stm32_rng_remove(struct udevice *dev)
186{
Simon Glassb75b15b2020-12-03 16:55:23 -0700187 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530188
189 return stm32_rng_cleanup(pdata);
190}
191
Simon Glassaad29ae2020-12-03 16:55:21 -0700192static int stm32_rng_of_to_plat(struct udevice *dev)
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530193{
Simon Glassb75b15b2020-12-03 16:55:23 -0700194 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530195 int err;
196
197 pdata->base = dev_read_addr(dev);
198 if (!pdata->base)
199 return -ENOMEM;
200
201 err = clk_get_by_index(dev, 0, &pdata->clk);
202 if (err)
203 return err;
204
205 err = reset_get_by_index(dev, 0, &pdata->rst);
206 if (err)
207 return err;
208
Gatien Chevalliere2acc952023-09-19 17:27:55 +0200209 pdata->ced = dev_read_bool(dev, "clock-error-detect");
210
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530211 return 0;
212}
213
214static const struct dm_rng_ops stm32_rng_ops = {
215 .read = stm32_rng_read,
216};
217
Lionel Debieve71f44212022-06-30 10:20:15 +0200218static const struct stm32_rng_data stm32mp13_rng_data = {
219 .has_cond_reset = true,
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +0200220 .max_clock_rate = 48000000,
Lionel Debieve71f44212022-06-30 10:20:15 +0200221};
222
223static const struct stm32_rng_data stm32_rng_data = {
224 .has_cond_reset = false,
Gatien Chevallier4f1f9e72023-09-19 17:27:56 +0200225 .max_clock_rate = 3000000,
Lionel Debieve71f44212022-06-30 10:20:15 +0200226};
227
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530228static const struct udevice_id stm32_rng_match[] = {
Lionel Debieve71f44212022-06-30 10:20:15 +0200229 {.compatible = "st,stm32mp13-rng", .data = (ulong)&stm32mp13_rng_data},
230 {.compatible = "st,stm32-rng", .data = (ulong)&stm32_rng_data},
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530231 {},
232};
233
234U_BOOT_DRIVER(stm32_rng) = {
235 .name = "stm32-rng",
236 .id = UCLASS_RNG,
237 .of_match = stm32_rng_match,
238 .ops = &stm32_rng_ops,
239 .probe = stm32_rng_probe,
240 .remove = stm32_rng_remove,
Simon Glassb75b15b2020-12-03 16:55:23 -0700241 .plat_auto = sizeof(struct stm32_rng_plat),
Simon Glassaad29ae2020-12-03 16:55:21 -0700242 .of_to_plat = stm32_rng_of_to_plat,
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530243};