blob: 49037d1165686bec71e461fd12d93d9cd05b0160 [file] [log] [blame]
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +01001// 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
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +01008#include <clk.h>
9#include <dm.h>
10#include <rng.h>
11#include <asm/io.h>
Alexey Romanova9234562023-10-12 10:58:25 +030012#include <linux/iopoll.h>
13
14#define RNG_DATA 0x00
15#define RNG_S4_DATA 0x08
16#define RNG_S4_CFG 0x00
17
18#define RUN_BIT BIT(0)
19#define SEED_READY_STS_BIT BIT(31)
20
21struct meson_rng_priv {
22 u32 (*read)(fdt_addr_t base);
23};
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +010024
Simon Glass8a8d24b2020-12-03 16:55:23 -070025struct meson_rng_plat {
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +010026 fdt_addr_t base;
27 struct clk clk;
Alexey Romanova9234562023-10-12 10:58:25 +030028 struct meson_rng_priv *priv;
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +010029};
30
31/**
32 * meson_rng_read() - fill buffer with random bytes
33 *
34 * @buffer: buffer to receive data
35 * @size: size of buffer
36 *
37 * Return: 0
38 */
39static int meson_rng_read(struct udevice *dev, void *data, size_t len)
40{
Simon Glass8a8d24b2020-12-03 16:55:23 -070041 struct meson_rng_plat *pdata = dev_get_plat(dev);
Alexey Romanova9234562023-10-12 10:58:25 +030042 struct meson_rng_priv *priv = pdata->priv;
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +010043 char *buffer = (char *)data;
44
45 while (len) {
Alexey Romanova9234562023-10-12 10:58:25 +030046 u32 rand = priv->read(pdata->base);
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +010047 size_t step;
48
49 if (len >= 4)
50 step = 4;
51 else
52 step = len;
53 memcpy(buffer, &rand, step);
54 buffer += step;
55 len -= step;
56 }
57 return 0;
58}
59
Alexey Romanova9234562023-10-12 10:58:25 +030060static int meson_rng_wait_status(void __iomem *cfg_addr, int bit)
61{
62 u32 status = 0;
63 int ret;
64
65 ret = readl_relaxed_poll_timeout(cfg_addr,
66 status, !(status & bit),
67 10000);
68 if (ret)
69 return -EBUSY;
70
71 return 0;
72}
73
74static u32 meson_common_rng_read(fdt_addr_t base)
75{
76 return readl(base);
77}
78
79static u32 meson_s4_rng_read(fdt_addr_t base)
80{
81 void __iomem *cfg_addr = (void *)base + RNG_S4_CFG;
82 int err;
83
84 writel_relaxed(readl_relaxed(cfg_addr) | SEED_READY_STS_BIT, cfg_addr);
85
86 err = meson_rng_wait_status(cfg_addr, SEED_READY_STS_BIT);
87 if (err) {
88 pr_err("Seed isn't ready, try again\n");
89 return err;
90 }
91
92 err = meson_rng_wait_status(cfg_addr, RUN_BIT);
93 if (err) {
94 pr_err("Can't get random number, try again\n");
95 return err;
96 }
97
98 return readl_relaxed(base + RNG_S4_DATA);
99}
100
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100101/**
102 * meson_rng_probe() - probe rng device
103 *
104 * @dev: device
105 * Return: 0 if ok
106 */
107static int meson_rng_probe(struct udevice *dev)
108{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700109 struct meson_rng_plat *pdata = dev_get_plat(dev);
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100110 int err;
111
112 err = clk_enable(&pdata->clk);
113 if (err)
114 return err;
115
Alexey Romanova9234562023-10-12 10:58:25 +0300116 pdata->priv = (struct meson_rng_priv *)dev_get_driver_data(dev);
117
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100118 return 0;
119}
120
121/**
122 * meson_rng_remove() - deinitialize rng device
123 *
124 * @dev: device
125 * Return: 0 if ok
126 */
127static int meson_rng_remove(struct udevice *dev)
128{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700129 struct meson_rng_plat *pdata = dev_get_plat(dev);
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100130
131 return clk_disable(&pdata->clk);
132}
133
134/**
Simon Glassd1998a92020-12-03 16:55:21 -0700135 * meson_rng_of_to_plat() - transfer device tree data to plaform data
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100136 *
137 * @dev: device
138 * Return: 0 if ok
139 */
Simon Glassd1998a92020-12-03 16:55:21 -0700140static int meson_rng_of_to_plat(struct udevice *dev)
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100141{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700142 struct meson_rng_plat *pdata = dev_get_plat(dev);
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100143 int err;
144
145 pdata->base = dev_read_addr(dev);
146 if (!pdata->base)
147 return -ENODEV;
148
Neil Armstrong02d249f2020-09-25 09:19:20 +0200149 /* Get optional "core" clock */
Sean Andersone96e2132022-01-15 15:52:47 -0500150 err = clk_get_by_name_optional(dev, "core", &pdata->clk);
151 if (err)
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100152 return err;
153
154 return 0;
155}
156
157static const struct dm_rng_ops meson_rng_ops = {
158 .read = meson_rng_read,
159};
160
Alexey Romanova9234562023-10-12 10:58:25 +0300161static const struct meson_rng_priv meson_rng_priv = {
162 .read = meson_common_rng_read,
163};
164
165static const struct meson_rng_priv meson_rng_priv_s4 = {
166 .read = meson_s4_rng_read,
167};
168
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100169static const struct udevice_id meson_rng_match[] = {
170 {
171 .compatible = "amlogic,meson-rng",
Alexey Romanova9234562023-10-12 10:58:25 +0300172 .data = (ulong)&meson_rng_priv,
173 },
174 {
175 .compatible = "amlogic,meson-s4-rng",
176 .data = (ulong)&meson_rng_priv_s4,
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100177 },
178 {},
179};
180
181U_BOOT_DRIVER(meson_rng) = {
182 .name = "meson-rng",
183 .id = UCLASS_RNG,
184 .of_match = meson_rng_match,
185 .ops = &meson_rng_ops,
186 .probe = meson_rng_probe,
187 .remove = meson_rng_remove,
Simon Glass8a8d24b2020-12-03 16:55:23 -0700188 .plat_auto = sizeof(struct meson_rng_plat),
Simon Glassd1998a92020-12-03 16:55:21 -0700189 .of_to_plat = meson_rng_of_to_plat,
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100190};