xref: /rk3399_rockchip-uboot/drivers/misc/mxs_ocotp.c (revision 1221ce459d04a428f8880f58581f671b736c3c27)
12bbcccf5SMarek Vasut /*
22bbcccf5SMarek Vasut  * Freescale i.MX28 OCOTP Driver
32bbcccf5SMarek Vasut  *
42bbcccf5SMarek Vasut  * Copyright (C) 2014 Marek Vasut <marex@denx.de>
52bbcccf5SMarek Vasut  *
62bbcccf5SMarek Vasut  * SPDX-License-Identifier:	GPL-2.0+
72bbcccf5SMarek Vasut  *
82bbcccf5SMarek Vasut  * Note: The i.MX23/i.MX28 OCOTP block is a predecessor to the OCOTP block
92bbcccf5SMarek Vasut  *       used in i.MX6 . While these blocks are very similar at the first
102bbcccf5SMarek Vasut  *       glance, by digging deeper, one will notice differences (like the
112bbcccf5SMarek Vasut  *       tight dependence on MXS power block, some completely new registers
122bbcccf5SMarek Vasut  *       etc.) which would make common driver an ifdef nightmare :-(
132bbcccf5SMarek Vasut  */
142bbcccf5SMarek Vasut 
152bbcccf5SMarek Vasut #include <common.h>
162bbcccf5SMarek Vasut #include <fuse.h>
17*1221ce45SMasahiro Yamada #include <linux/errno.h>
182bbcccf5SMarek Vasut #include <asm/io.h>
192bbcccf5SMarek Vasut #include <asm/arch/clock.h>
202bbcccf5SMarek Vasut #include <asm/arch/imx-regs.h>
212bbcccf5SMarek Vasut #include <asm/arch/sys_proto.h>
222bbcccf5SMarek Vasut 
232bbcccf5SMarek Vasut #define MXS_OCOTP_TIMEOUT	100000
242bbcccf5SMarek Vasut 
252bbcccf5SMarek Vasut static struct mxs_ocotp_regs *ocotp_regs =
262bbcccf5SMarek Vasut 	(struct mxs_ocotp_regs *)MXS_OCOTP_BASE;
272bbcccf5SMarek Vasut static struct mxs_power_regs *power_regs =
282bbcccf5SMarek Vasut 	(struct mxs_power_regs *)MXS_POWER_BASE;
292bbcccf5SMarek Vasut static struct mxs_clkctrl_regs *clkctrl_regs =
302bbcccf5SMarek Vasut 	(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
312bbcccf5SMarek Vasut 
mxs_ocotp_wait_busy_clear(void)322bbcccf5SMarek Vasut static int mxs_ocotp_wait_busy_clear(void)
332bbcccf5SMarek Vasut {
342bbcccf5SMarek Vasut 	uint32_t reg;
352bbcccf5SMarek Vasut 	int timeout = MXS_OCOTP_TIMEOUT;
362bbcccf5SMarek Vasut 
372bbcccf5SMarek Vasut 	while (--timeout) {
382bbcccf5SMarek Vasut 		reg = readl(&ocotp_regs->hw_ocotp_ctrl);
392bbcccf5SMarek Vasut 		if (!(reg & OCOTP_CTRL_BUSY))
402bbcccf5SMarek Vasut 			break;
412bbcccf5SMarek Vasut 		udelay(10);
422bbcccf5SMarek Vasut 	}
432bbcccf5SMarek Vasut 
442bbcccf5SMarek Vasut 	if (!timeout)
452bbcccf5SMarek Vasut 		return -EINVAL;
462bbcccf5SMarek Vasut 
472bbcccf5SMarek Vasut 	/* Wait a little as per FSL datasheet's 'write postamble' section. */
482bbcccf5SMarek Vasut 	udelay(10);
492bbcccf5SMarek Vasut 
502bbcccf5SMarek Vasut 	return 0;
512bbcccf5SMarek Vasut }
522bbcccf5SMarek Vasut 
mxs_ocotp_clear_error(void)532bbcccf5SMarek Vasut static void mxs_ocotp_clear_error(void)
542bbcccf5SMarek Vasut {
552bbcccf5SMarek Vasut 	writel(OCOTP_CTRL_ERROR, &ocotp_regs->hw_ocotp_ctrl_clr);
562bbcccf5SMarek Vasut }
572bbcccf5SMarek Vasut 
mxs_ocotp_read_bank_open(bool open)582bbcccf5SMarek Vasut static int mxs_ocotp_read_bank_open(bool open)
592bbcccf5SMarek Vasut {
602bbcccf5SMarek Vasut 	int ret = 0;
612bbcccf5SMarek Vasut 
622bbcccf5SMarek Vasut 	if (open) {
632bbcccf5SMarek Vasut 		writel(OCOTP_CTRL_RD_BANK_OPEN,
642bbcccf5SMarek Vasut 		       &ocotp_regs->hw_ocotp_ctrl_set);
652bbcccf5SMarek Vasut 
662bbcccf5SMarek Vasut 		/*
672bbcccf5SMarek Vasut 		 * Wait before polling the BUSY bit, since the BUSY bit might
682bbcccf5SMarek Vasut 		 * be asserted only after a few HCLK cycles and if we were to
692bbcccf5SMarek Vasut 		 * poll immediatelly, we could miss the busy bit.
702bbcccf5SMarek Vasut 		 */
712bbcccf5SMarek Vasut 		udelay(10);
722bbcccf5SMarek Vasut 		ret = mxs_ocotp_wait_busy_clear();
732bbcccf5SMarek Vasut 	} else {
742bbcccf5SMarek Vasut 		writel(OCOTP_CTRL_RD_BANK_OPEN,
752bbcccf5SMarek Vasut 		       &ocotp_regs->hw_ocotp_ctrl_clr);
762bbcccf5SMarek Vasut 	}
772bbcccf5SMarek Vasut 
782bbcccf5SMarek Vasut 	return ret;
792bbcccf5SMarek Vasut }
802bbcccf5SMarek Vasut 
mxs_ocotp_scale_vddio(bool enter,uint32_t * val)812bbcccf5SMarek Vasut static void mxs_ocotp_scale_vddio(bool enter, uint32_t *val)
822bbcccf5SMarek Vasut {
832bbcccf5SMarek Vasut 	uint32_t scale_val;
842bbcccf5SMarek Vasut 
852bbcccf5SMarek Vasut 	if (enter) {
862bbcccf5SMarek Vasut 		/*
872bbcccf5SMarek Vasut 		 * Enter the fuse programming VDDIO voltage setup. We start
882bbcccf5SMarek Vasut 		 * scaling the voltage from it's current value down to 2.8V
892bbcccf5SMarek Vasut 		 * which is the one and only correct voltage for programming
902bbcccf5SMarek Vasut 		 * the OCOTP fuses (according to datasheet).
912bbcccf5SMarek Vasut 		 */
922bbcccf5SMarek Vasut 		scale_val = readl(&power_regs->hw_power_vddioctrl);
932bbcccf5SMarek Vasut 		scale_val &= POWER_VDDIOCTRL_TRG_MASK;
942bbcccf5SMarek Vasut 
952bbcccf5SMarek Vasut 		/* Return the original voltage. */
962bbcccf5SMarek Vasut 		*val = scale_val;
972bbcccf5SMarek Vasut 
982bbcccf5SMarek Vasut 		/*
992bbcccf5SMarek Vasut 		 * Start scaling VDDIO down to 0x2, which is 2.8V . Actually,
1002bbcccf5SMarek Vasut 		 * the value 0x0 should be 2.8V, but that's not the case on
1012bbcccf5SMarek Vasut 		 * most designs due to load etc., so we play safe. Undervolt
1022bbcccf5SMarek Vasut 		 * can actually cause incorrect programming of the fuses and
1032bbcccf5SMarek Vasut 		 * or reboots of the board.
1042bbcccf5SMarek Vasut 		 */
1052bbcccf5SMarek Vasut 		while (scale_val > 2) {
1062bbcccf5SMarek Vasut 			clrsetbits_le32(&power_regs->hw_power_vddioctrl,
1072bbcccf5SMarek Vasut 					POWER_VDDIOCTRL_TRG_MASK, --scale_val);
1082bbcccf5SMarek Vasut 			udelay(500);
1092bbcccf5SMarek Vasut 		}
1102bbcccf5SMarek Vasut 	} else {
1112bbcccf5SMarek Vasut 		/* Start scaling VDDIO up to original value . */
1122bbcccf5SMarek Vasut 		for (scale_val = 2; scale_val <= *val; scale_val++) {
1132bbcccf5SMarek Vasut 			clrsetbits_le32(&power_regs->hw_power_vddioctrl,
1142bbcccf5SMarek Vasut 					POWER_VDDIOCTRL_TRG_MASK, scale_val);
1152bbcccf5SMarek Vasut 			udelay(500);
1162bbcccf5SMarek Vasut 		}
1172bbcccf5SMarek Vasut 	}
1182bbcccf5SMarek Vasut 
1192bbcccf5SMarek Vasut 	mdelay(10);
1202bbcccf5SMarek Vasut }
1212bbcccf5SMarek Vasut 
mxs_ocotp_wait_hclk_ready(void)1222bbcccf5SMarek Vasut static int mxs_ocotp_wait_hclk_ready(void)
1232bbcccf5SMarek Vasut {
1242bbcccf5SMarek Vasut 	uint32_t reg, timeout = MXS_OCOTP_TIMEOUT;
1252bbcccf5SMarek Vasut 
1262bbcccf5SMarek Vasut 	while (--timeout) {
1272bbcccf5SMarek Vasut 		reg = readl(&clkctrl_regs->hw_clkctrl_hbus);
1282bbcccf5SMarek Vasut 		if (!(reg & CLKCTRL_HBUS_ASM_BUSY))
1292bbcccf5SMarek Vasut 			break;
1302bbcccf5SMarek Vasut 	}
1312bbcccf5SMarek Vasut 
1322bbcccf5SMarek Vasut 	if (!timeout)
1332bbcccf5SMarek Vasut 		return -EINVAL;
1342bbcccf5SMarek Vasut 
1352bbcccf5SMarek Vasut 	return 0;
1362bbcccf5SMarek Vasut }
1372bbcccf5SMarek Vasut 
mxs_ocotp_scale_hclk(bool enter,uint32_t * val)1382bbcccf5SMarek Vasut static int mxs_ocotp_scale_hclk(bool enter, uint32_t *val)
1392bbcccf5SMarek Vasut {
1402bbcccf5SMarek Vasut 	uint32_t scale_val;
1412bbcccf5SMarek Vasut 	int ret;
1422bbcccf5SMarek Vasut 
1432bbcccf5SMarek Vasut 	ret = mxs_ocotp_wait_hclk_ready();
1442bbcccf5SMarek Vasut 	if (ret)
1452bbcccf5SMarek Vasut 		return ret;
1462bbcccf5SMarek Vasut 
1472bbcccf5SMarek Vasut 	/* Set CPU bypass */
1482bbcccf5SMarek Vasut 	writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
1492bbcccf5SMarek Vasut 	       &clkctrl_regs->hw_clkctrl_clkseq_set);
1502bbcccf5SMarek Vasut 
1512bbcccf5SMarek Vasut 	if (enter) {
1522bbcccf5SMarek Vasut 		/* Return the original HCLK clock speed. */
1532bbcccf5SMarek Vasut 		*val = readl(&clkctrl_regs->hw_clkctrl_hbus);
1542bbcccf5SMarek Vasut 		*val &= CLKCTRL_HBUS_DIV_MASK;
155d4b8b5d4SChris Smith 		*val >>= CLKCTRL_HBUS_DIV_OFFSET;
1562bbcccf5SMarek Vasut 
1572bbcccf5SMarek Vasut 		/* Scale the HCLK to 454/19 = 23.9 MHz . */
1582bbcccf5SMarek Vasut 		scale_val = (~19) << CLKCTRL_HBUS_DIV_OFFSET;
1592bbcccf5SMarek Vasut 		scale_val &= CLKCTRL_HBUS_DIV_MASK;
1602bbcccf5SMarek Vasut 	} else {
1612bbcccf5SMarek Vasut 		/* Scale the HCLK back to original frequency. */
1622bbcccf5SMarek Vasut 		scale_val = (~(*val)) << CLKCTRL_HBUS_DIV_OFFSET;
1632bbcccf5SMarek Vasut 		scale_val &= CLKCTRL_HBUS_DIV_MASK;
1642bbcccf5SMarek Vasut 	}
1652bbcccf5SMarek Vasut 
1662bbcccf5SMarek Vasut 	writel(CLKCTRL_HBUS_DIV_MASK,
1672bbcccf5SMarek Vasut 	       &clkctrl_regs->hw_clkctrl_hbus_set);
1682bbcccf5SMarek Vasut 	writel(scale_val,
1692bbcccf5SMarek Vasut 	       &clkctrl_regs->hw_clkctrl_hbus_clr);
1702bbcccf5SMarek Vasut 
1712bbcccf5SMarek Vasut 	mdelay(10);
1722bbcccf5SMarek Vasut 
1732bbcccf5SMarek Vasut 	ret = mxs_ocotp_wait_hclk_ready();
1742bbcccf5SMarek Vasut 	if (ret)
1752bbcccf5SMarek Vasut 		return ret;
1762bbcccf5SMarek Vasut 
1772bbcccf5SMarek Vasut 	/* Disable CPU bypass */
1782bbcccf5SMarek Vasut 	writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
1792bbcccf5SMarek Vasut 	       &clkctrl_regs->hw_clkctrl_clkseq_clr);
1802bbcccf5SMarek Vasut 
1812bbcccf5SMarek Vasut 	mdelay(10);
1822bbcccf5SMarek Vasut 
1832bbcccf5SMarek Vasut 	return 0;
1842bbcccf5SMarek Vasut }
1852bbcccf5SMarek Vasut 
mxs_ocotp_write_fuse(uint32_t addr,uint32_t mask)1862bbcccf5SMarek Vasut static int mxs_ocotp_write_fuse(uint32_t addr, uint32_t mask)
1872bbcccf5SMarek Vasut {
1882bbcccf5SMarek Vasut 	uint32_t hclk_val, vddio_val;
1892bbcccf5SMarek Vasut 	int ret;
1902bbcccf5SMarek Vasut 
1913d99fcbcSHector Palacios 	mxs_ocotp_clear_error();
1923d99fcbcSHector Palacios 
1932bbcccf5SMarek Vasut 	/* Make sure the banks are closed for reading. */
1942bbcccf5SMarek Vasut 	ret = mxs_ocotp_read_bank_open(0);
1952bbcccf5SMarek Vasut 	if (ret) {
1962bbcccf5SMarek Vasut 		puts("Failed closing banks for reading!\n");
1972bbcccf5SMarek Vasut 		return ret;
1982bbcccf5SMarek Vasut 	}
1992bbcccf5SMarek Vasut 
2002bbcccf5SMarek Vasut 	ret = mxs_ocotp_scale_hclk(1, &hclk_val);
2012bbcccf5SMarek Vasut 	if (ret) {
2022bbcccf5SMarek Vasut 		puts("Failed scaling down the HCLK!\n");
2032bbcccf5SMarek Vasut 		return ret;
2042bbcccf5SMarek Vasut 	}
2052bbcccf5SMarek Vasut 	mxs_ocotp_scale_vddio(1, &vddio_val);
2062bbcccf5SMarek Vasut 
2072bbcccf5SMarek Vasut 	ret = mxs_ocotp_wait_busy_clear();
2082bbcccf5SMarek Vasut 	if (ret) {
2092bbcccf5SMarek Vasut 		puts("Failed waiting for ready state!\n");
2102bbcccf5SMarek Vasut 		goto fail;
2112bbcccf5SMarek Vasut 	}
2122bbcccf5SMarek Vasut 
2132bbcccf5SMarek Vasut 	/* Program the fuse address */
2142bbcccf5SMarek Vasut 	writel(addr | OCOTP_CTRL_WR_UNLOCK_KEY, &ocotp_regs->hw_ocotp_ctrl);
2152bbcccf5SMarek Vasut 
2162bbcccf5SMarek Vasut 	/* Program the data. */
2172bbcccf5SMarek Vasut 	writel(mask, &ocotp_regs->hw_ocotp_data);
2182bbcccf5SMarek Vasut 
2192bbcccf5SMarek Vasut 	udelay(10);
2202bbcccf5SMarek Vasut 
2212bbcccf5SMarek Vasut 	ret = mxs_ocotp_wait_busy_clear();
2222bbcccf5SMarek Vasut 	if (ret) {
2232bbcccf5SMarek Vasut 		puts("Failed waiting for ready state!\n");
2242bbcccf5SMarek Vasut 		goto fail;
2252bbcccf5SMarek Vasut 	}
2262bbcccf5SMarek Vasut 
227ad5dd7aeSHector Palacios 	/* Check for errors */
228ad5dd7aeSHector Palacios 	if (readl(&ocotp_regs->hw_ocotp_ctrl) & OCOTP_CTRL_ERROR) {
229ad5dd7aeSHector Palacios 		puts("Failed writing fuses!\n");
230ad5dd7aeSHector Palacios 		ret = -EPERM;
231ad5dd7aeSHector Palacios 		goto fail;
232ad5dd7aeSHector Palacios 	}
233ad5dd7aeSHector Palacios 
2342bbcccf5SMarek Vasut fail:
2352bbcccf5SMarek Vasut 	mxs_ocotp_scale_vddio(0, &vddio_val);
236d8d160e4SHector Palacios 	if (mxs_ocotp_scale_hclk(0, &hclk_val))
2372bbcccf5SMarek Vasut 		puts("Failed scaling up the HCLK!\n");
2382bbcccf5SMarek Vasut 
2392bbcccf5SMarek Vasut 	return ret;
2402bbcccf5SMarek Vasut }
2412bbcccf5SMarek Vasut 
mxs_ocotp_read_fuse(uint32_t reg,uint32_t * val)2422bbcccf5SMarek Vasut static int mxs_ocotp_read_fuse(uint32_t reg, uint32_t *val)
2432bbcccf5SMarek Vasut {
2442bbcccf5SMarek Vasut 	int ret;
2452bbcccf5SMarek Vasut 
2462bbcccf5SMarek Vasut 	/* Register offset from CUST0 */
2472bbcccf5SMarek Vasut 	reg = ((uint32_t)&ocotp_regs->hw_ocotp_cust0) + (reg << 4);
2482bbcccf5SMarek Vasut 
2492bbcccf5SMarek Vasut 	ret = mxs_ocotp_wait_busy_clear();
2502bbcccf5SMarek Vasut 	if (ret) {
2512bbcccf5SMarek Vasut 		puts("Failed waiting for ready state!\n");
2522bbcccf5SMarek Vasut 		return ret;
2532bbcccf5SMarek Vasut 	}
2542bbcccf5SMarek Vasut 
2552bbcccf5SMarek Vasut 	mxs_ocotp_clear_error();
2562bbcccf5SMarek Vasut 
2572bbcccf5SMarek Vasut 	ret = mxs_ocotp_read_bank_open(1);
2582bbcccf5SMarek Vasut 	if (ret) {
2592bbcccf5SMarek Vasut 		puts("Failed opening banks for reading!\n");
2602bbcccf5SMarek Vasut 		return ret;
2612bbcccf5SMarek Vasut 	}
2622bbcccf5SMarek Vasut 
2632bbcccf5SMarek Vasut 	*val = readl(reg);
2642bbcccf5SMarek Vasut 
2652bbcccf5SMarek Vasut 	ret = mxs_ocotp_read_bank_open(0);
2662bbcccf5SMarek Vasut 	if (ret) {
2672bbcccf5SMarek Vasut 		puts("Failed closing banks for reading!\n");
2682bbcccf5SMarek Vasut 		return ret;
2692bbcccf5SMarek Vasut 	}
2702bbcccf5SMarek Vasut 
2712bbcccf5SMarek Vasut 	return ret;
2722bbcccf5SMarek Vasut }
2732bbcccf5SMarek Vasut 
mxs_ocotp_valid(u32 bank,u32 word)2742bbcccf5SMarek Vasut static int mxs_ocotp_valid(u32 bank, u32 word)
2752bbcccf5SMarek Vasut {
2762bbcccf5SMarek Vasut 	if (bank > 4)
2772bbcccf5SMarek Vasut 		return -EINVAL;
2782bbcccf5SMarek Vasut 	if (word > 7)
2792bbcccf5SMarek Vasut 		return -EINVAL;
2802bbcccf5SMarek Vasut 	return 0;
2812bbcccf5SMarek Vasut }
2822bbcccf5SMarek Vasut 
2832bbcccf5SMarek Vasut /*
2842bbcccf5SMarek Vasut  * The 'fuse' command API
2852bbcccf5SMarek Vasut  */
fuse_read(u32 bank,u32 word,u32 * val)2862bbcccf5SMarek Vasut int fuse_read(u32 bank, u32 word, u32 *val)
2872bbcccf5SMarek Vasut {
2882bbcccf5SMarek Vasut 	int ret;
2892bbcccf5SMarek Vasut 
2902bbcccf5SMarek Vasut 	ret = mxs_ocotp_valid(bank, word);
2912bbcccf5SMarek Vasut 	if (ret)
2922bbcccf5SMarek Vasut 		return ret;
2932bbcccf5SMarek Vasut 
2942bbcccf5SMarek Vasut 	return mxs_ocotp_read_fuse((bank << 3) | word, val);
2952bbcccf5SMarek Vasut }
2962bbcccf5SMarek Vasut 
fuse_prog(u32 bank,u32 word,u32 val)2972bbcccf5SMarek Vasut int fuse_prog(u32 bank, u32 word, u32 val)
2982bbcccf5SMarek Vasut {
2992bbcccf5SMarek Vasut 	int ret;
3002bbcccf5SMarek Vasut 
3012bbcccf5SMarek Vasut 	ret = mxs_ocotp_valid(bank, word);
3022bbcccf5SMarek Vasut 	if (ret)
3032bbcccf5SMarek Vasut 		return ret;
3042bbcccf5SMarek Vasut 
3052bbcccf5SMarek Vasut 	return mxs_ocotp_write_fuse((bank << 3) | word, val);
3062bbcccf5SMarek Vasut }
3072bbcccf5SMarek Vasut 
fuse_sense(u32 bank,u32 word,u32 * val)3082bbcccf5SMarek Vasut int fuse_sense(u32 bank, u32 word, u32 *val)
3092bbcccf5SMarek Vasut {
3102bbcccf5SMarek Vasut 	/* We do not support sensing :-( */
3112bbcccf5SMarek Vasut 	return -EINVAL;
3122bbcccf5SMarek Vasut }
3132bbcccf5SMarek Vasut 
fuse_override(u32 bank,u32 word,u32 val)3142bbcccf5SMarek Vasut int fuse_override(u32 bank, u32 word, u32 val)
3152bbcccf5SMarek Vasut {
3162bbcccf5SMarek Vasut 	/* We do not support overriding :-( */
3172bbcccf5SMarek Vasut 	return -EINVAL;
3182bbcccf5SMarek Vasut }
319