The vendor TF-A blobs for RK3562 leave the TRNG and RK RNG clocks gated
when returning to U-Boot proper.

Try to enable clocks while reading or otherwise accessing TRNG/RKRNG
regs to ensure random data can successfully be read on affected SoCs.

This is not expected to have any impact on SoCs using a clock driver
with unimplemented enable/disable ops.

Signed-off-by: Jonas Karlman <[email protected]>
---
 drivers/rng/rockchip_rng.c | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/drivers/rng/rockchip_rng.c b/drivers/rng/rockchip_rng.c
index 178a76c09347..b674d270d8ac 100644
--- a/drivers/rng/rockchip_rng.c
+++ b/drivers/rng/rockchip_rng.c
@@ -3,6 +3,7 @@
  * Copyright (c) 2020 Fuzhou Rockchip Electronics Co., Ltd
  */
 
+#include <clk.h>
 #include <dm.h>
 #include <rng.h>
 #include <asm/arch-rockchip/hardware.h>
@@ -103,6 +104,7 @@ struct rk_rng_soc_data {
 
 struct rk_rng_plat {
        fdt_addr_t base;
+       struct clk_bulk clks;
        struct rk_rng_soc_data *soc_data;
 };
 
@@ -296,7 +298,7 @@ static int rockchip_rng_read(struct udevice *dev, void 
*data, size_t len)
 {
        unsigned char *buf = data;
        unsigned int i;
-       int ret = -EIO;
+       int ret;
 
        struct rk_rng_plat *pdata = dev_get_priv(dev);
 
@@ -306,6 +308,10 @@ static int rockchip_rng_read(struct udevice *dev, void 
*data, size_t len)
        if (!pdata->soc_data || !pdata->soc_data->rk_rng_read)
                return -EINVAL;
 
+       ret = clk_enable_bulk(&pdata->clks);
+       if (ret && ret != -ENOENT)
+               return ret;
+
        for (i = 0; i < len / RK_HW_RNG_MAX; i++, buf += RK_HW_RNG_MAX) {
                ret = pdata->soc_data->rk_rng_read(dev, buf, RK_HW_RNG_MAX);
                if (ret)
@@ -317,6 +323,7 @@ static int rockchip_rng_read(struct udevice *dev, void 
*data, size_t len)
                                                   len % RK_HW_RNG_MAX);
 
 exit:
+       clk_disable_bulk(&pdata->clks);
        return ret;
 }
 
@@ -336,12 +343,22 @@ static int rockchip_rng_of_to_plat(struct udevice *dev)
 static int rockchip_rng_probe(struct udevice *dev)
 {
        struct rk_rng_plat *pdata = dev_get_priv(dev);
-       int ret = 0;
+       int ret;
+
+       ret = clk_get_bulk(dev, &pdata->clks);
+       if (ret && ret != -ENOENT && ret != -ENOSYS)
+               return ret;
 
        pdata->soc_data = (struct rk_rng_soc_data *)dev_get_driver_data(dev);
 
-       if (pdata->soc_data->rk_rng_init)
+       if (pdata->soc_data->rk_rng_init) {
+               ret = clk_enable_bulk(&pdata->clks);
+               if (ret && ret != -ENOENT)
+                       return ret;
+
                ret = pdata->soc_data->rk_rng_init(dev);
+               clk_disable_bulk(&pdata->clks);
+       }
 
        return ret;
 }
-- 
2.55.0

Reply via email to