All of lore.kernel.org
 help / color / mirror / Atom feed
From: Miquel Raynal <miquel.raynal@bootlin.com>
To: Martin Kurbanov <mmkurbanov@salutedevices.com>
Cc: Richard Weinberger <richard@nod.at>,
	Vignesh Raghavendra <vigneshr@ti.com>,
	Mika Westerberg <mika.westerberg@linux.intel.com>,
	Michael Walle <michael@walle.cc>, Mark Brown <broonie@kernel.org>,
	Chia-Lin Kao <acelan.kao@canonical.com>,
	Md Sadre Alam <quic_mdalam@quicinc.com>,
	Ezra Buehler <ezra.buehler@husqvarnagroup.com>,
	Sridharan S N <quic_sridsn@quicinc.com>,
	Frieder Schrempf <frieder.schrempf@kontron.de>,
	Alexey Romanov <avromanov@salutedevices.com>,
	<linux-kernel@vger.kernel.org>, <linux-mtd@lists.infradead.org>,
	<kernel@salutedevices.com>
Subject: Re: [PATCH v1 2/5] mtd: spinand: add OTP support
Date: Wed, 17 Jul 2024 10:36:23 +0200	[thread overview]
Message-ID: <20240717103623.6d6b63be@xps-13> (raw)
In-Reply-To: <20240617133504.179705-3-mmkurbanov@salutedevices.com>

Hi Martin,

mmkurbanov@salutedevices.com wrote on Mon, 17 Jun 2024 16:34:54 +0300:

> The MTD subsystem already supports accessing two OTP areas: user and
> factory. User areas can be written by the user. This patch only adds
> support for the user areas.
> 
> In this patch the OTP_INFO macro is provided to add parameters to
> spinand_info.
> To implement OTP operations, the client (flash driver) is provided with
> 5 callbacks: .read(), .write(), .info(), .lock(), .erase().

Good job! Please find minor comments below.

