diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-05-05 11:01:09 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-05-05 11:01:09 +0000 |
commit | 6251683a85f7efb0ecd95910fb03ebd1c20b30ac (patch) | |
tree | d031f5ff4c52f4912000d71aab493ad77bcf7bdf | |
parent | 8f0bc08bb64f7d54716657b84582e0e73d6a1d71 (diff) |
Add Dual Data Rate support for eMMC at 52MHz.
-rw-r--r-- | sys/arch/arm/xscale/pxa2x0_mmc.c | 6 | ||||
-rw-r--r-- | sys/arch/armv7/exynos/exesdhc.c | 6 | ||||
-rw-r--r-- | sys/arch/armv7/imx/imxesdhc.c | 6 | ||||
-rw-r--r-- | sys/arch/armv7/omap/ommmc.c | 6 | ||||
-rw-r--r-- | sys/dev/ic/rtsx.c | 6 | ||||
-rw-r--r-- | sys/dev/ic/w83l518d_sdmmc.c | 6 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdhc.c | 67 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmc.c | 8 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmc_io.c | 4 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmc_mem.c | 104 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmcchip.h | 21 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmcreg.h | 10 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmcvar.h | 9 |
13 files changed, 190 insertions, 69 deletions
diff --git a/sys/arch/arm/xscale/pxa2x0_mmc.c b/sys/arch/arm/xscale/pxa2x0_mmc.c index 434013cb71f..26c4bdd9c02 100644 --- a/sys/arch/arm/xscale/pxa2x0_mmc.c +++ b/sys/arch/arm/xscale/pxa2x0_mmc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pxa2x0_mmc.c,v 1.12 2016/05/01 16:04:39 kettenis Exp $ */ +/* $OpenBSD: pxa2x0_mmc.c,v 1.13 2016/05/05 11:01:08 kettenis Exp $ */ /* * Copyright (c) 2007 Uwe Stuehler <uwe@openbsd.org> @@ -56,7 +56,7 @@ u_int32_t pxammc_host_ocr(sdmmc_chipset_handle_t); int pxammc_host_maxblklen(sdmmc_chipset_handle_t); int pxammc_card_detect(sdmmc_chipset_handle_t); int pxammc_bus_power(sdmmc_chipset_handle_t, u_int32_t); -int pxammc_bus_clock(sdmmc_chipset_handle_t, int); +int pxammc_bus_clock(sdmmc_chipset_handle_t, int, int); void pxammc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *); void pxammc_clock_stop(struct pxammc_softc *); void pxammc_clock_start(struct pxammc_softc *); @@ -278,7 +278,7 @@ pxammc_bus_power(sdmmc_chipset_handle_t sch, u_int32_t ocr) } int -pxammc_bus_clock(sdmmc_chipset_handle_t sch, int freq) +pxammc_bus_clock(sdmmc_chipset_handle_t sch, int freq, int timing) { struct pxammc_softc *sc = sch; int actfreq = 19500; /* KHz */ diff --git a/sys/arch/armv7/exynos/exesdhc.c b/sys/arch/armv7/exynos/exesdhc.c index 7e03d5f5245..73ff91e2ac5 100644 --- a/sys/arch/armv7/exynos/exesdhc.c +++ b/sys/arch/armv7/exynos/exesdhc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: exesdhc.c,v 1.6 2016/05/01 16:04:39 kettenis Exp $ */ +/* $OpenBSD: exesdhc.c,v 1.7 2016/05/05 11:01:08 kettenis Exp $ */ /* * Copyright (c) 2009 Dale Rahn <drahn@openbsd.org> * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -197,7 +197,7 @@ uint32_t exesdhc_host_ocr(sdmmc_chipset_handle_t); int exesdhc_host_maxblklen(sdmmc_chipset_handle_t); int exesdhc_card_detect(sdmmc_chipset_handle_t); int exesdhc_bus_power(sdmmc_chipset_handle_t, uint32_t); -int exesdhc_bus_clock(sdmmc_chipset_handle_t, int); +int exesdhc_bus_clock(sdmmc_chipset_handle_t, int, int); void exesdhc_card_intr_mask(sdmmc_chipset_handle_t, int); void exesdhc_card_intr_ack(sdmmc_chipset_handle_t); void exesdhc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *); @@ -517,7 +517,7 @@ exesdhc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) * Return zero on success. */ int -exesdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq) +exesdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq, int timing) { struct exesdhc_softc *sc = sch; int div, pre_div, cur_freq, s; diff --git a/sys/arch/armv7/imx/imxesdhc.c b/sys/arch/armv7/imx/imxesdhc.c index 2a7f934bb65..43119ef05e0 100644 --- a/sys/arch/armv7/imx/imxesdhc.c +++ b/sys/arch/armv7/imx/imxesdhc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: imxesdhc.c,v 1.14 2016/05/01 16:04:39 kettenis Exp $ */ +/* $OpenBSD: imxesdhc.c,v 1.15 2016/05/05 11:01:08 kettenis Exp $ */ /* * Copyright (c) 2009 Dale Rahn <drahn@openbsd.org> * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -195,7 +195,7 @@ uint32_t imxesdhc_host_ocr(sdmmc_chipset_handle_t); int imxesdhc_host_maxblklen(sdmmc_chipset_handle_t); int imxesdhc_card_detect(sdmmc_chipset_handle_t); int imxesdhc_bus_power(sdmmc_chipset_handle_t, uint32_t); -int imxesdhc_bus_clock(sdmmc_chipset_handle_t, int); +int imxesdhc_bus_clock(sdmmc_chipset_handle_t, int, int); void imxesdhc_card_intr_mask(sdmmc_chipset_handle_t, int); void imxesdhc_card_intr_ack(sdmmc_chipset_handle_t); void imxesdhc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *); @@ -555,7 +555,7 @@ imxesdhc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) * Return zero on success. */ int -imxesdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq) +imxesdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq, int timing) { struct imxesdhc_softc *sc = sch; int div, pre_div, cur_freq, s; diff --git a/sys/arch/armv7/omap/ommmc.c b/sys/arch/armv7/omap/ommmc.c index 92a585bd5a5..1e7329375e5 100644 --- a/sys/arch/armv7/omap/ommmc.c +++ b/sys/arch/armv7/omap/ommmc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ommmc.c,v 1.18 2016/05/02 07:38:34 jsg Exp $ */ +/* $OpenBSD: ommmc.c,v 1.19 2016/05/05 11:01:08 kettenis Exp $ */ /* * Copyright (c) 2009 Dale Rahn <drahn@openbsd.org> @@ -228,7 +228,7 @@ uint32_t ommmc_host_ocr(sdmmc_chipset_handle_t); int ommmc_host_maxblklen(sdmmc_chipset_handle_t); int ommmc_card_detect(sdmmc_chipset_handle_t); int ommmc_bus_power(sdmmc_chipset_handle_t, uint32_t); -int ommmc_bus_clock(sdmmc_chipset_handle_t, int); +int ommmc_bus_clock(sdmmc_chipset_handle_t, int, int); int ommmc_bus_width(sdmmc_chipset_handle_t, int); void ommmc_card_intr_mask(sdmmc_chipset_handle_t, int); void ommmc_card_intr_ack(sdmmc_chipset_handle_t); @@ -631,7 +631,7 @@ ommmc_clock_divisor(struct ommmc_softc *sc, uint32_t freq) * Return zero on success. */ int -ommmc_bus_clock(sdmmc_chipset_handle_t sch, int freq) +ommmc_bus_clock(sdmmc_chipset_handle_t sch, int freq, int timing) { int error = 0; struct ommmc_softc *sc = sch; diff --git a/sys/dev/ic/rtsx.c b/sys/dev/ic/rtsx.c index ba734292ca6..9d1c379c130 100644 --- a/sys/dev/ic/rtsx.c +++ b/sys/dev/ic/rtsx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rtsx.c,v 1.13 2016/05/01 16:04:39 kettenis Exp $ */ +/* $OpenBSD: rtsx.c,v 1.14 2016/05/05 11:01:08 kettenis Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -95,7 +95,7 @@ u_int32_t rtsx_host_ocr(sdmmc_chipset_handle_t); int rtsx_host_maxblklen(sdmmc_chipset_handle_t); int rtsx_card_detect(sdmmc_chipset_handle_t); int rtsx_bus_power(sdmmc_chipset_handle_t, u_int32_t); -int rtsx_bus_clock(sdmmc_chipset_handle_t, int); +int rtsx_bus_clock(sdmmc_chipset_handle_t, int, int); void rtsx_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *); int rtsx_init(struct rtsx_softc *, int); void rtsx_soft_reset(struct rtsx_softc *); @@ -614,7 +614,7 @@ ret: * Return zero on success. */ int -rtsx_bus_clock(sdmmc_chipset_handle_t sch, int freq) +rtsx_bus_clock(sdmmc_chipset_handle_t sch, int freq, int timing) { struct rtsx_softc *sc = sch; int s; diff --git a/sys/dev/ic/w83l518d_sdmmc.c b/sys/dev/ic/w83l518d_sdmmc.c index 9e867ca7a12..76c7a10c8d6 100644 --- a/sys/dev/ic/w83l518d_sdmmc.c +++ b/sys/dev/ic/w83l518d_sdmmc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: w83l518d_sdmmc.c,v 1.3 2016/05/01 16:04:39 kettenis Exp $ */ +/* $OpenBSD: w83l518d_sdmmc.c,v 1.4 2016/05/05 11:01:08 kettenis Exp $ */ /* $NetBSD: w83l518d_sdmmc.c,v 1.1 2009/09/30 20:44:50 jmcneill Exp $ */ /* @@ -65,7 +65,7 @@ int wb_sdmmc_card_detect(sdmmc_chipset_handle_t); int wb_sdmmc_write_protect(sdmmc_chipset_handle_t); #endif int wb_sdmmc_bus_power(sdmmc_chipset_handle_t, uint32_t); -int wb_sdmmc_bus_clock(sdmmc_chipset_handle_t, int); +int wb_sdmmc_bus_clock(sdmmc_chipset_handle_t, int, int); int wb_sdmmc_bus_width(sdmmc_chipset_handle_t, int); void wb_sdmmc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *); @@ -278,7 +278,7 @@ wb_sdmmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) } int -wb_sdmmc_bus_clock(sdmmc_chipset_handle_t sch, int freq) +wb_sdmmc_bus_clock(sdmmc_chipset_handle_t sch, int freq, int timing) { struct wb_softc *wb = sch; uint8_t clk; diff --git a/sys/dev/sdmmc/sdhc.c b/sys/dev/sdmmc/sdhc.c index be29a5f8efa..47bcada5e87 100644 --- a/sys/dev/sdmmc/sdhc.c +++ b/sys/dev/sdmmc/sdhc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdhc.c,v 1.50 2016/05/04 14:05:32 kettenis Exp $ */ +/* $OpenBSD: sdhc.c,v 1.51 2016/05/05 11:01:08 kettenis Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -86,10 +86,11 @@ u_int32_t sdhc_host_ocr(sdmmc_chipset_handle_t); 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_clock(sdmmc_chipset_handle_t, int, 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); +int sdhc_signal_voltage(sdmmc_chipset_handle_t, int); void sdhc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *); int sdhc_start_command(struct sdhc_host *, struct sdmmc_command *); int sdhc_wait_state(struct sdhc_host *, u_int32_t, u_int32_t); @@ -123,7 +124,9 @@ struct sdmmc_chip_functions sdhc_functions = { sdhc_exec_command, /* card interrupt */ sdhc_card_intr_mask, - sdhc_card_intr_ack + sdhc_card_intr_ack, + /* UHS functions */ + sdhc_signal_voltage }; struct cfdriver sdhc_cd = { @@ -305,8 +308,13 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot, saa.caps |= SMC_CAPS_MMC_HIGHSPEED; if (SDHC_SPEC_VERSION(hp->version) >= SDHC_SPEC_V3) { + uint32_t caps2 = HREAD4(hp, SDHC_CAPABILITIES2); + if (ISSET(caps, SDHC_8BIT_MODE_SUPP)) saa.caps |= SMC_CAPS_8BIT_MODE; + + if (ISSET(caps2, SDHC_DDR50_SUPP)) + saa.caps |= SMC_CAPS_MMC_DDR52; } hp->sdmmc = config_found(&sc->sc_dev, &saa, NULL); @@ -542,7 +550,7 @@ sdhc_clock_divisor(struct sdhc_host *hp, u_int freq) * Return zero on success. */ int -sdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq) +sdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq, int timing) { struct sdhc_host *hp = sch; int s; @@ -567,6 +575,20 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq) if (freq == SDMMC_SDCLK_OFF) goto ret; + if (timing == SDMMC_TIMING_LEGACY) + HCLR1(hp, SDHC_HOST_CTL, SDHC_HIGH_SPEED); + else + HSET1(hp, SDHC_HOST_CTL, SDHC_HIGH_SPEED); + + if (SDHC_SPEC_VERSION(hp->version) >= SDHC_SPEC_V3) { + switch (timing) { + case SDMMC_TIMING_MMC_DDR52: + HCLR2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_MASK); + HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_DDR50); + break; + } + } + /* * Set the minimum base clock frequency divisor. */ @@ -600,11 +622,6 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq) */ HSET2(hp, SDHC_CLOCK_CTL, SDHC_SDCLK_ENABLE); - if (freq > 26000) - HSET1(hp, SDHC_HOST_CTL, SDHC_HIGH_SPEED); - else - HCLR1(hp, SDHC_HOST_CTL, SDHC_HIGH_SPEED); - ret: splx(s); return error; @@ -618,7 +635,7 @@ sdhc_bus_width(sdmmc_chipset_handle_t sch, int width) int s; if (width != 1 && width != 4 && width != 8) - return 1; + return EINVAL; s = splsdmmc(); @@ -663,6 +680,36 @@ sdhc_card_intr_ack(sdmmc_chipset_handle_t sch) } int +sdhc_signal_voltage(sdmmc_chipset_handle_t sch, int signal_voltage) +{ + struct sdhc_host *hp = sch; + + if (SDHC_SPEC_VERSION(hp->version) < SDHC_SPEC_V3) + return EINVAL; + + switch (signal_voltage) { + case SDMMC_SIGNAL_VOLTAGE_180: + HSET2(hp, SDHC_HOST_CTL2, SDHC_1_8V_SIGNAL_EN); + break; + case SDMMC_SIGNAL_VOLTAGE_330: + HCLR2(hp, SDHC_HOST_CTL2, SDHC_1_8V_SIGNAL_EN); + break; + default: + return EINVAL; + } + + /* Regulator output shall be stable within 5 ms. */ + sdmmc_delay(5000); + + /* Host controller clears this bit if 1.8V signalling fails. */ + if (signal_voltage == SDMMC_SIGNAL_VOLTAGE_180 && + !ISSET(HREAD4(hp, SDHC_HOST_CTL2), SDHC_1_8V_SIGNAL_EN)) + return EIO; + + return 0; +} + +int sdhc_wait_state(struct sdhc_host *hp, u_int32_t mask, u_int32_t value) { u_int32_t state; diff --git a/sys/dev/sdmmc/sdmmc.c b/sys/dev/sdmmc/sdmmc.c index e67338aebaa..e09391698e5 100644 --- a/sys/dev/sdmmc/sdmmc.c +++ b/sys/dev/sdmmc/sdmmc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmc.c,v 1.43 2016/05/04 09:30:06 kettenis Exp $ */ +/* $OpenBSD: sdmmc.c,v 1.44 2016/05/05 11:01:08 kettenis Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -420,7 +420,8 @@ sdmmc_enable(struct sdmmc_softc *sc) /* * Select the minimum clock frequency. */ - error = sdmmc_chip_bus_clock(sc->sct, sc->sch, SDMMC_SDCLK_400KHZ); + error = sdmmc_chip_bus_clock(sc->sct, sc->sch, + SDMMC_SDCLK_400KHZ, SDMMC_TIMING_LEGACY); if (error != 0) { printf("%s: can't supply clock\n", DEVNAME(sc)); goto err; @@ -456,7 +457,8 @@ sdmmc_disable(struct sdmmc_softc *sc) (void)sdmmc_select_card(sc, NULL); /* Turn off bus power and clock. */ - (void)sdmmc_chip_bus_clock(sc->sct, sc->sch, SDMMC_SDCLK_OFF); + (void)sdmmc_chip_bus_clock(sc->sct, sc->sch, + SDMMC_SDCLK_OFF, SDMMC_TIMING_LEGACY); (void)sdmmc_chip_bus_power(sc->sct, sc->sch, 0); } diff --git a/sys/dev/sdmmc/sdmmc_io.c b/sys/dev/sdmmc/sdmmc_io.c index 3c9372aa965..13c95710f4f 100644 --- a/sys/dev/sdmmc/sdmmc_io.c +++ b/sys/dev/sdmmc/sdmmc_io.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmc_io.c,v 1.24 2016/05/04 09:30:06 kettenis Exp $ */ +/* $OpenBSD: sdmmc_io.c,v 1.25 2016/05/05 11:01:08 kettenis Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -185,7 +185,7 @@ sdmmc_io_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) if (sf->number == 0) { /* XXX respect host and card capabilities */ (void)sdmmc_chip_bus_clock(sc->sct, sc->sch, - SDMMC_SDCLK_25MHZ); + 25000, SDMMC_TIMING_LEGACY); } return 0; diff --git a/sys/dev/sdmmc/sdmmc_mem.c b/sys/dev/sdmmc/sdmmc_mem.c index 8b5bb829fa1..9b8a288883f 100644 --- a/sys/dev/sdmmc/sdmmc_mem.c +++ b/sys/dev/sdmmc/sdmmc_mem.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmc_mem.c,v 1.27 2016/05/04 09:30:06 kettenis Exp $ */ +/* $OpenBSD: sdmmc_mem.c,v 1.28 2016/05/05 11:01:08 kettenis Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -579,7 +579,7 @@ sdmmc_be512_to_bitfield512(sdmmc_bitfield512_t *buf) { int sdmmc_mem_sd_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) { - int support_func, best_func, bus_clock, error; + int support_func, best_func, bus_clock, timing, error; sdmmc_bitfield512_t status; /* Switch Function Status */ uint32_t raw_scr[2]; @@ -604,6 +604,7 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) best_func = 0; bus_clock = 25000; + timing = SDMMC_TIMING_LEGACY; if (sf->scr.sd_spec >= SCR_SD_SPEC_VER_1_10 && ISSET(sf->csd.ccc, SD_CSD_CCC_SWITCH)) { DPRINTF(("%s: switch func mode 0\n", DEVNAME(sc))); @@ -630,6 +631,7 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) return error; } bus_clock = 50000; + timing = SDMMC_TIMING_HIGHSPEED; /* Wait 400KHz x 8 clock (2.5us * 8 + slop) */ delay(25); @@ -637,7 +639,7 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) } /* change bus clock */ - error = sdmmc_chip_bus_clock(sc->sct, sc->sch, bus_clock); + error = sdmmc_chip_bus_clock(sc->sct, sc->sch, bus_clock, timing); if (error) { printf("%s: can't change bus clock\n", DEVNAME(sc)); return error; @@ -650,10 +652,11 @@ int sdmmc_mem_mmc_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) { int width, value; + int card_type; int error = 0; u_int8_t ext_csd[512]; - int speed = 0; - int hs_timing = 0; + int speed = 20000; + int timing = SDMMC_TIMING_LEGACY; u_int32_t sectors = 0; if (sf->csd.mmcver >= MMC_CSD_MMCVER_4_0) { @@ -666,16 +669,56 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) return error; } - if (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_F_52M) { + card_type = ext_csd[EXT_CSD_CARD_TYPE]; + + if (card_type & EXT_CSD_CARD_TYPE_F_52M_1_8V && + ISSET(sc->sc_caps, SMC_CAPS_MMC_DDR52)) { + speed = 52000; + timing = SDMMC_TIMING_MMC_DDR52; + } else if (card_type & EXT_CSD_CARD_TYPE_F_52M && + ISSET(sc->sc_caps, SMC_CAPS_MMC_HIGHSPEED)) { speed = 52000; - hs_timing = 1; - } else if (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_F_26M) { + timing = SDMMC_TIMING_HIGHSPEED; + } else if (card_type & EXT_CSD_CARD_TYPE_F_26M) { speed = 26000; } else { printf("%s: unknown CARD_TYPE 0x%x\n", DEVNAME(sc), ext_csd[EXT_CSD_CARD_TYPE]); } + if (timing != SDMMC_TIMING_LEGACY) { + /* switch to high speed timing */ + error = sdmmc_mem_mmc_switch(sf, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_HS_TIMING, EXT_CSD_HS_TIMING_HS); + if (error != 0) { + printf("%s: can't change high speed\n", + DEVNAME(sc)); + return error; + } + + sdmmc_delay(10000); + } + + error = sdmmc_chip_bus_clock(sc->sct, sc->sch, speed, SDMMC_TIMING_HIGHSPEED); + if (error != 0) { + printf("%s: can't change bus clock\n", DEVNAME(sc)); + return error; + } + + if (timing != SDMMC_TIMING_LEGACY) { + /* read EXT_CSD again */ + error = sdmmc_mem_send_cxd_data(sc, + MMC_SEND_EXT_CSD, ext_csd, sizeof(ext_csd)); + if (error != 0) { + printf("%s: can't re-read EXT_CSD\n", DEVNAME(sc)); + return error; + } + if (ext_csd[EXT_CSD_HS_TIMING] != EXT_CSD_HS_TIMING_HS) { + printf("%s, HS_TIMING set failed\n", DEVNAME(sc)); + return EINVAL; + } + } + if (ISSET(sc->sc_caps, SMC_CAPS_8BIT_MODE)) { width = 8; value = EXT_CSD_BUS_WIDTH_8; @@ -703,40 +746,41 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) sdmmc_delay(10000); } - if (!ISSET(sc->sc_caps, SMC_CAPS_MMC_HIGHSPEED)) - hs_timing = 0; + if (timing == SDMMC_TIMING_MMC_DDR52) { + switch (width) { + case 4: + value = EXT_CSD_BUS_WIDTH_4_DDR; + break; + case 8: + value = EXT_CSD_BUS_WIDTH_8_DDR; + break; + } - if (hs_timing) { - /* switch to high speed timing */ error = sdmmc_mem_mmc_switch(sf, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_HS_TIMING, hs_timing); - if (error != 0) { - printf("%s: can't change high speed\n", + EXT_CSD_BUS_WIDTH, value); + if (error) { + printf("%s: can't switch to DDR\n", DEVNAME(sc)); return error; } sdmmc_delay(10000); - } - error = sdmmc_chip_bus_clock(sc->sct, sc->sch, speed); - if (error != 0) { - printf("%s: can't change bus clock\n", DEVNAME(sc)); - return error; - } + error = sdmmc_chip_signal_voltage(sc->sct, sc->sch, + SDMMC_SIGNAL_VOLTAGE_180); + if (error) { + printf("%s: can't switch signalling voltage\n", + DEVNAME(sc)); + return error; + } - if (hs_timing) { - /* read EXT_CSD again */ - error = sdmmc_mem_send_cxd_data(sc, - MMC_SEND_EXT_CSD, ext_csd, sizeof(ext_csd)); + error = sdmmc_chip_bus_clock(sc->sct, sc->sch, speed, timing); if (error != 0) { - printf("%s: can't re-read EXT_CSD\n", DEVNAME(sc)); + printf("%s: can't change bus clock\n", DEVNAME(sc)); return error; } - if (ext_csd[EXT_CSD_HS_TIMING] != hs_timing) { - printf("%s, HS_TIMING set failed\n", DEVNAME(sc)); - return EINVAL; - } + + sdmmc_delay(10000); } sectors = ext_csd[EXT_CSD_SEC_COUNT + 0] << 0 | diff --git a/sys/dev/sdmmc/sdmmcchip.h b/sys/dev/sdmmc/sdmmcchip.h index 20d5e3aa59b..4f4843cc741 100644 --- a/sys/dev/sdmmc/sdmmcchip.h +++ b/sys/dev/sdmmc/sdmmcchip.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmcchip.h,v 1.7 2016/05/01 16:04:39 kettenis Exp $ */ +/* $OpenBSD: sdmmcchip.h,v 1.8 2016/05/05 11:01:08 kettenis Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -36,7 +36,7 @@ struct sdmmc_chip_functions { int (*card_detect)(sdmmc_chipset_handle_t); /* bus power and clock frequency */ int (*bus_power)(sdmmc_chipset_handle_t, u_int32_t); - int (*bus_clock)(sdmmc_chipset_handle_t, int); + int (*bus_clock)(sdmmc_chipset_handle_t, int, int); int (*bus_width)(sdmmc_chipset_handle_t, int); /* command execution */ void (*exec_command)(sdmmc_chipset_handle_t, @@ -44,6 +44,8 @@ struct sdmmc_chip_functions { /* card interrupt */ void (*card_intr_mask)(sdmmc_chipset_handle_t, int); void (*card_intr_ack)(sdmmc_chipset_handle_t); + /* UHS functions */ + int (*signal_voltage)(sdmmc_chipset_handle_t, int); }; /* host controller reset */ @@ -60,8 +62,8 @@ struct sdmmc_chip_functions { /* bus power and clock frequency */ #define sdmmc_chip_bus_power(tag, handle, ocr) \ ((tag)->bus_power((handle), (ocr))) -#define sdmmc_chip_bus_clock(tag, handle, freq) \ - ((tag)->bus_clock((handle), (freq))) +#define sdmmc_chip_bus_clock(tag, handle, freq, timing) \ + ((tag)->bus_clock((handle), (freq), (timing))) #define sdmmc_chip_bus_width(tag, handle, width) \ ((tag)->bus_width((handle), (width))) /* command execution */ @@ -72,12 +74,23 @@ struct sdmmc_chip_functions { ((tag)->card_intr_mask((handle), (enable))) #define sdmmc_chip_card_intr_ack(tag, handle) \ ((tag)->card_intr_ack((handle))) +/* UHS functions */ +#define sdmmc_chip_signal_voltage(tag, handle, voltage) \ + ((tag)->signal_voltage((handle), (voltage))) /* clock frequencies for sdmmc_chip_bus_clock() */ #define SDMMC_SDCLK_OFF 0 #define SDMMC_SDCLK_400KHZ 400 #define SDMMC_SDCLK_25MHZ 25000 +/* voltage levels for sdmmc_chip_signal_voltage() */ +#define SDMMC_SIGNAL_VOLTAGE_330 0 +#define SDMMC_SIGNAL_VOLTAGE_180 1 + +#define SDMMC_TIMING_LEGACY 0 +#define SDMMC_TIMING_HIGHSPEED 1 +#define SDMMC_TIMING_MMC_DDR52 2 + struct sdmmcbus_attach_args { const char *saa_busname; sdmmc_chipset_tag_t sct; diff --git a/sys/dev/sdmmc/sdmmcreg.h b/sys/dev/sdmmc/sdmmcreg.h index c2751488b9e..c984afc9f78 100644 --- a/sys/dev/sdmmc/sdmmcreg.h +++ b/sys/dev/sdmmc/sdmmcreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmcreg.h,v 1.10 2016/05/04 09:30:06 kettenis Exp $ */ +/* $OpenBSD: sdmmcreg.h,v 1.11 2016/05/05 11:01:08 kettenis Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -104,10 +104,18 @@ #define EXT_CSD_CMD_SET_SECURE (1U << 1) #define EXT_CSD_CMD_SET_CPSECURE (1U << 2) +/* EXT_CSD_HS_TIMING */ +#define EXT_CSD_HS_TIMING_BC 0 +#define EXT_CSD_HS_TIMING_HS 1 +#define EXT_CSD_HS_TIMING_HS200 2 +#define EXT_CSD_HS_TIMING_HS400 3 + /* EXT_CSD_BUS_WIDTH */ #define EXT_CSD_BUS_WIDTH_1 0 #define EXT_CSD_BUS_WIDTH_4 1 #define EXT_CSD_BUS_WIDTH_8 2 +#define EXT_CSD_BUS_WIDTH_4_DDR 5 +#define EXT_CSD_BUS_WIDTH_8_DDR 6 /* EXT_CSD_CARD_TYPE */ /* The only currently valid values for this field are 0x01, 0x03, 0x07, diff --git a/sys/dev/sdmmc/sdmmcvar.h b/sys/dev/sdmmc/sdmmcvar.h index 7a66dd097c5..cc4074cd00b 100644 --- a/sys/dev/sdmmc/sdmmcvar.h +++ b/sys/dev/sdmmc/sdmmcvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmcvar.h,v 1.25 2016/05/04 09:30:06 kettenis Exp $ */ +/* $OpenBSD: sdmmcvar.h,v 1.26 2016/05/05 11:01:08 kettenis Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -191,6 +191,13 @@ struct sdmmc_softc { #define SMC_CAPS_MULTI_SEG_DMA 0x0080 /* multiple segment DMA transfer */ #define SMC_CAPS_SD_HIGHSPEED 0x0100 /* SD high-speed timing */ #define SMC_CAPS_MMC_HIGHSPEED 0x0200 /* MMC high-speed timing */ +#define SMC_CAPS_UHS_SDR50 0x0400 /* UHS SDR50 timing */ +#define SMC_CAPS_UHS_SDR104 0x0800 /* UHS SDR104 timing */ +#define SMC_CAPS_UHS_DDR50 0x1000 /* UHS DDR50 timing */ +#define SMC_CAPS_UHS_MASK 0x1c00 +#define SMC_CAPS_MMC_DDR52 0x2000 /* eMMC DDR52 timing */ +#define SMC_CAPS_MMC_HS200 0x4000 /* eMMC HS200 timing */ +#define SMC_CAPS_MMC_HS400 0x8000 /* eMMC HS400 timing */ int sc_function_count; /* number of I/O functions (SDIO) */ struct sdmmc_function *sc_card; /* selected card */ |