[RFC PATCH] mtd: nand: raw: Add ONFI NAND unique id read support.

Zixun LI admin at hifiphile.com
Thu Nov 6 18:01:23 CET 2025


This patch adds support for reading the unique ID from ONFI-compliant NAND
flash devices.

The unique ID is a 32 bytes long identifier that is useful for device
identification and tracking.

Tested on SAM9G25-EK with Macronix MX60LF8G18AC flash.

Signed-off-by: Zixun LI <admin at hifiphile.com>
---
 drivers/mtd/nand/raw/nand_base.c | 69 ++++++++++++++++++++++++++++++++
 include/linux/mtd/rawnand.h      |  8 ++++
 2 files changed, 77 insertions(+)

diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 48e3685d995..30aa578e074 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -991,6 +991,75 @@ static int nand_onfi_set_timings(struct mtd_info *mtd, struct nand_chip *chip)
 				       tmode_param);
 }
 
+/**
+ * nand_onfi_read_unique_id - read the ONFI unique ID sequence
+ * @chip: NAND chip descriptor
+ * @buf: destination buffer
+ * @len: size of the destination buffer
+ *
+ * Issues the ONFI UNIQUE_ID command sequence, validates the unique ID and
+ * copies it into @buf.
+ *
+ * Return: 0 on success or negative error code otherwise.
+ */
+int nand_onfi_read_unique_id(struct nand_chip *chip, void *buf,
+			     unsigned int len)
+{
+	struct mtd_info *mtd;
+	unsigned int copy;
+	unsigned int byte;
+	unsigned int copy_len;
+	u8 raw_id[ONFI_UNIQUE_ID_LEN * 2];
+	u8 *out = buf;
+	int ret = -EIO;
+
+	if (!chip)
+		return -EINVAL;
+
+	if (len && !buf)
+		return -EINVAL;
+
+	if (len > ONFI_UNIQUE_ID_LEN)
+		return -EINVAL;
+
+	if (!chip->onfi_version)
+		return -EOPNOTSUPP;
+
+	mtd = nand_to_mtd(chip);
+	nand_get_device(mtd, FL_READING);
+	chip->select_chip(mtd, 0);
+
+	chip->cmdfunc(mtd, NAND_CMD_UNIQUE_ID, 0, -1);
+
+	for (copy = 0; copy < ONFI_UNIQUE_ID_COPIES; copy++) {
+		for (byte = 0; byte < ONFI_UNIQUE_ID_LEN * 2; byte++)
+			raw_id[byte] = chip->read_byte(mtd);
+
+		for (byte = 0; byte < ONFI_UNIQUE_ID_LEN; byte++) {
+			u8 lo = raw_id[byte];
+			u8 hi = raw_id[byte + ONFI_UNIQUE_ID_LEN];
+
+			if ((lo ^ hi) != 0xff)
+				break;
+		}
+
+		if (byte == ONFI_UNIQUE_ID_LEN) {
+			copy_len = min_t(unsigned int, len, ONFI_UNIQUE_ID_LEN);
+
+			if (len)
+				memcpy(out, raw_id, copy_len);
+
+			ret = 0;
+			goto out;
+		}
+	}
+
+out:
+	nand_release_device(mtd);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(nand_onfi_read_unique_id);
+
 /**
  * nand_setup_data_interface - Setup the best data interface and timings
  * @chip: The NAND chip
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index 3e80b134063..87083c34aed 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -88,6 +88,7 @@ void nand_wait_ready(struct mtd_info *mtd);
 #define NAND_CMD_READID		0x90
 #define NAND_CMD_ERASE2		0xd0
 #define NAND_CMD_PARAM		0xec
+#define NAND_CMD_UNIQUE_ID	0xed
 #define NAND_CMD_GET_FEATURES	0xee
 #define NAND_CMD_SET_FEATURES	0xef
 #define NAND_CMD_RESET		0xff
@@ -409,6 +410,10 @@ struct onfi_ext_param_page {
 	 */
 } __packed;
 
+/* ONFI unique ID */
+#define ONFI_UNIQUE_ID_LEN 16
+#define ONFI_UNIQUE_ID_COPIES 16
+
 struct jedec_ecc_info {
 	u8 ecc_bits;
 	u8 codeword_size;
@@ -1385,4 +1390,7 @@ int nand_write_data_op(struct nand_chip *chip, const void *buf,
 /* Default extended ID decoding function */
 void nand_decode_ext_id(struct nand_chip *chip);
 
+int nand_onfi_read_unique_id(struct nand_chip *chip, void *buf,
+			     unsigned int len);
+
 #endif /* __LINUX_MTD_RAWNAND_H */
-- 
2.51.0



More information about the U-Boot mailing list