[PATCH 2/4] mtd: spi-nor: add advanced protection and security features support

shiva.linuxworks
2021-10-27T10:35:16Z

From: Shivamurthy Shastri <sshivamurthy@micron.com>

Added functionalities to support advanced securtiy and protection
features in new SPI NOR flashes.

Signed-off-by: Shivamurthy Shastri <sshivamurthy@micron.com>
---
drivers/mtd/spi-nor/Makefile | 2 +-
drivers/mtd/spi-nor/advprotsec.c | 209 +++++++++++++++++++++++++++++++
drivers/mtd/spi-nor/core.c | 2 +
include/linux/mtd/mtd.h | 19 +++
4 files changed, 231 insertions(+), 1 deletion(-)
create mode 100644 drivers/mtd/spi-nor/advprotsec.c

diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
index 6b904e439372..8e96e2c65c7a 100644
--- a/drivers/mtd/spi-nor/Makefile
+++ b/drivers/mtd/spi-nor/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0

-spi-nor-objs := core.o sfdp.o swp.o otp.o sysfs.o
+spi-nor-objs := core.o sfdp.o swp.o otp.o advprotsec.o sysfs.o
spi-nor-objs += atmel.o
spi-nor-objs += catalyst.o
spi-nor-objs += eon.o
diff --git a/drivers/mtd/spi-nor/advprotsec.c b/drivers/mtd/spi-nor/advprotsec.c
new file mode 100644
index 000000000000..4dc8e67b16ef
--- /dev/null
+++ b/drivers/mtd/spi-nor/advprotsec.c
@@ -0,0 +1,209 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SPI NOR Advanced Sector Protection and Security Features
+ *
+ * Copyright (C) 2021 Micron Technology, Inc.
+ */
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/spi-nor.h>
+
+#include "core.h"
+
+static int spi_nor_secure_read(struct mtd_info *mtd, size_t len, u8 *buf)
+{
+ struct spi_nor *nor = mtd_to_spi_nor(mtd);
+ int ret;
+
+ ret = spi_nor_lock_and_prep(nor);
+ if (ret)
+ return ret;
+
+ ret = nor->params->sec_ops->secure_read(nor, len, buf);
+
+ spi_nor_unlock_and_unprep(nor);
+ return ret;
+}
+
+static int spi_nor_secure_write(struct mtd_info *mtd, size_t len, u8 *buf)
+{
+ struct spi_nor *nor = mtd_to_spi_nor(mtd);
+ int ret;
+
+ ret = spi_nor_lock_and_prep(nor);
+ if (ret)
+ return ret;
+
+ ret = nor->params->sec_ops->secure_write(nor, len, buf);
+
+ spi_nor_unlock_and_unprep(nor);
+ return ret;
+}
+
+static int spi_nor_read_vlock_bits(struct mtd_info *mtd, u32 addr, size_t len,
+ u8 *buf)
+{
+ struct spi_nor *nor = mtd_to_spi_nor(mtd);
+ int ret;
+
+ ret = spi_nor_lock_and_prep(nor);
+ if (ret)
+ return ret;
+
+ ret = nor->params->sec_ops->read_vlock_bits(nor, addr, len, buf);
+
+ spi_nor_unlock_and_unprep(nor);
+ return ret;
+}
+
+static int spi_nor_write_vlock_bits(struct mtd_info *mtd, u32 addr, size_t len,
+ u8 *buf)
+{
+ struct spi_nor *nor = mtd_to_spi_nor(mtd);
+ int ret;
+
+ ret = spi_nor_lock_and_prep(nor);
+ if (ret)
+ return ret;
+
+ ret = spi_nor_write_enable(nor);
+ if (ret)
+ return ret;
+
+ ret = nor->params->sec_ops->write_vlock_bits(nor, addr, len, buf);
+ if (ret)
+ return ret;
+
+ ret = spi_nor_write_disable(nor);
+
+ spi_nor_unlock_and_unprep(nor);
+ return ret;
+}
+
+static int spi_nor_read_nvlock_bits(struct mtd_info *mtd, u32 addr, size_t len,
+ u8 *buf)
+{
+ struct spi_nor *nor = mtd_to_spi_nor(mtd);
+ int ret;
+
+ ret = spi_nor_lock_and_prep(nor);
+ if (ret)
+ return ret;
+
+ ret = nor->params->sec_ops->read_nvlock_bits(nor, addr, len, buf);
+
+ spi_nor_unlock_and_unprep(nor);
+ return ret;
+}
+
+static int spi_nor_write_nvlock_bits(struct mtd_info *mtd, u32 addr)
+{
+ struct spi_nor *nor = mtd_to_spi_nor(mtd);
+ int ret;
+
+ ret = spi_nor_lock_and_prep(nor);
+ if (ret)
+ return ret;
+
+ ret = spi_nor_write_enable(nor);
+ if (ret)
+ return ret;
+
+ ret = nor->params->sec_ops->write_nvlock_bits(nor, addr);
+ if (ret)
+ return ret;
+
+ ret = spi_nor_write_disable(nor);
+
+ spi_nor_unlock_and_unprep(nor);
+ return ret;
+}
+
+static int spi_nor_erase_nvlock_bits(struct mtd_info *mtd)
+{
+ struct spi_nor *nor = mtd_to_spi_nor(mtd);
+ int ret;
+
+ ret = spi_nor_lock_and_prep(nor);
+ if (ret)
+ return ret;
+
+ ret = spi_nor_write_enable(nor);
+ if (ret)
+ return ret;
+
+ ret = nor->params->sec_ops->erase_nvlock_bits(nor);
+ if (ret)
+ return ret;
+
+ ret = spi_nor_write_disable(nor);
+
+ spi_nor_unlock_and_unprep(nor);
+ return ret;
+}
+
+static int spi_nor_read_global_freeze_bits(struct mtd_info *mtd, size_t len,
+ u8 *buf)
+{
+ struct spi_nor *nor = mtd_to_spi_nor(mtd);
+ int ret;
+
+ ret = spi_nor_lock_and_prep(nor);
+ if (ret)
+ return ret;
+
+ ret = nor->params->sec_ops->read_global_freeze_bits(nor, len, buf);
+
+ spi_nor_unlock_and_unprep(nor);
+ return ret;
+}
+
+static int spi_nor_write_global_freeze_bits(struct mtd_info *mtd, size_t len,
+ u8 *buf)
+{
+ struct spi_nor *nor = mtd_to_spi_nor(mtd);
+ int ret;
+
+ ret = spi_nor_lock_and_prep(nor);
+ if (ret)
+ return ret;
+
+ ret = nor->params->sec_ops->write_global_freeze_bits(nor, len, buf);
+
+ spi_nor_unlock_and_unprep(nor);
+ return ret;
+}
+
+static int spi_nor_read_password(struct mtd_info *mtd, size_t len, u8 *buf)
+{
+ struct spi_nor *nor = mtd_to_spi_nor(mtd);
+ int ret;
+
+ ret = spi_nor_lock_and_prep(nor);
+ if (ret)
+ return ret;
+
+ ret = nor->params->sec_ops->read_password(nor, len, buf);
+
+ spi_nor_unlock_and_unprep(nor);
+ return ret;
+}
+
+void spi_nor_register_security_ops(struct spi_nor *nor)
+{
+ struct mtd_info *mtd = &nor->mtd;
+
+ if (!nor->params->sec_ops)
+ return;
+
+ mtd->_secure_packet_read = spi_nor_secure_read;
+ mtd->_secure_packet_write = spi_nor_secure_write;
+ mtd->_read_vlock_bits = spi_nor_read_vlock_bits;
+ mtd->_write_vlock_bits = spi_nor_write_vlock_bits;
+ mtd->_read_nvlock_bits = spi_nor_read_nvlock_bits;
+ mtd->_write_nvlock_bits = spi_nor_write_nvlock_bits;
+ mtd->_erase_nvlock_bits = spi_nor_erase_nvlock_bits;
+ mtd->_read_global_freeze_bits = spi_nor_read_global_freeze_bits;
+ mtd->_write_global_freeze_bits = spi_nor_write_global_freeze_bits;
+ mtd->_read_password = spi_nor_read_password;
+}
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index cc08bd707378..864f3c7783b3 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -3199,6 +3199,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,

