xref: /rk3399_rockchip-uboot/drivers/misc/rockchip-otp.c (revision 6be53b633a21a4024eb11bc8e4ccfa7c730ae55e)
14973d825SFinley Xiao // SPDX-License-Identifier: GPL-2.0
24973d825SFinley Xiao /*
34973d825SFinley Xiao  * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
44973d825SFinley Xiao  */
54973d825SFinley Xiao 
64973d825SFinley Xiao #include <common.h>
74973d825SFinley Xiao #include <asm/io.h>
84973d825SFinley Xiao #include <command.h>
94973d825SFinley Xiao #include <dm.h>
104973d825SFinley Xiao #include <linux/bitops.h>
114973d825SFinley Xiao #include <linux/delay.h>
124973d825SFinley Xiao #include <misc.h>
134973d825SFinley Xiao 
144973d825SFinley Xiao /* OTP Register Offsets */
154973d825SFinley Xiao #define OTPC_SBPI_CTRL			0x0020
164973d825SFinley Xiao #define OTPC_SBPI_CMD_VALID_PRE		0x0024
174973d825SFinley Xiao #define OTPC_SBPI_CS_VALID_PRE		0x0028
184973d825SFinley Xiao #define OTPC_SBPI_STATUS		0x002C
194973d825SFinley Xiao #define OTPC_USER_CTRL			0x0100
204973d825SFinley Xiao #define OTPC_USER_ADDR			0x0104
214973d825SFinley Xiao #define OTPC_USER_ENABLE		0x0108
224973d825SFinley Xiao #define OTPC_USER_Q			0x0124
234973d825SFinley Xiao #define OTPC_INT_STATUS			0x0304
244973d825SFinley Xiao #define OTPC_SBPI_CMD0_OFFSET		0x1000
254973d825SFinley Xiao #define OTPC_SBPI_CMD1_OFFSET		0x1004
264973d825SFinley Xiao 
274973d825SFinley Xiao /* OTP Register bits and masks */
284973d825SFinley Xiao #define OTPC_USER_ADDR_MASK		GENMASK(31, 16)
294973d825SFinley Xiao #define OTPC_USE_USER			BIT(0)
304973d825SFinley Xiao #define OTPC_USE_USER_MASK		GENMASK(16, 16)
314973d825SFinley Xiao #define OTPC_USER_FSM_ENABLE		BIT(0)
324973d825SFinley Xiao #define OTPC_USER_FSM_ENABLE_MASK	GENMASK(16, 16)
334973d825SFinley Xiao #define OTPC_SBPI_DONE			BIT(1)
344973d825SFinley Xiao #define OTPC_USER_DONE			BIT(2)
354973d825SFinley Xiao 
364973d825SFinley Xiao #define SBPI_DAP_ADDR			0x02
374973d825SFinley Xiao #define SBPI_DAP_ADDR_SHIFT		8
384973d825SFinley Xiao #define SBPI_DAP_ADDR_MASK		GENMASK(31, 24)
394973d825SFinley Xiao #define SBPI_CMD_VALID_MASK		GENMASK(31, 16)
404973d825SFinley Xiao #define SBPI_DAP_CMD_WRF		0xC0
414973d825SFinley Xiao #define SBPI_DAP_REG_ECC		0x3A
424973d825SFinley Xiao #define SBPI_ECC_ENABLE			0x00
434973d825SFinley Xiao #define SBPI_ECC_DISABLE		0x09
444973d825SFinley Xiao #define SBPI_ENABLE			BIT(0)
454973d825SFinley Xiao #define SBPI_ENABLE_MASK		GENMASK(16, 16)
464973d825SFinley Xiao 
474973d825SFinley Xiao #define OTPC_TIMEOUT			10000
484973d825SFinley Xiao 
494973d825SFinley Xiao typedef int (*OTP_READ)(struct udevice *dev, int offset, void *buf, int size);
504973d825SFinley Xiao 
514973d825SFinley Xiao struct rockchip_otp_platdata {
524973d825SFinley Xiao 	void __iomem *base;
534973d825SFinley Xiao };
544973d825SFinley Xiao 
554973d825SFinley Xiao #if defined(DEBUG)
564973d825SFinley Xiao static int dump_otps(cmd_tbl_t *cmdtp, int flag,
574973d825SFinley Xiao 		     int argc, char * const argv[])
584973d825SFinley Xiao {
594973d825SFinley Xiao 	struct udevice *dev;
604973d825SFinley Xiao 	u8 otps[64] = {0};
614973d825SFinley Xiao 	int ret;
624973d825SFinley Xiao 
634973d825SFinley Xiao 	/* retrieve the device */
644973d825SFinley Xiao 	ret = uclass_get_device_by_driver(UCLASS_MISC,
654973d825SFinley Xiao 					  DM_GET_DRIVER(rockchip_otp), &dev);
664973d825SFinley Xiao 	if (ret) {
674973d825SFinley Xiao 		printf("%s: no misc-device found\n", __func__);
684973d825SFinley Xiao 		return 0;
694973d825SFinley Xiao 	}
704973d825SFinley Xiao 
714973d825SFinley Xiao 	ret = misc_read(dev, 0, &otps, sizeof(otps));
724973d825SFinley Xiao 	if (ret) {
734973d825SFinley Xiao 		printf("%s: misc_read failed\n", __func__);
744973d825SFinley Xiao 		return 0;
754973d825SFinley Xiao 	}
764973d825SFinley Xiao 
774973d825SFinley Xiao 	printf("otp-contents:\n");
784973d825SFinley Xiao 	print_buffer(0, otps, 1, 64, 16);
794973d825SFinley Xiao 
804973d825SFinley Xiao 	return 0;
814973d825SFinley Xiao }
824973d825SFinley Xiao 
834973d825SFinley Xiao U_BOOT_CMD(
844973d825SFinley Xiao 	rockchip_dump_otps, 1, 1, dump_otps,
854973d825SFinley Xiao 	"Dump the content of the otps",
864973d825SFinley Xiao 	""
874973d825SFinley Xiao );
884973d825SFinley Xiao #endif
894973d825SFinley Xiao 
904973d825SFinley Xiao static int rockchip_otp_wait_status(struct rockchip_otp_platdata *otp,
914973d825SFinley Xiao 				    u32 flag)
924973d825SFinley Xiao {
934973d825SFinley Xiao 	int delay = OTPC_TIMEOUT;
944973d825SFinley Xiao 
954973d825SFinley Xiao 	while (!(readl(otp->base + OTPC_INT_STATUS) & flag)) {
964973d825SFinley Xiao 		udelay(1);
974973d825SFinley Xiao 		delay--;
984973d825SFinley Xiao 		if (delay <= 0) {
994973d825SFinley Xiao 			printf("%s: wait init status timeout\n", __func__);
1004973d825SFinley Xiao 			return -ETIMEDOUT;
1014973d825SFinley Xiao 		}
1024973d825SFinley Xiao 	}
1034973d825SFinley Xiao 
1044973d825SFinley Xiao 	/* clean int status */
1054973d825SFinley Xiao 	writel(flag, otp->base + OTPC_INT_STATUS);
1064973d825SFinley Xiao 
1074973d825SFinley Xiao 	return 0;
1084973d825SFinley Xiao }
1094973d825SFinley Xiao 
1104973d825SFinley Xiao static int rockchip_otp_ecc_enable(struct rockchip_otp_platdata *otp,
1114973d825SFinley Xiao 				   bool enable)
1124973d825SFinley Xiao {
1134973d825SFinley Xiao 	int ret = 0;
1144973d825SFinley Xiao 
1154973d825SFinley Xiao 	writel(SBPI_DAP_ADDR_MASK | (SBPI_DAP_ADDR << SBPI_DAP_ADDR_SHIFT),
1164973d825SFinley Xiao 	       otp->base + OTPC_SBPI_CTRL);
1174973d825SFinley Xiao 
1184973d825SFinley Xiao 	writel(SBPI_CMD_VALID_MASK | 0x1, otp->base + OTPC_SBPI_CMD_VALID_PRE);
1194973d825SFinley Xiao 	writel(SBPI_DAP_CMD_WRF | SBPI_DAP_REG_ECC,
1204973d825SFinley Xiao 	       otp->base + OTPC_SBPI_CMD0_OFFSET);
1214973d825SFinley Xiao 	if (enable)
1224973d825SFinley Xiao 		writel(SBPI_ECC_ENABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
1234973d825SFinley Xiao 	else
1244973d825SFinley Xiao 		writel(SBPI_ECC_DISABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
1254973d825SFinley Xiao 
1264973d825SFinley Xiao 	writel(SBPI_ENABLE_MASK | SBPI_ENABLE, otp->base + OTPC_SBPI_CTRL);
1274973d825SFinley Xiao 
1284973d825SFinley Xiao 	ret = rockchip_otp_wait_status(otp, OTPC_SBPI_DONE);
1294973d825SFinley Xiao 	if (ret < 0)
1304973d825SFinley Xiao 		printf("%s timeout during ecc_enable\n", __func__);
1314973d825SFinley Xiao 
1324973d825SFinley Xiao 	return ret;
1334973d825SFinley Xiao }
1344973d825SFinley Xiao 
1354973d825SFinley Xiao static int rockchip_px30_otp_read(struct udevice *dev, int offset,
1364973d825SFinley Xiao 				  void *buf, int size)
1374973d825SFinley Xiao {
1384973d825SFinley Xiao 	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
1394973d825SFinley Xiao 	u8 *buffer = buf;
1404973d825SFinley Xiao 	int ret = 0;
1414973d825SFinley Xiao 
1424973d825SFinley Xiao 	ret = rockchip_otp_ecc_enable(otp, false);
1434973d825SFinley Xiao 	if (ret < 0) {
1444973d825SFinley Xiao 		printf("%s rockchip_otp_ecc_enable err\n", __func__);
1454973d825SFinley Xiao 		return ret;
1464973d825SFinley Xiao 	}
1474973d825SFinley Xiao 
1484973d825SFinley Xiao 	writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
1494973d825SFinley Xiao 	udelay(5);
1504973d825SFinley Xiao 	while (size--) {
1514973d825SFinley Xiao 		writel(offset++ | OTPC_USER_ADDR_MASK,
1524973d825SFinley Xiao 		       otp->base + OTPC_USER_ADDR);
1534973d825SFinley Xiao 		writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
1544973d825SFinley Xiao 		       otp->base + OTPC_USER_ENABLE);
1554973d825SFinley Xiao 		ret = rockchip_otp_wait_status(otp, OTPC_USER_DONE);
1564973d825SFinley Xiao 		if (ret < 0) {
1574973d825SFinley Xiao 			printf("%s timeout during read setup\n", __func__);
1584973d825SFinley Xiao 			goto read_end;
1594973d825SFinley Xiao 		}
1604973d825SFinley Xiao 		*buffer++ = readb(otp->base + OTPC_USER_Q);
1614973d825SFinley Xiao 	}
1624973d825SFinley Xiao 
1634973d825SFinley Xiao read_end:
1644973d825SFinley Xiao 	writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
1654973d825SFinley Xiao 
1664973d825SFinley Xiao 	return ret;
1674973d825SFinley Xiao }
1684973d825SFinley Xiao 
1694973d825SFinley Xiao static int rockchip_otp_read(struct udevice *dev, int offset,
1704973d825SFinley Xiao 			     void *buf, int size)
1714973d825SFinley Xiao {
1724973d825SFinley Xiao 	OTP_READ otp_read = NULL;
1734973d825SFinley Xiao 
1744973d825SFinley Xiao 	otp_read = (OTP_READ)dev_get_driver_data(dev);
1754973d825SFinley Xiao 	if (!otp_read)
1764973d825SFinley Xiao 		return -ENOSYS;
1774973d825SFinley Xiao 
1784973d825SFinley Xiao 	return (*otp_read)(dev, offset, buf, size);
1794973d825SFinley Xiao }
1804973d825SFinley Xiao 
1814973d825SFinley Xiao static const struct misc_ops rockchip_otp_ops = {
1824973d825SFinley Xiao 	.read = rockchip_otp_read,
1834973d825SFinley Xiao };
1844973d825SFinley Xiao 
1854973d825SFinley Xiao static int rockchip_otp_ofdata_to_platdata(struct udevice *dev)
1864973d825SFinley Xiao {
1874973d825SFinley Xiao 	struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
1884973d825SFinley Xiao 
1894973d825SFinley Xiao 	otp->base = dev_read_addr_ptr(dev);
1904973d825SFinley Xiao 
1914973d825SFinley Xiao 	return 0;
1924973d825SFinley Xiao }
1934973d825SFinley Xiao 
1944973d825SFinley Xiao static const struct udevice_id rockchip_otp_ids[] = {
1954973d825SFinley Xiao 	{
1964973d825SFinley Xiao 		.compatible = "rockchip,px30-otp",
1974973d825SFinley Xiao 		.data = (ulong)&rockchip_px30_otp_read,
1984973d825SFinley Xiao 	},
199*6be53b63SFinley Xiao 	{
200*6be53b63SFinley Xiao 		.compatible = "rockchip,rk3308-otp",
201*6be53b63SFinley Xiao 		.data = (ulong)&rockchip_px30_otp_read,
202*6be53b63SFinley Xiao 	},
2034973d825SFinley Xiao 	{}
2044973d825SFinley Xiao };
2054973d825SFinley Xiao 
2064973d825SFinley Xiao U_BOOT_DRIVER(rockchip_otp) = {
2074973d825SFinley Xiao 	.name = "rockchip_otp",
2084973d825SFinley Xiao 	.id = UCLASS_MISC,
2094973d825SFinley Xiao 	.of_match = rockchip_otp_ids,
2104973d825SFinley Xiao 	.ops = &rockchip_otp_ops,
2114973d825SFinley Xiao 	.ofdata_to_platdata = rockchip_otp_ofdata_to_platdata,
2124973d825SFinley Xiao 	.platdata_auto_alloc_size = sizeof(struct rockchip_otp_platdata),
2134973d825SFinley Xiao };
214