Module Name:    src
Committed By:   matt
Date:           Thu Feb 23 21:06:21 UTC 2012

Modified Files:
        src/sys/dev/sdmmc: sdhc.c

Log Message:
Support 32-bit only access to the SDHC registers.
Add support for FreeScale "Enhanced" SDHC port.
Add support for CGM mode (XLP and BCM2835 (Arason)).


To generate a diff of this commit:
cvs rdiff -u -r1.10 -r1.11 src/sys/dev/sdmmc/sdhc.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/sdmmc/sdhc.c
diff -u src/sys/dev/sdmmc/sdhc.c:1.10 src/sys/dev/sdmmc/sdhc.c:1.11
--- src/sys/dev/sdmmc/sdhc.c:1.10	Thu Feb  2 22:49:17 2012
+++ src/sys/dev/sdmmc/sdhc.c	Thu Feb 23 21:06:21 2012
@@ -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,26 @@ 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);
+				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 +448,24 @@ 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) {
+				HWRITE4(hp, i,
+				    (hp->regs[i+0] << 0)
+				    |(hp->regs[i+1] << 8)
+				    |(hp->regs[i+2] << 16)
+				    |(hp->regs[i+3] << 24));
+			}
+		} else {
+			for (size_t i = 0; i < sizeof hp->regs; i++) {
+				HWRITE1(hp, i, hp->regs[i]);
+			}
+		}
 	}
 	return true;
 }
@@ -389,10 +475,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 +492,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 +514,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 +585,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 +622,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 +636,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 +678,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 +735,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 +758,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 +852,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 +864,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 +894,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 +912,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 +941,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 +1000,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 +1029,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 +1051,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 +1059,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 +1115,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 +1128,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 +1185,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 +1224,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 +1287,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 +1327,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 +1366,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 +1431,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 +1461,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 +1482,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 +1526,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 +1538,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 +1582,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,

Reply via email to