[RFC PATCH] mtd: nand: raw: Add ONFI NAND unique id read support.
Eugen Hristev
eugen.hristev at linaro.org
Fri Nov 7 11:41:24 CET 2025
On 11/6/25 19:01, Zixun LI wrote:
> 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);
> +
Something appears to be missing. Where is this function called ?
Eugen> #endif /* __LINUX_MTD_RAWNAND_H */
More information about the U-Boot
mailing list