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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 }, 509*dbf5f0e7SXuhui Lin { 510*dbf5f0e7SXuhui Lin .compatible = "rockchip,rv1103b-otp", 511*dbf5f0e7SXuhui Lin .data = (ulong)&rk3568_data, 512*dbf5f0e7SXuhui Lin }, 5134973d825SFinley Xiao {} 5144973d825SFinley Xiao }; 5154973d825SFinley Xiao 5164973d825SFinley Xiao U_BOOT_DRIVER(rockchip_otp) = { 5174973d825SFinley Xiao .name = "rockchip_otp", 5184973d825SFinley Xiao .id = UCLASS_MISC, 5194973d825SFinley Xiao .of_match = rockchip_otp_ids, 5204973d825SFinley Xiao .ops = &rockchip_otp_ops, 5214973d825SFinley Xiao .ofdata_to_platdata = rockchip_otp_ofdata_to_platdata, 5224973d825SFinley Xiao .platdata_auto_alloc_size = sizeof(struct rockchip_otp_platdata), 523a4c57e8aSFinley Xiao .probe = rockchip_otp_probe, 5244973d825SFinley Xiao }; 525