[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