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 v2 2/5] mtd: spinand: add OTP support
Date: Tue, 1 Oct 2024 11:12:25 +0200	[thread overview]
Message-ID: <20241001111225.36cb9701@xps-13> (raw)
In-Reply-To: <20240827174920.316756-3-mmkurbanov@salutedevices.com>

Hi Martin,

mmkurbanov@salutedevices.com wrote on Tue, 27 Aug 2024 20:49:00 +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().

Overall this looks good, I have minor changes to request. I'm not yet
done down to the last patch, but I think the implementation is neat.

> 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    | 232 ++++++++++++++++++++++++++++++++++
>  include/linux/mtd/spinand.h   |  56 ++++++++
>  4 files changed, 293 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..d459f811f9c04
> --- /dev/null
> +++ b/drivers/mtd/nand/spi/otp.c
> @@ -0,0 +1,232 @@
> +// 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 unsigned int spinand_otp_npages(const struct spinand_device *spinand)
> +{
> +	return spinand->otp->layout.npages;
> +}
> +
> +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_npages(spinand) * otp_pagesize;
> +}
> +
> +static int spinand_otp_rw(struct spinand_device *spinand, loff_t ofs,
> +			  size_t len, u8 *buf, size_t *retlen, bool is_write)
> +{
> +	struct nand_device *nand = spinand_to_nand(spinand);
> +	struct nand_page_io_req req = { 0 };

					= {}; is enough

> +	unsigned long long page;
> +	size_t copied = 0;
> +	size_t otp_pagesize = nanddev_page_size(nand) +
> +			      nanddev_per_page_oobsize(nand);
> +	int ret = 0;
> +
> +	page = ofs;
> +	req.dataoffs = do_div(page, otp_pagesize);
> +	req.pos.page = page;
> +	req.type = is_write ? NAND_PAGE_WRITE : NAND_PAGE_READ;
> +	req.mode = MTD_OPS_RAW;
> +	req.databuf.in = buf;
> +
> +	while (copied < len && req.pos.page < spinand_otp_npages(spinand)) {
> +		req.datalen = min_t(unsigned int,
> +				    otp_pagesize - req.dataoffs,
> +				    len - copied);
> +
> +		if (is_write)
> +			ret = spinand_write_page(spinand, &req);
> +		else
> +			ret = spinand_read_page(spinand, &req);
> +
> +		if (ret < 0)
> +			break;
> +
> +		req.dataoffs = 0;
> +		copied += req.datalen;
> +		req.pos.page++;
> +	}
> +
> +	*retlen = copied;
> +
> +	return ret;
> +}
> +
> +/**
> + * spinand_otp_read() - Read from OTP area
> + * @spinand: the spinand device
> + * @ofs: the offset to read
> + * @len: the number of data bytes to read
> + * @buf: the buffer to store the read data
> + * @retlen: the pointer to variable to store the number of read bytes
> + *
> + * Return: 0 on success, an error code otherwise.
> + */
> +int spinand_otp_read(struct spinand_device *spinand, loff_t ofs, size_t len,
> +		     u8 *buf, size_t *retlen)
> +{
> +	return spinand_otp_rw(spinand, ofs, len, buf, retlen, false);
> +}
> +
> +/**
> + * spinand_otp_write() - Write to OTP area
> + * @spinand:  the spinand device
> + * @ofs: the offset to write to
> + * @len: the number of bytes to write
> + * @buf: the buffer with data to write
> + * @retlen: the pointer to variable to store the number of written bytes
> + *
> + * Return: 0 on success, an error code otherwise.
> + */
> +int spinand_otp_write(struct spinand_device *spinand, loff_t ofs, size_t len,
> +		      const u8 *buf, size_t *retlen)
> +{
> +	return spinand_otp_rw(spinand, ofs, len, (u8 *)buf, retlen, true);
> +}

These spinand_otp_xxx() helpers are not yet used, and thus should be
introduced later, when they are useful.

