File Index
Files and directories
Sign in
FILE

imx-rngc.c

File preview with syntax highlighting.

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