linux-mmc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/6] mmc: introduce multi-block read gap tuning
@ 2025-08-18 14:02 Benoît Monin
  2025-08-18 14:02 ` [PATCH v4 1/6] mmc: core: add mmc_card_can_cmd23 Benoît Monin
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Benoît Monin @ 2025-08-18 14:02 UTC (permalink / raw)
  To: Ulf Hansson, Adrian Hunter
  Cc: linux-mmc, linux-kernel, Vladimir Kondratiev, Tawfik Bayouk,
	Gregory CLEMENT, Thomas Petazzoni, Benoît Monin

This patchset implements the multi-block read gap tuning for the SDHCI
cadence driver.

The first two patches introduce helpers to check for CMD23 support by
MMC card: mmc_card_can_cmd23 for support proper and mmc_card_blk_no_cmd23
for the NO_CMD23 quirk.

The next two patches use the new helpers in mmc/core/mmc_test.c and
mmc/core/block.c.

The next patch add mmc_read_tuning to read blocks from MMC as part of
the tuning. This function does not return the data read to the caller,
only the status of the read operation.

Finally the last patch uses mmc_read_tuning to implement the multi-block
read gap tuning in the cadence host driver, by doing a multi-block read
and increasing the gap delay until the read succeeds.

In the previous version of this series, mmc_read_tuning had a struct
mmc_card parameter and was making use of the helpers. This parameter has
been dropped so the last two patches are now independent of the rest of
the patchset.

Signed-off-by: Benoît Monin <benoit.monin@bootlin.com>
---
Changes in v4:
- Dropped the card parameter of mmc_read_tuning.
- Updated the last patch following the review of Adrian.
- Link to v3: https://lore.kernel.org/r/20250716-mobileye-emmc-for-upstream-4-v3-0-dc979d8edef0@bootlin.com

Changes in v3:
- Move the changes related to CMD23 support by MMC card to separate
  patches at the beginning of the series.
- Change the mmc read function to be less appealing to reuse/abuse
  outside of tuning context.
- Link to v2: https://lore.kernel.org/linux-mmc/cover.1751898225.git.benoit.monin@bootlin.com/

Changes in v2:
- Split the code between the core and the driver by adding a generic
  function to read blocks from the MMC.
- Link to v1: https://lore.kernel.org/linux-mmc/2a43386ffef4012530ca2421ad81ad21c36c8a25.1750943549.git.benoit.monin@bootlin.com/

---
Benoît Monin (6):
      mmc: core: add mmc_card_can_cmd23
      mmc: card: add mmc_card_blk_no_cmd23
      mmc: mmc_test: use mmc_card cmd23 helpers
      mmc: block: use mmc_card cmd23 helpers
      mmc: core: add mmc_read_tuning
      mmc: sdhci-cadence: implement multi-block read gap tuning

 drivers/mmc/core/block.c         | 12 ++-----
 drivers/mmc/core/card.h          |  9 +++--
 drivers/mmc/core/core.c          |  9 +++++
 drivers/mmc/core/core.h          |  1 +
 drivers/mmc/core/mmc_ops.c       | 72 ++++++++++++++++++++++++++++++++++++++++
 drivers/mmc/core/mmc_test.c      | 10 ++----
 drivers/mmc/host/sdhci-cadence.c | 63 ++++++++++++++++++++++++++++++++++-
 include/linux/mmc/host.h         |  1 +
 8 files changed, 157 insertions(+), 20 deletions(-)
---
base-commit: 8936497143de1da7958178d57db6011eceeb14a8
change-id: 20250716-mobileye-emmc-for-upstream-4-40ef552c3b59

Best regards,
-- 
Benoît Monin, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v4 1/6] mmc: core: add mmc_card_can_cmd23
  2025-08-18 14:02 [PATCH v4 0/6] mmc: introduce multi-block read gap tuning Benoît Monin
@ 2025-08-18 14:02 ` Benoît Monin
  2025-08-18 14:02 ` [PATCH v4 2/6] mmc: card: add mmc_card_blk_no_cmd23 Benoît Monin
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Benoît Monin @ 2025-08-18 14:02 UTC (permalink / raw)
  To: Ulf Hansson, Adrian Hunter
  Cc: linux-mmc, linux-kernel, Vladimir Kondratiev, Tawfik Bayouk,
	Gregory CLEMENT, Thomas Petazzoni, Benoît Monin

Add a dedicated helper to check for CMD23 support for MMC card, similar
to mmc_host_can_cmd23 for the host, as it is easy to get the check
wrong.

Signed-off-by: Benoît Monin <benoit.monin@bootlin.com>
---
 drivers/mmc/core/core.c | 9 +++++++++
 drivers/mmc/core/core.h | 1 +
 2 files changed, 10 insertions(+)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 874c6fe92855e3535ec0ebc0254146f4b96bccc3..88fd231fee1d150b22baebddb7ad47472c24fb32 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1875,6 +1875,15 @@ bool mmc_card_can_secure_erase_trim(struct mmc_card *card)
 }
 EXPORT_SYMBOL(mmc_card_can_secure_erase_trim);
 
+bool mmc_card_can_cmd23(struct mmc_card *card)
+{
+	return ((mmc_card_mmc(card) &&
+		 card->csd.mmca_vsn >= CSD_SPEC_VER_3) ||
+		(mmc_card_sd(card) && !mmc_card_ult_capacity(card) &&
+		 card->scr.cmds & SD_SCR_CMD23_SUPPORT));
+}
+EXPORT_SYMBOL(mmc_card_can_cmd23);
+
 int mmc_erase_group_aligned(struct mmc_card *card, sector_t from,
 			    unsigned int nr)
 {
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 622085cd766f91334d5b9362cd7b96245af8884d..73f5d3d8c77d5da53795fe09beb384f134d6a886 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -123,6 +123,7 @@ bool mmc_card_can_trim(struct mmc_card *card);
 bool mmc_card_can_discard(struct mmc_card *card);
 bool mmc_card_can_sanitize(struct mmc_card *card);
 bool mmc_card_can_secure_erase_trim(struct mmc_card *card);
+bool mmc_card_can_cmd23(struct mmc_card *card);
 int mmc_erase_group_aligned(struct mmc_card *card, sector_t from, unsigned int nr);
 unsigned int mmc_calc_max_discard(struct mmc_card *card);
 

-- 
2.50.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v4 2/6] mmc: card: add mmc_card_blk_no_cmd23
  2025-08-18 14:02 [PATCH v4 0/6] mmc: introduce multi-block read gap tuning Benoît Monin
  2025-08-18 14:02 ` [PATCH v4 1/6] mmc: core: add mmc_card_can_cmd23 Benoît Monin
