1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * RNG driver for Freescale RNGC |
4 | * |
5 | * Copyright (C) 2008-2012 Freescale Semiconductor, Inc. |
6 | * Copyright (C) 2017 Martin Kaiser <martin@kaiser.cx> |
7 | */ |
8 | |
9 | #include <linux/module.h> |
10 | #include <linux/mod_devicetable.h> |
11 | #include <linux/init.h> |
12 | #include <linux/kernel.h> |
13 | #include <linux/clk.h> |
14 | #include <linux/err.h> |
15 | #include <linux/platform_device.h> |
16 | #include <linux/interrupt.h> |
17 | #include <linux/hw_random.h> |
18 | #include <linux/completion.h> |
19 | #include <linux/io.h> |
20 | #include <linux/bitfield.h> |
21 | |
22 | #define RNGC_VER_ID 0x0000 |
23 | #define RNGC_COMMAND 0x0004 |
24 | #define RNGC_CONTROL 0x0008 |
25 | #define RNGC_STATUS 0x000C |
26 | #define RNGC_ERROR 0x0010 |
27 | #define RNGC_FIFO 0x0014 |
28 | |
29 | /* the fields in the ver id register */ |
30 | #define RNG_TYPE GENMASK(31, 28) |
31 | #define RNGC_VER_MAJ_SHIFT 8 |
32 | |
33 | /* the rng_type field */ |
34 | #define RNGC_TYPE_RNGB 0x1 |
35 | #define RNGC_TYPE_RNGC 0x2 |
36 | |
37 | |
38 | #define RNGC_CMD_CLR_ERR BIT(5) |
39 | #define RNGC_CMD_CLR_INT BIT(4) |
40 | #define RNGC_CMD_SEED BIT(1) |
41 | #define RNGC_CMD_SELF_TEST BIT(0) |
42 | |
43 | #define RNGC_CTRL_MASK_ERROR BIT(6) |
44 | #define RNGC_CTRL_MASK_DONE BIT(5) |
45 | #define RNGC_CTRL_AUTO_SEED BIT(4) |
46 | |
47 | #define RNGC_STATUS_ERROR BIT(16) |
48 | #define RNGC_STATUS_FIFO_LEVEL_MASK GENMASK(11, 8) |
49 | #define RNGC_STATUS_SEED_DONE BIT(5) |
50 | #define RNGC_STATUS_ST_DONE BIT(4) |
51 | |
52 | #define RNGC_ERROR_STATUS_STAT_ERR 0x00000008 |
53 | |
54 | #define RNGC_SELFTEST_TIMEOUT 2500 /* us */ |
55 | #define RNGC_SEED_TIMEOUT 200 /* ms */ |
56 | |
57 | static bool self_test = true; |
58 | module_param(self_test, bool, 0); |
59 | |
60 | struct imx_rngc { |
61 | struct device *dev; |
62 | struct clk *clk; |
63 | void __iomem *base; |
64 | struct hwrng rng; |
65 | struct completion rng_op_done; |
66 | /* |
67 | * err_reg is written only by the irq handler and read only |
68 | * when interrupts are masked, we need no spinlock |
69 | */ |
70 | u32 err_reg; |
71 | }; |
72 | |
73 | |
74 | static inline void imx_rngc_irq_mask_clear(struct imx_rngc *rngc) |
75 | { |
76 | u32 ctrl, cmd; |
77 | |
78 | /* mask interrupts */ |
79 | ctrl = readl(addr: rngc->base + RNGC_CONTROL); |
80 | ctrl |= RNGC_CTRL_MASK_DONE | RNGC_CTRL_MASK_ERROR; |
81 | writel(val: ctrl, addr: rngc->base + RNGC_CONTROL); |
82 | |
83 | /* |
84 | * CLR_INT clears the interrupt only if there's no error |
85 | * CLR_ERR clear the interrupt and the error register if there |
86 | * is an error |
87 | */ |
88 | cmd = readl(addr: rngc->base + RNGC_COMMAND); |
89 | cmd |= RNGC_CMD_CLR_INT | RNGC_CMD_CLR_ERR; |
90 | writel(val: cmd, addr: rngc->base + RNGC_COMMAND); |
91 | } |
92 | |
93 | static inline void imx_rngc_irq_unmask(struct imx_rngc *rngc) |
94 | { |
95 | u32 ctrl; |
96 | |
97 | ctrl = readl(addr: rngc->base + RNGC_CONTROL); |
98 | ctrl &= ~(RNGC_CTRL_MASK_DONE | RNGC_CTRL_MASK_ERROR); |
99 | writel(val: ctrl, addr: rngc->base + RNGC_CONTROL); |
100 | } |
101 | |
102 | static int imx_rngc_self_test(struct imx_rngc *rngc) |
103 | { |
104 | u32 cmd; |
105 | int ret; |
106 | |
107 | imx_rngc_irq_unmask(rngc); |
108 | |
109 | /* run self test */ |
110 | cmd = readl(addr: rngc->base + RNGC_COMMAND); |
111 | writel(val: cmd | RNGC_CMD_SELF_TEST, addr: rngc->base + RNGC_COMMAND); |
112 | |
113 | ret = wait_for_completion_timeout(x: &rngc->rng_op_done, |
114 | timeout: usecs_to_jiffies(RNGC_SELFTEST_TIMEOUT)); |
115 | imx_rngc_irq_mask_clear(rngc); |
116 | if (!ret) |
117 | return -ETIMEDOUT; |
118 | |
119 | return rngc->err_reg ? -EIO : 0; |
120 | } |
121 | |
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 | int retval = 0; |
127 | |
128 | while (max >= sizeof(u32)) { |
129 | status = readl(addr: rngc->base + RNGC_STATUS); |
130 | |
131 | /* is there some error while reading this random number? */ |
132 | if (status & RNGC_STATUS_ERROR) |
133 | break; |
134 | |
135 | if (status & RNGC_STATUS_FIFO_LEVEL_MASK) { |
136 | /* retrieve a random number from FIFO */ |
137 | *(u32 *)data = readl(addr: rngc->base + RNGC_FIFO); |
138 | |
139 | retval += sizeof(u32); |
140 | data += sizeof(u32); |
141 | max -= sizeof(u32); |
142 | } |
143 | } |
144 | |
145 | return retval ? retval : -EIO; |
146 | } |
147 | |
148 | static irqreturn_t imx_rngc_irq(int irq, void *priv) |
149 | { |
150 | struct imx_rngc *rngc = (struct imx_rngc *)priv; |
151 | u32 status; |
152 | |
153 | /* |
154 | * clearing the interrupt will also clear the error register |
155 | * read error and status before clearing |
156 | */ |
157 | status = readl(addr: rngc->base + RNGC_STATUS); |
158 | rngc->err_reg = readl(addr: rngc->base + RNGC_ERROR); |
159 | |
160 | imx_rngc_irq_mask_clear(rngc); |
161 | |
162 | if (status & (RNGC_STATUS_SEED_DONE | RNGC_STATUS_ST_DONE)) |
163 | complete(&rngc->rng_op_done); |
164 | |
165 | return IRQ_HANDLED; |
166 | } |
167 | |
168 | static int imx_rngc_init(struct hwrng *rng) |
169 | { |
170 | struct imx_rngc *rngc = container_of(rng, struct imx_rngc, rng); |
171 | u32 cmd, ctrl; |
172 | int ret; |
173 | |
174 | /* clear error */ |
175 | cmd = readl(addr: rngc->base + RNGC_COMMAND); |
176 | writel(val: cmd | RNGC_CMD_CLR_ERR, addr: rngc->base + RNGC_COMMAND); |
177 | |
178 | imx_rngc_irq_unmask(rngc); |
179 | |
180 | /* create seed, repeat while there is some statistical error */ |
181 | do { |
182 | /* seed creation */ |
183 | cmd = readl(addr: rngc->base + RNGC_COMMAND); |
184 | writel(val: cmd | RNGC_CMD_SEED, addr: rngc->base + RNGC_COMMAND); |
185 | |
186 | ret = wait_for_completion_timeout(x: &rngc->rng_op_done, |
187 | timeout: msecs_to_jiffies(RNGC_SEED_TIMEOUT)); |
188 | if (!ret) { |
189 | ret = -ETIMEDOUT; |
190 | goto err; |
191 | } |
192 | |
193 | } while (rngc->err_reg == RNGC_ERROR_STATUS_STAT_ERR); |
194 | |
195 | if (rngc->err_reg) { |
196 | ret = -EIO; |
197 | goto err; |
198 | } |
199 | |
200 | /* |
201 | * enable automatic seeding, the rngc creates a new seed automatically |
202 | * after serving 2^20 random 160-bit words |
203 | */ |
204 | ctrl = readl(addr: rngc->base + RNGC_CONTROL); |
205 | ctrl |= RNGC_CTRL_AUTO_SEED; |
206 | writel(val: ctrl, addr: rngc->base + RNGC_CONTROL); |
207 | |
208 | /* |
209 | * if initialisation was successful, we keep the interrupt |
210 | * unmasked until imx_rngc_cleanup is called |
211 | * we mask the interrupt ourselves if we return an error |
212 | */ |
213 | return 0; |
214 | |
215 | err: |
216 | imx_rngc_irq_mask_clear(rngc); |
217 | return ret; |
218 | } |
219 | |
220 | static void imx_rngc_cleanup(struct hwrng *rng) |
221 | { |
222 | struct imx_rngc *rngc = container_of(rng, struct imx_rngc, rng); |
223 | |
224 | imx_rngc_irq_mask_clear(rngc); |
225 | } |
226 | |
227 | static int __init imx_rngc_probe(struct platform_device *pdev) |
228 | { |
229 | struct imx_rngc *rngc; |
230 | int ret; |
231 | int irq; |
232 | u32 ver_id; |
233 | u8 rng_type; |
234 | |
235 | rngc = devm_kzalloc(dev: &pdev->dev, size: sizeof(*rngc), GFP_KERNEL); |
236 | if (!rngc) |
237 | return -ENOMEM; |
238 | |
239 | rngc->base = devm_platform_ioremap_resource(pdev, index: 0); |
240 | if (IS_ERR(ptr: rngc->base)) |
241 | return PTR_ERR(ptr: rngc->base); |
242 | |
243 | rngc->clk = devm_clk_get_enabled(dev: &pdev->dev, NULL); |
244 | if (IS_ERR(ptr: rngc->clk)) |
245 | return dev_err_probe(dev: &pdev->dev, err: PTR_ERR(ptr: rngc->clk), fmt: "Cannot get rng_clk\n" ); |
246 | |
247 | irq = platform_get_irq(pdev, 0); |
248 | if (irq < 0) |
249 | return irq; |
250 | |
251 | ver_id = readl(addr: rngc->base + RNGC_VER_ID); |
252 | rng_type = FIELD_GET(RNG_TYPE, ver_id); |
253 | /* |
254 | * This driver supports only RNGC and RNGB. (There's a different |
255 | * driver for RNGA.) |
256 | */ |
257 | if (rng_type != RNGC_TYPE_RNGC && rng_type != RNGC_TYPE_RNGB) |
258 | return -ENODEV; |
259 | |
260 | init_completion(x: &rngc->rng_op_done); |
261 | |
262 | rngc->rng.name = pdev->name; |
263 | rngc->rng.init = imx_rngc_init; |
264 | rngc->rng.read = imx_rngc_read; |
265 | rngc->rng.cleanup = imx_rngc_cleanup; |
266 | rngc->rng.quality = 19; |
267 | |
268 | rngc->dev = &pdev->dev; |
269 | platform_set_drvdata(pdev, data: rngc); |
270 | |
271 | imx_rngc_irq_mask_clear(rngc); |
272 | |
273 | ret = devm_request_irq(dev: &pdev->dev, |
274 | irq, handler: imx_rngc_irq, irqflags: 0, devname: pdev->name, dev_id: (void *)rngc); |
275 | if (ret) |
276 | return dev_err_probe(dev: &pdev->dev, err: ret, fmt: "Can't get interrupt working.\n" ); |
277 | |
278 | if (self_test) { |
279 | ret = imx_rngc_self_test(rngc); |
280 | if (ret) |
281 | return dev_err_probe(dev: &pdev->dev, err: ret, fmt: "self test failed\n" ); |
282 | } |
283 | |
284 | ret = devm_hwrng_register(dev: &pdev->dev, rng: &rngc->rng); |
285 | if (ret) |
286 | return dev_err_probe(dev: &pdev->dev, err: ret, fmt: "hwrng registration failed\n" ); |
287 | |
288 | dev_info(&pdev->dev, |
289 | "Freescale RNG%c registered (HW revision %d.%02d)\n" , |
290 | rng_type == RNGC_TYPE_RNGB ? 'B' : 'C', |
291 | (ver_id >> RNGC_VER_MAJ_SHIFT) & 0xff, ver_id & 0xff); |
292 | return 0; |
293 | } |
294 | |
295 | static int imx_rngc_suspend(struct device *dev) |
296 | { |
297 | struct imx_rngc *rngc = dev_get_drvdata(dev); |
298 | |
299 | clk_disable_unprepare(clk: rngc->clk); |
300 | |
301 | return 0; |
302 | } |
303 | |
304 | static int imx_rngc_resume(struct device *dev) |
305 | { |
306 | struct imx_rngc *rngc = dev_get_drvdata(dev); |
307 | |
308 | clk_prepare_enable(clk: rngc->clk); |
309 | |
310 | return 0; |
311 | } |
312 | |
313 | static DEFINE_SIMPLE_DEV_PM_OPS(imx_rngc_pm_ops, imx_rngc_suspend, imx_rngc_resume); |
314 | |
315 | static const struct of_device_id imx_rngc_dt_ids[] = { |
316 | { .compatible = "fsl,imx25-rngb" }, |
317 | { /* sentinel */ } |
318 | }; |
319 | MODULE_DEVICE_TABLE(of, imx_rngc_dt_ids); |
320 | |
321 | static struct platform_driver imx_rngc_driver = { |
322 | .driver = { |
323 | .name = KBUILD_MODNAME, |
324 | .pm = pm_sleep_ptr(&imx_rngc_pm_ops), |
325 | .of_match_table = imx_rngc_dt_ids, |
326 | }, |
327 | }; |
328 | |
329 | module_platform_driver_probe(imx_rngc_driver, imx_rngc_probe); |
330 | |
331 | MODULE_AUTHOR("Freescale Semiconductor, Inc." ); |
332 | MODULE_DESCRIPTION("H/W RNGC driver for i.MX" ); |
333 | MODULE_LICENSE("GPL" ); |
334 | |