Module Name:    src
Committed By:   jmcneill
Date:           Mon Aug  3 10:08:51 UTC 2015

Modified Files:
        src/sys/dev/sdmmc: sdhc.c sdmmc.c sdmmc_io.c sdmmc_mem.c sdmmcchip.h
            sdmmcreg.h sdmmcvar.h

Log Message:
Add support for DDR50 transfer modes.


To generate a diff of this commit:
cvs rdiff -u -r1.75 -r1.76 src/sys/dev/sdmmc/sdhc.c
cvs rdiff -u -r1.28 -r1.29 src/sys/dev/sdmmc/sdmmc.c
cvs rdiff -u -r1.9 -r1.10 src/sys/dev/sdmmc/sdmmc_io.c
cvs rdiff -u -r1.38 -r1.39 src/sys/dev/sdmmc/sdmmc_mem.c
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/sdmmc/sdmmcchip.h
cvs rdiff -u -r1.17 -r1.18 src/sys/dev/sdmmc/sdmmcreg.h \
    src/sys/dev/sdmmc/sdmmcvar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/sdmmc/sdhc.c
diff -u src/sys/dev/sdmmc/sdhc.c:1.75 src/sys/dev/sdmmc/sdhc.c:1.76
--- src/sys/dev/sdmmc/sdhc.c:1.75	Mon Aug  3 05:24:37 2015
+++ src/sys/dev/sdmmc/sdhc.c	Mon Aug  3 10:08:51 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdhc.c,v 1.75 2015/08/03 05:24:37 mlelstv Exp $	*/
+/*	$NetBSD: sdhc.c,v 1.76 2015/08/03 10:08:51 jmcneill 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.75 2015/08/03 05:24:37 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.76 2015/08/03 10:08:51 jmcneill Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -174,7 +174,7 @@ static int	sdhc_host_maxblklen(sdmmc_chi
 static int	sdhc_card_detect(sdmmc_chipset_handle_t);
 static int	sdhc_write_protect(sdmmc_chipset_handle_t);
 static int	sdhc_bus_power(sdmmc_chipset_handle_t, uint32_t);
-static int	sdhc_bus_clock(sdmmc_chipset_handle_t, int);
+static int	sdhc_bus_clock_ddr(sdmmc_chipset_handle_t, int, bool);
 static int	sdhc_bus_width(sdmmc_chipset_handle_t, int);
 static int	sdhc_bus_rod(sdmmc_chipset_handle_t, int);
 static void	sdhc_card_enable_intr(sdmmc_chipset_handle_t, int);
@@ -210,7 +210,7 @@ static struct sdmmc_chip_functions sdhc_
 
 	/* bus power, clock frequency, width and ROD(OpenDrain/PushPull) */
 	.bus_power = sdhc_bus_power,
-	.bus_clock = sdhc_bus_clock,
+	.bus_clock = NULL,	/* see sdhc_bus_clock_ddr */
 	.bus_width = sdhc_bus_width,
 	.bus_rod = sdhc_bus_rod,
 
@@ -223,6 +223,7 @@ static struct sdmmc_chip_functions sdhc_
 
 	/* UHS functions */
 	.signal_voltage = sdhc_signal_voltage,
+	.bus_clock_ddr = sdhc_bus_clock_ddr,
 };
 
 static int
@@ -418,14 +419,14 @@ sdhc_host_found(struct sdhc_softc *sc, b
 		SET(hp->ocr, MMC_OCR_S18A);
 		aprint_normal(" SDR50");
 	}
-	if (ISSET(caps2, SDHC_SDR104_SUPP)) {
-		SET(hp->ocr, MMC_OCR_S18A);
-		aprint_normal(" SDR104");
-	}
 	if (ISSET(caps2, SDHC_DDR50_SUPP)) {
 		SET(hp->ocr, MMC_OCR_S18A);
 		aprint_normal(" DDR50");
 	}
