diff options
author | ian <ian@FreeBSD.org> | 2014-12-20 01:13:13 +0000 |
---|---|---|
committer | ian <ian@FreeBSD.org> | 2014-12-20 01:13:13 +0000 |
commit | 7814dfac2fc976412cebca6c48d0b949f495c1c1 (patch) | |
tree | ff1a6817bca2c031c02e20ad2184b75062530784 /sys/arm | |
parent | f2e6cf3c8743406f318dbc756d18cd6bf9fb3509 (diff) | |
download | FreeBSD-src-7814dfac2fc976412cebca6c48d0b949f495c1c1.zip FreeBSD-src-7814dfac2fc976412cebca6c48d0b949f495c1c1.tar.gz |
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>
Diffstat (limited to 'sys/arm')
-rw-r--r-- | sys/arm/ti/ti_sdhci.c | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/sys/arm/ti/ti_sdhci.c b/sys/arm/ti/ti_sdhci.c index 6db13c3..380a40e 100644 --- a/sys/arm/ti/ti_sdhci.c +++ b/sys/arm/ti/ti_sdhci.c @@ -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) { @@ -583,6 +601,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. */ sc->slot.quirks |= SDHCI_QUIRK_BROKEN_DMA; |