[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