Index: sys/dev/sdmmc/sdhc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/sdmmc/sdhc.c,v
retrieving revision 1.10
diff -u -p -r1.10 sdhc.c
--- sys/dev/sdmmc/sdhc.c        2 Feb 2012 22:49:17 -0000       1.10
+++ sys/dev/sdmmc/sdhc.c        24 May 2012 19:11:33 -0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: sdhc.c,v 1.10 2012/02/02 22:49:17 nonaka Exp $ */
+/*     $NetBSD: sdhc.c,v 1.11 2012/02/23 21:06:21 matt 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.10 2012/02/02 22:49:17 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.11 2012/02/23 21:06:21 matt Exp $");

#ifdef _KERNEL_OPT
#include "opt_sdmmc.h"
@@ -82,30 +82,80 @@ struct sdhc_host {
       uint32_t flags;                 /* flags for this host */
#define SHF_USE_DMA            0x0001
#define SHF_USE_4BIT_MODE      0x0002
+#define SHF_USE_8BIT_MODE      0x0004
};

#define HDEVNAME(hp)   (device_xname((hp)->sc->sc_dev))

-#define HREAD1(hp, reg)                                                        \
-       (bus_space_read_1((hp)->iot, (hp)->ioh, (reg)))
-#define HREAD2(hp, reg)                                                        \
-       (bus_space_read_2((hp)->iot, (hp)->ioh, (reg)))
-#define HREAD4(hp, reg)                                                        \
+static uint8_t
+hread1(struct sdhc_host *hp, bus_size_t reg)
+{
+       if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS))
+               return bus_space_read_1(hp->iot, hp->ioh, reg);
+
+       return bus_space_read_4(hp->iot, hp->ioh, reg & -4) >> (8 * (reg & 3));
+}
+
+static uint16_t
+hread2(struct sdhc_host *hp, bus_size_t reg)
+{
+       if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS))
+               return bus_space_read_2(hp->iot, hp->ioh, reg);
+
+       return bus_space_read_4(hp->iot, hp->ioh, reg & -4) >> (8 * (reg & 2));
+}
+
+#define HREAD1(hp, reg)                hread1(hp, reg)
+#define HREAD2(hp, reg)                hread2(hp, reg)
+#define HREAD4(hp, reg)                \
       (bus_space_read_4((hp)->iot, (hp)->ioh, (reg)))
-#define HWRITE1(hp, reg, val)                                          \
-       bus_space_write_1((hp)->iot, (hp)->ioh, (reg), (val))
-#define HWRITE2(hp, reg, val)                                          \
-       bus_space_write_2((hp)->iot, (hp)->ioh, (reg), (val))
+
+
+static void
+hwrite1(struct sdhc_host *hp, bus_size_t o, uint8_t val)
+{
+       if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) {
+               bus_space_write_1(hp->iot, hp->ioh, o, val);
+       } else {
+               const size_t shift = 8 * (o & 3);
+               o &= -4;
+               uint32_t tmp = bus_space_read_4(hp->iot, hp->ioh, o);
+               tmp = (val << shift) | (tmp & ~(0xff << shift));
+               bus_space_write_4(hp->iot, hp->ioh, o, tmp);
+       }
+}
+
+static void
+hwrite2(struct sdhc_host *hp, bus_size_t o, uint16_t val)
+{
+       if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) {
+               bus_space_write_2(hp->iot, hp->ioh, o, val);
+       } else {
+               const size_t shift = 8 * (o & 2);
+               o &= -4;
+               uint32_t tmp = bus_space_read_4(hp->iot, hp->ioh, o);
+               tmp = (val << shift) | (tmp & ~(0xffff << shift));
+               bus_space_write_4(hp->iot, hp->ioh, o, tmp);
+       }
+}
+
+#define HWRITE1(hp, reg, val)          hwrite1(hp, reg, val)
+#define HWRITE2(hp, reg, val)          hwrite2(hp, reg, val)
#define HWRITE4(hp, reg, val)                                          \
       bus_space_write_4((hp)->iot, (hp)->ioh, (reg), (val))
+
#define HCLR1(hp, reg, bits)                                           \
-       HWRITE1((hp), (reg), HREAD1((hp), (reg)) & ~(bits))
+       do if (bits) HWRITE1((hp), (reg), HREAD1((hp), (reg)) & ~(bits)); while (0)
#define HCLR2(hp, reg, bits)                                           \
-       HWRITE2((hp), (reg), HREAD2((hp), (reg)) & ~(bits))
+       do if (bits) HWRITE2((hp), (reg), HREAD2((hp), (reg)) & ~(bits)); while (0)
+#define HCLR4(hp, reg, bits)                                           \
+       do if (bits) HWRITE4((hp), (reg), HREAD4((hp), (reg)) & ~(bits)); while (0)
#define HSET1(hp, reg, bits)                                           \
-       HWRITE1((hp), (reg), HREAD1((hp), (reg)) | (bits))
+       do if (bits) HWRITE1((hp), (reg), HREAD1((hp), (reg)) | (bits)); while (0)
#define HSET2(hp, reg, bits)                                           \
-       HWRITE2((hp), (reg), HREAD2((hp), (reg)) | (bits))
+       do if (bits) HWRITE2((hp), (reg), HREAD2((hp), (reg)) | (bits)); while (0)
+#define HSET4(hp, reg, bits)                                           \
+       do if (bits) HWRITE4((hp), (reg), HREAD4((hp), (reg)) | (bits)); while (0)

