From: Paul Burton <paul.bur...@imgtec.com>

Add driver for the efuse block in the JZ47xx SOC.

Cc: Daniel Schwierzeck <daniel.schwierz...@gmail.com>
Signed-off-by: Paul Burton <paul.bur...@imgtec.com>
Signed-off-by: Marek Vasut <marek.va...@gmail.com>
Signed-off-by: Ezequiel Garcia <ezequ...@collabora.com>
---
 drivers/misc/Kconfig        |   6 +++
 drivers/misc/Makefile       |   1 +
 drivers/misc/jz4780_efuse.c | 104 ++++++++++++++++++++++++++++++++++++
 3 files changed, 111 insertions(+)
 create mode 100644 drivers/misc/jz4780_efuse.c

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 48febc47d263..704c8dd1955f 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -120,6 +120,12 @@ config FSL_SEC_MON
          Security Monitor can be transitioned on any security failures,
          like software violations or hardware security violations.
 
+config JZ4780_EFUSE
+       bool "Ingenic JZ4780 eFUSE support"
+       depends on ARCH_JZ47XX
+       help
+         This selects support for the eFUSE on Ingenic JZ4780 SoCs.
+
 config MXC_OCOTP
        bool "Enable MXC OCOTP Driver"
        help
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 302d44159274..6bdf5054f475 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -62,3 +62,4 @@ obj-$(CONFIG_TEGRA_CAR) += tegra_car.o
 obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
 obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress_config.o
 obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o
+obj-$(CONFIG_JZ4780_EFUSE) += jz4780_efuse.o
diff --git a/drivers/misc/jz4780_efuse.c b/drivers/misc/jz4780_efuse.c
new file mode 100644
index 000000000000..7b327f54b15c
--- /dev/null
+++ b/drivers/misc/jz4780_efuse.c
@@ -0,0 +1,104 @@
+/*
+ * JZ4780 EFUSE driver
+ *
+ * Copyright (c) 2014 Imagination Technologies
+ * Author: Alex Smith <alex.sm...@imgtec.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+#include <errno.h>
+#include <mach/jz4780.h>
+#include <wait_bit.h>
+
+#define EFUSE_EFUCTRL                  0xd0
+#define EFUSE_EFUCFG                   0xd4
+#define EFUSE_EFUSTATE                 0xd8
+#define EFUSE_EFUDATA(n)               (0xdc + ((n) * 4))
+
+#define EFUSE_EFUCTRL_RD_EN            BIT(0)
+#define EFUSE_EFUCTRL_LEN_BIT          16
+#define EFUSE_EFUCTRL_LEN_MASK         0x1f
+#define EFUSE_EFUCTRL_ADDR_BIT         21
+#define EFUSE_EFUCTRL_ADDR_MASK                0x1ff
+#define EFUSE_EFUCTRL_CS               BIT(30)
+
+#define EFUSE_EFUCFG_RD_STROBE_BIT     16
+#define EFUSE_EFUCFG_RD_STROBE_MASK    0xf
+#define EFUSE_EFUCFG_RD_ADJ_BIT                20
+#define EFUSE_EFUCFG_RD_ADJ_MASK       0xf
+
+#define EFUSE_EFUSTATE_RD_DONE         BIT(0)
+
+static void jz4780_efuse_read_chunk(size_t addr, size_t count, u8 *buf)
+{
+       void __iomem *regs = (void __iomem *)NEMC_BASE;
+       size_t i;
+       u32 val;
+       int ret;
+
+       val = EFUSE_EFUCTRL_RD_EN |
+             ((count - 1) << EFUSE_EFUCTRL_LEN_BIT) |
+             (addr << EFUSE_EFUCTRL_ADDR_BIT) |
+             ((addr > 0x200) ? EFUSE_EFUCTRL_CS : 0);
+       writel(val, regs + EFUSE_EFUCTRL);
+
+       ret = wait_for_bit_le32(regs + EFUSE_EFUSTATE,
+                       EFUSE_EFUSTATE_RD_DONE, true, 10000, false);
+       if (ret)
+               return;
+
+       if ((count % 4) == 0) {
+               for (i = 0; i < count / 4; i++) {
+                       val = readl(regs + EFUSE_EFUDATA(i));
+                       put_unaligned(val, (u32 *)(buf + (i * 4)));
+               }
+       } else {
+               val = readl(regs + EFUSE_EFUDATA(0));
+               if (count > 2)
+                       buf[2] = (val >> 16) & 0xff;
+               if (count > 1)
+                       buf[1] = (val >> 8) & 0xff;
+               buf[0] = val & 0xff;
+       }
+}
+
+static inline int jz4780_efuse_chunk_size(size_t count)
+{
+       if (count >= 32)
+               return 32;
+       else if ((count / 4) > 0)
+               return (count / 4) * 4;
+       else
+               return count % 4;
+}
+
+void jz4780_efuse_read(size_t addr, size_t count, u8 *buf)
+{
+       size_t chunk;
+
+       while (count > 0) {
+               chunk = jz4780_efuse_chunk_size(count);
+               jz4780_efuse_read_chunk(addr, chunk, buf);
+               addr += chunk;
+               buf += chunk;
+               count -= chunk;
+       }
+}
+
+void jz4780_efuse_init(u32 ahb2_rate)
+{
+       void __iomem *regs = (void __iomem *)NEMC_BASE;
+       u32 rd_adj, rd_strobe, tmp;
+
+       rd_adj = (((6500 * (ahb2_rate / 1000000)) / 1000000) + 0xf) / 2;
+       tmp = (((35000 * (ahb2_rate / 1000000)) / 1000000) - 4) - rd_adj;
+       rd_strobe = ((tmp + 0xf) / 2 < 7) ? 7 : (tmp + 0xf) / 2;
+
+       tmp = (rd_adj << EFUSE_EFUCFG_RD_ADJ_BIT) |
+             (rd_strobe << EFUSE_EFUCFG_RD_STROBE_BIT);
+       writel(tmp, regs + EFUSE_EFUCFG);
+}
-- 
2.20.0

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to