[PATCH] hw/sd/sdhci: model the i.MX uSDHC clock, reset values and DMA boundary
Pablo Mazzini <[email protected]> Mon, 3 Aug 2026 09:53:56 -0700
| Newsgroups | gmane.comp.emulators.qemu.block,gmane.comp.emulators.qemu |
|---|---|
| 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 | 12 ++++++++---- 2 files changed, 13 insertions(+), 6 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..b354c0f31f 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; } @@ -613,9 +614,12 @@ 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 + * allow them to work properly. The i.MX uSDHC has no "Host SDMA Buffer + * Boundary" at all: its internal DMA transfers the whole programmed + * block count and reports only Transfer Complete. */ - if ((s->sdmasysad % boundary_chk) == 0) { + if ((s->sdmasysad % boundary_chk) == 0 && + !object_dynamic_cast(OBJECT(s), TYPE_IMX_USDHC)) { page_aligned = true; } @@ -994,7 +998,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