+	if (ISSET(caps2, SDHC_SDR104_SUPP)) {
+		SET(hp->ocr, MMC_OCR_S18A);
+		aprint_normal(" SDR104 HS200");
+	}
 	if (ISSET(caps, SDHC_VOLTAGE_SUPP_1_8V)) {
 		SET(hp->ocr, MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V);
 		aprint_normal(" 1.8V");
@@ -534,6 +535,14 @@ adma_done:
 		saa.saa_caps |= SMC_CAPS_8BIT_MODE;
 	if (ISSET(caps, SDHC_HIGH_SPEED_SUPP))
 		saa.saa_caps |= SMC_CAPS_SD_HIGHSPEED;
+	if (ISSET(caps2, SDHC_SDR104_SUPP))
+		saa.saa_caps |= SMC_CAPS_UHS_SDR104 |
+				SMC_CAPS_UHS_SDR50 |
+				SMC_CAPS_MMC_HS200;
+	if (ISSET(caps2, SDHC_SDR50_SUPP))
+		saa.saa_caps |= SMC_CAPS_UHS_SDR50;
+	if (ISSET(caps2, SDHC_DDR50_SUPP))
+		saa.saa_caps |= SMC_CAPS_UHS_DDR50;
 	if (ISSET(hp->flags, SHF_USE_DMA)) {
 		saa.saa_caps |= SMC_CAPS_DMA;
 		if (!ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED))
@@ -964,7 +973,7 @@ sdhc_clock_divisor(struct sdhc_host *hp,
  * Return zero on success.
  */
 static int
-sdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq)
+sdhc_bus_clock_ddr(sdmmc_chipset_handle_t sch, int freq, bool ddr)
 {
 	struct sdhc_host *hp = (struct sdhc_host *)sch;
 	u_int div;
@@ -1007,14 +1016,19 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sc
 	}
 
 	if (hp->specver >= SDHC_SPEC_VERS_300) {
-		/* XXX DDR */
 		HCLR2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_MASK);
 		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);
 		} else if (freq > 25000) {
-			HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR25);
+			if (ddr) {
+				HSET2(hp, SDHC_HOST_CTL2,
+				    SDHC_UHS_MODE_SELECT_DDR50);
+			} else {
+				HSET2(hp, SDHC_HOST_CTL2,
+				    SDHC_UHS_MODE_SELECT_SDR25);
+			}
 		} else if (freq > 400) {
 			HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR12);
 		}

Index: src/sys/dev/sdmmc/sdmmc.c
diff -u src/sys/dev/sdmmc/sdmmc.c:1.28 src/sys/dev/sdmmc/sdmmc.c:1.29
--- src/sys/dev/sdmmc/sdmmc.c:1.28	Mon Aug  3 05:32:50 2015
+++ src/sys/dev/sdmmc/sdmmc.c	Mon Aug  3 10:08:51 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmc.c,v 1.28 2015/08/03 05:32:50 mlelstv Exp $	*/
+/*	$NetBSD: sdmmc.c,v 1.29 2015/08/03 10:08:51 jmcneill Exp $	*/
 /*	$OpenBSD: sdmmc.c,v 1.18 2009/01/09 10:58:38 jsg Exp $	*/
 
 /*
@@ -49,7 +49,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.28 2015/08/03 05:32:50 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.29 2015/08/03 10:08:51 jmcneill Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -523,7 +523,8 @@ sdmmc_enable(struct sdmmc_softc *sc)
 	/*
 	 * Select the minimum clock frequency.
 	 */
-	error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, SDMMC_SDCLK_400K);
+	error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, SDMMC_SDCLK_400K,
+	    false);
 	if (error) {
 		aprint_error_dev(sc->sc_dev, "couldn't supply clock\n");
 		goto out;
@@ -569,7 +570,8 @@ sdmmc_disable(struct sdmmc_softc *sc)
 
 	/* Turn off bus power and clock. */
 	(void)sdmmc_chip_bus_width(sc->sc_sct, sc->sc_sch, 1);
-	(void)sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, SDMMC_SDCLK_OFF);
+	(void)sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, SDMMC_SDCLK_OFF,
+	    false);
 	(void)sdmmc_chip_bus_power(sc->sc_sct, sc->sc_sch, 0);
 	sc->sc_busclk = sc->sc_clkmax;
 }