@ 2025-08-18 14:02 ` Benoît Monin
  2025-08-18 14:02 ` [PATCH v4 3/6] mmc: mmc_test: use mmc_card cmd23 helpers Benoît Monin
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Benoît Monin @ 2025-08-18 14:02 UTC (permalink / raw)
  To: Ulf Hansson, Adrian Hunter
  Cc: linux-mmc, linux-kernel, Vladimir Kondratiev, Tawfik Bayouk,
	Gregory CLEMENT, Thomas Petazzoni, Benoît Monin

Add a helper to check for the missing CMD23 quirk, similar to other
quirk helpers. Also reorder the helpers to match the order of the quirk
bits defined in include/linux/mmc/card.h.

Signed-off-by: Benoît Monin <benoit.monin@bootlin.com>
---
 drivers/mmc/core/card.h | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/core/card.h b/drivers/mmc/core/card.h
index 9cbdd240c3a7d42ecbb45cbc52c5562e4664ee35..1200951bab08c2e18ce96becf56693e696b9f30b 100644
--- a/drivers/mmc/core/card.h
+++ b/drivers/mmc/core/card.h
@@ -245,14 +245,19 @@ static inline int mmc_blksz_for_byte_mode(const struct mmc_card *c)
 	return c->quirks & MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
 }
 
+static inline int mmc_card_nonstd_func_interface(const struct mmc_card *c)
+{
+	return c->quirks & MMC_QUIRK_NONSTD_FUNC_IF;
+}
+
 static inline int mmc_card_disable_cd(const struct mmc_card *c)
 {
 	return c->quirks & MMC_QUIRK_DISABLE_CD;
 }
 
-static inline int mmc_card_nonstd_func_interface(const struct mmc_card *c)
+static inline int mmc_card_blk_no_cmd23(const struct mmc_card *c)
 {
-	return c->quirks & MMC_QUIRK_NONSTD_FUNC_IF;
+	return c->quirks & MMC_QUIRK_BLK_NO_CMD23;
 }
 
 static inline int mmc_card_broken_byte_mode_512(const struct mmc_card *c)

