diff options
| author | Martin Kurbanov <mmkurbanov@salutedevices.com> | 2025-04-17 16:07:46 +0300 |
|---|---|---|
| committer | Dmitry Rokosov <rockosov@rulkc.org> | 2026-08-13 14:41:33 +0300 |
| commit | 2b98829558ed51b1d0a92dda01e3f799c8ad1b5d (patch) | |
| tree | 4c10068dacd76f7367ee8b15a1df5255776e3bea | |
| parent | 375c8c40130aca15bae25c3c4be281c1faee769c (diff) | |
| download | linux-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.c | 70 |
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 = { |
