Skip to content

Commit 7a92f2b

Browse files
committed
sdhci: clear BWR before refilling the PIO write buffer
1 parent 9bdc6cb commit 7a92f2b

2 files changed

Lines changed: 22 additions & 2 deletions

File tree

‎src/sdhci.c‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1699,6 +1699,10 @@ static int sdhci_transfer(int dir, uint32_t cmd_index, uint32_t block_addr,
16991699
if (reg & buf_ready_flag) {
17001700
uint32_t i, xfer_sz = (sz > SDHCI_BLOCK_SIZE) ?
17011701
SDHCI_BLOCK_SIZE : sz;
1702+
/* BWR is W1C: ack before refill or lose the next assertion. */
1703+
if (dir == SDHCI_DIR_WRITE) {
1704+
SDHCI_REG_SET(SDHCI_SRS12, SDHCI_SRS12_BWR);
1705+
}
17021706
for (i = 0; i < xfer_sz; i += 4) {
17031707
if (dir == SDHCI_DIR_READ) {
17041708
#ifdef SDHCI_PIO_WRITE_NONCACHED_ALIAS
@@ -1745,8 +1749,7 @@ static int sdhci_transfer(int dir, uint32_t cmd_index, uint32_t block_addr,
17451749
* (the CM4 microSD path, which drives the same EMMC2 block).
17461750
* For multi-block READ: clear BRR by writing 1 to it (W1C),
17471751
* then the outer loop waits for BRR to be set again when the
1748-
* next block's data is available.
1749-
* For WRITE: BWR auto-clears when buffer full, don't touch. */
1752+
* next block's data is available. */
17501753
if (sz > 0 && dir == SDHCI_DIR_READ) {
17511754
SDHCI_REG_SET(SDHCI_SRS12, SDHCI_SRS12_BRR);
17521755
}

‎tools/unit-tests/unit-sdhci-disk-unaligned.c‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,25 @@ void sdhci_reg_write(uint32_t offset, uint32_t val)
7777
if (offset == SDHCI_SRS08 && xfer.active && !xfer.is_read) {
7878
uint32_t pos = xfer.block_addr * SDHCI_BLOCK_SIZE + (xfer.word_index * 4);
7979

80+
/* Beginning a block while BWR is still asserted means the driver
81+
* refilled without acknowledging it. Real hardware overruns and
82+
* stalls there; fail the transfer so the test reports it. */
83+
if ((xfer.word_index % xfer.word_count) == 0 &&
84+
(mock_regs[SDHCI_SRS12 / sizeof(uint32_t)] & SDHCI_SRS12_BWR)) {
85+
mock_regs[SDHCI_SRS12 / sizeof(uint32_t)] |= SDHCI_SRS12_EINT;
86+
}
8087
memcpy(&mock_disk[pos], &val, sizeof(val));
8188
xfer.word_index++;
89+
/* BWR is raised once per block, not latched for the whole transfer:
90+
* re-assert it when the block just taken has drained and another is
91+
* still expected. */
92+
if ((xfer.word_index % xfer.word_count) == 0) {
93+
uint32_t blocks = mock_regs[SDHCI_SRS01 / sizeof(uint32_t)] >>
94+
SDHCI_SRS01_BCCT_SHIFT;
95+
if ((xfer.word_index / xfer.word_count) < blocks) {
96+
mock_regs[SDHCI_SRS12 / sizeof(uint32_t)] |= SDHCI_SRS12_BWR;
97+
}
98+
}
8299
return;
83100
}
84101

0 commit comments

Comments
 (0)