[PATCH] hw/sd/sdhci: model the i.MX uSDHC clock, reset values and DMA boundary
Pablo Mazzini <[email protected]> Mon, 3 Aug 2026 09:26:53 -0700
| Newsgroups | org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
The i.MX uSDHC differs from the Freescale eSDHC that this file already models in three ways that a vendor U-Boot depends on. Clock enables. The classic eSDHC keeps them in SYSCTL. The uSDHC moved them to VENDOR_SPEC bits 11-14. Teach SDHC_CLOCK_IS_ON() about the VENDOR_SPEC enable. Interrupt status enables. Unlike the SD Host Controller standard, the eSDHC does not reset these to zero, which commit d060b2789f7 already models for fsl-esdhc-be/le. The uSDHC behaves the same way. SDMA buffer boundary. The uSDHC's internal DMA has none; it transfers the whole programmed block count and reports only Transfer Complete. Signed-off-by: Pablo Mazzini <[email protected]> --- hw/sd/sdhci-internal.h | 7 +++++-- hw/sd/sdhci.c | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h index 4aeed120bf..60bed5af30 100644 --- a/hw/sd/sdhci-internal.h +++ b/hw/sd/sdhci-internal.h @@ -124,8 +124,11 @@ FIELD(SDHC_PWRCON, BUS_VOLTAGE, 1, 3); #define SDHC_CLOCK_INT_EN 0x0001 #define SDHC_CLOCK_SDCLK_EN (1 << 2) #define SDHC_CLOCK_CHK_MASK 0x0007 -#define SDHC_CLOCK_IS_ON(x) \ - (((x) & SDHC_CLOCK_CHK_MASK) == SDHC_CLOCK_CHK_MASK) +/* The i.MX uSDHC keeps its clock enables in VENDOR_SPEC instead */ +#define ESDHC_CKEN (1 << 14) +#define SDHC_CLOCK_IS_ON(clkcon, vendor_spec) \ + ((((clkcon) & SDHC_CLOCK_CHK_MASK) == SDHC_CLOCK_CHK_MASK) \ + || ((vendor_spec) & ESDHC_CKEN)) /* R/W Timeout Control Register 0x0 */ #define SDHC_TIMEOUTCON 0x2E diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index e58a610397..f64159c38b 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -308,7 +308,8 @@ static void sdhci_reset(SDHCIState *s) s->stopped_state = sdhc_not_stopped; s->pending_insert_state = false; if (object_dynamic_cast(OBJECT(s), TYPE_FSL_ESDHC_BE) || - object_dynamic_cast(OBJECT(s), TYPE_FSL_ESDHC_LE)) { + object_dynamic_cast(OBJECT(s), TYPE_FSL_ESDHC_LE) || + object_dynamic_cast(OBJECT(s), TYPE_IMX_USDHC)) { s->norintstsen = 0x013f; s->errintstsen = 0x117f; } @@ -619,6 +620,15 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) page_aligned = true; } + /* + * The i.MX uSDHC has no "Host SDMA Buffer Boundary": its internal DMA + * transfers the whole programmed block count and reports only Transfer + * Complete, so it never pauses at a boundary. + */ + if (object_dynamic_cast(OBJECT(s), TYPE_IMX_USDHC)) { + page_aligned = false; + } + s->prnsts |= SDHC_DATA_INHIBIT | SDHC_DAT_LINE_ACTIVE; if (s->trnmod & SDHC_TRNS_READ) { s->prnsts |= SDHC_DOING_READ; @@ -994,7 +1004,7 @@ static void sdhci_data_transfer(void *opaque) static bool sdhci_can_issue_command(SDHCIState *s) { - if (!SDHC_CLOCK_IS_ON(s->clkcon) || + if (!SDHC_CLOCK_IS_ON(s->clkcon, s->vendor_spec) || (((s->prnsts & SDHC_DATA_INHIBIT) || s->stopped_state) && ((s->cmdreg & SDHC_CMD_DATA_PRESENT) || ((s->cmdreg & SDHC_CMD_RESPONSE) == SDHC_CMD_RSP_WITH_BUSY && -- 2.53.0