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 <pmazzini@gmail.com>
---
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