On Sat, Sep 19, 2026 at 10:32 PM Bernhard Beschow <[email protected]> wrote: > > > > Am 4. September 2026 16:14:31 UTC schrieb Bin Meng > <[email protected]>: > >The standard SDHCI Block Size register encodes an SDMA buffer boundary > >in bits 14:12. The generic model stops at each selected boundary, sets > >the DMA status, and waits for software to rewrite the SDMA system > >address before continuing. > > > >Freescale eSDHC and i.MX uSDHC instead expose BLKATTR without a > >programmable standard boundary field. On both controller families, > >bits 14:13 are reserved and bit 12 is the high bit of the 13-bit > >block-size field. Linux masks the standard boundary encoding before > >writing BLKATTR. > > > >Despite its name, esdhc_write() is the shared register translation > >helper. usdhc_write() delegates common register accesses to it. The > >existing translation inserts 0x7 into the generic boundary field so > >the common core sees a 512 KiB boundary. > > > >For i.MX6UL uSDHC, BLK_ATT bits 15:13 are reserved and bit 12 is > >part of its 13-bit block size. DINT reports successful completion of > >the whole internal DMA transfer, not an intermediate boundary pause. > > > >U-Boot programs one contiguous DMA address and a block count, then > >waits for both DINT and transfer-complete. It never rewrites the address > >at an intermediate boundary. Reads larger than 512 KiB therefore reach > >the synthetic boundary and stall with blocks remaining. > > > >The missing field alone does not establish whether every older eSDHC > >has a fixed internal boundary handshake. Limit the new quirk to only > >TYPE_IMX_USDHC, where the reference manual, U-Boot behavior, and the > >observed failure agree. Existing FSL eSDHC and standard SDHCI behavior > >remain unchanged. > > > >Reference: IMX6ULRM (Rev. 2), section 56.8.2 and 56.8.13 > >https://www.nxp.com/webapp/Download?colCode=IMX6ULRM > > > >Signed-off-by: Bin Meng <[email protected]> > >--- > > > >(no changes since v1) > > > > include/hw/sd/sdhci.h | 5 +++++ > > hw/sd/sdhci.c | 37 ++++++++++++++++++++++++------------- > > 2 files changed, 29 insertions(+), 13 deletions(-) > > > >diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h > >index 83d465774b..6664822398 100644 > >--- a/include/hw/sd/sdhci.h > >+++ b/include/hw/sd/sdhci.h > >@@ -118,6 +118,11 @@ typedef struct SDHCIState SDHCIState; > > * SDHCI clock-control fields > > */ > > #define SDHCI_QUIRK_CLOCKS_IN_VENDOR BIT(1) > >+/* > >+ * Controller completes contiguous SDMA transfers without the standard > >+ * intermediate buffer-boundary stop and address-update handshake > >+ */ > >+#define SDHCI_QUIRK_NO_SDMA_BOUNDARY BIT(2) > > > > #define TYPE_PCI_SDHCI "sdhci-pci" > > DECLARE_INSTANCE_CHECKER(SDHCIState, PCI_SDHCI, > >diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c > >index 4d7bbdbe7a..de0883497b 100644 > >--- a/hw/sd/sdhci.c > >+++ b/hw/sd/sdhci.c > >@@ -687,12 +687,14 @@ static void sdhci_advance_sdma_address(SDHCIState *s, > >uint32_t bytes) > > /* Multi block SDMA transfer */ > > static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) > > { > >+ bool boundary_enabled = > >+ !(s->quirks & SDHCI_QUIRK_NO_SDMA_BOUNDARY); > > bool page_aligned = false; > > unsigned int begin; > > const uint16_t block_size = s->blksize & BLOCK_SIZE_MASK; > >- uint32_t boundary_chk = 1 << (((s->blksize & ~BLOCK_SIZE_MASK) >> 12) + > >12); > >+ uint32_t boundary_chk = 0; > > uint64_t sdma_address = sdhci_sdma_address(s); > >- uint32_t boundary_count = boundary_chk - (sdma_address % boundary_chk); > >+ uint32_t boundary_count = 0; > > > > if (!(s->trnmod & SDHC_TRNS_BLK_CNT_EN) || !s->blkcnt) { > > qemu_log_mask(LOG_UNIMP, "infinite transfer is not supported\n"); > >@@ -704,8 +706,11 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState > >*s) > > * possible stop at page boundary if initial address is not page > > aligned, > > * allow them to work properly > > */ > >- if ((sdma_address % boundary_chk) == 0) { > >- page_aligned = true; > >+ if (boundary_enabled) { > >+ boundary_chk = > >+ 1 << (((s->blksize & ~BLOCK_SIZE_MASK) >> 12) + 12); > >+ boundary_count = boundary_chk - (sdma_address % boundary_chk); > >+ page_aligned = (sdma_address % boundary_chk) == 0; > > } > > > > s->prnsts |= SDHC_DATA_INHIBIT | SDHC_DAT_LINE_ACTIVE; > >@@ -721,7 +726,9 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState > >*s) > > boundary_count = 0; > > } else { > > s->data_count = block_size; > >- boundary_count -= block_size - begin; > >+ if (boundary_enabled) { > >+ boundary_count -= block_size - begin; > >+ } > > if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) { > > s->blkcnt--; > > } > >@@ -746,7 +753,9 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState > >*s) > > boundary_count = 0; > > } else { > > s->data_count = block_size; > >- boundary_count -= block_size - begin; > >+ if (boundary_enabled) { > >+ boundary_count -= block_size - begin; > >+ } > > } > > dma_memory_read(s->dma_as, sdhci_sdma_address(s), > > &s->fifo_buffer[begin], > >@@ -2015,13 +2024,14 @@ esdhc_write(void *opaque, hwaddr offset, uint64_t > >val, unsigned size) > > > > case SDHC_BLKSIZE: > > /* > >- * ESDHCI does not implement "Host SDMA Buffer Boundary", and > >- * Linux driver will try to zero this field out which will > >- * break the rest of SDHCI emulation. > >+ * Freescale eSDHC and i.MX uSDHC use BLKATTR without the standard > >+ * Host SDMA Buffer Boundary field. uSDHC accesses reach this shared > >+ * register translation through usdhc_write(). > > * > >- * Linux defaults to maximum possible setting (512K boundary) > >- * and it seems to be the only option that i.MX IP implements, > >- * so we artificially set it to that value. > >+ * Keep the largest boundary in the generic representation to > >+ * preserve existing eSDHC behavior. TYPE_IMX_USDHC separately > >+ * disables the associated stop semantics because its DINT reports > >+ * completion of the entire transfer rather than a boundary event. > > */ > > val |= 0x7 << 12; > > /* FALLTHROUGH */ > >@@ -2168,7 +2178,8 @@ static void imx_usdhc_init(Object *obj) > > > > s->io_ops = &usdhc_mmio_ops; > > s->quirks = SDHCI_QUIRK_NO_BUSY_IRQ | > >- SDHCI_QUIRK_CLOCKS_IN_VENDOR; > >+ SDHCI_QUIRK_CLOCKS_IN_VENDOR | > >+ SDHCI_QUIRK_NO_SDMA_BOUNDARY; > > Given the above comments please also add the quirk to both ESDHC variants. > Thanks!
Will extend the quirk to eSDHC variants in v3. > > With the above fixed: > > Reviewed-by: Bernhard Beschow <[email protected]> > Regards, Bin
