summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Kurbanov <mmkurbanov@salutedevices.com>2025-04-17 16:07:46 +0300
committerDmitry Rokosov <rockosov@rulkc.org>2026-08-13 14:41:33 +0300
commit2b98829558ed51b1d0a92dda01e3f799c8ad1b5d (patch)
tree4c10068dacd76f7367ee8b15a1df5255776e3bea
parent375c8c40130aca15bae25c3c4be281c1faee769c (diff)
downloadlinux-2b98829558ed51b1d0a92dda01e3f799c8ad1b5d.tar.gz
linux-2b98829558ed51b1d0a92dda01e3f799c8ad1b5d.zip
mtd: spinand: esmt: introduce read/write OTP ops
In the generic code, ECC is disabled for OTP read/write operations. To enable ECC in OTP for the ESMT driver, custom OTP read/write callbacks must be implemented. This patch provides these callbacks. This is adaptation of the spinand_otp_rw() function. Signed-off-by: Martin Kurbanov <mmkurbanov@salutedevices.com> Signed-off-by: Dmitry Rokosov <rockosov@rulkc.org>
-rw-r--r--drivers/mtd/nand/spi/esmt.c70
1 files changed, 68 insertions, 2 deletions
diff --git a/drivers/mtd/nand/spi/esmt.c b/drivers/mtd/nand/spi/esmt.c
index 8607c2fdedcf..6f2e54b5862d 100644
--- a/drivers/mtd/nand/spi/esmt.c
+++ b/drivers/mtd/nand/spi/esmt.c
@@ -18,6 +18,8 @@
#define ESMT_F50L1G41LB_CFG_OTP_LOCK \
(CFG_OTP_ENABLE | ESMT_F50L1G41LB_CFG_OTP_PROTECT)
+#define ESMT_F50L1G41LB_USER_OTP_START_PAGE 2
+
static SPINAND_OP_VARIANTS(read_cache_variants,
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
@@ -173,11 +175,75 @@ out:
return ret;
}
+static int f50l1g41lb_otp_rw(struct spinand_device *spinand, loff_t ofs,
+ size_t len, size_t *retlen, u8 *buf, bool is_write)
+{
+ struct nand_device *nand = spinand_to_nand(spinand);
+ struct nand_page_io_req req = {};
+ unsigned long long page;
+ size_t copied = 0;
+ size_t otp_pagesize = spinand_otp_page_size(spinand);
+ size_t pagesize = nanddev_page_size(nand);
+ int ret;
+
+ ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, CFG_OTP_ENABLE);
+ if (ret)
+ return ret;
+
+ page = ofs;
+ req.dataoffs = do_div(page, otp_pagesize);
+ req.pos.page = page + ESMT_F50L1G41LB_USER_OTP_START_PAGE;
+ req.type = is_write ? NAND_PAGE_WRITE : NAND_PAGE_READ;
+ req.mode = MTD_OPS_RAW;
+ req.databuf.in = buf;
+
+ while (copied < len) {
+ req.datalen = min_t(unsigned int,
+ otp_pagesize - req.dataoffs,
+ len - copied);
+
+ if (is_write)
+ ret = spinand_write_page(spinand, &req);
+ else
+ ret = spinand_read_page(spinand, &req);
+
+ if (ret < 0)
+ break;
+
+ req.databuf.in += req.datalen;
+ req.pos.page++;
+ req.dataoffs = 0;
+ copied += req.datalen;
+ }
+
+ *retlen = copied;
+
+ if (spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0)) {
+ dev_warn(&spinand_to_mtd(spinand)->dev,
+ "Can not disable OTP mode\n");
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static int f50l1g41lb_user_otp_read(struct spinand_device *spinand, loff_t ofs,
+ size_t len, size_t *retlen, u8 *buf)
+{
+ return f50l1g41lb_otp_rw(spinand, ofs, len, retlen, buf, false);
+}
+
+static int f50l1g41lb_user_otp_write(struct spinand_device *spinand, loff_t ofs,
+ size_t len, size_t *retlen, const u8 *buf)
+{
+ return f50l1g41lb_otp_rw(spinand, ofs, len, retlen, (u8 *)buf, true);
+}
+
static const struct spinand_user_otp_ops f50l1g41lb_user_otp_ops = {
.info = f50l1g41lb_user_otp_info,
.lock = f50l1g41lb_otp_lock,
- .read = spinand_user_otp_read,
- .write = spinand_user_otp_write,
+ .read = f50l1g41lb_user_otp_read,
+ .write = f50l1g41lb_user_otp_write,
};
static const struct spinand_fact_otp_ops f50l1g41lb_fact_otp_ops = {