[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