]>
Commit | Line | Data |
---|---|---|
bc40eb27 HS |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* | |
3 | * Copyright 2020, Heinrich Schuchardt <[email protected]> | |
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 | ||
02d249f9 | 93 | /* Get optional "core" clock */ |
bc40eb27 | 94 | err = clk_get_by_name(dev, "core", &pdata->clk); |
02d249f9 | 95 | if (err && err != -ENODATA) |
bc40eb27 HS |
96 | return err; |
97 | ||
98 | return 0; | |
99 | } | |
100 | ||
101 | static const struct dm_rng_ops meson_rng_ops = { | |
102 | .read = meson_rng_read, | |
103 | }; | |
104 | ||
105 | static const struct udevice_id meson_rng_match[] = { | |
106 | { | |
107 | .compatible = "amlogic,meson-rng", | |
108 | }, | |
109 | {}, | |
110 | }; | |
111 | ||
112 | U_BOOT_DRIVER(meson_rng) = { | |
113 | .name = "meson-rng", | |
114 | .id = UCLASS_RNG, | |
115 | .of_match = meson_rng_match, | |
116 | .ops = &meson_rng_ops, | |
117 | .probe = meson_rng_probe, | |
118 | .remove = meson_rng_remove, | |
41575d8e | 119 | .platdata_auto = sizeof(struct meson_rng_platdata), |
bc40eb27 HS |
120 | .ofdata_to_platdata = meson_rng_ofdata_to_platdata, |
121 | }; |