Skip to content

Commit 190873a

Browse files
XBurstherbertx
authored andcommitted
crypto: ingenic - Add hardware RNG for Ingenic JZ4780 and X1000
Add JZ4780 SoC and X1000 SoC random number generator driver, based on PrasannaKumar Muralidharan's JZ4780 RNG driver. Tested-by: 周正 (Zhou Zheng) <[email protected]> Tested-by: Mathieu Malaterre <[email protected]> Suggested-by: Jeffrey Walton <[email protected]> Signed-off-by: PrasannaKumar Muralidharan <[email protected]> Signed-off-by: 周琰杰 (Zhou Yanjie) <[email protected]> Signed-off-by: Herbert Xu <[email protected]>
1 parent d86f443 commit 190873a

File tree

3 files changed

+170
-0
lines changed

3 files changed

+170
-0
lines changed

drivers/char/hw_random/Kconfig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,21 @@ config HW_RANDOM_IMX_RNGC
267267

268268
If unsure, say Y.
269269

270+
config HW_RANDOM_INGENIC_RNG
271+
tristate "Ingenic Random Number Generator support"
272+
depends on HW_RANDOM
273+
depends on MACH_JZ4780 || MACH_X1000
274+
default HW_RANDOM
275+
help
276+
This driver provides kernel-side support for the Random Number Generator
277+
hardware found in ingenic JZ4780 and X1000 SoC. MIPS Creator CI20 uses
278+
JZ4780 SoC, YSH & ATIL CU1000-Neo uses X1000 SoC.
279+
280+
To compile this driver as a module, choose M here: the
281+
module will be called ingenic-rng.
282+
283+
If unsure, say Y.
284+
270285
config HW_RANDOM_NOMADIK
271286
tristate "ST-Ericsson Nomadik Random Number Generator support"
272287
depends on ARCH_NOMADIK

drivers/char/hw_random/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o
2323
obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o
2424
obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o
2525
obj-$(CONFIG_HW_RANDOM_IMX_RNGC) += imx-rngc.o
26+
obj-$(CONFIG_HW_RANDOM_INGENIC_RNG) += ingenic-rng.o
2627
obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o
2728
obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
2829
obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o