> 
> Signed-off-by: Martin Kurbanov <mmkurbanov@salutedevices.com>
> ---
>  drivers/mtd/nand/spi/Makefile |   3 +-
>  drivers/mtd/nand/spi/core.c   |   3 +
>  drivers/mtd/nand/spi/otp.c    | 219 ++++++++++++++++++++++++++++++++++
>  include/linux/mtd/spinand.h   |  56 +++++++++
>  4 files changed, 280 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/mtd/nand/spi/otp.c
> 
> diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
> index 19cc77288ebbc..60d2e830ffc6b 100644
> --- a/drivers/mtd/nand/spi/Makefile
> +++ b/drivers/mtd/nand/spi/Makefile
> @@ -1,4 +1,5 @@
>  # SPDX-License-Identifier: GPL-2.0
> -spinand-objs := core.o alliancememory.o ato.o esmt.o foresee.o gigadevice.o macronix.o
> +spinand-objs := core.o otp.o
> +spinand-objs += alliancememory.o ato.o esmt.o foresee.o gigadevice.o macronix.o
>  spinand-objs += micron.o paragon.o toshiba.o winbond.o xtx.o
>  obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
> diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
> index 807c24b0c7c4f..2cb825edd49d0 100644
> --- a/drivers/mtd/nand/spi/core.c
> +++ b/drivers/mtd/nand/spi/core.c
> @@ -1111,6 +1111,7 @@ int spinand_match_and_init(struct spinand_device *spinand,
>  		spinand->flags = table[i].flags;
>  		spinand->id.len = 1 + table[i].devid.len;
>  		spinand->select_target = table[i].select_target;
> +		spinand->otp = &table[i].otp;
>  
>  		op = spinand_select_op_variant(spinand,
>  					       info->op_variants.read_cache);
> @@ -1292,6 +1293,8 @@ static int spinand_init(struct spinand_device *spinand)
>  	mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks;
>  	mtd->_resume = spinand_mtd_resume;
>  
> +	spinand_set_mtd_otp_ops(spinand);
> +
>  	if (nand->ecc.engine) {
>  		ret = mtd_ooblayout_count_freebytes(mtd);
>  		if (ret < 0)
> diff --git a/drivers/mtd/nand/spi/otp.c b/drivers/mtd/nand/spi/otp.c
> new file mode 100644
> index 0000000000000..e1f96b1898dcb
> --- /dev/null
> +++ b/drivers/mtd/nand/spi/otp.c
> @@ -0,0 +1,219 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
> + *
> + * Author: Martin Kurbanov <mmkurbanov@salutedevices.com>
> + */
> +
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/spinand.h>
> +
> +static size_t spinand_otp_size(struct spinand_device *spinand)
> +{
> +	struct nand_device *nand = spinand_to_nand(spinand);
> +	size_t otp_pagesize = nanddev_page_size(nand) +
> +			      nanddev_per_page_oobsize(nand);
> +
> +	return spinand->otp->layout.npages * otp_pagesize;
> +}
> +
> +static unsigned int spinand_otp_npages(const struct spinand_device *spinand)
> +{
> +	return spinand->otp->layout.npages;

Maybe you can move this helper up and use it in spinand_otp_size().

> +}
> +

...

> +static int spinand_mtd_otp_rw(struct mtd_info *mtd, loff_t ofs, size_t len,
> +			      size_t *retlen, u8 *buf, bool is_write)
> +{
> +	struct spinand_device *spinand = mtd_to_spinand(mtd);
> +	const struct spinand_otp_ops *ops = spinand->otp->ops;
> +	size_t total_len = len;
> +	int ret;
> +
> +	if (ofs < 0 || ofs + len > spinand_otp_size(spinand))
> +		return -EINVAL;
> +

Please just check if (!len) here

> +	total_len = min_t(size_t, total_len, spinand_otp_size(spinand) - ofs);

                                  len ^^^

Here you can just compute the minimum and don't check the output. It
will be simpler to understand.

> +	if (!total_len)
> +		return 0;
> +
> +	mutex_lock(&spinand->lock);
> +
> +	ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, CFG_OTP_ENABLE);
> +	if (ret)
> +		goto out_unlock;
> +
> +	if (is_write)
> +		ret = ops->write(spinand, ofs, len, buf, retlen);
> +	else
> +		ret = ops->read(spinand, ofs, len, buf, retlen);
> +
> +	if (spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0)) {
> +		WARN(1, "Can not disable OTP mode\n");

Please avoid WARN() statements like that. A normal pr_warn is enough.

> +		ret = -EIO;
> +	}
> +
> +out_unlock:
> +	mutex_unlock(&spinand->lock);
> +	return ret;
> +}
> +
> +static int spinand_mtd_otp_read(struct mtd_info *mtd, loff_t from, size_t len,

Can you keep the naming consistent?                 ofs vs. from  ^

> +				size_t *retlen, u8 *buf)
> +{
> +	return spinand_mtd_otp_rw(mtd, from, len, retlen, buf, false);
> +}
> +
> +static int spinand_mtd_otp_write(struct mtd_info *mtd, loff_t to, size_t len,
> +				 size_t *retlen, const u8 *buf)
> +{
> +	return spinand_mtd_otp_rw(mtd, to, len, retlen, (u8 *)buf, true);
> +}
> +
> +static int spinand_mtd_otp_erase(struct mtd_info *mtd, loff_t from, size_t len)
> +{
> +	struct spinand_device *spinand = mtd_to_spinand(mtd);
> +	const struct spinand_otp_ops *ops = spinand->otp->ops;
> +	int ret;
> +
> +	if (!ops->erase)
> +		return -EOPNOTSUPP;
> +
> +	if (!len)
> +		return 0;

This check seems sensible but is absent in the other helpers. Any
reason? Please add it to _lock() and _rw()

> +
> +	if (from < 0 || (from + len) > spinand_otp_size(spinand))
> +		return -EINVAL;

And this is also repeated three times, it is probably worth factorizing
out.

> +
> +	mutex_lock(&spinand->lock);
> +	ret = ops->erase(spinand, from, len);
> +	mutex_unlock(&spinand->lock);
> +
> +	return ret;
> +}
> +
> +static int spinand_mtd_otp_lock(struct mtd_info *mtd, loff_t from, size_t len)
> +{
> +	struct spinand_device *spinand = mtd_to_spinand(mtd);
> +	const struct spinand_otp_ops *ops = spinand->otp->ops;
> +	int ret;
> +
> +	if (!ops->lock)
> +		return -EOPNOTSUPP;
> +
> +	if (from < 0 || (from + len) > spinand_otp_size(spinand))
> +		return -EINVAL;
> +
> +	mutex_lock(&spinand->lock);
> +	ret = ops->lock(spinand, from, len);
> +	mutex_unlock(&spinand->lock);
> +
> +	return ret;
> +}
> +
> +/**
> + * spinand_set_mtd_otp_ops() - Set up OTP methods
> + * @spinand: the spinand device
> + *
> + * Set up OTP methods.
> + */
> +void spinand_set_mtd_otp_ops(struct spinand_device *spinand)
> +{
> +	struct mtd_info *mtd = spinand_to_mtd(spinand);
> +
> +	if (!spinand->otp->ops)
> +		return;
> +
> +	mtd->_get_user_prot_info = spinand_mtd_otp_info;
> +	mtd->_read_user_prot_reg = spinand_mtd_otp_read;
> +	mtd->_write_user_prot_reg = spinand_mtd_otp_write;
> +	mtd->_lock_user_prot_reg = spinand_mtd_otp_lock;
> +	mtd->_erase_user_prot_reg = spinand_mtd_otp_erase;
> +}
> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
> index 555846517faf6..a0d42a9be333f 100644
> --- a/include/linux/mtd/spinand.h
> +++ b/include/linux/mtd/spinand.h
> @@ -322,6 +322,43 @@ struct spinand_ondie_ecc_conf {
>  	u8 status;
>  };
>  
> +/**
> + * struct spinand_otp_layout - structure to describe the SPI NAND OTP area
> + * @npages: number of pages in the OTP
> + */
> +struct spinand_otp_layout {
> +	unsigned int npages;
> +};
> +
> +/**
> + * struct spinand_otp_ops - SPI NAND OTP methods
> + * @info: Get the OTP area information
> + * @lock: lock an OTP region
> + * @erase: erase an OTP region
> + * @read: read from the SPI NAND OTP area
> + * @write: write to the SPI NAND OTP area
> + */
> +struct spinand_otp_ops {
> +	int (*info)(struct spinand_device *spinand, size_t len,
> +		    struct otp_info *buf, size_t *retlen);
> +	int (*lock)(struct spinand_device *spinand, loff_t from, size_t len);
> +	int (*erase)(struct spinand_device *spinand, loff_t from, size_t len);
> +	int (*read)(struct spinand_device *spinand, loff_t from, size_t len,
> +		    u8 *buf, size_t *retlen);
> +	int (*write)(struct spinand_device *spinand, loff_t from, size_t len,
> +		     const u8 *buf, size_t *retlen);
> +};
> +
> +/**
> + * struct spinand_otp - SPI NAND OTP grouping structure
> + * @layout: OTP region layout
> + * @ops: OTP access ops
> + */
> +struct spinand_otp {
> +	const struct spinand_otp_layout layout;
> +	const struct spinand_otp_ops *ops;
> +};
> +
>  /**
>   * struct spinand_info - Structure used to describe SPI NAND chips
>   * @model: model name
> @@ -354,6 +391,7 @@ struct spinand_info {
>  	} op_variants;
>  	int (*select_target)(struct spinand_device *spinand,
>  			     unsigned int target);
> +	struct spinand_otp otp;
>  };
>  
>  #define SPINAND_ID(__method, ...)					\
> @@ -379,6 +417,14 @@ struct spinand_info {
>  #define SPINAND_SELECT_TARGET(__func)					\
>  	.select_target = __func,
>  
> +#define SPINAND_OTP_INFO(__npages, __ops)				\
> +	.otp = {							\
> +		.layout = {						\
> +			.npages = __npages,				\
> +		},							\
> +		.ops = __ops,						\
> +	}
> +
>  #define SPINAND_INFO(__model, __id, __memorg, __eccreq, __op_variants,	\
>  		     __flags, ...)					\
>  	{								\
> @@ -422,6 +468,7 @@ struct spinand_dirmap {
>   *		passed in spi_mem_op be DMA-able, so we can't based the bufs on
>   *		the stack
>   * @manufacturer: SPI NAND manufacturer information
> + * @otp: SPI NAND OTP info.
>   * @priv: manufacturer private data
>   */
>  struct spinand_device {
> @@ -450,6 +497,7 @@ struct spinand_device {
>  	u8 *oobbuf;
>  	u8 *scratchbuf;
>  	const struct spinand_manufacturer *manufacturer;
> +	const struct spinand_otp *otp;
>  	void *priv;
>  };
>  
> @@ -525,4 +573,12 @@ int spinand_read_page(struct spinand_device *spinand,
>  int spinand_write_page(struct spinand_device *spinand,
>  		       const struct nand_page_io_req *req);
>  
> +void spinand_set_mtd_otp_ops(struct spinand_device *spinand);
> +
> +int spinand_otp_read(struct spinand_device *spinand, loff_t from, size_t len,
> +		     u8 *buf, size_t *retlen);
> +
> +int spinand_otp_write(struct spinand_device *spinand, loff_t from, size_t len,
> +		      const u8 *buf, size_t *retlen);
> +

Why exposing spinand_otp_read and spinand_otp_write ?

>  #endif /* __LINUX_MTD_SPINAND_H */


Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

WARNING: multiple messages have this Message-ID (diff)
From: Miquel Raynal <miquel.raynal@bootlin.com>
To: Martin Kurbanov <mmkurbanov@salutedevices.com>
Cc: Richard Weinberger <richard@nod.at>,
	Vignesh Raghavendra <vigneshr@ti.com>,
	Mika Westerberg <mika.westerberg@linux.intel.com>,
	Michael Walle <michael@walle.cc>, Mark Brown <broonie@kernel.org>,
	Chia-Lin Kao <acelan.kao@canonical.com>,
	Md Sadre Alam <quic_mdalam@quicinc.com>,
	Ezra Buehler <ezra.buehler@husqvarnagroup.com>,
	Sridharan S N <quic_sridsn@quicinc.com>,
	Frieder Schrempf <frieder.schrempf@kontron.de>,
	Alexey Romanov <avromanov@salutedevices.com>,
	<linux-kernel@vger.kernel.org>, <linux-mtd@lists.infradead.org>,
	<kernel@salutedevices.com>
Subject: Re: [PATCH v1 2/5] mtd: spinand: add OTP support
Date: Wed, 17 Jul 2024 10:36:23 +0200	[thread overview]
Message-ID: <20240717103623.6d6b63be@xps-13> (raw)
In-Reply-To: <20240617133504.179705-3-mmkurbanov@salutedevices.com>

Hi Martin,

mmkurbanov@salutedevices.com wrote on Mon, 17 Jun 2024 16:34:54 +0300:

> The MTD subsystem already supports accessing two OTP areas: user and
> factory. User areas can be written by the user. This patch only adds
> support for the user areas.
> 
> In this patch the OTP_INFO macro is provided to add parameters to
> spinand_info.
> To implement OTP operations, the client (flash driver) is provided with
> 5 callbacks: .read(), .write(), .info(), .lock(), .erase().

Good job! Please find minor comments below.

> 
> Signed-off-by: Martin Kurbanov <mmkurbanov@salutedevices.com>
> ---
>  drivers/mtd/nand/spi/Makefile |   3 +-
>  drivers/mtd/nand/spi/core.c   |   3 +
>  drivers/mtd/nand/spi/otp.c    | 219 ++++++++++++++++++++++++++++++++++
>  include/linux/mtd/spinand.h   |  56 +++++++++
>  4 files changed, 280 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/mtd/nand/spi/otp.c
> 
> diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
> index 19cc77288ebbc..60d2e830ffc6b 100644
> --- a/drivers/mtd/nand/spi/Makefile
> +++ b/drivers/mtd/nand/spi/Makefile
> @@ -1,4 +1,5 @@
>  # SPDX-License-Identifier: GPL-2.0
> -spinand-objs := core.o alliancememory.o ato.o esmt.o foresee.o gigadevice.o macronix.o
> +spinand-objs := core.o otp.o
> +spinand-objs += alliancememory.o ato.o esmt.o foresee.o gigadevice.o macronix.o
>  spinand-objs += micron.o paragon.o toshiba.o winbond.o xtx.o
>  obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
> diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
> index 807c24b0c7c4f..2cb825edd49d0 100644
> --- a/drivers/mtd/nand/spi/core.c
> +++ b/drivers/mtd/nand/spi/core.c
> @@ -1111,6 +1111,7 @@ int spinand_match_and_init(struct spinand_device *spinand,
>  		spinand->flags = table[i].flags;
>  		spinand->id.len = 1 + table[i].devid.len;
>  		spinand->select_target = table[i].select_target;
> +		spinand->otp = &table[i].otp;
>  
>  		op = spinand_select_op_variant(spinand,
>  					       info->op_variants.read_cache);
> @@ -1292,6 +1293,8 @@ static int spinand_init(struct spinand_device *spinand)
>  	mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks;
>  	mtd->_resume = spinand_mtd_resume;
>  
> +	spinand_set_mtd_otp_ops(spinand);
> +
>  	if (nand->ecc.engine) {
>  		ret = mtd_ooblayout_count_freebytes(mtd);
>  		if (ret < 0)
> diff --git a/drivers/mtd/nand/spi/otp.c b/drivers/mtd/nand/spi/otp.c
> new file mode 100644
> index 0000000000000..e1f96b1898dcb
> --- /dev/null
> +++ b/drivers/mtd/nand/spi/otp.c
> @@ -0,0 +1,219 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2024, SaluteDevices. All Rights Reserved.
> + *
> + * Author: Martin Kurbanov <mmkurbanov@salutedevices.com>
> + */
> +
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/spinand.h>
> +
> +static size_t spinand_otp_size(struct spinand_device *spinand)
> +{
> +	struct nand_device *nand = spinand_to_nand(spinand);
> +	size_t otp_pagesize = nanddev_page_size(nand) +
> +			      nanddev_per_page_oobsize(nand);
> +
> +	return spinand->otp->layout.npages * otp_pagesize;
> +}
> +
> +static unsigned int spinand_otp_npages(const struct spinand_device *spinand)
> +{
> +	return spinand->otp->layout.npages;

Maybe you can move this helper up and use it in spinand_otp_size().

> +}
> +

...

> +static int spinand_mtd_otp_rw(struct mtd_info *mtd, loff_t ofs, size_t len,
> +			      size_t *retlen, u8 *buf, bool is_write)
> +{
> +	struct spinand_device *spinand = mtd_to_spinand(mtd);
> +	const struct spinand_otp_ops *ops = spinand->otp->ops;
> +	size_t total_len = len;
> +	int ret;
> +
> +	if (ofs < 0 || ofs + len > spinand_otp_size(spinand))
> +		return -EINVAL;
> +

Please just check if (!len) here

> +	total_len = min_t(size_t, total_len, spinand_otp_size(spinand) - ofs);

                                  len ^^^

Here you can just compute the minimum and don't check the output. It
will be simpler to understand.

> +	if (!total_len)
> +		return 0;
> +
> +	mutex_lock(&spinand->lock);
> +
> +	ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, CFG_OTP_ENABLE);
> +	if (ret)
> +		goto out_unlock;
> +
> +	if (is_write)
> +		ret = ops->write(spinand, ofs, len, buf, retlen);
> +	else
> +		ret = ops->read(spinand, ofs, len, buf, retlen);
> +
> +	if (spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0)) {
> +		WARN(1, "Can not disable OTP mode\n");

Please avoid WARN() statements like that. A normal pr_warn is enough.

> +		ret = -EIO;
> +	}
> +
> +out_unlock:
> +	mutex_unlock(&spinand->lock);
> +	return ret;
> +}
> +
> +static int spinand_mtd_otp_read(struct mtd_info *mtd, loff_t from, size_t len,

Can you keep the naming consistent?                 ofs vs. from  ^

> +				size_t *retlen, u8 *buf)
> +{
> +	return spinand_mtd_otp_rw(mtd, from, len, retlen, buf, false);
> +}
> +
> +static int spinand_mtd_otp_write(struct mtd_info *mtd, loff_t to, size_t len,
> +				 size_t *retlen, const u8 *buf)
> +{
> +	return spinand_mtd_otp_rw(mtd, to, len, retlen, (u8 *)buf, true);
> +}
> +
> +static int spinand_mtd_otp_erase(struct mtd_info *mtd, loff_t from, size_t len)
> +{
> +	struct spinand_device *spinand = mtd_to_spinand(mtd);
> +	const struct spinand_otp_ops *ops = spinand->otp->ops;
> +	int ret;
> +
> +	if (!ops->erase)
> +		return -EOPNOTSUPP;
> +
> +	if (!len)
> +		return 0;

This check seems sensible but is absent in the other helpers. Any
reason? Please add it to _lock() and _rw()

> +
> +	if (from < 0 || (from + len) > spinand_otp_size(spinand))
> +		return -EINVAL;

And this is also repeated three times, it is probably worth factorizing
out.

> +
> +	mutex_lock(&spinand->lock);
> +	ret = ops->erase(spinand, from, len);
> +	mutex_unlock(&spinand->lock);
> +
> +	return ret;
> +}
> +
> +static int spinand_mtd_otp_lock(struct mtd_info *mtd, loff_t from, size_t len)
> +{
> +	struct spinand_device *spinand = mtd_to_spinand(mtd);
> +	const struct spinand_otp_ops *ops = spinand->otp->ops;
> +	int ret;
> +
> +	if (!ops->lock)
> +		return -EOPNOTSUPP;
> +
> +	if (from < 0 || (from + len) > spinand_otp_size(spinand))
> +		return -EINVAL;
> +
> +	mutex_lock(&spinand->lock);
> +	ret = ops->lock(spinand, from, len);
> +	mutex_unlock(&spinand->lock);
> +
> +	return ret;
> +}
> +
> +/**
> + * spinand_set_mtd_otp_ops() - Set up OTP methods
> + * @spinand: the spinand device
> + *
> + * Set up OTP methods.
> + */
> +void spinand_set_mtd_otp_ops(struct spinand_device *spinand)
> +{
> +	struct mtd_info *mtd = spinand_to_mtd(spinand);
> +
> +	if (!spinand->otp->ops)
> +		return;
> +
> +	mtd->_get_user_prot_info = spinand_mtd_otp_info;
> +	mtd->_read_user_prot_reg = spinand_mtd_otp_read;
> +	mtd->_write_user_prot_reg = spinand_mtd_otp_write;
> +	mtd->_lock_user_prot_reg = spinand_mtd_otp_lock;
> +	mtd->_erase_user_prot_reg = spinand_mtd_otp_erase;
> +}
> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
> index 555846517faf6..a0d42a9be333f 100644
> --- a/include/linux/mtd/spinand.h
> +++ b/include/linux/mtd/spinand.h
> @@ -322,6 +322,43 @@ struct spinand_ondie_ecc_conf {
>  	u8 status;
>  };
>  
> +/**
> + * struct spinand_otp_layout - structure to describe the SPI NAND OTP area
> + * @npages: number of pages in the OTP
> + */
> +struct spinand_otp_layout {
> +	unsigned int npages;
> +};
> +
> +/**
> + * struct spinand_otp_ops - SPI NAND OTP methods
> + * @info: Get the OTP area information
> + * @lock: lock an OTP region
> + * @erase: erase an OTP region
> + * @read: read from the SPI NAND OTP area
> + * @write: write to the SPI NAND OTP area
> + */
> +struct spinand_otp_ops {
> +	int (*info)(struct spinand_device *spinand, size_t len,
> +		    struct otp_info *buf, size_t *retlen);
> +	int (*lock)(struct spinand_device *spinand, loff_t from, size_t len);
> +	int (*erase)(struct spinand_device *spinand, loff_t from, size_t len);
> +	int (*read)(struct spinand_device *spinand, loff_t from, size_t len,
> +		    u8 *buf, size_t *retlen);
> +	int (*write)(struct spinand_device *spinand, loff_t from, size_t len,
> +		     const u8 *buf, size_t *retlen);
> +};
> +
> +/**
> + * struct spinand_otp - SPI NAND OTP grouping structure
> + * @layout: OTP region layout
> + * @ops: OTP access ops
> + */
> +struct spinand_otp {
> +	const struct spinand_otp_layout layout;
> +	const struct spinand_otp_ops *ops;
> +};
> +
>  /**
>   * struct spinand_info - Structure used to describe SPI NAND chips
>   * @model: model name
> @@ -354,6 +391,7 @@ struct spinand_info {
>  	} op_variants;
>  	int (*select_target)(struct spinand_device *spinand,
>  			     unsigned int target);
> +	struct spinand_otp otp;
>  };
>  
>  #define SPINAND_ID(__method, ...)					\
> @@ -379,6 +417,14 @@ struct spinand_info {
>  #define SPINAND_SELECT_TARGET(__func)					\
>  	.select_target = __func,
>  
> +#define SPINAND_OTP_INFO(__npages, __ops)				\
> +	.otp = {							\
> +		.layout = {						\
> +			.npages = __npages,				\
> +		},							\
> +		.ops = __ops,						\
> +	}
> +
>  #define SPINAND_INFO(__model, __id, __memorg, __eccreq, __op_variants,	\
>  		     __flags, ...)					\
>  	{								\
> @@ -422,6 +468,7 @@ struct spinand_dirmap {
>   *		passed in spi_mem_op be DMA-able, so we can't based the bufs on
>   *		the stack
>   * @manufacturer: SPI NAND manufacturer information
> + * @otp: SPI NAND OTP info.
>   * @priv: manufacturer private data
>   */
>  struct spinand_device {
> @@ -450,6 +497,7 @@ struct spinand_device {
>  	u8 *oobbuf;
>  	u8 *scratchbuf;
>  	const struct spinand_manufacturer *manufacturer;
> +	const struct spinand_otp *otp;
>  	void *priv;
>  };
>  
> @@ -525,4 +573,12 @@ int spinand_read_page(struct spinand_device *spinand,
>  int spinand_write_page(struct spinand_device *spinand,
>  		       const struct nand_page_io_req *req);
>  
> +void spinand_set_mtd_otp_ops(struct spinand_device *spinand);
> +
> +int spinand_otp_read(struct spinand_device *spinand, loff_t from, size_t len,
> +		     u8 *buf, size_t *retlen);
> +
> +int spinand_otp_write(struct spinand_device *spinand, loff_t from, size_t len,
> +		      const u8 *buf, size_t *retlen);
> +

Why exposing spinand_otp_read and spinand_otp_write ?

>  #endif /* __LINUX_MTD_SPINAND_H */


Thanks,
Miquèl

  reply	other threads:[~2024-07-17  8:36 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-06-17 13:34 [PATCH v1 0/5] mtd: spinand: add OTP support Martin Kurbanov
2024-06-17 13:34 ` Martin Kurbanov
2024-06-17 13:34 ` [PATCH v1 1/5] mtd: spinand: make spinand_{read,write}_page global Martin Kurbanov
2024-06-17 13:34   ` Martin Kurbanov
2024-06-17 13:34 ` [PATCH v1 2/5] mtd: spinand: add OTP support Martin Kurbanov
2024-06-17 13:34   ` Martin Kurbanov
2024-07-17  8:36   ` Miquel Raynal [this message]
2024-07-17  8:36     ` Miquel Raynal
2024-06-17 13:34 ` [PATCH v1 3/5] mtd: spinand: make spinand_wait() global Martin Kurbanov
2024-06-17 13:34   ` Martin Kurbanov
2024-06-17 13:34 ` [PATCH v1 4/5] mtd: spinand: micron: OTP access for MT29F2G01ABAGD Martin Kurbanov
2024-06-17 13:34   ` Martin Kurbanov
2024-06-17 13:34 ` [PATCH v1 5/5] mtd: spinand: esmt: OTP access for F50{L,D}1G41LB Martin Kurbanov
2024-06-17 13:34   ` Martin Kurbanov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240717103623.6d6b63be@xps-13 \
    --to=miquel.raynal@bootlin.com \
    --cc=acelan.kao@canonical.com \
    --cc=avromanov@salutedevices.com \
    --cc=broonie@kernel.org \
    --cc=ezra.buehler@husqvarnagroup.com \
    --cc=frieder.schrempf@kontron.de \
    --cc=kernel@salutedevices.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mtd@lists.infradead.org \
    --cc=michael@walle.cc \
    --cc=mika.westerberg@linux.intel.com \
    --cc=mmkurbanov@salutedevices.com \
    --cc=quic_mdalam@quicinc.com \
    --cc=quic_sridsn@quicinc.com \
    --cc=richard@nod.at \
    --cc=vigneshr@ti.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.