blob: ada5d9221416a24d3155ea89a36d28b0db1d6e22 [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
Lionel Debieve12e11aa2022-06-30 10:20:15 +020021#define RNG_CR 0x00
22#define RNG_CR_RNGEN BIT(2)
23#define RNG_CR_CED BIT(5)
24#define RNG_CR_CONDRST BIT(30)
Sughosh Ganu231ec902019-12-28 23:58:29 +053025
Lionel Debieve12e11aa2022-06-30 10:20:15 +020026#define RNG_SR 0x04
27#define RNG_SR_SEIS BIT(6)
28#define RNG_SR_CEIS BIT(5)
29#define RNG_SR_SECS BIT(2)
30#define RNG_SR_DRDY BIT(0)
Sughosh Ganu231ec902019-12-28 23:58:29 +053031
Lionel Debieve12e11aa2022-06-30 10:20:15 +020032#define RNG_DR 0x08
33
34struct stm32_rng_data {
35 bool has_cond_reset;
36};
Sughosh Ganu231ec902019-12-28 23:58:29 +053037
Simon Glass8a8d24b2020-12-03 16:55:23 -070038struct stm32_rng_plat {
Sughosh Ganu231ec902019-12-28 23:58:29 +053039 fdt_addr_t base;
40 struct clk clk;
41 struct reset_ctl rst;
Lionel Debieve12e11aa2022-06-30 10:20:15 +020042 const struct stm32_rng_data *data;
Gatien Chevallier2d2574b2023-09-19 17:27:55 +020043 bool ced;
Sughosh Ganu231ec902019-12-28 23:58:29 +053044};
45
46static int stm32_rng_read(struct udevice *dev, void *data, size_t len)
47{
Heinrich Schuchardt250b3032020-02-16 10:11:18 +010048 int retval, i;
Sughosh Ganu231ec902019-12-28 23:58:29 +053049 u32 sr, count, reg;
50 size_t increment;
Simon Glass8a8d24b2020-12-03 16:55:23 -070051 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganu231ec902019-12-28 23:58:29 +053052
53 while (len > 0) {
54 retval = readl_poll_timeout(pdata->base + RNG_SR, sr,
55 sr & RNG_SR_DRDY, 10000);
56 if (retval)
57 return retval;
58
59 if (sr & (RNG_SR_SEIS | RNG_SR_SECS)) {
60 /* As per SoC TRM */
61 clrbits_le32(pdata->base + RNG_SR, RNG_SR_SEIS);
62 for (i = 0; i < 12; i++)
63 readl(pdata->base + RNG_DR);
64 if (readl(pdata->base + RNG_SR) & RNG_SR_SEIS) {
Heinrich Schuchardtcf0bf892020-09-17 16:49:02 +020065 log_err("RNG Noise");
Sughosh Ganu231ec902019-12-28 23:58:29 +053066 return -EIO;
67 }
68 /* start again */
69 continue;
70 }
71
72 /*
73 * Once the DRDY bit is set, the RNG_DR register can
74 * be read four consecutive times.
75 */
76 count = 4;
77 while (len && count) {
78 reg = readl(pdata->base + RNG_DR);
79 memcpy(data, &reg, min(len, sizeof(u32)));
80 increment = min(len, sizeof(u32));
81 data += increment;
82 len -= increment;
83 count--;
84 }
85 }
86
87 return 0;
88}
89
Simon Glass8a8d24b2020-12-03 16:55:23 -070090static int stm32_rng_init(struct stm32_rng_plat *pdata)
Sughosh Ganu231ec902019-12-28 23:58:29 +053091{
92 int err;
Lionel Debieve12e11aa2022-06-30 10:20:15 +020093 u32 cr, sr;
Sughosh Ganu231ec902019-12-28 23:58:29 +053094
95 err = clk_enable(&pdata->clk);
96 if (err)
97 return err;
98
Lionel Debieve12e11aa2022-06-30 10:20:15 +020099 cr = readl(pdata->base + RNG_CR);
100
Lionel Debieve12e11aa2022-06-30 10:20:15 +0200101 if (pdata->data->has_cond_reset) {
102 cr |= RNG_CR_CONDRST;
Gatien Chevallier2d2574b2023-09-19 17:27:55 +0200103 if (pdata->ced)
104 cr &= ~RNG_CR_CED;
105 else
106 cr |= RNG_CR_CED;
Lionel Debieve12e11aa2022-06-30 10:20:15 +0200107 writel(cr, pdata->base + RNG_CR);
108 cr &= ~RNG_CR_CONDRST;
Gatien Chevallier2d2574b2023-09-19 17:27:55 +0200109 cr |= RNG_CR_RNGEN;
Lionel Debieve12e11aa2022-06-30 10:20:15 +0200110 writel(cr, pdata->base + RNG_CR);
111 err = readl_poll_timeout(pdata->base + RNG_CR, cr,
112 (!(cr & RNG_CR_CONDRST)), 10000);
113 if (err)
114 return err;
Gatien Chevallier2d2574b2023-09-19 17:27:55 +0200115 } else {
116 if (pdata->ced)
117 cr &= ~RNG_CR_CED;
118 else
119 cr |= RNG_CR_CED;
120
121 cr |= RNG_CR_RNGEN;
122
123 writel(cr, pdata->base + RNG_CR);
Lionel Debieve12e11aa2022-06-30 10:20:15 +0200124 }
Sughosh Ganu231ec902019-12-28 23:58:29 +0530125
126 /* clear error indicators */
127 writel(0, pdata->base + RNG_SR);
128
Lionel Debieve12e11aa2022-06-30 10:20:15 +0200129 err = readl_poll_timeout(pdata->base + RNG_SR, sr,
130 sr & RNG_SR_DRDY, 10000);
131 return err;
Sughosh Ganu231ec902019-12-28 23:58:29 +0530132}
133
Simon Glass8a8d24b2020-12-03 16:55:23 -0700134static int stm32_rng_cleanup(struct stm32_rng_plat *pdata)
Sughosh Ganu231ec902019-12-28 23:58:29 +0530135{
136 writel(0, pdata->base + RNG_CR);
137
138 return clk_disable(&pdata->clk);
139}
140
141static int stm32_rng_probe(struct udevice *dev)
142{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700143 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganu231ec902019-12-28 23:58:29 +0530144
Lionel Debieve12e11aa2022-06-30 10:20:15 +0200145 pdata->data = (struct stm32_rng_data *)dev_get_driver_data(dev);
146
Sughosh Ganu231ec902019-12-28 23:58:29 +0530147 reset_assert(&pdata->rst);
148 udelay(20);
149 reset_deassert(&pdata->rst);
150
151 return stm32_rng_init(pdata);
152}
153
154static int stm32_rng_remove(struct udevice *dev)
155{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700156 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganu231ec902019-12-28 23:58:29 +0530157
158 return stm32_rng_cleanup(pdata);
159}
160
Simon Glassd1998a92020-12-03 16:55:21 -0700161static int stm32_rng_of_to_plat(struct udevice *dev)
Sughosh Ganu231ec902019-12-28 23:58:29 +0530162{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700163 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganu231ec902019-12-28 23:58:29 +0530164 int err;
165
166 pdata->base = dev_read_addr(dev);
167 if (!pdata->base)
168 return -ENOMEM;
169
170 err = clk_get_by_index(dev, 0, &pdata->clk);
171 if (err)
172 return err;
173
174 err = reset_get_by_index(dev, 0, &pdata->rst);
175 if (err)
176 return err;
177
Gatien Chevallier2d2574b2023-09-19 17:27:55 +0200178 pdata->ced = dev_read_bool(dev, "clock-error-detect");
179
Sughosh Ganu231ec902019-12-28 23:58:29 +0530180 return 0;
181}
182
183static const struct dm_rng_ops stm32_rng_ops = {
184 .read = stm32_rng_read,
185};
186
Lionel Debieve12e11aa2022-06-30 10:20:15 +0200187static const struct stm32_rng_data stm32mp13_rng_data = {
188 .has_cond_reset = true,
189};
190
191static const struct stm32_rng_data stm32_rng_data = {
192 .has_cond_reset = false,
193};
194
Sughosh Ganu231ec902019-12-28 23:58:29 +0530195static const struct udevice_id stm32_rng_match[] = {
Lionel Debieve12e11aa2022-06-30 10:20:15 +0200196 {.compatible = "st,stm32mp13-rng", .data = (ulong)&stm32mp13_rng_data},
197 {.compatible = "st,stm32-rng", .data = (ulong)&stm32_rng_data},
Sughosh Ganu231ec902019-12-28 23:58:29 +0530198 {},
199};
200
201U_BOOT_DRIVER(stm32_rng) = {
202 .name = "stm32-rng",
203 .id = UCLASS_RNG,
204 .of_match = stm32_rng_match,
205 .ops = &stm32_rng_ops,
206 .probe = stm32_rng_probe,
207 .remove = stm32_rng_remove,
Simon Glass8a8d24b2020-12-03 16:55:23 -0700208 .plat_auto = sizeof(struct stm32_rng_plat),
Simon Glassd1998a92020-12-03 16:55:21 -0700209 .of_to_plat = stm32_rng_of_to_plat,
Sughosh Ganu231ec902019-12-28 23:58:29 +0530210};