drivers/char/hw_random/ingenic-rng.c

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Ingenic Random Number Generator driver
4+
* Copyright (c) 2017 PrasannaKumar Muralidharan <[email protected]>
5+
* Copyright (c) 2020 周琰杰 (Zhou Yanjie) <[email protected]>
6+
*/
7+
8+
#include <linux/err.h>
9+
#include <linux/kernel.h>
10+
#include <linux/hw_random.h>
11+
#include <linux/io.h>
12+
#include <linux/iopoll.h>
13+
#include <linux/module.h>
14+
#include <linux/of_device.h>
15+
#include <linux/platform_device.h>
16+
#include <linux/slab.h>
17+
18+
/* RNG register offsets */
19+
#define RNG_REG_ERNG_OFFSET 0x0
20+
#define RNG_REG_RNG_OFFSET 0x4
21+
22+
/* bits within the ERND register */
23+
#define ERNG_READY BIT(31)
24+
#define ERNG_ENABLE BIT(0)
25+
26+
enum ingenic_rng_version {
27+
ID_JZ4780,
28+
ID_X1000,
29+
};
30+
31+
/* Device associated memory */
32+
struct ingenic_rng {
33+
enum ingenic_rng_version version;
34+
35+
void __iomem *base;
36+
struct hwrng rng;
37+
};
38+
39+
static int ingenic_rng_init(struct hwrng *rng)
40+
{
41+
struct ingenic_rng *priv = container_of(rng, struct ingenic_rng, rng);
42+
43+
writel(ERNG_ENABLE, priv->base + RNG_REG_ERNG_OFFSET);
44+
45+
return 0;
46+
}
47+
48+
static void ingenic_rng_cleanup(struct hwrng *rng)
49+
{
50+
struct ingenic_rng *priv = container_of(rng, struct ingenic_rng, rng);
51+
52+
writel(0, priv->base + RNG_REG_ERNG_OFFSET);
53+
}
54+
55+
static int ingenic_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
56+
{
57+
struct ingenic_rng *priv = container_of(rng, struct ingenic_rng, rng);
58+
u32 *data = buf;
59+
u32 status;
60+
int ret;
61+
62+
if (priv->version >= ID_X1000) {
63+
ret = readl_poll_timeout(priv->base + RNG_REG_ERNG_OFFSET, status,
64+
status & ERNG_READY, 10, 1000);
65+
if (ret == -ETIMEDOUT) {
66+
pr_err("%s: Wait for RNG data ready timeout\n", __func__);
67+
return ret;
68+
}
69+
} else {
70+
/*
71+
* A delay is required so that the current RNG data is not bit shifted
72+
* version of previous RNG data which could happen if random data is
73+
* read continuously from this device.
74+
*/
75+
udelay(20);
76+
}
77+
78+
*data = readl(priv->base + RNG_REG_RNG_OFFSET);
79+
80+
return 4;
81+
}
82+
83+
static int ingenic_rng_probe(struct platform_device *pdev)
84+
{
85+
struct ingenic_rng *priv;
86+
int ret;
87+
88+
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
89+
if (!priv)
90+
return -ENOMEM;
91+
92+
priv->base = devm_platform_ioremap_resource(pdev, 0);
93+
if (IS_ERR(priv->base)) {
94+
pr_err("%s: Failed to map RNG registers\n", __func__);
95+
ret = PTR_ERR(priv->base);
96+
goto err_free_rng;
97+
}
98+
99+
priv->version = (enum ingenic_rng_version)of_device_get_match_data(&pdev->dev);
100+
101+
priv->rng.name = pdev->name;
102+
priv->rng.init = ingenic_rng_init;
103+
priv->rng.cleanup = ingenic_rng_cleanup;
104+
priv->rng.read = ingenic_rng_read;
105+
106+
ret = hwrng_register(&priv->rng);
107+
if (ret) {
108+
dev_err(&pdev->dev, "Failed to register hwrng\n");
109+
goto err_free_rng;
110+
}
111+
112+
platform_set_drvdata(pdev, priv);
113+
114+
dev_info(&pdev->dev, "Ingenic RNG driver registered\n");
115+
return 0;
116+
117+
err_free_rng:
118+
kfree(priv);
119+
return ret;
120+
}
121+
122+
static int ingenic_rng_remove(struct platform_device *pdev)
123+
{
124+
struct ingenic_rng *priv = platform_get_drvdata(pdev);
125+
126+
hwrng_unregister(&priv->rng);
127+
128+
writel(0, priv->base + RNG_REG_ERNG_OFFSET);
129+
130+
return 0;
131+
}
132+
133+
static const struct of_device_id ingenic_rng_of_match[] = {
134+
{ .compatible = "ingenic,jz4780-rng", .data = (void *) ID_JZ4780 },
135+
{ .compatible = "ingenic,x1000-rng", .data = (void *) ID_X1000 },
136+
{ /* sentinel */ }
137+
};
138+
MODULE_DEVICE_TABLE(of, ingenic_rng_of_match);
139+
140+
static struct platform_driver ingenic_rng_driver = {
141+
.probe = ingenic_rng_probe,
142+
.remove = ingenic_rng_remove,
143+
.driver = {
144+
.name = "ingenic-rng",
145+
.of_match_table = ingenic_rng_of_match,
146+
},
147+
};
148+
149+
module_platform_driver(ingenic_rng_driver);
150+
151+
MODULE_LICENSE("GPL");
152+
MODULE_AUTHOR("PrasannaKumar Muralidharan <[email protected]>");
153+
MODULE_AUTHOR("周琰杰 (Zhou Yanjie) <[email protected]>");
154+
MODULE_DESCRIPTION("Ingenic Random Number Generator driver");

0 commit comments

Comments
 (0)