Index: src/sys/dev/sdmmc/sdmmc_io.c
diff -u src/sys/dev/sdmmc/sdmmc_io.c:1.9 src/sys/dev/sdmmc/sdmmc_io.c:1.10
--- src/sys/dev/sdmmc/sdmmc_io.c:1.9	Mon Aug  3 05:32:50 2015
+++ src/sys/dev/sdmmc/sdmmc_io.c	Mon Aug  3 10:08:51 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmc_io.c,v 1.9 2015/08/03 05:32:50 mlelstv Exp $	*/
+/*	$NetBSD: sdmmc_io.c,v 1.10 2015/08/03 10:08:51 jmcneill Exp $	*/
 /*	$OpenBSD: sdmmc_io.c,v 1.10 2007/09/17 01:33:33 krw Exp $	*/
 
 /*
@@ -20,7 +20,7 @@
 /* Routines for SD I/O cards. */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdmmc_io.c,v 1.9 2015/08/03 05:32:50 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc_io.c,v 1.10 2015/08/03 10:08:51 jmcneill Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -231,7 +231,8 @@ sdmmc_io_init(struct sdmmc_softc *sc, st
 		if (sc->sc_busclk > sf->csd.tran_speed)
 			sc->sc_busclk = sf->csd.tran_speed;
 		error =
-		    sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, sc->sc_busclk);
+		    sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, sc->sc_busclk,
+			false);
 		if (error)
 			aprint_error_dev(sc->sc_dev,
 			    "can't change bus clock\n");

Index: src/sys/dev/sdmmc/sdmmc_mem.c
diff -u src/sys/dev/sdmmc/sdmmc_mem.c:1.38 src/sys/dev/sdmmc/sdmmc_mem.c:1.39
--- src/sys/dev/sdmmc/sdmmc_mem.c:1.38	Mon Aug  3 05:32:50 2015
+++ src/sys/dev/sdmmc/sdmmc_mem.c	Mon Aug  3 10:08:51 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmc_mem.c,v 1.38 2015/08/03 05:32:50 mlelstv Exp $	*/
+/*	$NetBSD: sdmmc_mem.c,v 1.39 2015/08/03 10:08:51 jmcneill 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.38 2015/08/03 05:32:50 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.39 2015/08/03 10:08:51 jmcneill Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -96,6 +96,27 @@ static int sdmmc_mem_read_block_subr(str
 static int sdmmc_mem_write_block_subr(struct sdmmc_function *, bus_dmamap_t,
     uint32_t, u_char *, size_t);
 
+static const struct {
+	const char *name;
+	int v;
+	int freq;
+} switch_group0_functions[] = {
+	/* Default/SDR12 */
+	{ "Default/SDR12",	 0,			 25000 },
+
+	/* High-Speed/SDR25 */
+	{ "High-Speed/SDR25",	SMC_CAPS_SD_HIGHSPEED,	 50000 },
+
+	/* SDR50 */
+	{ "SDR50",		SMC_CAPS_UHS_SDR50,	100000 },
+
+	/* SDR104 */
+	{ "SDR104",		SMC_CAPS_UHS_SDR104,	208000 },
+
+	/* DDR50 */
+	{ "DDR50",		SMC_CAPS_UHS_DDR50,	 50000 },
+};
+
 /*
  * Initialize SD/MMC memory cards and memory in SDIO "combo" cards.
  */
@@ -221,7 +242,7 @@ mmc_mode:
 		 * Stop the clock
 		 */
 		error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch,
-		    SDMMC_SDCLK_OFF);
+		    SDMMC_SDCLK_OFF, false);
 		if (error)
 			goto out;
 
@@ -241,7 +262,8 @@ mmc_mode:
 		/*
 		 * Switch to SDR12 timing
 		 */
-		error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, 25000);
+		error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, 25000,
+		    false);
 		if (error)
 			goto out;
 
@@ -672,38 +694,39 @@ sdmmc_be512_to_bitfield512(sdmmc_bitfiel
 }
 
 static int
