[PATCH v1] drivers: rng: add check status bit feature
Alexey Romanov
avromanov at sberdevices.ru
Wed Jun 21 12:24:01 CEST 2023
For some Amlogic SOC's, the mechanism for obtain a random number
has been changed. For example, S4 now uses a status bit wait algo.
Signed-off-by: Alexey Romanov <avromanov at sberdevices.ru>
---
drivers/rng/meson-rng.c | 73 +++++++++++++++++++++++++++++++++++++----
1 file changed, 67 insertions(+), 6 deletions(-)
diff --git a/drivers/rng/meson-rng.c b/drivers/rng/meson-rng.c
index e0a1e8c7e04..3bf2eb9cf87 100644
--- a/drivers/rng/meson-rng.c
+++ b/drivers/rng/meson-rng.c
@@ -11,36 +11,82 @@
#include <rng.h>
#include <asm/io.h>
+struct meson_rng_data {
+ bool check_status_bit;
+};
+
struct meson_rng_plat {
fdt_addr_t base;
struct clk clk;
+ struct meson_rng_data *data;
};
+#define RETRY_CNT 100
+#define RNG_OUT_OFFSET 0x08
+
+#define SEED_READY_STS_BIT 0
+#define RUN_BIT 31
+
+static int meson_rng_wait_status(struct meson_rng_plat *pdata, int bit)
+{
+ u32 status;
+ u32 cnt = 0;
+
+ pr_debug("Poll status of bit: %d\n", bit);
+
+ do {
+ status = readl(pdata->base) & BIT(bit);
+ } while (status && (cnt++ < RETRY_CNT));
+
+ if (cnt == RETRY_CNT) {
+ pr_err("Can't get random number, try again");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
/**
* meson_rng_read() - fill buffer with random bytes
*
* @buffer: buffer to receive data
* @size: size of buffer
*
- * Return: 0
+ * Return: 0 on success or -errno in failure
*/
static int meson_rng_read(struct udevice *dev, void *data, size_t len)
{
struct meson_rng_plat *pdata = dev_get_plat(dev);
+ struct meson_rng_data *rng_data = pdata->data;
char *buffer = (char *)data;
+ int err;
while (len) {
- u32 rand = readl(pdata->base);
+ u32 rand;
size_t step;
- if (len >= 4)
- step = 4;
- else
- step = len;
+ if (rng_data->check_status_bit) {
+ writel(readl(pdata->base) | BIT(SEED_READY_STS_BIT), pdata->base);
+
+ err = meson_rng_wait_status(pdata, SEED_READY_STS_BIT);
+ if (err)
+ return err;
+
+ err = meson_rng_wait_status(pdata, RUN_BIT);
+ if (err)
+ return err;
+
+ rand = readl(pdata->base + RNG_OUT_OFFSET);
+ } else {
+ rand = readl(pdata->base);
+ }
+
+ step = min_t(u32, len, 4);
memcpy(buffer, &rand, step);
buffer += step;
len -= step;
}
+
return 0;
}
@@ -90,6 +136,8 @@ static int meson_rng_of_to_plat(struct udevice *dev)
if (!pdata->base)
return -ENODEV;
+ pdata->data = (struct meson_rng_data *)dev_get_driver_data(dev);
+
/* Get optional "core" clock */
err = clk_get_by_name_optional(dev, "core", &pdata->clk);
if (err)
@@ -102,9 +150,22 @@ static const struct dm_rng_ops meson_rng_ops = {
.read = meson_rng_read,
};
+static const struct meson_rng_data meson_rng_data = {
+ .check_status_bit = false,
+};
+
+static const struct meson_rng_data meson_rng_data_s4 = {
+ .check_status_bit = true,
+};
+
static const struct udevice_id meson_rng_match[] = {
{
.compatible = "amlogic,meson-rng",
+ .data = (ulong)&meson_rng_data,
+ },
+ {
+ .compatible = "amlogic,meson-rng-s4",
+ .data = (ulong)&meson_rng_data_s4,
},
{},
};
--
2.38.1
More information about the U-Boot
mailing list