Add support for the OTP memory device found on the Rockchip RK3588 SoC. While here, remove the unnecessary 'void *' casts in the OF device ID table. Co-developed-by: Finley Xiao <finley.xiao@xxxxxxxxxxxxxx> Signed-off-by: Finley Xiao <finley.xiao@xxxxxxxxxxxxxx> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@xxxxxxxxxxxxx> --- drivers/nvmem/rockchip-otp.c | 78 +++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/drivers/nvmem/rockchip-otp.c b/drivers/nvmem/rockchip-otp.c index 4370d6c5e4e9..022691cadf94 100644 --- a/drivers/nvmem/rockchip-otp.c +++ b/drivers/nvmem/rockchip-otp.c @@ -54,6 +54,19 @@ #define OTPC_TIMEOUT 10000 +/* RK3588 Register */ +#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) + struct rockchip_data { int size; const char * const *clocks; @@ -171,6 +184,52 @@ static int px30_otp_read(void *context, unsigned int offset, return ret; } +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_len; + int ret, i = 0; + u32 data; + u8 *buf; + + addr_start = round_down(offset, RK3588_NBYTES) / RK3588_NBYTES; + addr_end = round_up(offset + bytes, RK3588_NBYTES) / RK3588_NBYTES; + addr_len = addr_end - addr_start; + addr_start += RK3588_NO_SECURE_OFFSET; + + buf = kzalloc(array_size(addr_len, RK3588_NBYTES), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + 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 = rockchip_otp_wait_status(otp, RK3588_OTPC_INT_ST, + RK3588_RD_DONE); + if (ret < 0) { + dev_err(otp->dev, "timeout during read setup\n"); + goto read_end; + } + + data = readl(otp->base + RK3588_OTPC_DOUT0); + memcpy(&buf[i], &data, RK3588_NBYTES); + + i += RK3588_NBYTES; + addr_start++; + } + + memcpy(val, buf + offset % RK3588_NBYTES, bytes); + +read_end: + kfree(buf); + + return ret; +} + static int rockchip_otp_read(void *context, unsigned int offset, void *val, size_t bytes) { @@ -213,14 +272,29 @@ static const struct rockchip_data px30_data = { .reg_read = px30_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 struct of_device_id rockchip_otp_match[] = { { .compatible = "rockchip,px30-otp", - .data = (void *)&px30_data, + .data = &px30_data, }, { .compatible = "rockchip,rk3308-otp", - .data = (void *)&px30_data, + .data = &px30_data, + }, + { + .compatible = "rockchip,rk3588-otp", + .data = &rk3588_data, }, { /* sentinel */ }, }; -- 2.40.0