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