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,