All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kyle Fox <kylefoxaustin.github@gmail.com>
To: qemu-devel@nongnu.org
Cc: "Kyle Fox" <kylefoxaustin.github@gmail.com>,
	"Philippe Mathieu-Daudé" <philmd@mailo.com>,
	"Bin Meng" <bmeng.cn@gmail.com>,
	qemu-block@nongnu.org (open list:SD (Secure Card))
Subject: [PATCH 01/16] hw/sd/sdhci: add i.MX uSDHC SDCLK_AUTO_GATE and NO_SDMA_BOUNDARY quirks
Date: Wed, 19 Aug 2026 21:48:19 -0500	[thread overview]
Message-ID: <20260820024834.3286721-2-kylefoxaustin.github@gmail.com> (raw)
In-Reply-To: <20260820024834.3286721-1-kylefoxaustin.github@gmail.com>

The i.MX uSDHC issues commands with SDCLK auto-gated (its driver never
sets SDCLK_EN), and its SDMA does not honour the 512 KiB ADMA buffer
boundary the generic core assumes. Add two opt-in quirk bits for this:

  - SDCLK_AUTO_GATE: treat the clock as running once the internal clock
    is enabled and stable, instead of also requiring SDCLK_EN.
  - NO_SDMA_BOUNDARY: skip the buffer-boundary break in multi-block SDMA.

Both default off and are a no-op when the bit is clear, so no existing
user of the SDHCI models changes behaviour; a machine opts in by setting
the bits on its own uSDHC instances (the i.MX 95 SoC does so).

Signed-off-by: Kyle Fox <kylefoxaustin.github@gmail.com>
---
 hw/sd/sdhci.c         | 67 +++++++++++++++++++++++++++++++++++++++----
 include/hw/sd/sdhci.h | 21 ++++++++++++++
 2 files changed, 82 insertions(+), 6 deletions(-)

diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index e58a6103970..327e9a7cb74 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -611,12 +611,27 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
     }
 
     /*
-     * XXX: Some sd/mmc drivers (for example, u-boot-slp) do not account for
-     * possible stop at page boundary if initial address is not page aligned,
-     * allow them to work properly
+     * The i.MX/FSL uSDHC silicon does not implement the SDHCI "Host SDMA
+     * Buffer Boundary" mechanism; it transfers all blocks back-to-back
+     * regardless of buffer-boundary address alignment. The blksize-quirk
+     * in esdhc_write() forces bits 14:12 to 0b111 (= 512 KiB) so Linux's
+     * "zero this field out" pattern doesn't trip a 4 KiB boundary break,
+     * but the real hardware never pauses for the boundary at all, so
+     * neither should we. Skipping the page-aligned path makes the SDMA
+     * transfer run to completion (blkcnt -> 0) and fire transfer-complete,
+     * which is what the FSL U-Boot SPL driver expects (it doesn't ack
+     * SDMA-boundary IRQs by re-writing SYSAD). Controllers with this
+     * behaviour set SDHCI_QUIRK_NO_SDMA_BOUNDARY.
      */
-    if ((s->sdmasysad % boundary_chk) == 0) {
-        page_aligned = true;
+    if (!(s->quirks & SDHCI_QUIRK_NO_SDMA_BOUNDARY)) {
+        /*
+         * XXX: Some sd/mmc drivers (for example, u-boot-slp) do not
+         * account for possible stop at page boundary if initial address
+         * is not page aligned, allow them to work properly
+         */
+        if ((s->sdmasysad % boundary_chk) == 0) {
+            page_aligned = true;
+        }
     }
 
     s->prnsts |= SDHC_DATA_INHIBIT | SDHC_DAT_LINE_ACTIVE;
@@ -992,9 +1007,26 @@ static void sdhci_data_transfer(void *opaque)
     }
 }
 
