blob: 89da78c6c8bd2d2c7b40083f82adddce5cdd5c14 [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
Lionel Debieve71f44212022-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 Ganucd9a2f92019-12-28 23:58:29 +053025
Lionel Debieve71f44212022-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 Ganucd9a2f92019-12-28 23:58:29 +053031
Lionel Debieve71f44212022-06-30 10:20:15 +020032#define RNG_DR 0x08
33
34struct stm32_rng_data {
35 bool has_cond_reset;
36};
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053037
Simon Glassb75b15b2020-12-03 16:55:23 -070038struct stm32_rng_plat {
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053039 fdt_addr_t base;
40 struct clk clk;
41 struct reset_ctl rst;
Lionel Debieve71f44212022-06-30 10:20:15 +020042 const struct stm32_rng_data *data;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053043};
44
45static int stm32_rng_read(struct udevice *dev, void *data, size_t len)
46{
Heinrich Schuchardt2b39a032020-02-16 10:11:18 +010047 int retval, i;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053048 u32 sr, count, reg;
49 size_t increment;
Simon Glassb75b15b2020-12-03 16:55:23 -070050 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053051
52 while (len > 0) {
53 retval = readl_poll_timeout(pdata->base + RNG_SR, sr,
54 sr & RNG_SR_DRDY, 10000);
55 if (retval)
56 return retval;
57
58 if (sr & (RNG_SR_SEIS | RNG_SR_SECS)) {
59 /* As per SoC TRM */
60 clrbits_le32(pdata->base + RNG_SR, RNG_SR_SEIS);
61 for (i = 0; i < 12; i++)
62 readl(pdata->base + RNG_DR);
63 if (readl(pdata->base + RNG_SR) & RNG_SR_SEIS) {
Heinrich Schuchardtd909bab2020-09-17 16:49:02 +020064 log_err("RNG Noise");
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053065 return -EIO;
66 }
67 /* start again */
68 continue;
69 }
70
71 /*
72 * Once the DRDY bit is set, the RNG_DR register can
73 * be read four consecutive times.
74 */
75 count = 4;
76 while (len && count) {
77 reg = readl(pdata->base + RNG_DR);
78 memcpy(data, &reg, min(len, sizeof(u32)));
79 increment = min(len, sizeof(u32));
80 data += increment;
81 len -= increment;
82 count--;
83 }
84 }
85
86 return 0;
87}
88
Simon Glassb75b15b2020-12-03 16:55:23 -070089static int stm32_rng_init(struct stm32_rng_plat *pdata)
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053090{
91 int err;
Lionel Debieve71f44212022-06-30 10:20:15 +020092 u32 cr, sr;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +053093
94 err = clk_enable(&pdata->clk);
95 if (err)
96 return err;
97
Lionel Debieve71f44212022-06-30 10:20:15 +020098 cr = readl(pdata->base + RNG_CR);
99
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530100 /* Disable CED */
Lionel Debieve71f44212022-06-30 10:20:15 +0200101 cr |= RNG_CR_CED;
102 if (pdata->data->has_cond_reset) {
103 cr |= RNG_CR_CONDRST;
104 writel(cr, pdata->base + RNG_CR);
105 cr &= ~RNG_CR_CONDRST;
106 writel(cr, pdata->base + RNG_CR);
107 err = readl_poll_timeout(pdata->base + RNG_CR, cr,
108 (!(cr & RNG_CR_CONDRST)), 10000);
109 if (err)
110 return err;
111 }
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530112
113 /* clear error indicators */
114 writel(0, pdata->base + RNG_SR);
115
Lionel Debieve71f44212022-06-30 10:20:15 +0200116 cr |= RNG_CR_RNGEN;
117 writel(cr, pdata->base + RNG_CR);
118
119 err = readl_poll_timeout(pdata->base + RNG_SR, sr,
120 sr & RNG_SR_DRDY, 10000);
121 return err;
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530122}
123
Simon Glassb75b15b2020-12-03 16:55:23 -0700124static int stm32_rng_cleanup(struct stm32_rng_plat *pdata)
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530125{
126 writel(0, pdata->base + RNG_CR);
127
128 return clk_disable(&pdata->clk);
129}
130
131static int stm32_rng_probe(struct udevice *dev)
132{
Simon Glassb75b15b2020-12-03 16:55:23 -0700133 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530134
Lionel Debieve71f44212022-06-30 10:20:15 +0200135 pdata->data = (struct stm32_rng_data *)dev_get_driver_data(dev);
136
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530137 reset_assert(&pdata->rst);
138 udelay(20);
139 reset_deassert(&pdata->rst);
140
141 return stm32_rng_init(pdata);
142}
143
144static int stm32_rng_remove(struct udevice *dev)
145{
Simon Glassb75b15b2020-12-03 16:55:23 -0700146 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530147
148 return stm32_rng_cleanup(pdata);
149}
150
Simon Glassaad29ae2020-12-03 16:55:21 -0700151static int stm32_rng_of_to_plat(struct udevice *dev)
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530152{
Simon Glassb75b15b2020-12-03 16:55:23 -0700153 struct stm32_rng_plat *pdata = dev_get_plat(dev);
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530154 int err;
155
156 pdata->base = dev_read_addr(dev);
157 if (!pdata->base)
158 return -ENOMEM;
159
160 err = clk_get_by_index(dev, 0, &pdata->clk);
161 if (err)
162 return err;
163
164 err = reset_get_by_index(dev, 0, &pdata->rst);
165 if (err)
166 return err;
167
168 return 0;
169}
170
171static const struct dm_rng_ops stm32_rng_ops = {
172 .read = stm32_rng_read,
173};
174
Lionel Debieve71f44212022-06-30 10:20:15 +0200175static const struct stm32_rng_data stm32mp13_rng_data = {
176 .has_cond_reset = true,
177};
178
179static const struct stm32_rng_data stm32_rng_data = {
180 .has_cond_reset = false,
181};
182
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530183static const struct udevice_id stm32_rng_match[] = {
Lionel Debieve71f44212022-06-30 10:20:15 +0200184 {.compatible = "st,stm32mp13-rng", .data = (ulong)&stm32mp13_rng_data},
185 {.compatible = "st,stm32-rng", .data = (ulong)&stm32_rng_data},
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530186 {},
187};
188
189U_BOOT_DRIVER(stm32_rng) = {
190 .name = "stm32-rng",
191 .id = UCLASS_RNG,
192 .of_match = stm32_rng_match,
193 .ops = &stm32_rng_ops,
194 .probe = stm32_rng_probe,
195 .remove = stm32_rng_remove,
Simon Glassb75b15b2020-12-03 16:55:23 -0700196 .plat_auto = sizeof(struct stm32_rng_plat),
Simon Glassaad29ae2020-12-03 16:55:21 -0700197 .of_to_plat = stm32_rng_of_to_plat,
Sughosh Ganucd9a2f92019-12-28 23:58:29 +0530198};