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>
79fed581aSFinley Xiao #include <asm/arch/cpu.h>
84973d825SFinley Xiao #include <asm/io.h>
94973d825SFinley Xiao #include <command.h>
104973d825SFinley Xiao #include <dm.h>
114973d825SFinley Xiao #include <linux/bitops.h>
124973d825SFinley Xiao #include <linux/delay.h>
13a4c57e8aSFinley Xiao #include <linux/iopoll.h>
144973d825SFinley Xiao #include <misc.h>
156e12c1ddSJason Zhu #include <rockchip-otp.h>
164973d825SFinley Xiao
17a4c57e8aSFinley Xiao struct otp_data {
18dd270bd4SXuhui Lin int size;
19dd270bd4SXuhui Lin int ns_offset;
20a4c57e8aSFinley Xiao int (*init)(struct udevice *dev);
21a4c57e8aSFinley Xiao int (*read)(struct udevice *dev, int offset, void *buf, int size);
22a4c57e8aSFinley Xiao };
23a4c57e8aSFinley Xiao
rockchip_otp_wait_status(struct rockchip_otp_platdata * otp,u32 flag)244973d825SFinley Xiao static int rockchip_otp_wait_status(struct rockchip_otp_platdata *otp,
254973d825SFinley Xiao u32 flag)
264973d825SFinley Xiao {
274973d825SFinley Xiao int delay = OTPC_TIMEOUT;
284973d825SFinley Xiao
294973d825SFinley Xiao while (!(readl(otp->base + OTPC_INT_STATUS) & flag)) {
304973d825SFinley Xiao udelay(1);
314973d825SFinley Xiao delay--;
324973d825SFinley Xiao if (delay <= 0) {
334973d825SFinley Xiao printf("%s: wait init status timeout\n", __func__);
344973d825SFinley Xiao return -ETIMEDOUT;
354973d825SFinley Xiao }
364973d825SFinley Xiao }
374973d825SFinley Xiao
384973d825SFinley Xiao /* clean int status */
394973d825SFinley Xiao writel(flag, otp->base + OTPC_INT_STATUS);
404973d825SFinley Xiao
414973d825SFinley Xiao return 0;
424973d825SFinley Xiao }
434973d825SFinley Xiao
rockchip_otp_ecc_enable(struct rockchip_otp_platdata * otp,bool enable)444973d825SFinley Xiao static int rockchip_otp_ecc_enable(struct rockchip_otp_platdata *otp,
454973d825SFinley Xiao bool enable)
464973d825SFinley Xiao {
474973d825SFinley Xiao int ret = 0;
484973d825SFinley Xiao
494973d825SFinley Xiao writel(SBPI_DAP_ADDR_MASK | (SBPI_DAP_ADDR << SBPI_DAP_ADDR_SHIFT),
504973d825SFinley Xiao otp->base + OTPC_SBPI_CTRL);
514973d825SFinley Xiao
524973d825SFinley Xiao writel(SBPI_CMD_VALID_MASK | 0x1, otp->base + OTPC_SBPI_CMD_VALID_PRE);
534973d825SFinley Xiao writel(SBPI_DAP_CMD_WRF | SBPI_DAP_REG_ECC,
544973d825SFinley Xiao otp->base + OTPC_SBPI_CMD0_OFFSET);
554973d825SFinley Xiao if (enable)
564973d825SFinley Xiao writel(SBPI_ECC_ENABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
574973d825SFinley Xiao else
584973d825SFinley Xiao writel(SBPI_ECC_DISABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
594973d825SFinley Xiao
604973d825SFinley Xiao writel(SBPI_ENABLE_MASK | SBPI_ENABLE, otp->base + OTPC_SBPI_CTRL);
614973d825SFinley Xiao
624973d825SFinley Xiao ret = rockchip_otp_wait_status(otp, OTPC_SBPI_DONE);
634973d825SFinley Xiao if (ret < 0)
644973d825SFinley Xiao printf("%s timeout during ecc_enable\n", __func__);
654973d825SFinley Xiao
664973d825SFinley Xiao return ret;
674973d825SFinley Xiao }
684973d825SFinley Xiao
rockchip_px30_otp_read(struct udevice * dev,int offset,void * buf,int size)694973d825SFinley Xiao static int rockchip_px30_otp_read(struct udevice *dev, int offset,
704973d825SFinley Xiao void *buf, int size)
714973d825SFinley Xiao {
724973d825SFinley Xiao struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
734973d825SFinley Xiao u8 *buffer = buf;
744973d825SFinley Xiao int ret = 0;
754973d825SFinley Xiao
764973d825SFinley Xiao ret = rockchip_otp_ecc_enable(otp, false);
774973d825SFinley Xiao if (ret < 0) {
784973d825SFinley Xiao printf("%s rockchip_otp_ecc_enable err\n", __func__);
794973d825SFinley Xiao return ret;
804973d825SFinley Xiao }
814973d825SFinley Xiao
824973d825SFinley Xiao writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
834973d825SFinley Xiao udelay(5);
844973d825SFinley Xiao while (size--) {
854973d825SFinley Xiao writel(offset++ | OTPC_USER_ADDR_MASK,
864973d825SFinley Xiao otp->base + OTPC_USER_ADDR);
874973d825SFinley Xiao writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
884973d825SFinley Xiao otp->base + OTPC_USER_ENABLE);
894973d825SFinley Xiao ret = rockchip_otp_wait_status(otp, OTPC_USER_DONE);
904973d825SFinley Xiao if (ret < 0) {
914973d825SFinley Xiao printf("%s timeout during read setup\n", __func__);
924973d825SFinley Xiao goto read_end;
934973d825SFinley Xiao }
944973d825SFinley Xiao *buffer++ = readb(otp->base + OTPC_USER_Q);
954973d825SFinley Xiao }
964973d825SFinley Xiao
974973d825SFinley Xiao read_end:
984973d825SFinley Xiao writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
994973d825SFinley Xiao
1004973d825SFinley Xiao return ret;
1014973d825SFinley Xiao }
1024973d825SFinley Xiao
rk3308bs_otp_wait_status(struct rockchip_otp_platdata * otp,u32 flag)1039fed581aSFinley Xiao static int rk3308bs_otp_wait_status(struct rockchip_otp_platdata *otp, u32 flag)
1049fed581aSFinley Xiao {
1059fed581aSFinley Xiao int delay = OTPC_TIMEOUT;
1069fed581aSFinley Xiao
1079fed581aSFinley Xiao while (!(readl(otp->base + OTPC_IRQ_ST) & flag)) {
1089fed581aSFinley Xiao udelay(1);
1099fed581aSFinley Xiao delay--;
1109fed581aSFinley Xiao if (delay <= 0) {
1119fed581aSFinley Xiao printf("%s: wait init status timeout\n", __func__);
1129fed581aSFinley Xiao return -ETIMEDOUT;
1139fed581aSFinley Xiao }
1149fed581aSFinley Xiao }
1159fed581aSFinley Xiao
1169fed581aSFinley Xiao /* clean int status */
1179fed581aSFinley Xiao writel(flag, otp->base + OTPC_IRQ_ST);
1189fed581aSFinley Xiao
1199fed581aSFinley Xiao return 0;
1209fed581aSFinley Xiao }
1219fed581aSFinley Xiao
rk3308bs_otp_active(struct rockchip_otp_platdata * otp)1229fed581aSFinley Xiao static int rk3308bs_otp_active(struct rockchip_otp_platdata *otp)
1239fed581aSFinley Xiao {
1249fed581aSFinley Xiao int ret = 0;
1259fed581aSFinley Xiao u32 mode;
1269fed581aSFinley Xiao
1279fed581aSFinley Xiao mode = readl(otp->base + OTPC_MODE_CTRL);
1289fed581aSFinley Xiao
1299fed581aSFinley Xiao switch (mode) {
1309fed581aSFinley Xiao case OTPC_DEEP_STANDBY:
1319fed581aSFinley Xiao writel(OTPC_STANDBY, otp->base + OTPC_MODE_CTRL);
1329fed581aSFinley Xiao ret = rk3308bs_otp_wait_status(otp, OTPC_DP2STB_IRQ_ST);
1339fed581aSFinley Xiao if (ret < 0) {
1349fed581aSFinley Xiao dev_err(otp->dev, "timeout during wait dp2stb\n");
1359fed581aSFinley Xiao return ret;
1369fed581aSFinley Xiao }
1379fed581aSFinley Xiao case OTPC_STANDBY:
1389fed581aSFinley Xiao writel(OTPC_ACTIVE, otp->base + OTPC_MODE_CTRL);
1399fed581aSFinley Xiao ret = rk3308bs_otp_wait_status(otp, OTPC_STB2ACT_IRQ_ST);
1409fed581aSFinley Xiao if (ret < 0) {
1419fed581aSFinley Xiao dev_err(otp->dev, "timeout during wait stb2act\n");
1429fed581aSFinley Xiao return ret;
1439fed581aSFinley Xiao }
1449fed581aSFinley Xiao break;
1459fed581aSFinley Xiao default:
1469fed581aSFinley Xiao break;
1479fed581aSFinley Xiao }
1489fed581aSFinley Xiao
1499fed581aSFinley Xiao return ret;
1509fed581aSFinley Xiao }
1519fed581aSFinley Xiao
rk3308bs_otp_standby(struct rockchip_otp_platdata * otp)1529fed581aSFinley Xiao static int rk3308bs_otp_standby(struct rockchip_otp_platdata *otp)
1539fed581aSFinley Xiao {
1549fed581aSFinley Xiao int ret = 0;
1559fed581aSFinley Xiao u32 mode;
1569fed581aSFinley Xiao
1579fed581aSFinley Xiao mode = readl(otp->base + OTPC_MODE_CTRL);
1589fed581aSFinley Xiao
1599fed581aSFinley Xiao switch (mode) {
1609fed581aSFinley Xiao case OTPC_ACTIVE:
1619fed581aSFinley Xiao writel(OTPC_STANDBY, otp->base + OTPC_MODE_CTRL);
1629fed581aSFinley Xiao ret = rk3308bs_otp_wait_status(otp, OTPC_ACT2STB_IRQ_ST);
1639fed581aSFinley Xiao if (ret < 0) {
1649fed581aSFinley Xiao dev_err(otp->dev, "timeout during wait act2stb\n");
1659fed581aSFinley Xiao return ret;
1669fed581aSFinley Xiao }
1679fed581aSFinley Xiao case OTPC_STANDBY:
1689fed581aSFinley Xiao writel(OTPC_DEEP_STANDBY, otp->base + OTPC_MODE_CTRL);
1699fed581aSFinley Xiao ret = rk3308bs_otp_wait_status(otp, OTPC_STB2DP_IRQ_ST);
1709fed581aSFinley Xiao if (ret < 0) {
1719fed581aSFinley Xiao dev_err(otp->dev, "timeout during wait stb2dp\n");
1729fed581aSFinley Xiao return ret;
1739fed581aSFinley Xiao }
1749fed581aSFinley Xiao break;
1759fed581aSFinley Xiao default:
1769fed581aSFinley Xiao break;
1779fed581aSFinley Xiao }
1789fed581aSFinley Xiao
1799fed581aSFinley Xiao return ret;
1809fed581aSFinley Xiao }
1819fed581aSFinley Xiao
rockchip_rk3308bs_otp_read(struct udevice * dev,int offset,void * buf,int size)1829fed581aSFinley Xiao static int rockchip_rk3308bs_otp_read(struct udevice *dev, int offset,
1839fed581aSFinley Xiao void *buf, int size)
1849fed581aSFinley Xiao {
1859fed581aSFinley Xiao struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
1869fed581aSFinley Xiao unsigned int addr_start, addr_end, addr_offset, addr_len;
1879fed581aSFinley Xiao u32 out_value;
1889fed581aSFinley Xiao u8 *buffer;
1899fed581aSFinley Xiao int ret = 0, i = 0;
1909fed581aSFinley Xiao
1919fed581aSFinley Xiao if (offset > RK3308BS_MAX_BYTES - 1)
1929fed581aSFinley Xiao return -ENOMEM;
1939fed581aSFinley Xiao if (offset + size > RK3308BS_MAX_BYTES)
1949fed581aSFinley Xiao size = RK3308BS_MAX_BYTES - offset;
1959fed581aSFinley Xiao
1969fed581aSFinley Xiao ret = rk3308bs_otp_active(otp);
1979fed581aSFinley Xiao if (ret)
1989fed581aSFinley Xiao goto out;
1999fed581aSFinley Xiao
2009fed581aSFinley Xiao addr_start = rounddown(offset, RK3308BS_NBYTES) / RK3308BS_NBYTES;
2019fed581aSFinley Xiao addr_end = roundup(offset + size, RK3308BS_NBYTES) / RK3308BS_NBYTES;
2029fed581aSFinley Xiao addr_offset = offset % RK3308BS_NBYTES;
2039fed581aSFinley Xiao addr_len = addr_end - addr_start;
2049fed581aSFinley Xiao
2059fed581aSFinley Xiao buffer = calloc(1, sizeof(*buffer) * addr_len * RK3308BS_NBYTES);
2069fed581aSFinley Xiao if (!buffer) {
2079fed581aSFinley Xiao ret = -ENOMEM;
2089fed581aSFinley Xiao goto read_end;
2099fed581aSFinley Xiao }
2109fed581aSFinley Xiao
2119fed581aSFinley Xiao while (addr_len--) {
2129fed581aSFinley Xiao writel(OTPC_TRANS_NUM, otp->base + OTPC_REPR_RD_TRANS_NUM);
2139fed581aSFinley Xiao writel(addr_start++, otp->base + OTPC_ACCESS_ADDR);
2149fed581aSFinley Xiao writel(OTPC_READ_ACCESS, otp->base + OTPC_MODE_CTRL);
2159fed581aSFinley Xiao ret = rk3308bs_otp_wait_status(otp, OTPC_RDM_IRQ_ST);
2169fed581aSFinley Xiao if (ret < 0) {
2179fed581aSFinley Xiao printf("timeout during wait rd\n");
2189fed581aSFinley Xiao goto read_end;
2199fed581aSFinley Xiao }
2209fed581aSFinley Xiao out_value = readl(otp->base + OTPC_RD_DATA);
2219fed581aSFinley Xiao memcpy(&buffer[i], &out_value, RK3308BS_NBYTES);
2229fed581aSFinley Xiao i += RK3308BS_NBYTES;
2239fed581aSFinley Xiao }
2249fed581aSFinley Xiao memcpy(buf, buffer + addr_offset, size);
2259fed581aSFinley Xiao
2269fed581aSFinley Xiao read_end:
2279fed581aSFinley Xiao kfree(buffer);
2289fed581aSFinley Xiao rk3308bs_otp_standby(otp);
2299fed581aSFinley Xiao out:
2309fed581aSFinley Xiao return ret;
2319fed581aSFinley Xiao }
2329fed581aSFinley Xiao
rockchip_rk3568_otp_read(struct udevice * dev,int offset,void * buf,int size)233fd7b5182SFinley Xiao static int rockchip_rk3568_otp_read(struct udevice *dev, int offset, void *buf,
234fd7b5182SFinley Xiao int size)
235fd7b5182SFinley Xiao {
236fd7b5182SFinley Xiao struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
237fd7b5182SFinley Xiao unsigned int addr_start, addr_end, addr_offset, addr_len;
238fd7b5182SFinley Xiao u32 out_value;
239fd7b5182SFinley Xiao u8 *buffer;
240fd7b5182SFinley Xiao int ret = 0, i = 0;
241fd7b5182SFinley Xiao
242fd7b5182SFinley Xiao addr_start = rounddown(offset, RK3568_NBYTES) / RK3568_NBYTES;
243fd7b5182SFinley Xiao addr_end = roundup(offset + size, RK3568_NBYTES) / RK3568_NBYTES;
244fd7b5182SFinley Xiao addr_offset = offset % RK3568_NBYTES;
245fd7b5182SFinley Xiao addr_len = addr_end - addr_start;
246fd7b5182SFinley Xiao
247fd7b5182SFinley Xiao buffer = calloc(1, sizeof(*buffer) * addr_len * RK3568_NBYTES);
248fd7b5182SFinley Xiao if (!buffer)
249fd7b5182SFinley Xiao return -ENOMEM;
250fd7b5182SFinley Xiao
251e51b7fb1SFinley Xiao ret = rockchip_otp_ecc_enable(otp, true);
252fd7b5182SFinley Xiao if (ret < 0) {
253fd7b5182SFinley Xiao printf("%s rockchip_otp_ecc_enable err\n", __func__);
254fd7b5182SFinley Xiao return ret;
255fd7b5182SFinley Xiao }
256fd7b5182SFinley Xiao
257fd7b5182SFinley Xiao writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
258fd7b5182SFinley Xiao udelay(5);
259fd7b5182SFinley Xiao while (addr_len--) {
260fd7b5182SFinley Xiao writel(addr_start++ | OTPC_USER_ADDR_MASK,
261fd7b5182SFinley Xiao otp->base + OTPC_USER_ADDR);
262fd7b5182SFinley Xiao writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
263fd7b5182SFinley Xiao otp->base + OTPC_USER_ENABLE);
264fd7b5182SFinley Xiao ret = rockchip_otp_wait_status(otp, OTPC_USER_DONE);
265fd7b5182SFinley Xiao if (ret < 0) {
266fd7b5182SFinley Xiao printf("%s timeout during read setup\n", __func__);
267fd7b5182SFinley Xiao goto read_end;
268fd7b5182SFinley Xiao }
269fd7b5182SFinley Xiao out_value = readl(otp->base + OTPC_USER_Q);
270fd7b5182SFinley Xiao memcpy(&buffer[i], &out_value, RK3568_NBYTES);
271fd7b5182SFinley Xiao i += RK3568_NBYTES;
272fd7b5182SFinley Xiao }
273fd7b5182SFinley Xiao
274fd7b5182SFinley Xiao memcpy(buf, buffer + addr_offset, size);
275fd7b5182SFinley Xiao
276fd7b5182SFinley Xiao read_end:
277fd7b5182SFinley Xiao writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
278fd7b5182SFinley Xiao
279fd7b5182SFinley Xiao kfree(buffer);
280fd7b5182SFinley Xiao
281fd7b5182SFinley Xiao return ret;
282fd7b5182SFinley Xiao }
283fd7b5182SFinley Xiao
rockchip_rk3588_otp_read(struct udevice * dev,int offset,void * buf,int size)284975a7fc3SFinley Xiao static int rockchip_rk3588_otp_read(struct udevice *dev, int offset, void *buf,
285975a7fc3SFinley Xiao int size)
286975a7fc3SFinley Xiao {
287975a7fc3SFinley Xiao struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
288dd270bd4SXuhui Lin struct otp_data *data;
289975a7fc3SFinley Xiao unsigned int addr_start, addr_end, addr_offset, addr_len;
290975a7fc3SFinley Xiao int ret = 0, i = 0;
291975a7fc3SFinley Xiao u32 out_value, st = 0;
292975a7fc3SFinley Xiao u8 *buffer;
293975a7fc3SFinley Xiao
294dd270bd4SXuhui Lin data = (struct otp_data *)dev_get_driver_data(dev);
295dd270bd4SXuhui Lin if (!data)
296dd270bd4SXuhui Lin return -ENOSYS;
297dd270bd4SXuhui Lin
298dd270bd4SXuhui Lin if (offset > data->size - 1)
299975a7fc3SFinley Xiao return -ENOMEM;
300dd270bd4SXuhui Lin if (offset + size > data->size)
301dd270bd4SXuhui Lin size = data->size - offset;
302975a7fc3SFinley Xiao
303975a7fc3SFinley Xiao addr_start = rounddown(offset, RK3588_NBYTES) / RK3588_NBYTES;
304975a7fc3SFinley Xiao addr_end = roundup(offset + size, RK3588_NBYTES) / RK3588_NBYTES;
305975a7fc3SFinley Xiao addr_offset = offset % RK3588_NBYTES;
306975a7fc3SFinley Xiao addr_len = addr_end - addr_start;
307dd270bd4SXuhui Lin addr_start += data->ns_offset;
308975a7fc3SFinley Xiao
309975a7fc3SFinley Xiao buffer = calloc(1, sizeof(*buffer) * addr_len * RK3588_NBYTES);
310975a7fc3SFinley Xiao if (!buffer)
311975a7fc3SFinley Xiao return -ENOMEM;
312975a7fc3SFinley Xiao
313975a7fc3SFinley Xiao while (addr_len--) {
314975a7fc3SFinley Xiao writel((addr_start << RK3588_ADDR_SHIFT) |
315975a7fc3SFinley Xiao (RK3588_BURST_NUM << RK3588_BURST_SHIFT),
316975a7fc3SFinley Xiao otp->base + RK3588_OTPC_AUTO_CTRL);
317975a7fc3SFinley Xiao writel(RK3588_AUTO_EN, otp->base + RK3588_OTPC_AUTO_EN);
318975a7fc3SFinley Xiao ret = readl_poll_timeout(otp->base + RK3588_OTPC_INT_ST, st,
319975a7fc3SFinley Xiao st & RK3588_RD_DONE, OTPC_TIMEOUT);
320975a7fc3SFinley Xiao if (ret < 0) {
321975a7fc3SFinley Xiao printf("%s timeout during read setup\n", __func__);
322975a7fc3SFinley Xiao goto read_end;
323975a7fc3SFinley Xiao }
324975a7fc3SFinley Xiao writel(RK3588_RD_DONE, otp->base + RK3588_OTPC_INT_ST);
325975a7fc3SFinley Xiao
326975a7fc3SFinley Xiao out_value = readl(otp->base + RK3588_OTPC_DOUT0);
327975a7fc3SFinley Xiao memcpy(&buffer[i], &out_value, RK3588_NBYTES);
328975a7fc3SFinley Xiao i += RK3588_NBYTES;
329975a7fc3SFinley Xiao addr_start++;
330975a7fc3SFinley Xiao }
331975a7fc3SFinley Xiao
332975a7fc3SFinley Xiao memcpy(buf, buffer + addr_offset, size);
333975a7fc3SFinley Xiao
334975a7fc3SFinley Xiao read_end:
335975a7fc3SFinley Xiao kfree(buffer);
336975a7fc3SFinley Xiao
337975a7fc3SFinley Xiao return ret;
338975a7fc3SFinley Xiao }
339975a7fc3SFinley Xiao
rockchip_rv1126_otp_init(struct udevice * dev)340a4c57e8aSFinley Xiao static int rockchip_rv1126_otp_init(struct udevice *dev)
341a4c57e8aSFinley Xiao {
342a4c57e8aSFinley Xiao struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
343a4c57e8aSFinley Xiao u32 status = 0;
344a4c57e8aSFinley Xiao int ret;
345a4c57e8aSFinley Xiao
346a4c57e8aSFinley Xiao writel(0x0, otp->base + RV1126_OTP_NVM_CEB);
347a4c57e8aSFinley Xiao ret = readl_poll_timeout(otp->base + RV1126_OTP_NVM_ST, status,
348a4c57e8aSFinley Xiao status & 0x1, OTPC_TIMEOUT);
349a4c57e8aSFinley Xiao if (ret < 0) {
350a4c57e8aSFinley Xiao printf("%s timeout during set ceb\n", __func__);
351a4c57e8aSFinley Xiao return ret;
352a4c57e8aSFinley Xiao }
353a4c57e8aSFinley Xiao
354a4c57e8aSFinley Xiao writel(0x1, otp->base + RV1126_OTP_NVM_RSTB);
355a4c57e8aSFinley Xiao ret = readl_poll_timeout(otp->base + RV1126_OTP_NVM_ST, status,
356a4c57e8aSFinley Xiao status & 0x4, OTPC_TIMEOUT);
357a4c57e8aSFinley Xiao if (ret < 0) {
358a4c57e8aSFinley Xiao printf("%s timeout during set rstb\n", __func__);
359a4c57e8aSFinley Xiao return ret;
360a4c57e8aSFinley Xiao }
361a4c57e8aSFinley Xiao
362a4c57e8aSFinley Xiao return 0;
363a4c57e8aSFinley Xiao }
364a4c57e8aSFinley Xiao
rockchip_rv1126_otp_read(struct udevice * dev,int offset,void * buf,int size)365a4c57e8aSFinley Xiao static int rockchip_rv1126_otp_read(struct udevice *dev, int offset, void *buf,
366a4c57e8aSFinley Xiao int size)
367a4c57e8aSFinley Xiao {
368a4c57e8aSFinley Xiao struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
369a4c57e8aSFinley Xiao u32 status = 0;
370a4c57e8aSFinley Xiao u8 *buffer = buf;
371a4c57e8aSFinley Xiao int ret = 0;
372a4c57e8aSFinley Xiao
373a4c57e8aSFinley Xiao while (size--) {
374a4c57e8aSFinley Xiao writel(offset++, otp->base + RV1126_OTP_NVM_RADDR);
375a4c57e8aSFinley Xiao writel(0x1, otp->base + RV1126_OTP_NVM_RSTART);
376a4c57e8aSFinley Xiao ret = readl_poll_timeout(otp->base + RV1126_OTP_READ_ST,
377a4c57e8aSFinley Xiao status, status == 0, OTPC_TIMEOUT);
378a4c57e8aSFinley Xiao if (ret < 0) {
379a4c57e8aSFinley Xiao printf("%s timeout during read setup\n", __func__);
380a4c57e8aSFinley Xiao return ret;
381a4c57e8aSFinley Xiao }
382a4c57e8aSFinley Xiao
383a4c57e8aSFinley Xiao *buffer++ = readb(otp->base + RV1126_OTP_NVM_RDATA);
384a4c57e8aSFinley Xiao }
385a4c57e8aSFinley Xiao
386a4c57e8aSFinley Xiao return 0;
387a4c57e8aSFinley Xiao }
388a4c57e8aSFinley Xiao
rockchip_otp_read(struct udevice * dev,int offset,void * buf,int size)3894973d825SFinley Xiao static int rockchip_otp_read(struct udevice *dev, int offset,
3904973d825SFinley Xiao void *buf, int size)
3914973d825SFinley Xiao {
392a4c57e8aSFinley Xiao struct otp_data *data;
3934973d825SFinley Xiao
394a4c57e8aSFinley Xiao data = (struct otp_data *)dev_get_driver_data(dev);
395a4c57e8aSFinley Xiao if (!data)
3964973d825SFinley Xiao return -ENOSYS;
3974973d825SFinley Xiao
398738773c6SFinley Xiao if (soc_is_rk3308bs() || soc_is_px30s())
3999fed581aSFinley Xiao return rockchip_rk3308bs_otp_read(dev, offset, buf, size);
4009fed581aSFinley Xiao
401a4c57e8aSFinley Xiao return data->read(dev, offset, buf, size);
4024973d825SFinley Xiao }
4034973d825SFinley Xiao
4044973d825SFinley Xiao static const struct misc_ops rockchip_otp_ops = {
4054973d825SFinley Xiao .read = rockchip_otp_read,
4064973d825SFinley Xiao };
4074973d825SFinley Xiao
rockchip_otp_ofdata_to_platdata(struct udevice * dev)4084973d825SFinley Xiao static int rockchip_otp_ofdata_to_platdata(struct udevice *dev)
4094973d825SFinley Xiao {
4104973d825SFinley Xiao struct rockchip_otp_platdata *otp = dev_get_platdata(dev);
4114973d825SFinley Xiao
4124973d825SFinley Xiao otp->base = dev_read_addr_ptr(dev);
4134973d825SFinley Xiao
4144973d825SFinley Xiao return 0;
4154973d825SFinley Xiao }
4164973d825SFinley Xiao
rockchip_otp_probe(struct udevice * dev)417a4c57e8aSFinley Xiao static int rockchip_otp_probe(struct udevice *dev)
418a4c57e8aSFinley Xiao {
419a4c57e8aSFinley Xiao struct otp_data *data;
420a4c57e8aSFinley Xiao
421a4c57e8aSFinley Xiao data = (struct otp_data *)dev_get_driver_data(dev);
422a4c57e8aSFinley Xiao if (!data)
423a4c57e8aSFinley Xiao return -EINVAL;
424a4c57e8aSFinley Xiao
425a4c57e8aSFinley Xiao if (data->init)
426a4c57e8aSFinley Xiao return data->init(dev);
427a4c57e8aSFinley Xiao
428a4c57e8aSFinley Xiao return 0;
429a4c57e8aSFinley Xiao }
430a4c57e8aSFinley Xiao
431a4c57e8aSFinley Xiao static const struct otp_data px30_data = {
432a4c57e8aSFinley Xiao .read = rockchip_px30_otp_read,
433a4c57e8aSFinley Xiao };
434a4c57e8aSFinley Xiao
4359fed581aSFinley Xiao static const struct otp_data rk3308bs_data = {
4369fed581aSFinley Xiao .read = rockchip_rk3308bs_otp_read,
4379fed581aSFinley Xiao };
4389fed581aSFinley Xiao
439fd7b5182SFinley Xiao static const struct otp_data rk3568_data = {
440fd7b5182SFinley Xiao .read = rockchip_rk3568_otp_read,
441fd7b5182SFinley Xiao };
442fd7b5182SFinley Xiao
443dd270bd4SXuhui Lin static const struct otp_data rk3576_data = {
444dd270bd4SXuhui Lin .size = 0x100,
445dd270bd4SXuhui Lin .ns_offset = RK3576_NO_SECURE_OFFSET,
446dd270bd4SXuhui Lin .read = rockchip_rk3588_otp_read,
447dd270bd4SXuhui Lin };
448dd270bd4SXuhui Lin
449975a7fc3SFinley Xiao static const struct otp_data rk3588_data = {
450dd270bd4SXuhui Lin .size = 0x400,
451dd270bd4SXuhui Lin .ns_offset = RK3588_NO_SECURE_OFFSET,
452975a7fc3SFinley Xiao .read = rockchip_rk3588_otp_read,
453975a7fc3SFinley Xiao };
454975a7fc3SFinley Xiao
455a4c57e8aSFinley Xiao static const struct otp_data rv1126_data = {
456a4c57e8aSFinley Xiao .init = rockchip_rv1126_otp_init,
457a4c57e8aSFinley Xiao .read = rockchip_rv1126_otp_read,
458a4c57e8aSFinley Xiao };
459a4c57e8aSFinley Xiao
4604973d825SFinley Xiao static const struct udevice_id rockchip_otp_ids[] = {
4614973d825SFinley Xiao {
4624973d825SFinley Xiao .compatible = "rockchip,px30-otp",
463a4c57e8aSFinley Xiao .data = (ulong)&px30_data,
4644973d825SFinley Xiao },
4656be53b63SFinley Xiao {
466738773c6SFinley Xiao .compatible = "rockchip,px30s-otp",
467738773c6SFinley Xiao .data = (ulong)&rk3308bs_data,
468738773c6SFinley Xiao },
469738773c6SFinley Xiao {
4706be53b63SFinley Xiao .compatible = "rockchip,rk3308-otp",
471a4c57e8aSFinley Xiao .data = (ulong)&px30_data,
472a4c57e8aSFinley Xiao },
473a4c57e8aSFinley Xiao {
4749fed581aSFinley Xiao .compatible = "rockchip,rk3308bs-otp",
4759fed581aSFinley Xiao .data = (ulong)&rk3308bs_data,
4769fed581aSFinley Xiao },
4779fed581aSFinley Xiao {
4780e048a48SXuhui Lin .compatible = "rockchip,rk3506-otp",
4790e048a48SXuhui Lin .data = (ulong)&rk3568_data,
4800e048a48SXuhui Lin },
4810e048a48SXuhui Lin {
482abb97387SFinley Xiao .compatible = "rockchip,rk3528-otp",
483abb97387SFinley Xiao .data = (ulong)&rk3568_data,
484abb97387SFinley Xiao },
485abb97387SFinley Xiao {
4866e6ee2d7SFinley Xiao .compatible = "rockchip,rk3562-otp",
4876e6ee2d7SFinley Xiao .data = (ulong)&rk3568_data,
4886e6ee2d7SFinley Xiao },
4896e6ee2d7SFinley Xiao {
490fd7b5182SFinley Xiao .compatible = "rockchip,rk3568-otp",
491fd7b5182SFinley Xiao .data = (ulong)&rk3568_data,
492fd7b5182SFinley Xiao },
493fd7b5182SFinley Xiao {
494dd270bd4SXuhui Lin .compatible = "rockchip,rk3576-otp",
495dd270bd4SXuhui Lin .data = (ulong)&rk3576_data,
496dd270bd4SXuhui Lin },
497dd270bd4SXuhui Lin {
498975a7fc3SFinley Xiao .compatible = "rockchip,rk3588-otp",
499975a7fc3SFinley Xiao .data = (ulong)&rk3588_data,
500975a7fc3SFinley Xiao },
501975a7fc3SFinley Xiao {
5029fc67a2aSFinley Xiao .compatible = "rockchip,rv1106-otp",
5039fc67a2aSFinley Xiao .data = (ulong)&rk3568_data,
5049fc67a2aSFinley Xiao },
5059fc67a2aSFinley Xiao {
506a4c57e8aSFinley Xiao .compatible = "rockchip,rv1126-otp",
507a4c57e8aSFinley Xiao .data = (ulong)&rv1126_data,
5086be53b63SFinley Xiao },
509dbf5f0e7SXuhui Lin {
510*052b7b07SXuhui Lin .compatible = "rockchip,rv1126b-otp",
511*052b7b07SXuhui Lin .data = (ulong)&rk3568_data,
512*052b7b07SXuhui Lin },
513*052b7b07SXuhui Lin {
514dbf5f0e7SXuhui Lin .compatible = "rockchip,rv1103b-otp",
515dbf5f0e7SXuhui Lin .data = (ulong)&rk3568_data,
516dbf5f0e7SXuhui Lin },
5174973d825SFinley Xiao {}
5184973d825SFinley Xiao };
5194973d825SFinley Xiao
5204973d825SFinley Xiao U_BOOT_DRIVER(rockchip_otp) = {
5214973d825SFinley Xiao .name = "rockchip_otp",
5224973d825SFinley Xiao .id = UCLASS_MISC,
5234973d825SFinley Xiao .of_match = rockchip_otp_ids,
5244973d825SFinley Xiao .ops = &rockchip_otp_ops,
5254973d825SFinley Xiao .ofdata_to_platdata = rockchip_otp_ofdata_to_platdata,
5264973d825SFinley Xiao .platdata_auto_alloc_size = sizeof(struct rockchip_otp_platdata),
527a4c57e8aSFinley Xiao .probe = rockchip_otp_probe,
5284973d825SFinley Xiao };
529