Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/sdhci.c
Original file line number Diff line number Diff line change
Expand Up @@ -1699,6 +1699,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
Expand Down Expand Up @@ -1745,8 +1749,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);
}
Expand Down
17 changes: 17 additions & 0 deletions tools/unit-tests/unit-sdhci-disk-unaligned.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Loading