1 // SPDX-License-Identifier: GPL-2.0-or-later OR MIT
3 * Copyright (c) 2023 David Yang
7 #include <linux/hw_random.h>
9 #include <linux/iopoll.h>
10 #include <linux/kernel.h>
11 #include <linux/mod_devicetable.h>
12 #include <linux/module.h>
13 #include <linux/platform_device.h>
16 #define RNG_SOURCE GENMASK(1, 0)
17 #define DROP_ENABLE BIT(5)
18 #define POST_PROCESS_ENABLE BIT(7)
19 #define POST_PROCESS_DEPTH GENMASK(15, 8)
20 #define RNG_NUMBER 0x4
22 #define DATA_COUNT GENMASK(2, 0) /* max 4 */
24 struct histb_rng_priv
{
32 * depth = 255 -> ~16ms
34 static int histb_rng_wait(void __iomem
*base
)
38 return readl_relaxed_poll_timeout(base
+ RNG_STAT
, val
,
39 val
& DATA_COUNT
, 1000, 30 * 1000);
42 static void histb_rng_init(void __iomem
*base
, unsigned int depth
)
46 val
= readl_relaxed(base
+ RNG_CTRL
);
51 val
&= ~POST_PROCESS_DEPTH
;
52 val
|= min(depth
, 0xffu
) << 8;
54 val
|= POST_PROCESS_ENABLE
;
57 writel_relaxed(val
, base
+ RNG_CTRL
);
60 static int histb_rng_read(struct hwrng
*rng
, void *data
, size_t max
, bool wait
)
62 struct histb_rng_priv
*priv
= container_of(rng
, typeof(*priv
), rng
);
63 void __iomem
*base
= priv
->base
;
65 for (int i
= 0; i
< max
; i
+= sizeof(u32
)) {
66 if (!(readl_relaxed(base
+ RNG_STAT
) & DATA_COUNT
)) {
69 if (histb_rng_wait(base
)) {
70 pr_err("failed to generate random number, generated %d\n",
72 return i
? i
: -ETIMEDOUT
;
75 *(u32
*) (data
+ i
) = readl_relaxed(base
+ RNG_NUMBER
);
81 static unsigned int histb_rng_get_depth(void __iomem
*base
)
83 return (readl_relaxed(base
+ RNG_CTRL
) & POST_PROCESS_DEPTH
) >> 8;
87 depth_show(struct device
*dev
, struct device_attribute
*attr
, char *buf
)
89 struct histb_rng_priv
*priv
= dev_get_drvdata(dev
);
90 void __iomem
*base
= priv
->base
;
92 return sprintf(buf
, "%u\n", histb_rng_get_depth(base
));
96 depth_store(struct device
*dev
, struct device_attribute
*attr
,
97 const char *buf
, size_t count
)
99 struct histb_rng_priv
*priv
= dev_get_drvdata(dev
);
100 void __iomem
*base
= priv
->base
;
103 if (kstrtouint(buf
, 0, &depth
))
106 histb_rng_init(base
, depth
);
110 static DEVICE_ATTR_RW(depth
);
112 static struct attribute
*histb_rng_attrs
[] = {
113 &dev_attr_depth
.attr
,
117 ATTRIBUTE_GROUPS(histb_rng
);
119 static int histb_rng_probe(struct platform_device
*pdev
)
121 struct device
*dev
= &pdev
->dev
;
122 struct histb_rng_priv
*priv
;
126 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
130 base
= devm_platform_ioremap_resource(pdev
, 0);
132 return PTR_ERR(base
);
134 histb_rng_init(base
, 144);
135 if (histb_rng_wait(base
)) {
136 dev_err(dev
, "cannot bring up device\n");
141 priv
->rng
.name
= pdev
->name
;
142 priv
->rng
.read
= histb_rng_read
;
143 ret
= devm_hwrng_register(dev
, &priv
->rng
);
145 dev_err(dev
, "failed to register hwrng: %d\n", ret
);
149 platform_set_drvdata(pdev
, priv
);
150 dev_set_drvdata(dev
, priv
);
154 static const struct of_device_id histb_rng_of_match
[] = {
155 { .compatible
= "hisilicon,histb-rng", },
158 MODULE_DEVICE_TABLE(of
, histb_rng_of_match
);
160 static struct platform_driver histb_rng_driver
= {
161 .probe
= histb_rng_probe
,
164 .of_match_table
= histb_rng_of_match
,
165 .dev_groups
= histb_rng_groups
,
169 module_platform_driver(histb_rng_driver
);
171 MODULE_DESCRIPTION("Hisilicon STB random number generator driver");
172 MODULE_LICENSE("Dual MIT/GPL");
173 MODULE_AUTHOR("David Yang <mmyangfl@gmail.com>");