From 3eae38e0c13a4617f0d2f9a26bb911a2811f57b0 Mon Sep 17 00:00:00 2001 From: Finley Xiao Date: Mon, 12 Jul 2021 17:17:48 +0800 Subject: [PATCH] nvmem: rockchip-otp: Add support for rk3588-otp This adds the necessary data for handling otp on the rk3588. Change-Id: I55a162dfa5735139c2f1d74510b53496decacbb6 Signed-off-by: Finley Xiao --- drivers/nvmem/rockchip-otp.c | 101 +++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/drivers/nvmem/rockchip-otp.c b/drivers/nvmem/rockchip-otp.c index 3853749c4f9e..7ca6e3873c5f 100644 --- a/drivers/nvmem/rockchip-otp.c +++ b/drivers/nvmem/rockchip-otp.c @@ -57,6 +57,18 @@ #define OTPC_TIMEOUT_PROG 100000 #define RK3568_NBYTES 2 +#define RK3588_OTPC_AUTO_CTRL 0x04 +#define RK3588_OTPC_AUTO_EN 0x08 +#define RK3588_OTPC_INT_ST 0x84 +#define RK3588_OTPC_DOUT0 0x20 +#define RK3588_NO_SECURE_OFFSET 0x300 +#define RK3588_NBYTES 4 +#define RK3588_BURST_NUM 1 +#define RK3588_BURST_SHIFT 8 +#define RK3588_ADDR_SHIFT 16 +#define RK3588_AUTO_EN BIT(0) +#define RK3588_RD_DONE BIT(1) + #define RV1126_OTP_NVM_CEB 0x00 #define RV1126_OTP_NVM_RSTB 0x04 #define RV1126_OTP_NVM_ST 0x18 @@ -324,6 +336,80 @@ out: return ret; } +static int rk3588_otp_wait_status(struct rockchip_otp *otp, u32 flag) +{ + u32 status = 0; + int ret; + + ret = readl_poll_timeout_atomic(otp->base + RK3588_OTPC_INT_ST, status, + (status & flag), 1, OTPC_TIMEOUT); + if (ret) + return ret; + + /* clean int status */ + writel(flag, otp->base + RK3588_OTPC_INT_ST); + + return 0; +} + +static int rk3588_otp_read(void *context, unsigned int offset, void *val, + size_t bytes) +{ + struct rockchip_otp *otp = context; + unsigned int addr_start, addr_end, addr_offset, addr_len; + int ret = 0, i = 0; + u32 out_value; + u8 *buf; + + if (offset >= otp->data->size) + return -ENOMEM; + if (offset + bytes > otp->data->size) + bytes = otp->data->size - offset; + + addr_start = rounddown(offset, RK3588_NBYTES) / RK3588_NBYTES; + addr_end = roundup(offset + bytes, RK3588_NBYTES) / RK3588_NBYTES; + addr_offset = offset % RK3588_NBYTES; + addr_len = addr_end - addr_start; + addr_start += RK3588_NO_SECURE_OFFSET; + + buf = kzalloc(array3_size(addr_len, RK3588_NBYTES, sizeof(*buf)), + GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = clk_bulk_prepare_enable(otp->num_clks, otp->clks); + if (ret < 0) { + dev_err(otp->dev, "failed to prepare/enable clks\n"); + goto out; + } + + while (addr_len--) { + writel((addr_start << RK3588_ADDR_SHIFT) | + (RK3588_BURST_NUM << RK3588_BURST_SHIFT), + otp->base + RK3588_OTPC_AUTO_CTRL); + writel(RK3588_AUTO_EN, otp->base + RK3588_OTPC_AUTO_EN); + ret = rk3588_otp_wait_status(otp, RK3588_RD_DONE); + if (ret < 0) { + dev_err(otp->dev, "timeout during read setup\n"); + goto read_end; + } + + out_value = readl(otp->base + RK3588_OTPC_DOUT0); + memcpy(&buf[i], &out_value, RK3588_NBYTES); + i += RK3588_NBYTES; + addr_start++; + } + + memcpy(val, buf + addr_offset, bytes); + +read_end: + clk_bulk_disable_unprepare(otp->num_clks, otp->clks); +out: + kfree(buf); + + return ret; +} + static int rv1126_otp_init(struct rockchip_otp *otp) { u32 status = 0; @@ -515,6 +601,17 @@ static const struct rockchip_data rk3568_data = { .reg_read = rk3568_otp_read, }; +static const char * const rk3588_otp_clocks[] = { + "otpc", "apb", "arb", "phy", +}; + +static const struct rockchip_data rk3588_data = { + .size = 0x400, + .clocks = rk3588_otp_clocks, + .num_clks = ARRAY_SIZE(rk3588_otp_clocks), + .reg_read = rk3588_otp_read, +}; + static const char * const rv1126_otp_clocks[] = { "otp", "apb_pclk", }; @@ -541,6 +638,10 @@ static const struct of_device_id rockchip_otp_match[] = { .compatible = "rockchip,rk3568-otp", .data = (void *)&rk3568_data, }, + { + .compatible = "rockchip,rk3588-otp", + .data = (void *)&rk3588_data, + }, { .compatible = "rockchip,rv1126-otp", .data = (void *)&rv1126_data,