Implement TI AM335x's SDHC reset quirk. Beaglebone SDHC works now! Also, don't bother writing 0 while waiting for the reset to complete; there is no need. 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. Index: sys/arch/arm/omap/omap3_sdhc.c =================================================================== RCS file: /cvsroot/src/sys/arch/arm/omap/omap3_sdhc.c,v retrieving revision 1.4 diff -p -u -r1.4 omap3_sdhc.c --- sys/arch/arm/omap/omap3_sdhc.c 11 Dec 2012 19:26:40 -0000 1.4 +++ sys/arch/arm/omap/omap3_sdhc.c 13 Dec 2012 06:29:41 -0000 @@ -147,6 +147,9 @@ obiosdhc_attach(device_t parent, device_ 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 */ sc->sc.sc_clkmsk = 0x0000ffc0; Index: sys/dev/sdmmc/sdhc.c =================================================================== RCS file: /cvsroot/src/sys/dev/sdmmc/sdhc.c,v retrieving revision 1.32 diff -p -u -r1.32 sdhc.c --- sys/dev/sdmmc/sdhc.c 29 Oct 2012 13:30:25 -0000 1.32 +++ sys/dev/sdmmc/sdhc.c 13 Dec 2012 06:29:41 -0000 @@ -1512,17 +1512,37 @@ sdhc_soft_reset(struct sdhc_host *hp, in 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 is complete. + */ 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; } Index: sys/dev/sdmmc/sdhcvar.h =================================================================== RCS file: /cvsroot/src/sys/dev/sdmmc/sdhcvar.h,v retrieving revision 1.9 diff -p -u -r1.9 sdhcvar.h --- sys/dev/sdmmc/sdhcvar.h 29 Oct 2012 13:30:25 -0000 1.9 +++ sys/dev/sdmmc/sdhcvar.h 13 Dec 2012 06:29:41 -0000 @@ -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 */