common: Drop linux/delay.h from common header
[oweals/u-boot.git] / drivers / rng / stm32mp1_rng.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2019, Linaro Limited
4  */
5
6 #include <common.h>
7 #include <clk.h>
8 #include <dm.h>
9 #include <log.h>
10 #include <reset.h>
11 #include <rng.h>
12 #include <linux/delay.h>
13
14 #include <asm/io.h>
15 #include <linux/iopoll.h>
16 #include <linux/kernel.h>
17
18 #define RNG_CR 0x00
19 #define RNG_CR_RNGEN BIT(2)
20 #define RNG_CR_CED BIT(5)
21
22 #define RNG_SR 0x04
23 #define RNG_SR_SEIS BIT(6)
24 #define RNG_SR_CEIS BIT(5)
25 #define RNG_SR_SECS BIT(2)
26 #define RNG_SR_DRDY BIT(0)
27
28 #define RNG_DR 0x08
29
30 struct stm32_rng_platdata {
31         fdt_addr_t base;
32         struct clk clk;
33         struct reset_ctl rst;
34 };
35
36 static int stm32_rng_read(struct udevice *dev, void *data, size_t len)
37 {
38         int retval, i;
39         u32 sr, count, reg;
40         size_t increment;
41         struct stm32_rng_platdata *pdata = dev_get_platdata(dev);
42
43         while (len > 0) {
44                 retval = readl_poll_timeout(pdata->base + RNG_SR, sr,
45                                             sr & RNG_SR_DRDY, 10000);
46                 if (retval)
47                         return retval;
48
49                 if (sr & (RNG_SR_SEIS | RNG_SR_SECS)) {
50                         /* As per SoC TRM */
51                         clrbits_le32(pdata->base + RNG_SR, RNG_SR_SEIS);
52                         for (i = 0; i < 12; i++)
53                                 readl(pdata->base + RNG_DR);
54                         if (readl(pdata->base + RNG_SR) & RNG_SR_SEIS) {
55                                 printf("RNG Noise");
56                                 return -EIO;
57                         }
58                         /* start again */
59                         continue;
60                 }
61
62                 /*
63                  * Once the DRDY bit is set, the RNG_DR register can
64                  * be read four consecutive times.
65                  */
66                 count = 4;
67                 while (len && count) {
68                         reg = readl(pdata->base + RNG_DR);
69                         memcpy(data, &reg, min(len, sizeof(u32)));
70                         increment = min(len, sizeof(u32));
71                         data += increment;
72                         len -= increment;
73                         count--;
74                 }
75         }
76
77         return 0;
78 }
79
80 static int stm32_rng_init(struct stm32_rng_platdata *pdata)
81 {
82         int err;
83
84         err = clk_enable(&pdata->clk);
85         if (err)
86                 return err;
87
88         /* Disable CED */
89         writel(RNG_CR_RNGEN | RNG_CR_CED, pdata->base + RNG_CR);
90
91         /* clear error indicators */
92         writel(0, pdata->base + RNG_SR);
93
94         return 0;
95 }
96
97 static int stm32_rng_cleanup(struct stm32_rng_platdata *pdata)
98 {
99         writel(0, pdata->base + RNG_CR);
100
101         return clk_disable(&pdata->clk);
102 }
103
104 static int stm32_rng_probe(struct udevice *dev)
105 {
106         struct stm32_rng_platdata *pdata = dev_get_platdata(dev);
107
108         reset_assert(&pdata->rst);
109         udelay(20);
110         reset_deassert(&pdata->rst);
111
112         return stm32_rng_init(pdata);
113 }
114
115 static int stm32_rng_remove(struct udevice *dev)
116 {
117         struct stm32_rng_platdata *pdata = dev_get_platdata(dev);
118
119         return stm32_rng_cleanup(pdata);
120 }
121
122 static int stm32_rng_ofdata_to_platdata(struct udevice *dev)
123 {
124         struct stm32_rng_platdata *pdata = dev_get_platdata(dev);
125         int err;
126
127         pdata->base = dev_read_addr(dev);
128         if (!pdata->base)
129                 return -ENOMEM;
130
131         err = clk_get_by_index(dev, 0, &pdata->clk);
132         if (err)
133                 return err;
134
135         err = reset_get_by_index(dev, 0, &pdata->rst);
136         if (err)
137                 return err;
138
139         return 0;
140 }
141
142 static const struct dm_rng_ops stm32_rng_ops = {
143         .read = stm32_rng_read,
144 };
145
146 static const struct udevice_id stm32_rng_match[] = {
147         {
148                 .compatible = "st,stm32-rng",
149         },
150         {},
151 };
152
153 U_BOOT_DRIVER(stm32_rng) = {
154         .name = "stm32-rng",
155         .id = UCLASS_RNG,
156         .of_match = stm32_rng_match,
157         .ops = &stm32_rng_ops,
158         .probe = stm32_rng_probe,
159         .remove = stm32_rng_remove,
160         .platdata_auto_alloc_size = sizeof(struct stm32_rng_platdata),
161         .ofdata_to_platdata = stm32_rng_ofdata_to_platdata,
162 };