Refactor the driver to use driver data and ops to simplify handling
of SoCs that require a unique read op.

Move handling of the aligned bounce buffer to main read op in order to
keep the SoC unique read op simple.

Signed-off-by: Jonas Karlman <jo...@kwiboo.se>
---
 drivers/misc/rockchip-efuse.c | 160 ++++++++++++++++++----------------
 1 file changed, 85 insertions(+), 75 deletions(-)

diff --git a/drivers/misc/rockchip-efuse.c b/drivers/misc/rockchip-efuse.c
index 083ee65e0ad7..864c9c15bbe5 100644
--- a/drivers/misc/rockchip-efuse.c
+++ b/drivers/misc/rockchip-efuse.c
@@ -13,50 +13,40 @@
 #include <dm.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
+#include <malloc.h>
 #include <misc.h>
 
-#define RK3399_A_SHIFT          16
-#define RK3399_A_MASK           0x3ff
-#define RK3399_NFUSES           32
-#define RK3399_BYTES_PER_FUSE   4
-#define RK3399_STROBSFTSEL      BIT(9)
-#define RK3399_RSB              BIT(7)
-#define RK3399_PD               BIT(5)
-#define RK3399_PGENB            BIT(3)
-#define RK3399_LOAD             BIT(2)
-#define RK3399_STROBE           BIT(1)
-#define RK3399_CSB              BIT(0)
-
-struct rockchip_efuse_regs {
-       u32 ctrl;      /* 0x00  efuse control register */
-       u32 dout;      /* 0x04  efuse data out register */
-       u32 rf;        /* 0x08  efuse redundancy bit used register */
-       u32 _rsvd0;
-       u32 jtag_pass; /* 0x10  JTAG password */
-       u32 strobe_finish_ctrl;
-                      /* 0x14  efuse strobe finish control register */
-};
+#define EFUSE_CTRL             0x0000
+#define RK3399_A_SHIFT         16
+#define RK3399_A_MASK          GENMASK(25, 16)
+#define RK3399_ADDR(n)         ((n) << RK3399_A_SHIFT)
+#define RK3399_STROBSFTSEL     BIT(9)
+#define RK3399_RSB             BIT(7)
+#define RK3399_PD              BIT(5)
+#define RK3399_PGENB           BIT(3)
+#define RK3399_LOAD            BIT(2)
+#define RK3399_STROBE          BIT(1)
+#define RK3399_CSB             BIT(0)
+#define EFUSE_DOUT             0x0004
 
 struct rockchip_efuse_plat {
        void __iomem *base;
-       struct clk *clk;
+};
+
+struct rockchip_efuse_data {
+       int (*read)(struct udevice *dev, int offset, void *buf, int size);
+       int size;
+       int block_size;
 };
 
 #if defined(DEBUG)
