From nobody Sat Jun 13 04:53:58 2026 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 D57D838CFF6 for ; Wed, 29 Apr 2026 17:57:40 +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=1777485462; cv=none; b=Cexbbsg2d000e4UEWik+HmvuDpWP3rUvqF0m0A83SRspuk05UQQUUCoRrVTTRX9lrRXPda4BBBKxjx3f/X59mthvoQ9FvyzQOvZtK/2d5oLwdwP5lQ2qVKb0XunJZYubLKGJNdkw4EdVUPIr0vR3THzAX8WtfDovJlIT0F7Sm0Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777485462; c=relaxed/simple; bh=7Ve2dBr/dr2iIa3vzIEhgWL6CcjWV7+2Dr2g1rQ6HR8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=jXMdqhjmPMpEgigEOciWkJ9+AEhEHW3+LO0IDQhKeHVIzwhk8KH6k/2nQBUAMFdp71ollh3oXX/BiEgxUvpsRlpOAKYExpZHmpyH924YwDVuFObZWEXnDXfdEhMAOZo6ynxgErMDvqDx8RPpk144/ArtGApFV6pIfO1e6ePCCqY= 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=A0uy++Hp; 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="A0uy++Hp" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id 78629C5CD5E; Wed, 29 Apr 2026 17:58:23 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 43A3C5FD43; Wed, 29 Apr 2026 17:57:39 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 773411072B168; Wed, 29 Apr 2026 19:57:33 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1777485457; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=yWmmYQ59pDWo8CPH+WDZNUJOtVHq1mv94yrIZNpMFTQ=; b=A0uy++HpVsqXp/AWhYrAI2hp+p7ETugdFS9ytd4dkSCZwTjv36+cFoiIWz21fMnMSR76Pc e9+HB7ILr3sOak88h+392wCRwwauqRweo0aEedItbcLJw5mneGcjRYsFKXfoStHcHckx0G YdRGnC9kioVwBBtwXgo9e23sCWa5jBacVqwNtOjjGywvq/J3Kk2xPGQJ6jU9zWelyclGMn a7dCpyogvUIXu6KO4oUR91xBUJDErBJKBAX4/2ba3x4QQEmjuGjYXboWm+Z0S1WSQ1mS/G EU+q6ezfH6vSeti6bArRAEV8f3ILa5MPp+YtCN06qckkQkyMqihgfsw411IjUQ== From: Miquel Raynal Date: Wed, 29 Apr 2026 19:56:38 +0200 Subject: [PATCH v3 01/11] 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: <20260429-winbond-v6-18-rc1-cont-read-v3-1-0f38b3c229ad@bootlin.com> References: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> In-Reply-To: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> To: Mark Brown , Richard Weinberger , Vignesh Raghavendra , Michael Walle , Miquel Raynal , Takahiro Kuwano , Lorenzo Bianconi , Ray Liu , Chin-Ting Kuo , =?utf-8?q?C=C3=A9dric_Le_Goater?= , Joel Stanley , Andrew Jeffery , Avi Fishman , Tomer Maimon , Tali Perry , Patrick Venture , Nancy Yuen , Benjamin Fair , Maxime Coquelin , Alexandre Torgue , =?utf-8?q?Jonathan_Neusch=C3=A4fer?= Cc: Pratyush Yadav , Thomas Petazzoni , Steam Lin , Santhosh Kumar K , linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-aspeed@lists.ozlabs.org, openbmc@lists.ozlabs.org, linux-stm32@st-md-mailman.stormreply.com 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 66c90419f6d5..fba3cc213c88 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -878,6 +878,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); @@ -968,19 +974,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.53.0 From nobody Sat Jun 13 04:53:58 2026 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 4067438CFE9 for ; Wed, 29 Apr 2026 17:57:45 +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=1777485466; cv=none; b=jkCl70s+ku0ziL51GNDzJjVusvNK8zRwB5RnyLPbjXZ0w3LPmTRX5WjScMEBL1mW9PL5KU6EKvW7VEGwKdxa0sresqHJgbNzrD5ZybaiCQi/h2HLCTYRYaGTuW8cqt1+wiTt9xDl3pDKq7Wzk7XRF3Yz3DbPz3ZtwRV4KPdrBPI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777485466; c=relaxed/simple; bh=ckoJb0d1ziC0/OuZ8F+o7Rmk0By4kSHF2fy5sQ8Tyj0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=pOzC3k3TaGENMJJrFKRP2eqnEamAxrVI2Q7jw+hC7AemSzv/oqLbdWHK5eLIdhxp9Z54Evx0FowuouRtl73oPHrCktZi4lRLJmy/omTJOwnlLbbXoY4cAKK7zALmzcbLgCNtYkviZlV1pxtqLBE0W/AC/5pC3SvugPGMuqDd1UA= 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=NXWUJIFz; 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="NXWUJIFz" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-02.galae.net (Postfix) with ESMTPS id CF4001A33F4; Wed, 29 Apr 2026 17:57:43 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id A25475FD43; Wed, 29 Apr 2026 17:57:43 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 811921072B16D; Wed, 29 Apr 2026 19:57:37 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1777485461; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=pRtlUGFfk1AjNaQYKbHs4RmZNZ5DHT9f7bq1vbOMB34=; b=NXWUJIFzygDfQ7zjIeyD37p2jDhewvoKDSntinFms7jvk9dOXJLWtQHw+UkFYO0NhJeIjM STfpzdg2sYIjGY6C7+Fzr4WXsn+KBSuIu5UyfYzZlD/U1c7XLIx37jF1O1AhcTxI21N33E DQmxcpFD41RJYWNdmP5qpl3rNVUo2uPxARHR+n5Z8u599+GT+0ka1catIfl/VshOMoAu0W fsSlRi+NTvVI+VHtDf4qZIFZMj6xPiJCYPTqUPkB2Nns0fWL31gmeq1mdv9+6WcM7lGBeO JbHctYaj9m9K68JL+5ZH58LGrBE1dl+Luq9ZVrU4Z8dxJGq188aCiwAdf5nSSA== From: Miquel Raynal Date: Wed, 29 Apr 2026 19:56:39 +0200 Subject: [PATCH v3 02/11] 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: <20260429-winbond-v6-18-rc1-cont-read-v3-2-0f38b3c229ad@bootlin.com> References: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> In-Reply-To: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> To: Mark Brown , Richard Weinberger , Vignesh Raghavendra , Michael Walle , Miquel Raynal , Takahiro Kuwano , Lorenzo Bianconi , Ray Liu , Chin-Ting Kuo , =?utf-8?q?C=C3=A9dric_Le_Goater?= , Joel Stanley , Andrew Jeffery , Avi Fishman , Tomer Maimon , Tali Perry , Patrick Venture , Nancy Yuen , Benjamin Fair , Maxime Coquelin , Alexandre Torgue , =?utf-8?q?Jonathan_Neusch=C3=A4fer?= Cc: Pratyush Yadav , Thomas Petazzoni , Steam Lin , Santhosh Kumar K , linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-aspeed@lists.ozlabs.org, openbmc@lists.ozlabs.org, linux-stm32@st-md-mailman.stormreply.com 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 fba3cc213c88..1c3ac9ad650e 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -1400,7 +1400,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 58abd306ebe3..e1f19664bb25 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -862,6 +862,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.53.0 From nobody Sat Jun 13 04:53:58 2026 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 24D1141B356 for ; Wed, 29 Apr 2026 17:57:49 +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=1777485470; cv=none; b=Nd9yfNOg+fbe+X2obZwAWrRT7fDkX7YQIjZNcoloofymEvGaqp6epd4iULPthcI1ioK0A4yYKEL6mBWrB1riBnPp+EuDckAFApzoecSE+RSBuqR0llwCM4av9OL3rPMhjOqfslr7yXyUT8qDlhMsoEAnJ6JMQ9SG0yDaw62Irmw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777485470; c=relaxed/simple; bh=IlghUJ8CQ3gN7V/4c+I/BhZ/fG/rm5O/I49orTe7xSY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Lj2O1PinsH5I20lw0CsBPilUKDJgXil7RxDbYq6Xw2ID6NeDbcdwW6Yf0bay5+vOzyhCTncM/2q9YtNLTqu1eLFnEoHkwhYB3A4Z4btLx0IMireGqdN0TwCIdcg0mSM14OfjFcJto1jIXgdmt1Xdy3xccVG9ug5QXsdKshi/caE= 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=uDsKwvQO; 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="uDsKwvQO" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-02.galae.net (Postfix) with ESMTPS id E7DFE1A3409; Wed, 29 Apr 2026 17:57:47 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id BABB15FD43; Wed, 29 Apr 2026 17:57:47 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id C966E1072B171; Wed, 29 Apr 2026 19:57:41 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1777485465; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=QdHHmy5KibUj7IOUfvRAtvrskjTvNN+KNx7nY11cePM=; b=uDsKwvQOEhv6WrNXDMP9ss0SW/69JMJHgvqRB8tshJUyUYKiLRCiM6vONo8b0Y8rcmqBd2 BEABK7qva7LRm2ch44uFcuvG8mx9hdH2X0tMsCNHyRze3nTQMetp+I0I/QJ1rfejdggIGn X7Xzyl0AgBsSQxWeM+jW9LzsFGHgo6auF20jWVlet49Oi87WBUUHrFYCqb5wVjUTTO6+yA +bQzEtHGMLjcg6DzVm6/oVnNpjZlHFj0tm5qYGe1o5kqgg46w9Ku3um13/qpvofCq3I6Fj 5YbuqF48vQSXbuDiBZE7f2ssG/IeOKERTDFuPuNGrlmT8oGKR7YlaxyAhJQT3Q== From: Miquel Raynal Date: Wed, 29 Apr 2026 19:56:40 +0200 Subject: [PATCH v3 03/11] 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: <20260429-winbond-v6-18-rc1-cont-read-v3-3-0f38b3c229ad@bootlin.com> References: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> In-Reply-To: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> To: Mark Brown , Richard Weinberger , Vignesh Raghavendra , Michael Walle , Miquel Raynal , Takahiro Kuwano , Lorenzo Bianconi , Ray Liu , Chin-Ting Kuo , =?utf-8?q?C=C3=A9dric_Le_Goater?= , Joel Stanley , Andrew Jeffery , Avi Fishman , Tomer Maimon , Tali Perry , Patrick Venture , Nancy Yuen , Benjamin Fair , Maxime Coquelin , Alexandre Torgue , =?utf-8?q?Jonathan_Neusch=C3=A4fer?= Cc: Pratyush Yadav , Thomas Petazzoni , Steam Lin , Santhosh Kumar K , linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-aspeed@lists.ozlabs.org, openbmc@lists.ozlabs.org, linux-stm32@st-md-mailman.stormreply.com 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 1c3ac9ad650e..663f5d6a6bd7 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -487,10 +487,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)); @@ -579,10 +582,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)); @@ -1231,12 +1237,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)) @@ -1244,38 +1255,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 e1f19664bb25..896e9b5de0c4 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -684,8 +684,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.53.0 From nobody Sat Jun 13 04:53:58 2026 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 5E2F241B349; Wed, 29 Apr 2026 17:57:53 +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=1777485475; cv=none; b=m0HmT8QO75QnEMOZSLqDZqKPtJIuxgXqdIjx2efGm07qwVO/wEv49PiuIe5CSTYUA9Zd4gH6uWiGaz+vRkM6u9gFoijE13LNLO/6rgPnT3InpJVufwPyfPzY4yftPb33XWpQ0xFk3tEqc3IW0DYB5Ea3oVaONK/ys0bQJNh0WkE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777485475; c=relaxed/simple; bh=BOWkmd0zvsP4UHnJCCxkVdfwlM3xM1hOl21UD6l/NMI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Z8Jl2cUIllaOG8NBWHHR8ZdWlbGYX6ynMFKWKIUmuco+SOYPq0R0/DllYR/gMrnfyQbr/VIojjbsYbUDDGvX5pOdKYau4Afy4t7VVoD3a+xS8QXPNbw/XQqrzPintT+gHqLLBV5dlowjK4gRHlUs2H8A+cKLKn9GU0GFPMRE11M= 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=zNm+Ffi/; 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="zNm+Ffi/" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-02.galae.net (Postfix) with ESMTPS id 1DE281A3445; Wed, 29 Apr 2026 17:57:52 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id E6A625FD43; Wed, 29 Apr 2026 17:57:51 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 17C121072B158; Wed, 29 Apr 2026 19:57:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1777485469; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=yFQWpGXRfJAmrHLeBgm6kc2xglR3Fv5EghBUWQsY1Nk=; b=zNm+Ffi/6ezZMy6DwTh151pKgiOVgPBisspcIGedvwWOvv7SemEzu8DBkPpUArxO8wmQoy ZqQbAdOmWkEicjB0O1pVZPCJQXWlMQ8/xJvhZ+7n19dEqoazFbxftEv4yRMx5aNzKEnMPX KylWMWcXOPO18qPUgkMbG9Z5FOckORYvQSAZgaXr0O80NSWv786732KYJZcEDVIjlAgWVD Tb9SOVKOb7XC5m/pXCSKWz/+m4FlhTrIctcz/xTam0fS9fpRZ2A6BJNhZVnJC1SpNmNo1v 8q9/YkjqOuh68v+E6lLH1hb2/aA2czHcWoLZTevUILsrN/I/gV9v76M/7Fbu2w== From: Miquel Raynal Date: Wed, 29 Apr 2026 19:56:41 +0200 Subject: [PATCH v3 04/11] 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: <20260429-winbond-v6-18-rc1-cont-read-v3-4-0f38b3c229ad@bootlin.com> References: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> In-Reply-To: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> To: Mark Brown , Richard Weinberger , Vignesh Raghavendra , Michael Walle , Miquel Raynal , Takahiro Kuwano , Lorenzo Bianconi , Ray Liu , Chin-Ting Kuo , =?utf-8?q?C=C3=A9dric_Le_Goater?= , Joel Stanley , Andrew Jeffery , Avi Fishman , Tomer Maimon , Tali Perry , Patrick Venture , Nancy Yuen , Benjamin Fair , Maxime Coquelin , Alexandre Torgue , =?utf-8?q?Jonathan_Neusch=C3=A4fer?= Cc: Pratyush Yadav , Thomas Petazzoni , Steam Lin , Santhosh Kumar K , linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-aspeed@lists.ozlabs.org, openbmc@lists.ozlabs.org, linux-stm32@st-md-mailman.stormreply.com 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. Acked-by: Mark Brown Signed-off-by: Miquel Raynal --- drivers/mtd/nand/spi/core.c | 15 ++++++++------- drivers/mtd/spi-nor/core.c | 22 ++++++++++++---------- drivers/spi/spi-airoha-snfi.c | 6 +++--- drivers/spi/spi-aspeed-smc.c | 4 ++-- drivers/spi/spi-intel.c | 6 +++--- drivers/spi/spi-mem.c | 15 ++++++++------- drivers/spi/spi-mxic.c | 18 +++++++++--------- drivers/spi/spi-npcm-fiu.c | 16 ++++++++-------- drivers/spi/spi-rpc-if.c | 8 ++++---- drivers/spi/spi-stm32-ospi.c | 6 +++--- drivers/spi/spi-stm32-qspi.c | 6 +++--- drivers/spi/spi-wpcm-fiu.c | 2 +- include/linux/spi/spi-mem.h | 3 ++- 13 files changed, 66 insertions(+), 61 deletions(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 663f5d6a6bd7..a66510747b31 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -491,9 +491,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)); @@ -586,9 +586,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)); @@ -1247,7 +1247,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)) @@ -1256,8 +1257,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 5dd0b3cb5250..a7bc458edc5c 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -3641,14 +3641,15 @@ 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)), + .op_tmpl =3D &info.primary_op_tmpl, + .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 @@ -3672,14 +3673,15 @@ 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)), + .op_tmpl =3D &info.primary_op_tmpl, + .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-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c index 7b6c09f91fef..95bfde7c8e7f 100644 --- a/drivers/spi/spi-airoha-snfi.c +++ b/drivers/spi/spi-airoha-snfi.c @@ -546,7 +546,7 @@ static int airoha_snand_dirmap_create(struct spi_mem_di= rmap_desc *desc) if (desc->info.length > SPI_NAND_CACHE_SIZE) return -E2BIG; =20 - if (!airoha_snand_supports_op(desc->mem, &desc->info.op_tmpl)) + if (!airoha_snand_supports_op(desc->mem, desc->info.op_tmpl)) return -EOPNOTSUPP; =20 return 0; @@ -572,7 +572,7 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_= dirmap_desc *desc, * DUALIO and QUADIO opcodes are not supported by the spi controller, * replace them with supported opcodes. */ - opcode =3D desc->info.op_tmpl.cmd.opcode; + opcode =3D desc->info.op_tmpl->cmd.opcode; switch (opcode) { case SPI_NAND_OP_READ_FROM_CACHE_SINGLE: case SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST: @@ -761,7 +761,7 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem= _dirmap_desc *desc, /* minimum oob size is 64 */ bytes =3D round_up(offs + len, 64); =20 - opcode =3D desc->info.op_tmpl.cmd.opcode; + opcode =3D desc->info.op_tmpl->cmd.opcode; switch (opcode) { case SPI_NAND_OP_PROGRAM_LOAD_SINGLE: case SPI_NAND_OP_PROGRAM_LOAD_RAMDOM_SINGLE: diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c index c21323e07d3c..c20a33734f5c 100644 --- a/drivers/spi/spi-aspeed-smc.c +++ b/drivers/spi/spi-aspeed-smc.c @@ -697,7 +697,7 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirm= ap_desc *desc) { struct aspeed_spi *aspi =3D spi_controller_get_devdata(desc->mem->spi->co= ntroller); struct aspeed_spi_chip *chip =3D &aspi->chips[spi_get_chipselect(desc->me= m->spi, 0)]; - struct spi_mem_op *op =3D &desc->info.op_tmpl; + struct spi_mem_op *op =3D desc->info.op_tmpl; u32 ctl_val; int ret =3D 0; =20 @@ -769,7 +769,7 @@ static ssize_t aspeed_spi_dirmap_read(struct spi_mem_di= rmap_desc *desc, if (chip->ahb_window_size < offset + len || chip->force_user_mode) { int ret; =20 - ret =3D aspeed_spi_read_user(chip, &desc->info.op_tmpl, offset, len, buf= ); + ret =3D aspeed_spi_read_user(chip, desc->info.op_tmpl, offset, len, buf); if (ret < 0) return ret; } else { diff --git a/drivers/spi/spi-intel.c b/drivers/spi/spi-intel.c index 1775ad39e633..7494b921a743 100644 --- a/drivers/spi/spi-intel.c +++ b/drivers/spi/spi-intel.c @@ -814,7 +814,7 @@ static int intel_spi_dirmap_create(struct spi_mem_dirma= p_desc *desc) struct intel_spi *ispi =3D spi_controller_get_devdata(desc->mem->spi->con= troller); const struct intel_spi_mem_op *iop; =20 - iop =3D intel_spi_match_mem_op(ispi, &desc->info.op_tmpl); + iop =3D intel_spi_match_mem_op(ispi, desc->info.op_tmpl); if (!iop) return -EOPNOTSUPP; =20 @@ -827,7 +827,7 @@ static ssize_t intel_spi_dirmap_read(struct spi_mem_dir= map_desc *desc, u64 offs, { struct intel_spi *ispi =3D spi_controller_get_devdata(desc->mem->spi->con= troller); const struct intel_spi_mem_op *iop =3D desc->priv; - struct spi_mem_op op =3D desc->info.op_tmpl; + struct spi_mem_op op =3D *desc->info.op_tmpl; int ret; =20 /* Fill in the gaps */ @@ -844,7 +844,7 @@ static ssize_t intel_spi_dirmap_write(struct spi_mem_di= rmap_desc *desc, u64 offs { struct intel_spi *ispi =3D spi_controller_get_devdata(desc->mem->spi->con= troller); const struct intel_spi_mem_op *iop =3D desc->priv; - 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 offs; diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index a09371a075d2..e2eaa1ba4ff6 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -647,7 +647,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; @@ -667,7 +667,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; @@ -706,11 +706,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_obj(*desc); @@ -719,6 +719,7 @@ 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 spi_mem_access_start(mem); if (ret) { @@ -733,7 +734,7 @@ spi_mem_dirmap_create(struct spi_mem *mem, =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; @@ -857,7 +858,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) @@ -903,7 +904,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/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c index b0e7fc828a50..83b688e65284 100644 --- a/drivers/spi/spi-mxic.c +++ b/drivers/spi/spi-mxic.c @@ -403,20 +403,20 @@ static ssize_t mxic_spi_mem_dirmap_read(struct spi_me= m_dirmap_desc *desc, if (WARN_ON(offs + desc->info.offset + len > U32_MAX)) return -EINVAL; =20 - writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0, desc->info.op_tmpl.data.sw= ap16), + writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0, desc->info.op_tmpl->data.s= wap16), mxic->regs + HC_CFG); =20 - writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len), + writel(mxic_spi_mem_prep_op_cfg(desc->info.op_tmpl, len), mxic->regs + LRD_CFG); writel(desc->info.offset + offs, mxic->regs + LRD_ADDR); len =3D min_t(size_t, len, mxic->linear.size); writel(len, mxic->regs + LRD_RANGE); - writel(LMODE_CMD0(desc->info.op_tmpl.cmd.opcode) | + writel(LMODE_CMD0(desc->info.op_tmpl->cmd.opcode) | LMODE_SLV_ACT(spi_get_chipselect(desc->mem->spi, 0)) | LMODE_EN, mxic->regs + LRD_CTRL); =20 - if (mxic->ecc.use_pipelined_conf && desc->info.op_tmpl.data.ecc) { + if (mxic->ecc.use_pipelined_conf && desc->info.op_tmpl->data.ecc) { ret =3D mxic_ecc_process_data_pipelined(mxic->ecc.pipelined_engine, NAND_PAGE_READ, mxic->linear.dma + offs); @@ -448,20 +448,20 @@ static ssize_t mxic_spi_mem_dirmap_write(struct spi_m= em_dirmap_desc *desc, if (WARN_ON(offs + desc->info.offset + len > U32_MAX)) return -EINVAL; =20 - writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0, desc->info.op_tmpl.data.sw= ap16), + writel(mxic_spi_prep_hc_cfg(desc->mem->spi, 0, desc->info.op_tmpl->data.s= wap16), mxic->regs + HC_CFG); =20 - writel(mxic_spi_mem_prep_op_cfg(&desc->info.op_tmpl, len), + writel(mxic_spi_mem_prep_op_cfg(desc->info.op_tmpl, len), mxic->regs + LWR_CFG); writel(desc->info.offset + offs, mxic->regs + LWR_ADDR); len =3D min_t(size_t, len, mxic->linear.size); writel(len, mxic->regs + LWR_RANGE); - writel(LMODE_CMD0(desc->info.op_tmpl.cmd.opcode) | + writel(LMODE_CMD0(desc->info.op_tmpl->cmd.opcode) | LMODE_SLV_ACT(spi_get_chipselect(desc->mem->spi, 0)) | LMODE_EN, mxic->regs + LWR_CTRL); =20 - if (mxic->ecc.use_pipelined_conf && desc->info.op_tmpl.data.ecc) { + if (mxic->ecc.use_pipelined_conf && desc->info.op_tmpl->data.ecc) { ret =3D mxic_ecc_process_data_pipelined(mxic->ecc.pipelined_engine, NAND_PAGE_WRITE, mxic->linear.dma + offs); @@ -509,7 +509,7 @@ static int mxic_spi_mem_dirmap_create(struct spi_mem_di= rmap_desc *desc) if (desc->info.offset + desc->info.length > U32_MAX) return -EINVAL; =20 - if (!mxic_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl)) + if (!mxic_spi_mem_supports_op(desc->mem, desc->info.op_tmpl)) return -EOPNOTSUPP; =20 return 0; diff --git a/drivers/spi/spi-npcm-fiu.c b/drivers/spi/spi-npcm-fiu.c index 6617751009c3..4b825044038b 100644 --- a/drivers/spi/spi-npcm-fiu.c +++ b/drivers/spi/spi-npcm-fiu.c @@ -299,11 +299,11 @@ static ssize_t npcm_fiu_direct_read(struct spi_mem_di= rmap_desc *desc, for (i =3D 0 ; i < len ; i++) *(buf_rx + i) =3D ioread8(src + i); } else { - if (desc->info.op_tmpl.addr.buswidth !=3D fiu->drd_op.addr.buswidth || - desc->info.op_tmpl.dummy.nbytes !=3D fiu->drd_op.dummy.nbytes || - desc->info.op_tmpl.cmd.opcode !=3D fiu->drd_op.cmd.opcode || - desc->info.op_tmpl.addr.nbytes !=3D fiu->drd_op.addr.nbytes) - npcm_fiu_set_drd(fiu, &desc->info.op_tmpl); + if (desc->info.op_tmpl->addr.buswidth !=3D fiu->drd_op.addr.buswidth || + desc->info.op_tmpl->dummy.nbytes !=3D fiu->drd_op.dummy.nbytes || + desc->info.op_tmpl->cmd.opcode !=3D fiu->drd_op.cmd.opcode || + desc->info.op_tmpl->addr.nbytes !=3D fiu->drd_op.addr.nbytes) + npcm_fiu_set_drd(fiu, desc->info.op_tmpl); =20 memcpy_fromio(buf_rx, src, len); } @@ -609,7 +609,7 @@ static int npcm_fiu_dirmap_create(struct spi_mem_dirmap= _desc *desc) } =20 if (!fiu->spix_mode && - desc->info.op_tmpl.data.dir =3D=3D SPI_MEM_DATA_OUT) { + desc->info.op_tmpl->data.dir =3D=3D SPI_MEM_DATA_OUT) { desc->nodirmap =3D true; return 0; } @@ -644,9 +644,9 @@ static int npcm_fiu_dirmap_create(struct spi_mem_dirmap= _desc *desc) NPCM_FIU_CFG_FIU_FIX); } =20 - if (desc->info.op_tmpl.data.dir =3D=3D SPI_MEM_DATA_IN) { + if (desc->info.op_tmpl->data.dir =3D=3D SPI_MEM_DATA_IN) { if (!fiu->spix_mode) - npcm_fiu_set_drd(fiu, &desc->info.op_tmpl); + npcm_fiu_set_drd(fiu, desc->info.op_tmpl); else npcm_fiux_set_direct_rd(fiu); =20 diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c index 6edc0c4db854..1ef7bd91b3b3 100644 --- a/drivers/spi/spi-rpc-if.c +++ b/drivers/spi/spi-rpc-if.c @@ -83,7 +83,7 @@ static ssize_t xspi_spi_mem_dirmap_write(struct spi_mem_d= irmap_desc *desc, if (offs + desc->info.offset + len > U32_MAX) return -EINVAL; =20 - rpcif_spi_mem_prepare(desc->mem->spi, &desc->info.op_tmpl, &offs, &len); + rpcif_spi_mem_prepare(desc->mem->spi, desc->info.op_tmpl, &offs, &len); =20 return xspi_dirmap_write(rpc->dev, offs, len, buf); } @@ -97,7 +97,7 @@ static ssize_t rpcif_spi_mem_dirmap_read(struct spi_mem_d= irmap_desc *desc, if (offs + desc->info.offset + len > U32_MAX) return -EINVAL; =20 - rpcif_spi_mem_prepare(desc->mem->spi, &desc->info.op_tmpl, &offs, &len); + rpcif_spi_mem_prepare(desc->mem->spi, desc->info.op_tmpl, &offs, &len); =20 return rpcif_dirmap_read(rpc->dev, offs, len, buf); } @@ -110,13 +110,13 @@ static int rpcif_spi_mem_dirmap_create(struct spi_mem= _dirmap_desc *desc) if (desc->info.offset + desc->info.length > U32_MAX) return -EINVAL; =20 - if (!rpcif_spi_mem_supports_op(desc->mem, &desc->info.op_tmpl)) + if (!rpcif_spi_mem_supports_op(desc->mem, desc->info.op_tmpl)) return -EOPNOTSUPP; =20 if (!rpc->dirmap) return -EOPNOTSUPP; =20 - if (!rpc->xspi && desc->info.op_tmpl.data.dir !=3D SPI_MEM_DATA_IN) + if (!rpc->xspi && desc->info.op_tmpl->data.dir !=3D SPI_MEM_DATA_IN) return -EOPNOTSUPP; =20 return 0; diff --git a/drivers/spi/spi-stm32-ospi.c b/drivers/spi/spi-stm32-ospi.c index 4461c6e24b9e..5f5b3cd5d725 100644 --- a/drivers/spi/spi-stm32-ospi.c +++ b/drivers/spi/spi-stm32-ospi.c @@ -602,11 +602,11 @@ static int stm32_ospi_dirmap_create(struct spi_mem_di= rmap_desc *desc) { struct stm32_ospi *ospi =3D spi_controller_get_devdata(desc->mem->spi->co= ntroller); =20 - if (desc->info.op_tmpl.data.dir =3D=3D SPI_MEM_DATA_OUT) + if (desc->info.op_tmpl->data.dir =3D=3D SPI_MEM_DATA_OUT) return -EOPNOTSUPP; =20 /* Should never happen, as mm_base =3D=3D null is an error probe exit con= dition */ - if (!ospi->mm_base && desc->info.op_tmpl.data.dir =3D=3D SPI_MEM_DATA_IN) + if (!ospi->mm_base && desc->info.op_tmpl->data.dir =3D=3D SPI_MEM_DATA_IN) return -EOPNOTSUPP; =20 if (!ospi->mm_size) @@ -633,7 +633,7 @@ static ssize_t stm32_ospi_dirmap_read(struct spi_mem_di= rmap_desc *desc, * spi_mem_op template with offs, len and *buf in order to get * all needed transfer information into struct spi_mem_op */ - memcpy(&op, &desc->info.op_tmpl, sizeof(struct spi_mem_op)); + memcpy(&op, desc->info.op_tmpl, sizeof(struct spi_mem_op)); dev_dbg(ospi->dev, "%s len =3D 0x%zx offs =3D 0x%llx buf =3D 0x%p\n", __f= unc__, len, offs, buf); =20 op.data.nbytes =3D len; diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index df1bbacec90a..e2a6a6eaf9b2 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -506,11 +506,11 @@ static int stm32_qspi_dirmap_create(struct spi_mem_di= rmap_desc *desc) { struct stm32_qspi *qspi =3D spi_controller_get_devdata(desc->mem->spi->co= ntroller); =20 - if (desc->info.op_tmpl.data.dir =3D=3D SPI_MEM_DATA_OUT) + if (desc->info.op_tmpl->data.dir =3D=3D SPI_MEM_DATA_OUT) return -EOPNOTSUPP; =20 /* should never happen, as mm_base =3D=3D null is an error probe exit con= dition */ - if (!qspi->mm_base && desc->info.op_tmpl.data.dir =3D=3D SPI_MEM_DATA_IN) + if (!qspi->mm_base && desc->info.op_tmpl->data.dir =3D=3D SPI_MEM_DATA_IN) return -EOPNOTSUPP; =20 if (!qspi->mm_size) @@ -536,7 +536,7 @@ static ssize_t stm32_qspi_dirmap_read(struct spi_mem_di= rmap_desc *desc, * spi_mem_op template with offs, len and *buf in order to get * all needed transfer information into struct spi_mem_op */ - memcpy(&op, &desc->info.op_tmpl, sizeof(struct spi_mem_op)); + memcpy(&op, desc->info.op_tmpl, sizeof(struct spi_mem_op)); dev_dbg(qspi->dev, "%s len =3D 0x%zx offs =3D 0x%llx buf =3D 0x%p\n", __f= unc__, len, offs, buf); =20 op.data.nbytes =3D len; diff --git a/drivers/spi/spi-wpcm-fiu.c b/drivers/spi/spi-wpcm-fiu.c index 0e26ff178505..cd78e927953d 100644 --- a/drivers/spi/spi-wpcm-fiu.c +++ b/drivers/spi/spi-wpcm-fiu.c @@ -377,7 +377,7 @@ static int wpcm_fiu_dirmap_create(struct spi_mem_dirmap= _desc *desc) struct wpcm_fiu_spi *fiu =3D spi_controller_get_devdata(desc->mem->spi->c= ontroller); int cs =3D spi_get_chipselect(desc->mem->spi, 0); =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 -EOPNOTSUPP; =20 /* diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h index c8e207522223..9a96ddace3eb 100644 --- a/include/linux/spi/spi-mem.h +++ b/include/linux/spi/spi-mem.h @@ -237,7 +237,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.53.0 From nobody Sat Jun 13 04:53:58 2026 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 64EA141B352; Wed, 29 Apr 2026 17:57:57 +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=1777485478; cv=none; b=WDzpnBOZ+7kiIxcph09DEqgrx4mYSLnf2bAF9tXwTWoYyUq2H2zR0Q91zRdDtc7J1jBkYyZHtiblO5J8Y1uodYv/1wY1FqoeESRx6KH0K27ixzzBiZstm8EVtGjmxd4KBhKIqmoYRmEqq5MZ8tFEBWJSGZcwy4BeQ/avk1inwiQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777485478; c=relaxed/simple; bh=phTwVY58SZL7fjULrgc3nFQZ0M51jPXq2NYti7BkbNY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=BN/erFx9aCw4BuKC5c18IOI6UQ3In7c18UWY29T5ZpEcEqoXVXl3Qjiwk40On5GIVXtlKbABT2nXZQR84hbqG+IAc/l9Ns2QvrLd1QTzQx1J9EVH+AjCDoH5QQ7fS+qEyoIc/my2iwtY55D67fus/zPS8IM3Pd7LLGArteQvtew= 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=K0amzfyc; 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="K0amzfyc" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-02.galae.net (Postfix) with ESMTPS id 2B37A1A3453; Wed, 29 Apr 2026 17:57:56 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id F35B55FD43; Wed, 29 Apr 2026 17:57:55 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 3FF5A1072B173; Wed, 29 Apr 2026 19:57:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1777485474; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=ChgtJK72vZUlsiBaKPcyKbWrS3ajSynsgsTRx3iHXAU=; b=K0amzfycc9kXe6uiG4uUt/UiAhIdiGMzKOl7+OtAUig03P9w5Oi4pi71lfOK4VzCWadfpc nS5TLgH8UeOpLv9oqplFB7SfTVmfJbMNIhuGL5isL94d1zok7pU+S8QA5DWBkSbgh28SJz DZearlJ5Cu/VO0kJdyM9+tAQscMA0+OXCO9beDN4ZJPGNWzVEq1MJI7sPFDuRqVpC63fLQ Pic34fN8lxySr8+En0zBofRfLA+dt1XFD2tD6zmSWls95oUd8rvbzJXRh5bZmIbqP8kUKa E5JC9PYLpexMp71IOMLC7TSlwz1RJMfwhawHgZ7crGtjiqwa80VGQE5DnFcuTw== From: Miquel Raynal Date: Wed, 29 Apr 2026 19:56:42 +0200 Subject: [PATCH v3 05/11] 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: <20260429-winbond-v6-18-rc1-cont-read-v3-5-0f38b3c229ad@bootlin.com> References: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> In-Reply-To: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> To: Mark Brown , Richard Weinberger , Vignesh Raghavendra , Michael Walle , Miquel Raynal , Takahiro Kuwano , Lorenzo Bianconi , Ray Liu , Chin-Ting Kuo , =?utf-8?q?C=C3=A9dric_Le_Goater?= , Joel Stanley , Andrew Jeffery , Avi Fishman , Tomer Maimon , Tali Perry , Patrick Venture , Nancy Yuen , Benjamin Fair , Maxime Coquelin , Alexandre Torgue , =?utf-8?q?Jonathan_Neusch=C3=A4fer?= Cc: Pratyush Yadav , Thomas Petazzoni , Steam Lin , Santhosh Kumar K , linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-aspeed@lists.ozlabs.org, openbmc@lists.ozlabs.org, linux-stm32@st-md-mailman.stormreply.com 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. Acked-by: Mark Brown Signed-off-by: Miquel Raynal --- 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 e2eaa1ba4ff6..f64eda9bbd9f 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -713,6 +713,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_obj(*desc); if (!desc) return ERR_PTR(-ENOMEM); diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h index 9a96ddace3eb..2012a3b2ef91 100644 --- a/include/linux/spi/spi-mem.h +++ b/include/linux/spi/spi-mem.h @@ -227,6 +227,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 * @@ -239,6 +241,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; }; @@ -382,12 +385,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.53.0 From nobody Sat Jun 13 04:53:58 2026 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 15A4B41B352; Wed, 29 Apr 2026 17:58: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=1777485483; cv=none; b=UHUBfeaXkPym6q4b6mtc1hbXur7D6j47PwhtNDCVKAOqJCnjiQqP6Yxl34BitCmx7ZIHqkb/UEznsQlicajndMKfE0jwkvjEHR+dvQM652zn0CcVVsSjUDDTgZ090DT5nDMYRC/tKCjKCpzgqfpiaRpQje2CsF03hSECpp9CIY8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777485483; c=relaxed/simple; bh=adXdJ+I+WcixMjrUXc6N5cC5ru4yXVEX+wE2UFbNaqs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=JBT5rw1t15Na/bswOgbIyTgcLhpTQ76mNPRZUFGPY89S+yc7jxeVpZizu+xc4Vl9pvfzSQN5cCmWplrWLMUvzAJUaC7K2vPuUqkLhEi24VuQT2NH5TPDP2ewjVNDhBKlF6LMJ9+nSRacJUu5RZ+JujU3WvZDR1oqm0itEkYXXiU= 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=ufpsxmOn; 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="ufpsxmOn" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-02.galae.net (Postfix) with ESMTPS id C45C11A3452; Wed, 29 Apr 2026 17:58:00 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 8FE375FD43; Wed, 29 Apr 2026 17:58:00 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 6862E1072B175; Wed, 29 Apr 2026 19:57:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1777485478; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=5kdA1IC/RYXviplmXjfBx2K4qGRHF5L/z4JMU8G7heo=; b=ufpsxmOnbM4aWlTqONbvM/hU0uS6dcXEqlxSHSr1HWYBIfGT90YPkgaK0cuFSbVDO2ePk8 pWi3bwyR8ypZOab+t1cJA74MjXfz7fLvozJ6V7qmbhj3f34ty/OOJYwRbTAzFsAix386Ly D1FsPPSsy7tCoNaMLBxBDPlrFb/XK+/uCgMaGjsQ2R+B/RuAlAGmsUx5DuKH7qOrDHX7rD xayotK3EyInONV8I9cHKvaHPdCz3+n8OX+quL0wUzfkGZxlSYM7f+O8L+6M140LefKPS6/ +pSdGDvUfdVqb0jYh6gv0v4c1CPJTYtO1hzRdfUdURt2Ao08UPOejiDAM7KKqQ== From: Miquel Raynal Date: Wed, 29 Apr 2026 19:56:43 +0200 Subject: [PATCH v3 06/11] 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: <20260429-winbond-v6-18-rc1-cont-read-v3-6-0f38b3c229ad@bootlin.com> References: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> In-Reply-To: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> To: Mark Brown , Richard Weinberger , Vignesh Raghavendra , Michael Walle , Miquel Raynal , Takahiro Kuwano , Lorenzo Bianconi , Ray Liu , Chin-Ting Kuo , =?utf-8?q?C=C3=A9dric_Le_Goater?= , Joel Stanley , Andrew Jeffery , Avi Fishman , Tomer Maimon , Tali Perry , Patrick Venture , Nancy Yuen , Benjamin Fair , Maxime Coquelin , Alexandre Torgue , =?utf-8?q?Jonathan_Neusch=C3=A4fer?= Cc: Pratyush Yadav , Thomas Petazzoni , Steam Lin , Santhosh Kumar K , linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-aspeed@lists.ozlabs.org, openbmc@lists.ozlabs.org, linux-stm32@st-md-mailman.stormreply.com 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 | 61 +++++++++++++++++++++++++++++++++++++++++= +++- include/linux/mtd/spinand.h | 12 +++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index a66510747b31..45c3afb9cceb 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -489,6 +489,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; @@ -1221,6 +1226,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); @@ -1237,11 +1243,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 @@ -1259,6 +1278,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); @@ -1607,6 +1630,33 @@ int spinand_match_and_init(struct spinand_device *sp= inand, if (ret) return ret; =20 + if (info->op_variants.cont_read_cache) { + op =3D spinand_select_op_variant(spinand, SSDR, + info->op_variants.cont_read_cache); + if (op) { + const struct spi_mem_op *read_op; + + read_op =3D spinand->ssdr_op_templates.read_cache; + + /* + * 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 > op->cmd.buswidth || + (read_op->cmd.dtr && !op->cmd.dtr) || + read_op->addr.buswidth > op->addr.buswidth || + (read_op->addr.dtr && !op->addr.dtr) || + read_op->data.buswidth > op->data.buswidth || + (read_op->data.dtr && !op->data.dtr)) + spinand->cont_read_possible =3D false; + else + spinand->ssdr_op_templates.cont_read_cache =3D op; + } else { + spinand->cont_read_possible =3D false; + } + } + /* I/O variants selection with octo-spi DDR commands (optional) */ =20 ret =3D spinand_init_odtr_instruction_set(spinand); @@ -1629,6 +1679,15 @@ int spinand_match_and_init(struct spinand_device *sp= inand, info->op_variants.update_cache); spinand->odtr_op_templates.update_cache =3D op; =20 + if (info->op_variants.cont_read_cache) { + 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; + else + spinand->cont_read_possible =3D false; + } + return 0; } =20 diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index 896e9b5de0c4..4ff3f3383d46 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -576,6 +576,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 @@ -600,6 +601,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, @@ -629,6 +631,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 @@ -700,6 +710,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; @@ -714,6 +725,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.53.0 From nobody Sat Jun 13 04:53:58 2026 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 7E1DC41B370; Wed, 29 Apr 2026 17:58:06 +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=1777485487; cv=none; b=eaSgUayr6XP8tCHPwUZq5kpszUC2pWa8ufVUwN5AShwQ3Vfdwc4v0YHIzSy5pDWf1vrrzimVuDATkdOOBoQl8+IU9bz2kkd752hrhwGhQuMDrV7kSdTqbRwymc9pNNCxkFdjaxe8pjv783BS1mQoni1LTNThTuYrIMmlXgx1GO4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777485487; c=relaxed/simple; bh=tT0vI6x6+vRBWXLzlyXVUDtMNsqw/gVPmvwECAfidTo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=MZGGSgXbuOFXd0H1ne0eZcjAcLOQjzDH6ER2hXCXQikCde3ppRZrx2u2OhLd6FAAOrG+Of51NYNdpMz8cBCKsAb9s/skQIFD+0Pyk5pMzBdr7KLJ5rYwvxH2xDHLkANvw6J1aZkzOR9V58NXtBa7ed5yCdYNGBUfLmeB65DQ358= 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=2h0yUx/p; 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="2h0yUx/p" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id 77959C5CD60; Wed, 29 Apr 2026 17:58:49 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 45BF15FD43; Wed, 29 Apr 2026 17:58:05 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id C10A61072B178; Wed, 29 Apr 2026 19:57:58 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1777485483; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=HprCtklTZSXAxrv5AUxEIcuHwzjnoOSSK/fyyTwUO1Q=; b=2h0yUx/p5Hja1S+pQd+gl50t3YIhkpxRsKG5nJ165vnvrTv90N4OXtorw37kK/rs2QOMtF UcAPQAMKCm9kV3K6OFJh2acQrCERzuvscuxFcscI84fQEWqCQ2rtotTXnFMopvBIxwPfON kL3XlLNf2JQ8p34gdBDBSTFxxPFVG3lp2kL7K6jIGQmPib7VBgXwOa+Ifudb8hrNj6Qibi XCM0FThdYK9o2KKUOjT5j8c8ladUrhTaPyatCIwsrXzpF5UcQB0FeJCDaPuox/5jC9U+XW 3fQJes8ft8SlKmb/vtM3gnScS/HSiGG7M87RZUlOVt5IMRuvOEgWDBTr8IsPcg== From: Miquel Raynal Date: Wed, 29 Apr 2026 19:56:44 +0200 Subject: [PATCH v3 07/11] mtd: spinand: winbond: Ensure chips are ordered by density 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: <20260429-winbond-v6-18-rc1-cont-read-v3-7-0f38b3c229ad@bootlin.com> References: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> In-Reply-To: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> To: Mark Brown , Richard Weinberger , Vignesh Raghavendra , Michael Walle , Miquel Raynal , Takahiro Kuwano , Lorenzo Bianconi , Ray Liu , Chin-Ting Kuo , =?utf-8?q?C=C3=A9dric_Le_Goater?= , Joel Stanley , Andrew Jeffery , Avi Fishman , Tomer Maimon , Tali Perry , Patrick Venture , Nancy Yuen , Benjamin Fair , Maxime Coquelin , Alexandre Torgue , =?utf-8?q?Jonathan_Neusch=C3=A4fer?= Cc: Pratyush Yadav , Thomas Petazzoni , Steam Lin , Santhosh Kumar K , linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-aspeed@lists.ozlabs.org, openbmc@lists.ozlabs.org, linux-stm32@st-md-mailman.stormreply.com X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 All W35N0xJW chips have been added in a row, move the definition of the 2 and 4 Gb variants so their respective locations in the table. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/spi/winbond.c | 44 +++++++++++++++++++++-----------------= ---- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c index ad22774096e6..f4d4ffaa1f62 100644 --- a/drivers/mtd/nand/spi/winbond.c +++ b/drivers/mtd/nand/spi/winbond.c @@ -511,28 +511,6 @@ static const struct spinand_info winbond_spinand_table= [] =3D { SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops), SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL), SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)), - 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), - 0, - SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops), - SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL), - SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)), - 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), - 0, - SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops), - SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL), - SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)), /* 2G-bit densities */ SPINAND_INFO("W25M02GV", /* 2x1G-bit 3.3V */ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21), @@ -573,6 +551,17 @@ static const struct spinand_info winbond_spinand_table= [] =3D { &update_cache_variants), 0, SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), + 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), + 0, + SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops), + SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL), + SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)), /* 4G-bit densities */ SPINAND_INFO("W25N04KV", /* 3.3V */ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x23), @@ -592,6 +581,17 @@ static const struct spinand_info winbond_spinand_table= [] =3D { &update_cache_variants), 0, SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), + 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), + 0, + SPINAND_INFO_VENDOR_OPS(&winbond_w35_ops), + SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL), + SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)), }; =20 static int winbond_spinand_init(struct spinand_device *spinand) --=20 2.53.0 From nobody Sat Jun 13 04:53:58 2026 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 6D18A41B352; Wed, 29 Apr 2026 17:58:11 +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=1777485493; cv=none; b=faMZjM12PnOvo4M+6X6CqeDLcpPyvBVDSBVdF2Q6MvGDw/Wa0bthMS6T95pXgJWjH4q++z0990ayBlCTvcY1Tk99NUz4C/idE2hl2/MC0uLJK967gtCXxRUw2HkOCn/GeRYRlwiDLW7/CCmo4J+BNqjQuvmJzT+8uwBmCDzDCvM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777485493; c=relaxed/simple; bh=p3+es8rHWPYlhdr8kfQrAH5rTENaBs9muroPHf/JQy0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=R7m8ukkrdgR8+6G4Fi8A9oOdlPBX+9V310SFTGp+haHzwib4DTmbxiWqTMLwxZ4jLjv/j4WN77D+QaWo2YnKHVwaYRbJfhcp/bTJepmjwGu3oVmVZj9J7UArD4/+uu5tJrKdOgSOWb51knkCWu8xH/w2o8seJW7KLIQOf7s0SXQ= 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=bLojio66; 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="bLojio66" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-02.galae.net (Postfix) with ESMTPS id 22BA01A3452; Wed, 29 Apr 2026 17:58:10 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id E9AEA5FD43; Wed, 29 Apr 2026 17:58:09 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 715EB1072B16B; Wed, 29 Apr 2026 19:58:03 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1777485487; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=pSiHGhf6ru2F9nLoledFRKcwtuecIRMIsmhWqwY8OEQ=; b=bLojio66LcIQgqN/n+btKKH1+KzZHd0PhjJy8pHU7MF2zY82En696K6fsqgENUw3A3AiWY X3FxgrXGk0o1KAKhuIXvZpamGGbU32i2p4Gb5DM8ThZNiNaHCKEfAM25Tj4GfcHeUp38Ic JN20kVj7ma8kWBTC92wK1zqutKyjAEaIxGMNPSoVSNzpsERpflZ1gcOcahdkVe+BCVuqME IfXeNaYNchdXorisuS9wvRB0un5DgtDzDQf7URs05HuP4/S7wGhp0DnwWiXj4DXWJLlAr8 /Pf9CLPcC1E+1hnBjbVv7CguXmPeSSmuY/vsYMQnmnEKbndre52QePySVLx4wA== From: Miquel Raynal Date: Wed, 29 Apr 2026 19:56:45 +0200 Subject: [PATCH v3 08/11] 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: <20260429-winbond-v6-18-rc1-cont-read-v3-8-0f38b3c229ad@bootlin.com> References: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> In-Reply-To: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> To: Mark Brown , Richard Weinberger , Vignesh Raghavendra , Michael Walle , Miquel Raynal , Takahiro Kuwano , Lorenzo Bianconi , Ray Liu , Chin-Ting Kuo , =?utf-8?q?C=C3=A9dric_Le_Goater?= , Joel Stanley , Andrew Jeffery , Avi Fishman , Tomer Maimon , Tali Perry , Patrick Venture , Nancy Yuen , Benjamin Fair , Maxime Coquelin , Alexandre Torgue , =?utf-8?q?Jonathan_Neusch=C3=A4fer?= Cc: Pratyush Yadav , Thomas Petazzoni , Steam Lin , Santhosh Kumar K , linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-aspeed@lists.ozlabs.org, openbmc@lists.ozlabs.org, linux-stm32@st-md-mailman.stormreply.com 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 f4d4ffaa1f62..6c11f59a9f8d 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) { @@ -451,6 +529,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 */ @@ -504,13 +594,15 @@ 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)), /* 2G-bit densities */ SPINAND_INFO("W25M02GV", /* 2x1G-bit 3.3V */ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21), @@ -555,13 +647,15 @@ static const struct spinand_info winbond_spinand_tabl= e[] =3D { 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)), /* 4G-bit densities */ SPINAND_INFO("W25N04KV", /* 3.3V */ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x23), @@ -585,13 +679,15 @@ static const struct spinand_info winbond_spinand_tabl= e[] =3D { 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)), }; =20 static int winbond_spinand_init(struct spinand_device *spinand) --=20 2.53.0 From nobody Sat Jun 13 04:53:58 2026 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 6E39C3FE640; Wed, 29 Apr 2026 17:58:15 +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=1777485496; cv=none; b=i5c/erFIMKvR43MUjZjL1wG9YqQ6ODMuCrFOT6UJOmwIuqjRcfSQT033Fa+4SNs6bqmZ0XASu+yvnvSKE3M1OoIJFJBjdRZYfiGCas/xGOBUp8mLD9OLQYVAVt87Jy5bAJZm+GNTwP0lFe0PbmiOqat7B2tdb+Kg8AmqfJeJbls= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777485496; c=relaxed/simple; bh=6/F36LKn/NGibzDI14OIAiRrlVxPejW0eb2Oqu7W7Xg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=SXI/8HcndOPWRgWeUP2X3raqH/s96rhGdu5Yul4ECJnLrWDQN6cuYvJj+MO//DdlCwkz5v3oVq4t1nskHNGIqYMslZxuTmMMlQKNk7lve5MKJrYL6TZLZSIwVgd97d7HOnFUhhSKu8ReuV8SJfeYEra8ddu7YbTDC3So8ghSydQ= 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=Vmb/o8DH; 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="Vmb/o8DH" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id 35F694E42B73; Wed, 29 Apr 2026 17:58:14 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 09E735FD43; Wed, 29 Apr 2026 17:58:14 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 1A14B1072B175; Wed, 29 Apr 2026 19:58:07 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1777485491; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=5tIkRnE1ORjoj4u0h1eWmFg73tjo03bMRc5hBjhSYqM=; b=Vmb/o8DHri8qfjlDxdgxVCmz1cOiWo5fai2OHnEYLHyIsyVdpDTgWD44JJKYBik+Bop6+W qO/mPLDC2HvVPtzzFzJzmO0zmj8Ud0q8Cl6mkOzfLIV5t4BqhYfAOS/P4cCduBkSpSOfmM 5M8eLmzfXkqP4D5NBRKhvhmcWtsq9c1mg0MVwung6UnlsGwZeb4fsNZ/pNVgjm2S/Vrlqz cQsoBDbxgbA6MAC7jdwUUgJJZj7f2xsTfwFvpawEIDwOwqd6ZhkIt1k16aESiXmhdrWfdA Wg5O+8KVvlIUYgrSqKw5HE7tXplaioeNXtYi4yXBgQzvAFVe4lpxohvMt0C13A== From: Miquel Raynal Date: Wed, 29 Apr 2026 19:56:46 +0200 Subject: [PATCH v3 09/11] mtd: spinand: winbond: Create a helper to write the HS bit 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: <20260429-winbond-v6-18-rc1-cont-read-v3-9-0f38b3c229ad@bootlin.com> References: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> In-Reply-To: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> To: Mark Brown , Richard Weinberger , Vignesh Raghavendra , Michael Walle , Miquel Raynal , Takahiro Kuwano , Lorenzo Bianconi , Ray Liu , Chin-Ting Kuo , =?utf-8?q?C=C3=A9dric_Le_Goater?= , Joel Stanley , Andrew Jeffery , Avi Fishman , Tomer Maimon , Tali Perry , Patrick Venture , Nancy Yuen , Benjamin Fair , Maxime Coquelin , Alexandre Torgue , =?utf-8?q?Jonathan_Neusch=C3=A4fer?= Cc: Pratyush Yadav , Thomas Petazzoni , Steam Lin , Santhosh Kumar K , linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-aspeed@lists.ozlabs.org, openbmc@lists.ozlabs.org, linux-stm32@st-md-mailman.stormreply.com X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 Updating the HS bit is not complex but implies reading, setting/clearing a bit and writing. Clean a bit this section by moving this logic in its own helper. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/spi/winbond.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c index 6c11f59a9f8d..b30a343a6672 100644 --- a/drivers/mtd/nand/spi/winbond.c +++ b/drivers/mtd/nand/spi/winbond.c @@ -404,13 +404,28 @@ static int w25w35nxxjw_ecc_get_status(struct spinand_= device *spinand, u8 status) return -EINVAL; } =20 +static int w25n0xjw_set_sr4_hs(struct spinand_device *spinand, bool enable) +{ + int ret; + u8 sr4; + + ret =3D spinand_read_reg_op(spinand, W25N0XJW_SR4, &sr4); + if (ret) + return ret; + + if (enable) + sr4 |=3D W25N0XJW_SR4_HS; + else + sr4 &=3D ~W25N0XJW_SR4_HS; + + return spinand_write_reg_op(spinand, W25N0XJW_SR4, sr4); +} + static int w25n0xjw_hs_cfg(struct spinand_device *spinand, enum spinand_bus_interface iface) { const struct spi_mem_op *op; bool hs; - u8 sr4; - int ret; =20 if (iface !=3D SSDR) return -EOPNOTSUPP; @@ -429,20 +444,7 @@ static int w25n0xjw_hs_cfg(struct spinand_device *spin= and, else hs =3D true; =20 - ret =3D spinand_read_reg_op(spinand, W25N0XJW_SR4, &sr4); - if (ret) - return ret; - - if (hs) - sr4 |=3D W25N0XJW_SR4_HS; - else - sr4 &=3D ~W25N0XJW_SR4_HS; - - ret =3D spinand_write_reg_op(spinand, W25N0XJW_SR4, sr4); - if (ret) - return ret; - - return 0; + return w25n0xjw_set_sr4_hs(spinand, hs); } =20 static int w35n0xjw_write_vcr(struct spinand_device *spinand, u8 reg, u8 v= al) --=20 2.53.0 From nobody Sat Jun 13 04:53:58 2026 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 A4BBD3FE640; Wed, 29 Apr 2026 17:58:19 +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=1777485500; cv=none; b=XtwOrhhL8OrbG7o78FT7cDZapuMbXRr/09epb+PVc/BQGbrVgobRi4TUKrQR3lKXcqUg0kdhFKKSmzql+xDqUn34JnJsiBV5lSywVcERSqnBgtyJ9t/a5FAzPUavbnJzJK2iU2H8gJfz2QWUHbpKMXblO9sBJofPB6r7eLwCKI0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777485500; c=relaxed/simple; bh=SVk1CaFNho+vedmpEbxVPP6KCLDt4+qYheoCLm1aG/I=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=FlqKx7XC8/9CxsYoo1+Kt1AWXkOK5z79zuSQV0VZaLMsxHG6sMp7TRQUyqtk2NOtPR2Ga5t6/rlosIjByWR0LptpkbRK+BmCAOB1f8D6wT5x6rYa4QLXYzt3SknkpEpDifyjbSj7yw469FCBM5NXULsZtemfbW3GiVzjEEC2eb4= 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=NmSZF+iW; 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="NmSZF+iW" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-03.galae.net (Postfix) with ESMTPS id 38FA24E42B71; Wed, 29 Apr 2026 17:58:18 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 0CCFF5FD43; Wed, 29 Apr 2026 17:58:18 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 3C0971072B171; Wed, 29 Apr 2026 19:58:12 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1777485495; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=djNQC+WiehgbSjZPUHPGAOR2nkZcZmEr0KjHIcYf3t4=; b=NmSZF+iWjEyn2SmSbXR4+EkHCCLdjDtILUG9X51p5SCiphlxZnjKNNGhMMDdv6+IE8Z0pT ASIHf/oK5ins8abEGkf3OT/DpAh4+l/rTkVjcESvNc56zjX3c6MzBilErApZ2Bhx8qWhnA q4skr5wiZcq3mmwHq2jiVNGW1mYCJN/tNbDh2F3BzrrvyfD4fdGmhsSID0jKhhjNOiGAz6 jJJPYq8QKvuUtagfzMs9+zJqCAJairETws7j+Woa85G71iDosgPBr85dnsTyIGKlD82Shb llYfvCKlpMGTCJF/Xyt0qdAzxC71iYXH4L/FxQpv9jVgln0FJY4chh9edS6YQw== From: Miquel Raynal Date: Wed, 29 Apr 2026 19:56:47 +0200 Subject: [PATCH v3 10/11] mtd: spinand: winbond: Create a helper to detect the need for the HS bit 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: <20260429-winbond-v6-18-rc1-cont-read-v3-10-0f38b3c229ad@bootlin.com> References: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> In-Reply-To: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> To: Mark Brown , Richard Weinberger , Vignesh Raghavendra , Michael Walle , Miquel Raynal , Takahiro Kuwano , Lorenzo Bianconi , Ray Liu , Chin-Ting Kuo , =?utf-8?q?C=C3=A9dric_Le_Goater?= , Joel Stanley , Andrew Jeffery , Avi Fishman , Tomer Maimon , Tali Perry , Patrick Venture , Nancy Yuen , Benjamin Fair , Maxime Coquelin , Alexandre Torgue , =?utf-8?q?Jonathan_Neusch=C3=A4fer?= Cc: Pratyush Yadav , Thomas Petazzoni , Steam Lin , Santhosh Kumar K , linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-aspeed@lists.ozlabs.org, openbmc@lists.ozlabs.org, linux-stm32@st-md-mailman.stormreply.com X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 The logic is not complex but might be reused to cleanup a bit the section by moving it to a dedicated helper. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/spi/winbond.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c index b30a343a6672..ffbcd25b0366 100644 --- a/drivers/mtd/nand/spi/winbond.c +++ b/drivers/mtd/nand/spi/winbond.c @@ -421,30 +421,33 @@ static int w25n0xjw_set_sr4_hs(struct spinand_device = *spinand, bool enable) return spinand_write_reg_op(spinand, W25N0XJW_SR4, sr4); } =20 +/* + * SDR dual and quad I/O operations over 104MHz require the HS bit to + * enable a few more dummy cycles. + */ +static bool w25n0xjw_op_needs_hs(const struct spi_mem_op *op) +{ + if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr) + return false; + else if (op->cmd.buswidth !=3D 1 || op->addr.buswidth =3D=3D 1) + return false; + else if (op->max_freq && op->max_freq <=3D 104 * HZ_PER_MHZ) + return false; + + return true; +} + static int w25n0xjw_hs_cfg(struct spinand_device *spinand, enum spinand_bus_interface iface) { const struct spi_mem_op *op; - bool hs; =20 if (iface !=3D SSDR) return -EOPNOTSUPP; =20 - /* - * SDR dual and quad I/O operations over 104MHz require the HS bit to - * enable a few more dummy cycles. - */ op =3D spinand->op_templates->read_cache; - if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr) - hs =3D false; - else if (op->cmd.buswidth !=3D 1 || op->addr.buswidth =3D=3D 1) - hs =3D false; - else if (op->max_freq && op->max_freq <=3D 104 * HZ_PER_MHZ) - hs =3D false; - else - hs =3D true; =20 - return w25n0xjw_set_sr4_hs(spinand, hs); + return w25n0xjw_set_sr4_hs(spinand, w25n0xjw_op_needs_hs(op)); } =20 static int w35n0xjw_write_vcr(struct spinand_device *spinand, u8 reg, u8 v= al) --=20 2.53.0 From nobody Sat Jun 13 04:53:58 2026 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 34AB538B7DD; Wed, 29 Apr 2026 17:58:22 +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=1777485504; cv=none; b=JvT5kw88SxBkCR8Prt+/AXe+Z+/tCYuR5lzvsfJ3W6C6qUpvJjEbFD+Z+KL1uBW3BcgTXMQUkhW+csKv1TDanfz+S3FY9kld/esnQvl8FVCoI+ZcucCto4vJf3fNqiXCVc1RtrdcqI9cg0mekbIcmmoouwzFYWTvNvwpOlHDqtk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777485504; c=relaxed/simple; bh=xmFDmlgVjkj++QwdPDqsdB8zWzCpz+FyZ0E8Ra5CwBM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=jY0gpxv3r8NEAC3e9sUZEEWM61VNSkfXVsRdhYVK3jRP8pq6iEDlky7mjiRo0dfxwb5ZWKPKEJwicXJDjSIJEDTKi3lQ97KlYKBdwCQB6gHPGNZPUic8qU7XUBca55a3AKjP701dik0z9FFnTB6Hto54dySe1lH32H/k03KqDvM= 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=Kc0vRRlq; 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="Kc0vRRlq" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id 290B4C5CD63; Wed, 29 Apr 2026 17:59:06 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id E99E35FD43; Wed, 29 Apr 2026 17:58:21 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 6FE631072B176; Wed, 29 Apr 2026 19:58:16 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1777485500; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=MmcPFcCFT0gegKw7/GAlAOSTHc6JlaEROIWqR2nOl4k=; b=Kc0vRRlqvfSudEFr1jF1Gd7LJngYIVk/OpJ9Xy8LuG253NtHk6/h4qCUHyLC/uelRVb4cc 4dtdIBzKI2GiH9nxWVLuBkH0XM6+60TUTV3lPbduunRwVmtsS7NZANu7HdJhAtQLgyg/XC qfAyvlNfSlYsoOKdexYgZ4wm/bWSodcggsYCwEBKkDHvzztBYmluC6xuKPrOLpX9/h7Qic pT6L6tnkencqHbZvV4EVzLeBhMxFjsgykFNa9YcAAIpXCmpJMwhvoG1NFc/Ior2L3DtbkU 3DKkjUd9tAEKhfs0hEhZ7womvlhnP/h4dMJsvpfuXnYvpxywIGUMsaSX8ch/9Q== From: Miquel Raynal Date: Wed, 29 Apr 2026 19:56:48 +0200 Subject: [PATCH v3 11/11] 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: <20260429-winbond-v6-18-rc1-cont-read-v3-11-0f38b3c229ad@bootlin.com> References: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> In-Reply-To: <20260429-winbond-v6-18-rc1-cont-read-v3-0-0f38b3c229ad@bootlin.com> To: Mark Brown , Richard Weinberger , Vignesh Raghavendra , Michael Walle , Miquel Raynal , Takahiro Kuwano , Lorenzo Bianconi , Ray Liu , Chin-Ting Kuo , =?utf-8?q?C=C3=A9dric_Le_Goater?= , Joel Stanley , Andrew Jeffery , Avi Fishman , Tomer Maimon , Tali Perry , Patrick Venture , Nancy Yuen , Benjamin Fair , Maxime Coquelin , Alexandre Torgue , =?utf-8?q?Jonathan_Neusch=C3=A4fer?= Cc: Pratyush Yadav , Thomas Petazzoni , Steam Lin , Santhosh Kumar K , linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-aspeed@lists.ozlabs.org, openbmc@lists.ozlabs.org, linux-stm32@st-md-mailman.stormreply.com 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. Signed-off-by: Miquel Raynal --- All variants have been validated on a Nuvoton MA35D1 platform. --- drivers/mtd/nand/spi/winbond.c | 108 +++++++++++++++++++++++++++++++++++++= ---- 1 file changed, 98 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c index ffbcd25b0366..578f702528ee 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(7, 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), @@ -445,11 +515,25 @@ static int w25n0xjw_hs_cfg(struct spinand_device *spi= nand, if (iface !=3D SSDR) return -EOPNOTSUPP; =20 + /* + * At this stage, we do not yet know the continuous read template, nor + * if there is going to be one. Let's assume the continuous read + * template will be selected with the same heuristics as the buffered + * read variant, as there cannot be a HS configuration mismatch between + * them. + */ op =3D spinand->op_templates->read_cache; =20 return w25n0xjw_set_sr4_hs(spinand, w25n0xjw_op_needs_hs(op)); } =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, 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, @@ -580,12 +664,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), SPINAND_HAS_QE_BIT, - 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), @@ -624,12 +710,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), SPINAND_HAS_QE_BIT, - 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.53.0