summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Smith <alex.smith@imgtec.com>2014-06-06 15:05:05 +0400
committerAlex Smith <alex.smith@imgtec.com>2014-06-24 19:54:36 +0400
commitebf0c0a0fbdd15eb7429ec1892a292d982b82048 (patch)
tree73ca76135cdf7e8ac63e526cf1834771f78eb8b8
parent7cbab83166d0006dcd39f586a29a71fb47fbae59 (diff)
downloadCI20_u-boot-ebf0c0a0fbdd15eb7429ec1892a292d982b82048.tar.xz
jz4780_efuse: add EFUSE driver for the Ingenic JZ4780
Add a driver which allows reading from the EFUSE on Ingenic JZ4780 SoCs. Signed-off-by: Alex Smith <alex.smith@imgtec.com>
-rw-r--r--arch/mips/include/asm/arch-jz4780/efuse.h35
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/jz4780_efuse.c76
3 files changed, 112 insertions, 0 deletions
diff --git a/arch/mips/include/asm/arch-jz4780/efuse.h b/arch/mips/include/asm/arch-jz4780/efuse.h
new file mode 100644
index 000000000..8a84011b9
--- /dev/null
+++ b/arch/mips/include/asm/arch-jz4780/efuse.h
@@ -0,0 +1,35 @@
+/*
+ * JZ4780 EFUSE driver
+ *
+ * Copyright (c) 2014 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __JZ4780_EFUSE_H__
+#define __JZ4780_EFUSE_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 (1 << 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 (1 << 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 (1 << 0)
+
+extern void jz4780_efuse_read(size_t addr, size_t count, uint8_t *buf);
+extern void jz4780_efuse_init(uint32_t ahb2_rate);
+
+#endif /* __JZ4780_EFUSE_H__ */
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 08828ee31..e994c27ff 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -18,6 +18,7 @@ COBJS-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o
COBJS-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o
COBJS-$(CONFIG_FSL_IIM) += fsl_iim.o
COBJS-$(CONFIG_GPIO_LED) += gpio_led.o
+COBJS-$(CONFIG_JZ4780_EFUSE) += jz4780_efuse.o
COBJS-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o
COBJS-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o
COBJS-$(CONFIG_NS87308) += ns87308.o
diff --git a/drivers/misc/jz4780_efuse.c b/drivers/misc/jz4780_efuse.c
new file mode 100644
index 000000000..8b8d20d53
--- /dev/null
+++ b/drivers/misc/jz4780_efuse.c
@@ -0,0 +1,76 @@
+/*
+ * JZ4780 EFUSE driver
+ *
+ * Copyright (c) 2014 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/efuse.h>
+#include <asm/arch/jz4780.h>
+#include <asm/unaligned.h>
+
+static void jz4780_efuse_read_chunk(size_t addr, size_t count, uint8_t *buf)
+{
+ uint32_t val;
+ size_t i;
+
+ val = EFUSE_EFUCTRL_RD_EN |
+ (count - 1) << EFUSE_EFUCTRL_LEN_BIT |
+ addr << EFUSE_EFUCTRL_ADDR_BIT |
+ ((addr > 0x200) ? EFUSE_EFUCTRL_CS : 0);
+ writel(val, NEMC_BASE + EFUSE_EFUCTRL);
+
+ while (!(readl(NEMC_BASE + EFUSE_EFUSTATE) & EFUSE_EFUSTATE_RD_DONE))
+ ;
+
+ if ((count % 4) == 0) {
+ for (i = 0; i < count / 4; i++) {
+ val = readl(NEMC_BASE + EFUSE_EFUDATA(i));
+ put_unaligned(val, (uint32_t *)(buf + (i * 4)));
+ }
+ } else {
+ val = readl(NEMC_BASE + 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, uint8_t *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(uint32_t ahb2_rate)
+{
+ uint32_t 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, NEMC_BASE + EFUSE_EFUCFG);
+}