static int     sdhc_host_reset(sdmmc_chipset_handle_t);
static int     sdhc_host_reset1(sdmmc_chipset_handle_t);
@@ -128,8 +178,11 @@ static int sdhc_wait_intr(struct sdhc_ho
static void    sdhc_transfer_data(struct sdhc_host *, struct sdmmc_command *);
static int     sdhc_transfer_data_dma(struct sdhc_host *, struct sdmmc_command *);
static int     sdhc_transfer_data_pio(struct sdhc_host *, struct sdmmc_command *);
-static void    sdhc_read_data_pio(struct sdhc_host *, uint8_t *, int);
-static void    sdhc_write_data_pio(struct sdhc_host *, uint8_t *, int);
+static void    sdhc_read_data_pio(struct sdhc_host *, uint8_t *, u_int);
+static void    sdhc_write_data_pio(struct sdhc_host *, uint8_t *, u_int);
+static void    esdhc_read_data_pio(struct sdhc_host *, uint8_t *, u_int);
+static void    esdhc_write_data_pio(struct sdhc_host *, uint8_t *, u_int);
+

static struct sdmmc_chip_functions sdhc_functions = {
       /* host controller reset */
@@ -257,16 +310,23 @@ sdhc_host_found(struct sdhc_softc *sc, b
        * capabilities. (2.2.15)
        */
       HWRITE1(hp, SDHC_TIMEOUT_CTL, SDHC_TIMEOUT_MAX);
+#if 0
+       if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED))
+               HWRITE4(hp, SDHC_NINTR_STATUS, SDHC_CMD_TIMEOUT_ERROR << 16);
+#endif

       /*
        * Determine SD bus voltage levels supported by the controller.
        */
-       if (ISSET(caps, SDHC_VOLTAGE_SUPP_1_8V))
+       if (ISSET(caps, SDHC_VOLTAGE_SUPP_1_8V)) {
               SET(hp->ocr, MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V);
-       if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_0V))
+       }
+       if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_0V)) {
               SET(hp->ocr, MMC_OCR_2_9V_3_0V | MMC_OCR_3_0V_3_1V);
-       if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_3V))
+       }
+       if (ISSET(caps, SDHC_VOLTAGE_SUPP_3_3V)) {
               SET(hp->ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V);
+       }

       /*
        * Determine the maximum block length supported by the host
@@ -308,9 +368,15 @@ sdhc_host_found(struct sdhc_softc *sc, b
       saa.saa_dmat = hp->dmat;
       saa.saa_clkmin = hp->clkbase / 256;
       saa.saa_clkmax = hp->clkbase;
-       if (ISSET(sc->sc_flags, SDHC_FLAG_HAVE_DVS))
+       if (ISSET(sc->sc_flags, SDHC_FLAG_HAVE_CGM))
+               saa.saa_clkmin /= 2046;
+       else if (ISSET(sc->sc_flags, SDHC_FLAG_HAVE_DVS))
               saa.saa_clkmin /= 16;
       saa.saa_caps = SMC_CAPS_4BIT_MODE|SMC_CAPS_AUTO_STOP;
+       if (ISSET(sc->sc_flags, SDHC_FLAG_8BIT_MODE))
+               saa.saa_caps |= SMC_CAPS_8BIT_MODE;
+       if (ISSET(caps, SDHC_HIGH_SPEED_SUPP))
+               saa.saa_caps |= SMC_CAPS_SD_HIGHSPEED;
#if notyet
       if (ISSET(hp->flags, SHF_USE_DMA))
               saa.saa_caps |= SMC_CAPS_DMA;
@@ -353,16 +419,28 @@ sdhc_suspend(device_t dev, const pmf_qua
{
       struct sdhc_softc *sc = device_private(dev);
       struct sdhc_host *hp;
-       int n, i;

       /* XXX poll for command completion or suspend command
        * in progress */

       /* Save the host controller state. */
