Hi Bin,
On 23/7/26 17:18, Bin Meng wrote:
SDHCI version 4 moves the SDMA system address from the legacy 32-bit
register at offset 0x00 to the address pair at offsets 0x58 and 0x5c.
At present QEMU always uses the legacy register, so guest SDHCI driver
with version 4 mode enabled uses an incorrect DMA address.
Select the address register from Host Version 4 Enable and honor 64-bit
Addressing when reading and advancing it. Keep the existing offset 0x00
behavior when version 4 mode is disabled.
Signed-off-by: Bin Meng <[email protected]>
---
hw/sd/sdhci-internal.h | 1 +
hw/sd/sdhci.c | 63 ++++++++++++++++++++++++++++++++++--------
2 files changed, 53 insertions(+), 11 deletions(-)
I'm splitting this patch in 3 to ease reviewing:
-- >8 --
commit 39ca75d42c0926d1b48e377bc3d32d439689936c
Author: Bin Meng <[email protected]>
Date: Sat Aug 15 16:35:46 2026 +0200
hw/sd: sdhci: Factor sdhci_advance_sdma_address() helper out
Signed-off-by: Bin Meng <[email protected]>
Message-ID: <[email protected]>
[PMD: Split of bigger patch]
Signed-off-by: Philippe Mathieu-Daudé <[email protected]>
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index 586e4680bee..ad370407c6e 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -600,2 +600,7 @@ static void sdhci_write_dataport(SDHCIState *s,
uint32_t value, unsigned size)
+static void sdhci_advance_sdma_address(SDHCIState *s, uint32_t bytes)
+{
+ s->sdmasysad += bytes;
+}
+
/* Multi block SDMA transfer */
@@ -643,3 +648,3 @@ static void
sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
s->data_count - begin,
MEMTXATTRS_UNSPECIFIED);
- s->sdmasysad += s->data_count - begin;
+ sdhci_advance_sdma_address(s, s->data_count - begin);
if (s->data_count == block_size) {
@@ -664,3 +669,3 @@ static void
sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
s->data_count - begin,
MEMTXATTRS_UNSPECIFIED);
- s->sdmasysad += s->data_count - begin;
+ sdhci_advance_sdma_address(s, s->data_count - begin);
if (s->data_count == block_size) {
---
-- >8 --
commit a9ba0290e8c299c6e32c623755219fcd95f3d237
Author: Bin Meng <[email protected]>
Date: Sat Aug 15 16:36:00 2026 +0200
hw/sd: sdhci: Factor sdhci_sdma_address() helper out
Signed-off-by: Bin Meng <[email protected]>
Message-ID: <[email protected]>
[PMD: Split of bigger patch]
Signed-off-by: Philippe Mathieu-Daudé <[email protected]>
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index ad370407c6e..93e1687dbe5 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -600,2 +600,7 @@ static void sdhci_write_dataport(SDHCIState *s,
uint32_t value, unsigned size)
+static uint64_t sdhci_sdma_address(SDHCIState *s)
+{
+ return s->sdmasysad;
+}
+
static void sdhci_advance_sdma_address(SDHCIState *s, uint32_t bytes)
@@ -612,3 +617,4 @@ static void
sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
uint32_t boundary_chk = 1 << (((s->blksize & ~BLOCK_SIZE_MASK) >>
12) + 12);
- uint32_t boundary_count = boundary_chk - (s->sdmasysad % boundary_chk);
+ uint64_t sdma_address = sdhci_sdma_address(s);
+ uint32_t boundary_count = boundary_chk - (sdma_address % boundary_chk);
@@ -624,3 +630,3 @@ static void
sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
*/
- if ((s->sdmasysad % boundary_chk) == 0) {
+ if ((sdma_address % boundary_chk) == 0) {
page_aligned = true;
@@ -646,3 +652,4 @@ static void
sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
}
- dma_memory_write(s->dma_as, s->sdmasysad,
&s->fifo_buffer[begin],
+ dma_memory_write(s->dma_as, sdhci_sdma_address(s),
+ &s->fifo_buffer[begin],
s->data_count - begin,
MEMTXATTRS_UNSPECIFIED);
@@ -667,3 +674,4 @@ static void
sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
}
- dma_memory_read(s->dma_as, s->sdmasysad,
&s->fifo_buffer[begin],
+ dma_memory_read(s->dma_as, sdhci_sdma_address(s),
+ &s->fifo_buffer[begin],
s->data_count - begin,
MEMTXATTRS_UNSPECIFIED);
@@ -702,6 +710,8 @@ static void
sdhci_sdma_transfer_single_block(SDHCIState *s)
sdbus_read_data(&s->sdbus, s->fifo_buffer, datacnt);
- dma_memory_write(s->dma_as, s->sdmasysad, s->fifo_buffer, datacnt,
+ dma_memory_write(s->dma_as, sdhci_sdma_address(s),
+ s->fifo_buffer, datacnt,
MEMTXATTRS_UNSPECIFIED);
} else {
- dma_memory_read(s->dma_as, s->sdmasysad, s->fifo_buffer, datacnt,
+ dma_memory_read(s->dma_as, sdhci_sdma_address(s),
+ s->fifo_buffer, datacnt,
MEMTXATTRS_UNSPECIFIED);
---
This patch becoming simpler:
-- >8 --
diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h
index 4aeed120bf1..2116995dcca 100644
--- a/hw/sd/sdhci-internal.h
+++ b/hw/sd/sdhci-internal.h
@@ -203,2 +203,3 @@ FIELD(SDHC_HOSTCTL2, CMD23_ENA, 11, 1); /*
since v4 */
FIELD(SDHC_HOSTCTL2, VERSION4, 12, 1); /* since v4 */
+FIELD(SDHC_HOSTCTL2, ADDRESSING_64, 13, 1); /* since v4 */
FIELD(SDHC_HOSTCTL2, ASYNC_INT, 14, 1);
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index 93e1687dbe5..3fba3970d4f 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -600,5 +600,20 @@ static void sdhci_write_dataport(SDHCIState *s,
uint32_t value, unsigned size)
+static bool sdhci_version4_enabled(SDHCIState *s)
+{
+ return FIELD_EX32(s->hostctl2, SDHC_HOSTCTL2, VERSION4);
+}
+
+static bool sdhci_64bit_addressing_enabled(SDHCIState *s)
+{
+ return FIELD_EX32(s->hostctl2, SDHC_HOSTCTL2, ADDRESSING_64);
+}
+
static uint64_t sdhci_sdma_address(SDHCIState *s)
{
+ if (!sdhci_version4_enabled(s)) {
return s->sdmasysad;
+ }
+
+ return sdhci_64bit_addressing_enabled(s) ?
+ s->admasysaddr : (uint32_t)s->admasysaddr;
}
@@ -607,3 +622,13 @@ static void sdhci_advance_sdma_address(SDHCIState
*s, uint32_t bytes)
{
+ if (!sdhci_version4_enabled(s)) {
s->sdmasysad += bytes;
+ } else if (sdhci_64bit_addressing_enabled(s)) {
+ s->admasysaddr += bytes;
+ } else {
+ uint32_t address = s->admasysaddr;
+
+ address += bytes;
+ s->admasysaddr = (s->admasysaddr & 0xffffffff00000000ULL) |
+ address;
+ }
}
@@ -1382,6 +1407,7 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t
val, unsigned size)
/*
- * VERSION4 is writable even without UHS-I. Preserve all other
- * Host Control 2 bits when UHS-I is not supported.
+ * Version 4 fields are writable even without UHS-I.
Preserve all
+ * other Host Control 2 bits when UHS-I is not supported.
*/
- uint16_t independent = R_SDHC_HOSTCTL2_VERSION4_MASK;
+ uint16_t independent = R_SDHC_HOSTCTL2_VERSION4_MASK |
+ R_SDHC_HOSTCTL2_ADDRESSING_64_MASK;
---
Reviewed-by: Philippe Mathieu-Daudé <[email protected]>