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 | 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