Module Name: src
Committed By: riz
Date: Mon Jun 11 17:45:32 UTC 2012
Modified Files:
src/sys/arch/powerpc/booke/dev [netbsd-6]: pq3sdhc.c
src/sys/dev/sdmmc [netbsd-6]: sdhc.c
Log Message:
Pull up following revision(s) (requested by matt in ticket #254):
sys/arch/powerpc/booke/dev/pq3sdhc.c: revision 1.4
sys/dev/sdmmc/sdhc.c: revision 1.11
sys/dev/sdmmc/sdhc.c: revision 1.13
Use the new 32-bit and ESDHC support in sdhc.c
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)).
Do not read past array end, found by gcc -O3.
This could cause to HWRITE4() a bad value, but maybe last 2 bytes are
probably ignored by hardware anyway.
To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.3.8.1 src/sys/arch/powerpc/booke/dev/pq3sdhc.c
cvs rdiff -u -r1.10 -r1.10.2.1 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/arch/powerpc/booke/dev/pq3sdhc.c
diff -u src/sys/arch/powerpc/booke/dev/pq3sdhc.c:1.3 src/sys/arch/powerpc/booke/dev/pq3sdhc.c:1.3.8.1
--- src/sys/arch/powerpc/booke/dev/pq3sdhc.c:1.3 Wed Jun 29 06:12:10 2011
+++ src/sys/arch/powerpc/booke/dev/pq3sdhc.c Mon Jun 11 17:45:32 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: pq3sdhc.c,v 1.3 2011/06/29 06:12:10 matt Exp $ */
+/* $NetBSD: pq3sdhc.c,v 1.3.8.1 2012/06/11 17:45:32 riz Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -29,7 +29,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pq3sdhc.c,v 1.3 2011/06/29 06:12:10 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pq3sdhc.c,v 1.3.8.1 2012/06/11 17:45:32 riz Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -53,7 +53,6 @@ static int pq3sdhc_match(device_t, cfdat
static void pq3sdhc_attach(device_t, device_t, void *);
struct pq3sdhc_softc {
- struct powerpc_bus_space sc_mybst;
struct sdhc_softc sc;
bus_space_tag_t sc_bst;
bus_space_handle_t sc_bsh;
@@ -64,114 +63,6 @@ struct pq3sdhc_softc {
CFATTACH_DECL_NEW(pq3sdhc, sizeof(struct pq3sdhc_softc),
pq3sdhc_match, pq3sdhc_attach, NULL, NULL);
-static uint8_t
-pq3sdhc_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
-{
- const struct pq3sdhc_softc * const sc = (const void *) t;
-
- KASSERT((o & -4) != SDHC_DATA);
-
- const uint32_t v = bus_space_read_4(sc->sc_bst, h, o & -4);
-
- return v >> ((o & 3) * 8);
-}
-
-static uint16_t
-pq3sdhc_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
-{
- const struct pq3sdhc_softc * const sc = (const void *) t;
-
- KASSERT((o & 1) == 0);
- KASSERT((o & -4) != SDHC_DATA);
-
- uint32_t v = bus_space_read_4(sc->sc_bst, h, o & -4);
-
- if (__predict_false(o == SDHC_HOST_VER))
- return v;
- if (__predict_false(o == SDHC_NINTR_STATUS)) {
- v |= SDHC_ERROR_INTERRUPT * ((v > 0xffff) != 0);
- if (v != 0)
- printf("get(INTR_STATUS)=%#x\n", v);
- }
- if (__predict_false(o == SDHC_EINTR_STATUS)) {
- if (v != 0)
- printf("get(INTR_STATUS)=%#x\n", v);
- }
-
- return v >> ((o & 2) * 8);
-}
-
-static uint32_t
-pq3sdhc_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
-{
- const struct pq3sdhc_softc * const sc = (const void *) t;
-
- KASSERT((o & 3) == 0);
-
- uint32_t v = bus_space_read_4(sc->sc_bst, h, o & -4);
-
- if (__predict_false(o == SDHC_DATA))
- v = htole32(v);
-
- return v;
-}
-
-static void
-pq3sdhc_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint8_t nv)
-{
- const struct pq3sdhc_softc * const sc = (const void *) t;
- KASSERT((o & -4) != SDHC_DATA);
- uint32_t v = bus_space_read_4(sc->sc_bst, h, o & -4);
- const u_int shift = (o & 3) * 8;
-
- if (o == SDHC_HOST_CTL) {
- nv &= ~EDSHC_HOST_CTL_RES;
- }
-
- v &= ~(0xff << shift);
- v |= (nv << shift);
-
- bus_space_write_4(sc->sc_bst, h, o & -4, v);
-}
-
-static void
-pq3sdhc_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint16_t nv)
-{
- const struct pq3sdhc_softc * const sc = (const void *) t;
- KASSERT((o & 1) == 0);
- KASSERT((o & -4) != SDHC_DATA);
- const u_int shift = (o & 2) * 8;
- uint32_t v;
-
- /*
- * Since NINTR_STATUS and EINTR_STATUS are W1C, don't bother getting
- * the previous value since we'd clear them.
- */
- if (__predict_true((o & -4) != SDHC_NINTR_STATUS)) {
- v = bus_space_read_4(sc->sc_bst, h, o & -4);
- v &= ~(0xffff << shift);
- v |= nv << shift;
- } else {
- v = nv << shift;
- printf("put(INTR_STATUS,%#x)\n", v);
- }
-
- bus_space_write_4(sc->sc_bst, h, o & -4, v);
-}
-
-static void
-pq3sdhc_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, uint32_t v)
-{
- const struct pq3sdhc_softc * const sc = (const void *) t;
-
- KASSERT((o & 3) == 0);
-
- if (__predict_false(o == SDHC_DATA))
- v = le32toh(v);
-
- bus_space_write_4(sc->sc_bst, h, o & -4, v);
-}
-
static int
pq3sdhc_match(device_t parent, cfdata_t cf, void *aux)
{
@@ -194,19 +85,12 @@ pq3sdhc_attach(device_t parent, device_t
psc->sc_children |= cna->cna_childmask;
sc->sc.sc_dmat = cna->cna_dmat;
sc->sc.sc_dev = self;
- //sc->sc.sc_flags |= SDHC_FLAG_USE_DMA;
- sc->sc.sc_flags |= SDHC_FLAG_HAVE_DVS;
+ sc->sc.sc_flags |= SDHC_FLAG_USE_DMA;
+ sc->sc.sc_flags |=
+ SDHC_FLAG_HAVE_DVS | SDHC_FLAG_32BIT_ACCESS | SDHC_FLAG_ENHANCED;
sc->sc.sc_host = sc->sc_hosts;
sc->sc.sc_clkbase = board_info_get_number("bus-frequency") / 2000;
sc->sc_bst = cna->cna_memt;
- sc->sc_mybst = *cna->cna_memt;
-
- sc->sc_mybst.pbs_scalar.pbss_read_1 = pq3sdhc_read_1;
- sc->sc_mybst.pbs_scalar.pbss_read_2 = pq3sdhc_read_2;
- sc->sc_mybst.pbs_scalar.pbss_read_4 = pq3sdhc_read_4;
- sc->sc_mybst.pbs_scalar.pbss_write_1 = pq3sdhc_write_1;
- sc->sc_mybst.pbs_scalar.pbss_write_2 = pq3sdhc_write_2;
- sc->sc_mybst.pbs_scalar.pbss_write_4 = pq3sdhc_write_4;
error = bus_space_map(sc->sc_bst, cnl->cnl_addr, cnl->cnl_size, 0,
&sc->sc_bsh);
@@ -229,7 +113,7 @@ pq3sdhc_attach(device_t parent, device_t
aprint_normal_dev(self, "interrupting on irq %d\n",
cnl->cnl_intrs[0]);
- error = sdhc_host_found(&sc->sc, &sc->sc_mybst, sc->sc_bsh,
+ error = sdhc_host_found(&sc->sc, sc->sc_bst, sc->sc_bsh,
cnl->cnl_size);
if (error != 0) {
aprint_error_dev(self, "couldn't initialize host, error=%d\n",
Index: src/sys/dev/sdmmc/sdhc.c
diff -u src/sys/dev/sdmmc/sdhc.c:1.10 src/sys/dev/sdmmc/sdhc.c:1.10.2.1
--- src/sys/dev/sdmmc/sdhc.c:1.10 Thu Feb 2 22:49:17 2012
+++ src/sys/dev/sdmmc/sdhc.c Mon Jun 11 17:45:32 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: sdhc.c,v 1.10 2012/02/02 22:49:17 nonaka Exp $ */
+/* $NetBSD: sdhc.c,v 1.10.2.1 2012/06/11 17:45:32 riz 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.10.2.1 2012/06/11 17:45:32 riz 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,