From 98770c509f0b9974959b983478aa5c9ad41138f2 Mon Sep 17 00:00:00 2001 From: riastradh <riastradh@NetBSD.org> Date: Thu, 13 Dec 2012 06:43:37 +0000 Subject: [PATCH] Implement TI AM335x's SDHC reset quirk. Beaglebone SDHC works now! On the AM335x, we first must wait for the controller to acknowledge the reset; then we can wait for the reset to complete. I believe this quirk also applies to the OMAP4 ES, but I don't have one of those to test and we don't seem to have an obvious conditional for it anyway. This quirk may work for controllers that don't require it too, but I am nervous about doing it by default because if we miss the reset acknowledgement, then we'll just time out even though everything is really hunky-dory. Also, for all sdhc, don't bother writing 0 in sdhc_soft_reset while waiting for the reset to complete; there is no need. ok matt --- sys/arch/arm/omap/omap3_sdhc.c | 7 +++++-- sys/dev/sdmmc/sdhc.c | 28 ++++++++++++++++++++++++---- sys/dev/sdmmc/sdhcvar.h | 3 ++- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/sys/arch/arm/omap/omap3_sdhc.c b/sys/arch/arm/omap/omap3_sdhc.c index 1b66a70dea28..6f3f6e4fa188 100644 --- a/sys/arch/arm/omap/omap3_sdhc.c +++ b/sys/arch/arm/omap/omap3_sdhc.c @@ -1,4 +1,4 @@ -/* $NetBSD: omap3_sdhc.c,v 1.5 2012/12/12 15:19:53 matt Exp $ */ +/* $NetBSD: omap3_sdhc.c,v 1.6 2012/12/13 06:43:38 riastradh Exp $ */ /*- * Copyright (c) 2011 The NetBSD Foundation, Inc. * All rights reserved. @@ -29,7 +29,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: omap3_sdhc.c,v 1.5 2012/12/12 15:19:53 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: omap3_sdhc.c,v 1.6 2012/12/13 06:43:38 riastradh Exp $"); #include "opt_omap.h" @@ -150,6 +150,9 @@ obiosdhc_attach(device_t parent, device_t self, void *aux) sc->sc.sc_flags |= SDHC_FLAG_NO_LED_ON; sc->sc.sc_flags |= SDHC_FLAG_RSP136_CRC; sc->sc.sc_flags |= SDHC_FLAG_SINGLE_ONLY; +#ifdef TI_AM335X + sc->sc.sc_flags |= SDHC_FLAG_WAIT_RESET; +#endif sc->sc.sc_host = sc->sc_hosts; sc->sc.sc_clkbase = 96000; /* 96MHZ */ if (!prop_dictionary_get_uint32(prop, "clkmask", &sc->sc.sc_clkmsk)) diff --git a/sys/dev/sdmmc/sdhc.c b/sys/dev/sdmmc/sdhc.c index bb449ba3f9e4..931e16b556f1 100644 --- a/sys/dev/sdmmc/sdhc.c +++ b/sys/dev/sdmmc/sdhc.c @@ -1,4 +1,4 @@ -/* $NetBSD: sdhc.c,v 1.34 2012/12/12 15:15:31 matt Exp $ */ +/* $NetBSD: sdhc.c,v 1.35 2012/12/13 06:43:37 riastradh Exp $ */ /* $OpenBSD: sdhc.c,v 1.25 2009/01/13 19:44:20 grange Exp $ */ /* @@ -23,7 +23,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.34 2012/12/12 15:15:31 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.35 2012/12/13 06:43:37 riastradh Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -1518,17 +1518,37 @@ sdhc_soft_reset(struct sdhc_host *hp, int mask) DPRINTF(1,("%s: software reset reg=%08x\n", HDEVNAME(hp), mask)); + /* Request the reset. */ HWRITE1(hp, SDHC_SOFTWARE_RESET, mask); + + /* + * If necessary, wait for the controller to set the bits to + * acknowledge the reset. + */ + if (ISSET(hp->sc->sc_flags, SDHC_FLAG_WAIT_RESET) && + ISSET(mask, (SDHC_RESET_DAT | SDHC_RESET_CMD))) { + for (timo = 10000; timo > 0; timo--) { + if (ISSET(HREAD1(hp, SDHC_SOFTWARE_RESET), mask)) + break; + /* Short delay because I worry we may miss it... */ + sdmmc_delay(1); + } + if (timo == 0) + return ETIMEDOUT; + } + + /* + * Wait for the controller to clear the bits to indicate that + * the reset has completed. + */ for (timo = 10; timo > 0; timo--) { if (!ISSET(HREAD1(hp, SDHC_SOFTWARE_RESET), mask)) break; sdmmc_delay(10000); - HWRITE1(hp, SDHC_SOFTWARE_RESET, 0); } if (timo == 0) { DPRINTF(1,("%s: timeout reg=%08x\n", HDEVNAME(hp), HREAD1(hp, SDHC_SOFTWARE_RESET))); - HWRITE1(hp, SDHC_SOFTWARE_RESET, 0); return ETIMEDOUT; } diff --git a/sys/dev/sdmmc/sdhcvar.h b/sys/dev/sdmmc/sdhcvar.h index 4d945549819c..fd1441c349b1 100644 --- a/sys/dev/sdmmc/sdhcvar.h +++ b/sys/dev/sdmmc/sdhcvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: sdhcvar.h,v 1.10 2012/12/12 15:15:31 matt Exp $ */ +/* $NetBSD: sdhcvar.h,v 1.11 2012/12/13 06:43:37 riastradh Exp $ */ /* $OpenBSD: sdhcvar.h,v 1.3 2007/09/06 08:01:01 jsg Exp $ */ /* @@ -47,6 +47,7 @@ struct sdhc_softc { #define SDHC_FLAG_HOSTCAPS 0x0200 /* No device provided capabilities */ #define SDHC_FLAG_RSP136_CRC 0x0400 /* Resp 136 with CRC and end-bit */ #define SDHC_FLAG_SINGLE_ONLY 0x0800 /* Single transfer only */ +#define SDHC_FLAG_WAIT_RESET 0x1000 /* Wait for soft resets to start */ uint32_t sc_clkbase; int sc_clkmsk; /* Mask for SDCLK */