• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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