summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authornonaka <nonaka@NetBSD.org>2017-02-17 10:50:43 +0000
committernonaka <nonaka@NetBSD.org>2017-02-17 10:50:43 +0000
commit700349fb4a450ceb78a5e2ca11bcbc4686b869ff (patch)
tree56105e25d97233961202b04fedc11529a3723eb5 /sys
parente779b04b38111253be6daf0768d4deb747b92031 (diff)
sdhc(4), sdmmc(4): Added MMC HS DDR52 support.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/sdmmc/sdhc.c15
-rw-r--r--sys/dev/sdmmc/sdmmc_mem.c54
-rw-r--r--sys/dev/sdmmc/sdmmcchip.h4
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)