-static int dump_efuses(struct cmd_tbl *cmdtp, int flag,
-                      int argc, char *const argv[])
+static int dump_efuse(struct cmd_tbl *cmdtp, int flag,
+                     int argc, char *const argv[])
 {
-       /*
-        * N.B.: This function is tailored towards the RK3399 and assumes that
-        *       there's always 32 fuses x 32 bits (i.e. 128 bytes of data) to
-        *       be read.
-        */
-
        struct udevice *dev;
-       u8 fuses[128];
-       int ret;
+       u8 data[4];
+       int ret, i;
 
-       /* retrieve the device */
        ret = uclass_get_device_by_driver(UCLASS_MISC,
                                          DM_DRIVER_GET(rockchip_efuse), &dev);
        if (ret) {
@@ -64,21 +54,20 @@ static int dump_efuses(struct cmd_tbl *cmdtp, int flag,
                return 0;
        }
 
-       ret = misc_read(dev, 0, &fuses, sizeof(fuses));
-       if (ret < 0) {
-               printf("%s: misc_read failed\n", __func__);
-               return 0;
-       }
+       for (i = 0; true; i += sizeof(data)) {
+               ret = misc_read(dev, i, &data, sizeof(data));
+               if (ret < 0)
+                       return 0;
 
-       printf("efuse-contents:\n");
-       print_buffer(0, fuses, 1, 128, 16);
+               print_buffer(i, data, sizeof(data), 1, 1);
+       }
 
        return 0;
 }
 
 U_BOOT_CMD(
-       rk3399_dump_efuses, 1, 1, dump_efuses,
-       "Dump the content of the efuses",
+       dump_efuse, 1, 1, dump_efuse,
+       "Dump the content of the efuse",
        ""
 );
 #endif
@@ -86,43 +75,25 @@ U_BOOT_CMD(
 static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset,
                                      void *buf, int size)
 {
-       struct rockchip_efuse_plat *plat = dev_get_plat(dev);
-       struct rockchip_efuse_regs *efuse =
-               (struct rockchip_efuse_regs *)plat->base;
-
-       unsigned int addr_start, addr_end, addr_offset;
-       u32 out_value;
-       u8  bytes[RK3399_NFUSES * RK3399_BYTES_PER_FUSE];
-       int i = 0;
-       u32 addr;
-
-       addr_start = offset / RK3399_BYTES_PER_FUSE;
-       addr_offset = offset % RK3399_BYTES_PER_FUSE;
-       addr_end = DIV_ROUND_UP(offset + size, RK3399_BYTES_PER_FUSE);
-
-       /* cap to the size of the efuse block */
-       if (addr_end > RK3399_NFUSES)
-               addr_end = RK3399_NFUSES;
+       struct rockchip_efuse_plat *efuse = dev_get_plat(dev);
+       u32 *buffer = buf;
 
+       /* Switch to array read mode */
        writel(RK3399_LOAD | RK3399_PGENB | RK3399_STROBSFTSEL | RK3399_RSB,
-              &efuse->ctrl);
+              efuse->base + EFUSE_CTRL);
        udelay(1);
-       for (addr = addr_start; addr < addr_end; addr++) {
-               setbits_le32(&efuse->ctrl,
-                            RK3399_STROBE | (addr << RK3399_A_SHIFT));
+
+       while (size--) {
+               setbits_le32(efuse->base + EFUSE_CTRL,
+                            RK3399_STROBE | RK3399_ADDR(offset++));
                udelay(1);
-               out_value = readl(&efuse->dout);
-               clrbits_le32(&efuse->ctrl, RK3399_STROBE);
+               *buffer++ = readl(efuse->base + EFUSE_DOUT);
+               clrbits_le32(efuse->base + EFUSE_CTRL, RK3399_STROBE);
                udelay(1);
-
-               memcpy(&bytes[i], &out_value, RK3399_BYTES_PER_FUSE);
-               i += RK3399_BYTES_PER_FUSE;
        }
 
-       /* Switch to standby mode */
-       writel(RK3399_PD | RK3399_CSB, &efuse->ctrl);
-
-       memcpy(buf, bytes + addr_offset, size);
+       /* Switch to power-down mode */
+       writel(RK3399_PD | RK3399_CSB, efuse->base + EFUSE_CTRL);
 
        return 0;
 }
@@ -130,7 +101,36 @@ static int rockchip_rk3399_efuse_read(struct udevice *dev, 
int offset,
 static int rockchip_efuse_read(struct udevice *dev, int offset,
                               void *buf, int size)
 {
-       return rockchip_rk3399_efuse_read(dev, offset, buf, size);
+       const struct rockchip_efuse_data *data =
+               (void *)dev_get_driver_data(dev);
+       u32 block_start, block_end, block_offset, blocks;
+       u8 *buffer;
+       int ret;
+
+       if (offset < 0 || !buf || size <= 0 || offset + size > data->size)
+               return -EINVAL;
+
+       if (!data->read)
+               return -ENOSYS;
+
+       if (data->block_size <= 1)
+               return data->read(dev, offset, buf, size);
+
+       block_start = offset / data->block_size;
+       block_offset = offset % data->block_size;
+       block_end = DIV_ROUND_UP(offset + size, data->block_size);
+       blocks = block_end - block_start;
+
+       buffer = calloc(blocks, data->block_size);
+       if (!buffer)
+               return -ENOMEM;
+
+       ret = data->read(dev, block_start, buffer, blocks);
+       if (!ret)
+               memcpy(buf, buffer + block_offset, size);
+
+       free(buffer);
+       return ret;
 }
 
 static const struct misc_ops rockchip_efuse_ops = {
@@ -142,11 +142,21 @@ static int rockchip_efuse_of_to_plat(struct udevice *dev)
        struct rockchip_efuse_plat *plat = dev_get_plat(dev);
 
        plat->base = dev_read_addr_ptr(dev);
+
        return 0;
 }
 
+static const struct rockchip_efuse_data rk3399_data = {
+       .read = rockchip_rk3399_efuse_read,
+       .size = 0x80,
+       .block_size = 4,
+};
+
 static const struct udevice_id rockchip_efuse_ids[] = {
-       { .compatible = "rockchip,rk3399-efuse" },
+       {
+               .compatible = "rockchip,rk3399-efuse",
+               .data = (ulong)&rk3399_data,
+       },
        {}
 };
 
@@ -155,6 +165,6 @@ U_BOOT_DRIVER(rockchip_efuse) = {
        .id = UCLASS_MISC,
        .of_match = rockchip_efuse_ids,
        .of_to_plat = rockchip_efuse_of_to_plat,
-       .plat_auto      = sizeof(struct rockchip_efuse_plat),
+       .plat_auto = sizeof(struct rockchip_efuse_plat),
        .ops = &rockchip_efuse_ops,
 };
-- 
2.39.1

Reply via email to