summaryrefslogtreecommitdiff
path: root/sys/dev/sdmmc/sdhc.c
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2016-05-01 16:04:40 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2016-05-01 16:04:40 +0000
commit6bd1ebc4f6372213e2d48e527b38f1d9c3c14f0e (patch)
tree80ea831bd0078578a4716851e31069b80e26e830 /sys/dev/sdmmc/sdhc.c
parent9350001d745387d778c568a6f38cc76cb9f0beb8 (diff)
Add support for changing the bus width to the sdmmc subsystem and the sdhc(4)
controller. Use this to switch SD cards to a 4-bit bus if they support it. ok deraadt@, jsg@
Diffstat (limited to 'sys/dev/sdmmc/sdhc.c')
-rw-r--r--sys/dev/sdmmc/sdhc.c35
1 files changed, 34 insertions, 1 deletions
diff --git a/sys/dev/sdmmc/sdhc.c b/sys/dev/sdmmc/sdhc.c
index a85044b8475..dc0350a729b 100644
--- a/sys/dev/sdmmc/sdhc.c
+++ b/sys/dev/sdmmc/sdhc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sdhc.c,v 1.45 2016/04/30 13:33:35 kettenis Exp $ */
+/* $OpenBSD: sdhc.c,v 1.46 2016/05/01 16:04:39 kettenis Exp $ */
/*
* Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
@@ -87,6 +87,7 @@ int sdhc_host_maxblklen(sdmmc_chipset_handle_t);
int sdhc_card_detect(sdmmc_chipset_handle_t);
int sdhc_bus_power(sdmmc_chipset_handle_t, u_int32_t);
int sdhc_bus_clock(sdmmc_chipset_handle_t, int);
+int sdhc_bus_width(sdmmc_chipset_handle_t, int);
void sdhc_card_intr_mask(sdmmc_chipset_handle_t, int);
void sdhc_card_intr_ack(sdmmc_chipset_handle_t);
void sdhc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *);
@@ -117,6 +118,7 @@ struct sdmmc_chip_functions sdhc_functions = {
/* bus power and clock frequency */
sdhc_bus_power,
sdhc_bus_clock,
+ sdhc_bus_width,
/* command execution */
sdhc_exec_command,
/* card interrupt */
@@ -289,6 +291,7 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot,
saa.saa_busname = "sdmmc";
saa.sct = &sdhc_functions;
saa.sch = hp;
+ saa.caps = SMC_CAPS_4BIT_MODE;
saa.dmat = sc->sc_dmat;
if (ISSET(hp->flags, SHF_USE_DMA))
saa.caps |= SMC_CAPS_DMA;
@@ -599,6 +602,36 @@ ret:
return error;
}
+int
+sdhc_bus_width(sdmmc_chipset_handle_t sch, int width)
+{
+ struct sdhc_host *hp = (struct sdhc_host *)sch;
+ int reg;
+ int s;
+
+ if (width != 1 && width != 4 && width != 8)
+ return 1;
+
+ s = splsdmmc();
+
+ reg = HREAD1(hp, SDHC_HOST_CTL);
+ reg &= ~SDHC_4BIT_MODE;
+ if (SDHC_SPEC_VERSION(hp->version) >= SDHC_SPEC_V3) {
+ reg &= ~SDHC_8BIT_MODE;
+ }
+ if (width == 4) {
+ reg |= SDHC_4BIT_MODE;
+ } else if (width == 8) {
+ KASSERT(SDHC_SPEC_VERSION(hp->version) >= SDHC_SPEC_V3);
+ reg |= SDHC_8BIT_MODE;
+ }
+ HWRITE1(hp, SDHC_HOST_CTL, reg);
+
+ splx(s);
+
+ return 0;
+}
+
void
sdhc_card_intr_mask(sdmmc_chipset_handle_t sch, int enable)
{