summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/Makefile1
-rw-r--r--common/cmd_imxotp.c156
-rw-r--r--cpu/arm_cortexa8/mx6/generic.c24
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/imx_otp.c256
-rw-r--r--include/asm-arm/arch-mx6/regs-ocotp.h367
-rw-r--r--include/configs/mx6q_arm2.h11
-rw-r--r--include/imx_otp.h30
8 files changed, 846 insertions, 0 deletions
diff --git a/common/Makefile b/common/Makefile
index f4d2cbdeed..1f218e7b7e 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -171,6 +171,7 @@ COBJS-$(CONFIG_MODEM_SUPPORT) += modem.o
COBJS-$(CONFIG_UPDATE_TFTP) += update.o
COBJS-$(CONFIG_USB_KEYBOARD) += usb_kbd.o
COBJS-$(CONFIG_FASTBOOT) += cmd_fastboot.o
+COBJS-$(CONFIG_CMD_IMXOTP) += cmd_imxotp.o
COBJS := $(sort $(COBJS-y))
SRCS := $(AOBJS:.o=.S) $(COBJS:.o=.c)
diff --git a/common/cmd_imxotp.c b/common/cmd_imxotp.c
new file mode 100644
index 0000000000..b976aaa2ef
--- /dev/null
+++ b/common/cmd_imxotp.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <command.h>
+#include <imx_otp.h>
+
+/*
+ * meant to reject most of the zeros return by simple_strtoul call.
+ *
+ */
+int validate_zero_from_simple_strtoul(char *str)
+{
+ int i = 0;
+
+ /* reject negatives */
+ if (str[0] == '-')
+ return -1;
+
+ /* reject no zero initialed */
+ if (str[0] != '0')
+ return -1;
+
+ /* accept zero */
+ if (strlen(str) == 1)
+ return 0;
+
+ /* only accept started with "0x" or "0X" or "00" */
+ if (str[1] != 'x' && str[1] != 'X' && str[1] != '0')
+ return -1;
+
+ /* reject "0x" or "0X" or "00" only */
+ if (strlen(str) == 3)
+ return -1;
+
+ /* only accept all zeros */
+ for (i = 1; i < strlen(str) - 1; i++) {
+ if (str[1] != '0')
+ return -1;
+ }
+ return 0;
+}
+
+int do_imxotp(cmd_tbl_t *cmd_tbl, int flag, int argc, char* argv[])
+{
+ u32 addr, value_read, fused_value, value_to_fuse;
+ int force_to_fuse = 0;
+
+ if (argc < 3) {
+usage:
+ cmd_usage(cmd_tbl);
+ return 1;
+ }
+
+ if (!strcmp(argv[1], "read")) {
+ switch (argc) {
+ case 3:
+ addr = simple_strtoul(argv[2], NULL, 16);
+ if ((addr == 0) &&
+ validate_zero_from_simple_strtoul(argv[2]))
+ goto usage;
+ break;
+ default:
+ goto usage;
+ }
+ printf("Reading fuse at index: 0x%X\n", addr);
+ if (imx_otp_read_one_u32(addr, &value_read))
+ return -1;
+ printf("Fuse at (index: 0x%X) value: 0x%X\n", addr, value_read);
+ } else if (!strcmp(argv[1], "blow")) {
+ if (argc < 4 || argc > 5)
+ goto usage;
+
+ if (!strcmp(argv[2], "--force")) {
+ force_to_fuse = 1;
+ addr = simple_strtoul(argv[3], NULL, 16);
+ if ((addr == 0)
+ && validate_zero_from_simple_strtoul(argv[3]))
+ goto usage;
+ value_to_fuse = simple_strtoul(argv[4], NULL, 16);
+ if ((value_to_fuse == 0)
+ && validate_zero_from_simple_strtoul(argv[4]))
+ goto usage;
+ } else {
+ addr = simple_strtoul(argv[2], NULL, 16);
+ if ((addr == 0)
+ && validate_zero_from_simple_strtoul(argv[2]))
+ goto usage;
+ value_to_fuse = simple_strtoul(argv[3], NULL, 16);
+ if ((value_to_fuse == 0)
+ && validate_zero_from_simple_strtoul(argv[3]))
+ goto usage;
+ }
+
+ /* show the current value of specified address (fuse index) */
+ if (imx_otp_read_one_u32(addr, &value_read))
+ return -1;
+ printf("Current fuse at (index: 0x%X) value: 0x%X\n",
+ addr, value_read);
+
+ if ((value_to_fuse & value_read) == value_to_fuse)
+ printf("!! Fuse blow skipped:"
+ " the bits have been already set.\n");
+ else if (force_to_fuse) {
+ printf("Blowing fuse at index: 0x%X, value: 0x%X\n",
+ addr, value_to_fuse);
+ if (imx_otp_blow_one_u32(addr,
+ value_to_fuse, &fused_value)) {
+ printf("ERROR: failed to blow fuse"
+ " at 0x%X with value of 0x%X\n",
+ addr, value_to_fuse);
+ } else {
+ printf("Operation %s fuse"
+ " at (index: 0x%X) value: 0x%X\n",
+ ((fused_value & value_to_fuse) ==
+ value_to_fuse) ? "succeeded"
+ : "failed",
+ addr, fused_value);
+ }
+ } else {
+ printf("!! Fuse blow aborted."
+ " if you do want to blow it."
+ " Please use the command:\n"
+ "%s blow --force %X %X\n",
+ argv[0], addr, value_to_fuse);
+ }
+ } else
+ goto usage;
+
+ return 0;
+}
+
+U_BOOT_CMD(imxotp, 5, 0, do_imxotp,
+ "One-Time Programable sub-system",
+ "imxotp read <addr>\n"
+ " - read fuse at 'addr'\n"
+ "imxotp blow [--force] <addr> <value>\n"
+ " - blow fuse at 'addr' with hex value 'value'\n"
+);
diff --git a/cpu/arm_cortexa8/mx6/generic.c b/cpu/arm_cortexa8/mx6/generic.c
index f959b9598a..11fac50f2c 100644
--- a/cpu/arm_cortexa8/mx6/generic.c
+++ b/cpu/arm_cortexa8/mx6/generic.c
@@ -770,3 +770,27 @@ void ipu_clk_enable(void)
void ipu_clk_disable(void)
{
}
+
+int otp_clk_enable(void)
+{
+ u32 reg = 0;
+
+ reg = readl(CCM_BASE_ADDR + CLKCTL_CCGR2);
+ if (!(reg & 0x3000))
+ reg |= 0x3000;
+ writel(reg, CCM_BASE_ADDR + CLKCTL_CCGR2);
+ return 0;
+}
+
+int otp_clk_disable(void)
+{
+ u32 reg = 0;
+
+ reg = readl(CCM_BASE_ADDR + CLKCTL_CCGR2);
+ if ((reg & 0x3000) == 0x3000)
+ reg &= ~(0x3000);
+ writel(reg, CCM_BASE_ADDR + CLKCTL_CCGR2);
+ return 0;
+}
+
+
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 5bbafea781..685ae8c729 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -29,6 +29,7 @@ COBJS-$(CONFIG_ALI152X) += ali512x.o
COBJS-$(CONFIG_DS4510) += ds4510.o
COBJS-$(CONFIG_FSL_LAW) += fsl_law.o
COBJS-$(CONFIG_IMX_IIM) += imx_iim.o
+COBJS-$(CONFIG_IMX_OTP) += imx_otp.o
COBJS-$(CONFIG_IMX_PWM) += imx_pwm.o
COBJS-$(CONFIG_NS87308) += ns87308.o
COBJS-$(CONFIG_STATUS_LED) += status_led.o
diff --git a/drivers/misc/imx_otp.c b/drivers/misc/imx_otp.c
new file mode 100644
index 0000000000..917924d6ee
--- /dev/null
+++ b/drivers/misc/imx_otp.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <linux/types.h>
+#include <asm/io.h>
+#include <common.h>
+#include <asm-arm/arch/regs-ocotp.h>
+#include <imx_otp.h>
+
+#define HW_OCOTP_CUSTn(n) (0x00000400 + (n) * 0x10)
+#define BF(value, field) (((value) << BP_##field) & BM_##field)
+#define DEF_RELAX 20
+
+#ifdef CONFIG_IMX_OTP_DEBUG
+#define log(a, ...) printf("[%s,%3d]:"a"\n", __func__, __LINE__, ## __VA_ARGS__)
+#else
+#define log(a, ...)
+#endif
+
+static int otp_wait_busy(u32 flags)
+{
+ int count;
+ u32 c;
+
+ for (count = 10000; count >= 0; count--) {
+ c = readl(IMX_OTP_BASE + HW_OCOTP_CTRL);
+ if (!(c & (BM_OCOTP_CTRL_BUSY | BM_OCOTP_CTRL_ERROR | flags)))
+ break;
+ }
+
+ if (count < 0) {
+ printf("ERROR: otp_wait_busy timeout. 0x%X\n", c);
+ /* clear ERROR bit, busy bit will be cleared by controller */
+ writel(BM_OCOTP_CTRL_ERROR, IMX_OTP_BASE + HW_OCOTP_CTRL_CLR);
+ return -1;
+ }
+
+ log("wait busy successful.");
+ return 0;
+}
+
+static int set_otp_timing(void)
+{
+ u32 clk_rate = 0;
+ u32 relax, strobe_read, strobe_prog;
+ u32 timing = 0;
+
+ /* get clock */
+ clk_rate = mxc_get_clock(MXC_IPG_CLK);
+ if (clk_rate == -1) {
+ printf("ERROR: mxc_get_clock failed\n");
+ return -1;
+ }
+
+ log("clk_rate: %d.", clk_rate);
+
+ relax = clk_rate / (1000000000 / DEF_RELAX) - 1;
+ strobe_prog = clk_rate / (1000000000 / 10000) + 2 * (DEF_RELAX + 1) - 1;
+ strobe_read = clk_rate / (1000000000 / 40) + 2 * (DEF_RELAX + 1) - 1;
+
+ timing = BF(relax, OCOTP_TIMING_RELAX);
+ timing |= BF(strobe_read, OCOTP_TIMING_STROBE_READ);
+ timing |= BF(strobe_prog, OCOTP_TIMING_STROBE_PROG);
+ log("timing: 0x%X", timing);
+
+ writel(timing, IMX_OTP_BASE + HW_OCOTP_TIMING);
+
+ return 0;
+}
+
+static int otp_read_prep(void)
+{
+ return (!set_otp_timing()) ? otp_wait_busy(0) : -1;
+}
+
+static int otp_read_post(void)
+{
+ return 0;
+}
+
+static int otp_blow_prep(void)
+{
+ return (!set_otp_timing()) ? otp_wait_busy(0) : -1;
+}
+
+static int otp_blow_post(void)
+{
+ printf("Reloading shadow registers...\n");
+ /* reload all the shadow registers */
+ writel(BM_OCOTP_CTRL_RELOAD_SHADOWS,
+ IMX_OTP_BASE + HW_OCOTP_CTRL_SET);
+ udelay(1);
+
+ return otp_wait_busy(BM_OCOTP_CTRL_RELOAD_SHADOWS);
+}
+
+static int fuse_read_addr(u32 addr, u32 *pdata)
+{
+ u32 ctrl_reg = 0;
+
+#ifdef CONFIG_IMX_OTP_READ_SHADOW_REG
+ *pdata = readl(IMX_OTP_BASE + HW_OCOTP_CUSTn(addr));
+ printf("Shadow register data: 0x%X\n", *pdata);
+#endif
+
+ ctrl_reg = readl(IMX_OTP_BASE + HW_OCOTP_CTRL);
+ ctrl_reg &= ~BM_OCOTP_CTRL_ADDR;
+ ctrl_reg &= ~BM_OCOTP_CTRL_WR_UNLOCK;
+ ctrl_reg |= BF(addr, OCOTP_CTRL_ADDR);
+ writel(ctrl_reg, IMX_OTP_BASE + HW_OCOTP_CTRL);
+
+ writel(BM_OCOTP_READ_CTRL_READ_FUSE, IMX_OTP_BASE + HW_OCOTP_READ_CTRL);
+ if (otp_wait_busy(0))
+ return -1;
+
+ *pdata = readl(IMX_OTP_BASE + HW_OCOTP_READ_FUSE_DATA);
+ *pdata = BF_OCOTP_READ_FUSE_DATA_DATA(*pdata);
+ return 0;
+}
+
+static int fuse_blow_addr(u32 addr, u32 value)
+{
+ u32 ctrl_reg = 0;
+
+ log("blowing...");
+
+ /* control register */
+ ctrl_reg = readl(IMX_OTP_BASE + HW_OCOTP_CTRL);
+ ctrl_reg &= ~BM_OCOTP_CTRL_ADDR;
+ ctrl_reg |= BF(addr, OCOTP_CTRL_ADDR);
+ ctrl_reg |= BF(BV_OCOTP_CTRL_WR_UNLOCK__KEY, OCOTP_CTRL_WR_UNLOCK);
+ writel(ctrl_reg, IMX_OTP_BASE + HW_OCOTP_CTRL);
+
+ writel(BF_OCOTP_DATA_DATA(value), IMX_OTP_BASE + HW_OCOTP_DATA);
+ if (otp_wait_busy(0))
+ return -1;
+
+ /* write postamble */
+ udelay(2000);
+ return 0;
+}
+
+/*
+ * read one u32 to indexed fuse
+ */
+int imx_otp_read_one_u32(u32 index, u32 *pdata)
+{
+ u32 ctrl_reg = 0;
+ int ret = 0;
+
+ log("index: 0x%X", index);
+ if (index > IMX_OTP_ADDR_MAX) {
+ printf("ERROR: invalid address.\n");
+ ret = -1;
+ goto exit_nop;
+ }
+
+ if (otp_clk_enable()) {
+ ret = -1;
+ printf("ERROR: failed to initialize OTP\n");
+ goto exit_nop;
+ }
+
+ if (otp_read_prep()) {
+ ret = -1;
+ printf("ERROR: read preparation failed\n");
+ goto exit_cleanup;
+ }
+ if (fuse_read_addr(index, pdata)) {
+ ret = -1;
+ printf("ERROR: read failed\n");
+ goto exit_cleanup;
+ }
+ if (otp_read_post()) {
+ ret = -1;
+ printf("ERROR: read post operation failed\n");
+ goto exit_cleanup;
+ }
+
+ if (*pdata == IMX_OTP_DATA_ERROR_VAL) {
+ ctrl_reg = readl(IMX_OTP_BASE + HW_OCOTP_CTRL);
+ if (ctrl_reg & BM_OCOTP_CTRL_ERROR) {
+ printf("ERROR: read fuse failed\n");
+ ret = -1;
+ goto exit_cleanup;
+ }
+ }
+
+exit_cleanup:
+ otp_clk_disable();
+exit_nop:
+ return ret;
+}
+
+/*
+ * blow one u32 to indexed fuse
+ */
+int imx_otp_blow_one_u32(u32 index, u32 data, u32 *pfused_value)
+{
+ u32 ctrl_reg = 0;
+ int ret = 0;
+
+ if (otp_clk_enable()) {
+ ret = -1;
+ goto exit_nop;
+ }
+
+ if (otp_blow_prep()) {
+ ret = -1;
+ printf("ERROR: blow preparation failed\n");
+ goto exit_cleanup;
+ }
+ if (fuse_blow_addr(index, data)) {
+ ret = -1;
+ printf("ERROR: blow fuse failed\n");
+ goto exit_cleanup;
+ }
+ if (otp_blow_post()) {
+ ret = -1;
+ printf("ERROR: blow post operation failed\n");
+ goto exit_cleanup;
+ }
+
+ ctrl_reg = readl(IMX_OTP_BASE + HW_OCOTP_CTRL);
+ if (ctrl_reg & BM_OCOTP_CTRL_ERROR) {
+ ret = -1;
+ goto exit_cleanup;
+ }
+
+ if (imx_otp_read_one_u32(index, pfused_value)) {
+ ret = -1;
+ goto exit_cleanup;
+ }
+
+exit_cleanup:
+ otp_clk_disable();
+exit_nop:
+ return ret;
+}
+
diff --git a/include/asm-arm/arch-mx6/regs-ocotp.h b/include/asm-arm/arch-mx6/regs-ocotp.h
new file mode 100644
index 0000000000..d3c8de982f
--- /dev/null
+++ b/include/asm-arm/arch-mx6/regs-ocotp.h
@@ -0,0 +1,367 @@
+/*
+ * Freescale OCOTP Register Definitions
+ *
+ * Copyright 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * This file is created by xml file. Don't Edit it.
+ *
+ * Xml Revision: 1.12
+ * Template revision: 1.3
+ */
+
+#ifndef __ARCH_ARM___OCOTP_H
+#define __ARCH_ARM___OCOTP_H
+
+
+#define HW_OCOTP_CTRL (0x00000000)
+#define HW_OCOTP_CTRL_SET (0x00000004)
+#define HW_OCOTP_CTRL_CLR (0x00000008)
+#define HW_OCOTP_CTRL_TOG (0x0000000c)
+
+#define BP_OCOTP_CTRL_WR_UNLOCK 16
+#define BM_OCOTP_CTRL_WR_UNLOCK 0xFFFF0000
+#define BF_OCOTP_CTRL_WR_UNLOCK(v) \
+ (((v) << 16) & BM_OCOTP_CTRL_WR_UNLOCK)
+#define BV_OCOTP_CTRL_WR_UNLOCK__KEY 0x3E77
+#define BP_OCOTP_CTRL_RSVD1 13
+#define BM_OCOTP_CTRL_RSVD1 0x0000E000
+#define BF_OCOTP_CTRL_RSVD1(v) \
+ (((v) << 13) & BM_OCOTP_CTRL_RSVD1)
+#define BM_OCOTP_CTRL_CRC_FAIL 0x00001000
+#define BM_OCOTP_CTRL_CRC_TEST 0x00000800
+#define BM_OCOTP_CTRL_RELOAD_SHADOWS 0x00000400
+#define BM_OCOTP_CTRL_ERROR 0x00000200
+#define BM_OCOTP_CTRL_BUSY 0x00000100
+#define BM_OCOTP_CTRL_RSVD0 0x00000080
+#define BP_OCOTP_CTRL_ADDR 0
+#define BM_OCOTP_CTRL_ADDR 0x0000007F
+#define BF_OCOTP_CTRL_ADDR(v) \
+ (((v) << 0) & BM_OCOTP_CTRL_ADDR)
+
+#define HW_OCOTP_TIMING (0x00000010)
+
+#define BP_OCOTP_TIMING_RSRVD0 28
+#define BM_OCOTP_TIMING_RSRVD0 0xF0000000
+#define BF_OCOTP_TIMING_RSRVD0(v) \
+ (((v) << 28) & BM_OCOTP_TIMING_RSRVD0)
+#define BP_OCOTP_TIMING_WAIT 22
+#define BM_OCOTP_TIMING_WAIT 0x0FC00000
+#define BF_OCOTP_TIMING_WAIT(v) \
+ (((v) << 22) & BM_OCOTP_TIMING_WAIT)
+#define BP_OCOTP_TIMING_STROBE_READ 16
+#define BM_OCOTP_TIMING_STROBE_READ 0x003F0000
+#define BF_OCOTP_TIMING_STROBE_READ(v) \
+ (((v) << 16) & BM_OCOTP_TIMING_STROBE_READ)
+#define BP_OCOTP_TIMING_RELAX 12
+#define BM_OCOTP_TIMING_RELAX 0x0000F000
+#define BF_OCOTP_TIMING_RELAX(v) \
+ (((v) << 12) & BM_OCOTP_TIMING_RELAX)
+#define BP_OCOTP_TIMING_STROBE_PROG 0
+#define BM_OCOTP_TIMING_STROBE_PROG 0x00000FFF
+#define BF_OCOTP_TIMING_STROBE_PROG(v) \
+ (((v) << 0) & BM_OCOTP_TIMING_STROBE_PROG)
+
+#define HW_OCOTP_DATA (0x00000020)
+
+#define BP_OCOTP_DATA_DATA 0
+#define BM_OCOTP_DATA_DATA 0xFFFFFFFF
+#define BF_OCOTP_DATA_DATA(v) (v)
+
+#define HW_OCOTP_READ_CTRL (0x00000030)
+
+#define BP_OCOTP_READ_CTRL_RSVD0 1
+#define BM_OCOTP_READ_CTRL_RSVD0 0xFFFFFFFE
+#define BF_OCOTP_READ_CTRL_RSVD0(v) \
+ (((v) << 1) & BM_OCOTP_READ_CTRL_RSVD0)
+#define BM_OCOTP_READ_CTRL_READ_FUSE 0x00000001
+
+#define HW_OCOTP_READ_FUSE_DATA (0x00000040)
+
+#define BP_OCOTP_READ_FUSE_DATA_DATA 0
+#define BM_OCOTP_READ_FUSE_DATA_DATA 0xFFFFFFFF
+#define BF_OCOTP_READ_FUSE_DATA_DATA(v) (v)
+
+#define HW_OCOTP_SW_STICKY (0x00000050)
+
+#define BP_OCOTP_SW_STICKY_RSVD0 5
+#define BM_OCOTP_SW_STICKY_RSVD0 0xFFFFFFE0
+#define BF_OCOTP_SW_STICKY_RSVD0(v) \
+ (((v) << 5) & BM_OCOTP_SW_STICKY_RSVD0)
+#define BM_OCOTP_SW_STICKY_JTAG_BLOCK_RELEASE 0x00000010
+#define BM_OCOTP_SW_STICKY_BLOCK_ROM_PART 0x00000008
+#define BM_OCOTP_SW_STICKY_FIELD_RETURN_LOCK 0x00000004
+#define BM_OCOTP_SW_STICKY_SRK_REVOKE_LOCK 0x00000002
+#define BM_OCOTP_SW_STICKY_BLOCK_DTCP_KEY 0x00000001
+
+#define HW_OCOTP_SCS (0x00000060)
+#define HW_OCOTP_SCS_SET (0x00000064)
+#define HW_OCOTP_SCS_CLR (0x00000068)
+#define HW_OCOTP_SCS_TOG (0x0000006c)
+
+#define BM_OCOTP_SCS_LOCK 0x80000000
+#define BP_OCOTP_SCS_SPARE 1
+#define BM_OCOTP_SCS_SPARE 0x7FFFFFFE
+#define BF_OCOTP_SCS_SPARE(v) \
+ (((v) << 1) & BM_OCOTP_SCS_SPARE)
+#define BM_OCOTP_SCS_HAB_JDE 0x00000001
+
+#define HW_OCOTP_CRC_ADDR (0x00000070)
+
+#define BP_OCOTP_CRC_ADDR_RSVD0 19
+#define BM_OCOTP_CRC_ADDR_RSVD0 0xFFF80000
+#define BF_OCOTP_CRC_ADDR_RSVD0(v) \
+ (((v) << 19) & BM_OCOTP_CRC_ADDR_RSVD0)
+#define BP_OCOTP_CRC_ADDR_CRC_ADDR 16
+#define BM_OCOTP_CRC_ADDR_CRC_ADDR 0x00070000
+#define BF_OCOTP_CRC_ADDR_CRC_ADDR(v) \
+ (((v) << 16) & BM_OCOTP_CRC_ADDR_CRC_ADDR)
+#define BP_OCOTP_CRC_ADDR_DATA_END_ADDR 8
+#define BM_OCOTP_CRC_ADDR_DATA_END_ADDR 0x0000FF00
+#define BF_OCOTP_CRC_ADDR_DATA_END_ADDR(v) \
+ (((v) << 8) & BM_OCOTP_CRC_ADDR_DATA_END_ADDR)
+#define BP_OCOTP_CRC_ADDR_DATA_START_ADDR 0
+#define BM_OCOTP_CRC_ADDR_DATA_START_ADDR 0x000000FF
+#define BF_OCOTP_CRC_ADDR_DATA_START_ADDR(v) \
+ (((v) << 0) & BM_OCOTP_CRC_ADDR_DATA_START_ADDR)
+
+#define HW_OCOTP_CRC_VALUE (0x00000080)
+
+#define BP_OCOTP_CRC_VALUE_DATA 0
+#define BM_OCOTP_CRC_VALUE_DATA 0xFFFFFFFF
+#define BF_OCOTP_CRC_VALUE_DATA(v) (v)
+
+#define HW_OCOTP_VERSION (0x00000090)
+
+#define BP_OCOTP_VERSION_MAJOR 24
+#define BM_OCOTP_VERSION_MAJOR 0xFF000000
+#define BF_OCOTP_VERSION_MAJOR(v) \
+ (((v) << 24) & BM_OCOTP_VERSION_MAJOR)
+#define BP_OCOTP_VERSION_MINOR 16
+#define BM_OCOTP_VERSION_MINOR 0x00FF0000
+#define BF_OCOTP_VERSION_MINOR(v) \
+ (((v) << 16) & BM_OCOTP_VERSION_MINOR)
+#define BP_OCOTP_VERSION_STEP 0
+#define BM_OCOTP_VERSION_STEP 0x0000FFFF
+#define BF_OCOTP_VERSION_STEP(v) \
+ (((v) << 0) & BM_OCOTP_VERSION_STEP)
+
+#define HW_OCOTP_LOCK (0x00000400)
+
+#define BP_OCOTP_LOCK_UNALLOCATED 30
+#define BM_OCOTP_LOCK_UNALLOCATED 0xC0000000
+#define BF_OCOTP_LOCK_UNALLOCATED(v) \
+ (((v) << 30) & BM_OCOTP_LOCK_UNALLOCATED)
+#define BP_OCOTP_LOCK_CRC_GP_HI_LOCK 28
+#define BM_OCOTP_LOCK_CRC_GP_HI_LOCK 0x30000000
+#define BF_OCOTP_LOCK_CRC_GP_HI_LOCK(v) \
+ (((v) << 28) & BM_OCOTP_LOCK_CRC_GP_HI_LOCK)
+#define BP_OCOTP_LOCK_CRC_GP_LO_LOCK 26
+#define BM_OCOTP_LOCK_CRC_GP_LO_LOCK 0x0C000000
+#define BF_OCOTP_LOCK_CRC_GP_LO_LOCK(v) \
+ (((v) << 26) & BM_OCOTP_LOCK_CRC_GP_LO_LOCK)
+#define BM_OCOTP_LOCK_PIN 0x02000000
+#define BM_OCOTP_LOCK_RSVD2 0x01000000
+#define BM_OCOTP_LOCK_DTCP_DEV_CERT 0x00800000
+#define BM_OCOTP_LOCK_MISC_CONF 0x00400000
+#define BM_OCOTP_LOCK_HDCP_KEYS 0x00200000
+#define BM_OCOTP_LOCK_HDCP_KSV 0x00100000
+#define BP_OCOTP_LOCK_ANALOG 18
+#define BM_OCOTP_LOCK_ANALOG 0x000C0000
+#define BF_OCOTP_LOCK_ANALOG(v) \
+ (((v) << 18) & BM_OCOTP_LOCK_ANALOG)
+#define BM_OCOTP_LOCK_OTPMK 0x00020000
+#define BM_OCOTP_LOCK_DTCP_KEY 0x00010000
+#define BM_OCOTP_LOCK_RSVD1 0x00008000
+#define BM_OCOTP_LOCK_SRK 0x00004000
+#define BP_OCOTP_LOCK_GP2 12
+#define BM_OCOTP_LOCK_GP2 0x00003000
+#define BF_OCOTP_LOCK_GP2(v) \
+ (((v) << 12) & BM_OCOTP_LOCK_GP2)
+#define BP_OCOTP_LOCK_GP1 10
+#define BM_OCOTP_LOCK_GP1 0x00000C00
+#define BF_OCOTP_LOCK_GP1(v) \
+ (((v) << 10) & BM_OCOTP_LOCK_GP1)
+#define BP_OCOTP_LOCK_MAC_ADDR 8
+#define BM_OCOTP_LOCK_MAC_ADDR 0x00000300
+#define BF_OCOTP_LOCK_MAC_ADDR(v) \
+ (((v) << 8) & BM_OCOTP_LOCK_MAC_ADDR)
+#define BM_OCOTP_LOCK_RSVD0 0x00000080
+#define BM_OCOTP_LOCK_SJC_RESP 0x00000040
+#define BP_OCOTP_LOCK_MEM_TRIM 4
+#define BM_OCOTP_LOCK_MEM_TRIM 0x00000030
+#define BF_OCOTP_LOCK_MEM_TRIM(v) \
+ (((v) << 4) & BM_OCOTP_LOCK_MEM_TRIM)
+#define BP_OCOTP_LOCK_BOOT_CFG 2
+#define BM_OCOTP_LOCK_BOOT_CFG 0x0000000C
+#define BF_OCOTP_LOCK_BOOT_CFG(v) \
+ (((v) << 2) & BM_OCOTP_LOCK_BOOT_CFG)
+#define BP_OCOTP_LOCK_TESTER 0
+#define BM_OCOTP_LOCK_TESTER 0x00000003
+#define BF_OCOTP_LOCK_TESTER(v) \
+ (((v) << 0) & BM_OCOTP_LOCK_TESTER)
+
+/*
+ * multi-register-define name HW_OCOTP_CFGn
+ * base 0x00000410
+ * count 7
+ * offset 0x10
+ */
+#define HW_OCOTP_CFGn(n) (0x00000410 + (n) * 0x10)
+#define BP_OCOTP_CFGn_BITS 0
+#define BM_OCOTP_CFGn_BITS 0xFFFFFFFF
+#define BF_OCOTP_CFGn_BITS(v) (v)
+
+/*
+ * multi-register-define name HW_OCOTP_MEMn
+ * base 0x00000480
+ * count 5
+ * offset 0x10
+ */
+#define HW_OCOTP_MEMn(n) (0x00000480 + (n) * 0x10)
+#define BP_OCOTP_MEMn_BITS 0
+#define BM_OCOTP_MEMn_BITS 0xFFFFFFFF
+#define BF_OCOTP_MEMn_BITS(v) (v)
+
+/*
+ * multi-register-define name HW_OCOTP_ANAn
+ * base 0x000004D0
+ * count 3
+ * offset 0x10
+ */
+#define HW_OCOTP_ANAn(n) (0x000004d0 + (n) * 0x10)
+#define BP_OCOTP_ANAn_BITS 0
+#define BM_OCOTP_ANAn_BITS 0xFFFFFFFF
+#define BF_OCOTP_ANAn_BITS(v) (v)
+
+/*
+ * multi-register-define name HW_OCOTP_OTPMKn
+ * base 0x00000500
+ * count 8
+ * offset 0x10
+ */
+#define HW_OCOTP_OTPMKn(n) (0x00000500 + (n) * 0x10)
+#define BP_OCOTP_OTPMKn_BITS 0
+#define BM_OCOTP_OTPMKn_BITS 0xFFFFFFFF
+#define BF_OCOTP_OTPMKn_BITS(v) (v)
+
+/*
+ * multi-register-define name HW_OCOTP_SRKn
+ * base 0x00000580
+ * count 8
+ * offset 0x10
+ */
+#define HW_OCOTP_SRKn(n) (0x00000580 + (n) * 0x10)
+#define BP_OCOTP_SRKn_BITS 0
+#define BM_OCOTP_SRKn_BITS 0xFFFFFFFF
+#define BF_OCOTP_SRKn_BITS(v) (v)
+
+/*
+ * multi-register-define name HW_OCOTP_SJC_RESPn
+ * base 0x00000600
+ * count 2
+ * offset 0x10
+ */
+#define HW_OCOTP_SJC_RESPn(n) (0x00000600 + (n) * 0x10)
+#define BP_OCOTP_SJC_RESPn_BITS 0
+#define BM_OCOTP_SJC_RESPn_BITS 0xFFFFFFFF
+#define BF_OCOTP_SJC_RESPn_BITS(v) (v)
+
+/*
+ * multi-register-define name HW_OCOTP_MACn
+ * base 0x00000620
+ * count 2
+ * offset 0x10
+ */
+#define HW_OCOTP_MACn(n) (0x00000620 + (n) * 0x10)
+#define BP_OCOTP_MACn_BITS 0
+#define BM_OCOTP_MACn_BITS 0xFFFFFFFF
+#define BF_OCOTP_MACn_BITS(v) (v)
+
+/*
+ * multi-register-define name HW_OCOTP_HDCP_KSVn
+ * base 0x00000640
+ * count 2
+ * offset 0x10
+ */
+#define HW_OCOTP_HDCP_KSVn(n) (0x00000640 + (n) * 0x10)
+#define BP_OCOTP_HDCP_KSVn_BITS 0
+#define BM_OCOTP_HDCP_KSVn_BITS 0xFFFFFFFF
+#define BF_OCOTP_HDCP_KSVn_BITS(v) (v)
+
+#define HW_OCOTP_GP1 (0x00000660)
+
+#define BP_OCOTP_GP1_BITS 0
+#define BM_OCOTP_GP1_BITS 0xFFFFFFFF
+#define BF_OCOTP_GP1_BITS(v) (v)
+
+#define HW_OCOTP_GP2 (0x00000670)
+
+#define BP_OCOTP_GP2_BITS 0
+#define BM_OCOTP_GP2_BITS 0xFFFFFFFF
+#define BF_OCOTP_GP2_BITS(v) (v)
+
+/*
+ * multi-register-define name HW_OCOTP_DTCP_KEYn
+ * base 0x00000680
+ * count 5
+ * offset 0x10
+ */
+#define HW_OCOTP_DTCP_KEYn(n) (0x00000680 + (n) * 0x10)
+#define BP_OCOTP_DTCP_KEYn_BITS 0
+#define BM_OCOTP_DTCP_KEYn_BITS 0xFFFFFFFF
+#define BF_OCOTP_DTCP_KEYn_BITS(v) (v)
+
+#define HW_OCOTP_MISC_CONF (0x000006d0)
+
+#define BP_OCOTP_MISC_CONF_BITS 0
+#define BM_OCOTP_MISC_CONF_BITS 0xFFFFFFFF
+#define BF_OCOTP_MISC_CONF_BITS(v) (v)
+
+#define HW_OCOTP_FIELD_RETURN (0x000006e0)
+
+#define BP_OCOTP_FIELD_RETURN_BITS 0
+#define BM_OCOTP_FIELD_RETURN_BITS 0xFFFFFFFF
+#define BF_OCOTP_FIELD_RETURN_BITS(v) (v)
+
+#define HW_OCOTP_SRK_REVOKE (0x000006f0)
+
+#define BP_OCOTP_SRK_REVOKE_BITS 0
+#define BM_OCOTP_SRK_REVOKE_BITS 0xFFFFFFFF
+#define BF_OCOTP_SRK_REVOKE_BITS(v) (v)
+
+/*
+ * multi-register-define name HW_OCOTP_HDCP_KEYn
+ * base 0x00000800
+ * count 72
+ * offset 0x10
+ */
+#define HW_OCOTP_HDCP_KEYn(n) (0x00000800 + (n) * 0x10)
+#define BP_OCOTP_HDCP_KEYn_BITS 0
+#define BM_OCOTP_HDCP_KEYn_BITS 0xFFFFFFFF
+#define BF_OCOTP_HDCP_KEYn_BITS(v) (v)
+
+/*
+ * multi-register-define name HW_OCOTP_CRCn
+ * base 0x00000D00
+ * count 8
+ * offset 0x10
+ */
+#define HW_OCOTP_CRCn(n) (0x00000d00 + (n) * 0x10)
+#define BP_OCOTP_CRCn_BITS 0
+#define BM_OCOTP_CRCn_BITS 0xFFFFFFFF
+#define BF_OCOTP_CRCn_BITS(v) (v)
+#endif /* __ARCH_ARM___OCOTP_H */
diff --git a/include/configs/mx6q_arm2.h b/include/configs/mx6q_arm2.h
index 165d13a8be..c9bff96613 100644
--- a/include/configs/mx6q_arm2.h
+++ b/include/configs/mx6q_arm2.h
@@ -90,6 +90,7 @@
#define CONFIG_CMD_SPI
#define CONFIG_CMD_I2C
+#define CONFIG_CMD_IMXOTP
/* Enable below configure when supporting nand */
#define CONFIG_CMD_SF
@@ -169,6 +170,16 @@
#define CONFIG_NETMASK 255.255.255.0
/*
+ * OCOTP Configs
+ */
+#ifdef CONFIG_CMD_IMXOTP
+ #define CONFIG_IMX_OTP
+ #define IMX_OTP_BASE OCOTP_BASE_ADDR
+ #define IMX_OTP_ADDR_MAX 0x7F
+ #define IMX_OTP_DATA_ERROR_VAL 0xBADABADA
+#endif
+
+/*
* I2C Configs
*/
#ifdef CONFIG_CMD_I2C
diff --git a/include/imx_otp.h b/include/imx_otp.h
new file mode 100644
index 0000000000..87650d806b
--- /dev/null
+++ b/include/imx_otp.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __IMX_OCOTP_H_
+#define __IMX_OCOTP_H_ 1
+
+int imx_otp_read_one_u32(u32 addr, u32 *value);
+int imx_otp_blow_one_u32(u32 addr, u32 value, u32 *pfused_value);
+
+int otp_clk_enable(void);
+int otp_clk_disable(void);
+
+#endif
+