summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Karlman <jonas@kwiboo.se>2023-02-22 22:44:39 +0000
committerKever Yang <kever.yang@rock-chips.com>2023-02-28 18:07:28 +0800
commitd58d55d242b88711d5ee3561345a8edd0a34e63c (patch)
tree684498e15811548dbc07fd5f8798a77b6d1fcc35
parent8fa1870e11ebf049af74be94bfaad17006eb18da (diff)
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 <jonas@kwiboo.se> Reviewed-by: Kever Yang <kever.yang@rock-chips.com>
-rw-r--r--drivers/misc/rockchip-otp.c67
1 files changed, 66 insertions, 1 deletions
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 <linux/bitops.h>
#include <linux/delay.h>
#include <linux/iopoll.h>
+#include <malloc.h>
#include <misc.h>
/* 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,
+ },
{}
};