+sdmmc_mem_select_transfer_mode(struct sdmmc_softc *sc, int support_func)
+{
+	if (ISSET(sc->sc_flags, SMF_UHS_MODE)) {
+		if (ISSET(sc->sc_caps, SMC_CAPS_UHS_SDR104) &&
+		    ISSET(support_func, SD_ACCESS_MODE_SDR104)) {
+			return SD_ACCESS_MODE_SDR104;
+		}
+		if (ISSET(sc->sc_caps, SMC_CAPS_UHS_DDR50) &&
+		    ISSET(support_func, SD_ACCESS_MODE_DDR50)) {
+			return SD_ACCESS_MODE_DDR50;
+		}
+		if (ISSET(sc->sc_caps, SMC_CAPS_UHS_SDR50) &&
+		    ISSET(support_func, SD_ACCESS_MODE_SDR50)) {
+			return SD_ACCESS_MODE_SDR50;
+		}
+	}
+	if (ISSET(sc->sc_caps, SMC_CAPS_SD_HIGHSPEED) &&
+	    ISSET(support_func, SD_ACCESS_MODE_SDR25)) {
+		return SD_ACCESS_MODE_SDR25;
+	}
+	return SD_ACCESS_MODE_SDR12;
+}
+
+static int
 sdmmc_mem_sd_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
 {
-	static const struct {
-		int v;
-		int freq;
-		int uhs;
-	} switch_group0_functions[] = {
-		/* Default/SDR12 */
-		{ MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V |
-		  MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V,	 25000, 0 },
-
-		/* High-Speed/SDR25 */
-		{ MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V |
-		  MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V,	 50000, 0 },
-
-		/* SDR50 */
-		{ MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V,	100000, 1 },
-
-		/* SDR104 */
-		{ MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V,	208000, 1 },
-
-#if notyet
-		/* DDR50 */
-		{ MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V,	 50000, 1 },
-#endif
-	};
-	int host_ocr, support_func, best_func, bus_clock, error, g, i;
+	int support_func, best_func, bus_clock, error, i;
 	sdmmc_bitfield512_t status; /* Switch Function Status */
+	bool ddr = false;
 
 	/* change bus clock */
 	bus_clock = min(sc->sc_busclk, sf->csd.tran_speed);
-	error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, bus_clock);
+	error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, bus_clock, false);
 	if (error) {
 		aprint_error_dev(sc->sc_dev, "can't change bus clock\n");
 		return error;
@@ -730,6 +753,7 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc
 		sf->width = 4;
 	}
 
+	best_func = 0;
 	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", SDMMCDEVNAME(sc)));
@@ -740,22 +764,22 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc
 			return error;
 		}
 
-		host_ocr = sdmmc_chip_host_ocr(sc->sc_sct, sc->sc_sch);
 		support_func = SFUNC_STATUS_GROUP(&status, 1);
-		DPRINTF(("%s: support_func %#x\n", SDMMCDEVNAME(sc), support_func));
-		best_func = 0;
-		for (i = 0, g = 1;
-		    i < __arraycount(switch_group0_functions); i++, g <<= 1) {
-			if (!(switch_group0_functions[i].v & host_ocr))
+
+		for (i = 0; i < __arraycount(switch_group0_functions); i++) {
+			if (!(support_func & (1 << i)))
 				continue;
-			if (switch_group0_functions[i].uhs &&
-			    !ISSET(sc->sc_flags, SMF_UHS_MODE))
-				break;
-			if (g & support_func)
-				best_func = i;
+			DPRINTF(("%s: card supports mode %s\n",
+			    SDMMCDEVNAME(sc),
+			    switch_group0_functions[i].name));
 		}
-		if (ISSET(sc->sc_caps, SMC_CAPS_SD_HIGHSPEED) &&
-		    best_func != 0) {
+
+		best_func = sdmmc_mem_select_transfer_mode(sc, support_func);
+
+		DPRINTF(("%s: using mode %s\n", SDMMCDEVNAME(sc),
+		    switch_group0_functions[best_func].name));
+
+		if (best_func != 0) {
 			DPRINTF(("%s: switch func mode 1(func=%d)\n",
 			    SDMMCDEVNAME(sc), best_func));
 			error =
@@ -770,6 +794,9 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc
 			sf->csd.tran_speed =
 			    switch_group0_functions[best_func].freq;
 
+			if (best_func == SD_ACCESS_MODE_DDR50)
+				ddr = true;
+
 			/* Wait 400KHz x 8 clock (2.5us * 8 + slop) */
 			delay(25);
 		}
@@ -778,16 +805,20 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc
 	/* update bus clock */
 	if (sc->sc_busclk > sf->csd.tran_speed)
 		sc->sc_busclk = sf->csd.tran_speed;
-	if (sc->sc_busclk == bus_clock)
+	if (sc->sc_busclk == bus_clock && sc->sc_busddr == ddr)
 		return 0;
 
 	/* change bus clock */
-	error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, sc->sc_busclk);
+	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;
 	}
 
