diff options
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/imx8/Makefile | 1 | ||||
-rw-r--r-- | drivers/misc/imx8/fuse.c | 86 | ||||
-rw-r--r-- | drivers/misc/imx8/scu.c | 16 | ||||
-rw-r--r-- | drivers/misc/mxc_ocotp.c | 23 |
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(®s, 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 |