The Cadence Linux driver enables version 4 mode and 64-bit addressing in
Host Control 2 but retains the ADMA2 encoding in Host Control 1. QEMU
treats the transfer as 32-bit ADMA and uses 12-byte descriptors because
it only decodes Host Control 1.

Resolve the DMA type from both control registers and use 16-byte version
4 descriptors. Preserve the legacy 12-byte ADMA2 64-bit format when
version 4 mode is disabled.

Signed-off-by: Bin Meng <[email protected]>
---

 hw/sd/sdhci.c | 25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index d2132035eb..00a4b9b0e4 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -227,6 +227,23 @@ static bool sdhci_update_irq(SDHCIState *s)
     return pending;
 }
 
+static uint8_t sdhci_get_dma_type(SDHCIState *s)
+{
+    uint8_t type = SDHC_DMA_TYPE(s->hostctl1);
+
+    /*
+     * In version 4 mode, the legacy ADMA2_32 encoding selects ADMA2,
+     * while ADDRESSING_64 determines its address width.
+     */
+    if (type == SDHC_CTRL_ADMA2_32 &&
+        FIELD_EX32(s->hostctl2, SDHC_HOSTCTL2, VERSION4) &&
+        FIELD_EX32(s->hostctl2, SDHC_HOSTCTL2, ADDRESSING_64)) {
+        return SDHC_CTRL_ADMA2_64;
+    }
+
+    return type;
+}
+
 static void sdhci_raise_insertion_irq(void *opaque)
 {
     SDHCIState *s = (SDHCIState *)opaque;
@@ -781,7 +798,7 @@ static void get_adma_description(SDHCIState *s, ADMADescr 
*dscr)
     uint32_t adma1 = 0;
     uint64_t adma2 = 0;
     hwaddr entry_addr = (hwaddr)s->admasysaddr;
-    switch (SDHC_DMA_TYPE(s->hostctl1)) {
+    switch (sdhci_get_dma_type(s)) {
     case SDHC_CTRL_ADMA2_32:
         dma_memory_read(s->dma_as, entry_addr, &adma2, sizeof(adma2),
                         MEMTXATTRS_UNSPECIFIED);
@@ -818,7 +835,9 @@ static void get_adma_description(SDHCIState *s, ADMADescr 
*dscr)
                         MEMTXATTRS_UNSPECIFIED);
         dscr->addr = le64_to_cpu(dscr->addr);
         dscr->attr &= (uint8_t) ~0xC0;
-        dscr->incr = 12;
+        /* Version 4 pads 64-bit ADMA2 descriptors from 96 to 128 bits */
+        dscr->incr = FIELD_EX32(s->hostctl2, SDHC_HOSTCTL2, VERSION4) ?
+                     16 : 12;
         break;
     }
 }
@@ -998,7 +1017,7 @@ static void sdhci_data_transfer(void *opaque)
     SDHCIState *s = (SDHCIState *)opaque;
 
     if (s->trnmod & SDHC_TRNS_DMA) {
-        switch (SDHC_DMA_TYPE(s->hostctl1)) {
+        switch (sdhci_get_dma_type(s)) {
         case SDHC_CTRL_SDMA:
             sdhci_sdma_transfer(s);
             break;
-- 
2.34.1


Reply via email to