spi_nor_register_locking_ops(nor);

+ spi_nor_register_security_ops(nor);
+
/* Send all the required SPI flash commands to initialize device */
ret = spi_nor_init(nor);
if (ret)
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 88227044fc86..bce358c9fb94 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -360,6 +360,25 @@ struct mtd_info {
int (*_get_device) (struct mtd_info *mtd);
void (*_put_device) (struct mtd_info *mtd);

+ /*
+ * Security Operations
+ */
+ int (*_secure_packet_read)(struct mtd_info *mtd, size_t len, u8 *buf);
+ int (*_secure_packet_write)(struct mtd_info *mtd, size_t len, u8 *buf);
+ int (*_read_vlock_bits)(struct mtd_info *mtd, u32 addr, size_t len,
+ u8 *buf);
+ int (*_write_vlock_bits)(struct mtd_info *mtd, u32 addr, size_t len,
+ u8 *buf);
+ int (*_read_nvlock_bits)(struct mtd_info *mtd, u32 addr, size_t len,
+ u8 *buf);
+ int (*_write_nvlock_bits)(struct mtd_info *mtd, u32 addr);
+ int (*_erase_nvlock_bits)(struct mtd_info *mtd);
+ int (*_read_global_freeze_bits)(struct mtd_info *mtd, size_t len,
+ u8 *buf);
+ int (*_write_global_freeze_bits)(struct mtd_info *mtd, size_t len,
+ u8 *buf);
+ int (*_read_password)(struct mtd_info *mtd, size_t len, u8 *buf);
+
/*
* flag indicates a panic write, low level drivers can take appropriate
* action if required to ensure writes go through
--
2.25.1