> +
> +static int spinand_otp_check_bounds(struct spinand_device *spinand, loff_t ofs,
> +				    size_t len)
> +{
> +	if (ofs < 0 || ofs + len > spinand_otp_size(spinand))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int spinand_mtd_otp_info(struct mtd_info *mtd, size_t len,
> +				size_t *retlen, struct otp_info *buf)
> +{
> +	struct spinand_device *spinand = mtd_to_spinand(mtd);
> +	const struct spinand_otp_ops *ops = spinand->otp->ops;
> +	int ret;
> +
> +	mutex_lock(&spinand->lock);
> +	ret = ops->info(spinand, len, buf, retlen);
> +	mutex_unlock(&spinand->lock);
> +
> +	return ret;
> +}
> +
> +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;
> +	int ret;
> +
> +	if (!len)
> +		return 0;
> +
> +	ret = spinand_otp_check_bounds(spinand, ofs, len);
> +	if (ret)
> +		return ret;
> +
> +	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)) {
> +		pr_warn(1, "Can not disable OTP mode\n");

dev_warn?

> +		ret = -EIO;
> +	}
> +
> +out_unlock:
> +	mutex_unlock(&spinand->lock);
> +	return ret;
> +}
> +
> +static int spinand_mtd_otp_read(struct mtd_info *mtd, loff_t ofs, size_t len,
> +				size_t *retlen, u8 *buf)
> +{
> +	return spinand_mtd_otp_rw(mtd, ofs, len, retlen, buf, false);
> +}
> +
> +static int spinand_mtd_otp_write(struct mtd_info *mtd, loff_t ofs, size_t len,
> +				 size_t *retlen, const u8 *buf)
> +{
> +	return spinand_mtd_otp_rw(mtd, ofs, len, retlen, (u8 *)buf, true);
> +}
> +
> +static int spinand_mtd_otp_erase(struct mtd_info *mtd, loff_t ofs, 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;
> +
> +	ret = spinand_otp_check_bounds(spinand, ofs, len);
> +	if (ret)
> +		return ret;
> +
> +	mutex_lock(&spinand->lock);
> +	ret = ops->erase(spinand, ofs, len);
> +	mutex_unlock(&spinand->lock);
> +
> +	return ret;
> +}
> +
> +static int spinand_mtd_otp_lock(struct mtd_info *mtd, loff_t ofs, 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 (!len)
> +		return 0;
> +
> +	ret = spinand_otp_check_bounds(spinand, ofs, len);
> +	if (ret)
> +		return ret;
> +
> +	mutex_lock(&spinand->lock);
> +	ret = ops->lock(spinand, ofs, 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)

Could we use something else as check? It feels odd to check for otp ops
and then just ignore the fact that they are here. Maybe check npages or
otp_size() ?

> +		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..8099f35f0e051 100644
> --- a/include/linux/mtd/spinand.h
> +++ b/include/linux/mtd/spinand.h
> @@ -322,6 +322,43 @@ struct spinand_ondie_ecc_conf {
>  	u8 status;
>  };

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 v2 2/5] mtd: spinand: add OTP support
Date: Tue, 1 Oct 2024 11:12:25 +0200	[thread overview]
Message-ID: <20241001111225.36cb9701@xps-13> (raw)
In-Reply-To: <20240827174920.316756-3-mmkurbanov@salutedevices.com>

Hi Martin,

mmkurbanov@salutedevices.com wrote on Tue, 27 Aug 2024 20:49:00 +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().

Overall this looks good, I have minor changes to request. I'm not yet
done down to the last patch, but I think the implementation is neat.