+static bool sdhci_clock_is_on(SDHCIState *s)
+{
+    /*
+     * The i.MX (u)SDHC has no software SD-clock-enable bit (the card clock
+     * is auto-gated by hardware), so its driver never sets
+     * SDHC_CLOCK_SDCLK_EN. For such a controller, treat the clock as
+     * running once the internal clock is enabled and stable; otherwise
+     * every command would be silently dropped (no completion/timeout IRQ),
+     * stalling the guest on 10s host-side timeouts.
+     */
+    if (s->quirks & SDHCI_QUIRK_SDCLK_AUTO_GATE) {
+        return (s->clkcon & (SDHC_CLOCK_INT_EN | SDHC_CLOCK_INT_STABLE)) ==
+               (SDHC_CLOCK_INT_EN | SDHC_CLOCK_INT_STABLE);
+    }
+    return SDHC_CLOCK_IS_ON(s->clkcon);
+}
+
 static bool sdhci_can_issue_command(SDHCIState *s)
 {
-    if (!SDHC_CLOCK_IS_ON(s->clkcon) ||
+    if (!sdhci_clock_is_on(s) ||
         (((s->prnsts & SDHC_DATA_INHIBIT) || s->stopped_state) &&
         ((s->cmdreg & SDHC_CMD_DATA_PRESENT) ||
         ((s->cmdreg & SDHC_CMD_RESPONSE) == SDHC_CMD_RSP_WITH_BUSY &&
@@ -1613,6 +1645,9 @@ static void sdhci_bus_class_init(ObjectClass *klass, const void *data)
 
 #define ESDHC_VENDOR_SPEC               0xc0
 #define ESDHC_FRC_SDCLK_ON              (1 << 8)
+#define ESDHC_VENDORSPEC_IPGEN          (1 << 11)
+#define ESDHC_VENDORSPEC_HCKEN          (1 << 12)
+#define ESDHC_VENDORSPEC_CKEN           (1 << 14)
 
 #define ESDHC_DLL_CTRL                  0x60
 
@@ -1707,6 +1742,26 @@ esdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
         } else {
             s->prnsts |= ESDHC_PRNSTS_CLOCK_GATE_OFF;
         }
+        /*
+         * An SDCLK_AUTO_GATE i.MX uSDHC drives the SD clock through
+         * VENDORSPEC, not through the SDHCI CLKCON. For those instances
+         * mirror the VENDORSPEC clock-enable bits into clkcon so the
+         * standard SDHCI paths (PRNSTS.SDSTB derived from CLOCK_INT_STABLE;
+         * sdhci_can_issue_command gating on CLOCK_IS_ON) see the clock as
+         * enabled; otherwise the U-Boot fsl_esdhc_imx driver waits forever
+         * for SDSTB. Consumers without the quirk keep the upstream behaviour
+         * (a VENDORSPEC write touches only vendor_spec/prnsts).
+         */
+        if (s->quirks & SDHCI_QUIRK_SDCLK_AUTO_GATE) {
+            if (value & (ESDHC_VENDORSPEC_HCKEN | ESDHC_VENDORSPEC_IPGEN)) {
+                s->clkcon |= SDHC_CLOCK_INT_EN | SDHC_CLOCK_INT_STABLE;
+            }
+            if (value & ESDHC_VENDORSPEC_CKEN) {
+                s->clkcon |= SDHC_CLOCK_SDCLK_EN;
+            } else {
+                s->clkcon &= ~SDHC_CLOCK_SDCLK_EN;
+            }
+        }
         break;
 
     case SDHC_HOSTCTL:
diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h
index a9da6203fcb..e6940b62562 100644
--- a/include/hw/sd/sdhci.h
+++ b/include/hw/sd/sdhci.h
@@ -115,6 +115,27 @@ typedef struct SDHCIState SDHCIState;
  */
 #define SDHCI_QUIRK_NO_BUSY_IRQ    BIT(14)
 
+/*
+ * The i.MX (u)SDHC gates the SD card clock automatically and has no
+ * software-visible "SD Clock Enable" bit: its driver programs only the
+ * divider and the internal-clock enable, never SDHC_CLOCK_SDCLK_EN. With
+ * this quirk the controller is considered ready to issue commands once the
+ * internal clock is enabled and stable, instead of also requiring
+ * SDHC_CLOCK_SDCLK_EN (which such a driver never sets). QEMU-internal bit,
+ * taken from the top of the word to avoid the Linux quirk numbering.
+ */
+#define SDHCI_QUIRK_SDCLK_AUTO_GATE    BIT(31)
+
+/*
+ * The i.MX uSDHC silicon does not implement the SDHCI "Host SDMA Buffer
+ * Boundary" mechanism; it streams all blocks back-to-back regardless of the
+ * buffer-boundary alignment, never pausing at the boundary. With this quirk
+ * the SDMA engine skips the page-aligned boundary-break path so the transfer
+ * runs to completion. QEMU-internal bit, taken from the top of the word to
+ * avoid the Linux quirk numbering.
+ */
+#define SDHCI_QUIRK_NO_SDMA_BOUNDARY    BIT(30)
+
 #define TYPE_PCI_SDHCI "sdhci-pci"
 DECLARE_INSTANCE_CHECKER(SDHCIState, PCI_SDHCI,
                          TYPE_PCI_SDHCI)
-- 
2.34.1



  reply	other threads:[~2026-08-20  2:49 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-20  2:48 [PATCH 00/16] hw/arm: add the NXP i.MX 95 EVK machine Kyle Fox
2026-08-20  2:48 ` Kyle Fox [this message]
2026-08-20  2:48 ` [PATCH 02/16] hw/arm/boot: let a board preset initrd_start Kyle Fox
2026-08-20  2:48 ` [PATCH 03/16] target/arm: opt-in align-down for a misaligned PMSAv7 MPU RBAR Kyle Fox
2026-08-20  2:48 ` [PATCH 04/16] hw/arm/armv7m: forward pmsav7-rbar-align-down to the CPU Kyle Fox
2026-08-20  2:48 ` [PATCH 05/16] hw/char: add i.MX LPUART Kyle Fox
2026-08-20  2:48 ` [PATCH 06/16] hw/i2c: add i.MX LPI2C Kyle Fox
2026-08-20  2:48 ` [PATCH 07/16] hw/misc: add i.MX Messaging Unit (MU v2) Kyle Fox
2026-08-20  2:48 ` [PATCH 08/16] hw/misc: add NXP EdgeLock Enclave (ELE) responder Kyle Fox
2026-08-20  2:48 ` [PATCH 09/16] hw/timer: add i.MX 95 system counter Kyle Fox
2026-08-20  2:48 ` [PATCH 10/16] hw/misc: add i.MX 95 watchdog Kyle Fox
2026-08-20  2:48 ` [PATCH 11/16] hw/misc: add i.MX 95 ANATOP/AONMIX/GPC/SRC power and clock blocks Kyle Fox
2026-08-20  2:48 ` [PATCH 12/16] hw/misc: add i.MX 95 PMIC (PF09/PF53/PCAL6408A) and xcache controllers Kyle Fox
2026-08-20  2:48 ` [PATCH 13/16] hw/misc: add i.MX 95 DPU command-sequencer stub (headless) Kyle Fox
2026-08-20  2:48 ` [PATCH 14/16] hw/arm: add i.MX 95 SoC container (fsl-imx95) Kyle Fox
2026-08-20  2:48 ` [PATCH 15/16] hw/arm: add i.MX 95 19x19 EVK board Kyle Fox
2026-08-20  2:48 ` [PATCH 16/16] docs, MAINTAINERS, tests/functional: add i.MX 95 EVK Kyle Fox

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260820024834.3286721-2-kylefoxaustin.github@gmail.com \
    --to=kylefoxaustin.github@gmail.com \
    --cc=bmeng.cn@gmail.com \
    --cc=philmd@mailo.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.