-       for (n = 0; n < sc->sc_nhosts; n++) {
+       for (size_t n = 0; n < sc->sc_nhosts; n++) {
               hp = sc->sc_host[n];
-               for (i = 0; i < sizeof hp->regs; i++)
-                       hp->regs[i] = HREAD1(hp, i);
+               if (ISSET(sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) {
+                       for (size_t i = 0; i < sizeof hp->regs; i += 4) {
+                               uint32_t v = HREAD4(hp, i);
+                               hp->regs[i + 0] = (v >> 0);
+                               hp->regs[i + 1] = (v >> 8);
+                               if (i + 3 < sizeof hp->regs) {
+                                       hp->regs[i + 2] = (v >> 16);
+                                       hp->regs[i + 3] = (v >> 24);
+                               }
+                       }
+               } else {
+                       for (size_t i = 0; i < sizeof hp->regs; i++) {
+                               hp->regs[i] = HREAD1(hp, i);
+                       }
+               }
       }
       return true;
}
@@ -372,14 +450,30 @@ sdhc_resume(device_t dev, const pmf_qual
{
       struct sdhc_softc *sc = device_private(dev);
       struct sdhc_host *hp;
-       int n, i;

       /* Restore the host controller state. */
-       for (n = 0; n < sc->sc_nhosts; n++) {
+       for (size_t n = 0; n < sc->sc_nhosts; n++) {
               hp = sc->sc_host[n];
               (void)sdhc_host_reset(hp);
-               for (i = 0; i < sizeof hp->regs; i++)
-                       HWRITE1(hp, i, hp->regs[i]);
+               if (ISSET(sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) {
+                       for (size_t i = 0; i < sizeof hp->regs; i += 4) {
+                               if (i + 3 < sizeof hp->regs) {
+                                       HWRITE4(hp, i,
+                                           (hp->regs[i + 0] << 0)
+                                           | (hp->regs[i + 1] << 8)
+                                           | (hp->regs[i + 2] << 16)
+                                           | (hp->regs[i + 3] << 24));
+                               } else {
+                                       HWRITE4(hp, i,
+                                           (hp->regs[i + 0] << 0)
+                                           | (hp->regs[i + 1] << 8));
+                               }
+                       }
+               } else {
+                       for (size_t i = 0; i < sizeof hp->regs; i++) {
+                               HWRITE1(hp, i, hp->regs[i]);
+                       }
+               }
       }
       return true;
}
@@ -389,10 +483,9 @@ sdhc_shutdown(device_t dev, int flags)
{
       struct sdhc_softc *sc = device_private(dev);
       struct sdhc_host *hp;
-       int i;

       /* XXX chip locks up if we don't disable it before reboot. */
-       for (i = 0; i < sc->sc_nhosts; i++) {
+       for (size_t i = 0; i < sc->sc_nhosts; i++) {
               hp = sc->sc_host[i];
               (void)sdhc_host_reset(hp);
       }
@@ -407,13 +500,17 @@ static int
sdhc_host_reset1(sdmmc_chipset_handle_t sch)
{
       struct sdhc_host *hp = (struct sdhc_host *)sch;
-       uint16_t sdhcimask;
+       uint32_t sdhcimask;
       int error;

       /* Don't lock. */

       /* Disable all interrupts. */
-       HWRITE2(hp, SDHC_NINTR_SIGNAL_EN, 0);
+       if (ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) {
+               HWRITE4(hp, SDHC_NINTR_SIGNAL_EN, 0);
+       } else {
+               HWRITE2(hp, SDHC_NINTR_SIGNAL_EN, 0);
+       }

       /*
        * Reset the entire host controller and wait up to 100ms for
@@ -425,16 +522,30 @@ sdhc_host_reset1(sdmmc_chipset_handle_t

       /* Set data timeout counter value to max for now. */
       HWRITE1(hp, SDHC_TIMEOUT_CTL, SDHC_TIMEOUT_MAX);
+#if 0
+       if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED))
+               HWRITE4(hp, SDHC_NINTR_STATUS, SDHC_CMD_TIMEOUT_ERROR << 16);
+#endif

       /* Enable interrupts. */
       sdhcimask = SDHC_CARD_REMOVAL | SDHC_CARD_INSERTION |
           SDHC_BUFFER_READ_READY | SDHC_BUFFER_WRITE_READY |
           SDHC_DMA_INTERRUPT | SDHC_BLOCK_GAP_EVENT |
           SDHC_TRANSFER_COMPLETE | SDHC_COMMAND_COMPLETE;
-       HWRITE2(hp, SDHC_NINTR_STATUS_EN, sdhcimask);
-       HWRITE2(hp, SDHC_EINTR_STATUS_EN, SDHC_EINTR_STATUS_MASK);
-       HWRITE2(hp, SDHC_NINTR_SIGNAL_EN, sdhcimask);
-       HWRITE2(hp, SDHC_EINTR_SIGNAL_EN, SDHC_EINTR_SIGNAL_MASK);
+       if (ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) {
+               sdhcimask |= SDHC_EINTR_STATUS_MASK << 16;
+               HWRITE4(hp, SDHC_NINTR_STATUS_EN, sdhcimask);
+               sdhcimask ^=
+                   (SDHC_EINTR_STATUS_MASK ^ SDHC_EINTR_SIGNAL_MASK) << 16;
+               sdhcimask ^= SDHC_BUFFER_READ_READY ^ SDHC_BUFFER_WRITE_READY;
+               HWRITE4(hp, SDHC_NINTR_SIGNAL_EN, sdhcimask);
+       } else {
+               HWRITE2(hp, SDHC_NINTR_STATUS_EN, sdhcimask);
+               HWRITE2(hp, SDHC_EINTR_STATUS_EN, SDHC_EINTR_STATUS_MASK);
+               sdhcimask ^= SDHC_BUFFER_READ_READY ^ SDHC_BUFFER_WRITE_READY;
+               HWRITE2(hp, SDHC_NINTR_SIGNAL_EN, sdhcimask);
+               HWRITE2(hp, SDHC_EINTR_SIGNAL_EN, SDHC_EINTR_SIGNAL_MASK);
+       }

out:
       return error;
@@ -482,9 +593,7 @@ sdhc_card_detect(sdmmc_chipset_handle_t
       r = ISSET(HREAD4(hp, SDHC_PRESENT_STATE), SDHC_CARD_INSERTED);
       mutex_exit(&hp->host_mtx);

-       if (r)
-               return 1;
-       return 0;
+       return r ? 1 : 0;
}

/*
@@ -521,7 +630,8 @@ sdhc_bus_power(sdmmc_chipset_handle_t sc
       /*
        * Disable bus power before voltage change.
        */
-       if (!(hp->sc->sc_flags & SDHC_FLAG_NO_PWR0))
+       if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)
+           && !ISSET(hp->sc->sc_flags, SDHC_FLAG_NO_PWR0))
               HWRITE1(hp, SDHC_POWER_CTL, 0);

       /* If power is disabled, reset the host and return now. */
@@ -534,34 +644,36 @@ sdhc_bus_power(sdmmc_chipset_handle_t sc
        * Select the lowest voltage according to capabilities.
        */
       ocr &= hp->ocr;
-       if (ISSET(ocr, MMC_OCR_1_7V_1_8V|MMC_OCR_1_8V_1_9V))
+       if (ISSET(ocr, MMC_OCR_1_7V_1_8V|MMC_OCR_1_8V_1_9V)) {
               vdd = SDHC_VOLTAGE_1_8V;
-       else if (ISSET(ocr, MMC_OCR_2_9V_3_0V|MMC_OCR_3_0V_3_1V))
+       } else if (ISSET(ocr, MMC_OCR_2_9V_3_0V|MMC_OCR_3_0V_3_1V)) {
               vdd = SDHC_VOLTAGE_3_0V;
-       else if (ISSET(ocr, MMC_OCR_3_2V_3_3V|MMC_OCR_3_3V_3_4V))
+       } else if (ISSET(ocr, MMC_OCR_3_2V_3_3V|MMC_OCR_3_3V_3_4V)) {
               vdd = SDHC_VOLTAGE_3_3V;
-       else {
+       } else {
               /* Unsupported voltage level requested. */
               error = EINVAL;
               goto out;
       }

-       /*
-        * Enable bus power.  Wait at least 1 ms (or 74 clocks) plus
-        * voltage ramp until power rises.
-        */
-       HWRITE1(hp, SDHC_POWER_CTL,
-           (vdd << SDHC_VOLTAGE_SHIFT) | SDHC_BUS_POWER);
-       sdmmc_delay(10000);
+       if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
+               /*
+                * Enable bus power.  Wait at least 1 ms (or 74 clocks) plus
+                * voltage ramp until power rises.
+                */
+               HWRITE1(hp, SDHC_POWER_CTL,
+                   (vdd << SDHC_VOLTAGE_SHIFT) | SDHC_BUS_POWER);
+               sdmmc_delay(10000);

-       /*
-        * The host system may not power the bus due to battery low,
-        * etc.  In that case, the host controller should clear the
-        * bus power bit.
-        */
-       if (!ISSET(HREAD1(hp, SDHC_POWER_CTL), SDHC_BUS_POWER)) {
-               error = ENXIO;
-               goto out;
+               /*
+                * The host system may not power the bus due to battery low,
+                * etc.  In that case, the host controller should clear the
+                * bus power bit.
+                */
+               if (!ISSET(HREAD1(hp, SDHC_POWER_CTL), SDHC_BUS_POWER)) {
+                       error = ENXIO;
+                       goto out;
+               }
       }

out:
@@ -574,30 +686,53 @@ out:
 * Return the smallest possible base clock frequency divisor value
 * for the CLOCK_CTL register to produce `freq' (KHz).
 */
-static int
-sdhc_clock_divisor(struct sdhc_host *hp, u_int freq)
+static bool
+sdhc_clock_divisor(struct sdhc_host *hp, u_int freq, u_int *divp)
{
-       int div;
+       u_int div;

-       if (hp->sc->sc_flags & SDHC_FLAG_HAVE_DVS) {
-               int dvs = (hp->clkbase + freq - 1) / freq;
-               div = 1;
-               for (div = 1; div <= 256; div <<= 1, dvs >>= 1) {
-                       if (dvs <= 16) {
-                               div <<= SDHC_SDCLK_DIV_SHIFT;
-                               div |= (dvs - 1) << SDHC_SDCLK_DVS_SHIFT;
-                               return div;
+       if (ISSET(hp->sc->sc_flags, SDHC_FLAG_HAVE_CGM)) {
+               for (div = hp->clkbase / freq; div <= 0x3ff; div++) {
+                       if ((hp->clkbase / div) <= freq) {
+                               *divp = SDHC_SDCLK_CGM
+                                   | ((div & 0x300) << SDHC_SDCLK_XDIV_SHIFT)
+                                   | ((div & 0x0ff) << SDHC_SDCLK_DIV_SHIFT);
+                               return true;
+                       }
+               }
+               /* No divisor found. */
+               return false;
+       }
+       if (ISSET(hp->sc->sc_flags, SDHC_FLAG_HAVE_DVS)) {
+               u_int dvs = (hp->clkbase + freq - 1) / freq;
+               u_int roundup = dvs & 1;
+               for (dvs >>= 1, div = 1; div <= 256; div <<= 1, dvs >>= 1) {
+                       if (dvs + roundup <= 16) {
+                               dvs += roundup - 1;
+                               *divp = (div << SDHC_SDCLK_DIV_SHIFT)
+                                   |   (dvs << SDHC_SDCLK_DVS_SHIFT);
+                               DPRINTF(2,
+                                   ("%s: divisor for freq %u is %u * %u\n",
+                                   HDEVNAME(hp), freq, div * 2, dvs + 1));
+                               return true;
                       }
+                       /*
+                        * If we drop bits, we need to round up the divisor.
+                        */
+                       roundup |= dvs & 1;
               }
+               panic("%s: can't find divisor for freq %u", HDEVNAME(hp), freq);
       } else {
               for (div = 1; div <= 256; div *= 2) {
-                       if ((hp->clkbase / div) <= freq)
-                               return (div / 2) << SDHC_SDCLK_DIV_SHIFT;
+                       if ((hp->clkbase / div) <= freq) {
+                               *divp = (div / 2) << SDHC_SDCLK_DIV_SHIFT;
+                               return true;
+                       }
               }
       }

       /* No divisor found. */
-       return -1;
+       return false;
}

/*
@@ -608,11 +743,11 @@ static int
sdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq)
{
       struct sdhc_host *hp = (struct sdhc_host *)sch;
-       int div;
-       int timo;
+       u_int div;
+       u_int timo;
       int error = 0;
#ifdef DIAGNOSTIC
-       int ispresent;
+       bool ispresent;
#endif

#ifdef DIAGNOSTIC
@@ -631,43 +766,82 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sc
       /*
        * Stop SD clock before changing the frequency.
        */
-       HWRITE2(hp, SDHC_CLOCK_CTL, 0);
-       if (freq == SDMMC_SDCLK_OFF)
-               goto out;
+       if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
+               HCLR4(hp, SDHC_CLOCK_CTL, 0xfff8);
+               if (freq == SDMMC_SDCLK_OFF) {
+                       HSET4(hp, SDHC_CLOCK_CTL, 0x80f0);
+                       goto out;
+               }
+       } else {
+               HWRITE2(hp, SDHC_CLOCK_CTL, 0);
+               if (freq == SDMMC_SDCLK_OFF)
+                       goto out;
+       }

       /*
        * Set the minimum base clock frequency divisor.
        */
-       if ((div = sdhc_clock_divisor(hp, freq)) < 0) {
+       if (!sdhc_clock_divisor(hp, freq, &div)) {
               /* Invalid base clock frequency or `freq' value. */
               error = EINVAL;
               goto out;
       }
-       HWRITE2(hp, SDHC_CLOCK_CTL, div);
+       if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
+               HWRITE4(hp, SDHC_CLOCK_CTL,
+                   div | (SDHC_TIMEOUT_MAX << 16));
+       } else {
+               HWRITE2(hp, SDHC_CLOCK_CTL, div);
+       }

       /*
        * Start internal clock.  Wait 10ms for stabilization.
        */
-       HSET2(hp, SDHC_CLOCK_CTL, SDHC_INTCLK_ENABLE);
-       for (timo = 1000; timo > 0; timo--) {
-               if (ISSET(HREAD2(hp, SDHC_CLOCK_CTL), SDHC_INTCLK_STABLE))
-                       break;
-               sdmmc_delay(10);
-       }
-       if (timo == 0) {
-               error = ETIMEDOUT;
-               goto out;
+       if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
+               sdmmc_delay(10000);
+               HSET4(hp, SDHC_CLOCK_CTL, 8|SDHC_INTCLK_ENABLE|SDHC_INTCLK_STABLE);
+       } else {
+               HSET2(hp, SDHC_CLOCK_CTL, SDHC_INTCLK_ENABLE);
+               for (timo = 1000; timo > 0; timo--) {
+                       if (ISSET(HREAD2(hp, SDHC_CLOCK_CTL), SDHC_INTCLK_STABLE))
+                               break;
+                       sdmmc_delay(10);
+               }
+               if (timo == 0) {
+                       error = ETIMEDOUT;
+                       goto out;
+               }
       }

-       /*
-        * Enable SD clock.
-        */
-       HSET2(hp, SDHC_CLOCK_CTL, SDHC_SDCLK_ENABLE);
+       if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
+               HSET1(hp, SDHC_SOFTWARE_RESET, SDHC_INIT_ACTIVE);
+               /*
+                * Sending 80 clocks at 400kHz takes 200us.
+                * So delay for that time + slop and then
+                * check a few times for completion.
+                */
+               sdmmc_delay(210);
+               for (timo = 10; timo > 0; timo--) {
+                       if (!ISSET(HREAD1(hp, SDHC_SOFTWARE_RESET),
+                           SDHC_INIT_ACTIVE))
+                               break;
+                       sdmmc_delay(10);
+               }
+               DPRINTF(2,("%s: %u init spins\n", __func__, 10 - timo));
+               /*
+                * Enable SD clock.
+                */
+               HSET4(hp, SDHC_CLOCK_CTL, SDHC_SDCLK_ENABLE);
+       } else {
+               /*
+                * Enable SD clock.
+                */
+               HSET2(hp, SDHC_CLOCK_CTL, SDHC_SDCLK_ENABLE);

-       if (freq > 25000)
-               HSET1(hp, SDHC_HOST_CTL, SDHC_HIGH_SPEED);
-       else
-               HCLR1(hp, SDHC_HOST_CTL, SDHC_HIGH_SPEED);
+               if (freq > 25000)
+                       HSET1(hp, SDHC_HOST_CTL, SDHC_HIGH_SPEED);
+               else
+                       HCLR1(hp, SDHC_HOST_CTL, SDHC_HIGH_SPEED);
+       }

out:
       mutex_exit(&hp->host_mtx);
@@ -686,6 +860,10 @@ sdhc_bus_width(sdmmc_chipset_handle_t sc
       case 4:
               break;

+       case 8:
+               if (ISSET(hp->sc->sc_flags, SDHC_FLAG_8BIT_MODE))
+                       break;
+               /* FALLTHROUGH */
       default:
               DPRINTF(0,("%s: unsupported bus width (%d)\n",
                   HDEVNAME(hp), width));
@@ -694,9 +872,17 @@ sdhc_bus_width(sdmmc_chipset_handle_t sc

       mutex_enter(&hp->host_mtx);
       reg = HREAD1(hp, SDHC_HOST_CTL);
-       reg &= ~SDHC_4BIT_MODE;
-       if (width == 4)
-               reg |= SDHC_4BIT_MODE;
+       if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
+               reg &= ~(SDHC_4BIT_MODE|SDHC_8BIT_MODE);
+               if (width == 4)
+                       reg |= SDHC_4BIT_MODE;
+               else if (width == 8)
+                       reg |= SDHC_8BIT_MODE;
+       } else {
+               reg &= ~SDHC_4BIT_MODE;
+               if (width == 4)
+                       reg |= SDHC_4BIT_MODE;
+       }
       HWRITE1(hp, SDHC_HOST_CTL, reg);
       mutex_exit(&hp->host_mtx);

@@ -716,15 +902,17 @@ sdhc_card_enable_intr(sdmmc_chipset_hand
{
       struct sdhc_host *hp = (struct sdhc_host *)sch;

-       mutex_enter(&hp->host_mtx);
-       if (enable) {
-               HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
-               HSET2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT);
-       } else {
-               HCLR2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT);
-               HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
+       if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
+               mutex_enter(&hp->host_mtx);
+               if (enable) {
+                       HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
+                       HSET2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT);
+               } else {
+                       HCLR2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_CARD_INTERRUPT);
+                       HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
+               }
+               mutex_exit(&hp->host_mtx);
       }
-       mutex_exit(&hp->host_mtx);
}

