From owner-svn-src-head@FreeBSD.ORG Sat Dec 20 01:13:15 2014 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 3C7D55BE; Sat, 20 Dec 2014 01:13:15 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 1D7001FE5; Sat, 20 Dec 2014 01:13:15 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id sBK1DEQD081585; Sat, 20 Dec 2014 01:13:14 GMT (envelope-from ian@FreeBSD.org) Received: (from ian@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id sBK1DEOG081581; Sat, 20 Dec 2014 01:13:14 GMT (envelope-from ian@FreeBSD.org) Message-Id: <201412200113.sBK1DEOG081581@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: ian set sender to ian@FreeBSD.org using -f From: Ian Lepore Date: Sat, 20 Dec 2014 01:13:14 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r275950 - in head/sys: arm/ti dev/sdhci X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 20 Dec 2014 01:13:15 -0000 Author: ian Date: Sat Dec 20 01:13:13 2014 New Revision: 275950 URL: https://svnweb.freebsd.org/changeset/base/275950 Log: 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 Modified: head/sys/arm/ti/ti_sdhci.c head/sys/dev/sdhci/sdhci.c head/sys/dev/sdhci/sdhci.h Modified: head/sys/arm/ti/ti_sdhci.c ============================================================================== --- head/sys/arm/ti/ti_sdhci.c Sat Dec 20 00:37:56 2014 (r275949) +++ head/sys/arm/ti/ti_sdhci.c Sat Dec 20 01:13:13 2014 (r275950) @@ -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; Modified: head/sys/dev/sdhci/sdhci.c ============================================================================== --- head/sys/dev/sdhci/sdhci.c Sat Dec 20 00:37:56 2014 (r275949) +++ head/sys/dev/sdhci/sdhci.c Sat Dec 20 01:13:13 2014 (r275950) @@ -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, uin 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); } } Modified: head/sys/dev/sdhci/sdhci.h ============================================================================== --- head/sys/dev/sdhci/sdhci.h Sat Dec 20 00:37:56 2014 (r275949) +++ head/sys/dev/sdhci/sdhci.h Sat Dec 20 01:13:13 2014 (r275950) @@ -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