diff options
| author | nonaka <nonaka@NetBSD.org> | 2017-02-17 10:50:43 +0000 |
|---|---|---|
| committer | nonaka <nonaka@NetBSD.org> | 2017-02-17 10:50:43 +0000 |
| commit | 700349fb4a450ceb78a5e2ca11bcbc4686b869ff (patch) | |
| tree | 56105e25d97233961202b04fedc11529a3723eb5 /sys/dev | |
| parent | e779b04b38111253be6daf0768d4deb747b92031 (diff) | |
sdhc(4), sdmmc(4): Added MMC HS DDR52 support.
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/sdmmc/sdhc.c | 15 | ||||
| -rw-r--r-- | sys/dev/sdmmc/sdmmc_mem.c | 54 | ||||
| -rw-r--r-- | sys/dev/sdmmc/sdmmcchip.h | 4 |
3 files changed, 63 insertions, 10 deletions
diff --git a/sys/dev/sdmmc/sdhc.c b/sys/dev/sdmmc/sdhc.c index b817003534b..b8c1cba1cdd 100644 --- a/sys/dev/sdmmc/sdhc.c +++ b/sys/dev/sdmmc/sdhc.c @@ -1,4 +1,4 @@ -/* $NetBSD: sdhc.c,v 1.97 2017/01/07 15:05:08 kiyohara Exp $ */ +/* $NetBSD: sdhc.c,v 1.98 2017/02/17 10:50:43 nonaka 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.97 2017/01/07 15:05:08 kiyohara Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.98 2017/02/17 10:50:43 nonaka Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -1107,7 +1107,13 @@ sdhc_bus_clock_ddr(sdmmc_chipset_handle_t sch, int freq, bool ddr) if (freq > 100000) { HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR104); } else if (freq > 50000) { - HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR50); + if (ddr) { + HSET2(hp, SDHC_HOST_CTL2, + SDHC_UHS_MODE_SELECT_DDR50); + } else { + HSET2(hp, SDHC_HOST_CTL2, + SDHC_UHS_MODE_SELECT_SDR50); + } } else if (freq > 25000) { if (ddr) { HSET2(hp, SDHC_HOST_CTL2, @@ -1335,6 +1341,9 @@ sdhc_signal_voltage(sdmmc_chipset_handle_t sch, int signal_voltage) { struct sdhc_host *hp = (struct sdhc_host *)sch; + if (hp->specver < SDHC_SPEC_VERS_300) + return EINVAL; + mutex_enter(&hp->intr_lock); switch (signal_voltage) { case SDMMC_SIGNAL_VOLTAGE_180: diff --git a/sys/dev/sdmmc/sdmmc_mem.c b/sys/dev/sdmmc/sdmmc_mem.c index bbd1e943814..c7e6863e653 100644 --- a/sys/dev/sdmmc/sdmmc_mem.c +++ b/sys/dev/sdmmc/sdmmc_mem.c @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmc_mem.c,v 1.53 2017/02/17 10:48:19 nonaka Exp $ */ +/* $NetBSD: sdmmc_mem.c,v 1.54 2017/02/17 10:50:43 nonaka Exp $ */ /* $OpenBSD: sdmmc_mem.c,v 1.10 2009/01/09 10:55:22 jsg Exp $ */ /* @@ -45,7 +45,7 @@ /* Routines for SD/MMC memory cards. */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.53 2017/02/17 10:48:19 nonaka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.54 2017/02/17 10:50:43 nonaka Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -907,6 +907,7 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) int width, value, hs_timing, bus_clock, error; uint8_t ext_csd[512]; uint32_t sectors = 0; + bool ddr = false; sc->sc_transfer_mode = NULL; @@ -934,11 +935,15 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) return ENOTSUP; } - sc->sc_transfer_mode = NULL; if (ISSET(sc->sc_caps, SMC_CAPS_MMC_HS200) && ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_F_HS200_1_8V) { sf->csd.tran_speed = 200000; /* 200MHz SDR */ hs_timing = EXT_CSD_HS_TIMING_HS200; + } else if (ISSET(sc->sc_caps, SMC_CAPS_MMC_DDR52) && + ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_F_DDR52_1_8V) { + sf->csd.tran_speed = 52000; /* 52MHz */ + hs_timing = EXT_CSD_HS_TIMING_HIGHSPEED; + ddr = true; } else if (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_F_52M) { sf->csd.tran_speed = 52000; /* 52MHz */ hs_timing = EXT_CSD_HS_TIMING_HIGHSPEED; @@ -1022,6 +1027,47 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) } } + /* + * HS_TIMING must be set to “0x1” before setting BUS_WIDTH + * for dual data rate operation + */ + if (ddr && + hs_timing == EXT_CSD_HS_TIMING_HIGHSPEED && + width > 1) { + error = sdmmc_mem_mmc_switch(sf, + EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, + (width == 8) ? EXT_CSD_BUS_WIDTH_8_DDR : + EXT_CSD_BUS_WIDTH_4_DDR); + if (error) { + DPRINTF(("%s: can't switch to DDR" + " (%d bit)\n", SDMMCDEVNAME(sc), width)); + return error; + } + + delay(10000); + + error = sdmmc_mem_signal_voltage(sc, + SDMMC_SIGNAL_VOLTAGE_180); + if (error) { + aprint_error_dev(sc->sc_dev, + "can't switch signaling voltage\n"); + return error; + } + + error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, + sc->sc_busclk, ddr); + if (error) { + aprint_error_dev(sc->sc_dev, + "can't change bus clock\n"); + return error; + } + + delay(10000); + + sc->sc_transfer_mode = "DDR52"; + sc->sc_busddr = ddr; + } + sectors = ext_csd[EXT_CSD_SEC_COUNT + 0] << 0 | ext_csd[EXT_CSD_SEC_COUNT + 1] << 8 | ext_csd[EXT_CSD_SEC_COUNT + 2] << 16 | @@ -1041,8 +1087,6 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) "can't execute MMC tuning\n"); return error; } - } else { - sc->sc_transfer_mode = NULL; } } else { if (sc->sc_busclk > sf->csd.tran_speed) diff --git a/sys/dev/sdmmc/sdmmcchip.h b/sys/dev/sdmmc/sdmmcchip.h index 2619bf90c82..9014f9434d4 100644 --- a/sys/dev/sdmmc/sdmmcchip.h +++ b/sys/dev/sdmmc/sdmmcchip.h @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmcchip.h,v 1.7 2015/08/05 10:29:37 jmcneill Exp $ */ +/* $NetBSD: sdmmcchip.h,v 1.8 2017/02/17 10:50:43 nonaka Exp $ */ /* $OpenBSD: sdmmcchip.h,v 1.3 2007/05/31 10:09:01 uwe Exp $ */ /* @@ -97,7 +97,7 @@ struct sdmmc_chip_functions { ((tag)->card_intr_ack((handle))) /* UHS functions */ #define sdmmc_chip_signal_voltage(tag, handle, voltage) \ - ((tag)->signal_voltage((handle), (voltage))) + ((tag)->signal_voltage ? (tag)->signal_voltage((handle), (voltage)) : EINVAL) #define sdmmc_chip_execute_tuning(tag, handle, timing) \ ((tag)->execute_tuning ? (tag)->execute_tuning((handle), (timing)) : EINVAL) |
