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