sdhci: clear BWR before refilling the PIO write buffer

pull/948/head
David Garske 2026-10-14 15:04:02 -07:00 committed by Daniele Lacamera
parent 43655708c3
commit 08f20f8364
2 changed files with 22 additions and 2 deletions

View File

@ -1713,6 +1713,10 @@ static int sdhci_transfer(int dir, uint32_t cmd_index, uint32_t block_addr,
if (reg & buf_ready_flag) {
uint32_t i, xfer_sz = (sz > SDHCI_BLOCK_SIZE) ?
SDHCI_BLOCK_SIZE : sz;
/* BWR is W1C: ack before refill or lose the next assertion. */
if (dir == SDHCI_DIR_WRITE) {
SDHCI_REG_SET(SDHCI_SRS12, SDHCI_SRS12_BWR);
}
for (i = 0; i < xfer_sz; i += 4) {
if (dir == SDHCI_DIR_READ) {
#ifdef SDHCI_PIO_WRITE_NONCACHED_ALIAS
@ -1759,8 +1763,7 @@ static int sdhci_transfer(int dir, uint32_t cmd_index, uint32_t block_addr,
* (the CM4 microSD path, which drives the same EMMC2 block).
* For multi-block READ: clear BRR by writing 1 to it (W1C),
* then the outer loop waits for BRR to be set again when the
* next block's data is available.
* For WRITE: BWR auto-clears when buffer full, don't touch. */
* next block's data is available. */
if (sz > 0 && dir == SDHCI_DIR_READ) {
SDHCI_REG_SET(SDHCI_SRS12, SDHCI_SRS12_BRR);
}

View File

@ -77,8 +77,25 @@ void sdhci_reg_write(uint32_t offset, uint32_t val)
if (offset == SDHCI_SRS08 && xfer.active && !xfer.is_read) {
uint32_t pos = xfer.block_addr * SDHCI_BLOCK_SIZE + (xfer.word_index * 4);
/* Beginning a block while BWR is still asserted means the driver
* refilled without acknowledging it. Real hardware overruns and
* stalls there; fail the transfer so the test reports it. */
if ((xfer.word_index % xfer.word_count) == 0 &&
(mock_regs[SDHCI_SRS12 / sizeof(uint32_t)] & SDHCI_SRS12_BWR)) {
mock_regs[SDHCI_SRS12 / sizeof(uint32_t)] |= SDHCI_SRS12_EINT;
}
memcpy(&mock_disk[pos], &val, sizeof(val));
xfer.word_index++;
/* BWR is raised once per block, not latched for the whole transfer:
* re-assert it when the block just taken has drained and another is
* still expected. */
if ((xfer.word_index % xfer.word_count) == 0) {
uint32_t blocks = mock_regs[SDHCI_SRS01 / sizeof(uint32_t)] >>
SDHCI_SRS01_BCCT_SHIFT;
if ((xfer.word_index / xfer.word_count) < blocks) {
mock_regs[SDHCI_SRS12 / sizeof(uint32_t)] |= SDHCI_SRS12_BWR;
}
}
return;
}