> 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    | 232 ++++++++++++++++++++++++++++++++++
>  include/linux/mtd/spinand.h   |  56 ++++++++
>  4 files changed, 293 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..d459f811f9c04
> --- /dev/null
> +++ b/drivers/mtd/nand/spi/otp.c
> @@ -0,0 +1,232 @@
> +// 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 unsigned int spinand_otp_npages(const struct spinand_device *spinand)
> +{
> +	return spinand->otp->layout.npages;
> +}
> +
> +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_npages(spinand) * otp_pagesize;
> +}
> +
> +static int spinand_otp_rw(struct spinand_device *spinand, loff_t ofs,
> +			  size_t len, u8 *buf, size_t *retlen, bool is_write)
> +{
> +	struct nand_device *nand = spinand_to_nand(spinand);
> +	struct nand_page_io_req req = { 0 };

					= {}; is enough

> +	unsigned long long page;
> +	size_t copied = 0;
> +	size_t otp_pagesize = nanddev_page_size(nand) +
> +			      nanddev_per_page_oobsize(nand);
> +	int ret = 0;
> +
> +	page = ofs;
> +	req.dataoffs = do_div(page, otp_pagesize);
> +	req.pos.page = page;
> +	req.type = is_write ? NAND_PAGE_WRITE : NAND_PAGE_READ;
> +	req.mode = MTD_OPS_RAW;
> +	req.databuf.in = buf;
> +
> +	while (copied < len && req.pos.page < spinand_otp_npages(spinand)) {
> +		req.datalen = min_t(unsigned int,
> +				    otp_pagesize - req.dataoffs,
> +				    len - copied);
> +
> +		if (is_write)
> +			ret = spinand_write_page(spinand, &req);
> +		else
> +			ret = spinand_read_page(spinand, &req);
> +
> +		if (ret < 0)
> +			break;
> +
> +		req.dataoffs = 0;
> +		copied += req.datalen;
> +		req.pos.page++;
> +	}
> +
> +	*retlen = copied;
> +
> +	return ret;
> +}
> +
> +/**
> + * spinand_otp_read() - Read from OTP area
> + * @spinand: the spinand device
> + * @ofs: the offset to read
> + * @len: the number of data bytes to read
> + * @buf: the buffer to store the read data
> + * @retlen: the pointer to variable to store the number of read bytes
> + *
> + * Return: 0 on success, an error code otherwise.
> + */
> +int spinand_otp_read(struct spinand_device *spinand, loff_t ofs, size_t len,
> +		     u8 *buf, size_t *retlen)
> +{
> +	return spinand_otp_rw(spinand, ofs, len, buf, retlen, false);
> +}
> +
> +/**
> + * spinand_otp_write() - Write to OTP area
> + * @spinand:  the spinand device
> + * @ofs: the offset to write to
> + * @len: the number of bytes to write
> + * @buf: the buffer with data to write
> + * @retlen: the pointer to variable to store the number of written bytes
> + *
> + * Return: 0 on success, an error code otherwise.
> + */
> +int spinand_otp_write(struct spinand_device *spinand, loff_t ofs, size_t len,
> +		      const u8 *buf, size_t *retlen)
> +{
> +	return spinand_otp_rw(spinand, ofs, len, (u8 *)buf, retlen, true);
> +}

These spinand_otp_xxx() helpers are not yet used, and thus should be
introduced later, when they are useful.

