Add a new sdhci quirk, SDHCI_QUIRK_WAITFOR_RESET_ASSERTED, to work around
TI OMAP controllers which will return the reset-in-progress bit as zero if you read the status register too fast after setting the reset bit. The zero is apparently from a stale snapshot of the internal state presented in the interface register, and leads to a false indication that the reset is complete when it either hasn't started yet or is in-progress. The workaround is to first loop until the bit is seen as asserted, then do the normal loop waiting to see it de-asserted. Submitted by: Michal Meloun <meloun@miracle.cz>
This commit is contained in:
parent
7e5866432f
commit
61bc42f782
@ -413,9 +413,27 @@ ti_sdhci_hw_init(device_t dev)
|
||||
DELAY(100);
|
||||
}
|
||||
|
||||
/* Reset both the command and data state machines */
|
||||
/*
|
||||
* Reset the command and data state machines and also other aspects of
|
||||
* the controller such as bus clock and power.
|
||||
*
|
||||
* If we read the software reset register too fast after writing it we
|
||||
* can get back a zero that means the reset hasn't started yet rather
|
||||
* than that the reset is complete. Per TI recommendations, work around
|
||||
* it by reading until we see the reset bit asserted, then read until
|
||||
* it's clear. We also set the SDHCI_QUIRK_WAITFOR_RESET_ASSERTED quirk
|
||||
* so that the main sdhci driver uses this same logic in its resets.
|
||||
*/
|
||||
ti_sdhci_write_1(dev, NULL, SDHCI_SOFTWARE_RESET, SDHCI_RESET_ALL);
|
||||
timeout = 1000;
|
||||
timeout = 10000;
|
||||
while ((ti_sdhci_read_1(dev, NULL, SDHCI_SOFTWARE_RESET) &
|
||||
SDHCI_RESET_ALL) != SDHCI_RESET_ALL) {
|
||||
if (--timeout == 0) {
|
||||
break;
|
||||
}
|
||||
DELAY(1);
|
||||
}
|
||||
timeout = 10000;
|
||||
while ((ti_sdhci_read_1(dev, NULL, SDHCI_SOFTWARE_RESET) &
|
||||
SDHCI_RESET_ALL)) {
|
||||
if (--timeout == 0) {
|
||||
@ -582,6 +600,12 @@ ti_sdhci_attach(device_t dev)
|
||||
*/
|
||||
sc->slot.quirks |= SDHCI_QUIRK_DONT_SHIFT_RESPONSE;
|
||||
|
||||
/*
|
||||
* Reset bits are broken, have to wait to see the bits asserted
|
||||
* before waiting to see them de-asserted.
|
||||
*/
|
||||
sc->slot.quirks |= SDHCI_QUIRK_WAITFOR_RESET_ASSERTED;
|
||||
|
||||
/*
|
||||
* DMA is not really broken, I just haven't implemented it yet.
|
||||
*/
|
||||
|
@ -149,7 +149,6 @@ static void
|
||||
sdhci_reset(struct sdhci_slot *slot, uint8_t mask)
|
||||
{
|
||||
int timeout;
|
||||
uint8_t res;
|
||||
|
||||
if (slot->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
|
||||
if (!(RD4(slot, SDHCI_PRESENT_STATE) &
|
||||
@ -168,26 +167,43 @@ sdhci_reset(struct sdhci_slot *slot, uint8_t mask)
|
||||
sdhci_set_clock(slot, clock);
|
||||
}
|
||||
|
||||
WR1(slot, SDHCI_SOFTWARE_RESET, mask);
|
||||
|
||||
if (mask & SDHCI_RESET_ALL) {
|
||||
slot->clock = 0;
|
||||
slot->power = 0;
|
||||
}
|
||||
|
||||
WR1(slot, SDHCI_SOFTWARE_RESET, mask);
|
||||
|
||||
if (slot->quirks & SDHCI_QUIRK_WAITFOR_RESET_ASSERTED) {
|
||||
/*
|
||||
* Resets on TI OMAPs and AM335x are incompatible with SDHCI
|
||||
* specification. The reset bit has internal propagation delay,
|
||||
* so a fast read after write returns 0 even if reset process is
|
||||
* in progress. The workaround is to poll for 1 before polling
|
||||
* for 0. In the worst case, if we miss seeing it asserted the
|
||||
* time we spent waiting is enough to ensure the reset finishes.
|
||||
*/
|
||||
timeout = 10000;
|
||||
while ((RD1(slot, SDHCI_SOFTWARE_RESET) & mask) != mask) {
|
||||
if (timeout <= 0)
|
||||
break;
|
||||
timeout--;
|
||||
DELAY(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait max 100 ms */
|
||||
timeout = 100;
|
||||
timeout = 10000;
|
||||
/* Controller clears the bits when it's done */
|
||||
while ((res = RD1(slot, SDHCI_SOFTWARE_RESET)) & mask) {
|
||||
if (timeout == 0) {
|
||||
slot_printf(slot,
|
||||
"Reset 0x%x never completed - 0x%x.\n",
|
||||
(int)mask, (int)res);
|
||||
while (RD1(slot, SDHCI_SOFTWARE_RESET) & mask) {
|
||||
if (timeout <= 0) {
|
||||
slot_printf(slot, "Reset 0x%x never completed.\n",
|
||||
mask);
|
||||
sdhci_dumpregs(slot);
|
||||
return;
|
||||
}
|
||||
timeout--;
|
||||
DELAY(1000);
|
||||
DELAY(10);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,8 @@
|
||||
#define SDHCI_QUIRK_MISSING_CAPS (1<<12)
|
||||
/* Hardware shifts the 136-bit response, don't do it in software. */
|
||||
#define SDHCI_QUIRK_DONT_SHIFT_RESPONSE (1<<13)
|
||||
/* Wait to see reset bit asserted before waiting for de-asserted */
|
||||
#define SDHCI_QUIRK_WAITFOR_RESET_ASSERTED (1<<14)
|
||||
|
||||
/*
|
||||
* Controller registers
|
||||
|
Loading…
Reference in New Issue
Block a user