static void
@@ -732,9 +920,11 @@ sdhc_card_intr_ack(sdmmc_chipset_handle_
{
       struct sdhc_host *hp = (struct sdhc_host *)sch;

-       mutex_enter(&hp->host_mtx);
-       HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
-       mutex_exit(&hp->host_mtx);
+       if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
+               mutex_enter(&hp->host_mtx);
+               HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
+               mutex_exit(&hp->host_mtx);
+       }
}

static int
@@ -759,6 +949,19 @@ sdhc_exec_command(sdmmc_chipset_handle_t
       struct sdhc_host *hp = (struct sdhc_host *)sch;
       int error;

+#if 0
+       if (cmd->c_data) {
+               const uint16_t ready = SDHC_BUFFER_READ_READY | SDHC_BUFFER_WRITE_READY;
+               if (ISSET(hp->flags, SHF_USE_DMA)) {
+                       HCLR2(hp, SDHC_NINTR_SIGNAL_EN, ready);
+                       HCLR2(hp, SDHC_NINTR_STATUS_EN, ready);
+               } else {
+                       HSET2(hp, SDHC_NINTR_SIGNAL_EN, ready);
+                       HSET2(hp, SDHC_NINTR_STATUS_EN, ready);
+               }
+       }
+#endif
+
       /*
        * Start the MMC command, or mark `cmd' as failed and return.
        */
@@ -805,10 +1008,25 @@ sdhc_exec_command(sdmmc_chipset_handle_t
               sdhc_transfer_data(hp, cmd);

out:
-       mutex_enter(&hp->host_mtx);
-       /* Turn off the LED. */
-       HCLR1(hp, SDHC_HOST_CTL, SDHC_LED_ON);
-       mutex_exit(&hp->host_mtx);
+#if 0
+       if (cmd->c_dmamap != NULL && cmd->c_error == 0
+           && ISSET(hp->flags, SHF_USE_DMA)
+           && ISSET(cmd->c_flags, SCF_CMD_READ) {
+               if (((uintptr_t)cmd->c_data & PAGE_MASK) + cmd->c_datalen > PAGE_SIZE) {
+                       memcpy(cmd->c_data,
+                           (void *)hp->sc->dma_map->dm_segs[0].ds_addr,
+                           cmd->c_datalen);
+               }
+               bus_dmamap_unload(hp->sc->dt, hp->sc->dma_map);
+       }
+#endif
+
+       if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
+               mutex_enter(&hp->host_mtx);
+               /* Turn off the LED. */
+               HCLR1(hp, SDHC_HOST_CTL, SDHC_LED_ON);
+               mutex_exit(&hp->host_mtx);
+       }
       SET(cmd->c_flags, SCF_ITSDONE);

       DPRINTF(1,("%s: cmd %d %s (flags=%08x error=%d)\n", HDEVNAME(hp),
@@ -819,15 +1037,16 @@ out:
static int
sdhc_start_command(struct sdhc_host *hp, struct sdmmc_command *cmd)
{
+       struct sdhc_softc * const sc = hp->sc;
       uint16_t blksize = 0;
       uint16_t blkcount = 0;
       uint16_t mode;
       uint16_t command;
       int error;

-       DPRINTF(1,("%s: start cmd %d arg=%08x data=%p dlen=%d flags=%08x\n",
+       DPRINTF(1,("%s: start cmd %d arg=%08x data=%p dlen=%d flags=%08x, status=%#x\n",
           HDEVNAME(hp), cmd->c_opcode, cmd->c_arg, cmd->c_data,
-           cmd->c_datalen, cmd->c_flags));
+           cmd->c_datalen, cmd->c_flags, HREAD4(hp, SDHC_NINTR_STATUS)));

       /*
        * The maximum block length for commands should be the minimum
@@ -840,7 +1059,7 @@ sdhc_start_command(struct sdhc_host *hp,
               blkcount = cmd->c_datalen / blksize;
               if (cmd->c_datalen % blksize > 0) {
                       /* XXX: Split this command. (1.7.4) */
-                       aprint_error_dev(hp->sc->sc_dev,
+                       aprint_error_dev(sc->sc_dev,
                           "data not a multiple of %u bytes\n", blksize);
                       return EINVAL;
               }
@@ -848,7 +1067,7 @@ sdhc_start_command(struct sdhc_host *hp,

       /* Check limit imposed by 9-bit block count. (1.7.2) */
       if (blkcount > SDHC_BLOCK_COUNT_MAX) {
-               aprint_error_dev(hp->sc->sc_dev, "too much data\n");
+               aprint_error_dev(sc->sc_dev, "too much data\n");
               return EINVAL;
       }

@@ -904,8 +1123,10 @@ sdhc_start_command(struct sdhc_host *hp,

       mutex_enter(&hp->host_mtx);

-       /* Alert the user not to remove the card. */
-       HSET1(hp, SDHC_HOST_CTL, SDHC_LED_ON);
+       if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
+               /* Alert the user not to remove the card. */
+               HSET1(hp, SDHC_HOST_CTL, SDHC_LED_ON);
+       }

       /* Set DMA start address. */
       if (ISSET(mode, SDHC_DMA_ENABLE))
@@ -915,12 +1136,18 @@ sdhc_start_command(struct sdhc_host *hp,
        * Start a CPU data transfer.  Writing to the high order byte
        * of the SDHC_COMMAND register triggers the SD command. (1.5)
        */
-       HWRITE2(hp, SDHC_TRANSFER_MODE, mode);
-       HWRITE2(hp, SDHC_BLOCK_SIZE, blksize);
-       if (blkcount > 1)
-               HWRITE2(hp, SDHC_BLOCK_COUNT, blkcount);
-       HWRITE4(hp, SDHC_ARGUMENT, cmd->c_arg);
-       HWRITE2(hp, SDHC_COMMAND, command);
+       if (ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) {
+               HWRITE4(hp, SDHC_BLOCK_SIZE, blksize | (blkcount << 16));
+               HWRITE4(hp, SDHC_ARGUMENT, cmd->c_arg);
+               HWRITE4(hp, SDHC_TRANSFER_MODE, mode | (command << 16));
+       } else {
+               HWRITE2(hp, SDHC_TRANSFER_MODE, mode);
+               HWRITE2(hp, SDHC_BLOCK_SIZE, blksize);
+               if (blkcount > 1)
+                       HWRITE2(hp, SDHC_BLOCK_COUNT, blkcount);
+               HWRITE4(hp, SDHC_ARGUMENT, cmd->c_arg);
+               HWRITE2(hp, SDHC_COMMAND, command);
+       }

       mutex_exit(&hp->host_mtx);

@@ -966,6 +1193,11 @@ sdhc_transfer_data_dma(struct sdhc_host
       uint16_t remain;
       int error = 0;

+       KASSERT(HREAD2(hp, SDHC_NINTR_STATUS_EN) & SDHC_DMA_INTERRUPT);
+       KASSERT(HREAD2(hp, SDHC_NINTR_SIGNAL_EN) & SDHC_DMA_INTERRUPT);
+       KASSERT(HREAD2(hp, SDHC_NINTR_STATUS_EN) & SDHC_TRANSFER_COMPLETE);
+       KASSERT(HREAD2(hp, SDHC_NINTR_SIGNAL_EN) & SDHC_TRANSFER_COMPLETE);
+
       for (;;) {
               if (!sdhc_wait_intr(hp,
                   SDHC_DMA_INTERRUPT|SDHC_TRANSFER_COMPLETE,
@@ -1000,31 +1232,56 @@ static int
sdhc_transfer_data_pio(struct sdhc_host *hp, struct sdmmc_command *cmd)
{
       uint8_t *data = cmd->c_data;
-       int len, datalen;
-       int mask;
+       u_int len, datalen;
+       u_int imask;
+       u_int pmask;
       int error = 0;
+       void (*pio_func)(struct sdhc_host *, uint8_t *, u_int);

-       mask = ISSET(cmd->c_flags, SCF_CMD_READ) ?
-           SDHC_BUFFER_READ_ENABLE : SDHC_BUFFER_WRITE_ENABLE;
+       if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
+               imask = SDHC_BUFFER_READ_READY;
+               pmask = SDHC_BUFFER_READ_ENABLE;
+               if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
+                       pio_func = esdhc_read_data_pio;
+               } else {
+                       pio_func = sdhc_read_data_pio;
+               }
+       } else {
+               imask = SDHC_BUFFER_WRITE_READY;
+               pmask = SDHC_BUFFER_WRITE_ENABLE;
+               if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
+                       pio_func = esdhc_write_data_pio;
+               } else {
+                       pio_func = sdhc_write_data_pio;
+               }
+       }
       datalen = cmd->c_datalen;

+       KASSERT(HREAD2(hp, SDHC_NINTR_STATUS_EN) & imask);
+       KASSERT(HREAD2(hp, SDHC_NINTR_STATUS_EN) & SDHC_TRANSFER_COMPLETE);
+       KASSERT(HREAD2(hp, SDHC_NINTR_SIGNAL_EN) & SDHC_TRANSFER_COMPLETE);
+
       while (datalen > 0) {
-               if (!sdhc_wait_intr(hp,
-                   SDHC_BUFFER_READ_READY|SDHC_BUFFER_WRITE_READY,
-                   SDHC_BUFFER_TIMEOUT)) {
-                       error = ETIMEDOUT;
-                       break;
-               }
+               if (!ISSET(HREAD4(hp, SDHC_PRESENT_STATE), imask)) {
+                       if (ISSET(hp->sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) {
+                               HSET4(hp, SDHC_NINTR_SIGNAL_EN, imask);
+                       } else {
+                               HSET2(hp, SDHC_NINTR_SIGNAL_EN, imask);
+                       }
+                       if (!sdhc_wait_intr(hp, imask, SDHC_BUFFER_TIMEOUT)) {
+                               error = ETIMEDOUT;
+                               break;
+                       }

-               error = sdhc_wait_state(hp, mask, mask);
-               if (error)
-                       break;
+                       error = sdhc_wait_state(hp, pmask, pmask);
+                       if (error)
+                               break;
+               }

               len = MIN(datalen, cmd->c_blklen);
-               if (ISSET(cmd->c_flags, SCF_CMD_READ))
-                       sdhc_read_data_pio(hp, data, len);
-               else
-                       sdhc_write_data_pio(hp, data, len);
+               (*pio_func)(hp, data, len);
+               DPRINTF(2,("%s: pio data transfer %u @ %p\n",
+                   HDEVNAME(hp), len, data));

               data += len;
               datalen -= len;
@@ -1038,7 +1295,7 @@ sdhc_transfer_data_pio(struct sdhc_host
}

static void
-sdhc_read_data_pio(struct sdhc_host *hp, uint8_t *data, int datalen)
+sdhc_read_data_pio(struct sdhc_host *hp, uint8_t *data, u_int datalen)
{

       if (((__uintptr_t)data & 3) == 0) {
@@ -1078,7 +1335,7 @@ sdhc_read_data_pio(struct sdhc_host *hp,
}

static void
-sdhc_write_data_pio(struct sdhc_host *hp, uint8_t *data, int datalen)
+sdhc_write_data_pio(struct sdhc_host *hp, uint8_t *data, u_int datalen)
{

       if (((__uintptr_t)data & 3) == 0) {
@@ -1117,6 +1374,49 @@ sdhc_write_data_pio(struct sdhc_host *hp
       }
}

+
+static void
+esdhc_read_data_pio(struct sdhc_host *hp, uint8_t *data, u_int datalen)
+{
+       uint16_t status = HREAD2(hp, SDHC_NINTR_STATUS);
+       while (datalen > 3 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {
+               uint32_t v = HREAD4(hp, SDHC_DATA);
+               v = le32toh(v);
+               *(uint32_t *)data = v;
+               data += 4;
+               datalen -= 4;
+               status = HREAD2(hp, SDHC_NINTR_STATUS);
+       }
+
+       if (datalen > 0 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {
+               uint32_t v = HREAD4(hp, SDHC_DATA);
+               v = le32toh(v);
+               do {
+                       *data++ = v;
+                       v >>= 8;
+               } while (--datalen > 0);
+       }
+}
+
+static void
+esdhc_write_data_pio(struct sdhc_host *hp, uint8_t *data, u_int datalen)
+{
+       uint16_t status = HREAD2(hp, SDHC_NINTR_STATUS);
+       while (datalen > 3 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {
+               uint32_t v = *(uint32_t *)data;
+               v = htole32(v);
+               HWRITE4(hp, SDHC_DATA, v);
+               data += 4;
+               datalen -= 4;
+               status = HREAD2(hp, SDHC_NINTR_STATUS);
+       }
+       if (datalen > 0 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {
+               uint32_t v = *(uint32_t *)data;
+               v = htole32(v);
+               HWRITE4(hp, SDHC_DATA, v);
+       }
+}
+
/* Prepare for another command. */
static int
sdhc_soft_reset(struct sdhc_host *hp, int mask)
@@ -1139,6 +1439,10 @@ sdhc_soft_reset(struct sdhc_host *hp, in
               return ETIMEDOUT;
       }

+       if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
+               HWRITE4(hp, SDHC_DMA_CTL, SDHC_DMA_SNOOP);
+       }
+
       return 0;
}

@@ -1165,9 +1469,12 @@ sdhc_wait_intr(struct sdhc_host *hp, int
           hp->intr_error_status));

       /* Command timeout has higher priority than command complete. */
-       if (ISSET(status, SDHC_ERROR_INTERRUPT)) {
+       if (ISSET(status, SDHC_ERROR_INTERRUPT) || hp->intr_error_status) {
               hp->intr_error_status = 0;
-               (void)sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
+               hp->intr_status &= ~SDHC_ERROR_INTERRUPT;
+               if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
+                   (void)sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
+               }
               status = 0;
       }
       mutex_exit(&hp->intr_mtx);
@@ -1183,29 +1490,43 @@ sdhc_intr(void *arg)
{
       struct sdhc_softc *sc = (struct sdhc_softc *)arg;
       struct sdhc_host *hp;
-       int host;
       int done = 0;
       uint16_t status;
       uint16_t error;

       /* We got an interrupt, but we don't know from which slot. */
-       for (host = 0; host < sc->sc_nhosts; host++) {
+       for (size_t host = 0; host < sc->sc_nhosts; host++) {
               hp = sc->sc_host[host];
               if (hp == NULL)
                       continue;

-               /* Find out which interrupts are pending. */
-               status = HREAD2(hp, SDHC_NINTR_STATUS);
-               if (!ISSET(status, SDHC_NINTR_STATUS_MASK))
-                       continue; /* no interrupt for us */
-
-               /* Acknowledge the interrupts we are about to handle. */
-               HWRITE2(hp, SDHC_NINTR_STATUS, status);
-               DPRINTF(2,("%s: interrupt status=%x\n", HDEVNAME(hp),
-                   status));
-
-               if (!ISSET(status, SDHC_NINTR_STATUS_MASK))
-                       continue;
+               if (ISSET(sc->sc_flags, SDHC_FLAG_32BIT_ACCESS)) {
+                       /* Find out which interrupts are pending. */
+                       uint32_t xstatus = HREAD4(hp, SDHC_NINTR_STATUS);
+                       status = xstatus;
+                       error = xstatus >> 16;
+                       status |= (error ? SDHC_ERROR_INTERRUPT : 0);
+                       if (!ISSET(status, SDHC_NINTR_STATUS_MASK))
+                               continue; /* no interrupt for us */
+                       /* Acknowledge the interrupts we are about to handle. */
+                       HWRITE4(hp, SDHC_NINTR_STATUS, xstatus);
+               } else {
+                       /* Find out which interrupts are pending. */
+                       error = 0;
+                       status = HREAD2(hp, SDHC_NINTR_STATUS);
+                       if (!ISSET(status, SDHC_NINTR_STATUS_MASK))
+                               continue; /* no interrupt for us */
+                       /* Acknowledge the interrupts we are about to handle. */
+                       HWRITE2(hp, SDHC_NINTR_STATUS, status);
+                       if (ISSET(status, SDHC_ERROR_INTERRUPT)) {
+                               /* Acknowledge error interrupts. */
+                               error = HREAD2(hp, SDHC_EINTR_STATUS);
+                               HWRITE2(hp, SDHC_EINTR_STATUS, error);
+                       }
+               }
+
+               DPRINTF(2,("%s: interrupt status=%x error=%x\n", HDEVNAME(hp),
+                   status, error));

               /* Claim this interrupt. */
               done = 1;
@@ -1213,19 +1534,11 @@ sdhc_intr(void *arg)
               /*
                * Service error interrupts.
                */
-               if (ISSET(status, SDHC_ERROR_INTERRUPT)) {
-                       /* Acknowledge error interrupts. */
-                       error = HREAD2(hp, SDHC_EINTR_STATUS);
-                       HWRITE2(hp, SDHC_EINTR_STATUS, error);
-                       DPRINTF(2,("%s: error interrupt, status=%x\n",
-                           HDEVNAME(hp), error));
-
-                       if (ISSET(error, SDHC_CMD_TIMEOUT_ERROR|
-                           SDHC_DATA_TIMEOUT_ERROR)) {
-                               hp->intr_error_status |= error;
-                               hp->intr_status |= status;
-                               cv_broadcast(&hp->intr_cv);
-                       }
+               if (ISSET(error, SDHC_CMD_TIMEOUT_ERROR|
+                   SDHC_DATA_TIMEOUT_ERROR)) {
+                       hp->intr_error_status |= error;
+                       hp->intr_status |= status;
+                       cv_broadcast(&hp->intr_cv);
               }

               /*
@@ -1233,27 +1546,34 @@ sdhc_intr(void *arg)
                */
               if (ISSET(status, SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION)) {
                       sdmmc_needs_discover(hp->sdmmc);
-#if 0
-                       HCLR2(hp, SDHC_NINTR_STATUS_EN,
-                           status & (SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION));
-#endif
+                       if (ISSET(sc->sc_flags, SDHC_FLAG_ENHANCED)) {
+                               HCLR4(hp, SDHC_NINTR_STATUS_EN,
+                                   status & (SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION));
+                               HCLR4(hp, SDHC_NINTR_SIGNAL_EN,
+                                   status & (SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION));
+                       }
               }

               /*
                * Wake up the blocking process to service command
                * related interrupt(s).
                */
-               if (ISSET(status, SDHC_BUFFER_READ_READY|
-                   SDHC_BUFFER_WRITE_READY|SDHC_COMMAND_COMPLETE|
+               if (ISSET(status, SDHC_COMMAND_COMPLETE|
+                   SDHC_BUFFER_READ_READY|SDHC_BUFFER_WRITE_READY|
                   SDHC_TRANSFER_COMPLETE|SDHC_DMA_INTERRUPT)) {
                       hp->intr_status |= status;
+                       if (ISSET(sc->sc_flags, SDHC_FLAG_ENHANCED)) {
+                               HCLR4(hp, SDHC_NINTR_SIGNAL_EN,
+                                   status & (SDHC_BUFFER_READ_READY|SDHC_BUFFER_WRITE_READY));
+                       }
                       cv_broadcast(&hp->intr_cv);
               }

               /*
                * Service SD card interrupts.
                */
-               if (ISSET(status, SDHC_CARD_INTERRUPT)) {
+               if (!ISSET(sc->sc_flags, SDHC_FLAG_ENHANCED)
+                   && ISSET(status, SDHC_CARD_INTERRUPT)) {
                       DPRINTF(0,("%s: card interrupt\n", HDEVNAME(hp)));
                       HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_CARD_INTERRUPT);
                       sdmmc_card_intr(hp->sdmmc);
@@ -1270,8 +1590,9 @@ sdhc_dump_regs(struct sdhc_host *hp)

       printf("0x%02x PRESENT_STATE:    %x\n", SDHC_PRESENT_STATE,
           HREAD4(hp, SDHC_PRESENT_STATE));
-       printf("0x%02x POWER_CTL:        %x\n", SDHC_POWER_CTL,
-           HREAD1(hp, SDHC_POWER_CTL));
+       if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED))
+               printf("0x%02x POWER_CTL:        %x\n", SDHC_POWER_CTL,
+                   HREAD1(hp, SDHC_POWER_CTL));
       printf("0x%02x NINTR_STATUS:     %x\n", SDHC_NINTR_STATUS,
           HREAD2(hp, SDHC_NINTR_STATUS));
       printf("0x%02x EINTR_STATUS:     %x\n", SDHC_EINTR_STATUS,