From nobody Tue Dec 16 07:34:53 2025 Received: from smtpout-02.galae.net (smtpout-02.galae.net [185.246.84.56]) (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 5FBCA2459CF; Fri, 5 Dec 2025 19:39:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.84.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764963585; cv=none; b=YrZkhSsTwqkD87m0XeGgJrNYVZq7U0LqasEXLu785YjcpmKxfdin2LU3I/QO2f85efSrzzmp2ykPd0o7VeFI5RgsyiwyeXuZYVD0fhH+IP8kq1PxvK9QSV0qUxUd+WDpJw/WzysxezSui31dqXcBZZ4kPT557Ld7vP1U91/Dnqc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764963585; c=relaxed/simple; bh=ulElZZ6V3nq9rJMP/rkg5tZKYiISdRhCdU5SzeNdOjc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=cOHGUlW5oAYNMaH+pcpdqoqxEf+kd1YDinSEjFfmajpFwFY10JaH2edtWw6j0ILFA1NYZYiUJDoNQQdwwlLBfG+AewE2o9rpZbedE22aJFbr4h5FmkfQ5LHUINnH8pbyaZwL7H2SsQeplSt9QRsjYkWoc3aJocwaKieYU8JSaAU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=rwfR0l88; arc=none smtp.client-ip=185.246.84.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="rwfR0l88" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-02.galae.net (Postfix) with ESMTPS id AF5441A1F9D; Fri, 5 Dec 2025 19:39:41 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 86FAA606AC; Fri, 5 Dec 2025 19:39:41 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id E7219102F17A8; Fri, 5 Dec 2025 20:39:38 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1764963580; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=qGBKhT3RNIHcjkZ9EmczMf85mf9EwSENJtITDWUwMNE=; b=rwfR0l88X+RfLeOIGJQ8PprYYUukBuV8926iW1SSP/RE5++dAcHwq9Z1T/FaWQmbrQutGz aRubIFfOLGVdHv8hTUByo2ygcNrgQPSPF01zV/FDbdsFozAt10b8J7r+HIa+O+eGi8KqGp mIlr8JimntwKvSR5hqv75F86p8CkeTPTDkQNv/wB5jHkCxNRFxqBpg4Wepl/TJ7UvaIiGS Z/NatzKyehSc8txDt73ytaNKr5xYMhmJWiPgZLMz+mgY+1TAhuFcbc8ZXIg/Qm3I47ML5r z1jb8gqDW4BJN0jPYDnOZs+I9CYc+lm4S0OC8FaZOOyCZOrI3PgIL11bk0HY1A== From: Miquel Raynal Date: Fri, 05 Dec 2025 20:38:52 +0100 Subject: [PATCH RFC 1/8] mtd: spinand: Drop a too strong limitation Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251205-winbond-v6-18-rc1-cont-read-v1-1-01bc48631c73@bootlin.com> References: <20251205-winbond-v6-18-rc1-cont-read-v1-0-01bc48631c73@bootlin.com> In-Reply-To: <20251205-winbond-v6-18-rc1-cont-read-v1-0-01bc48631c73@bootlin.com> To: Mark Brown , Richard Weinberger , Vignesh Raghavendra , Michael Walle Cc: Tudor Ambarus , Pratyush Yadav , Thomas Petazzoni , Steam Lin , Santhosh Kumar K , linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, Miquel Raynal X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 Since continuous reads may sometimes not be able to go past an erase block boundary, it has been decided not to attempt longer reads and if the user request is bigger, it will be split across eraseblocks. As these request will anyway be handled correctly, there is no reason to filter out cases where we would go over a target or a die, so drop this limitation which had a side effect: any request to read more than the content of an eraseblock would simply not benefit from the continuous read feature. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/spi/core.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 49ee03a7252b..f19150740979 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -788,6 +788,12 @@ static int spinand_mtd_continuous_page_read(struct mtd= _info *mtd, loff_t from, * Each data read must be a multiple of 4-bytes and full pages should be = read; * otherwise, the data output might get out of sequence from one read com= mand * to another. + * + * Continuous reads never cross LUN boundaries. Some devices don't + * support crossing planes boundaries. Some devices don't even support + * crossing blocks boundaries. The common case being to read through UBI, + * we will very rarely read two consequent blocks or more, so let's only = enable + * continuous reads when reading within the same erase block. */ nanddev_io_for_each_block(nand, NAND_PAGE_READ, from, ops, &iter) { ret =3D spinand_select_target(spinand, iter.req.pos.target); @@ -870,19 +876,6 @@ static bool spinand_use_cont_read(struct mtd_info *mtd= , loff_t from, nanddev_offs_to_pos(nand, from, &start_pos); nanddev_offs_to_pos(nand, from + ops->len - 1, &end_pos); =20 - /* - * Continuous reads never cross LUN boundaries. Some devices don't - * support crossing planes boundaries. Some devices don't even support - * crossing blocks boundaries. The common case being to read through UBI, - * we will very rarely read two consequent blocks or more, so it is safer - * and easier (can be improved) to only enable continuous reads when - * reading within the same erase block. - */ - if (start_pos.target !=3D end_pos.target || - start_pos.plane !=3D end_pos.plane || - start_pos.eraseblock !=3D end_pos.eraseblock) - return false; - return start_pos.page < end_pos.page; } =20 --=20 2.51.1 From nobody Tue Dec 16 07:34:53 2025 Received: from smtpout-04.galae.net (smtpout-04.galae.net [185.171.202.116]) (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 542752F49FC for ; Fri, 5 Dec 2025 19:39:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.171.202.116 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764963587; cv=none; b=gu5L4g8fvop/KWdPAn9a2M0SErl48CjPow38Q667J2nbQhmP/9qxi0bPTO9HOnLYlOtpleiZeG9OVT035YhgRhReGYjt5euK5G/15zXo0uKXEr2ipdsZ8E0FXlrJMer/kD+31cdywyO0ms/o3Jzk/tuik/hTZw9Z/5eW4Q9ZScw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764963587; c=relaxed/simple; bh=mQaaxpYiYEA4WG+VkY9JcwF+LpKCHCFQheQhakl466s=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=YdKdIhI1yOP2bc6ywk2Nx5QHnNeyLRmyB8gggpN0VvbwBeLUTac85p17zPRwki4Ht1Ov2DRTPqqoNofGQj6VkOKit5Wrt0hWTqiCvHXGn5Mw91t0bNafvb/drv+bldErfQlkup5qyNbOQsCVvoY/LYe/OWOdvJ/4HuVHwyKFuYE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=kdl8sj1F; arc=none smtp.client-ip=185.171.202.116 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="kdl8sj1F" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id 175F4C19651; Fri, 5 Dec 2025 19:39:20 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 8EB41606AC; Fri, 5 Dec 2025 19:39:43 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 38787102F18E2; Fri, 5 Dec 2025 20:39:41 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1764963582; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=GsPfW5nIrd5pUnvoNUZwEFGa4mbzSWlHyDo81A+WvbQ=; b=kdl8sj1F1iOIT4hz0E2OFm3VYpUtyMOasoawoaUZOU4bJdRlkRuR/L5h2wxiuywE2ulpU1 5OJsczM5hBpkRyWlluHcWhpAP9Jo1VA34C6Ta5XZEbFakxra7daw+eYFGAI3ZAQyDCXr+9 sKVUGXfn+6U4Jct+kwy0Grz5r0LOFHCH1qngzo+s4h5axTMBDKD7I7GT52IIKRSp7P41CF hymHESESD6jzDg3HlGIZL/4XbLYln7uigDGjCQopihp5DB26Anl+7TKEr0z2s3HJzZm5VA zoaJb+dPuaZVhvkpJX33okuFuRxUxr1mYSCU1IcvS8jmEfF6xFk3PHMPh7QwZQ== From: Miquel Raynal Date: Fri, 05 Dec 2025 20:38:53 +0100 Subject: [PATCH RFC 2/8] mtd: spinand: Expose spinand_op_is_odtr() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251205-winbond-v6-18-rc1-cont-read-v1-2-01bc48631c73@bootlin.com> References: <20251205-winbond-v6-18-rc1-cont-read-v1-0-01bc48631c73@bootlin.com> In-Reply-To: <20251205-winbond-v6-18-rc1-cont-read-v1-0-01bc48631c73@bootlin.com> To: Mark Brown , Richard Weinberger , Vignesh Raghavendra , Michael Walle Cc: Tudor Ambarus , Pratyush Yadav , Thomas Petazzoni , Steam Lin , Santhosh Kumar K , linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, Miquel Raynal X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 This helper is going to be needed in a vendor driver, so expose it. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/spi/core.c | 2 +- include/linux/mtd/spinand.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index f19150740979..3765fcc95c4a 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -1300,7 +1300,7 @@ static void spinand_manufacturer_cleanup(struct spina= nd_device *spinand) return spinand->manufacturer->ops->cleanup(spinand); } =20 -static bool spinand_op_is_odtr(const struct spi_mem_op *op) +bool spinand_op_is_odtr(const struct spi_mem_op *op) { return op->cmd.dtr && op->cmd.buswidth =3D=3D 8; } diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index eb8ae164b3aa..a90e873cf693 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -944,6 +944,8 @@ static inline void spinand_set_of_node(struct spinand_d= evice *spinand, nanddev_set_of_node(&spinand->base, np); } =20 +bool spinand_op_is_odtr(const struct spi_mem_op *op); + int spinand_match_and_init(struct spinand_device *spinand, const struct spinand_info *table, unsigned int table_size, --=20 2.51.1 From nobody Tue Dec 16 07:34:53 2025 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (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 C1E46218AB9 for ; Fri, 5 Dec 2025 19:39:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764963590; cv=none; b=rfldWmXm5h5erRgEIw5Dg29S9JboWWOqi/f8DdiqSWoNt9qPsnnlPiIoAapMOU0CCYNWOQS5MTylq4CHqCADIDygc9V0xZ62HfDGbwpivCBHHCD9syo50g8BARskI51pQ+2uCs4WrhXoEi6E9j//mESZS3drSW4Yo+iycmv0oaU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764963590; c=relaxed/simple; bh=0cukgJ5NKjqHVM+tQAlvy8PWi0Q1Fsr8fCIOzOzJR88=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=HHpGaDu8wu2XYgsb2eCZ9nN/uaMR7ezORMr9Ij2ZISup7kKT3ixotkdY3UC74pDxj0fsKAwadzC3iMvVODLctaw1EPmUzG9vUNpbZx5/kDH+IcQTpps1B6H1ZMByDZQjU+usf4Qofk5G8NnSaklfAUzpEla8YdT3tUWCGjTisb8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=aKWi69wq; arc=none smtp.client-ip=185.246.85.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="aKWi69wq" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id 0BB684E41A72; Fri, 5 Dec 2025 19:39:46 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id D70CC606AC; Fri, 5 Dec 2025 19:39:45 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 456D9102F170A; Fri, 5 Dec 2025 20:39:43 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1764963585; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=EMGpx1MzAg6O8NLZEwbaJM17V1d6KdJfLT/hxVY3Xs4=; b=aKWi69wqYVysNMyrftPssWDmkIa8f8R9dT8gmxcN+8e0mdsA4bY3Pg33colA+ecbDjOTMy B56XCj5cmtA2GOpR0qlgG4kEqxeYU73gBu94dlmCrKWFTBWF3/7RzDBLGFMFzUUoZrioTu Xvrnm51iWn2q06pQ+dnHJJoAHkiyKQ0N6Y+7Z8jvY7T+lGJG+h9YoBI8K2Mp4+E/WWoiAt E9tqOrnuy9Mse6k60/dv5C7n10rrb4Tg4HXKq+TXBMCQ5tX21gSlJYQl63XTrFPoSgRYkT WfzD8yofRYqIGFo6sr5ULVyb9AY5LmSp0uC9klZkK1nDtkA2s4OSgA+iPaiPCw== From: Miquel Raynal Date: Fri, 05 Dec 2025 20:38:54 +0100 Subject: [PATCH RFC 3/8] mtd: spinand: Drop ECC dirmaps Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251205-winbond-v6-18-rc1-cont-read-v1-3-01bc48631c73@bootlin.com> References: <20251205-winbond-v6-18-rc1-cont-read-v1-0-01bc48631c73@bootlin.com> In-Reply-To: <20251205-winbond-v6-18-rc1-cont-read-v1-0-01bc48631c73@bootlin.com> To: Mark Brown , Richard Weinberger , Vignesh Raghavendra , Michael Walle Cc: Tudor Ambarus , Pratyush Yadav , Thomas Petazzoni , Steam Lin , Santhosh Kumar K , linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, Miquel Raynal X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 Direct mappings are very static concepts, which allow us to reuse a template to perform reads or writes in a very efficient manner after a single initialization. With the introduction of pipelined ECC engines for SPI controllers, the need to differentiate between an operation with and without correction has arised. The chosen solution at that time has been to create new direct mappings for these operations, jumping from 2 to 4 dirmaps per target. Enabling ECC was done by choosing the correct dirmap. Today, we need to further parametrize dirmaps. With the goal to enable continuous reads on a wider range of devices, we will need more flexibility regarding the read from cache operation template to pick at run time, for instance to use shorter "continuous read from cache" variants. We could create other direct mappings, but it would increase the matrix by a power of two, bringing the theoretical number of dirmaps to 8 (read/write, ecc, shorter read variants) per target. This grow is not sustainable, so let's change how dirmaps work - a little bit. Operations already carry an ECC parameter, use it to indicate whether error correction is required or not. In practice this change happens only at the core level, SPI controller drivers do not care about the direct mapping structure in this case, they just pick whatever is in the template as a base. As a result, we allow the core to dynamically change the content of the templates. He who can do more can do less, so during the checking steps, make sure to enable the ECC requirement just for the time of the checks. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/spi/core.c | 52 +++++++++++++++++------------------------= ---- include/linux/mtd/spinand.h | 2 -- 2 files changed, 20 insertions(+), 34 deletions(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 3765fcc95c4a..086c9f293373 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -397,10 +397,13 @@ static int spinand_read_from_cache_op(struct spinand_= device *spinand, } } =20 - if (req->mode =3D=3D MTD_OPS_RAW) - rdesc =3D spinand->dirmaps[req->pos.plane].rdesc; + rdesc =3D spinand->dirmaps[req->pos.plane].rdesc; + + if (nand->ecc.engine->integration =3D=3D NAND_ECC_ENGINE_INTEGRATION_PIPE= LINED && + req->mode !=3D MTD_OPS_RAW) + rdesc->info.op_tmpl.data.ecc =3D true; else - rdesc =3D spinand->dirmaps[req->pos.plane].rdesc_ecc; + rdesc->info.op_tmpl.data.ecc =3D false; =20 if (spinand->flags & SPINAND_HAS_READ_PLANE_SELECT_BIT) column |=3D req->pos.plane << fls(nanddev_page_size(nand)); @@ -489,10 +492,13 @@ static int spinand_write_to_cache_op(struct spinand_d= evice *spinand, req->ooblen); } =20 - if (req->mode =3D=3D MTD_OPS_RAW) - wdesc =3D spinand->dirmaps[req->pos.plane].wdesc; + wdesc =3D spinand->dirmaps[req->pos.plane].wdesc; + + if (nand->ecc.engine->integration =3D=3D NAND_ECC_ENGINE_INTEGRATION_PIPE= LINED && + req->mode !=3D MTD_OPS_RAW) + wdesc->info.op_tmpl.data.ecc =3D true; else - wdesc =3D spinand->dirmaps[req->pos.plane].wdesc_ecc; + wdesc->info.op_tmpl.data.ecc =3D false; =20 if (spinand->flags & SPINAND_HAS_PROG_PLANE_SELECT_BIT) column |=3D req->pos.plane << fls(nanddev_page_size(nand)); @@ -1133,12 +1139,17 @@ static int spinand_create_dirmap(struct spinand_dev= ice *spinand, struct nand_device *nand =3D spinand_to_nand(spinand); struct spi_mem_dirmap_info info =3D { 0 }; struct spi_mem_dirmap_desc *desc; + bool enable_ecc =3D false; + + if (nand->ecc.engine->integration =3D=3D NAND_ECC_ENGINE_INTEGRATION_PIPE= LINED) + enable_ecc =3D true; =20 /* The plane number is passed in MSB just above the column address */ info.offset =3D plane << fls(nand->memorg.pagesize); =20 + /* Write descriptor */ info.length =3D nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); - info.op_tmpl =3D *spinand->op_templates->update_cache; + info.op_tmpl.data.ecc =3D enable_ecc; desc =3D devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, spinand->spimem, &info); if (IS_ERR(desc)) @@ -1146,38 +1157,15 @@ static int spinand_create_dirmap(struct spinand_dev= ice *spinand, =20 spinand->dirmaps[plane].wdesc =3D desc; =20 + /* Read descriptor */ info.op_tmpl =3D *spinand->op_templates->read_cache; + info.op_tmpl.data.ecc =3D enable_ecc; desc =3D spinand_create_rdesc(spinand, &info); if (IS_ERR(desc)) return PTR_ERR(desc); =20 spinand->dirmaps[plane].rdesc =3D desc; =20 - if (nand->ecc.engine->integration !=3D NAND_ECC_ENGINE_INTEGRATION_PIPELI= NED) { - spinand->dirmaps[plane].wdesc_ecc =3D spinand->dirmaps[plane].wdesc; - spinand->dirmaps[plane].rdesc_ecc =3D spinand->dirmaps[plane].rdesc; - - return 0; - } - - info.length =3D nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); - info.op_tmpl =3D *spinand->op_templates->update_cache; - info.op_tmpl.data.ecc =3D true; - desc =3D devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, - spinand->spimem, &info); - if (IS_ERR(desc)) - return PTR_ERR(desc); - - spinand->dirmaps[plane].wdesc_ecc =3D desc; - - info.op_tmpl =3D *spinand->op_templates->read_cache; - info.op_tmpl.data.ecc =3D true; - desc =3D spinand_create_rdesc(spinand, &info); - if (IS_ERR(desc)) - return PTR_ERR(desc); - - spinand->dirmaps[plane].rdesc_ecc =3D desc; - return 0; } =20 diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index a90e873cf693..5ca1181048f7 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -681,8 +681,6 @@ struct spinand_info { struct spinand_dirmap { struct spi_mem_dirmap_desc *wdesc; struct spi_mem_dirmap_desc *rdesc; - struct spi_mem_dirmap_desc *wdesc_ecc; - struct spi_mem_dirmap_desc *rdesc_ecc; }; =20 /** --=20 2.51.1 From nobody Tue Dec 16 07:34:53 2025 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (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 456F5322B81 for ; Fri, 5 Dec 2025 19:39:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764963592; cv=none; b=D8uxYSX7nEaV43ehROlDOkz/3k6dKyGllpnO+MPTRamyWQaGBPtIxy8QVCli1cAnUEcmIKy89WSNHPV/yNFW52w87OqKs9E8apq4SGfbDcBCvR83HnHLlevj0XkrLFCFY3fx7jUuk7QtJY+X9kqvYdeXgmOwDjGuz4UIHEZ1jOw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764963592; c=relaxed/simple; bh=NtGMTPcvwLs/cyAIQMv0WvoA4poN06nbQoGZCMYKOQU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=KMcOwNepZtwZ8gSW/fN6TrF39kNSUqsAaFJelbHJofGZe6XZ4AQPPHKn9PPv0RVFpxCjk3MRH3W9xBzIwEDNdVtPlsqr0G0WZ8zWP7Dh05KrZFRE8TRTTPbk78mdsCT8upamatlfnJY4pxvsYfNcPi9NELlZkC6KKFuY+jWbx7k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=qZdm467v; arc=none smtp.client-ip=185.246.85.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="qZdm467v" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id E1ED64E41A73; Fri, 5 Dec 2025 19:39:48 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id B2E06606AC; Fri, 5 Dec 2025 19:39:48 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id A2979102F17A8; Fri, 5 Dec 2025 20:39:45 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1764963587; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=rzut/2vscrbvO9lhGJS+PxaQwT5GezE0dsfH+zXVtxg=; b=qZdm467v7LenNWq01VJrJCVXwBEoTdtnu3Rj4uoqGcO1qAc7pJqZZEyz5nRmFRtYYrq6FW 6QzmoUbSXY89q8xCsXnVTi9W+pMBcJPf/zPJsXHGbAAGaIv+xfmd+SQC7KYvjbg/kZLv1+ O7lS7ER+RAnQNL87qEQPATl2fSf3/yiOuBaEQIdrrlQy/LGABPJiogIaFsqVvn6XnGjAgI pfH5ADEOm+BzLbfgEKfnPMIbej9dc4J2m8XMzi8ZHH8sXBzbjf1I4CBjgYLA1JuGDDw2yO 9gvCe+G97ApIDkCGC2fpDRNaDVF8d2NjC5LX5e6hcElWaVkl/aWCmWXp2+4H9w== From: Miquel Raynal Date: Fri, 05 Dec 2025 20:38:55 +0100 Subject: [PATCH RFC 4/8] spi: spi-mem: Transform the read operation template Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251205-winbond-v6-18-rc1-cont-read-v1-4-01bc48631c73@bootlin.com> References: <20251205-winbond-v6-18-rc1-cont-read-v1-0-01bc48631c73@bootlin.com> In-Reply-To: <20251205-winbond-v6-18-rc1-cont-read-v1-0-01bc48631c73@bootlin.com> To: Mark Brown , Richard Weinberger , Vignesh Raghavendra , Michael Walle Cc: Tudor Ambarus , Pratyush Yadav , Thomas Petazzoni , Steam Lin , Santhosh Kumar K , linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, Miquel Raynal X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 As of now, we only use a single operation template when creating SPI memory direct mappings. With the idea to extend this possibility to 2, rename the template to reflect that we are currently setting the "primary" operation, and create a pointer in the same structure to point to it. From a user point of view, the op_tmpl name remains but becomes a pointer, leading to minor changes in both the SPI NAND and SPI NOR cores. There is no functional change. Signed-off-by: Miquel Raynal Acked-by: Mark Brown --- drivers/mtd/nand/spi/core.c | 15 ++++++++------- drivers/mtd/spi-nor/core.c | 20 ++++++++++---------- drivers/spi/spi-mem.c | 15 ++++++++------- include/linux/spi/spi-mem.h | 3 ++- 4 files changed, 28 insertions(+), 25 deletions(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 086c9f293373..209146f21326 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -401,9 +401,9 @@ static int spinand_read_from_cache_op(struct spinand_de= vice *spinand, =20 if (nand->ecc.engine->integration =3D=3D NAND_ECC_ENGINE_INTEGRATION_PIPE= LINED && req->mode !=3D MTD_OPS_RAW) - rdesc->info.op_tmpl.data.ecc =3D true; + rdesc->info.op_tmpl->data.ecc =3D true; else - rdesc->info.op_tmpl.data.ecc =3D false; + rdesc->info.op_tmpl->data.ecc =3D false; =20 if (spinand->flags & SPINAND_HAS_READ_PLANE_SELECT_BIT) column |=3D req->pos.plane << fls(nanddev_page_size(nand)); @@ -496,9 +496,9 @@ static int spinand_write_to_cache_op(struct spinand_dev= ice *spinand, =20 if (nand->ecc.engine->integration =3D=3D NAND_ECC_ENGINE_INTEGRATION_PIPE= LINED && req->mode !=3D MTD_OPS_RAW) - wdesc->info.op_tmpl.data.ecc =3D true; + wdesc->info.op_tmpl->data.ecc =3D true; else - wdesc->info.op_tmpl.data.ecc =3D false; + wdesc->info.op_tmpl->data.ecc =3D false; =20 if (spinand->flags & SPINAND_HAS_PROG_PLANE_SELECT_BIT) column |=3D req->pos.plane << fls(nanddev_page_size(nand)); @@ -1149,7 +1149,8 @@ static int spinand_create_dirmap(struct spinand_devic= e *spinand, =20 /* Write descriptor */ info.length =3D nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); - info.op_tmpl.data.ecc =3D enable_ecc; + info.primary_op_tmpl =3D *spinand->op_templates->update_cache; + info.primary_op_tmpl.data.ecc =3D enable_ecc; desc =3D devm_spi_mem_dirmap_create(&spinand->spimem->spi->dev, spinand->spimem, &info); if (IS_ERR(desc)) @@ -1158,8 +1159,8 @@ static int spinand_create_dirmap(struct spinand_devic= e *spinand, spinand->dirmaps[plane].wdesc =3D desc; =20 /* Read descriptor */ - info.op_tmpl =3D *spinand->op_templates->read_cache; - info.op_tmpl.data.ecc =3D enable_ecc; + info.primary_op_tmpl =3D *spinand->op_templates->read_cache; + info.primary_op_tmpl.data.ecc =3D enable_ecc; desc =3D spinand_create_rdesc(spinand, &info); if (IS_ERR(desc)) return PTR_ERR(desc); diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 20ea80450f22..4de0a2b66e56 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -3631,14 +3631,14 @@ EXPORT_SYMBOL_GPL(spi_nor_scan); static int spi_nor_create_read_dirmap(struct spi_nor *nor) { struct spi_mem_dirmap_info info =3D { - .op_tmpl =3D SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0), - SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), - SPI_MEM_OP_DUMMY(nor->read_dummy, 0), - SPI_MEM_OP_DATA_IN(0, NULL, 0)), + .primary_op_tmpl =3D SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 0), + SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), + SPI_MEM_OP_DUMMY(nor->read_dummy, 0), + SPI_MEM_OP_DATA_IN(0, NULL, 0)), .offset =3D 0, .length =3D nor->params->size, }; - struct spi_mem_op *op =3D &info.op_tmpl; + struct spi_mem_op *op =3D info.op_tmpl; =20 spi_nor_spimem_setup_op(nor, op, nor->read_proto); =20 @@ -3662,14 +3662,14 @@ static int spi_nor_create_read_dirmap(struct spi_no= r *nor) static int spi_nor_create_write_dirmap(struct spi_nor *nor) { struct spi_mem_dirmap_info info =3D { - .op_tmpl =3D SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0), - SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), - SPI_MEM_OP_NO_DUMMY, - SPI_MEM_OP_DATA_OUT(0, NULL, 0)), + .primary_op_tmpl =3D SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 0), + SPI_MEM_OP_ADDR(nor->addr_nbytes, 0, 0), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(0, NULL, 0)), .offset =3D 0, .length =3D nor->params->size, }; - struct spi_mem_op *op =3D &info.op_tmpl; + struct spi_mem_op *op =3D info.op_tmpl; =20 if (nor->program_opcode =3D=3D SPINOR_OP_AAI_WP && nor->sst_write_second) op->addr.nbytes =3D 0; diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index 71e3eaf59df9..50f16943dc73 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -642,7 +642,7 @@ EXPORT_SYMBOL_GPL(spi_mem_calc_op_duration); static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc, u64 offs, size_t len, void *buf) { - struct spi_mem_op op =3D desc->info.op_tmpl; + struct spi_mem_op op =3D *desc->info.op_tmpl; int ret; =20 op.addr.val =3D desc->info.offset + offs; @@ -662,7 +662,7 @@ static ssize_t spi_mem_no_dirmap_read(struct spi_mem_di= rmap_desc *desc, static ssize_t spi_mem_no_dirmap_write(struct spi_mem_dirmap_desc *desc, u64 offs, size_t len, const void *buf) { - struct spi_mem_op op =3D desc->info.op_tmpl; + struct spi_mem_op op =3D *desc->info.op_tmpl; int ret; =20 op.addr.val =3D desc->info.offset + offs; @@ -701,11 +701,11 @@ spi_mem_dirmap_create(struct spi_mem *mem, int ret =3D -ENOTSUPP; =20 /* Make sure the number of address cycles is between 1 and 8 bytes. */ - if (!info->op_tmpl.addr.nbytes || info->op_tmpl.addr.nbytes > 8) + if (!info->primary_op_tmpl.addr.nbytes || info->primary_op_tmpl.addr.nbyt= es > 8) return ERR_PTR(-EINVAL); =20 /* data.dir should either be SPI_MEM_DATA_IN or SPI_MEM_DATA_OUT. */ - if (info->op_tmpl.data.dir =3D=3D SPI_MEM_NO_DATA) + if (info->primary_op_tmpl.data.dir =3D=3D SPI_MEM_NO_DATA) return ERR_PTR(-EINVAL); =20 desc =3D kzalloc(sizeof(*desc), GFP_KERNEL); @@ -714,12 +714,13 @@ spi_mem_dirmap_create(struct spi_mem *mem, =20 desc->mem =3D mem; desc->info =3D *info; + desc->info.op_tmpl =3D &desc->info.primary_op_tmpl; if (ctlr->mem_ops && ctlr->mem_ops->dirmap_create) ret =3D ctlr->mem_ops->dirmap_create(desc); =20 if (ret) { desc->nodirmap =3D true; - if (!spi_mem_supports_op(desc->mem, &desc->info.op_tmpl)) + if (!spi_mem_supports_op(desc->mem, &desc->info.primary_op_tmpl)) ret =3D -EOPNOTSUPP; else ret =3D 0; @@ -843,7 +844,7 @@ ssize_t spi_mem_dirmap_read(struct spi_mem_dirmap_desc = *desc, struct spi_controller *ctlr =3D desc->mem->spi->controller; ssize_t ret; =20 - if (desc->info.op_tmpl.data.dir !=3D SPI_MEM_DATA_IN) + if (desc->info.op_tmpl->data.dir !=3D SPI_MEM_DATA_IN) return -EINVAL; =20 if (!len) @@ -889,7 +890,7 @@ ssize_t spi_mem_dirmap_write(struct spi_mem_dirmap_desc= *desc, struct spi_controller *ctlr =3D desc->mem->spi->controller; ssize_t ret; =20 - if (desc->info.op_tmpl.data.dir !=3D SPI_MEM_DATA_OUT) + if (desc->info.op_tmpl->data.dir !=3D SPI_MEM_DATA_OUT) return -EINVAL; =20 if (!len) diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h index e4db0924898c..3092caefa0b6 100644 --- a/include/linux/spi/spi-mem.h +++ b/include/linux/spi/spi-mem.h @@ -217,7 +217,8 @@ struct spi_mem_op { * direction is directly encoded in the ->op_tmpl.data.dir field. */ struct spi_mem_dirmap_info { - struct spi_mem_op op_tmpl; + struct spi_mem_op *op_tmpl; + struct spi_mem_op primary_op_tmpl; u64 offset; u64 length; }; --=20 2.51.1 From nobody Tue Dec 16 07:34:53 2025 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (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 306B231AAB8; Fri, 5 Dec 2025 19:39:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764963595; cv=none; b=rfSyCCENq11xIujBDXa15ZjrMgcXgYWtgtFBC4s1d+BySIBZx7Ag1BP7oAe0DupBlhgu3QYWdLYMtVIx/Fk7G/TbtKSmiHM7kC4UDXuV7x3oMNT4VHVi+bcA4H0TMNpobg6LfSJyhmvpIYTsNQqAdqfFts3KZ5DAzZBBeX01tTk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764963595; c=relaxed/simple; bh=8MfZrxm+61/f0kdvvZFpnJWPO1aniiNrAmuo+gmtrlM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=F16XXhkJJgI+lUqZXqRT+Zil2xeyN7jmAGh8VAsdu8YH91QK19gkY6jjyTt8wQ1zi35fLOkAZoX0hhjuMGjGvhAwaz5sYngYz/7LevY3rQUsUtNCnuRDqCyGq33nd2njSLmmdo7i2NPlV2BtRqeqeR3YKLyLPfUBgGEa8mZHBy8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=nSdCXRxc; arc=none smtp.client-ip=185.246.85.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="nSdCXRxc" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id 76F314E41A72; Fri, 5 Dec 2025 19:39:51 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 478CA606AC; Fri, 5 Dec 2025 19:39:51 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 2C20C102F1956; Fri, 5 Dec 2025 20:39:48 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1764963590; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=V1ljS8mutIdNmKv1uTSb1HOPJkaHUuTFfvh6FqXD2eU=; b=nSdCXRxcvN2Tl6j80JiBHD5VXqmAb7ozAe3pOWLL0TCcmgz74lHnCUVCUSrEU0h4mGed34 JNJ9VkXDTUIHl3A12525JxJqlmuFa26k2arTrtbB8a9xN5IvUj/6XHs3tbByK28V3fw+EB To0Wo+B7Wnzw11pFwQorDZXUR2VwwYRP+88vRe552E/aCI8AutOTrY4XhYJAgfcbKyeEq6 53hZk46QueC2gXbjkX/ouxdtBvNbiAHqdNCcBUnUsCCN41z88bw5FV9eS3pz1Ap1R0NFvZ Cl4KHTzx3XaLEtD2XmviJoHz+l3JEVspmc9a8Lpy9Ln+a5+OsbO4MBZGhtbpxw== From: Miquel Raynal Date: Fri, 05 Dec 2025 20:38:56 +0100 Subject: [PATCH RFC 5/8] spi: spi-mem: Create a secondary read operation Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251205-winbond-v6-18-rc1-cont-read-v1-5-01bc48631c73@bootlin.com> References: <20251205-winbond-v6-18-rc1-cont-read-v1-0-01bc48631c73@bootlin.com> In-Reply-To: <20251205-winbond-v6-18-rc1-cont-read-v1-0-01bc48631c73@bootlin.com> To: Mark Brown , Richard Weinberger , Vignesh Raghavendra , Michael Walle Cc: Tudor Ambarus , Pratyush Yadav , Thomas Petazzoni , Steam Lin , Santhosh Kumar K , linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, Miquel Raynal X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 In some situations, direct mappings may need to use different operation templates. For instance, when enabling continuous reads, Winbond SPI NANDs no longer expect address cycles because they would be ignoring them otherwise. Hence, right after the command opcode, they start counting dummy cycles, followed by the data cycles as usual. This breaks the assumptions of "reads from cache" always being done identically once the best variant has been picked up, across the lifetime of the system. In order to support this feature, we must give direct mapping more than a single operation template to use, in order to switch to using secondary operations upon request by the upper layer. Create the concept of optional secondary operation template, which may or may not be fulfilled by the SPI NAND and SPI NOR cores. If the underlying SPI controller does not leverage any kind of direct mapping acceleration, the feature has no impact and can be freely used. Otherwise, the controller driver needs to opt-in for using this feature, if supported. The condition checked to know whether a secondary operation has been provided or not is to look for a non zero opcode to limit the creation of extra variables. In practice, the opcode 0x00 exist, but is not related to any cache related operation. Signed-off-by: Miquel Raynal Acked-by: Mark Brown --- The choice of defining two variables named primary and secondary instead of using an array of templates is on purpose, to simplify the reading. I find less obvious the use of an array here but this is personal taste. --- drivers/spi/spi-mem.c | 17 +++++++++++++++++ include/linux/spi/spi-mem.h | 5 +++++ 2 files changed, 22 insertions(+) diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index 50f16943dc73..b6debc796cf8 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -708,6 +708,23 @@ spi_mem_dirmap_create(struct spi_mem *mem, if (info->primary_op_tmpl.data.dir =3D=3D SPI_MEM_NO_DATA) return ERR_PTR(-EINVAL); =20 + /* Apply similar constraints to the secondary template */ + if (info->secondary_op_tmpl.cmd.opcode) { + if (!info->secondary_op_tmpl.addr.nbytes || + info->secondary_op_tmpl.addr.nbytes > 8) + return ERR_PTR(-EINVAL); + + if (info->secondary_op_tmpl.data.dir =3D=3D SPI_MEM_NO_DATA) + return ERR_PTR(-EINVAL); + + if (!spi_mem_supports_op(mem, &info->secondary_op_tmpl)) + return ERR_PTR(-EOPNOTSUPP); + + if (ctlr->mem_ops && ctlr->mem_ops->dirmap_create && + !spi_mem_controller_is_capable(ctlr, secondary_op_tmpl)) + return ERR_PTR(-EOPNOTSUPP); + } + desc =3D kzalloc(sizeof(*desc), GFP_KERNEL); if (!desc) return ERR_PTR(-ENOMEM); diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h index 3092caefa0b6..099de23e7084 100644 --- a/include/linux/spi/spi-mem.h +++ b/include/linux/spi/spi-mem.h @@ -207,6 +207,8 @@ struct spi_mem_op { * struct spi_mem_dirmap_info - Direct mapping information * @op_tmpl: operation template that should be used by the direct mapping = when * the memory device is accessed + * @secondary_op_tmpl: secondary template, may be used as an alternative t= o the + * primary template (decided by the upper layer) * @offset: absolute offset this direct mapping is pointing to * @length: length in byte of this direct mapping * @@ -219,6 +221,7 @@ struct spi_mem_op { struct spi_mem_dirmap_info { struct spi_mem_op *op_tmpl; struct spi_mem_op primary_op_tmpl; + struct spi_mem_op secondary_op_tmpl; u64 offset; u64 length; }; @@ -362,12 +365,14 @@ struct spi_controller_mem_ops { * @swap16: Supports swapping bytes on a 16 bit boundary when configured in * Octal DTR * @per_op_freq: Supports per operation frequency switching + * @secondary_op_tmpl: Supports leveraging a secondary memory operation te= mplate */ struct spi_controller_mem_caps { bool dtr; bool ecc; bool swap16; bool per_op_freq; + bool secondary_op_tmpl; }; =20 #define spi_mem_controller_is_capable(ctlr, cap) \ --=20 2.51.1 From nobody Tue Dec 16 07:34:53 2025 Received: from smtpout-04.galae.net (smtpout-04.galae.net [185.171.202.116]) (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 70541322B7E; Fri, 5 Dec 2025 19:39:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.171.202.116 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764963598; cv=none; b=qTVBsoihaNZuKsX7rr4Mbwkk9KEy5SsgVR1ZUyuBcjoOFJ/JUKeRHrGhvQxwYu82fCKZ9mF21mZATLrJgfgegL3eJuGD1zKZjUJweqSsZsdt//LbsjS12I45yvu1lbMSZWQSgjX8WP3uoug9Nn4BZIxQVqdfj3T3XEzITpfGsrI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764963598; c=relaxed/simple; bh=vPU+4PGXnQKsNC72tkHF1EUG8fgwp0WizxbbC7wkK7M=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=DggfXMV+kQtVap+3YAqDMkylnRAaGS8KKrEp+i4x7el0G4ACDATyBNvrbtGqiOFuDRHfic9EUGg/5Ngs/a+L3Qkaasrl4wj7vf3JOTPa1oICFkk5Q3i3cpfWuv/12Lvt6IZ394NIg/4h+qJJ+3iQQi652rS0D1Eyrpf4rIeRLl4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=l0UnPVwa; arc=none smtp.client-ip=185.171.202.116 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="l0UnPVwa" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id 93921C1964F; Fri, 5 Dec 2025 19:39:31 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 15AB9606AC; Fri, 5 Dec 2025 19:39:55 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id DA3F6102F18EA; Fri, 5 Dec 2025 20:39:52 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1764963594; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=EkSh6VEYpuxxHIEG0meSRCtp2QS/BqvaPUatfSsQwyk=; b=l0UnPVwaxkv3cNVoVZhqxcBtHj/KIOZxR4infQxPfyFagCIgmhNDZrxDjBI5puCdWJc8+f DUWCSsjTC1lRV2W0N3O7Vb07COds0f9Llo9oTAHnY9MQ/gc5RF2AccEJanM8/9DGYCM6u0 tafGBtWg+ZDkWmD0d/NidnUnLk8dpAWL6Ug16H237c2ECGdoTB633g5WiVIwQ9tF9xis/8 9bXB3yk1O9XepqOXPAHFlppJSmrnaEcb1A7p5lxNRID4ClW0pkhk0KaBLr3ncywxFUqQk5 AKNIhfgJntzOV/0pHNo8pRGRuegIkA/aTy1QyTORiHEmqKJaSKPSZKnKMFvbDw== From: Miquel Raynal Date: Fri, 05 Dec 2025 20:38:57 +0100 Subject: [PATCH RFC 6/8] mtd: spinand: Use secondary ops for continuous reads Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251205-winbond-v6-18-rc1-cont-read-v1-6-01bc48631c73@bootlin.com> References: <20251205-winbond-v6-18-rc1-cont-read-v1-0-01bc48631c73@bootlin.com> In-Reply-To: <20251205-winbond-v6-18-rc1-cont-read-v1-0-01bc48631c73@bootlin.com> To: Mark Brown , Richard Weinberger , Vignesh Raghavendra , Michael Walle Cc: Tudor Ambarus , Pratyush Yadav , Thomas Petazzoni , Steam Lin , Santhosh Kumar K , linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, Miquel Raynal X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 In case a chip supports continuous reads, but uses a slightly different cache operation for these, it may provide a secondary operation template which will be used only during continuous cache read operations. From a vendor driver point of view, enabling this feature implies providing a new set of templates for these continuous read operations. The core will automatically pick the fastest variant, depending on the hardware capabilities. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/spi/core.c | 51 +++++++++++++++++++++++++++++++++++++++++= +++- include/linux/mtd/spinand.h | 12 +++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 209146f21326..37a0d0373942 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -399,6 +399,11 @@ static int spinand_read_from_cache_op(struct spinand_d= evice *spinand, =20 rdesc =3D spinand->dirmaps[req->pos.plane].rdesc; =20 + if (spinand->op_templates->cont_read_cache && req->continuous) + rdesc->info.op_tmpl =3D &rdesc->info.secondary_op_tmpl; + else + rdesc->info.op_tmpl =3D &rdesc->info.primary_op_tmpl; + if (nand->ecc.engine->integration =3D=3D NAND_ECC_ENGINE_INTEGRATION_PIPE= LINED && req->mode !=3D MTD_OPS_RAW) rdesc->info.op_tmpl->data.ecc =3D true; @@ -1123,6 +1128,7 @@ static struct spi_mem_dirmap_desc *spinand_create_rde= sc( * its spi controller, use regular reading */ spinand->cont_read_possible =3D false; + memset(&info->secondary_op_tmpl, 0, sizeof(info->secondary_op_tmpl)); =20 info->length =3D nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); @@ -1139,11 +1145,24 @@ static int spinand_create_dirmap(struct spinand_dev= ice *spinand, struct nand_device *nand =3D spinand_to_nand(spinand); struct spi_mem_dirmap_info info =3D { 0 }; struct spi_mem_dirmap_desc *desc; - bool enable_ecc =3D false; + bool enable_ecc =3D false, secondary_op =3D false; =20 if (nand->ecc.engine->integration =3D=3D NAND_ECC_ENGINE_INTEGRATION_PIPE= LINED) enable_ecc =3D true; =20 + if (spinand->cont_read_possible && spinand->op_templates->cont_read_cache) + secondary_op =3D true; + + /* + * Continuous read implies that only the main data is retrieved, backed + * by an on-die ECC engine. It is not possible to use a pipelind ECC + * engine with continuous read. + */ + if (enable_ecc && secondary_op) { + secondary_op =3D false; + spinand->cont_read_possible =3D false; + } + /* The plane number is passed in MSB just above the column address */ info.offset =3D plane << fls(nand->memorg.pagesize); =20 @@ -1161,6 +1180,10 @@ static int spinand_create_dirmap(struct spinand_devi= ce *spinand, /* Read descriptor */ info.primary_op_tmpl =3D *spinand->op_templates->read_cache; info.primary_op_tmpl.data.ecc =3D enable_ecc; + if (secondary_op) { + info.secondary_op_tmpl =3D *spinand->op_templates->cont_read_cache; + info.secondary_op_tmpl.data.ecc =3D enable_ecc; + } desc =3D spinand_create_rdesc(spinand, &info); if (IS_ERR(desc)) return PTR_ERR(desc); @@ -1505,6 +1528,27 @@ int spinand_match_and_init(struct spinand_device *sp= inand, if (ret) return ret; =20 + op =3D spinand_select_op_variant(spinand, SSDR, + info->op_variants.cont_read_cache); + if (op) { + const struct spi_mem_op *read_op =3D spinand->ssdr_op_templates.read_ca= che; + + /* + * Sometimes the fastest continuous read variant may not + * be supported. In this case, prefer to use the fastest + * read from cache variant and disable continuous reads. + */ + if (read_op->cmd.buswidth !=3D op->cmd.buswidth || + read_op->cmd.dtr !=3D op->cmd.dtr || + read_op->addr.buswidth !=3D op->addr.buswidth || + read_op->addr.dtr !=3D op->addr.dtr || + read_op->cmd.buswidth !=3D op->cmd.buswidth || + read_op->cmd.dtr !=3D op->cmd.dtr) + spinand->cont_read_possible =3D false; + else + spinand->ssdr_op_templates.cont_read_cache =3D op; + } + /* I/O variants selection with octo-spi DDR commands (optional) */ =20 ret =3D spinand_init_odtr_instruction_set(spinand); @@ -1527,6 +1571,11 @@ int spinand_match_and_init(struct spinand_device *sp= inand, info->op_variants.update_cache); spinand->odtr_op_templates.update_cache =3D op; =20 + op =3D spinand_select_op_variant(spinand, ODTR, + info->op_variants.cont_read_cache); + if (op) + spinand->odtr_op_templates.cont_read_cache =3D op; + return 0; } =20 diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index 5ca1181048f7..5ec7d756df8b 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -573,6 +573,7 @@ enum spinand_bus_interface { * @op_variants.read_cache: variants of the read-cache operation * @op_variants.write_cache: variants of the write-cache operation * @op_variants.update_cache: variants of the update-cache operation + * @op_variants.cont_read_cache: variants of the continuous read-cache ope= ration * @vendor_ops: vendor specific operations * @select_target: function used to select a target/die. Required only for * multi-die chips @@ -597,6 +598,7 @@ struct spinand_info { const struct spinand_op_variants *read_cache; const struct spinand_op_variants *write_cache; const struct spinand_op_variants *update_cache; + const struct spinand_op_variants *cont_read_cache; } op_variants; const struct spinand_op_variants *vendor_ops; int (*select_target)(struct spinand_device *spinand, @@ -626,6 +628,14 @@ struct spinand_info { .update_cache =3D __update, \ } =20 +#define SPINAND_INFO_OP_VARIANTS_WITH_CONT(__read, __write, __update, __co= nt_read) \ + { \ + .read_cache =3D __read, \ + .write_cache =3D __write, \ + .update_cache =3D __update, \ + .cont_read_cache =3D __cont_read, \ + } + #define SPINAND_INFO_VENDOR_OPS(__ops) \ .vendor_ops =3D __ops =20 @@ -697,6 +707,7 @@ struct spinand_dirmap { * @read_cache: read cache op template * @write_cache: write cache op template * @update_cache: update cache op template + * @cont_read_cache: continuous read cache op template (optional) */ struct spinand_mem_ops { struct spi_mem_op reset; @@ -711,6 +722,7 @@ struct spinand_mem_ops { const struct spi_mem_op *read_cache; const struct spi_mem_op *write_cache; const struct spi_mem_op *update_cache; + const struct spi_mem_op *cont_read_cache; }; =20 /** --=20 2.51.1 From nobody Tue Dec 16 07:34:53 2025 Received: from smtpout-03.galae.net (smtpout-03.galae.net [185.246.85.4]) (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 CD72031AABC for ; Fri, 5 Dec 2025 19:39:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.85.4 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764963601; cv=none; b=jwkqHd/O3Rxo4BIPHyYJi6SkzOQSSwgVsXwYjmW1g93ND4PBDA7GQR/0ct4c7cGw8y1svIJ1/N1zruzd1yhi19t0mjWma3BXQgCAU5SUI8cRlbbTr2hfs7Bhr4RwcLxnN2fQPyCQb2tuuoLRYXKG4bx4UPmHCTiFsJg5p0sbUhM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764963601; c=relaxed/simple; bh=2GbAvy1Qw5k+Ex13ZF8rGtLEOuqfGDAb75VkLT269oU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=BGyoHxUY0Vf9z+My/bUGV4r31P0AqVh4xd4QDCmR4kmgz29HY9x3At4Ly7QvcSVoJDF+l+2je4sRz52CmkWbXG6Yv2HbZHuV+Z+8+wNFE8Sf77LYFbPHJf7gw+QTBXkAtm33x6C2gGD8OXLXXitsMfq6UifLNTCnvGxTibIoJrU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=ivBdp0CX; arc=none smtp.client-ip=185.246.85.4 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="ivBdp0CX" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id 6E1954E41A73; Fri, 5 Dec 2025 19:39:57 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 456F3606AC; Fri, 5 Dec 2025 19:39:57 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id D5CB0102F1912; Fri, 5 Dec 2025 20:39:54 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1764963596; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=sVPNQ7cUFtk5zE8KkLKIlIZlmxcg1JpVSLwuIhQXnKA=; b=ivBdp0CXmxla8MF/ehBTkt1OxYIDldUWu8bIKlsLWF3/yBe/vA/ff9jP1J8B6Co3qNC0CO vc7O9p0skdr012rMhgRzml+WZ9ocxjJYcbFsZjPg91Wy+W3cevNH7kogR2tnoBA+andzqF eUalJ5t/lMOcrvdtcq9BfMn8dpPrbvRFi/sqtXwFE2Lm0cgLa/I/aw/SClSuUNsB0CdxIp JSu38S6oCv4P4iIC4Uzelx/iaodrh1oTQIIJEY8y8AODHmNxo16iDZFgO8R7q33bbdME7g U4ZMybsbFJ1gCasD/dsRtYZwQGdbTgr4wLqWfKrXgscg2jNYA+ORTGf8o6KM2A== From: Miquel Raynal Date: Fri, 05 Dec 2025 20:38:58 +0100 Subject: [PATCH RFC 7/8] mtd: spinand: winbond: Add support for continuous reads on W35NxxJW Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251205-winbond-v6-18-rc1-cont-read-v1-7-01bc48631c73@bootlin.com> References: <20251205-winbond-v6-18-rc1-cont-read-v1-0-01bc48631c73@bootlin.com> In-Reply-To: <20251205-winbond-v6-18-rc1-cont-read-v1-0-01bc48631c73@bootlin.com> To: Mark Brown , Richard Weinberger , Vignesh Raghavendra , Michael Walle Cc: Tudor Ambarus , Pratyush Yadav , Thomas Petazzoni , Steam Lin , Santhosh Kumar K , linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, Miquel Raynal X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 W35N{01,02,04}JW support being read continuously under certain circumstances. A bit must be set in their configuration register, and a specific read from cache operation, a bit shorter than usual because it no longer requires the address cycles, must be used for the occasion. Setting the "enable" bit is already supported by the core, aside from the subtlety of making sure the HFREQ bit is also set in octal DTR mode above 90MHz. However, handling two different read from cache templates involves creating a list of read from cache variants adapted the continuous reads, ie. without address cycles. Unfortunately, these operations, despite being very close to their original read from cache cousins, are often unsupported by smart SPI controller drivers because reading from cache historically allowed changing the offset at which the host would start by providing a 2-byte column address. In order to prevent issues with this, it has been decided to implement these variants with a single "ignored" address byte (respectively two in the octal DTR case), further reducing the amount of dummy cycles needed before the first bit of data. Enabling continuous reads has a side effect: the ECC status register now may also return the value b11, which means that more than 1 uncorrectable error happened during the read. This non standard behaviour requires to re-implement, almost identically the "get ECC" helper from the core, with just an extra case for this value (it is prefixed "w25w35nxxjw" because all these chips have the same behaviour). Speed gain is substantial, see below. The flash_speed -C benchmark has been run on a TI AM62A7 LP SK with CPU power management disabled, mounted with a W35N01JW chip. 1S-8S-8S: 1 page read speed is 15058 KiB/s 2 page read speed is 15058 KiB/s 3 page read speed is 16800 KiB/s 4 page read speed is 17066 KiB/s 5 page read speed is 18461 KiB/s 6 page read speed is 18461 KiB/s 7 page read speed is 19384 KiB/s 8 page read speed is 19692 KiB/s 9 page read speed is 19384 KiB/s 10 page read speed is 20000 KiB/s 11 page read speed is 20000 KiB/s 12 page read speed is 20000 KiB/s 13 page read speed is 20800 KiB/s 14 page read speed is 20363 KiB/s 15 page read speed is 20000 KiB/s 16 page read speed is 19692 KiB/s 32 page read speed is 19692 KiB/s 64 page read speed is 19692 KiB/s 8D-8D-8D: 1 page read speed is 23272 KiB/s 2 page read speed is 23272 KiB/s 3 page read speed is 28000 KiB/s 4 page read speed is 32000 KiB/s 5 page read speed is 34285 KiB/s 6 page read speed is 34285 KiB/s 7 page read speed is 36000 KiB/s 8 page read speed is 36571 KiB/s 9 page read speed is 36000 KiB/s 10 page read speed is 34285 KiB/s 11 page read speed is 36666 KiB/s 12 page read speed is 40000 KiB/s 13 page read speed is 41600 KiB/s 14 page read speed is 37333 KiB/s 15 page read speed is 40000 KiB/s 16 page read speed is 36571 KiB/s 32 page read speed is 42666 KiB/s 64 page read speed is 42666 KiB/s Signed-off-by: Miquel Raynal --- Not all configurations have been tested/validated yet. --- drivers/mtd/nand/spi/winbond.c | 126 ++++++++++++++++++++++++++++++++++++-= ---- 1 file changed, 111 insertions(+), 15 deletions(-) diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c index d0c50eb93827..716ec0031dcc 100644 --- a/drivers/mtd/nand/spi/winbond.c +++ b/drivers/mtd/nand/spi/winbond.c @@ -15,9 +15,11 @@ =20 #define SPINAND_MFR_WINBOND 0xEF =20 +#define WINBOND_CFG_HFREQ BIT(0) #define WINBOND_CFG_BUF_READ BIT(3) =20 #define W25N04KV_STATUS_ECC_5_8_BITFLIPS (3 << 4) +#define W25W35NXXJW_STATUS_ECC_MULT_UNCOR (3 << 4) =20 #define W25N0XJW_SR4 0xD0 #define W25N0XJW_SR4_HS BIT(2) @@ -29,6 +31,49 @@ #define W35N01JW_VCR_IO_MODE_OCTAL_DDR 0xC7 #define W35N01JW_VCR_DUMMY_CLOCK_REG 0x01 =20 +/* + * Winbond chips ignore the address bytes during continuous reads, and + * because the dummy cycles are enough they indicate dropping the + * address cycles from the continuous read from cache variants. This is + * very poorly supported by SPI controller drivers which are "wired" to + * always at least provide the column. Keep using address cycles, but + * reduce the number of dummy cycles accordingly. + */ +#define WINBOND_CONT_READ_FROM_CACHE_FAST_1S_1S_1S_OP(ndummy, buf, len, fr= eq) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x0b, 1), \ + SPI_MEM_OP_ADDR(1, 0, 1), \ + SPI_MEM_OP_DUMMY(ndummy - 1, 1), \ + SPI_MEM_OP_DATA_IN(len, buf, 1), \ + SPI_MEM_OP_MAX_FREQ(freq)) + +#define WINBOND_CONT_READ_FROM_CACHE_1S_1S_8S_OP(ndummy, buf, len, freq) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x8b, 1), \ + SPI_MEM_OP_ADDR(1, 0, 1), \ + SPI_MEM_OP_DUMMY(ndummy - 1, 1), \ + SPI_MEM_OP_DATA_IN(len, buf, 8), \ + SPI_MEM_OP_MAX_FREQ(freq)) + +#define WINBOND_CONT_READ_FROM_CACHE_1S_1D_8D_OP(ndummy, buf, len, freq) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x9d, 1), \ + SPI_MEM_DTR_OP_ADDR(1, 0, 1), \ + SPI_MEM_DTR_OP_DUMMY(ndummy - 1, 1), \ + SPI_MEM_DTR_OP_DATA_IN(len, buf, 8), \ + SPI_MEM_OP_MAX_FREQ(freq)) + +#define WINBOND_CONT_READ_FROM_CACHE_1S_8S_8S_OP(ndummy, buf, len, freq) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0xcb, 1), \ + SPI_MEM_OP_ADDR(1, 0, 8), \ + SPI_MEM_OP_DUMMY(ndummy - 1, 8), \ + SPI_MEM_OP_DATA_IN(len, buf, 8), \ + SPI_MEM_OP_MAX_FREQ(freq)) + +#define WINBOND_CONT_READ_FROM_CACHE_8D_8D_8D_OP(ndummy, buf, len, freq) \ + SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9d, 8), \ + SPI_MEM_DTR_OP_ADDR(2, 0, 8), \ + SPI_MEM_DTR_OP_DUMMY(ndummy - 2, 8), \ + SPI_MEM_DTR_OP_DATA_IN(len, buf, 8), \ + SPI_MEM_OP_MAX_FREQ(freq)) + /* * "X2" in the core is equivalent to "dual output" in the datasheets, * "X4" in the core is equivalent to "quad output" in the datasheets. @@ -49,6 +94,19 @@ static SPINAND_OP_VARIANTS(read_cache_octal_variants, SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); =20 +static SPINAND_OP_VARIANTS(cont_read_cache_octal_variants, + WINBOND_CONT_READ_FROM_CACHE_8D_8D_8D_OP(24, NULL, 0, 120 * HZ_PER_MHZ), + WINBOND_CONT_READ_FROM_CACHE_8D_8D_8D_OP(16, NULL, 0, 86 * HZ_PER_MHZ), + WINBOND_CONT_READ_FROM_CACHE_1S_1D_8D_OP(3, NULL, 0, 120 * HZ_PER_MHZ), + WINBOND_CONT_READ_FROM_CACHE_1S_1D_8D_OP(2, NULL, 0, 105 * HZ_PER_MHZ), + WINBOND_CONT_READ_FROM_CACHE_1S_8S_8S_OP(20, NULL, 0, 0), + WINBOND_CONT_READ_FROM_CACHE_1S_8S_8S_OP(16, NULL, 0, 162 * HZ_PER_MHZ), + WINBOND_CONT_READ_FROM_CACHE_1S_8S_8S_OP(12, NULL, 0, 124 * HZ_PER_MHZ), + WINBOND_CONT_READ_FROM_CACHE_1S_8S_8S_OP(8, NULL, 0, 86 * HZ_PER_MHZ), + WINBOND_CONT_READ_FROM_CACHE_1S_1S_8S_OP(2, NULL, 0, 0), + WINBOND_CONT_READ_FROM_CACHE_1S_1S_8S_OP(1, NULL, 0, 133 * HZ_PER_MHZ), + WINBOND_CONT_READ_FROM_CACHE_FAST_1S_1S_1S_OP(1, NULL, 0, 0)); + static SPINAND_OP_VARIANTS(write_cache_octal_variants, SPINAND_PROG_LOAD_8D_8D_8D_OP(true, 0, NULL, 0), SPINAND_PROG_LOAD_1S_8S_8S_OP(true, 0, NULL, 0), @@ -326,6 +384,26 @@ static int w25n02kv_ecc_get_status(struct spinand_devi= ce *spinand, return -EINVAL; } =20 +static int w25w35nxxjw_ecc_get_status(struct spinand_device *spinand, u8 s= tatus) +{ + switch (status & STATUS_ECC_MASK) { + case STATUS_ECC_NO_BITFLIPS: + return 0; + + case STATUS_ECC_HAS_BITFLIPS: + return 1; + + case STATUS_ECC_UNCOR_ERROR: + case W25W35NXXJW_STATUS_ECC_MULT_UNCOR: + return -EBADMSG; + + default: + break; + } + + return -EINVAL; +} + static int w25n0xjw_hs_cfg(struct spinand_device *spinand, enum spinand_bus_interface iface) { @@ -448,6 +526,18 @@ static int w35n0xjw_vcr_cfg(struct spinand_device *spi= nand, return 0; } =20 +static int w35n0xjw_set_cont_read(struct spinand_device *spinand, bool ena= ble) +{ + const struct spi_mem_op *cont_op =3D spinand->op_templates->cont_read_cac= he; + u8 mask =3D enable ? 0 : WINBOND_CFG_BUF_READ; + + if (cont_op && enable && spinand_op_is_odtr(cont_op) && + cont_op->max_freq >=3D 90 * HZ_PER_MHZ) + mask |=3D WINBOND_CFG_HFREQ; + + return spinand_upd_cfg(spinand, WINBOND_CFG_BUF_READ | WINBOND_CFG_HFREQ,= mask); +} + static const struct spinand_info winbond_spinand_table[] =3D { /* 512M-bit densities */ SPINAND_INFO("W25N512GW", /* 1.8V */ @@ -501,35 +591,41 @@ static const struct spinand_info winbond_spinand_tabl= e[] =3D { SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdc, 0x21), NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 1, 1), NAND_ECCREQ(1, 512), - SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants, - &write_cache_octal_variants, - &update_cache_octal_variants), + SPINAND_INFO_OP_VARIANTS_WITH_CONT(&read_cache_octal_variants, + &write_cache_octal_variants, + &update_cache_octal_variants, + &cont_read_cache_octal_variants), 0, SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops), - SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL), - SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)), + SPINAND_ECCINFO(&w35n01jw_ooblayout, w25w35nxxjw_ecc_get_status), + SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg), + SPINAND_CONT_READ(w35n0xjw_set_cont_read)), SPINAND_INFO("W35N02JW", /* 1.8V */ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdf, 0x22), NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 2, 1), NAND_ECCREQ(1, 512), - SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants, - &write_cache_octal_variants, - &update_cache_octal_variants), + SPINAND_INFO_OP_VARIANTS_WITH_CONT(&read_cache_octal_variants, + &write_cache_octal_variants, + &update_cache_octal_variants, + &cont_read_cache_octal_variants), 0, SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops), - SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL), - SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)), + SPINAND_ECCINFO(&w35n01jw_ooblayout, w25w35nxxjw_ecc_get_status), + SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg), + SPINAND_CONT_READ(w35n0xjw_set_cont_read)), SPINAND_INFO("W35N04JW", /* 1.8V */ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdf, 0x23), NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 4, 1), NAND_ECCREQ(1, 512), - SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants, - &write_cache_octal_variants, - &update_cache_octal_variants), + SPINAND_INFO_OP_VARIANTS_WITH_CONT(&read_cache_octal_variants, + &write_cache_octal_variants, + &update_cache_octal_variants, + &cont_read_cache_octal_variants), 0, SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops), - SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL), - SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)), + SPINAND_ECCINFO(&w35n01jw_ooblayout, w25w35nxxjw_ecc_get_status), + SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg), + SPINAND_CONT_READ(w35n0xjw_set_cont_read)), /* 2G-bit densities */ SPINAND_INFO("W25M02GV", /* 2x1G-bit 3.3V */ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21), --=20 2.51.1 From nobody Tue Dec 16 07:34:53 2025 Received: from smtpout-02.galae.net (smtpout-02.galae.net [185.246.84.56]) (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 BC9FD322B62 for ; Fri, 5 Dec 2025 19:40:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.246.84.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764963604; cv=none; b=ioEaWktyI7ecnPNWwgQtz/3w+xANFri6yxPJHvRljvoUMmiOH8r/lYPioiKCPK4Z6VZq+Kd7CWBM8sVnVhwyAEsACILPhBh02XoIQfVS1H6syPCqkECqgaMneN4vLSnckDominIJULbzcVhJtIUAcMSmjN4Kpdi33itZXEWs4LA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764963604; c=relaxed/simple; bh=LOlYXx8mxPNt6HaussYG9Evt0KcGlY6+Gxa3oa0zQPU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=u4qyvUoxclEvbP43HlY+P/KsosT6Yxa9+7yTvIEdvujLN8oQ5NIMbGBXbVsqtt2B/M08KSjfBxg5uiMk7gkUrPb6Jy9I69jhQ5zHTFG0LWXSVnmXSSfdu5xygyMDzKtihzPtY814lfs1rYX3MQ2GE1MyeVzV8WGrFbMkghxl4xM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=nANrOYy6; arc=none smtp.client-ip=185.246.84.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="nANrOYy6" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-02.galae.net (Postfix) with ESMTPS id 03D611A1F9E; Fri, 5 Dec 2025 19:40:00 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id C866D606AC; Fri, 5 Dec 2025 19:39:59 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 061BC102F1922; Fri, 5 Dec 2025 20:39:56 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1764963598; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=VLpCbibqMqq4V05mhr2XLWcbEbjHZFZ15G7eFy3jZnQ=; b=nANrOYy6a19zO5JBJlb2qKQGQew00dsTdnPuL2Tdzstdw2bC+Wr7eHrYa7GMoJhZBhu0k/ mIF+CkU/SeSLAzOhSIJIgEoW3FGEzQFZwMPjhg6iDvqtQl42ceArz4s0P29rOUmNOMpaOC am3HQDJU7XOc8WiuXj0mokFMdrSCSoGrPLLfCAtRfCkXdA4Jj3d5iPQP9WlTh5TtpWoNta CTsdJ1Nos05nn2PO8jWs40pP+ZKBIEorlA/jDRKXVhuTHF485OTx4uJvlNyM5ybYiwaspC +56DfuMHMQSpoyJA2tBGzcZky4flwFoZLBKs6AXj6Eus07HfMnOi3Vv0C+nSNA== From: Miquel Raynal Date: Fri, 05 Dec 2025 20:38:59 +0100 Subject: [PATCH RFC 8/8] mtd: spinand: winbond: Add support for continuous reads on W25NxxJW Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251205-winbond-v6-18-rc1-cont-read-v1-8-01bc48631c73@bootlin.com> References: <20251205-winbond-v6-18-rc1-cont-read-v1-0-01bc48631c73@bootlin.com> In-Reply-To: <20251205-winbond-v6-18-rc1-cont-read-v1-0-01bc48631c73@bootlin.com> To: Mark Brown , Richard Weinberger , Vignesh Raghavendra , Michael Walle Cc: Tudor Ambarus , Pratyush Yadav , Thomas Petazzoni , Steam Lin , Santhosh Kumar K , linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, Miquel Raynal X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 As for the W35NxxJW family, add support for W25N{01,02}JW continuous read support. Similar operations require to be done, such as setting a specific bit in a configuration register, and providing a set of read variants without the address cycles. As read from cache variants are badly supported by SPI memory controllers, we create a new set of read from cache templates with a fake address cycle and just enough dummy cycles. There are two unsupported configurations (which would require 4.5 dummy bytes), so we just do not provide them. The same extra value in the ECC is possible as with the W35NxxJW family, so we reference the same helper to retrieve the ECC status. TODO: Further validate the feature and measure its impact. Signed-off-by: Miquel Raynal --- This patch has been compile tested only. --- drivers/mtd/nand/spi/winbond.c | 101 +++++++++++++++++++++++++++++++++++++= ---- 1 file changed, 91 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c index 716ec0031dcc..55f6229666bc 100644 --- a/drivers/mtd/nand/spi/winbond.c +++ b/drivers/mtd/nand/spi/winbond.c @@ -46,6 +46,62 @@ SPI_MEM_OP_DATA_IN(len, buf, 1), \ SPI_MEM_OP_MAX_FREQ(freq)) =20 +#define WINBOND_CONT_READ_FROM_CACHE_1S_1D_1D_OP(ndummy, buf, len, freq) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x0d, 1), \ + SPI_MEM_DTR_OP_ADDR(2, 0, 1), \ + SPI_MEM_DTR_OP_DUMMY(ndummy, 1), \ + SPI_MEM_DTR_OP_DATA_IN(len, buf, 1), \ + SPI_MEM_OP_MAX_FREQ(freq)) + +#define WINBOND_CONT_READ_FROM_CACHE_1S_1S_2S_OP(ndummy, buf, len, freq) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \ + SPI_MEM_OP_ADDR(1, 0, 1), \ + SPI_MEM_OP_DUMMY(ndummy - 1, 1), \ + SPI_MEM_OP_DATA_IN(len, buf, 2), \ + SPI_MEM_OP_MAX_FREQ(freq)) + +#define WINBOND_CONT_READ_FROM_CACHE_1S_2S_2S_OP(ndummy, buf, len, freq) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \ + SPI_MEM_OP_ADDR(1, 0, 2), \ + SPI_MEM_OP_DUMMY(ndummy - 1, 2), \ + SPI_MEM_OP_DATA_IN(len, buf, 2), \ + SPI_MEM_OP_MAX_FREQ(freq)) + +#define WINBOND_CONT_READ_FROM_CACHE_1S_2D_2D_OP(ndummy, buf, len, freq) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0xbd, 1), \ + SPI_MEM_DTR_OP_ADDR(1, 0, 2), \ + SPI_MEM_DTR_OP_DUMMY(ndummy - 1, 2), \ + SPI_MEM_DTR_OP_DATA_IN(len, buf, 2), \ + SPI_MEM_OP_MAX_FREQ(freq)) + +#define WINBOND_CONT_READ_FROM_CACHE_1S_1S_4S_OP(ndummy, buf, len, freq) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \ + SPI_MEM_OP_ADDR(1, 0, 1), \ + SPI_MEM_OP_DUMMY(ndummy - 1, 1), \ + SPI_MEM_OP_DATA_IN(len, buf, 4), \ + SPI_MEM_OP_MAX_FREQ(freq)) + +#define WINBOND_CONT_READ_FROM_CACHE_1S_1D_4D_OP(ndummy, buf, len, freq) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x6d, 1), \ + SPI_MEM_DTR_OP_ADDR(1, 0, 1), \ + SPI_MEM_DTR_OP_DUMMY(ndummy - 1, 1), \ + SPI_MEM_DTR_OP_DATA_IN(len, buf, 4), \ + SPI_MEM_OP_MAX_FREQ(freq)) + +#define WINBOND_CONT_READ_FROM_CACHE_1S_4S_4S_OP(ndummy, buf, len, freq) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \ + SPI_MEM_OP_ADDR(1, 0, 4), \ + SPI_MEM_OP_DUMMY(ndummy - 1, 4), \ + SPI_MEM_OP_DATA_IN(len, buf, 4), \ + SPI_MEM_OP_MAX_FREQ(freq)) + +#define WINBOND_CONT_READ_FROM_CACHE_1S_4D_4D_OP(ndummy, buf, len, freq) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0xed, 1), \ + SPI_MEM_DTR_OP_ADDR(1, 0, 4), \ + SPI_MEM_DTR_OP_DUMMY(ndummy - 1, 4), \ + SPI_MEM_DTR_OP_DATA_IN(len, buf, 4), \ + SPI_MEM_OP_MAX_FREQ(freq)) + #define WINBOND_CONT_READ_FROM_CACHE_1S_1S_8S_OP(ndummy, buf, len, freq) \ SPI_MEM_OP(SPI_MEM_OP_CMD(0x8b, 1), \ SPI_MEM_OP_ADDR(1, 0, 1), \ @@ -133,6 +189,20 @@ static SPINAND_OP_VARIANTS(read_cache_dual_quad_dtr_va= riants, SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 54 * HZ_PER_MHZ)= ); =20 +static SPINAND_OP_VARIANTS(cont_read_cache_dual_quad_dtr_variants, + WINBOND_CONT_READ_FROM_CACHE_1S_4D_4D_OP(11, NULL, 0, 80 * HZ_PER_MHZ), + WINBOND_CONT_READ_FROM_CACHE_1S_1D_4D_OP(5, NULL, 0, 80 * HZ_PER_MHZ), + WINBOND_CONT_READ_FROM_CACHE_1S_4S_4S_OP(8, NULL, 0, 0), + WINBOND_CONT_READ_FROM_CACHE_1S_4S_4S_OP(6, NULL, 0, 104 * HZ_PER_MHZ), + WINBOND_CONT_READ_FROM_CACHE_1S_1S_4S_OP(4, NULL, 0, 0), + WINBOND_CONT_READ_FROM_CACHE_1S_2D_2D_OP(6, NULL, 0, 80 * HZ_PER_MHZ), + /* The 1S_1D_2D variant would require 4.5 dummy bytes, this is not possi= ble */ + WINBOND_CONT_READ_FROM_CACHE_1S_2S_2S_OP(5, NULL, 0, 0), + WINBOND_CONT_READ_FROM_CACHE_1S_2S_2S_OP(4, NULL, 0, 104 * HZ_PER_MHZ), + WINBOND_CONT_READ_FROM_CACHE_1S_1S_2S_OP(4, NULL, 0, 0), + /* The 1S_1D_1D variant would require 4.5 dummy bytes, this is not possi= ble */ + WINBOND_CONT_READ_FROM_CACHE_FAST_1S_1S_1S_OP(4, NULL, 0, 0)); + static SPINAND_OP_VARIANTS(read_cache_variants, SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0), SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), @@ -442,6 +512,13 @@ static int w25n0xjw_hs_cfg(struct spinand_device *spin= and, return 0; } =20 +static int w25n0xjw_set_cont_read(struct spinand_device *spinand, bool ena= ble) +{ + u8 mask =3D enable ? 0 : WINBOND_CFG_BUF_READ; + + return spinand_upd_cfg(spinand, WINBOND_CFG_BUF_READ | WINBOND_CFG_HFREQ,= mask); +} + static int w35n0xjw_write_vcr(struct spinand_device *spinand, u8 reg, u8 v= al) { struct spi_mem_op op =3D SPINAND_OP(spinand, winbond_write_vcr, @@ -572,12 +649,14 @@ static const struct spinand_info winbond_spinand_tabl= e[] =3D { SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbc, 0x21), NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(1, 512), - SPINAND_INFO_OP_VARIANTS(&read_cache_dual_quad_dtr_variants, - &write_cache_variants, - &update_cache_variants), + SPINAND_INFO_OP_VARIANTS_WITH_CONT(&read_cache_dual_quad_dtr_varian= ts, + &write_cache_variants, + &update_cache_variants, + &cont_read_cache_dual_quad_dtr_variants), 0, - SPINAND_ECCINFO(&w25n01jw_ooblayout, NULL), - SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg)), + SPINAND_ECCINFO(&w25n01jw_ooblayout, w25w35nxxjw_ecc_get_status), + SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg), + SPINAND_CONT_READ(w25n0xjw_set_cont_read)), SPINAND_INFO("W25N01KV", /* 3.3V */ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae, 0x21), NAND_MEMORG(1, 2048, 96, 64, 1024, 20, 1, 1, 1), @@ -642,12 +721,14 @@ static const struct spinand_info winbond_spinand_tabl= e[] =3D { SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbf, 0x22), NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 2, 1), NAND_ECCREQ(1, 512), - SPINAND_INFO_OP_VARIANTS(&read_cache_dual_quad_dtr_variants, - &write_cache_variants, - &update_cache_variants), + SPINAND_INFO_OP_VARIANTS_WITH_CONT(&read_cache_dual_quad_dtr_varian= ts, + &write_cache_variants, + &update_cache_variants, + &cont_read_cache_dual_quad_dtr_variants), 0, - SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), - SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg)), + SPINAND_ECCINFO(&w25m02gv_ooblayout, w25w35nxxjw_ecc_get_status), + SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg), + SPINAND_CONT_READ(w25n0xjw_set_cont_read)), SPINAND_INFO("W25N02KV", /* 3.3V */ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22), NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), --=20 2.51.1