1 /*
2 * RNG driver for Freescale RNGC
3 *
4 * Copyright (C) 2008-2012 Freescale Semiconductor, Inc.
5 * Copyright (C) 2017 Martin Kaiser <martin@kaiser.cx>
6 *
7 * The code contained herein is licensed under the GNU General Public
8 * License. You may obtain a copy of the GNU General Public License
9 * Version 2 or later at the following locations:
10 *
11 * http://www.opensource.org/licenses/gpl-license.html
12 * http://www.gnu.org/copyleft/gpl.html
13 */
14
15 #include <linux/module.h>
16 #include <linux/mod_devicetable.h>
17 #include <linux/init.h>
18 #include <linux/kernel.h>
19 #include <linux/clk.h>
20 #include <linux/err.h>
21 #include <linux/platform_device.h>
22 #include <linux/interrupt.h>
23 #include <linux/hw_random.h>
24 #include <linux/completion.h>
25 #include <linux/io.h>
26
27 #define RNGC_COMMAND 0x0004
28 #define RNGC_CONTROL 0x0008
29 #define RNGC_STATUS 0x000C
30 #define RNGC_ERROR 0x0010
31 #define RNGC_FIFO 0x0014
32
33 #define RNGC_CMD_CLR_ERR 0x00000020
34 #define RNGC_CMD_CLR_INT 0x00000010
35 #define RNGC_CMD_SEED 0x00000002
36 #define RNGC_CMD_SELF_TEST 0x00000001
37
38 #define RNGC_CTRL_MASK_ERROR 0x00000040
39 #define RNGC_CTRL_MASK_DONE 0x00000020
40
41 #define RNGC_STATUS_ERROR 0x00010000
42 #define RNGC_STATUS_FIFO_LEVEL_MASK 0x00000f00
43 #define RNGC_STATUS_FIFO_LEVEL_SHIFT 8
44 #define RNGC_STATUS_SEED_DONE 0x00000020
45 #define RNGC_STATUS_ST_DONE 0x00000010
46
47 #define RNGC_ERROR_STATUS_STAT_ERR 0x00000008
48
49 #define RNGC_TIMEOUT 3000 /* 3 sec */
50
51
52 static bool self_test = true;
53 module_param(self_test, bool, 0);
54
55 struct imx_rngc {
56 struct device *dev;
57 struct clk *clk;
58 void __iomem *base;
59 struct hwrng rng;
60 struct completion rng_op_done;
61 /*
62 * err_reg is written only by the irq handler and read only
63 * when interrupts are masked, we need no spinlock
64 */
65 u32 err_reg;
66 };
67
68
imx_rngc_irq_mask_clear(struct imx_rngc * rngc)69 static inline void imx_rngc_irq_mask_clear(struct imx_rngc *rngc)
70 {
71 u32 ctrl, cmd;
72
73 /* mask interrupts */
74 ctrl = readl(rngc->base + RNGC_CONTROL);
75 ctrl |= RNGC_CTRL_MASK_DONE | RNGC_CTRL_MASK_ERROR;
76 writel(ctrl, rngc->base + RNGC_CONTROL);
77
78 /*
79 * CLR_INT clears the interrupt only if there's no error
80 * CLR_ERR clear the interrupt and the error register if there
81 * is an error
82 */
83 cmd = readl(rngc->base + RNGC_COMMAND);
84 cmd |= RNGC_CMD_CLR_INT | RNGC_CMD_CLR_ERR;
85 writel(cmd, rngc->base + RNGC_COMMAND);
86 }
87
imx_rngc_irq_unmask(struct imx_rngc * rngc)88 static inline void imx_rngc_irq_unmask(struct imx_rngc *rngc)
89 {
90 u32 ctrl;
91
92 ctrl = readl(rngc->base + RNGC_CONTROL);
93 ctrl &= ~(RNGC_CTRL_MASK_DONE | RNGC_CTRL_MASK_ERROR);
94 writel(ctrl, rngc->base + RNGC_CONTROL);
95 }
96
imx_rngc_self_test(struct imx_rngc * rngc)97 static int imx_rngc_self_test(struct imx_rngc *rngc)
98 {
99 u32 cmd;
100 int ret;
101
102 imx_rngc_irq_unmask(rngc);
103
104 /* run self test */
105 cmd = readl(rngc->base + RNGC_COMMAND);
106 writel(cmd | RNGC_CMD_SELF_TEST, rngc->base + RNGC_COMMAND);
107
108 ret = wait_for_completion_timeout(&rngc->rng_op_done, RNGC_TIMEOUT);
109 if (!ret) {
110 imx_rngc_irq_mask_clear(rngc);
111 return -ETIMEDOUT;
112 }
113
114 if (rngc->err_reg != 0) {
115 imx_rngc_irq_mask_clear(rngc);
116 return -EIO;
117 }
118
119 return 0;
120 }
121
imx_rngc_read(struct hwrng * rng,void * data,size_t max,bool wait)122 static int imx_rngc_read(struct hwrng *rng, void *data, size_t max, bool wait)
123 {
124 struct imx_rngc *rngc = container_of(rng, struct imx_rngc, rng);
125 unsigned int status;
126 unsigned int level;
127 int retval = 0;
128
129 while (max >= sizeof(u32)) {
130 status = readl(rngc->base + RNGC_STATUS);
131
132 /* is there some error while reading this random number? */
133 if (status & RNGC_STATUS_ERROR)
134 break;
135
136 /* how many random numbers are in FIFO? [0-16] */
137 level = (status & RNGC_STATUS_FIFO_LEVEL_MASK) >>
138 RNGC_STATUS_FIFO_LEVEL_SHIFT;
139
140 if (level) {
141 /* retrieve a random number from FIFO */
142 *(u32 *)data = readl(rngc->base + RNGC_FIFO);
143
144 retval += sizeof(u32);
145 data += sizeof(u32);
146 max -= sizeof(u32);
147 }
148 }
149
150 return retval ? retval : -EIO;
151 }
152
imx_rngc_irq(int irq,void * priv)153 static irqreturn_t imx_rngc_irq(int irq, void *priv)
154 {
155 struct imx_rngc *rngc = (struct imx_rngc *)priv;
156 u32 status;
157
158 /*
159 * clearing the interrupt will also clear the error register
160 * read error and status before clearing
161 */
162 status = readl(rngc->base + RNGC_STATUS);
163 rngc->err_reg = readl(rngc->base + RNGC_ERROR);
164
165 imx_rngc_irq_mask_clear(rngc);
166
167 if (status & (RNGC_STATUS_SEED_DONE | RNGC_STATUS_ST_DONE))
168 complete(&rngc->rng_op_done);
169
170 return IRQ_HANDLED;
171 }
172
imx_rngc_init(struct hwrng * rng)173 static int imx_rngc_init(struct hwrng *rng)
174 {
175 struct imx_rngc *rngc = container_of(rng, struct imx_rngc, rng);
176 u32 cmd;
177 int ret;
178
179 /* clear error */
180 cmd = readl(rngc->base + RNGC_COMMAND);
181 writel(cmd | RNGC_CMD_CLR_ERR, rngc->base + RNGC_COMMAND);
182
183 /* create seed, repeat while there is some statistical error */
184 do {
185 imx_rngc_irq_unmask(rngc);
186
187 /* seed creation */
188 cmd = readl(rngc->base + RNGC_COMMAND);
189 writel(cmd | RNGC_CMD_SEED, rngc->base + RNGC_COMMAND);
190
191 ret = wait_for_completion_timeout(&rngc->rng_op_done,
192 RNGC_TIMEOUT);
193
194 if (!ret) {
195 imx_rngc_irq_mask_clear(rngc);
196 return -ETIMEDOUT;
197 }
198
199 } while (rngc->err_reg == RNGC_ERROR_STATUS_STAT_ERR);
200
201 return rngc->err_reg ? -EIO : 0;
202 }
203
imx_rngc_probe(struct platform_device * pdev)204 static int imx_rngc_probe(struct platform_device *pdev)
205 {
206 struct imx_rngc *rngc;
207 struct resource *res;
208 int ret;
209 int irq;
210
211 rngc = devm_kzalloc(&pdev->dev, sizeof(*rngc), GFP_KERNEL);
212 if (!rngc)
213 return -ENOMEM;
214
215 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
216 rngc->base = devm_ioremap_resource(&pdev->dev, res);
217 if (IS_ERR(rngc->base))
218 return PTR_ERR(rngc->base);
219
220 rngc->clk = devm_clk_get(&pdev->dev, NULL);
221 if (IS_ERR(rngc->clk)) {
222 dev_err(&pdev->dev, "Can not get rng_clk\n");
223 return PTR_ERR(rngc->clk);
224 }
225
226 irq = platform_get_irq(pdev, 0);
227 if (irq <= 0) {
228 dev_err(&pdev->dev, "Couldn't get irq %d\n", irq);
229 return irq;
230 }
231
232 ret = clk_prepare_enable(rngc->clk);
233 if (ret)
234 return ret;
235
236 ret = devm_request_irq(&pdev->dev,
237 irq, imx_rngc_irq, 0, pdev->name, (void *)rngc);
238 if (ret) {
239 dev_err(rngc->dev, "Can't get interrupt working.\n");
240 goto err;
241 }
242
243 init_completion(&rngc->rng_op_done);
244
245 rngc->rng.name = pdev->name;
246 rngc->rng.init = imx_rngc_init;
247 rngc->rng.read = imx_rngc_read;
248
249 rngc->dev = &pdev->dev;
250 platform_set_drvdata(pdev, rngc);
251
252 imx_rngc_irq_mask_clear(rngc);
253
254 if (self_test) {
255 ret = imx_rngc_self_test(rngc);
256 if (ret) {
257 dev_err(rngc->dev, "FSL RNGC self test failed.\n");
258 goto err;
259 }
260 }
261
262 ret = hwrng_register(&rngc->rng);
263 if (ret) {
264 dev_err(&pdev->dev, "FSL RNGC registering failed (%d)\n", ret);
265 goto err;
266 }
267
268 dev_info(&pdev->dev, "Freescale RNGC registered.\n");
269 return 0;
270
271 err:
272 clk_disable_unprepare(rngc->clk);
273
274 return ret;
275 }
276
imx_rngc_remove(struct platform_device * pdev)277 static int __exit imx_rngc_remove(struct platform_device *pdev)
278 {
279 struct imx_rngc *rngc = platform_get_drvdata(pdev);
280
281 hwrng_unregister(&rngc->rng);
282
283 clk_disable_unprepare(rngc->clk);
284
285 return 0;
286 }
287
imx_rngc_suspend(struct device * dev)288 static int __maybe_unused imx_rngc_suspend(struct device *dev)
289 {
290 struct imx_rngc *rngc = dev_get_drvdata(dev);
291
292 clk_disable_unprepare(rngc->clk);
293
294 return 0;
295 }
296
imx_rngc_resume(struct device * dev)297 static int __maybe_unused imx_rngc_resume(struct device *dev)
298 {
299 struct imx_rngc *rngc = dev_get_drvdata(dev);
300
301 clk_prepare_enable(rngc->clk);
302
303 return 0;
304 }
305
306 static SIMPLE_DEV_PM_OPS(imx_rngc_pm_ops, imx_rngc_suspend, imx_rngc_resume);
307
308 static const struct of_device_id imx_rngc_dt_ids[] = {
309 { .compatible = "fsl,imx25-rngb", .data = NULL, },
310 { /* sentinel */ }
311 };
312 MODULE_DEVICE_TABLE(of, imx_rngc_dt_ids);
313
314 static struct platform_driver imx_rngc_driver = {
315 .driver = {
316 .name = "imx_rngc",
317 .pm = &imx_rngc_pm_ops,
318 .of_match_table = imx_rngc_dt_ids,
319 },
320 .remove = __exit_p(imx_rngc_remove),
321 };
322
323 module_platform_driver_probe(imx_rngc_driver, imx_rngc_probe);
324
325 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
326 MODULE_DESCRIPTION("H/W RNGC driver for i.MX");
327 MODULE_LICENSE("GPL");
328