From nobody Mon Feb 9 07:39:36 2026 Received: from mx1.sberdevices.ru (mx1.sberdevices.ru [37.18.73.165]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 74884FC08 for ; Mon, 27 Jan 2025 15:39:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=37.18.73.165 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737992365; cv=none; b=UspZNWqI7nlBLl8XHZzmRHM6dU0G65lYGY89FuyvFssM1Xq71+uWbf1qzMvgWg6g3UWJdVqSPtFhZ8s+iKhGDRBdSFdtrrd0Gasohvvljr0tHAuAn6XTsZcLfqX8948/iXNC4vacEVu7XDXQyp1zEwAlhKm0SzN8YeGQajT9zlE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737992365; c=relaxed/simple; bh=hFvV4WF4vbXUDaE9q6/CEbRkGWQTVOB8XLq8jF0ygqs=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=K4X2ZmI0H5jJ779BF3IHxhY9X7hoEkq46FsOjOBTd5COuhalpMxhhKz8Lks8bYr2L2AR6gtBEaHlvMpZjw/yYOrR16XBqlGQe5zwnUdjGOSpgtsgiWnN5sxlwF3DwbxpKQ6WgexV/ut42y1Kk+jg0cjbmc+BeFBtW793wdU2dY0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=salutedevices.com; spf=pass smtp.mailfrom=salutedevices.com; dkim=pass (2048-bit key) header.d=salutedevices.com header.i=@salutedevices.com header.b=C5umvKqr; arc=none smtp.client-ip=37.18.73.165 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=salutedevices.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=salutedevices.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=salutedevices.com header.i=@salutedevices.com header.b="C5umvKqr" Received: from p-infra-ksmg-sc-msk01.sberdevices.ru (localhost [127.0.0.1]) by mx1.sberdevices.ru (Postfix) with ESMTP id 18B17100003; Mon, 27 Jan 2025 18:39:14 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.sberdevices.ru 18B17100003 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=salutedevices.com; s=mail; t=1737992354; bh=k4zRURgP6TcAjGzDVbgsDqd5SL1Hrj9IcGlTfuA8tNY=; h=From:To:Subject:Date:Message-ID:MIME-Version:Content-Type:From; b=C5umvKqrPk5rchByxzS3i+Ksy70ymvPNFZh+CZNlw/g85gDVKpN/5HCtgbazUeEgb QpH4oj9yDUnJIOR1RAoylz2ERTLG4HTlKTAVqmFGwnZv99rNGrztoAsskY11lZXcgK +4L+0gz4WAItth2BASbVQRtEkZ3XkaPcrKu2UJqB05qj8ZuRBlIr3G/d2JVzZhWPdI bgWHjnkGYvAdRJa+GdXWvxADuH9xh20DWLwaGIIAy+x0RgciPKQJAtN1TGfTwcLXvx OltJAzUNjWSPON0/4cXHhunhRp0+LZ7XvpycAB1rjw/JiWM2XChuQ1129JrDQKELsH XEG/zFlvUuqUA== Received: from smtp.sberdevices.ru (p-i-exch-sc-m01.sberdevices.ru [172.16.192.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.sberdevices.ru (Postfix) with ESMTPS; Mon, 27 Jan 2025 18:39:13 +0300 (MSK) From: Martin Kurbanov To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Ezra Buehler , Cheng Ming Lin , Pratyush Yadav , Daniel Golle , Frieder Schrempf , Alexey Romanov CC: , , , Martin Kurbanov Subject: [PATCH v4 1/6] mtd: spinand: make spinand_{read,write}_page global Date: Mon, 27 Jan 2025 18:38:19 +0300 Message-ID: <20250127153848.199526-2-mmkurbanov@salutedevices.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250127153848.199526-1-mmkurbanov@salutedevices.com> References: <20250127153848.199526-1-mmkurbanov@salutedevices.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: p-i-exch-a-m1.sberdevices.ru (172.24.196.116) To p-i-exch-sc-m01.sberdevices.ru (172.16.192.107) X-KSMG-Rule-ID: 10 X-KSMG-Message-Action: clean X-KSMG-AntiSpam-Lua-Profiles: 190596 [Jan 27 2025] X-KSMG-AntiSpam-Version: 6.1.1.7 X-KSMG-AntiSpam-Envelope-From: mmkurbanov@salutedevices.com X-KSMG-AntiSpam-Rate: 0 X-KSMG-AntiSpam-Status: not_detected X-KSMG-AntiSpam-Method: none X-KSMG-AntiSpam-Auth: dkim=none X-KSMG-AntiSpam-Info: LuaCore: 50 0.3.50 df4aeb250ed63fd3baa80a493fa6caee5dd9e10f, {Tracking_from_domain_doesnt_match_to}, salutedevices.com:7.1.1;smtp.sberdevices.ru:5.0.1,7.1.1;d41d8cd98f00b204e9800998ecf8427e.com:7.1.1;127.0.0.199:7.1.2, FromAlignment: s X-MS-Exchange-Organization-SCL: -1 X-KSMG-AntiSpam-Interceptor-Info: scan successful X-KSMG-AntiPhishing: Clean X-KSMG-LinksScanning: Clean X-KSMG-AntiVirus: Kaspersky Secure Mail Gateway, version 2.0.1.6960, bases: 2025/01/27 09:37:00 #27129213 X-KSMG-AntiVirus-Status: Clean, skipped Content-Type: text/plain; charset="utf-8" Change these functions from static to global so that to use them later in OTP operations. Since reading OTP pages is no different from reading pages from the main area. Signed-off-by: Martin Kurbanov --- drivers/mtd/nand/spi/core.c | 24 ++++++++++++++++++++---- include/linux/mtd/spinand.h | 6 ++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 4d76f9f71a0e9..d55d1b544bc9d 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -601,8 +601,16 @@ static int spinand_lock_block(struct spinand_device *s= pinand, u8 lock) return spinand_write_reg_op(spinand, REG_BLOCK_LOCK, lock); } =20 -static int spinand_read_page(struct spinand_device *spinand, - const struct nand_page_io_req *req) +/** + * spinand_read_page() - Read a page + * @spinand: the spinand device + * @req: the I/O request + * + * Return: 0 or a positive number of bitflips corrected on success. + * A negative error code otherwise. + */ +int spinand_read_page(struct spinand_device *spinand, + const struct nand_page_io_req *req) { struct nand_device *nand =3D spinand_to_nand(spinand); u8 status; @@ -632,8 +640,16 @@ static int spinand_read_page(struct spinand_device *sp= inand, return nand_ecc_finish_io_req(nand, (struct nand_page_io_req *)req); } =20 -static int spinand_write_page(struct spinand_device *spinand, - const struct nand_page_io_req *req) +/** + * spinand_write_page() - Write a page + * @spinand: the spinand device + * @req: the I/O request + * + * Return: 0 or a positive number of bitflips corrected on success. + * A negative error code otherwise. + */ +int spinand_write_page(struct spinand_device *spinand, + const struct nand_page_io_req *req) { struct nand_device *nand =3D spinand_to_nand(spinand); u8 status; diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index 702e5fb13dae7..383c197e32c68 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -538,4 +538,10 @@ int spinand_upd_cfg(struct spinand_device *spinand, u8= mask, u8 val); int spinand_write_reg_op(struct spinand_device *spinand, u8 reg, u8 val); int spinand_select_target(struct spinand_device *spinand, unsigned int tar= get); =20 +int spinand_read_page(struct spinand_device *spinand, + const struct nand_page_io_req *req); + +int spinand_write_page(struct spinand_device *spinand, + const struct nand_page_io_req *req); + #endif /* __LINUX_MTD_SPINAND_H */ --=20 2.43.0 From nobody Mon Feb 9 07:39:36 2026 Received: from mx1.sberdevices.ru (mx2.sberdevices.ru [45.89.224.132]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7F564126C16 for ; Mon, 27 Jan 2025 15:39:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.89.224.132 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737992366; cv=none; b=p9MVaejoidJd6f05wacbUrO3EnKi5w8il1my43rSscaayZrtD+iXi0o0Z6CY2fyfvUVW7yl62JDnMNQ4wr0r7Z3UrndVizJAKACh/k80HQQB8iOfez9d0676K2YNKcLqvcmcXPAxMoFoTSOUj4l8DGuj5kfUgad0en+ZzDlq27o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737992366; c=relaxed/simple; bh=T17D04DNKDmr2TZaUQhB6FdCH3Cy8hKF2bOGnnUE66s=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=CdLVdZH6MqksZCF7ELWMHDd4jO6qOY1772VxFU5iPoNTnev2nIzFDE+iRV2yCIjsdQdxxiL3twjhmP3n68tIZfRgf2udwdtlK0BCYXOQzvvLFkrDgFJYx2RMdplUGqk/QnHOr2zJwHtCaXUr6XTopdacYr2CxprmmNMiLoQIaLw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=salutedevices.com; spf=pass smtp.mailfrom=salutedevices.com; dkim=pass (2048-bit key) header.d=salutedevices.com header.i=@salutedevices.com header.b=IdradAjc; arc=none smtp.client-ip=45.89.224.132 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=salutedevices.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=salutedevices.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=salutedevices.com header.i=@salutedevices.com header.b="IdradAjc" Received: from p-infra-ksmg-sc-msk02.sberdevices.ru (localhost [127.0.0.1]) by mx1.sberdevices.ru (Postfix) with ESMTP id 69FC5120005; Mon, 27 Jan 2025 18:39:14 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.sberdevices.ru 69FC5120005 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=salutedevices.com; s=mail; t=1737992354; bh=rfZUMe/Lq73MhlTc4B5nAsWHePz8GDyDkimpHdbSnBI=; h=From:To:Subject:Date:Message-ID:MIME-Version:Content-Type:From; b=IdradAjcYkVMJCFEPbz17txbL35kNnP42HygVgMwNiWG7n2gketQlLM1kRTHNoeYt 5g+PbBXVBCGX6PIl5GIKNLnum7lrUthUQN8fF0nkCfjXSzZkqvztIIUjblrS3LbYEJ qDighqLjBSLDHQorQCCGXyBzY9MdBkIadpyEOnQ2Q59yPs13LYQtBFgPRXcUFRrBqW mc01/YbMgz+A25fafEaJfcI7o6oFnMB458f0A7TFVdUGY5t+EjtkW7i2mBD66gEgIU y5vCFpyinq0qEQJKGTNHCSPCuqoptXQMgyRQ19PTg2ZwYH0e+hhegbb0g50BGNzG9J BiRKY+vmr1yKw== Received: from smtp.sberdevices.ru (p-i-exch-sc-m01.sberdevices.ru [172.16.192.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.sberdevices.ru (Postfix) with ESMTPS; Mon, 27 Jan 2025 18:39:14 +0300 (MSK) From: Martin Kurbanov To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Ezra Buehler , Cheng Ming Lin , Pratyush Yadav , Daniel Golle , Frieder Schrempf , Alexey Romanov CC: , , , Martin Kurbanov Subject: [PATCH v4 2/6] mtd: spinand: add OTP support Date: Mon, 27 Jan 2025 18:38:20 +0300 Message-ID: <20250127153848.199526-3-mmkurbanov@salutedevices.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250127153848.199526-1-mmkurbanov@salutedevices.com> References: <20250127153848.199526-1-mmkurbanov@salutedevices.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: p-i-exch-a-m1.sberdevices.ru (172.24.196.116) To p-i-exch-sc-m01.sberdevices.ru (172.16.192.107) X-KSMG-Rule-ID: 10 X-KSMG-Message-Action: clean X-KSMG-AntiSpam-Lua-Profiles: 190599 [Jan 27 2025] X-KSMG-AntiSpam-Version: 6.1.1.7 X-KSMG-AntiSpam-Envelope-From: mmkurbanov@salutedevices.com X-KSMG-AntiSpam-Rate: 0 X-KSMG-AntiSpam-Status: not_detected X-KSMG-AntiSpam-Method: none X-KSMG-AntiSpam-Auth: dkim=none X-KSMG-AntiSpam-Info: LuaCore: 50 0.3.50 df4aeb250ed63fd3baa80a493fa6caee5dd9e10f, {Tracking_from_domain_doesnt_match_to}, salutedevices.com:7.1.1;127.0.0.199:7.1.2;d41d8cd98f00b204e9800998ecf8427e.com:7.1.1;smtp.sberdevices.ru:5.0.1,7.1.1, FromAlignment: s X-MS-Exchange-Organization-SCL: -1 X-KSMG-AntiSpam-Interceptor-Info: scan successful X-KSMG-AntiPhishing: Clean X-KSMG-LinksScanning: Clean X-KSMG-AntiVirus: Kaspersky Secure Mail Gateway, version 2.0.1.6960, bases: 2025/01/27 13:50:00 #27131010 X-KSMG-AntiVirus-Status: Clean, skipped Content-Type: text/plain; charset="utf-8" The MTD subsystem already supports accessing two OTP areas: user and factory. User areas can be written by the user. This patch provides the SPINAND_FACT_OTP_INFO and SPINAND_USER_OTP_INFO macros to add parameters to spinand_info. To implement OTP operations, the client (flash driver) is provided with callbacks for user area: .read(), .write(), .info(), .lock(), .erase(); and for factory area: .read(), .info(); Signed-off-by: Martin Kurbanov --- drivers/mtd/nand/spi/Makefile | 3 +- drivers/mtd/nand/spi/core.c | 8 ++ drivers/mtd/nand/spi/otp.c | 244 ++++++++++++++++++++++++++++++++++ include/linux/mtd/spinand.h | 93 +++++++++++++ 4 files changed, 347 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 :=3D core.o alliancememory.o ato.o esmt.o foresee.o gigadevic= e.o macronix.o +spinand-objs :=3D core.o otp.o +spinand-objs +=3D alliancememory.o ato.o esmt.o foresee.o gigadevice.o mac= ronix.o spinand-objs +=3D micron.o paragon.o toshiba.o winbond.o xtx.o obj-$(CONFIG_MTD_SPI_NAND) +=3D spinand.o diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index d55d1b544bc9d..832ac36666edb 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -1284,6 +1284,8 @@ int spinand_match_and_init(struct spinand_device *spi= nand, spinand->id.len =3D 1 + table[i].devid.len; spinand->select_target =3D table[i].select_target; spinand->set_cont_read =3D table[i].set_cont_read; + spinand->fact_otp =3D &table[i].fact_otp; + spinand->user_otp =3D &table[i].user_otp; =20 op =3D spinand_select_op_variant(spinand, info->op_variants.read_cache); @@ -1470,6 +1472,12 @@ static int spinand_init(struct spinand_device *spina= nd) mtd->_max_bad_blocks =3D nanddev_mtd_max_bad_blocks; mtd->_resume =3D spinand_mtd_resume; =20 + if (spinand_user_otp_size(spinand) || spinand_fact_otp_size(spinand)) { + ret =3D spinand_set_mtd_otp_ops(spinand); + if (ret) + goto err_cleanup_ecc_engine; + } + if (nand->ecc.engine) { ret =3D 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..d465dced554c4 --- /dev/null +++ b/drivers/mtd/nand/spi/otp.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024, SaluteDevices. All Rights Reserved. + * + * Author: Martin Kurbanov + */ + +#include +#include + +static size_t spinand_otp_size(struct spinand_device *spinand, + const struct spinand_otp_layout *layout) +{ + struct nand_device *nand =3D spinand_to_nand(spinand); + size_t otp_pagesize =3D nanddev_page_size(nand) + + nanddev_per_page_oobsize(nand); + + return layout->npages * otp_pagesize; +} + +/** + * spinand_fact_otp_size() - Get SPI-NAND factory OTP area size + * @spinand: the spinand device + * + * Return: the OTP size. + */ +size_t spinand_fact_otp_size(struct spinand_device *spinand) +{ + return spinand_otp_size(spinand, &spinand->fact_otp->layout); +} + +/** + * spinand_user_otp_size() - Get SPI-NAND user OTP area size + * @spinand: the spinand device + * + * Return: the OTP size. + */ +size_t spinand_user_otp_size(struct spinand_device *spinand) +{ + return spinand_otp_size(spinand, &spinand->user_otp->layout); +} + +static int spinand_otp_check_bounds(struct spinand_device *spinand, loff_t= ofs, + size_t len, + const struct spinand_otp_layout *layout) +{ + if (ofs < 0 || ofs + len > spinand_otp_size(spinand, layout)) + return -EINVAL; + + return 0; +} + +static int spinand_user_otp_check_bounds(struct spinand_device *spinand, + loff_t ofs, size_t len) +{ + return spinand_otp_check_bounds(spinand, ofs, len, + &spinand->user_otp->layout); +} + +static int spinand_mtd_otp_info(struct mtd_info *mtd, size_t len, + size_t *retlen, struct otp_info *buf, + bool is_fact) +{ + struct spinand_device *spinand =3D mtd_to_spinand(mtd); + int ret; + + *retlen =3D 0; + + mutex_lock(&spinand->lock); + + if (is_fact) + ret =3D spinand->fact_otp->ops->info(spinand, len, buf, retlen); + else + ret =3D spinand->user_otp->ops->info(spinand, len, buf, retlen); + + mutex_unlock(&spinand->lock); + + return ret; +} + +static int spinand_mtd_fact_otp_info(struct mtd_info *mtd, size_t len, + size_t *retlen, struct otp_info *buf) +{ + return spinand_mtd_otp_info(mtd, len, retlen, buf, true); +} + +static int spinand_mtd_user_otp_info(struct mtd_info *mtd, size_t len, + size_t *retlen, struct otp_info *buf) +{ + return spinand_mtd_otp_info(mtd, len, retlen, buf, false); +} + +static int spinand_mtd_otp_read(struct mtd_info *mtd, loff_t ofs, size_t l= en, + size_t *retlen, u8 *buf, bool is_fact) +{ + struct spinand_device *spinand =3D mtd_to_spinand(mtd); + int ret; + + *retlen =3D 0; + + if (!len) + return 0; + + ret =3D spinand_otp_check_bounds(spinand, ofs, len, + is_fact ? &spinand->fact_otp->layout : + &spinand->user_otp->layout); + if (ret) + return ret; + + mutex_lock(&spinand->lock); + + if (is_fact) + ret =3D spinand->fact_otp->ops->read(spinand, ofs, len, retlen, + buf); + else + ret =3D spinand->user_otp->ops->read(spinand, ofs, len, retlen, + buf); + + mutex_unlock(&spinand->lock); + + return ret; +} + +static int spinand_mtd_fact_otp_read(struct mtd_info *mtd, loff_t ofs, + size_t len, size_t *retlen, u8 *buf) +{ + return spinand_mtd_otp_read(mtd, ofs, len, retlen, buf, true); +} + +static int spinand_mtd_user_otp_read(struct mtd_info *mtd, loff_t ofs, + size_t len, size_t *retlen, u8 *buf) +{ + return spinand_mtd_otp_read(mtd, ofs, len, retlen, buf, false); +} + +static int spinand_mtd_user_otp_write(struct mtd_info *mtd, loff_t ofs, + size_t len, size_t *retlen, const u8 *buf) +{ + struct spinand_device *spinand =3D mtd_to_spinand(mtd); + const struct spinand_user_otp_ops *ops =3D spinand->user_otp->ops; + int ret; + + *retlen =3D 0; + + if (!len) + return 0; + + ret =3D spinand_user_otp_check_bounds(spinand, ofs, len); + if (ret) + return ret; + + mutex_lock(&spinand->lock); + ret =3D ops->write(spinand, ofs, len, retlen, buf); + mutex_unlock(&spinand->lock); + + return ret; +} + +static int spinand_mtd_user_otp_erase(struct mtd_info *mtd, loff_t ofs, + size_t len) +{ + struct spinand_device *spinand =3D mtd_to_spinand(mtd); + const struct spinand_user_otp_ops *ops =3D spinand->user_otp->ops; + int ret; + + if (!len) + return 0; + + ret =3D spinand_user_otp_check_bounds(spinand, ofs, len); + if (ret) + return ret; + + mutex_lock(&spinand->lock); + ret =3D ops->erase(spinand, ofs, len); + mutex_unlock(&spinand->lock); + + return ret; +} + +static int spinand_mtd_user_otp_lock(struct mtd_info *mtd, loff_t ofs, + size_t len) +{ + struct spinand_device *spinand =3D mtd_to_spinand(mtd); + const struct spinand_user_otp_ops *ops =3D spinand->user_otp->ops; + int ret; + + if (!len) + return 0; + + ret =3D spinand_user_otp_check_bounds(spinand, ofs, len); + if (ret) + return ret; + + mutex_lock(&spinand->lock); + ret =3D ops->lock(spinand, ofs, len); + mutex_unlock(&spinand->lock); + + return ret; +} + +/** + * spinand_set_mtd_otp_ops() - Setup OTP methods + * @spinand: the spinand device + * + * Setup OTP methods. + * + * Return: 0 on success, a negative error code otherwise. + */ +int spinand_set_mtd_otp_ops(struct spinand_device *spinand) +{ + struct mtd_info *mtd =3D spinand_to_mtd(spinand); + const struct spinand_fact_otp_ops *fact_ops =3D spinand->fact_otp->ops; + const struct spinand_user_otp_ops *user_ops =3D spinand->user_otp->ops; + + if (!user_ops && !fact_ops) + return -EINVAL; + + if (user_ops) { + if (user_ops->info) + mtd->_get_user_prot_info =3D spinand_mtd_user_otp_info; + + if (user_ops->read) + mtd->_read_user_prot_reg =3D spinand_mtd_user_otp_read; + + if (user_ops->write) + mtd->_write_user_prot_reg =3D spinand_mtd_user_otp_write; + + if (user_ops->lock) + mtd->_lock_user_prot_reg =3D spinand_mtd_user_otp_lock; + + if (user_ops->erase) + mtd->_erase_user_prot_reg =3D spinand_mtd_user_otp_erase; + } + + if (fact_ops) { + if (fact_ops->info) + mtd->_get_fact_prot_info =3D spinand_mtd_fact_otp_info; + + if (fact_ops->read) + mtd->_read_fact_prot_reg =3D spinand_mtd_fact_otp_read; + } + + return 0; +} diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index 383c197e32c68..458bf4b0bea2d 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -324,6 +324,67 @@ struct spinand_ondie_ecc_conf { u8 status; }; =20 +/** + * struct spinand_otp_layout - structure to describe the SPI NAND OTP area + * @npages: number of pages in the OTP + * @start_page: start page of the user/factory OTP area. + */ +struct spinand_otp_layout { + unsigned int npages; + unsigned int start_page; +}; + +/** + * struct spinand_fact_otp_ops - SPI NAND OTP methods for factory area + * @info: get the OTP area information + * @read: read from the SPI NAND OTP area + */ +struct spinand_fact_otp_ops { + int (*info)(struct spinand_device *spinand, size_t len, + struct otp_info *buf, size_t *retlen); + int (*read)(struct spinand_device *spinand, loff_t from, size_t len, + size_t *retlen, u8 *buf); +}; + +/** + * struct spinand_user_otp_ops - SPI NAND OTP methods for user area + * @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_user_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, + size_t *retlen, u8 *buf); + int (*write)(struct spinand_device *spinand, loff_t from, size_t len, + size_t *retlen, const u8 *buf); +}; + +/** + * struct spinand_fact_otp - SPI NAND OTP grouping structure for factory a= rea + * @layout: OTP region layout + * @ops: OTP access ops + */ +struct spinand_fact_otp { + const struct spinand_otp_layout layout; + const struct spinand_fact_otp_ops *ops; +}; + +/** + * struct spinand_user_otp - SPI NAND OTP grouping structure for user area + * @layout: OTP region layout + * @ops: OTP access ops + */ +struct spinand_user_otp { + const struct spinand_otp_layout layout; + const struct spinand_user_otp_ops *ops; +}; + /** * struct spinand_info - Structure used to describe SPI NAND chips * @model: model name @@ -339,6 +400,8 @@ struct spinand_ondie_ecc_conf { * @select_target: function used to select a target/die. Required only for * multi-die chips * @set_cont_read: enable/disable continuous cached reads + * @fact_otp: SPI NAND factory OTP info. + * @user_otp: SPI NAND user OTP info. * * Each SPI NAND manufacturer driver should have a spinand_info table * describing all the chips supported by the driver. @@ -359,6 +422,8 @@ struct spinand_info { unsigned int target); int (*set_cont_read)(struct spinand_device *spinand, bool enable); + struct spinand_fact_otp fact_otp; + struct spinand_user_otp user_otp; }; =20 #define SPINAND_ID(__method, ...) \ @@ -387,6 +452,24 @@ struct spinand_info { #define SPINAND_CONT_READ(__set_cont_read) \ .set_cont_read =3D __set_cont_read, =20 +#define SPINAND_FACT_OTP_INFO(__npages, __start_page, __ops) \ + .fact_otp =3D { \ + .layout =3D { \ + .npages =3D __npages, \ + .start_page =3D __start_page, \ + }, \ + .ops =3D __ops, \ + } + +#define SPINAND_USER_OTP_INFO(__npages, __start_page, __ops) \ + .user_otp =3D { \ + .layout =3D { \ + .npages =3D __npages, \ + .start_page =3D __start_page, \ + }, \ + .ops =3D __ops, \ + } + #define SPINAND_INFO(__model, __id, __memorg, __eccreq, __op_variants, \ __flags, ...) \ { \ @@ -437,6 +520,8 @@ struct spinand_dirmap { * actually relevant to enable this feature. * @set_cont_read: Enable/disable the continuous read feature * @priv: manufacturer private data + * @fact_otp: SPI NAND factory OTP info. + * @user_otp: SPI NAND user OTP info. */ struct spinand_device { struct nand_device base; @@ -469,6 +554,9 @@ struct spinand_device { bool cont_read_possible; int (*set_cont_read)(struct spinand_device *spinand, bool enable); + + const struct spinand_fact_otp *fact_otp; + const struct spinand_user_otp *user_otp; }; =20 /** @@ -544,4 +632,9 @@ int spinand_read_page(struct spinand_device *spinand, int spinand_write_page(struct spinand_device *spinand, const struct nand_page_io_req *req); =20 +size_t spinand_fact_otp_size(struct spinand_device *spinand); +size_t spinand_user_otp_size(struct spinand_device *spinand); + +int spinand_set_mtd_otp_ops(struct spinand_device *spinand); + #endif /* __LINUX_MTD_SPINAND_H */ --=20 2.43.0 From nobody Mon Feb 9 07:39:36 2026 Received: from mx1.sberdevices.ru (mx2.sberdevices.ru [45.89.224.132]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DF28213B5B6 for ; Mon, 27 Jan 2025 15:39:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.89.224.132 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737992368; cv=none; b=aZLldI0jL27kJfY3lewgXGnV4Y+X+Pa/OOmUcvB6lt5U+5+UHshyDSmeSccKbCt4cZ7llWKNbORD8uTHHvk6Nz5+S4MnAhsZj/R9VyiAE9IMpGDe15ck9jtEUfh9Uok4YU9pN51fDSGRjyU0r5MR8JwBAZeNT5WxyVNOg/xRTEs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737992368; c=relaxed/simple; bh=hWuXQjnvcDxKcH9tsZZopRYEFLapyMDZQyKCVkkHckU=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=GrGBMz0wbDoihM81O1/9eV2Qp584gs+/j24vDxQG8Q6kofs2yfOCBxUGB1AHVdC/RglR1k5771Cmz5HsdsdgX4O0IA2aQFZBjeKufz4uQRHjfCRE32iIu3F75vsKNAtJELBiD7kWzs3rwqkcre6JTOmjAnIT4DQJ9CZmf9iMBmM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=salutedevices.com; spf=pass smtp.mailfrom=salutedevices.com; dkim=pass (2048-bit key) header.d=salutedevices.com header.i=@salutedevices.com header.b=q6LJSEqD; arc=none smtp.client-ip=45.89.224.132 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=salutedevices.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=salutedevices.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=salutedevices.com header.i=@salutedevices.com header.b="q6LJSEqD" Received: from p-infra-ksmg-sc-msk02.sberdevices.ru (localhost [127.0.0.1]) by mx1.sberdevices.ru (Postfix) with ESMTP id 984FA12000A; Mon, 27 Jan 2025 18:39:14 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.sberdevices.ru 984FA12000A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=salutedevices.com; s=mail; t=1737992354; bh=NAdg8iOfY3hOQ3Sfvs8WLDdRB6CCC8PTCW8ddrTRSSA=; h=From:To:Subject:Date:Message-ID:MIME-Version:Content-Type:From; b=q6LJSEqD0cvAU99NfqCcRTxpf4dl9lX5ROnJO3+jZHSKhzZjr930YiqJ93fjrENdU otkeC1QuhAzefS0/B/cI9ng9mmv2IRC99VXHShQftvBLPMOEqSLmLlF4+XQXqqERch mYxYF+hfk3bp91Eu5CqRGQJ/u/uD63+zEjgte9171XVWSCJjIRLn1jNIGvRM7E6q95 Dd6gQgpHBuGRV7VOWYR9oTzf317HgquudQH6YFRkbPDW1ce5csPIBi8sIuJDYoF/EX tmFEv/bIl7o85dteGTtH6kBQD0ztVP9fTWpYU0xZHVHgrE/LyOimrBIJ0Apqn66QsV tVnhrcz3RhtKw== Received: from smtp.sberdevices.ru (p-i-exch-sc-m01.sberdevices.ru [172.16.192.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.sberdevices.ru (Postfix) with ESMTPS; Mon, 27 Jan 2025 18:39:14 +0300 (MSK) From: Martin Kurbanov To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Ezra Buehler , Cheng Ming Lin , Pratyush Yadav , Daniel Golle , Frieder Schrempf , Alexey Romanov CC: , , , Martin Kurbanov Subject: [PATCH v4 3/6] mtd: spinand: make spinand_{wait,otp_page_size} global Date: Mon, 27 Jan 2025 18:38:21 +0300 Message-ID: <20250127153848.199526-4-mmkurbanov@salutedevices.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250127153848.199526-1-mmkurbanov@salutedevices.com> References: <20250127153848.199526-1-mmkurbanov@salutedevices.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: p-i-exch-a-m1.sberdevices.ru (172.24.196.116) To p-i-exch-sc-m01.sberdevices.ru (172.16.192.107) X-KSMG-Rule-ID: 10 X-KSMG-Message-Action: clean X-KSMG-AntiSpam-Lua-Profiles: 190599 [Jan 27 2025] X-KSMG-AntiSpam-Version: 6.1.1.7 X-KSMG-AntiSpam-Envelope-From: mmkurbanov@salutedevices.com X-KSMG-AntiSpam-Rate: 0 X-KSMG-AntiSpam-Status: not_detected X-KSMG-AntiSpam-Method: none X-KSMG-AntiSpam-Auth: dkim=none X-KSMG-AntiSpam-Info: LuaCore: 50 0.3.50 df4aeb250ed63fd3baa80a493fa6caee5dd9e10f, {Tracking_from_domain_doesnt_match_to}, salutedevices.com:7.1.1;127.0.0.199:7.1.2;d41d8cd98f00b204e9800998ecf8427e.com:7.1.1;smtp.sberdevices.ru:5.0.1,7.1.1, FromAlignment: s X-MS-Exchange-Organization-SCL: -1 X-KSMG-AntiSpam-Interceptor-Info: scan successful X-KSMG-AntiPhishing: Clean X-KSMG-LinksScanning: Clean X-KSMG-AntiVirus: Kaspersky Secure Mail Gateway, version 2.0.1.6960, bases: 2025/01/27 13:50:00 #27131010 X-KSMG-AntiVirus-Status: Clean, skipped Content-Type: text/plain; charset="utf-8" Change the functions spinand_wait() and spinand_otp_page_size() from static to global so that SPI NAND flash drivers don't duplicate it. Signed-off-by: Martin Kurbanov --- drivers/mtd/nand/spi/core.c | 18 ++++++++++++++---- drivers/mtd/nand/spi/otp.c | 19 ++++++++++++++----- include/linux/mtd/spinand.h | 4 ++++ 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 832ac36666edb..0b5cddc4664ac 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -531,10 +531,20 @@ static int spinand_erase_op(struct spinand_device *sp= inand, return spi_mem_exec_op(spinand->spimem, &op); } =20 -static int spinand_wait(struct spinand_device *spinand, - unsigned long initial_delay_us, - unsigned long poll_delay_us, - u8 *s) +/** + * spinand_wait() - Poll memory device status + * @spinand: the spinand device + * @initial_delay_us: delay in us before starting to poll + * @poll_delay_us: time to sleep between reads in us + * @s: the pointer to variable to store the value of REG_STATUS + * + * This function polls a status register (REG_STATUS) and returns when + * the STATUS_READY bit is 0 or when the timeout has expired. + * + * Return: 0 on success, a negative error code otherwise. + */ +int spinand_wait(struct spinand_device *spinand, unsigned long initial_del= ay_us, + unsigned long poll_delay_us, u8 *s) { struct spi_mem_op op =3D SPINAND_GET_FEATURE_OP(REG_STATUS, spinand->scratchbuf); diff --git a/drivers/mtd/nand/spi/otp.c b/drivers/mtd/nand/spi/otp.c index d465dced554c4..1eb5677508ff8 100644 --- a/drivers/mtd/nand/spi/otp.c +++ b/drivers/mtd/nand/spi/otp.c @@ -8,14 +8,23 @@ #include #include =20 -static size_t spinand_otp_size(struct spinand_device *spinand, - const struct spinand_otp_layout *layout) +/** + * spinand_otp_page_size() - Get SPI-NAND OTP page size + * @spinand: the spinand device + * + * Return: the OTP page size. + */ +size_t spinand_otp_page_size(struct spinand_device *spinand) { struct nand_device *nand =3D spinand_to_nand(spinand); - size_t otp_pagesize =3D nanddev_page_size(nand) + - nanddev_per_page_oobsize(nand); =20 - return layout->npages * otp_pagesize; + return nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); +} + +static size_t spinand_otp_size(struct spinand_device *spinand, + const struct spinand_otp_layout *layout) +{ + return layout->npages * spinand_otp_page_size(spinand); } =20 /** diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index 458bf4b0bea2d..e0fdd3408ffa1 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -626,12 +626,16 @@ int spinand_upd_cfg(struct spinand_device *spinand, u= 8 mask, u8 val); int spinand_write_reg_op(struct spinand_device *spinand, u8 reg, u8 val); int spinand_select_target(struct spinand_device *spinand, unsigned int tar= get); =20 +int spinand_wait(struct spinand_device *spinand, unsigned long initial_del= ay_us, + unsigned long poll_delay_us, u8 *s); + int spinand_read_page(struct spinand_device *spinand, const struct nand_page_io_req *req); =20 int spinand_write_page(struct spinand_device *spinand, const struct nand_page_io_req *req); =20 +size_t spinand_otp_page_size(struct spinand_device *spinand); size_t spinand_fact_otp_size(struct spinand_device *spinand); size_t spinand_user_otp_size(struct spinand_device *spinand); =20 --=20 2.43.0 From nobody Mon Feb 9 07:39:36 2026 Received: from mx1.sberdevices.ru (mx2.sberdevices.ru [45.89.224.132]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8E5FA13541B for ; Mon, 27 Jan 2025 15:39:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.89.224.132 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737992366; cv=none; b=Ryhny6s14YNYmCXmN2I0Vc59FWhnXDENc0guiV9url1quXiMhJBEyy8fI3UN25qz5y3eeYjKg+dHKVHY/zykzDUA8UiEGSYv7a3U/SOadNdem0+B4C6wT0sjgP/cyLZzep+NZ6uT5LW4eTYVZOhIuNWG39x/+0SvY77cWNvi1Po= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737992366; c=relaxed/simple; bh=v6Gd5144s0SLusmhLMTjYQ9mzjQgHa+yqe8ZqFBAFeI=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=U5O9qr2lwf+nY8RaDdoaySowrCu6kjfp2okPpCXiJoPdzDTGt4/nGCdt67fgTfr5R79/DwuK6DQlJmfxkeOV71saTP4AiFB3l21ShU4YjgHjzg56soEOQhbU6CRkuzeFhupzpXq7Z8xjigMke82KXqv9+CVhFiJCy+rHxJylEYo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=salutedevices.com; spf=pass smtp.mailfrom=salutedevices.com; dkim=pass (2048-bit key) header.d=salutedevices.com header.i=@salutedevices.com header.b=fEO2ZArD; arc=none smtp.client-ip=45.89.224.132 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=salutedevices.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=salutedevices.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=salutedevices.com header.i=@salutedevices.com header.b="fEO2ZArD" Received: from p-infra-ksmg-sc-msk02.sberdevices.ru (localhost [127.0.0.1]) by mx1.sberdevices.ru (Postfix) with ESMTP id C6F7B12000C; Mon, 27 Jan 2025 18:39:14 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.sberdevices.ru C6F7B12000C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=salutedevices.com; s=mail; t=1737992354; bh=bKL1onzXan4crhgGkuR4R78sczemBBsrxY++TbfeZIw=; h=From:To:Subject:Date:Message-ID:MIME-Version:Content-Type:From; b=fEO2ZArDRAuyvuZOwLX3I7PJP9qsZYxzzZhiK4KtXoexKLSFVuaFo8ogac1F0dtdj +Q1cmEc0XpT0XQ3tx0FMxVqCXgbmh7PPW7KFieom6o49FRfNy5nLgpbJy4sbZIu6za Potyd/leGED0WNawbkE1uXWZ+v1HlkhKxvDKg+we212rMmw8/GWnqI2VLSw109eh6s WTZqTY/x+CzN2QHibtwY5Vc1hETOztH3CwGfRO6PYvVMfUv9nhJhx56N/fI2Z/0I9Z cYmxpZwtKpJ6ykktyQfK72s1Q7YF1PIeiNdWh9Xp/jwT9UHJwiHsWBiVbbUBuGzigP tX61hR2IYmk7Q== Received: from smtp.sberdevices.ru (p-i-exch-sc-m01.sberdevices.ru [172.16.192.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.sberdevices.ru (Postfix) with ESMTPS; Mon, 27 Jan 2025 18:39:14 +0300 (MSK) From: Martin Kurbanov To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Ezra Buehler , Cheng Ming Lin , Pratyush Yadav , Daniel Golle , Frieder Schrempf , Alexey Romanov CC: , , , Martin Kurbanov Subject: [PATCH v4 4/6] mtd: spinand: otp: add helpers functions Date: Mon, 27 Jan 2025 18:38:22 +0300 Message-ID: <20250127153848.199526-5-mmkurbanov@salutedevices.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250127153848.199526-1-mmkurbanov@salutedevices.com> References: <20250127153848.199526-1-mmkurbanov@salutedevices.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: p-i-exch-a-m1.sberdevices.ru (172.24.196.116) To p-i-exch-sc-m01.sberdevices.ru (172.16.192.107) X-KSMG-Rule-ID: 10 X-KSMG-Message-Action: clean X-KSMG-AntiSpam-Lua-Profiles: 190599 [Jan 27 2025] X-KSMG-AntiSpam-Version: 6.1.1.7 X-KSMG-AntiSpam-Envelope-From: mmkurbanov@salutedevices.com X-KSMG-AntiSpam-Rate: 0 X-KSMG-AntiSpam-Status: not_detected X-KSMG-AntiSpam-Method: none X-KSMG-AntiSpam-Auth: dkim=none X-KSMG-AntiSpam-Info: LuaCore: 50 0.3.50 df4aeb250ed63fd3baa80a493fa6caee5dd9e10f, {Tracking_from_domain_doesnt_match_to}, salutedevices.com:7.1.1;127.0.0.199:7.1.2;d41d8cd98f00b204e9800998ecf8427e.com:7.1.1;smtp.sberdevices.ru:5.0.1,7.1.1, FromAlignment: s X-MS-Exchange-Organization-SCL: -1 X-KSMG-AntiSpam-Interceptor-Info: scan successful X-KSMG-AntiPhishing: Clean X-KSMG-LinksScanning: Clean X-KSMG-AntiVirus: Kaspersky Secure Mail Gateway, version 2.0.1.6960, bases: 2025/01/27 13:50:00 #27131010 X-KSMG-AntiVirus-Status: Clean, skipped Content-Type: text/plain; charset="utf-8" The global functions spinand_otp_read() and spinand_otp_write() have been introduced. Since most SPI-NAND flashes read/write OTP in the same way, let's define global functions to avoid code duplication. Signed-off-by: Martin Kurbanov --- drivers/mtd/nand/spi/otp.c | 109 ++++++++++++++++++++++++++++++++++++ include/linux/mtd/spinand.h | 7 +++ 2 files changed, 116 insertions(+) diff --git a/drivers/mtd/nand/spi/otp.c b/drivers/mtd/nand/spi/otp.c index 1eb5677508ff8..740f61749e1f4 100644 --- a/drivers/mtd/nand/spi/otp.c +++ b/drivers/mtd/nand/spi/otp.c @@ -66,6 +66,115 @@ static int spinand_user_otp_check_bounds(struct spinand= _device *spinand, &spinand->user_otp->layout); } =20 +static int spinand_otp_rw(struct spinand_device *spinand, loff_t ofs, + size_t len, size_t *retlen, u8 *buf, bool is_write, + const struct spinand_otp_layout *layout) +{ + struct nand_page_io_req req =3D {}; + unsigned long long page; + size_t copied =3D 0; + size_t otp_pagesize =3D spinand_otp_page_size(spinand); + int ret; + + if (!len) + return 0; + + ret =3D spinand_otp_check_bounds(spinand, ofs, len, layout); + if (ret) + return ret; + + ret =3D spinand_upd_cfg(spinand, CFG_OTP_ENABLE, CFG_OTP_ENABLE); + if (ret) + return ret; + + page =3D ofs; + req.dataoffs =3D do_div(page, otp_pagesize); + req.pos.page =3D page + layout->start_page; + req.type =3D is_write ? NAND_PAGE_WRITE : NAND_PAGE_READ; + req.mode =3D MTD_OPS_RAW; + req.databuf.in =3D buf; + + while (copied < len) { + req.datalen =3D min_t(unsigned int, + otp_pagesize - req.dataoffs, + len - copied); + + if (is_write) + ret =3D spinand_write_page(spinand, &req); + else + ret =3D spinand_read_page(spinand, &req); + + if (ret < 0) + break; + + req.databuf.in +=3D req.datalen; + req.pos.page++; + req.dataoffs =3D 0; + copied +=3D req.datalen; + } + + *retlen =3D copied; + + if (spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0)) { + dev_warn(&spinand_to_mtd(spinand)->dev, + "Can not disable OTP mode\n"); + ret =3D -EIO; + } + + return ret; +} + +/** + * spinand_fact_otp_read() - Read from OTP area + * @spinand: the spinand device + * @ofs: the offset to read + * @len: the number of data bytes to read + * @retlen: the pointer to variable to store the number of read bytes + * @buf: the buffer to store the read data + * + * Return: 0 on success, an error code otherwise. + */ +int spinand_fact_otp_read(struct spinand_device *spinand, loff_t ofs, + size_t len, size_t *retlen, u8 *buf) +{ + return spinand_otp_rw(spinand, ofs, len, retlen, buf, false, + &spinand->fact_otp->layout); +} + +/** + * spinand_user_otp_read() - Read from OTP area + * @spinand: the spinand device + * @ofs: the offset to read + * @len: the number of data bytes to read + * @retlen: the pointer to variable to store the number of read bytes + * @buf: the buffer to store the read data + * + * Return: 0 on success, an error code otherwise. + */ +int spinand_user_otp_read(struct spinand_device *spinand, loff_t ofs, + size_t len, size_t *retlen, u8 *buf) +{ + return spinand_otp_rw(spinand, ofs, len, retlen, buf, false, + &spinand->user_otp->layout); +} + +/** + * spinand_user_otp_write() - Write to OTP area + * @spinand: the spinand device + * @ofs: the offset to write to + * @len: the number of bytes to write + * @retlen: the pointer to variable to store the number of written bytes + * @buf: the buffer with data to write + * + * Return: 0 on success, an error code otherwise. + */ +int spinand_user_otp_write(struct spinand_device *spinand, loff_t ofs, + size_t len, size_t *retlen, const u8 *buf) +{ + return spinand_otp_rw(spinand, ofs, len, retlen, (u8 *)buf, true, + &spinand->user_otp->layout); +} + static int spinand_mtd_otp_info(struct mtd_info *mtd, size_t len, size_t *retlen, struct otp_info *buf, bool is_fact) diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index e0fdd3408ffa1..e2c6a9ac30c10 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -639,6 +639,13 @@ size_t spinand_otp_page_size(struct spinand_device *sp= inand); size_t spinand_fact_otp_size(struct spinand_device *spinand); size_t spinand_user_otp_size(struct spinand_device *spinand); =20 +int spinand_fact_otp_read(struct spinand_device *spinand, loff_t ofs, + size_t len, size_t *retlen, u8 *buf); +int spinand_user_otp_read(struct spinand_device *spinand, loff_t ofs, + size_t len, size_t *retlen, u8 *buf); +int spinand_user_otp_write(struct spinand_device *spinand, loff_t ofs, + size_t len, size_t *retlen, const u8 *buf); + int spinand_set_mtd_otp_ops(struct spinand_device *spinand); =20 #endif /* __LINUX_MTD_SPINAND_H */ --=20 2.43.0 From nobody Mon Feb 9 07:39:36 2026 Received: from mx1.sberdevices.ru (mx1.sberdevices.ru [37.18.73.165]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1901213D246 for ; Mon, 27 Jan 2025 15:39:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=37.18.73.165 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737992369; cv=none; b=furdBH1kKIolPJfoG+VX112Qmnvbhpfr5I7iBVRMIMmsKQtYcuiE4z/2turaVbxX4IWO8YYa9m0lVSCWVGq5pngN4wPf+d3fe7I0Zqh8EMKqo53rwwFJ/3eeoh5WQxwmwtInkaK1zx94ePHWbRmpiumr6bECqfmQMEN++duLbUM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737992369; c=relaxed/simple; bh=GbB5YU2X5QfE4+YC6HAxFDzQ4/BNU7lSoWvViLQETDY=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Tn6MO+Yhg/wBK0+YWPWlHe7IScXhLvaKtnMxFsbevjUAsgTA+sgKrzsUG5o0nqXxGo1RlUgiEBa8cyp1im8JK3JDgTN9mxpYT5c/iaZn7Lr+ClsMiAIChNjY1htSqUWBPvp2DQuEiFcplBPNouWXAcgDe8mRwE3aswJKssvEuhg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=salutedevices.com; spf=pass smtp.mailfrom=salutedevices.com; dkim=pass (2048-bit key) header.d=salutedevices.com header.i=@salutedevices.com header.b=qKXOTFYF; arc=none smtp.client-ip=37.18.73.165 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=salutedevices.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=salutedevices.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=salutedevices.com header.i=@salutedevices.com header.b="qKXOTFYF" Received: from p-infra-ksmg-sc-msk01.sberdevices.ru (localhost [127.0.0.1]) by mx1.sberdevices.ru (Postfix) with ESMTP id 1E740100004; Mon, 27 Jan 2025 18:39:15 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.sberdevices.ru 1E740100004 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=salutedevices.com; s=mail; t=1737992355; bh=P8oBy0hM+/nsKiAeOgpi2vWfWfXqaiBXCDoH11AkK84=; h=From:To:Subject:Date:Message-ID:MIME-Version:Content-Type:From; b=qKXOTFYFT+5jwXrcR/mhR3wKSeWDqBOdZptd1hLCIgxqCJwnuXqWZ9QFdkh/gx013 u3aDXJ/yCrLUcCimiY8VA+kUVjtt4zSr0t5E5SE1VqkpZhgvyjLImfUQeBh/Z6Ho0W hsEQsVTqHo8k1P2yfLvG5912Ta2nJWGRuMkUZi9hZNUGeGyCfSjqdku5WKwXEunOwy 8eP6P8WhgVRKDy4Rxk+VU5+z/aqr/pxscbMba3KdJhspTm8pekDI9n9374iIWiQWXy zbt0w9uk1qFj8TBFDn6sxxd1aDV63kpW0S7VUkLOvXP55TLp1c5DP8SN7TQcxLiEzg qnyIXcQK9LQnw== Received: from smtp.sberdevices.ru (p-i-exch-sc-m01.sberdevices.ru [172.16.192.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.sberdevices.ru (Postfix) with ESMTPS; Mon, 27 Jan 2025 18:39:14 +0300 (MSK) From: Martin Kurbanov To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Ezra Buehler , Cheng Ming Lin , Pratyush Yadav , Daniel Golle , Frieder Schrempf , Alexey Romanov CC: , , , Martin Kurbanov Subject: [PATCH v4 5/6] mtd: spinand: micron: OTP access for MT29F2G01ABAGD Date: Mon, 27 Jan 2025 18:38:23 +0300 Message-ID: <20250127153848.199526-6-mmkurbanov@salutedevices.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250127153848.199526-1-mmkurbanov@salutedevices.com> References: <20250127153848.199526-1-mmkurbanov@salutedevices.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: p-i-exch-a-m1.sberdevices.ru (172.24.196.116) To p-i-exch-sc-m01.sberdevices.ru (172.16.192.107) X-KSMG-Rule-ID: 10 X-KSMG-Message-Action: clean X-KSMG-AntiSpam-Lua-Profiles: 190596 [Jan 27 2025] X-KSMG-AntiSpam-Version: 6.1.1.7 X-KSMG-AntiSpam-Envelope-From: mmkurbanov@salutedevices.com X-KSMG-AntiSpam-Rate: 0 X-KSMG-AntiSpam-Status: not_detected X-KSMG-AntiSpam-Method: none X-KSMG-AntiSpam-Auth: dkim=none X-KSMG-AntiSpam-Info: LuaCore: 50 0.3.50 df4aeb250ed63fd3baa80a493fa6caee5dd9e10f, {Tracking_from_domain_doesnt_match_to}, salutedevices.com:7.1.1;smtp.sberdevices.ru:5.0.1,7.1.1;d41d8cd98f00b204e9800998ecf8427e.com:7.1.1;127.0.0.199:7.1.2, FromAlignment: s X-MS-Exchange-Organization-SCL: -1 X-KSMG-AntiSpam-Interceptor-Info: scan successful X-KSMG-AntiPhishing: Clean X-KSMG-LinksScanning: Clean X-KSMG-AntiVirus: Kaspersky Secure Mail Gateway, version 2.0.1.6960, bases: 2025/01/27 09:37:00 #27129213 X-KSMG-AntiVirus-Status: Clean, skipped Content-Type: text/plain; charset="utf-8" Support for OTP area access on Micron MT29F2G01ABAGD chip. Signed-off-by: Martin Kurbanov --- drivers/mtd/nand/spi/micron.c | 135 +++++++++++++++++++++++++++++++++- 1 file changed, 134 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c index 8d741be6d5f3e..4d089eca1c337 100644 --- a/drivers/mtd/nand/spi/micron.c +++ b/drivers/mtd/nand/spi/micron.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include =20 #define SPINAND_MFR_MICRON 0x2c =20 @@ -28,6 +30,10 @@ =20 #define MICRON_SELECT_DIE(x) ((x) << 6) =20 +#define MICRON_MT29F2G01ABAGD_CFG_OTP_STATE BIT(7) +#define MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK \ + (CFG_OTP_ENABLE | MICRON_MT29F2G01ABAGD_CFG_OTP_STATE) + static SPINAND_OP_VARIANTS(quadio_read_cache_variants, //SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), @@ -182,6 +188,131 @@ static int micron_8_ecc_get_status(struct spinand_dev= ice *spinand, return -EINVAL; } =20 +static int mt29f2g01abagd_otp_is_locked(struct spinand_device *spinand) +{ + size_t bufsize =3D spinand_otp_page_size(spinand); + size_t retlen; + u8 *buf; + int ret; + + buf =3D kmalloc(bufsize, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret =3D spinand_upd_cfg(spinand, + MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK, + MICRON_MT29F2G01ABAGD_CFG_OTP_STATE); + if (ret) + goto free_buf; + + ret =3D spinand_user_otp_read(spinand, 0, bufsize, &retlen, buf); + + if (spinand_upd_cfg(spinand, MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK, + 0)) { + dev_warn(&spinand_to_mtd(spinand)->dev, + "Can not disable OTP mode\n"); + ret =3D -EIO; + } + + if (ret) + goto free_buf; + + /* If all zeros, then the OTP area is locked. */ + if (mem_is_zero(buf, bufsize)) + ret =3D 1; + +free_buf: + kfree(buf); + return ret; +} + +static int mt29f2g01abagd_otp_info(struct spinand_device *spinand, size_t = len, + struct otp_info *buf, size_t *retlen, + bool user) +{ + int locked; + + if (len < sizeof(*buf)) + return -EINVAL; + + locked =3D mt29f2g01abagd_otp_is_locked(spinand); + if (locked < 0) + return locked; + + buf->locked =3D locked; + buf->start =3D 0; + buf->length =3D user ? spinand_user_otp_size(spinand) : + spinand_fact_otp_size(spinand); + + *retlen =3D sizeof(*buf); + return 0; +} + +static int mt29f2g01abagd_fact_otp_info(struct spinand_device *spinand, + size_t len, struct otp_info *buf, + size_t *retlen) +{ + return mt29f2g01abagd_otp_info(spinand, len, buf, retlen, false); +} + +static int mt29f2g01abagd_user_otp_info(struct spinand_device *spinand, + size_t len, struct otp_info *buf, + size_t *retlen) +{ + return mt29f2g01abagd_otp_info(spinand, len, buf, retlen, true); +} + +static int mt29f2g01abagd_otp_lock(struct spinand_device *spinand, loff_t = from, + size_t len) +{ + struct spi_mem_op write_op =3D SPINAND_WR_EN_DIS_OP(true); + struct spi_mem_op exec_op =3D SPINAND_PROG_EXEC_OP(0); + u8 status; + int ret; + + ret =3D spinand_upd_cfg(spinand, + MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK, + MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK); + if (!ret) + return ret; + + ret =3D spi_mem_exec_op(spinand->spimem, &write_op); + if (!ret) + goto out; + + ret =3D spi_mem_exec_op(spinand->spimem, &exec_op); + if (!ret) + goto out; + + ret =3D spinand_wait(spinand, + SPINAND_WRITE_INITIAL_DELAY_US, + SPINAND_WRITE_POLL_DELAY_US, + &status); + if (!ret && (status & STATUS_PROG_FAILED)) + ret =3D -EIO; + +out: + if (spinand_upd_cfg(spinand, MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK, 0)) { + dev_warn(&spinand_to_mtd(spinand)->dev, + "Can not disable OTP mode\n"); + ret =3D -EIO; + } + + return ret; +} + +static const struct spinand_user_otp_ops mt29f2g01abagd_user_otp_ops =3D { + .info =3D mt29f2g01abagd_user_otp_info, + .lock =3D mt29f2g01abagd_otp_lock, + .read =3D spinand_user_otp_read, + .write =3D spinand_user_otp_write, +}; + +static const struct spinand_fact_otp_ops mt29f2g01abagd_fact_otp_ops =3D { + .info =3D mt29f2g01abagd_fact_otp_info, + .read =3D spinand_fact_otp_read, +}; + static const struct spinand_info micron_spinand_table[] =3D { /* M79A 2Gb 3.3V */ SPINAND_INFO("MT29F2G01ABAGD", @@ -193,7 +324,9 @@ static const struct spinand_info micron_spinand_table[]= =3D { &x4_update_cache_variants), 0, SPINAND_ECCINFO(µn_8_ooblayout, - micron_8_ecc_get_status)), + micron_8_ecc_get_status), + SPINAND_USER_OTP_INFO(12, 2, &mt29f2g01abagd_user_otp_ops), + SPINAND_FACT_OTP_INFO(2, 0, &mt29f2g01abagd_fact_otp_ops)), /* M79A 2Gb 1.8V */ SPINAND_INFO("MT29F2G01ABBGD", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25), --=20 2.43.0 From nobody Mon Feb 9 07:39:36 2026 Received: from mx1.sberdevices.ru (mx2.sberdevices.ru [45.89.224.132]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DF22D13AA2E for ; Mon, 27 Jan 2025 15:39:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.89.224.132 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737992369; cv=none; b=FnhaFuhwb3AVdSv98QBXqOBVPNBGwnk+nVxqxPvMpXcDfchIskQcWzZxCxvSzFUZSixnO7Duh4Uz9QIvJnySibyuu+MGTqRLGVhUB1ETa6GLFwoy27JxB/DpddHpiaVVT/DcicEXf5XXAjsVMtVPN3LUXJPGgOIqWygEE21Ulpk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737992369; c=relaxed/simple; bh=dCDkE8mlpAZLPuZwByvCoDOhZhLItTlU0iPdvM8Qb70=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=KoKDOx9cJmj3Pd8EeYPcy4soJdP+GCarJAlwneCJP16v31k5E5Sj12Mg4lWqlccs+hDfAKcGyVoh645o5FU0rPuViCH4oGVWgeVqgPAi1StEdBB2eUgjiOeinf8wyck4eBfIEbihS6FdMpKkxoU7UpiP6lZniQWoFXJjzra8ySs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=salutedevices.com; spf=pass smtp.mailfrom=salutedevices.com; dkim=pass (2048-bit key) header.d=salutedevices.com header.i=@salutedevices.com header.b=Pqo3cLMa; arc=none smtp.client-ip=45.89.224.132 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=salutedevices.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=salutedevices.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=salutedevices.com header.i=@salutedevices.com header.b="Pqo3cLMa" Received: from p-infra-ksmg-sc-msk02.sberdevices.ru (localhost [127.0.0.1]) by mx1.sberdevices.ru (Postfix) with ESMTP id 51E3912000D; Mon, 27 Jan 2025 18:39:15 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.sberdevices.ru 51E3912000D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=salutedevices.com; s=mail; t=1737992355; bh=kAYvtxBqe5R068u7fiS5JpXkwrfKKqbubvRmbXnB2DA=; h=From:To:Subject:Date:Message-ID:MIME-Version:Content-Type:From; b=Pqo3cLMaBkW1EjUhHLPkT7K1aCNTthlt7HzLPGE0qaFQioUhqlIpIqJCVGW8izSKt xz6LUTM2Pi6iJr2Hy5FTYQwJesKcIQu6qS591AdyhueJmuQAPIcxVrESzgU+reJByp KdvHr47XQZSkfikHvi6V8Bp3vGOrRgV07yVSxLPkWwskmy79QovlARROI+c+WoWj5Z TeUkld5W6WTQU+9DUusWtG22T4hxvbN3W/pNkYz6g+sfvQFLZtX8B094WySHTt0Dch KwgLTySeU6Aut2TKCv/l0ynkDNUDcYfUdHNcIVARArmBGyeogKNaEpsJHZHc3Ya4sJ oXRaCX4Sj1GkQ== Received: from smtp.sberdevices.ru (p-i-exch-sc-m01.sberdevices.ru [172.16.192.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.sberdevices.ru (Postfix) with ESMTPS; Mon, 27 Jan 2025 18:39:15 +0300 (MSK) From: Martin Kurbanov To: Miquel Raynal , Richard Weinberger , Vignesh Raghavendra , Ezra Buehler , Cheng Ming Lin , Pratyush Yadav , Daniel Golle , Frieder Schrempf , Alexey Romanov CC: , , , Martin Kurbanov Subject: [PATCH v4 6/6] mtd: spinand: esmt: OTP access for F50{L,D}1G41LB Date: Mon, 27 Jan 2025 18:38:24 +0300 Message-ID: <20250127153848.199526-7-mmkurbanov@salutedevices.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250127153848.199526-1-mmkurbanov@salutedevices.com> References: <20250127153848.199526-1-mmkurbanov@salutedevices.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: p-i-exch-a-m1.sberdevices.ru (172.24.196.116) To p-i-exch-sc-m01.sberdevices.ru (172.16.192.107) X-KSMG-Rule-ID: 10 X-KSMG-Message-Action: clean X-KSMG-AntiSpam-Lua-Profiles: 190599 [Jan 27 2025] X-KSMG-AntiSpam-Version: 6.1.1.7 X-KSMG-AntiSpam-Envelope-From: mmkurbanov@salutedevices.com X-KSMG-AntiSpam-Rate: 0 X-KSMG-AntiSpam-Status: not_detected X-KSMG-AntiSpam-Method: none X-KSMG-AntiSpam-Auth: dkim=none X-KSMG-AntiSpam-Info: LuaCore: 50 0.3.50 df4aeb250ed63fd3baa80a493fa6caee5dd9e10f, {Tracking_from_domain_doesnt_match_to}, salutedevices.com:7.1.1;127.0.0.199:7.1.2;d41d8cd98f00b204e9800998ecf8427e.com:7.1.1;smtp.sberdevices.ru:5.0.1,7.1.1, FromAlignment: s X-MS-Exchange-Organization-SCL: -1 X-KSMG-AntiSpam-Interceptor-Info: scan successful X-KSMG-AntiPhishing: Clean X-KSMG-LinksScanning: Clean X-KSMG-AntiVirus: Kaspersky Secure Mail Gateway, version 2.0.1.6960, bases: 2025/01/27 13:50:00 #27131010 X-KSMG-AntiVirus-Status: Clean, skipped Content-Type: text/plain; charset="utf-8" Support for OTP area access on ESMT F50L1G41LB and F50D1G41LB chips. Signed-off-by: Martin Kurbanov --- drivers/mtd/nand/spi/esmt.c | 90 ++++++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/spi/esmt.c b/drivers/mtd/nand/spi/esmt.c index 4597a82de23a4..c555ce616b65c 100644 --- a/drivers/mtd/nand/spi/esmt.c +++ b/drivers/mtd/nand/spi/esmt.c @@ -8,10 +8,15 @@ #include #include #include +#include =20 /* ESMT uses GigaDevice 0xc8 JECDEC ID on some SPI NANDs */ #define SPINAND_MFR_ESMT_C8 0xc8 =20 +#define ESMT_F50L1G41LB_CFG_OTP_PROTECT BIT(7) +#define ESMT_F50L1G41LB_CFG_OTP_LOCK \ + (CFG_OTP_ENABLE | ESMT_F50L1G41LB_CFG_OTP_PROTECT) + static SPINAND_OP_VARIANTS(read_cache_variants, SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), @@ -102,6 +107,83 @@ static const struct mtd_ooblayout_ops f50l1g41lb_oobla= yout =3D { .free =3D f50l1g41lb_ooblayout_free, }; =20 +static int f50l1g41lb_otp_info(struct spinand_device *spinand, size_t len, + struct otp_info *buf, size_t *retlen, bool user) +{ + if (len < sizeof(*buf)) + return -EINVAL; + + buf->locked =3D 0; + buf->start =3D 0; + buf->length =3D user ? spinand_user_otp_size(spinand) : + spinand_fact_otp_size(spinand); + + *retlen =3D sizeof(*buf); + return 0; +} + +static int f50l1g41lb_fact_otp_info(struct spinand_device *spinand, size_t= len, + struct otp_info *buf, size_t *retlen) +{ + return f50l1g41lb_otp_info(spinand, len, buf, retlen, false); +} + +static int f50l1g41lb_user_otp_info(struct spinand_device *spinand, size_t= len, + struct otp_info *buf, size_t *retlen) +{ + return f50l1g41lb_otp_info(spinand, len, buf, retlen, true); +} + +static int f50l1g41lb_otp_lock(struct spinand_device *spinand, loff_t from, + size_t len) +{ + struct spi_mem_op write_op =3D SPINAND_WR_EN_DIS_OP(true); + struct spi_mem_op exec_op =3D SPINAND_PROG_EXEC_OP(0); + u8 status; + int ret; + + ret =3D spinand_upd_cfg(spinand, ESMT_F50L1G41LB_CFG_OTP_LOCK, + ESMT_F50L1G41LB_CFG_OTP_LOCK); + if (!ret) + return ret; + + ret =3D spi_mem_exec_op(spinand->spimem, &write_op); + if (!ret) + goto out; + + ret =3D spi_mem_exec_op(spinand->spimem, &exec_op); + if (!ret) + goto out; + + ret =3D spinand_wait(spinand, + SPINAND_WRITE_INITIAL_DELAY_US, + SPINAND_WRITE_POLL_DELAY_US, + &status); + if (!ret && (status & STATUS_PROG_FAILED)) + ret =3D -EIO; + +out: + if (spinand_upd_cfg(spinand, ESMT_F50L1G41LB_CFG_OTP_LOCK, 0)) { + dev_warn(&spinand_to_mtd(spinand)->dev, + "Can not disable OTP mode\n"); + ret =3D -EIO; + } + + return ret; +} + +static const struct spinand_user_otp_ops f50l1g41lb_user_otp_ops =3D { + .info =3D f50l1g41lb_user_otp_info, + .lock =3D f50l1g41lb_otp_lock, + .read =3D spinand_user_otp_read, + .write =3D spinand_user_otp_write, +}; + +static const struct spinand_fact_otp_ops f50l1g41lb_fact_otp_ops =3D { + .info =3D f50l1g41lb_fact_otp_info, + .read =3D spinand_fact_otp_read, +}; + static const struct spinand_info esmt_c8_spinand_table[] =3D { SPINAND_INFO("F50L1G41LB", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01, 0x7f, @@ -112,7 +194,9 @@ static const struct spinand_info esmt_c8_spinand_table[= ] =3D { &write_cache_variants, &update_cache_variants), 0, - SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)), + SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL), + SPINAND_USER_OTP_INFO(28, 2, &f50l1g41lb_user_otp_ops), + SPINAND_FACT_OTP_INFO(2, 0, &f50l1g41lb_fact_otp_ops)), SPINAND_INFO("F50D1G41LB", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x11, 0x7f, 0x7f, 0x7f), @@ -122,7 +206,9 @@ static const struct spinand_info esmt_c8_spinand_table[= ] =3D { &write_cache_variants, &update_cache_variants), 0, - SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)), + SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL), + SPINAND_USER_OTP_INFO(28, 2, &f50l1g41lb_user_otp_ops), + SPINAND_FACT_OTP_INFO(2, 0, &f50l1g41lb_fact_otp_ops)), SPINAND_INFO("F50D2G41KA", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x51, 0x7f, 0x7f, 0x7f), --=20 2.43.0