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