-- 
2.50.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v4 3/6] mmc: mmc_test: use mmc_card cmd23 helpers
  2025-08-18 14:02 [PATCH v4 0/6] mmc: introduce multi-block read gap tuning Benoît Monin
  2025-08-18 14:02 ` [PATCH v4 1/6] mmc: core: add mmc_card_can_cmd23 Benoît Monin
  2025-08-18 14:02 ` [PATCH v4 2/6] mmc: card: add mmc_card_blk_no_cmd23 Benoît Monin
@ 2025-08-18 14:02 ` Benoît Monin
  2025-08-18 14:02 ` [PATCH v4 4/6] mmc: block: " Benoît Monin
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Benoît Monin @ 2025-08-18 14:02 UTC (permalink / raw)
  To: Ulf Hansson, Adrian Hunter
  Cc: linux-mmc, linux-kernel, Vladimir Kondratiev, Tawfik Bayouk,
	Gregory CLEMENT, Thomas Petazzoni, Benoît Monin

Use mmc_card_can_cmd23 instead of using a local and partial
implementation, and check for the CMD23 quirk with
mmc_card_blk_no_cmd23.

Signed-off-by: Benoît Monin <benoit.monin@bootlin.com>
---
 drivers/mmc/core/mmc_test.c | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c
index 80e5d87a5e50bea772c06443bca8f48f042d6ad5..67d4a301895c905bf52776f970bfc7a8f86a65aa 100644
--- a/drivers/mmc/core/mmc_test.c
+++ b/drivers/mmc/core/mmc_test.c
@@ -180,20 +180,14 @@ static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size)
 	return mmc_set_blocklen(test->card, size);
 }
 
-static bool mmc_test_card_cmd23(struct mmc_card *card)
-{
-	return mmc_card_mmc(card) ||
-	       (mmc_card_sd(card) && card->scr.cmds & SD_SCR_CMD23_SUPPORT);
-}
-
 static void mmc_test_prepare_sbc(struct mmc_test_card *test,
 				 struct mmc_request *mrq, unsigned int blocks)
 {
 	struct mmc_card *card = test->card;
 
 	if (!mrq->sbc || !mmc_host_can_cmd23(card->host) ||
-	    !mmc_test_card_cmd23(card) || !mmc_op_multi(mrq->cmd->opcode) ||
-	    (card->quirks & MMC_QUIRK_BLK_NO_CMD23)) {
+	    !mmc_card_can_cmd23(card) || !mmc_op_multi(mrq->cmd->opcode) ||
+	    mmc_card_blk_no_cmd23(card)) {
 		mrq->sbc = NULL;
 		return;
 	}

-- 
2.50.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v4 4/6] mmc: block: use mmc_card cmd23 helpers
  2025-08-18 14:02 [PATCH v4 0/6] mmc: introduce multi-block read gap tuning Benoît Monin
                   ` (2 preceding siblings ...)
  2025-08-18 14:02 ` [PATCH v4 3/6] mmc: mmc_test: use mmc_card cmd23 helpers Benoît Monin
@ 2025-08-18 14:02 ` Benoît Monin
  2025-08-18 14:02 ` [PATCH v4 5/6] mmc: core: add mmc_read_tuning Benoît Monin
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Benoît Monin @ 2025-08-18 14:02 UTC (permalink / raw)
  To: Ulf Hansson, Adrian Hunter
  Cc: linux-mmc, linux-kernel, Vladimir Kondratiev, Tawfik Bayouk,
	Gregory CLEMENT, Thomas Petazzoni, Benoît Monin

Use the dedicated helpers for CMD23 card support.

Signed-off-by: Benoît Monin <benoit.monin@bootlin.com>
---
 drivers/mmc/core/block.c | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
