summaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/imx8/Makefile1
-rw-r--r--drivers/misc/imx8/fuse.c86
-rw-r--r--drivers/misc/imx8/scu.c16
-rw-r--r--drivers/misc/mxc_ocotp.c23
4 files changed, 116 insertions, 10 deletions
diff --git a/drivers/misc/imx8/Makefile b/drivers/misc/imx8/Makefile
index ee05893cbb..48fdb5b61c 100644
--- a/drivers/misc/imx8/Makefile
+++ b/drivers/misc/imx8/Makefile
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0+
obj-y += scu_api.o scu.o
+obj-$(CONFIG_CMD_FUSE) += fuse.o
diff --git a/drivers/misc/imx8/fuse.c b/drivers/misc/imx8/fuse.c
new file mode 100644
index 0000000000..29d2256a22
--- /dev/null
+++ b/drivers/misc/imx8/fuse.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <common.h>
+#include <console.h>
+#include <errno.h>
+#include <fuse.h>
+#include <asm/arch/sci/sci.h>
+#include <asm/arch/sys_proto.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define FSL_ECC_WORD_START_1 0x10
+#define FSL_ECC_WORD_END_1 0x10F
+
+#ifdef CONFIG_IMX8QXP
+#define FSL_ECC_WORD_START_2 0x220
+#define FSL_ECC_WORD_END_2 0x31F
+
+#define FSL_QXP_FUSE_GAP_START 0x110
+#define FSL_QXP_FUSE_GAP_END 0x21F
+#endif
+
+#define FSL_SIP_OTP_READ 0xc200000A
+#define FSL_SIP_OTP_WRITE 0xc200000B
+
+int fuse_read(u32 bank, u32 word, u32 *val)
+{
+ return fuse_sense(bank, word, val);
+}
+
+int fuse_sense(u32 bank, u32 word, u32 *val)
+{
+ unsigned long ret = 0, value = 0;
+
+ if (bank != 0) {
+ printf("Invalid bank argument, ONLY bank 0 is supported\n");
+ return -EINVAL;
+ }
+
+ ret = call_imx_sip_ret2(FSL_SIP_OTP_READ, (unsigned long)word, &value,
+ 0, 0);
+ *val = (u32)value;
+
+ return ret;
+}
+
+int fuse_prog(u32 bank, u32 word, u32 val)
+{
+ if (bank != 0) {
+ printf("Invalid bank argument, ONLY bank 0 is supported\n");
+ return -EINVAL;
+ }
+
+ if (IS_ENABLED(CONFIG_IMX8QXP)) {
+ if (word >= FSL_QXP_FUSE_GAP_START &&
+ word <= FSL_QXP_FUSE_GAP_END) {
+ printf("Invalid word argument for this SoC\n");
+ return -EINVAL;
+ }
+ }
+
+ if ((word >= FSL_ECC_WORD_START_1 && word <= FSL_ECC_WORD_END_1) ||
+ (word >= FSL_ECC_WORD_START_2 && word <= FSL_ECC_WORD_END_2)) {
+ puts("Warning: Words in this index range have ECC protection\n"
+ "and can only be programmed once per word. Individual bit\n"
+ "operations will be rejected after the first one.\n"
+ "\n\n Really program this word? <y/N>\n");
+
+ if (!confirm_yesno()) {
+ puts("Word programming aborted\n");
+ return -EPERM;
+ }
+ }
+
+ return call_imx_sip(FSL_SIP_OTP_WRITE, (unsigned long)word,
+ (unsigned long)val, 0);
+}
+
+int fuse_override(u32 bank, u32 word, u32 val)
+{
+ printf("Override fuse to i.MX8 in u-boot is forbidden\n");
+ return -EPERM;
+}
diff --git a/drivers/misc/imx8/scu.c b/drivers/misc/imx8/scu.c
index 1b9c49c99c..9ec00457b8 100644
--- a/drivers/misc/imx8/scu.c
+++ b/drivers/misc/imx8/scu.c
@@ -219,11 +219,21 @@ static int imx8_scu_bind(struct udevice *dev)
int ret;
struct udevice *child;
int node;
+ char *clk_compatible, *iomuxc_compatible;
+
+ if (IS_ENABLED(CONFIG_IMX8QXP)) {
+ clk_compatible = "fsl,imx8qxp-clk";
+ iomuxc_compatible = "fsl,imx8qxp-iomuxc";
+ } else if (IS_ENABLED(CONFIG_IMX8QM)) {
+ clk_compatible = "fsl,imx8qm-clk";
+ iomuxc_compatible = "fsl,imx8qm-iomuxc";
+ } else {
+ return -EINVAL;
+ }
debug("%s(dev=%p)\n", __func__, dev);
- node = fdt_node_offset_by_compatible(gd->fdt_blob, -1,
- "fsl,imx8qxp-clk");
+ node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, clk_compatible);
if (node < 0)
panic("No clk node found\n");
@@ -234,7 +244,7 @@ static int imx8_scu_bind(struct udevice *dev)
plat->clk = child;
node = fdt_node_offset_by_compatible(gd->fdt_blob, -1,
- "fsl,imx8qxp-iomuxc");
+ iomuxc_compatible);
if (node < 0)
panic("No iomuxc node found\n");
diff --git a/drivers/misc/mxc_ocotp.c b/drivers/misc/mxc_ocotp.c
index f84fe88db1..1b945e9727 100644
--- a/drivers/misc/mxc_ocotp.c
+++ b/drivers/misc/mxc_ocotp.c
@@ -321,6 +321,11 @@ int fuse_sense(u32 bank, u32 word, u32 *val)
struct ocotp_regs *regs;
int ret;
+ if (is_imx8mq() && is_soc_rev(CHIP_REV_2_1)) {
+ printf("mxc_ocotp %s(): fuse sense is disabled\n", __func__);
+ return -EPERM;
+ }
+
ret = prepare_read(&regs, bank, word, val, __func__);
if (ret)
return ret;
@@ -354,13 +359,17 @@ static int prepare_write(struct ocotp_regs **regs, u32 bank, u32 word,
/* Only bank 0 and 1 are redundancy mode, others are ECC mode */
if (bank != 0 && bank != 1) {
- ret = fuse_sense(bank, word, &val);
- if (ret)
- return ret;
-
- if (val != 0) {
- printf("mxc_ocotp: The word has been programmed, no more write\n");
- return -EPERM;
+ if ((soc_rev() < CHIP_REV_2_0) ||
+ ((soc_rev() >= CHIP_REV_2_0) &&
+ bank != 9 && bank != 10 && bank != 28)) {
+ ret = fuse_sense(bank, word, &val);
+ if (ret)
+ return ret;
+
+ if (val != 0) {
+ printf("mxc_ocotp: The word has been programmed, no more write\n");
+ return -EPERM;
+ }
}
}
#endif