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

Michael Nazzareno Trimarchi michael at amarulasolutions.com
Fri Nov 7 11:45:28 CET 2025


Hi all

On Fri, Nov 7, 2025 at 11:41 AM Eugen Hristev <eugen.hristev at linaro.org> wrote:
>
>
>
> 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 ?
>

I prefer to apply if we have a use case and a consumer of this patch.

Michael

> Eugen>  #endif /* __LINUX_MTD_RAWNAND_H */
>


-- 
Michael Nazzareno Trimarchi
Co-Founder & Chief Executive Officer
M. +39 347 913 2170
michael at amarulasolutions.com
__________________________________

Amarula Solutions BV
Joop Geesinkweg 125, 1114 AB, Amsterdam, NL
T. +31 (0)85 111 9172
info at amarulasolutions.com
www.amarulasolutions.com


More information about the U-Boot mailing list