drivers/rng: add Amlogic hardware RNG driver
[oweals/u-boot.git] / drivers / rng / meson-rng.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
4  *
5  * Driver for Amlogic hardware random number generator
6  */
7
8 #include <common.h>
9 #include <clk.h>
10 #include <dm.h>
11 #include <rng.h>
12 #include <asm/io.h>
13
14 struct meson_rng_platdata {
15         fdt_addr_t base;
16         struct clk clk;
17 };
18
19 /**
20  * meson_rng_read() - fill buffer with random bytes
21  *
22  * @buffer:     buffer to receive data
23  * @size:       size of buffer
24  *
25  * Return:      0
26  */
27 static int meson_rng_read(struct udevice *dev, void *data, size_t len)
28 {
29         struct meson_rng_platdata *pdata = dev_get_platdata(dev);
30         char *buffer = (char *)data;
31
32         while (len) {
33                 u32 rand = readl(pdata->base);
34                 size_t step;
35
36                 if (len >= 4)
37                         step = 4;
38                 else
39                         step = len;
40                 memcpy(buffer, &rand, step);
41                 buffer += step;
42                 len -= step;
43         }
44         return 0;
45 }
46
47 /**
48  * meson_rng_probe() - probe rng device
49  *
50  * @dev:        device
51  * Return:      0 if ok
52  */
53 static int meson_rng_probe(struct udevice *dev)
54 {
55         struct meson_rng_platdata *pdata = dev_get_platdata(dev);
56         int err;
57
58         err = clk_enable(&pdata->clk);
59         if (err)
60                 return err;
61
62         return 0;
63 }
64
65 /**
66  * meson_rng_remove() - deinitialize rng device
67  *
68  * @dev:        device
69  * Return:      0 if ok
70  */
71 static int meson_rng_remove(struct udevice *dev)
72 {
73         struct meson_rng_platdata *pdata = dev_get_platdata(dev);
74
75         return clk_disable(&pdata->clk);
76 }
77
78 /**
79  * meson_rng_ofdata_to_platdata() - transfer device tree data to plaform data
80  *
81  * @dev:        device
82  * Return:      0 if ok
83  */
84 static int meson_rng_ofdata_to_platdata(struct udevice *dev)
85 {
86         struct meson_rng_platdata *pdata = dev_get_platdata(dev);
87         int err;
88
89         pdata->base = dev_read_addr(dev);
90         if (!pdata->base)
91                 return -ENODEV;
92
93         err = clk_get_by_name(dev, "core", &pdata->clk);
94         if (err)
95                 return err;
96
97         return 0;
98 }
99
100 static const struct dm_rng_ops meson_rng_ops = {
101         .read = meson_rng_read,
102 };
103
104 static const struct udevice_id meson_rng_match[] = {
105         {
106                 .compatible = "amlogic,meson-rng",
107         },
108         {},
109 };
110
111 U_BOOT_DRIVER(meson_rng) = {
112         .name = "meson-rng",
113         .id = UCLASS_RNG,
114         .of_match = meson_rng_match,
115         .ops = &meson_rng_ops,
116         .probe = meson_rng_probe,
117         .remove = meson_rng_remove,
118         .platdata_auto_alloc_size = sizeof(struct meson_rng_platdata),
119         .ofdata_to_platdata = meson_rng_ofdata_to_platdata,
120 };