index 9cc47bf94804b64a9cc60c7a5d95a0082d546ea9..8fd9891462054da8c00bdbb93e3414614441644d 100644
--- a/drivers/mmc/core/block.c
+++ b/drivers/mmc/core/block.c
@@ -1768,8 +1768,7 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
 	 * these, while retaining features like reliable writes.
 	 */
 	if ((md->flags & MMC_BLK_CMD23) && mmc_op_multi(brq->cmd.opcode) &&
-	    (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23) ||
-	     do_data_tag)) {
+	    (do_rel_wr || !mmc_card_blk_no_cmd23(card) || do_data_tag)) {
 		brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
 		brq->sbc.arg = brq->data.blocks |
 			(do_rel_wr ? (1 << 31) : 0) |
@@ -2618,13 +2617,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
 	 */
 	md->read_only = mmc_blk_readonly(card);
 
-	if (mmc_host_can_cmd23(card->host)) {
-		if ((mmc_card_mmc(card) &&
-		     card->csd.mmca_vsn >= CSD_SPEC_VER_3) ||
-		    (mmc_card_sd(card) && !mmc_card_ult_capacity(card) &&
-		     card->scr.cmds & SD_SCR_CMD23_SUPPORT))
-			md->flags |= MMC_BLK_CMD23;
-	}
+	if (mmc_host_can_cmd23(card->host) && mmc_card_can_cmd23(card))
+		md->flags |= MMC_BLK_CMD23;
 
 	if (md->flags & MMC_BLK_CMD23 &&
 	    ((card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN) ||

-- 
2.50.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v4 5/6] mmc: core: add mmc_read_tuning
  2025-08-18 14:02 [PATCH v4 0/6] mmc: introduce multi-block read gap tuning Benoît Monin
                   ` (3 preceding siblings ...)
  2025-08-18 14:02 ` [PATCH v4 4/6] mmc: block: " Benoît Monin
@ 2025-08-18 14:02 ` Benoît Monin
  2025-08-18 14:02 ` [PATCH v4 6/6] mmc: sdhci-cadence: implement multi-block read gap tuning Benoît Monin
  2025-08-18 14:56 ` [PATCH v4 0/6] mmc: introduce " Ulf Hansson
  6 siblings, 0 replies; 8+ messages in thread
From: Benoît Monin @ 2025-08-18 14:02 UTC (permalink / raw)
  To: Ulf Hansson, Adrian Hunter
  Cc: linux-mmc, linux-kernel, Vladimir Kondratiev, Tawfik Bayouk,
	Gregory CLEMENT, Thomas Petazzoni, Benoît Monin

Provide a function to the MMC hosts to read some blocks of data as part
of their tuning.

This function only returns the status of the read operation, not the
data read.

Signed-off-by: Benoît Monin <benoit.monin@bootlin.com>
---
 drivers/mmc/core/mmc_ops.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mmc/host.h   |  1 +
 2 files changed, 73 insertions(+)

diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 66283825513cb4ff993a1b2ec1f0b0cac4e74487..a952cc8265af8f9d9587e4f21884d5f6d2fe0369 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -1077,3 +1077,75 @@ int mmc_sanitize(struct mmc_card *card, unsigned int timeout_ms)
 	return err;
 }
 EXPORT_SYMBOL_GPL(mmc_sanitize);
+
+/**
+ * mmc_read_tuning() - read data blocks from the mmc
+ * @host: mmc host doing the read
+ * @blksz: data block size
+ * @blocks: number of blocks to read
+ *
+ * Read one or more blocks of data from the beginning of the mmc. This is a
+ * low-level helper for tuning operation. It is assumed that CMD23 can be used
+ * for multi-block read if the host supports it.
+ *
+ * Note: Allocate and free a temporary buffer to store the data read. The data
+ * is not available outside of the function, only the status of the read
+ * operation.
+ *
+ * Return: 0 in case of success, otherwise -EIO / -ENOMEM / -E2BIG
+ */
+int mmc_read_tuning(struct mmc_host *host, unsigned int blksz, unsigned int blocks)
+{
+	struct mmc_request mrq = {};
+	struct mmc_command sbc = {};
+	struct mmc_command cmd = {};
+	struct mmc_command stop = {};
+	struct mmc_data data = {};
+	struct scatterlist sg;
+	void *buf;
+	unsigned int len;
+
+	if (blocks > 1) {
+		if (mmc_host_can_cmd23(host)) {
+			mrq.sbc = &sbc;
+			sbc.opcode = MMC_SET_BLOCK_COUNT;
+			sbc.arg = blocks;
+			sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
+		}
+		cmd.opcode = MMC_READ_MULTIPLE_BLOCK;
+		mrq.stop = &stop;
+		stop.opcode = MMC_STOP_TRANSMISSION;
+		stop.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+	} else {
+		cmd.opcode = MMC_READ_SINGLE_BLOCK;
+	}
+
+	mrq.cmd = &cmd;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+
+	mrq.data = &data;
+	data.flags = MMC_DATA_READ;
+	data.blksz = blksz;
+	data.blocks = blocks;
+	data.blk_addr = 0;
+	data.sg = &sg;
+	data.sg_len = 1;
+	data.timeout_ns = 1000000000;
+
+	if (check_mul_overflow(blksz, blocks, &len))
+		return -E2BIG;
+	buf = kmalloc(len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	sg_init_one(&sg, buf, len);
+
+	mmc_wait_for_req(host, &mrq);
+	kfree(buf);
+
+	if (sbc.error || cmd.error || data.error)
+		return -EIO;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mmc_read_tuning);
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 68f09a955a902047ac517441b6820fa6e4166a13..5ed5d203de23c1cd503061e0ef6a8bfd7253c8af 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -743,5 +743,6 @@ int mmc_send_status(struct mmc_card *card, u32 *status);
 int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
 int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode);
 int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
+int mmc_read_tuning(struct mmc_host *host, unsigned int blksz, unsigned int blocks);
 
 #endif /* LINUX_MMC_HOST_H */

-- 
2.50.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v4 6/6] mmc: sdhci-cadence: implement multi-block read gap tuning
  2025-08-18 14:02 [PATCH v4 0/6] mmc: introduce multi-block read gap tuning Benoît Monin
                   ` (4 preceding siblings ...)
  2025-08-18 14:02 ` [PATCH v4 5/6] mmc: core: add mmc_read_tuning Benoît Monin
@ 2025-08-18 14:02 ` Benoît Monin
  2025-08-18 14:56 ` [PATCH v4 0/6] mmc: introduce " Ulf Hansson
  6 siblings, 0 replies; 8+ messages in thread
From: Benoît Monin @ 2025-08-18 14:02 UTC (permalink / raw)
  To: Ulf Hansson, Adrian Hunter
  Cc: linux-mmc, linux-kernel, Vladimir Kondratiev, Tawfik Bayouk,
	Gregory CLEMENT, Thomas Petazzoni, Benoît Monin

The controller suspends the clock between blocks when reading from the
MMC as part of its flow-control, called read block gap. At higher clock
speed and with IO delay between the controller and the MMC, this clock
pause can happen too late, during the read of the next block and
trigger a read error.

To prevent this, the delay can be programmed for each mode via the pair
of registers HRS37/38. This delay is obtained during tuning, by trying
a multi-block read and increasing the delay until the read succeeds.

For now, the tuning is only done in HS200, as the read error has only
been observed at that speed.

Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Benoît Monin <benoit.monin@bootlin.com>
---
 drivers/mmc/host/sdhci-cadence.c | 63 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 62 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c
index 2d823e158c59844dc7916db6a1d6e3d8b02ea5a0..a2a4a5b0ab964883cef8c5d7f6e0c961fe76bc13 100644
--- a/drivers/mmc/host/sdhci-cadence.c
+++ b/drivers/mmc/host/sdhci-cadence.c
@@ -36,6 +36,24 @@
 #define   SDHCI_CDNS_HRS06_MODE_MMC_HS400	0x5
 #define   SDHCI_CDNS_HRS06_MODE_MMC_HS400ES	0x6
 
+/* Read block gap */
+#define SDHCI_CDNS_HRS37		0x94	/* interface mode select */
+#define   SDHCI_CDNS_HRS37_MODE_DS		0x0
+#define   SDHCI_CDNS_HRS37_MODE_HS		0x1
+#define   SDHCI_CDNS_HRS37_MODE_UDS_SDR12	0x8
+#define   SDHCI_CDNS_HRS37_MODE_UDS_SDR25	0x9
+#define   SDHCI_CDNS_HRS37_MODE_UDS_SDR50	0xa
+#define   SDHCI_CDNS_HRS37_MODE_UDS_SDR104	0xb
+#define   SDHCI_CDNS_HRS37_MODE_UDS_DDR50	0xc
+#define   SDHCI_CDNS_HRS37_MODE_MMC_LEGACY	0x20
+#define   SDHCI_CDNS_HRS37_MODE_MMC_SDR		0x21
+#define   SDHCI_CDNS_HRS37_MODE_MMC_DDR		0x22
+#define   SDHCI_CDNS_HRS37_MODE_MMC_HS200	0x23
+#define   SDHCI_CDNS_HRS37_MODE_MMC_HS400	0x24
+#define   SDHCI_CDNS_HRS37_MODE_MMC_HS400ES	0x25
+#define SDHCI_CDNS_HRS38		0x98	/* Read block gap coefficient */
+#define   SDHCI_CDNS_HRS38_BLKGAP_MAX		0xf
+
 /* SRS - Slot Register Set (SDHCI-compatible) */
 #define SDHCI_CDNS_SRS_BASE		0x200
 
@@ -251,6 +269,44 @@ static int sdhci_cdns_set_tune_val(struct sdhci_host *host, unsigned int val)
 	return 0;
 }
 
+/**
+ * sdhci_cdns_tune_blkgap() - tune multi-block read gap
+ * @mmc: MMC host
+ *
+ * Tune delay used in multi block read. To do so,
+ * try sending multi-block read command with incremented gap, unless
+ * it succeeds.
+ *
+ * Return: error code
+ */
+static int sdhci_cdns_tune_blkgap(struct mmc_host *mmc)
+{
+	struct sdhci_host *host = mmc_priv(mmc);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_cdns_priv *priv = sdhci_pltfm_priv(pltfm_host);
+	void __iomem *hrs37_reg = priv->hrs_addr + SDHCI_CDNS_HRS37;
+	void __iomem *hrs38_reg = priv->hrs_addr + SDHCI_CDNS_HRS38;
+	int ret;
+	u32 gap;
+	u32 hrs37_mode;
+
+	/* Currently only needed in HS200 mode */
+	if (host->timing != MMC_TIMING_MMC_HS200)
+		return 0;
+
+	writel(hrs37_mode, hrs37_reg);
+
+	for (gap = 0; gap <= SDHCI_CDNS_HRS38_BLKGAP_MAX; gap++) {
+		writel(gap, hrs38_reg);
+		ret = mmc_read_tuning(mmc, 512, 32);
+		if (!ret)
+			break;
+	}
+
+	dev_dbg(mmc_dev(mmc), "read block gap tune %s, gap %d\n", ret ? "failed" : "OK", gap);
+	return ret;
+}
+
 /*
  * In SD mode, software must not use the hardware tuning and instead perform
  * an almost identical procedure to eMMC.
@@ -261,6 +317,7 @@ static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
 	int max_streak = 0;
 	int end_of_streak = 0;
 	int i;
+	int ret;
 
 	/*
 	 * Do not execute tuning for UHS_SDR50 or UHS_DDR50.
@@ -288,7 +345,11 @@ static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
 		return -EIO;
 	}
 
-	return sdhci_cdns_set_tune_val(host, end_of_streak - max_streak / 2);
+	ret = sdhci_cdns_set_tune_val(host, end_of_streak - max_streak / 2);
+	if (ret)
+		return ret;
+
+	return sdhci_cdns_tune_blkgap(host->mmc);
 }
 
 static void sdhci_cdns_set_uhs_signaling(struct sdhci_host *host,

-- 
2.50.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v4 0/6] mmc: introduce multi-block read gap tuning
  2025-08-18 14:02 [PATCH v4 0/6] mmc: introduce multi-block read gap tuning Benoît Monin
                   ` (5 preceding siblings ...)
  2025-08-18 14:02 ` [PATCH v4 6/6] mmc: sdhci-cadence: implement multi-block read gap tuning Benoît Monin
@ 2025-08-18 14:56 ` Ulf Hansson
  6 siblings, 0 replies; 8+ messages in thread
From: Ulf Hansson @ 2025-08-18 14:56 UTC (permalink / raw)
  To: Benoît Monin
  Cc: Adrian Hunter, linux-mmc, linux-kernel, Vladimir Kondratiev,
	Tawfik Bayouk, Gregory CLEMENT, Thomas Petazzoni

On Mon, 18 Aug 2025 at 16:03, Benoît Monin <benoit.monin@bootlin.com> wrote:
>
> This patchset implements the multi-block read gap tuning for the SDHCI
> cadence driver.
>
> The first two patches introduce helpers to check for CMD23 support by
> MMC card: mmc_card_can_cmd23 for support proper and mmc_card_blk_no_cmd23
> for the NO_CMD23 quirk.
>
> The next two patches use the new helpers in mmc/core/mmc_test.c and
> mmc/core/block.c.
>
> The next patch add mmc_read_tuning to read blocks from MMC as part of
> the tuning. This function does not return the data read to the caller,
> only the status of the read operation.
>
> Finally the last patch uses mmc_read_tuning to implement the multi-block
> read gap tuning in the cadence host driver, by doing a multi-block read
> and increasing the gap delay until the read succeeds.
>
> In the previous version of this series, mmc_read_tuning had a struct
> mmc_card parameter and was making use of the helpers. This parameter has
> been dropped so the last two patches are now independent of the rest of
> the patchset.
>
> Signed-off-by: Benoît Monin <benoit.monin@bootlin.com>

Applied for next, thanks!

Kind regards
Uffe

> ---
> Changes in v4:
> - Dropped the card parameter of mmc_read_tuning.
> - Updated the last patch following the review of Adrian.
> - Link to v3: https://lore.kernel.org/r/20250716-mobileye-emmc-for-upstream-4-v3-0-dc979d8edef0@bootlin.com
>
> Changes in v3:
> - Move the changes related to CMD23 support by MMC card to separate
>   patches at the beginning of the series.
> - Change the mmc read function to be less appealing to reuse/abuse
>   outside of tuning context.
> - Link to v2: https://lore.kernel.org/linux-mmc/cover.1751898225.git.benoit.monin@bootlin.com/
>
> Changes in v2:
> - Split the code between the core and the driver by adding a generic
>   function to read blocks from the MMC.
> - Link to v1: https://lore.kernel.org/linux-mmc/2a43386ffef4012530ca2421ad81ad21c36c8a25.1750943549.git.benoit.monin@bootlin.com/
>
> ---
> Benoît Monin (6):
>       mmc: core: add mmc_card_can_cmd23
>       mmc: card: add mmc_card_blk_no_cmd23
>       mmc: mmc_test: use mmc_card cmd23 helpers
>       mmc: block: use mmc_card cmd23 helpers
>       mmc: core: add mmc_read_tuning
>       mmc: sdhci-cadence: implement multi-block read gap tuning
>
>  drivers/mmc/core/block.c         | 12 ++-----
>  drivers/mmc/core/card.h          |  9 +++--
>  drivers/mmc/core/core.c          |  9 +++++
>  drivers/mmc/core/core.h          |  1 +
>  drivers/mmc/core/mmc_ops.c       | 72 ++++++++++++++++++++++++++++++++++++++++
>  drivers/mmc/core/mmc_test.c      | 10 ++----
>  drivers/mmc/host/sdhci-cadence.c | 63 ++++++++++++++++++++++++++++++++++-
>  include/linux/mmc/host.h         |  1 +
>  8 files changed, 157 insertions(+), 20 deletions(-)
> ---
> base-commit: 8936497143de1da7958178d57db6011eceeb14a8
> change-id: 20250716-mobileye-emmc-for-upstream-4-40ef552c3b59
>
> Best regards,
> --
> Benoît Monin, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com
>

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2025-08-18 14:57 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-18 14:02 [PATCH v4 0/6] mmc: introduce multi-block read gap tuning Benoît Monin
2025-08-18 14:02 ` [PATCH v4 1/6] mmc: core: add mmc_card_can_cmd23 Benoît Monin
2025-08-18 14:02 ` [PATCH v4 2/6] mmc: card: add mmc_card_blk_no_cmd23 Benoît Monin
2025-08-18 14:02 ` [PATCH v4 3/6] mmc: mmc_test: use mmc_card cmd23 helpers Benoît Monin
2025-08-18 14:02 ` [PATCH v4 4/6] mmc: block: " Benoît Monin
2025-08-18 14:02 ` [PATCH v4 5/6] mmc: core: add mmc_read_tuning Benoît Monin
2025-08-18 14:02 ` [PATCH v4 6/6] mmc: sdhci-cadence: implement multi-block read gap tuning Benoît Monin
2025-08-18 14:56 ` [PATCH v4 0/6] mmc: introduce " Ulf Hansson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).