]> www.infradead.org Git - linux-platform-drivers-x86.git/commitdiff
mtd: add OTP (one-time-programmable) erase ioctl
authorMichael Walle <michael@walle.cc>
Wed, 3 Mar 2021 20:18:19 +0000 (21:18 +0100)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Sun, 28 Mar 2021 17:24:54 +0000 (19:24 +0200)
This may sound like a contradiction but some SPI-NOR flashes really
support erasing their OTP region until it is finally locked. Having the
possibility to erase an OTP region might come in handy during
development.

The ioctl argument follows the OTPLOCK style.

Signed-off-by: Michael Walle <michael@walle.cc>
Acked-by: Vignesh Raghavendra <vigneshr@ti.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20210303201819.2752-1-michael@walle.cc
drivers/mtd/mtdchar.c
drivers/mtd/mtdcore.c
include/linux/mtd/mtd.h
include/uapi/mtd/mtd-abi.h

index 870f7a19ad9d30ddac53493e81ccb66d924359da..155e991d9d7533b1232d2a4c088b7ff3bc4f9cc7 100644 (file)
@@ -666,6 +666,7 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
        case MEMWRITEOOB64:
        case MEMWRITE:
        case OTPLOCK:
+       case OTPERASE:
                if (!(file->f_mode & FMODE_WRITE))
                        return -EPERM;
                break;
@@ -930,6 +931,7 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
        }
 
        case OTPLOCK:
+       case OTPERASE:
        {
                struct otp_info oinfo;
 
@@ -937,7 +939,10 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
                        return -EINVAL;
                if (copy_from_user(&oinfo, argp, sizeof(oinfo)))
                        return -EFAULT;
-               ret = mtd_lock_user_prot_reg(mtd, oinfo.start, oinfo.length);
+               if (cmd == OTPLOCK)
+                       ret = mtd_lock_user_prot_reg(mtd, oinfo.start, oinfo.length);
+               else
+                       ret = mtd_erase_user_prot_reg(mtd, oinfo.start, oinfo.length);
                break;
        }
 
index 38782ceea1f689168e87eec031ee4f36d00f987a..aea58366a94ee8ce968f3b55b9692a3fabd79866 100644 (file)
@@ -1919,6 +1919,18 @@ int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len)
 }
 EXPORT_SYMBOL_GPL(mtd_lock_user_prot_reg);
 
+int mtd_erase_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len)
+{
+       struct mtd_info *master = mtd_get_master(mtd);
+
+       if (!master->_erase_user_prot_reg)
+               return -EOPNOTSUPP;
+       if (!len)
+               return 0;
+       return master->_erase_user_prot_reg(master, from, len);
+}
+EXPORT_SYMBOL_GPL(mtd_erase_user_prot_reg);
+
 /* Chip-supported device locking */
 int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
 {
index ceabc2cae8a4de09abb04acdfb79ef8fdc302bb2..4aac200ca8b5d7a47cf150033469a0865325600d 100644 (file)
@@ -337,6 +337,8 @@ struct mtd_info {
                                     size_t len, size_t *retlen, u_char *buf);
        int (*_lock_user_prot_reg) (struct mtd_info *mtd, loff_t from,
                                    size_t len);
+       int (*_erase_user_prot_reg) (struct mtd_info *mtd, loff_t from,
+                                    size_t len);
        int (*_writev) (struct mtd_info *mtd, const struct kvec *vecs,
                        unsigned long count, loff_t to, size_t *retlen);
        void (*_sync) (struct mtd_info *mtd);
@@ -518,6 +520,7 @@ int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
 int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len,
                            size_t *retlen, u_char *buf);
 int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len);
+int mtd_erase_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len);
 
 int mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
               unsigned long count, loff_t to, size_t *retlen);
index 65b9db9365577b278424a4ec48f78dd96ce35367..b869990c2db20d12e24b820b839c97e5b5222518 100644 (file)
@@ -205,6 +205,8 @@ struct otp_info {
  * without OOB, e.g., NOR flash.
  */
 #define MEMWRITE               _IOWR('M', 24, struct mtd_write_req)
+/* Erase a given range of user data (must be in mode %MTD_FILE_MODE_OTP_USER) */
+#define OTPERASE               _IOW('M', 25, struct otp_info)
 
 /*
  * Obsolete legacy interface. Keep it in order not to break userspace