> +
> +static int spinand_otp_check_bounds(struct spinand_device *spinand, loff_t ofs,
> +				    size_t len)
> +{
> +	if (ofs < 0 || ofs + len > spinand_otp_size(spinand))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int spinand_mtd_otp_info(struct mtd_info *mtd, size_t len,
> +				size_t *retlen, struct otp_info *buf)
> +{
> +	struct spinand_device *spinand = mtd_to_spinand(mtd);
> +	const struct spinand_otp_ops *ops = spinand->otp->ops;
> +	int ret;
> +
> +	mutex_lock(&spinand->lock);
> +	ret = ops->info(spinand, len, buf, retlen);
> +	mutex_unlock(&spinand->lock);
> +
> +	return ret;
> +}
> +
> +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;
> +	int ret;
> +
> +	if (!len)
> +		return 0;
> +
> +	ret = spinand_otp_check_bounds(spinand, ofs, len);
> +	if (ret)
> +		return ret;
> +
> +	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)) {
> +		pr_warn(1, "Can not disable OTP mode\n");

dev_warn?

> +		ret = -EIO;
> +	}
> +
> +out_unlock:
> +	mutex_unlock(&spinand->lock);
> +	return ret;
> +}
> +
> +static int spinand_mtd_otp_read(struct mtd_info *mtd, loff_t ofs, size_t len,
> +				size_t *retlen, u8 *buf)
> +{
> +	return spinand_mtd_otp_rw(mtd, ofs, len, retlen, buf, false);
> +}
> +
> +static int spinand_mtd_otp_write(struct mtd_info *mtd, loff_t ofs, size_t len,
> +				 size_t *retlen, const u8 *buf)
> +{
> +	return spinand_mtd_otp_rw(mtd, ofs, len, retlen, (u8 *)buf, true);
> +}
> +
> +static int spinand_mtd_otp_erase(struct mtd_info *mtd, loff_t ofs, 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;
> +
> +	ret = spinand_otp_check_bounds(spinand, ofs, len);
> +	if (ret)
> +		return ret;
> +
> +	mutex_lock(&spinand->lock);
> +	ret = ops->erase(spinand, ofs, len);
> +	mutex_unlock(&spinand->lock);
> +
> +	return ret;
> +}
> +
> +static int spinand_mtd_otp_lock(struct mtd_info *mtd, loff_t ofs, 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 (!len)
> +		return 0;
> +
> +	ret = spinand_otp_check_bounds(spinand, ofs, len);
> +	if (ret)
> +		return ret;
> +
> +	mutex_lock(&spinand->lock);
> +	ret = ops->lock(spinand, ofs, 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)

Could we use something else as check? It feels odd to check for otp ops
and then just ignore the fact that they are here. Maybe check npages or
otp_size() ?

> +		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..8099f35f0e051 100644
> --- a/include/linux/mtd/spinand.h
> +++ b/include/linux/mtd/spinand.h
> @@ -322,6 +322,43 @@ struct spinand_ondie_ecc_conf {
>  	u8 status;
>  };

Thanks,
Miquèl

  parent reply	other threads:[~2024-10-01  9:12 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-08-27 17:48 [PATCH v2 0/5] mtd: spinand: add OTP support Martin Kurbanov
2024-08-27 17:48 ` Martin Kurbanov
2024-08-27 17:48 ` [PATCH v2 1/5] mtd: spinand: make spinand_{read,write}_page global Martin Kurbanov
2024-08-27 17:48   ` Martin Kurbanov
2024-10-01  9:12   ` Miquel Raynal
2024-10-01  9:12     ` Miquel Raynal
2024-08-27 17:49 ` [PATCH v2 2/5] mtd: spinand: add OTP support Martin Kurbanov
2024-08-27 17:49   ` Martin Kurbanov
2024-08-27 17:57   ` Martin Kurbanov
2024-08-27 17:57     ` Martin Kurbanov
2024-09-02 14:18     ` Miquel Raynal
2024-09-02 14:18       ` Miquel Raynal
2024-10-01  9:12   ` Miquel Raynal [this message]
2024-10-01  9:12     ` Miquel Raynal
2024-10-14 12:27     ` Martin Kurbanov
2024-10-14 12:27       ` Martin Kurbanov
2024-10-25  7:48       ` Miquel Raynal
2024-10-25  7:48         ` Miquel Raynal
2024-08-27 17:49 ` [PATCH v2 3/5] mtd: spinand: make spinand_wait() global Martin Kurbanov
2024-08-27 17:49   ` Martin Kurbanov
2024-08-27 17:49 ` [PATCH v2 4/5] mtd: spinand: micron: OTP access for MT29F2G01ABAGD Martin Kurbanov
2024-08-27 17:49   ` Martin Kurbanov
2024-10-01  9:31   ` Miquel Raynal
2024-10-01  9:31     ` Miquel Raynal
2024-10-14 12:48     ` Martin Kurbanov
2024-10-14 12:48       ` Martin Kurbanov
2024-10-25  7:51       ` Miquel Raynal
2024-10-25  7:51         ` Miquel Raynal
2024-08-27 17:49 ` [PATCH v2 5/5] mtd: spinand: esmt: OTP access for F50{L,D}1G41LB Martin Kurbanov
2024-08-27 17:49   ` Martin Kurbanov
2024-10-01  9:32   ` Miquel Raynal
2024-10-01  9:32     ` Miquel Raynal

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=20241001111225.36cb9701@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.