xref: /OK3568_Linux_fs/kernel/drivers/char/hw_random/st-rng.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * ST Random Number Generator Driver ST's Platforms
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Author: Pankaj Dev: <pankaj.dev@st.com>
6*4882a593Smuzhiyun  *         Lee Jones <lee.jones@linaro.org>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Copyright (C) 2015 STMicroelectronics (R&D) Limited
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/clk.h>
12*4882a593Smuzhiyun #include <linux/delay.h>
13*4882a593Smuzhiyun #include <linux/hw_random.h>
14*4882a593Smuzhiyun #include <linux/io.h>
15*4882a593Smuzhiyun #include <linux/kernel.h>
16*4882a593Smuzhiyun #include <linux/module.h>
17*4882a593Smuzhiyun #include <linux/of.h>
18*4882a593Smuzhiyun #include <linux/platform_device.h>
19*4882a593Smuzhiyun #include <linux/slab.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun /* Registers */
22*4882a593Smuzhiyun #define ST_RNG_STATUS_REG		0x20
23*4882a593Smuzhiyun #define ST_RNG_DATA_REG			0x24
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /* Registers fields */
26*4882a593Smuzhiyun #define ST_RNG_STATUS_BAD_SEQUENCE	BIT(0)
27*4882a593Smuzhiyun #define ST_RNG_STATUS_BAD_ALTERNANCE	BIT(1)
28*4882a593Smuzhiyun #define ST_RNG_STATUS_FIFO_FULL		BIT(5)
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #define ST_RNG_SAMPLE_SIZE		2 /* 2 Byte (16bit) samples */
31*4882a593Smuzhiyun #define ST_RNG_FIFO_DEPTH		4
32*4882a593Smuzhiyun #define ST_RNG_FIFO_SIZE		(ST_RNG_FIFO_DEPTH * ST_RNG_SAMPLE_SIZE)
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun /*
35*4882a593Smuzhiyun  * Samples are documented to be available every 0.667us, so in theory
36*4882a593Smuzhiyun  * the 4 sample deep FIFO should take 2.668us to fill.  However, during
37*4882a593Smuzhiyun  * thorough testing, it became apparent that filling the FIFO actually
38*4882a593Smuzhiyun  * takes closer to 12us.  We then multiply by 2 in order to account for
39*4882a593Smuzhiyun  * the lack of udelay()'s reliability, suggested by Russell King.
40*4882a593Smuzhiyun  */
41*4882a593Smuzhiyun #define ST_RNG_FILL_FIFO_TIMEOUT	(12 * 2)
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun struct st_rng_data {
44*4882a593Smuzhiyun 	void __iomem	*base;
45*4882a593Smuzhiyun 	struct clk	*clk;
46*4882a593Smuzhiyun 	struct hwrng	ops;
47*4882a593Smuzhiyun };
48*4882a593Smuzhiyun 
st_rng_read(struct hwrng * rng,void * data,size_t max,bool wait)49*4882a593Smuzhiyun static int st_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun 	struct st_rng_data *ddata = (struct st_rng_data *)rng->priv;
52*4882a593Smuzhiyun 	u32 status;
53*4882a593Smuzhiyun 	int i;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	/* Wait until FIFO is full - max 4uS*/
56*4882a593Smuzhiyun 	for (i = 0; i < ST_RNG_FILL_FIFO_TIMEOUT; i++) {
57*4882a593Smuzhiyun 		status = readl_relaxed(ddata->base + ST_RNG_STATUS_REG);
58*4882a593Smuzhiyun 		if (status & ST_RNG_STATUS_FIFO_FULL)
59*4882a593Smuzhiyun 			break;
60*4882a593Smuzhiyun 		udelay(1);
61*4882a593Smuzhiyun 	}
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	if (i == ST_RNG_FILL_FIFO_TIMEOUT)
64*4882a593Smuzhiyun 		return 0;
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	for (i = 0; i < ST_RNG_FIFO_SIZE && i < max; i += 2)
67*4882a593Smuzhiyun 		*(u16 *)(data + i) =
68*4882a593Smuzhiyun 			readl_relaxed(ddata->base + ST_RNG_DATA_REG);
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	return i;	/* No of bytes read */
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun 
st_rng_probe(struct platform_device * pdev)73*4882a593Smuzhiyun static int st_rng_probe(struct platform_device *pdev)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	struct st_rng_data *ddata;
76*4882a593Smuzhiyun 	struct clk *clk;
77*4882a593Smuzhiyun 	void __iomem *base;
78*4882a593Smuzhiyun 	int ret;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
81*4882a593Smuzhiyun 	if (!ddata)
82*4882a593Smuzhiyun 		return -ENOMEM;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	base = devm_platform_ioremap_resource(pdev, 0);
85*4882a593Smuzhiyun 	if (IS_ERR(base))
86*4882a593Smuzhiyun 		return PTR_ERR(base);
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	clk = devm_clk_get(&pdev->dev, NULL);
89*4882a593Smuzhiyun 	if (IS_ERR(clk))
90*4882a593Smuzhiyun 		return PTR_ERR(clk);
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	ret = clk_prepare_enable(clk);
93*4882a593Smuzhiyun 	if (ret)
94*4882a593Smuzhiyun 		return ret;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	ddata->ops.priv	= (unsigned long)ddata;
97*4882a593Smuzhiyun 	ddata->ops.read	= st_rng_read;
98*4882a593Smuzhiyun 	ddata->ops.name	= pdev->name;
99*4882a593Smuzhiyun 	ddata->base	= base;
100*4882a593Smuzhiyun 	ddata->clk	= clk;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	dev_set_drvdata(&pdev->dev, ddata);
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	ret = devm_hwrng_register(&pdev->dev, &ddata->ops);
105*4882a593Smuzhiyun 	if (ret) {
106*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Failed to register HW RNG\n");
107*4882a593Smuzhiyun 		clk_disable_unprepare(clk);
108*4882a593Smuzhiyun 		return ret;
109*4882a593Smuzhiyun 	}
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	dev_info(&pdev->dev, "Successfully registered HW RNG\n");
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	return 0;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun 
st_rng_remove(struct platform_device * pdev)116*4882a593Smuzhiyun static int st_rng_remove(struct platform_device *pdev)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun 	struct st_rng_data *ddata = dev_get_drvdata(&pdev->dev);
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	clk_disable_unprepare(ddata->clk);
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	return 0;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun static const struct of_device_id st_rng_match[] __maybe_unused = {
126*4882a593Smuzhiyun 	{ .compatible = "st,rng" },
127*4882a593Smuzhiyun 	{},
128*4882a593Smuzhiyun };
129*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, st_rng_match);
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun static struct platform_driver st_rng_driver = {
132*4882a593Smuzhiyun 	.driver = {
133*4882a593Smuzhiyun 		.name = "st-hwrandom",
134*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(st_rng_match),
135*4882a593Smuzhiyun 	},
136*4882a593Smuzhiyun 	.probe = st_rng_probe,
137*4882a593Smuzhiyun 	.remove = st_rng_remove
138*4882a593Smuzhiyun };
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun module_platform_driver(st_rng_driver);
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun MODULE_AUTHOR("Pankaj Dev <pankaj.dev@st.com>");
143*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
144