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