+	sc->sc_transfer_mode = switch_group0_functions[best_func].name;
+	sc->sc_busddr = ddr;
+
 	return 0;
 }
 
@@ -797,18 +828,17 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s
 	int width, value, hs_timing, bus_clock, error;
 	char ext_csd[512];
 	uint32_t sectors = 0;
-	int host_ocr;
+
+	sc->sc_transfer_mode = NULL;
 
 	/* change bus clock */
 	bus_clock = min(sc->sc_busclk, sf->csd.tran_speed);
-	error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, bus_clock);
+	error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, bus_clock, false);
 	if (error) {
 		aprint_error_dev(sc->sc_dev, "can't change bus clock\n");
 		return error;
 	}
 
-	host_ocr = sdmmc_chip_host_ocr(sc->sc_sct, sc->sc_sch);
-
 	if (sf->csd.mmcver >= MMC_CSD_MMCVER_4_0) {
 		error = sdmmc_mem_send_cxd_data(sc,
 		    MMC_SEND_EXT_CSD, ext_csd, sizeof(ext_csd));
@@ -825,7 +855,8 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s
 			return ENOTSUP;
 		}
 
-		if (ISSET(host_ocr, MMC_OCR_1_7V_1_8V|MMC_OCR_1_8V_1_9V) &&
+		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 = 2;
@@ -842,7 +873,42 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s
 			return ENOTSUP;
 		}
 
