Skip to content

Commit a2216e1

Browse files
yangflherbertx
authored andcommitted
crypto: hisilicon/trng - add support for HiSTB TRNG
HiSTB TRNG are found on some HiSilicon STB SoCs. Signed-off-by: David Yang <mmyangfl@gmail.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
1 parent e93c608 commit a2216e1

4 files changed

Lines changed: 187 additions & 1 deletion

File tree

drivers/crypto/hisilicon/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,10 @@ config CRYPTO_DEV_HISI_TRNG
8282
select CRYPTO_RNG
8383
help
8484
Support for HiSilicon TRNG Driver.
85+
86+
config CRYPTO_DEV_HISTB_TRNG
87+
tristate "Support for HiSTB TRNG Driver"
88+
depends on ARCH_HISI || COMPILE_TEST
89+
select HW_RANDOM
90+
help
91+
Support for HiSTB TRNG Driver.

drivers/crypto/hisilicon/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ obj-$(CONFIG_CRYPTO_DEV_HISI_SEC2) += sec2/
55
obj-$(CONFIG_CRYPTO_DEV_HISI_QM) += hisi_qm.o
66
hisi_qm-objs = qm.o sgl.o debugfs.o
77
obj-$(CONFIG_CRYPTO_DEV_HISI_ZIP) += zip/
8-
obj-$(CONFIG_CRYPTO_DEV_HISI_TRNG) += trng/
8+
obj-y += trng/
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
obj-$(CONFIG_CRYPTO_DEV_HISI_TRNG) += hisi-trng-v2.o
22
hisi-trng-v2-objs = trng.o
3+
4+
obj-$(CONFIG_CRYPTO_DEV_HISTB_TRNG) += histb-trng.o
5+
histb-trng-objs += trng-stb.o
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
2+
/*
3+
* Device driver for True RNG in HiSTB SoCs
4+
*
5+
* Copyright (c) 2023 David Yang
6+
*/
7+
8+
#include <crypto/internal/rng.h>
9+
#include <linux/device.h>
10+
#include <linux/err.h>
11+
#include <linux/hw_random.h>
12+
#include <linux/io.h>
13+
#include <linux/iopoll.h>
14+
#include <linux/kernel.h>
15+
#include <linux/module.h>
16+
#include <linux/mutex.h>
17+
#include <linux/of_device.h>
18+
19+
#define HISTB_TRNG_CTRL 0x0
20+
#define RNG_SOURCE GENMASK(1, 0)
21+
#define DROP_ENABLE BIT(5)
22+
#define POST_PROCESS_ENABLE BIT(7)
23+
#define POST_PROCESS_DEPTH GENMASK(15, 8)
24+
#define HISTB_TRNG_NUMBER 0x4
25+
#define HISTB_TRNG_STAT 0x8
26+
#define DATA_COUNT GENMASK(2, 0) /* max 4 */
27+
28+
struct histb_trng_priv {
29+
struct hwrng rng;
30+
void __iomem *base;
31+
};
32+
33+
/*
34+
* Observed:
35+
* depth = 1 -> ~1ms
36+
* depth = 255 -> ~16ms
37+
*/
38+
static int histb_trng_wait(void __iomem *base)
39+
{
40+
u32 val;
41+
42+
return readl_relaxed_poll_timeout(base + HISTB_TRNG_STAT, val,
43+
val & DATA_COUNT, 1000, 30 * 1000);
44+
}
45+
46+
static void histb_trng_init(void __iomem *base, unsigned int depth)
47+
{
48+
u32 val;
49+
50+
val = readl_relaxed(base + HISTB_TRNG_CTRL);
51+
52+
val &= ~RNG_SOURCE;
53+
val |= 2;
54+
55+
val &= ~POST_PROCESS_DEPTH;
56+
val |= min(depth, 0xffu) << 8;
57+
58+
val |= POST_PROCESS_ENABLE;
59+
val |= DROP_ENABLE;
60+
61+
writel_relaxed(val, base + HISTB_TRNG_CTRL);
62+
}
63+
64+
static int histb_trng_read(struct hwrng *rng, void *data, size_t max, bool wait)
65+
{
66+
struct histb_trng_priv *priv = container_of(rng, typeof(*priv), rng);
67+
void __iomem *base = priv->base;
68+
69+
for (int i = 0; i < max; i += sizeof(u32)) {
70+
if (!(readl_relaxed(base + HISTB_TRNG_STAT) & DATA_COUNT)) {
71+
if (!wait)
72+
return i;
73+
if (histb_trng_wait(base)) {
74+
pr_err("failed to generate random number, generated %d\n",
75+
i);
76+
return i ? i : -ETIMEDOUT;
77+
}
78+
}
79+
*(u32 *) (data + i) = readl_relaxed(base + HISTB_TRNG_NUMBER);
80+
}
81+
82+
return max;
83+
}
84+
85+
static unsigned int histb_trng_get_depth(void __iomem *base)
86+
{
87+
return (readl_relaxed(base + HISTB_TRNG_CTRL) & POST_PROCESS_DEPTH) >> 8;
88+
}
89+
90+
static ssize_t
91+
depth_show(struct device *dev, struct device_attribute *attr, char *buf)
92+
{
93+
struct histb_trng_priv *priv = dev_get_drvdata(dev);
94+
void __iomem *base = priv->base;
95+
96+
return sprintf(buf, "%d\n", histb_trng_get_depth(base));
97+
}
98+
99+
static ssize_t
100+
depth_store(struct device *dev, struct device_attribute *attr,
101+
const char *buf, size_t count)
102+
{
103+
struct histb_trng_priv *priv = dev_get_drvdata(dev);
104+
void __iomem *base = priv->base;
105+
unsigned int depth;
106+
107+
if (kstrtouint(buf, 0, &depth))
108+
return -ERANGE;
109+
110+
histb_trng_init(base, depth);
111+
return count;
112+
}
113+
114+
static DEVICE_ATTR_RW(depth);
115+
116+
static struct attribute *histb_trng_attrs[] = {
117+
&dev_attr_depth.attr,
118+
NULL,
119+
};
120+
121+
ATTRIBUTE_GROUPS(histb_trng);
122+
123+
static int histb_trng_probe(struct platform_device *pdev)
124+
{
125+
struct device *dev = &pdev->dev;
126+
struct histb_trng_priv *priv;
127+
void __iomem *base;
128+
int ret;
129+
130+
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
131+
if (!priv)
132+
return -ENOMEM;
133+
134+
base = devm_platform_ioremap_resource(pdev, 0);
135+
if (IS_ERR(base))
136+
return -ENOMEM;
137+
138+
histb_trng_init(base, 144);
139+
if (histb_trng_wait(base)) {
140+
dev_err(dev, "cannot bring up device\n");
141+
return -ENODEV;
142+
}
143+
144+
priv->base = base;
145+
priv->rng.name = pdev->name;
146+
priv->rng.read = histb_trng_read;
147+
ret = devm_hwrng_register(dev, &priv->rng);
148+
if (ret) {
149+
dev_err(dev, "failed to register hwrng: %d\n", ret);
150+
return ret;
151+
}
152+
153+
platform_set_drvdata(pdev, priv);
154+
dev_set_drvdata(dev, priv);
155+
return 0;
156+
}
157+
158+
static const struct of_device_id histb_trng_of_match[] = {
159+
{ .compatible = "hisilicon,histb-trng", },
160+
{ }
161+
};
162+
163+
static struct platform_driver histb_trng_driver = {
164+
.probe = histb_trng_probe,
165+
.driver = {
166+
.name = "histb-trng",
167+
.of_match_table = histb_trng_of_match,
168+
.dev_groups = histb_trng_groups,
169+
},
170+
};
171+
172+
module_platform_driver(histb_trng_driver);
173+
174+
MODULE_DESCRIPTION("HiSTB True RNG");
175+
MODULE_LICENSE("Dual MIT/GPL");
176+
MODULE_AUTHOR("David Yang <mmyangfl@gmail.com>");

0 commit comments

Comments
 (0)