From 8fa1870e11ebf049af74be94bfaad17006eb18da Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Wed, 22 Feb 2023 22:44:38 +0000 Subject: rockchip: otp: Refactor to use driver data and ops Refactor the driver to use driver data and ops to simplify handling of SoCs that require a unique read op. Use readl_poll_sleep_timeout instead of a custom poll loop, and add validation of input parameter to main read op. Signed-off-by: Jonas Karlman Reviewed-by: Kever Yang --- drivers/misc/rockchip-otp.c | 85 +++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 41 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/rockchip-otp.c b/drivers/misc/rockchip-otp.c index cc9a5450e0c..80bf9c1aeac 100644 --- a/drivers/misc/rockchip-otp.c +++ b/drivers/misc/rockchip-otp.c @@ -5,10 +5,10 @@ #include #include -#include #include #include #include +#include #include /* OTP Register Offsets */ @@ -49,35 +49,31 @@ struct rockchip_otp_plat { void __iomem *base; - unsigned long secure_conf_base; - unsigned long otp_mask_base; }; -static int rockchip_otp_wait_status(struct rockchip_otp_plat *otp, - u32 flag) +struct rockchip_otp_data { + int (*read)(struct udevice *dev, int offset, void *buf, int size); + int size; +}; + +static int rockchip_otp_poll_timeout(struct rockchip_otp_plat *otp, u32 flag) { - int delay = OTPC_TIMEOUT; - - while (!(readl(otp->base + OTPC_INT_STATUS) & flag)) { - udelay(1); - delay--; - if (delay <= 0) { - printf("%s: wait init status timeout\n", __func__); - return -ETIMEDOUT; - } - } + u32 status; + int ret; + + ret = readl_poll_sleep_timeout(otp->base + OTPC_INT_STATUS, status, + (status & flag), 1, OTPC_TIMEOUT); + if (ret) + return ret; - /* clean int status */ + /* Clear int flag */ writel(flag, otp->base + OTPC_INT_STATUS); return 0; } -static int rockchip_otp_ecc_enable(struct rockchip_otp_plat *otp, - bool enable) +static int rockchip_otp_ecc_enable(struct rockchip_otp_plat *otp, bool enable) { - int ret = 0; - writel(SBPI_DAP_ADDR_MASK | (SBPI_DAP_ADDR << SBPI_DAP_ADDR_SHIFT), otp->base + OTPC_SBPI_CTRL); @@ -92,11 +88,7 @@ static int rockchip_otp_ecc_enable(struct rockchip_otp_plat *otp, writel(SBPI_ENABLE_MASK | SBPI_ENABLE, otp->base + OTPC_SBPI_CTRL); - ret = rockchip_otp_wait_status(otp, OTPC_SBPI_DONE); - if (ret < 0) - printf("%s timeout during ecc_enable\n", __func__); - - return ret; + return rockchip_otp_poll_timeout(otp, OTPC_SBPI_DONE); } static int rockchip_px30_otp_read(struct udevice *dev, int offset, @@ -104,29 +96,26 @@ static int rockchip_px30_otp_read(struct udevice *dev, int offset, { struct rockchip_otp_plat *otp = dev_get_plat(dev); u8 *buffer = buf; - int ret = 0; + int ret; ret = rockchip_otp_ecc_enable(otp, false); - if (ret < 0) { - printf("%s rockchip_otp_ecc_enable err\n", __func__); + if (ret) return ret; - } writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL); udelay(5); + while (size--) { writel(offset++ | OTPC_USER_ADDR_MASK, otp->base + OTPC_USER_ADDR); writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK, otp->base + OTPC_USER_ENABLE); - ret = rockchip_otp_wait_status(otp, OTPC_USER_DONE); - if (ret < 0) { - printf("%s timeout during read setup\n", __func__); + ret = rockchip_otp_poll_timeout(otp, OTPC_USER_DONE); + if (ret) goto read_end; - } - *buffer++ = readb(otp->base + OTPC_USER_Q); + *buffer++ = (u8)(readl(otp->base + OTPC_USER_Q) & 0xFF); } read_end: @@ -138,7 +127,16 @@ read_end: static int rockchip_otp_read(struct udevice *dev, int offset, void *buf, int size) { - return rockchip_px30_otp_read(dev, offset, buf, size); + const struct rockchip_otp_data *data = + (void *)dev_get_driver_data(dev); + + if (offset < 0 || !buf || size <= 0 || offset + size > data->size) + return -EINVAL; + + if (!data->read) + return -ENOSYS; + + return data->read(dev, offset, buf, size); } static const struct misc_ops rockchip_otp_ops = { @@ -147,21 +145,26 @@ static const struct misc_ops rockchip_otp_ops = { static int rockchip_otp_of_to_plat(struct udevice *dev) { - struct rockchip_otp_plat *otp = dev_get_plat(dev); + struct rockchip_otp_plat *plat = dev_get_plat(dev); - otp->base = dev_read_addr_ptr(dev); + plat->base = dev_read_addr_ptr(dev); return 0; } +static const struct rockchip_otp_data px30_data = { + .read = rockchip_px30_otp_read, + .size = 0x40, +}; + static const struct udevice_id rockchip_otp_ids[] = { { .compatible = "rockchip,px30-otp", - .data = (ulong)&rockchip_px30_otp_read, + .data = (ulong)&px30_data, }, { .compatible = "rockchip,rk3308-otp", - .data = (ulong)&rockchip_px30_otp_read, + .data = (ulong)&px30_data, }, {} }; @@ -170,7 +173,7 @@ U_BOOT_DRIVER(rockchip_otp) = { .name = "rockchip_otp", .id = UCLASS_MISC, .of_match = rockchip_otp_ids, - .ops = &rockchip_otp_ops, .of_to_plat = rockchip_otp_of_to_plat, - .plat_auto = sizeof(struct rockchip_otp_plat), + .plat_auto = sizeof(struct rockchip_otp_plat), + .ops = &rockchip_otp_ops, }; -- cgit v1.3.1 From d58d55d242b88711d5ee3561345a8edd0a34e63c Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Wed, 22 Feb 2023 22:44:39 +0000 Subject: rockchip: otp: Add support for RK3568 Add support for rk3568 compatible. Handle allocation of an aligned bounce buffer in main read op in order to keep the SoC unique read op simple. Signed-off-by: Jonas Karlman Reviewed-by: Kever Yang --- drivers/misc/rockchip-otp.c | 67 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/rockchip-otp.c b/drivers/misc/rockchip-otp.c index 80bf9c1aeac..fea3ca7c288 100644 --- a/drivers/misc/rockchip-otp.c +++ b/drivers/misc/rockchip-otp.c @@ -9,6 +9,7 @@ #include #include #include +#include #include /* OTP Register Offsets */ @@ -54,6 +55,7 @@ struct rockchip_otp_plat { struct rockchip_otp_data { int (*read)(struct udevice *dev, int offset, void *buf, int size); int size; + int block_size; }; static int rockchip_otp_poll_timeout(struct rockchip_otp_plat *otp, u32 flag) @@ -124,11 +126,47 @@ read_end: return ret; } +static int rockchip_rk3568_otp_read(struct udevice *dev, int offset, + void *buf, int size) +{ + struct rockchip_otp_plat *otp = dev_get_plat(dev); + u16 *buffer = buf; + int ret; + + ret = rockchip_otp_ecc_enable(otp, false); + if (ret) + return ret; + + writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL); + udelay(5); + + while (size--) { + writel(offset++ | OTPC_USER_ADDR_MASK, + otp->base + OTPC_USER_ADDR); + writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK, + otp->base + OTPC_USER_ENABLE); + + ret = rockchip_otp_poll_timeout(otp, OTPC_USER_DONE); + if (ret) + goto read_end; + + *buffer++ = (u16)(readl(otp->base + OTPC_USER_Q) & 0xFFFF); + } + +read_end: + writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL); + + return ret; +} + static int rockchip_otp_read(struct udevice *dev, int offset, void *buf, int size) { const struct rockchip_otp_data *data = (void *)dev_get_driver_data(dev); + u32 block_start, block_end, block_offset, blocks; + u8 *buffer; + int ret; if (offset < 0 || !buf || size <= 0 || offset + size > data->size) return -EINVAL; @@ -136,7 +174,24 @@ static int rockchip_otp_read(struct udevice *dev, int offset, if (!data->read) return -ENOSYS; - return data->read(dev, offset, buf, size); + if (data->block_size <= 1) + return data->read(dev, offset, buf, size); + + block_start = offset / data->block_size; + block_offset = offset % data->block_size; + block_end = DIV_ROUND_UP(offset + size, data->block_size); + blocks = block_end - block_start; + + buffer = calloc(blocks, data->block_size); + if (!buffer) + return -ENOMEM; + + ret = data->read(dev, block_start, buffer, blocks); + if (!ret) + memcpy(buf, buffer + block_offset, size); + + free(buffer); + return ret; } static const struct misc_ops rockchip_otp_ops = { @@ -157,6 +212,12 @@ static const struct rockchip_otp_data px30_data = { .size = 0x40, }; +static const struct rockchip_otp_data rk3568_data = { + .read = rockchip_rk3568_otp_read, + .size = 0x80, + .block_size = 2, +}; + static const struct udevice_id rockchip_otp_ids[] = { { .compatible = "rockchip,px30-otp", @@ -166,6 +227,10 @@ static const struct udevice_id rockchip_otp_ids[] = { .compatible = "rockchip,rk3308-otp", .data = (ulong)&px30_data, }, + { + .compatible = "rockchip,rk3568-otp", + .data = (ulong)&rk3568_data, + }, {} }; -- cgit v1.3.1 From f888098229174514029c02d76918e27be50d9e1a Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Wed, 22 Feb 2023 22:44:39 +0000 Subject: rockchip: otp: Add support for RK3588 Add support for rk3588 compatible. Adjust offset using driver data in main read op. Signed-off-by: Jonas Karlman Reviewed-by: Kever Yang --- drivers/misc/rockchip-otp.c | 63 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 6 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/rockchip-otp.c b/drivers/misc/rockchip-otp.c index fea3ca7c288..3da99e83179 100644 --- a/drivers/misc/rockchip-otp.c +++ b/drivers/misc/rockchip-otp.c @@ -48,28 +48,41 @@ #define OTPC_TIMEOUT 10000 +#define RK3588_OTPC_AUTO_CTRL 0x0004 +#define RK3588_ADDR_SHIFT 16 +#define RK3588_ADDR(n) ((n) << RK3588_ADDR_SHIFT) +#define RK3588_BURST_SHIFT 8 +#define RK3588_BURST(n) ((n) << RK3588_BURST_SHIFT) +#define RK3588_OTPC_AUTO_EN 0x0008 +#define RK3588_AUTO_EN BIT(0) +#define RK3588_OTPC_DOUT0 0x0020 +#define RK3588_OTPC_INT_ST 0x0084 +#define RK3588_RD_DONE BIT(1) + struct rockchip_otp_plat { void __iomem *base; }; struct rockchip_otp_data { int (*read)(struct udevice *dev, int offset, void *buf, int size); + int offset; int size; int block_size; }; -static int rockchip_otp_poll_timeout(struct rockchip_otp_plat *otp, u32 flag) +static int rockchip_otp_poll_timeout(struct rockchip_otp_plat *otp, + u32 flag, u32 reg) { u32 status; int ret; - ret = readl_poll_sleep_timeout(otp->base + OTPC_INT_STATUS, status, + ret = readl_poll_sleep_timeout(otp->base + reg, status, (status & flag), 1, OTPC_TIMEOUT); if (ret) return ret; /* Clear int flag */ - writel(flag, otp->base + OTPC_INT_STATUS); + writel(flag, otp->base + reg); return 0; } @@ -90,7 +103,7 @@ static int rockchip_otp_ecc_enable(struct rockchip_otp_plat *otp, bool enable) writel(SBPI_ENABLE_MASK | SBPI_ENABLE, otp->base + OTPC_SBPI_CTRL); - return rockchip_otp_poll_timeout(otp, OTPC_SBPI_DONE); + return rockchip_otp_poll_timeout(otp, OTPC_SBPI_DONE, OTPC_INT_STATUS); } static int rockchip_px30_otp_read(struct udevice *dev, int offset, @@ -113,7 +126,8 @@ static int rockchip_px30_otp_read(struct udevice *dev, int offset, writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK, otp->base + OTPC_USER_ENABLE); - ret = rockchip_otp_poll_timeout(otp, OTPC_USER_DONE); + ret = rockchip_otp_poll_timeout(otp, OTPC_USER_DONE, + OTPC_INT_STATUS); if (ret) goto read_end; @@ -146,7 +160,8 @@ static int rockchip_rk3568_otp_read(struct udevice *dev, int offset, writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK, otp->base + OTPC_USER_ENABLE); - ret = rockchip_otp_poll_timeout(otp, OTPC_USER_DONE); + ret = rockchip_otp_poll_timeout(otp, OTPC_USER_DONE, + OTPC_INT_STATUS); if (ret) goto read_end; @@ -159,6 +174,29 @@ read_end: return ret; } +static int rockchip_rk3588_otp_read(struct udevice *dev, int offset, + void *buf, int size) +{ + struct rockchip_otp_plat *otp = dev_get_plat(dev); + u32 *buffer = buf; + int ret; + + while (size--) { + writel(RK3588_ADDR(offset++) | RK3588_BURST(1), + otp->base + RK3588_OTPC_AUTO_CTRL); + writel(RK3588_AUTO_EN, otp->base + RK3588_OTPC_AUTO_EN); + + ret = rockchip_otp_poll_timeout(otp, RK3588_RD_DONE, + RK3588_OTPC_INT_ST); + if (ret) + return ret; + + *buffer++ = readl(otp->base + RK3588_OTPC_DOUT0); + } + + return 0; +} + static int rockchip_otp_read(struct udevice *dev, int offset, void *buf, int size) { @@ -174,6 +212,8 @@ static int rockchip_otp_read(struct udevice *dev, int offset, if (!data->read) return -ENOSYS; + offset += data->offset; + if (data->block_size <= 1) return data->read(dev, offset, buf, size); @@ -218,6 +258,13 @@ static const struct rockchip_otp_data rk3568_data = { .block_size = 2, }; +static const struct rockchip_otp_data rk3588_data = { + .read = rockchip_rk3588_otp_read, + .offset = 0xC00, + .size = 0x400, + .block_size = 4, +}; + static const struct udevice_id rockchip_otp_ids[] = { { .compatible = "rockchip,px30-otp", @@ -231,6 +278,10 @@ static const struct udevice_id rockchip_otp_ids[] = { .compatible = "rockchip,rk3568-otp", .data = (ulong)&rk3568_data, }, + { + .compatible = "rockchip,rk3588-otp", + .data = (ulong)&rk3588_data, + }, {} }; -- cgit v1.3.1 From 9a850d1fcd2bd2def1adceef58b48d9a9cf3e309 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Wed, 22 Feb 2023 22:44:39 +0000 Subject: rockchip: otp: Add dump_otp debug command Add a simple debug command to dump the content of the otp. Signed-off-by: Jonas Karlman Reviewed-by: Kever Yang --- drivers/misc/rockchip-otp.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/rockchip-otp.c b/drivers/misc/rockchip-otp.c index 3da99e83179..c19cd5ce625 100644 --- a/drivers/misc/rockchip-otp.c +++ b/drivers/misc/rockchip-otp.c @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include #include @@ -70,6 +72,39 @@ struct rockchip_otp_data { int block_size; }; +#if defined(DEBUG) +static int dump_otp(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + struct udevice *dev; + u8 data[4]; + int ret, i; + + ret = uclass_get_device_by_driver(UCLASS_MISC, + DM_DRIVER_GET(rockchip_otp), &dev); + if (ret) { + printf("%s: no misc-device found\n", __func__); + return 0; + } + + for (i = 0; true; i += sizeof(data)) { + ret = misc_read(dev, i, &data, sizeof(data)); + if (ret < 0) + return 0; + + print_buffer(i, data, 1, sizeof(data), sizeof(data)); + } + + return 0; +} + +U_BOOT_CMD( + dump_otp, 1, 1, dump_otp, + "Dump the content of the otp", + "" +); +#endif + static int rockchip_otp_poll_timeout(struct rockchip_otp_plat *otp, u32 flag, u32 reg) { -- cgit v1.3.1 From 433260ac1a69b5f3467e97328978a707fb2d6e3a Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Wed, 22 Feb 2023 22:44:39 +0000 Subject: rockchip: efuse: Refactor to use driver data and ops Refactor the driver to use driver data and ops to simplify handling of SoCs that require a unique read op. Move handling of the aligned bounce buffer to main read op in order to keep the SoC unique read op simple. Signed-off-by: Jonas Karlman Reviewed-by: Kever Yang --- drivers/misc/rockchip-efuse.c | 160 ++++++++++++++++++++++-------------------- 1 file changed, 85 insertions(+), 75 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/rockchip-efuse.c b/drivers/misc/rockchip-efuse.c index 083ee65e0ad..7d4a984dce3 100644 --- a/drivers/misc/rockchip-efuse.c +++ b/drivers/misc/rockchip-efuse.c @@ -13,50 +13,40 @@ #include #include #include +#include #include -#define RK3399_A_SHIFT 16 -#define RK3399_A_MASK 0x3ff -#define RK3399_NFUSES 32 -#define RK3399_BYTES_PER_FUSE 4 -#define RK3399_STROBSFTSEL BIT(9) -#define RK3399_RSB BIT(7) -#define RK3399_PD BIT(5) -#define RK3399_PGENB BIT(3) -#define RK3399_LOAD BIT(2) -#define RK3399_STROBE BIT(1) -#define RK3399_CSB BIT(0) - -struct rockchip_efuse_regs { - u32 ctrl; /* 0x00 efuse control register */ - u32 dout; /* 0x04 efuse data out register */ - u32 rf; /* 0x08 efuse redundancy bit used register */ - u32 _rsvd0; - u32 jtag_pass; /* 0x10 JTAG password */ - u32 strobe_finish_ctrl; - /* 0x14 efuse strobe finish control register */ -}; +#define EFUSE_CTRL 0x0000 +#define RK3399_A_SHIFT 16 +#define RK3399_A_MASK GENMASK(25, 16) +#define RK3399_ADDR(n) ((n) << RK3399_A_SHIFT) +#define RK3399_STROBSFTSEL BIT(9) +#define RK3399_RSB BIT(7) +#define RK3399_PD BIT(5) +#define RK3399_PGENB BIT(3) +#define RK3399_LOAD BIT(2) +#define RK3399_STROBE BIT(1) +#define RK3399_CSB BIT(0) +#define EFUSE_DOUT 0x0004 struct rockchip_efuse_plat { void __iomem *base; - struct clk *clk; +}; + +struct rockchip_efuse_data { + int (*read)(struct udevice *dev, int offset, void *buf, int size); + int size; + int block_size; }; #if defined(DEBUG) -static int dump_efuses(struct cmd_tbl *cmdtp, int flag, - int argc, char *const argv[]) +static int dump_efuse(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) { - /* - * N.B.: This function is tailored towards the RK3399 and assumes that - * there's always 32 fuses x 32 bits (i.e. 128 bytes of data) to - * be read. - */ - struct udevice *dev; - u8 fuses[128]; - int ret; + u8 data[4]; + int ret, i; - /* retrieve the device */ ret = uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(rockchip_efuse), &dev); if (ret) { @@ -64,21 +54,20 @@ static int dump_efuses(struct cmd_tbl *cmdtp, int flag, return 0; } - ret = misc_read(dev, 0, &fuses, sizeof(fuses)); - if (ret < 0) { - printf("%s: misc_read failed\n", __func__); - return 0; - } + for (i = 0; true; i += sizeof(data)) { + ret = misc_read(dev, i, &data, sizeof(data)); + if (ret < 0) + return 0; - printf("efuse-contents:\n"); - print_buffer(0, fuses, 1, 128, 16); + print_buffer(i, data, 1, sizeof(data), sizeof(data)); + } return 0; } U_BOOT_CMD( - rk3399_dump_efuses, 1, 1, dump_efuses, - "Dump the content of the efuses", + dump_efuse, 1, 1, dump_efuse, + "Dump the content of the efuse", "" ); #endif @@ -86,43 +75,25 @@ U_BOOT_CMD( static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset, void *buf, int size) { - struct rockchip_efuse_plat *plat = dev_get_plat(dev); - struct rockchip_efuse_regs *efuse = - (struct rockchip_efuse_regs *)plat->base; - - unsigned int addr_start, addr_end, addr_offset; - u32 out_value; - u8 bytes[RK3399_NFUSES * RK3399_BYTES_PER_FUSE]; - int i = 0; - u32 addr; - - addr_start = offset / RK3399_BYTES_PER_FUSE; - addr_offset = offset % RK3399_BYTES_PER_FUSE; - addr_end = DIV_ROUND_UP(offset + size, RK3399_BYTES_PER_FUSE); - - /* cap to the size of the efuse block */ - if (addr_end > RK3399_NFUSES) - addr_end = RK3399_NFUSES; + struct rockchip_efuse_plat *efuse = dev_get_plat(dev); + u32 *buffer = buf; + /* Switch to array read mode */ writel(RK3399_LOAD | RK3399_PGENB | RK3399_STROBSFTSEL | RK3399_RSB, - &efuse->ctrl); + efuse->base + EFUSE_CTRL); udelay(1); - for (addr = addr_start; addr < addr_end; addr++) { - setbits_le32(&efuse->ctrl, - RK3399_STROBE | (addr << RK3399_A_SHIFT)); + + while (size--) { + setbits_le32(efuse->base + EFUSE_CTRL, + RK3399_STROBE | RK3399_ADDR(offset++)); udelay(1); - out_value = readl(&efuse->dout); - clrbits_le32(&efuse->ctrl, RK3399_STROBE); + *buffer++ = readl(efuse->base + EFUSE_DOUT); + clrbits_le32(efuse->base + EFUSE_CTRL, RK3399_STROBE); udelay(1); - - memcpy(&bytes[i], &out_value, RK3399_BYTES_PER_FUSE); - i += RK3399_BYTES_PER_FUSE; } - /* Switch to standby mode */ - writel(RK3399_PD | RK3399_CSB, &efuse->ctrl); - - memcpy(buf, bytes + addr_offset, size); + /* Switch to power-down mode */ + writel(RK3399_PD | RK3399_CSB, efuse->base + EFUSE_CTRL); return 0; } @@ -130,7 +101,36 @@ static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset, static int rockchip_efuse_read(struct udevice *dev, int offset, void *buf, int size) { - return rockchip_rk3399_efuse_read(dev, offset, buf, size); + const struct rockchip_efuse_data *data = + (void *)dev_get_driver_data(dev); + u32 block_start, block_end, block_offset, blocks; + u8 *buffer; + int ret; + + if (offset < 0 || !buf || size <= 0 || offset + size > data->size) + return -EINVAL; + + if (!data->read) + return -ENOSYS; + + if (data->block_size <= 1) + return data->read(dev, offset, buf, size); + + block_start = offset / data->block_size; + block_offset = offset % data->block_size; + block_end = DIV_ROUND_UP(offset + size, data->block_size); + blocks = block_end - block_start; + + buffer = calloc(blocks, data->block_size); + if (!buffer) + return -ENOMEM; + + ret = data->read(dev, block_start, buffer, blocks); + if (!ret) + memcpy(buf, buffer + block_offset, size); + + free(buffer); + return ret; } static const struct misc_ops rockchip_efuse_ops = { @@ -142,11 +142,21 @@ static int rockchip_efuse_of_to_plat(struct udevice *dev) struct rockchip_efuse_plat *plat = dev_get_plat(dev); plat->base = dev_read_addr_ptr(dev); + return 0; } +static const struct rockchip_efuse_data rk3399_data = { + .read = rockchip_rk3399_efuse_read, + .size = 0x80, + .block_size = 4, +}; + static const struct udevice_id rockchip_efuse_ids[] = { - { .compatible = "rockchip,rk3399-efuse" }, + { + .compatible = "rockchip,rk3399-efuse", + .data = (ulong)&rk3399_data, + }, {} }; @@ -155,6 +165,6 @@ U_BOOT_DRIVER(rockchip_efuse) = { .id = UCLASS_MISC, .of_match = rockchip_efuse_ids, .of_to_plat = rockchip_efuse_of_to_plat, - .plat_auto = sizeof(struct rockchip_efuse_plat), + .plat_auto = sizeof(struct rockchip_efuse_plat), .ops = &rockchip_efuse_ops, }; -- cgit v1.3.1 From 6f95b3e1034fb491a04479d792d35130ba41d887 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Wed, 22 Feb 2023 22:44:40 +0000 Subject: rockchip: efuse: Add support for RK3288 and more Add support for rk3066a, rk3188, rk322x and rk3288 compatible. Signed-off-by: Jonas Karlman Reviewed-by: Kever Yang --- drivers/misc/Kconfig | 4 --- drivers/misc/rockchip-efuse.c | 68 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 60 insertions(+), 12 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index b07261d3db5..b5707a15c50 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -92,10 +92,6 @@ config ROCKCHIP_EFUSE or through child-nodes that are generated based on the e-fuse map retrieved from the DTS. - This driver currently supports the RK3399 only, but can easily be - extended (by porting the read function from the Linux kernel sources) - to support other recent Rockchip devices. - config ROCKCHIP_OTP bool "Rockchip OTP Support" depends on MISC diff --git a/drivers/misc/rockchip-efuse.c b/drivers/misc/rockchip-efuse.c index 7d4a984dce3..99220d5b1ea 100644 --- a/drivers/misc/rockchip-efuse.c +++ b/drivers/misc/rockchip-efuse.c @@ -17,16 +17,19 @@ #include #define EFUSE_CTRL 0x0000 +#define RK3288_A_SHIFT 6 +#define RK3288_A_MASK GENMASK(15, 6) +#define RK3288_ADDR(n) ((n) << RK3288_A_SHIFT) #define RK3399_A_SHIFT 16 #define RK3399_A_MASK GENMASK(25, 16) #define RK3399_ADDR(n) ((n) << RK3399_A_SHIFT) #define RK3399_STROBSFTSEL BIT(9) #define RK3399_RSB BIT(7) #define RK3399_PD BIT(5) -#define RK3399_PGENB BIT(3) -#define RK3399_LOAD BIT(2) -#define RK3399_STROBE BIT(1) -#define RK3399_CSB BIT(0) +#define EFUSE_PGENB BIT(3) +#define EFUSE_LOAD BIT(2) +#define EFUSE_STROBE BIT(1) +#define EFUSE_CSB BIT(0) #define EFUSE_DOUT 0x0004 struct rockchip_efuse_plat { @@ -72,6 +75,34 @@ U_BOOT_CMD( ); #endif +static int rockchip_rk3288_efuse_read(struct udevice *dev, int offset, + void *buf, int size) +{ + struct rockchip_efuse_plat *efuse = dev_get_plat(dev); + u8 *buffer = buf; + + /* Switch to read mode */ + writel(EFUSE_CSB, efuse->base + EFUSE_CTRL); + writel(EFUSE_LOAD | EFUSE_PGENB, efuse->base + EFUSE_CTRL); + udelay(2); + + while (size--) { + clrsetbits_le32(efuse->base + EFUSE_CTRL, RK3288_A_MASK, + RK3288_ADDR(offset++)); + udelay(2); + setbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE); + udelay(2); + *buffer++ = (u8)(readl(efuse->base + EFUSE_DOUT) & 0xFF); + clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE); + udelay(2); + } + + /* Switch to standby mode */ + writel(EFUSE_CSB | EFUSE_PGENB, efuse->base + EFUSE_CTRL); + + return 0; +} + static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset, void *buf, int size) { @@ -79,21 +110,21 @@ static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset, u32 *buffer = buf; /* Switch to array read mode */ - writel(RK3399_LOAD | RK3399_PGENB | RK3399_STROBSFTSEL | RK3399_RSB, + writel(EFUSE_LOAD | EFUSE_PGENB | RK3399_STROBSFTSEL | RK3399_RSB, efuse->base + EFUSE_CTRL); udelay(1); while (size--) { setbits_le32(efuse->base + EFUSE_CTRL, - RK3399_STROBE | RK3399_ADDR(offset++)); + EFUSE_STROBE | RK3399_ADDR(offset++)); udelay(1); *buffer++ = readl(efuse->base + EFUSE_DOUT); - clrbits_le32(efuse->base + EFUSE_CTRL, RK3399_STROBE); + clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE); udelay(1); } /* Switch to power-down mode */ - writel(RK3399_PD | RK3399_CSB, efuse->base + EFUSE_CTRL); + writel(RK3399_PD | EFUSE_CSB, efuse->base + EFUSE_CTRL); return 0; } @@ -146,6 +177,11 @@ static int rockchip_efuse_of_to_plat(struct udevice *dev) return 0; } +static const struct rockchip_efuse_data rk3288_data = { + .read = rockchip_rk3288_efuse_read, + .size = 0x20, +}; + static const struct rockchip_efuse_data rk3399_data = { .read = rockchip_rk3399_efuse_read, .size = 0x80, @@ -153,6 +189,22 @@ static const struct rockchip_efuse_data rk3399_data = { }; static const struct udevice_id rockchip_efuse_ids[] = { + { + .compatible = "rockchip,rk3066a-efuse", + .data = (ulong)&rk3288_data, + }, + { + .compatible = "rockchip,rk3188-efuse", + .data = (ulong)&rk3288_data, + }, + { + .compatible = "rockchip,rk3228-efuse", + .data = (ulong)&rk3288_data, + }, + { + .compatible = "rockchip,rk3288-efuse", + .data = (ulong)&rk3288_data, + }, { .compatible = "rockchip,rk3399-efuse", .data = (ulong)&rk3399_data, -- cgit v1.3.1 From b0828cf98901c993f7a88ef8f5b7f97a1c0c5d51 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Wed, 22 Feb 2023 22:44:40 +0000 Subject: rockchip: efuse: Add support for RK3328 Add support for rk3328 compatible. Signed-off-by: Jonas Karlman Reviewed-by: Kever Yang --- drivers/misc/rockchip-efuse.c | 45 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/rockchip-efuse.c b/drivers/misc/rockchip-efuse.c index 99220d5b1ea..8cf61e36aef 100644 --- a/drivers/misc/rockchip-efuse.c +++ b/drivers/misc/rockchip-efuse.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,12 @@ #define EFUSE_STROBE BIT(1) #define EFUSE_CSB BIT(0) #define EFUSE_DOUT 0x0004 +#define RK3328_INT_STATUS 0x0018 +#define RK3328_INT_FINISH BIT(0) +#define RK3328_DOUT 0x0020 +#define RK3328_AUTO_CTRL 0x0024 +#define RK3328_AUTO_RD BIT(1) +#define RK3328_AUTO_ENB BIT(0) struct rockchip_efuse_plat { void __iomem *base; @@ -38,6 +45,7 @@ struct rockchip_efuse_plat { struct rockchip_efuse_data { int (*read)(struct udevice *dev, int offset, void *buf, int size); + int offset; int size; int block_size; }; @@ -103,6 +111,30 @@ static int rockchip_rk3288_efuse_read(struct udevice *dev, int offset, return 0; } +static int rockchip_rk3328_efuse_read(struct udevice *dev, int offset, + void *buf, int size) +{ + struct rockchip_efuse_plat *efuse = dev_get_plat(dev); + u32 status, *buffer = buf; + int ret; + + while (size--) { + writel(RK3328_AUTO_RD | RK3328_AUTO_ENB | RK3399_ADDR(offset++), + efuse->base + RK3328_AUTO_CTRL); + udelay(1); + + ret = readl_poll_sleep_timeout(efuse->base + RK3328_INT_STATUS, + status, (status & RK3328_INT_FINISH), 1, 50); + if (ret) + return ret; + + *buffer++ = readl(efuse->base + RK3328_DOUT); + writel(RK3328_INT_FINISH, efuse->base + RK3328_INT_STATUS); + } + + return 0; +} + static int rockchip_rk3399_efuse_read(struct udevice *dev, int offset, void *buf, int size) { @@ -144,6 +176,8 @@ static int rockchip_efuse_read(struct udevice *dev, int offset, if (!data->read) return -ENOSYS; + offset += data->offset; + if (data->block_size <= 1) return data->read(dev, offset, buf, size); @@ -182,6 +216,13 @@ static const struct rockchip_efuse_data rk3288_data = { .size = 0x20, }; +static const struct rockchip_efuse_data rk3328_data = { + .read = rockchip_rk3328_efuse_read, + .offset = 0x60, + .size = 0x20, + .block_size = 4, +}; + static const struct rockchip_efuse_data rk3399_data = { .read = rockchip_rk3399_efuse_read, .size = 0x80, @@ -205,6 +246,10 @@ static const struct udevice_id rockchip_efuse_ids[] = { .compatible = "rockchip,rk3288-efuse", .data = (ulong)&rk3288_data, }, + { + .compatible = "rockchip,rk3328-efuse", + .data = (ulong)&rk3328_data, + }, { .compatible = "rockchip,rk3399-efuse", .data = (ulong)&rk3399_data, -- cgit v1.3.1 From 16e8afa802ebc3869c99d57186720476f3affd6b Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Wed, 22 Feb 2023 22:44:40 +0000 Subject: rockchip: efuse: Add support for RK3128 Add support for rk3128 compatible. Signed-off-by: Jonas Karlman Reviewed-by: Kever Yang --- drivers/misc/rockchip-efuse.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/rockchip-efuse.c b/drivers/misc/rockchip-efuse.c index 8cf61e36aef..bc73fd3baa1 100644 --- a/drivers/misc/rockchip-efuse.c +++ b/drivers/misc/rockchip-efuse.c @@ -18,6 +18,9 @@ #include #define EFUSE_CTRL 0x0000 +#define RK3128_A_SHIFT 7 +#define RK3128_A_MASK GENMASK(15, 7) +#define RK3128_ADDR(n) ((n) << RK3128_A_SHIFT) #define RK3288_A_SHIFT 6 #define RK3288_A_MASK GENMASK(15, 6) #define RK3288_ADDR(n) ((n) << RK3288_A_SHIFT) @@ -83,6 +86,33 @@ U_BOOT_CMD( ); #endif +static int rockchip_rk3128_efuse_read(struct udevice *dev, int offset, + void *buf, int size) +{ + struct rockchip_efuse_plat *efuse = dev_get_plat(dev); + u8 *buffer = buf; + + /* Switch to read mode */ + writel(EFUSE_LOAD, efuse->base + EFUSE_CTRL); + udelay(2); + + while (size--) { + clrsetbits_le32(efuse->base + EFUSE_CTRL, RK3128_A_MASK, + RK3128_ADDR(offset++)); + udelay(2); + setbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE); + udelay(2); + *buffer++ = (u8)(readl(efuse->base + EFUSE_DOUT) & 0xFF); + clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE); + udelay(2); + } + + /* Switch to inactive mode */ + writel(0x0, efuse->base + EFUSE_CTRL); + + return 0; +} + static int rockchip_rk3288_efuse_read(struct udevice *dev, int offset, void *buf, int size) { @@ -211,6 +241,11 @@ static int rockchip_efuse_of_to_plat(struct udevice *dev) return 0; } +static const struct rockchip_efuse_data rk3128_data = { + .read = rockchip_rk3128_efuse_read, + .size = 0x40, +}; + static const struct rockchip_efuse_data rk3288_data = { .read = rockchip_rk3288_efuse_read, .size = 0x20, @@ -234,6 +269,10 @@ static const struct udevice_id rockchip_efuse_ids[] = { .compatible = "rockchip,rk3066a-efuse", .data = (ulong)&rk3288_data, }, + { + .compatible = "rockchip,rk3128-efuse", + .data = (ulong)&rk3128_data, + }, { .compatible = "rockchip,rk3188-efuse", .data = (ulong)&rk3288_data, -- cgit v1.3.1 From dd5684b87850ad535ec4fd6532cf675d07b73983 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Wed, 22 Feb 2023 22:44:40 +0000 Subject: rockchip: efuse: Add support for RK3036 Add support for rk3036 compatible. Signed-off-by: Jonas Karlman Reviewed-by: Kever Yang --- drivers/misc/rockchip-efuse.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/rockchip-efuse.c b/drivers/misc/rockchip-efuse.c index bc73fd3baa1..60931a51312 100644 --- a/drivers/misc/rockchip-efuse.c +++ b/drivers/misc/rockchip-efuse.c @@ -18,6 +18,9 @@ #include #define EFUSE_CTRL 0x0000 +#define RK3036_A_SHIFT 8 +#define RK3036_A_MASK GENMASK(15, 8) +#define RK3036_ADDR(n) ((n) << RK3036_A_SHIFT) #define RK3128_A_SHIFT 7 #define RK3128_A_MASK GENMASK(15, 7) #define RK3128_ADDR(n) ((n) << RK3128_A_SHIFT) @@ -86,6 +89,33 @@ U_BOOT_CMD( ); #endif +static int rockchip_rk3036_efuse_read(struct udevice *dev, int offset, + void *buf, int size) +{ + struct rockchip_efuse_plat *efuse = dev_get_plat(dev); + u8 *buffer = buf; + + /* Switch to read mode */ + writel(EFUSE_LOAD, efuse->base + EFUSE_CTRL); + udelay(2); + + while (size--) { + clrsetbits_le32(efuse->base + EFUSE_CTRL, RK3036_A_MASK, + RK3036_ADDR(offset++)); + udelay(2); + setbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE); + udelay(2); + *buffer++ = (u8)(readl(efuse->base + EFUSE_DOUT) & 0xFF); + clrbits_le32(efuse->base + EFUSE_CTRL, EFUSE_STROBE); + udelay(2); + } + + /* Switch to inactive mode */ + writel(0x0, efuse->base + EFUSE_CTRL); + + return 0; +} + static int rockchip_rk3128_efuse_read(struct udevice *dev, int offset, void *buf, int size) { @@ -241,6 +271,11 @@ static int rockchip_efuse_of_to_plat(struct udevice *dev) return 0; } +static const struct rockchip_efuse_data rk3036_data = { + .read = rockchip_rk3036_efuse_read, + .size = 0x20, +}; + static const struct rockchip_efuse_data rk3128_data = { .read = rockchip_rk3128_efuse_read, .size = 0x40, @@ -265,6 +300,10 @@ static const struct rockchip_efuse_data rk3399_data = { }; static const struct udevice_id rockchip_efuse_ids[] = { + { + .compatible = "rockchip,rk3036-efuse", + .data = (ulong)&rk3036_data, + }, { .compatible = "rockchip,rk3066a-efuse", .data = (ulong)&rk3288_data, -- cgit v1.3.1