-		if (!ISSET(sc->sc_caps, SMC_CAPS_MMC_HIGHSPEED)) {
+		if (hs_timing == 2) {
+			error = sdmmc_chip_signal_voltage(sc->sc_sct,
+			    sc->sc_sch, SDMMC_SIGNAL_VOLTAGE_180);
+			if (error)
+				hs_timing = 1;
+		}
+
+		if (ISSET(sc->sc_caps, SMC_CAPS_8BIT_MODE)) {
+			width = 8;
+			value = EXT_CSD_BUS_WIDTH_8;
+		} else if (ISSET(sc->sc_caps, SMC_CAPS_4BIT_MODE)) {
+			width = 4;
+			value = EXT_CSD_BUS_WIDTH_4;
+		} else {
+			width = 1;
+			value = EXT_CSD_BUS_WIDTH_1;
+		}
+
+		if (width != 1) {
+			error = sdmmc_mem_mmc_switch(sf, EXT_CSD_CMD_SET_NORMAL,
+			    EXT_CSD_BUS_WIDTH, value);
+			if (error == 0)
+				error = sdmmc_chip_bus_width(sc->sc_sct,
+				    sc->sc_sch, width);
+			else {
+				DPRINTF(("%s: can't change bus width"
+				    " (%d bit)\n", SDMMCDEVNAME(sc), width));
+				return error;
+			}
+
+			/* XXXX: need bus test? (using by CMD14 & CMD19) */
+		}
+		sf->width = width;
+
+		if (hs_timing == 1 &&
+		    !ISSET(sc->sc_caps, SMC_CAPS_MMC_HIGHSPEED)) {
 			hs_timing = 0;
 		}
 		if (hs_timing) {
@@ -859,7 +925,7 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s
 			sc->sc_busclk = sf->csd.tran_speed;
 		if (sc->sc_busclk != bus_clock) {
 			error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch,
-			    sc->sc_busclk);
+			    sc->sc_busclk, false);
 			if (error) {
 				aprint_error_dev(sc->sc_dev,
 				    "can't change bus clock\n");
@@ -891,38 +957,17 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s
 			sf->csd.capacity = sectors;
 		}
 
-		if (ISSET(sc->sc_caps, SMC_CAPS_8BIT_MODE)) {
-			width = 8;
-			value = EXT_CSD_BUS_WIDTH_8;
-		} else if (ISSET(sc->sc_caps, SMC_CAPS_4BIT_MODE)) {
-			width = 4;
-			value = EXT_CSD_BUS_WIDTH_4;
+		if (hs_timing == 2) {
+			sc->sc_transfer_mode = "HS200";
 		} else {
-			width = 1;
-			value = EXT_CSD_BUS_WIDTH_1;
+			sc->sc_transfer_mode = NULL;
 		}
-
-		if (width != 1) {
-			error = sdmmc_mem_mmc_switch(sf, EXT_CSD_CMD_SET_NORMAL,
-			    EXT_CSD_BUS_WIDTH, value);
-			if (error == 0)
-				error = sdmmc_chip_bus_width(sc->sc_sct,
-				    sc->sc_sch, width);
-			else {
-				DPRINTF(("%s: can't change bus width"
-				    " (%d bit)\n", SDMMCDEVNAME(sc), width));
-				return error;
-			}
-
-			/* XXXX: need bus test? (using by CMD14 & CMD19) */
-		}
-		sf->width = width;
 	} else {
 		if (sc->sc_busclk > sf->csd.tran_speed)
 			sc->sc_busclk = sf->csd.tran_speed;
 		if (sc->sc_busclk != bus_clock) {
 			error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch,
-			    sc->sc_busclk);
+			    sc->sc_busclk, false);
 			if (error) {
 				aprint_error_dev(sc->sc_dev,
 				    "can't change bus clock\n");
@@ -1083,11 +1128,11 @@ sdmmc_mem_decode_scr(struct sdmmc_softc 
 	sf->scr.sd_spec = SCR_SD_SPEC(resp);
 	sf->scr.bus_width = SCR_SD_BUS_WIDTHS(resp);
 
-	DPRINTF(("%s: sdmmc_mem_decode_scr: %08x%08x spec=%d, bus width=%d\n",
+	DPRINTF(("%s: sdmmc_mem_decode_scr: %08x%08x ver=%d, spec=%d, bus width=%d, spec3=%d\n",
 	    SDMMCDEVNAME(sc), resp[1], resp[0],
-	    sf->scr.sd_spec, sf->scr.bus_width));
+	    ver, sf->scr.sd_spec, sf->scr.bus_width, sf->scr.sd_spec3));
 
-	if (ver != 0) {
+	if (ver != 0 && ver != 1) {
 		DPRINTF(("%s: unknown structure version: %d\n",
 		    SDMMCDEVNAME(sc), ver));
 		return EINVAL;

Index: src/sys/dev/sdmmc/sdmmcchip.h
diff -u src/sys/dev/sdmmc/sdmmcchip.h:1.5 src/sys/dev/sdmmc/sdmmcchip.h:1.6
--- src/sys/dev/sdmmc/sdmmcchip.h:1.5	Sun Aug  2 21:44:36 2015
+++ src/sys/dev/sdmmc/sdmmcchip.h	Mon Aug  3 10:08:51 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmcchip.h,v 1.5 2015/08/02 21:44:36 jmcneill Exp $	*/
+/*	$NetBSD: sdmmcchip.h,v 1.6 2015/08/03 10:08:51 jmcneill Exp $	*/
 /*	$OpenBSD: sdmmcchip.h,v 1.3 2007/05/31 10:09:01 uwe Exp $	*/
 
 /*
@@ -60,6 +60,7 @@ struct sdmmc_chip_functions {
 
 	/* UHS functions */
 	int		(*signal_voltage)(sdmmc_chipset_handle_t, int);
+	int		(*bus_clock_ddr)(sdmmc_chipset_handle_t, int, bool);
 };
 
 /* host controller reset */
@@ -79,8 +80,8 @@ struct sdmmc_chip_functions {
 /* bus power, clock frequency, width and rod */
 #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, ddr)			\
+	((tag)->bus_clock_ddr ? (tag)->bus_clock_ddr((handle), (freq), (ddr)) : ((ddr) ? EINVAL : ((tag)->bus_clock((handle), (freq)))))
 #define sdmmc_chip_bus_width(tag, handle, width)			\
 	((tag)->bus_width((handle), (width)))
 #define sdmmc_chip_bus_rod(tag, handle, width)				\

Index: src/sys/dev/sdmmc/sdmmcreg.h
diff -u src/sys/dev/sdmmc/sdmmcreg.h:1.17 src/sys/dev/sdmmc/sdmmcreg.h:1.18
--- src/sys/dev/sdmmc/sdmmcreg.h:1.17	Sun Aug  2 22:47:05 2015
+++ src/sys/dev/sdmmc/sdmmcreg.h	Mon Aug  3 10:08:51 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmcreg.h,v 1.17 2015/08/02 22:47:05 jmcneill Exp $	*/
+/*	$NetBSD: sdmmcreg.h,v 1.18 2015/08/03 10:08:51 jmcneill Exp $	*/
 /*	$OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $	*/
 
 /*
@@ -334,6 +334,12 @@
 #define SFUNC_STATUS_GROUP(status, group) \
 	(__bitfield((uint32_t *)(status), 400 + (group - 1) * 16, 16))
 
+#define SD_ACCESS_MODE_SDR12	0
+#define SD_ACCESS_MODE_SDR25	1
+#define SD_ACCESS_MODE_SDR50	2
+#define SD_ACCESS_MODE_SDR104	3
+#define SD_ACCESS_MODE_DDR50	4
+
 /* This assumes the response fields are in host byte order in 32-bit units.  */
 #define MMC_RSP_BITS(resp, start, len)	__bitfield((resp), (start)-8, (len))
 static inline uint32_t
Index: src/sys/dev/sdmmc/sdmmcvar.h
diff -u src/sys/dev/sdmmc/sdmmcvar.h:1.17 src/sys/dev/sdmmc/sdmmcvar.h:1.18
--- src/sys/dev/sdmmc/sdmmcvar.h:1.17	Sun Aug  2 21:44:36 2015
+++ src/sys/dev/sdmmc/sdmmcvar.h	Mon Aug  3 10:08:51 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmcvar.h,v 1.17 2015/08/02 21:44:36 jmcneill Exp $	*/
+/*	$NetBSD: sdmmcvar.h,v 1.18 2015/08/03 10:08:51 jmcneill Exp $	*/
 /*	$OpenBSD: sdmmcvar.h,v 1.13 2009/01/09 10:55:22 jsg Exp $	*/
 
 /*
@@ -229,6 +229,11 @@ 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	0x1000	/* UHS SDR50 timing */
+#define SMC_CAPS_UHS_SDR104	0x2000	/* UHS SDR104 timing */
+#define SMC_CAPS_UHS_DDR50	0x4000	/* UHS DDR50 timing */
+#define SMC_CAPS_UHS_MASK	0x7000
+#define SMC_CAPS_MMC_HS200	0x8000	/* eMMC HS200 timing */
 
 	/* function */
 	int sc_function_count;		/* number of I/O functions (SDIO) */
@@ -254,7 +259,9 @@ struct sdmmc_softc {
 	u_int sc_clkmin;		/* host min bus clock */
 	u_int sc_clkmax;		/* host max bus clock */
 	u_int sc_busclk;		/* host bus clock */
+	bool sc_busddr;			/* host bus clock is in DDR mode */
 	int sc_buswidth;		/* host bus width */
+	const char *sc_transfer_mode;	/* current transfer mode */
 
 	callout_t sc_card_detect_ch;	/* polling card insert/remove */
 };

Reply via email to