static ssize_t fsl_otp_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { unsigned int index = attr - otp_kattr; u32 value; int ret; sscanf(buf, "0x%x", &value); ret = clk_prepare_enable(otp_clk); if (ret) return 0; mutex_lock(&otp_mutex); set_otp_timing(); ret = otp_wait_busy(0); if (ret) goto out; otp_write_bits(index, value, 0x3e77); /* Reload all the shadow registers */ __raw_writel(BM_OCOTP_CTRL_RELOAD_SHADOWS, otp_base + HW_OCOTP_CTRL_SET); udelay(1); otp_wait_busy(BM_OCOTP_CTRL_RELOAD_SHADOWS); out: mutex_unlock(&otp_mutex); clk_disable_unprepare(otp_clk); return ret ? 0 : count; }
static ssize_t fsl_otp_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { unsigned int index = attr - otp_kattr; u32 value = 0; int ret; ret = clk_prepare_enable(otp_clk); if (ret) return 0; mutex_lock(&otp_mutex); set_otp_timing(); ret = otp_wait_busy(0); if (ret) goto out; value = __raw_readl(otp_base + HW_OCOTP_CUST_N(index)); out: mutex_unlock(&otp_mutex); clk_disable_unprepare(otp_clk); return ret ? 0 : sprintf(buf, "0x%x\n", value); }
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 otp_write_bits(int addr, u32 data, u32 magic) { u32 c; /* for control register */ /* init the control register */ c = __raw_readl(otp_base + HW_OCOTP_CTRL); c &= ~BM_OCOTP_CTRL_ADDR; c |= BF(addr, OCOTP_CTRL_ADDR); c |= BF(magic, OCOTP_CTRL_WR_UNLOCK); __raw_writel(c, otp_base + HW_OCOTP_CTRL); /* init the data register */ __raw_writel(data, otp_base + HW_OCOTP_DATA); otp_wait_busy(0); mdelay(2); /* Write Postamble */ 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; }
int fsl_otp_readl(unsigned long offset, u32 *value) { int ret = 0; ret = clk_prepare_enable(otp_clk); if (ret) return ret; mutex_lock(&otp_mutex); set_otp_timing(); ret = otp_wait_busy(0); if (ret) goto out; *value = __raw_readl(otp_base + offset); out: mutex_unlock(&otp_mutex); clk_disable_unprepare(otp_clk); return ret; }
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 otp_blow_prep(void) { return (!set_otp_timing()) ? otp_wait_busy(0) : -1; }