From nobody Tue Dec 16 15:13:55 2025 Received: from smtpout-04.galae.net (smtpout-04.galae.net [185.171.202.116]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 70541322B7E; Fri, 5 Dec 2025 19:39:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.171.202.116 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764963598; cv=none; b=qTVBsoihaNZuKsX7rr4Mbwkk9KEy5SsgVR1ZUyuBcjoOFJ/JUKeRHrGhvQxwYu82fCKZ9mF21mZATLrJgfgegL3eJuGD1zKZjUJweqSsZsdt//LbsjS12I45yvu1lbMSZWQSgjX8WP3uoug9Nn4BZIxQVqdfj3T3XEzITpfGsrI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764963598; c=relaxed/simple; bh=vPU+4PGXnQKsNC72tkHF1EUG8fgwp0WizxbbC7wkK7M=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=DggfXMV+kQtVap+3YAqDMkylnRAaGS8KKrEp+i4x7el0G4ACDATyBNvrbtGqiOFuDRHfic9EUGg/5Ngs/a+L3Qkaasrl4wj7vf3JOTPa1oICFkk5Q3i3cpfWuv/12Lvt6IZ394NIg/4h+qJJ+3iQQi652rS0D1Eyrpf4rIeRLl4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=l0UnPVwa; arc=none smtp.client-ip=185.171.202.116 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="l0UnPVwa" Received: from smtpout-01.galae.net (smtpout-01.galae.net [212.83.139.233]) by smtpout-04.galae.net (Postfix) with ESMTPS id 93921C1964F; Fri, 5 Dec 2025 19:39:31 +0000 (UTC) Received: from mail.galae.net (mail.galae.net [212.83.136.155]) by smtpout-01.galae.net (Postfix) with ESMTPS id 15AB9606AC; Fri, 5 Dec 2025 19:39:55 +0000 (UTC) Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id DA3F6102F18EA; Fri, 5 Dec 2025 20:39:52 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=dkim; t=1764963594; h=from:subject:date:message-id:to:cc:mime-version:content-type: content-transfer-encoding:in-reply-to:references; bh=EkSh6VEYpuxxHIEG0meSRCtp2QS/BqvaPUatfSsQwyk=; b=l0UnPVwaxkv3cNVoVZhqxcBtHj/KIOZxR4infQxPfyFagCIgmhNDZrxDjBI5puCdWJc8+f DUWCSsjTC1lRV2W0N3O7Vb07COds0f9Llo9oTAHnY9MQ/gc5RF2AccEJanM8/9DGYCM6u0 tafGBtWg+ZDkWmD0d/NidnUnLk8dpAWL6Ug16H237c2ECGdoTB633g5WiVIwQ9tF9xis/8 9bXB3yk1O9XepqOXPAHFlppJSmrnaEcb1A7p5lxNRID4ClW0pkhk0KaBLr3ncywxFUqQk5 AKNIhfgJntzOV/0pHNo8pRGRuegIkA/aTy1QyTORiHEmqKJaSKPSZKnKMFvbDw== From: Miquel Raynal Date: Fri, 05 Dec 2025 20:38:57 +0100 Subject: [PATCH RFC 6/8] mtd: spinand: Use secondary ops for continuous reads Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251205-winbond-v6-18-rc1-cont-read-v1-6-01bc48631c73@bootlin.com> References: <20251205-winbond-v6-18-rc1-cont-read-v1-0-01bc48631c73@bootlin.com> In-Reply-To: <20251205-winbond-v6-18-rc1-cont-read-v1-0-01bc48631c73@bootlin.com> To: Mark Brown , Richard Weinberger , Vignesh Raghavendra , Michael Walle Cc: Tudor Ambarus , Pratyush Yadav , Thomas Petazzoni , Steam Lin , Santhosh Kumar K , linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, Miquel Raynal X-Mailer: b4 0.14.3 X-Last-TLS-Session-Version: TLSv1.3 In case a chip supports continuous reads, but uses a slightly different cache operation for these, it may provide a secondary operation template which will be used only during continuous cache read operations. From a vendor driver point of view, enabling this feature implies providing a new set of templates for these continuous read operations. The core will automatically pick the fastest variant, depending on the hardware capabilities. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/spi/core.c | 51 +++++++++++++++++++++++++++++++++++++++++= +++- include/linux/mtd/spinand.h | 12 +++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 209146f21326..37a0d0373942 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -399,6 +399,11 @@ static int spinand_read_from_cache_op(struct spinand_d= evice *spinand, =20 rdesc =3D spinand->dirmaps[req->pos.plane].rdesc; =20 + if (spinand->op_templates->cont_read_cache && req->continuous) + rdesc->info.op_tmpl =3D &rdesc->info.secondary_op_tmpl; + else + rdesc->info.op_tmpl =3D &rdesc->info.primary_op_tmpl; + if (nand->ecc.engine->integration =3D=3D NAND_ECC_ENGINE_INTEGRATION_PIPE= LINED && req->mode !=3D MTD_OPS_RAW) rdesc->info.op_tmpl->data.ecc =3D true; @@ -1123,6 +1128,7 @@ static struct spi_mem_dirmap_desc *spinand_create_rde= sc( * its spi controller, use regular reading */ spinand->cont_read_possible =3D false; + memset(&info->secondary_op_tmpl, 0, sizeof(info->secondary_op_tmpl)); =20 info->length =3D nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); @@ -1139,11 +1145,24 @@ static int spinand_create_dirmap(struct spinand_dev= ice *spinand, struct nand_device *nand =3D spinand_to_nand(spinand); struct spi_mem_dirmap_info info =3D { 0 }; struct spi_mem_dirmap_desc *desc; - bool enable_ecc =3D false; + bool enable_ecc =3D false, secondary_op =3D false; =20 if (nand->ecc.engine->integration =3D=3D NAND_ECC_ENGINE_INTEGRATION_PIPE= LINED) enable_ecc =3D true; =20 + if (spinand->cont_read_possible && spinand->op_templates->cont_read_cache) + secondary_op =3D true; + + /* + * Continuous read implies that only the main data is retrieved, backed + * by an on-die ECC engine. It is not possible to use a pipelind ECC + * engine with continuous read. + */ + if (enable_ecc && secondary_op) { + secondary_op =3D false; + spinand->cont_read_possible =3D false; + } + /* The plane number is passed in MSB just above the column address */ info.offset =3D plane << fls(nand->memorg.pagesize); =20 @@ -1161,6 +1180,10 @@ static int spinand_create_dirmap(struct spinand_devi= ce *spinand, /* Read descriptor */ info.primary_op_tmpl =3D *spinand->op_templates->read_cache; info.primary_op_tmpl.data.ecc =3D enable_ecc; + if (secondary_op) { + info.secondary_op_tmpl =3D *spinand->op_templates->cont_read_cache; + info.secondary_op_tmpl.data.ecc =3D enable_ecc; + } desc =3D spinand_create_rdesc(spinand, &info); if (IS_ERR(desc)) return PTR_ERR(desc); @@ -1505,6 +1528,27 @@ int spinand_match_and_init(struct spinand_device *sp= inand, if (ret) return ret; =20 + op =3D spinand_select_op_variant(spinand, SSDR, + info->op_variants.cont_read_cache); + if (op) { + const struct spi_mem_op *read_op =3D spinand->ssdr_op_templates.read_ca= che; + + /* + * Sometimes the fastest continuous read variant may not + * be supported. In this case, prefer to use the fastest + * read from cache variant and disable continuous reads. + */ + if (read_op->cmd.buswidth !=3D op->cmd.buswidth || + read_op->cmd.dtr !=3D op->cmd.dtr || + read_op->addr.buswidth !=3D op->addr.buswidth || + read_op->addr.dtr !=3D op->addr.dtr || + read_op->cmd.buswidth !=3D op->cmd.buswidth || + read_op->cmd.dtr !=3D op->cmd.dtr) + spinand->cont_read_possible =3D false; + else + spinand->ssdr_op_templates.cont_read_cache =3D op; + } + /* I/O variants selection with octo-spi DDR commands (optional) */ =20 ret =3D spinand_init_odtr_instruction_set(spinand); @@ -1527,6 +1571,11 @@ int spinand_match_and_init(struct spinand_device *sp= inand, info->op_variants.update_cache); spinand->odtr_op_templates.update_cache =3D op; =20 + op =3D spinand_select_op_variant(spinand, ODTR, + info->op_variants.cont_read_cache); + if (op) + spinand->odtr_op_templates.cont_read_cache =3D op; + return 0; } =20 diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index 5ca1181048f7..5ec7d756df8b 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -573,6 +573,7 @@ enum spinand_bus_interface { * @op_variants.read_cache: variants of the read-cache operation * @op_variants.write_cache: variants of the write-cache operation * @op_variants.update_cache: variants of the update-cache operation + * @op_variants.cont_read_cache: variants of the continuous read-cache ope= ration * @vendor_ops: vendor specific operations * @select_target: function used to select a target/die. Required only for * multi-die chips @@ -597,6 +598,7 @@ struct spinand_info { const struct spinand_op_variants *read_cache; const struct spinand_op_variants *write_cache; const struct spinand_op_variants *update_cache; + const struct spinand_op_variants *cont_read_cache; } op_variants; const struct spinand_op_variants *vendor_ops; int (*select_target)(struct spinand_device *spinand, @@ -626,6 +628,14 @@ struct spinand_info { .update_cache =3D __update, \ } =20 +#define SPINAND_INFO_OP_VARIANTS_WITH_CONT(__read, __write, __update, __co= nt_read) \ + { \ + .read_cache =3D __read, \ + .write_cache =3D __write, \ + .update_cache =3D __update, \ + .cont_read_cache =3D __cont_read, \ + } + #define SPINAND_INFO_VENDOR_OPS(__ops) \ .vendor_ops =3D __ops =20 @@ -697,6 +707,7 @@ struct spinand_dirmap { * @read_cache: read cache op template * @write_cache: write cache op template * @update_cache: update cache op template + * @cont_read_cache: continuous read cache op template (optional) */ struct spinand_mem_ops { struct spi_mem_op reset; @@ -711,6 +722,7 @@ struct spinand_mem_ops { const struct spi_mem_op *read_cache; const struct spi_mem_op *write_cache; const struct spi_mem_op *update_cache; + const struct spi_mem_op *cont_read_cache; }; =20 /** --=20 2.51.1