Hi,

On 21/06/2023 12:24, Alexey Romanov wrote:
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.

Thanks for the change, but could you add this first in Linux with the
associated bindings update and DT changes then port it to U-boot ?

Thanks,
Neil


Signed-off-by: Alexey Romanov <avroma...@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,
        },
        {},
  };

Reply via email to