diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-05-01 16:04:40 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-05-01 16:04:40 +0000 |
commit | 6bd1ebc4f6372213e2d48e527b38f1d9c3c14f0e (patch) | |
tree | 80ea831bd0078578a4716851e31069b80e26e830 /sys/dev/sdmmc/sdhc.c | |
parent | 9350001d745387d778c568a6f38cc76cb9f0beb8 (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.c | 35 |
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) { |