Module Name:    src
Committed By:   jmcneill
Date:           Sun Aug  2 21:44:36 UTC 2015

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

Log Message:
Add basic UHS-I support. SDR50 and SDR104 are supported, but not DDR50.


To generate a diff of this commit:
cvs rdiff -u -r1.34 -r1.35 src/sys/dev/sdmmc/sdmmc_mem.c
cvs rdiff -u -r1.4 -r1.5 src/sys/dev/sdmmc/sdmmcchip.h
cvs rdiff -u -r1.15 -r1.16 src/sys/dev/sdmmc/sdmmcreg.h
cvs rdiff -u -r1.16 -r1.17 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/sdmmc_mem.c
diff -u src/sys/dev/sdmmc/sdmmc_mem.c:1.34 src/sys/dev/sdmmc/sdmmc_mem.c:1.35
--- src/sys/dev/sdmmc/sdmmc_mem.c:1.34	Fri Feb 27 16:08:17 2015
+++ src/sys/dev/sdmmc/sdmmc_mem.c	Sun Aug  2 21:44:36 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmc_mem.c,v 1.34 2015/02/27 16:08:17 nonaka Exp $	*/
+/*	$NetBSD: sdmmc_mem.c,v 1.35 2015/08/02 21:44:36 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.34 2015/02/27 16:08:17 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.35 2015/08/02 21:44:36 jmcneill Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -104,6 +104,7 @@ sdmmc_mem_enable(struct sdmmc_softc *sc)
 {
 	uint32_t host_ocr;
 	uint32_t card_ocr;
+	uint32_t new_ocr;
 	uint32_t ocr = 0;
 	int error;
 
@@ -184,19 +185,78 @@ mmc_mode:
 		error = sdmmc_mem_send_if_cond(sc, 0x1aa, &card_ocr);
 		if (error == 0 && card_ocr == 0x1aa)
 			SET(ocr, MMC_OCR_HCS);
+
+		if (sdmmc_chip_host_ocr(sc->sc_sct, sc->sc_sch) & MMC_OCR_S18A)
+			SET(ocr, MMC_OCR_S18A);
 	}
 	host_ocr |= ocr;
 
 	/* Send the new OCR value until all cards are ready. */
-	error = sdmmc_mem_send_op_cond(sc, host_ocr, NULL);
+	error = sdmmc_mem_send_op_cond(sc, host_ocr, &new_ocr);
 	if (error) {
 		DPRINTF(("%s: couldn't send memory OCR\n", SDMMCDEVNAME(sc)));
 		goto out;
 	}
 
+	if (ISSET(new_ocr, MMC_OCR_S18A) && sc->sc_sct->signal_voltage) {
+		/*
+		 * Card and host support low voltage mode, begin switch
+		 * sequence.
+		 */
+		struct sdmmc_command cmd;
+		memset(&cmd, 0, sizeof(cmd));
+		cmd.c_arg = 0;
+		cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1;
+		cmd.c_opcode = SD_VOLTAGE_SWITCH;
+		error = sdmmc_mmc_command(sc, &cmd);
+		if (error) {
+			DPRINTF(("%s: voltage switch command failed\n",
+			    SDMMCDEVNAME(sc)));
+			goto out;
+		}
+
+		delay(1000);
+
+		/*
+		 * Stop the clock
+		 */
+		error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch,
+		    SDMMC_SDCLK_OFF);
+		if (error)
+			goto out;
+
+		delay(1000);
+
+		/*
+		 * Card switch command was successful, update host controller
+		 * signal voltage setting.
+		 */
+		error = sdmmc_chip_signal_voltage(sc->sc_sct,
+		    sc->sc_sch, SDMMC_SIGNAL_VOLTAGE_180);
+		if (error)
+			goto out;
+
+		delay(5000);
+
+		/*
+		 * Switch to SDR12 timing
+		 */
+		error = sdmmc_chip_bus_clock(sc->sc_sct, sc->sc_sch, 25000);
+		if (error)
+			goto out;
+
+		delay(1000);
+
+		SET(sc->sc_flags, SMF_UHS_MODE);
+	}
+
 out:
 	SDMMC_UNLOCK(sc);
 
+	if (error)
+		printf("%s: %s failed with error %d\n", SDMMCDEVNAME(sc),
+		    __func__, error);
+
 	return error;
 }
 
@@ -617,23 +677,26 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc
 	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 },
+		  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 },
+		  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 },
+		{ 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 },
+		{ 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 },
+		{ 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;
 	sdmmc_bitfield512_t status; /* Switch Function Status */
@@ -684,6 +747,9 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc
 		    i < __arraycount(switch_group0_functions); i++, g <<= 1) {
 			if (!(switch_group0_functions[i].v & host_ocr))
 				continue;
+			if (switch_group0_functions[i].uhs &&
+			    !ISSET(sc->sc_flags, SMF_UHS_MODE))
+				break;
 			if (g & support_func)
 				best_func = i;
 		}

Index: src/sys/dev/sdmmc/sdmmcchip.h
diff -u src/sys/dev/sdmmc/sdmmcchip.h:1.4 src/sys/dev/sdmmc/sdmmcchip.h:1.5
--- src/sys/dev/sdmmc/sdmmcchip.h:1.4	Wed May 18 01:07:17 2011
+++ src/sys/dev/sdmmc/sdmmcchip.h	Sun Aug  2 21:44:36 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmcchip.h,v 1.4 2011/05/18 01:07:17 dyoung Exp $	*/
+/*	$NetBSD: sdmmcchip.h,v 1.5 2015/08/02 21:44:36 jmcneill Exp $	*/
 /*	$OpenBSD: sdmmcchip.h,v 1.3 2007/05/31 10:09:01 uwe Exp $	*/
 
 /*
@@ -57,6 +57,9 @@ struct sdmmc_chip_functions {
 	/* card interrupt */
 	void		(*card_enable_intr)(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 */
@@ -90,11 +93,18 @@ struct sdmmc_chip_functions {
 	((tag)->card_enable_intr((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_400K	400
 
+/* voltage levels for sdmmc_chip_signal_voltage() */
+#define SDMMC_SIGNAL_VOLTAGE_330	0
+#define SDMMC_SIGNAL_VOLTAGE_180	1
+
 /* SPI mode */
 struct sdmmc_spi_chip_functions {
 	/* card initialize */

Index: src/sys/dev/sdmmc/sdmmcreg.h
diff -u src/sys/dev/sdmmc/sdmmcreg.h:1.15 src/sys/dev/sdmmc/sdmmcreg.h:1.16
--- src/sys/dev/sdmmc/sdmmcreg.h:1.15	Sun Dec  7 20:07:25 2014
+++ src/sys/dev/sdmmc/sdmmcreg.h	Sun Aug  2 21:44:36 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmcreg.h,v 1.15 2014/12/07 20:07:25 jmcneill Exp $	*/
+/*	$NetBSD: sdmmcreg.h,v 1.16 2015/08/02 21:44:36 jmcneill Exp $	*/
 /*	$OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $	*/
 
 /*
@@ -58,6 +58,7 @@
 #define SD_SEND_RELATIVE_ADDR 	  	3	/* R6 */
 #define SD_SEND_SWITCH_FUNC		6	/* R1 */
 #define SD_SEND_IF_COND			8	/* R7 */
+#define SD_VOLTAGE_SWITCH		11	/* R1 */
 
 /* SD application commands */			/* response type */
 #define SD_APP_SET_BUS_WIDTH		6	/* R1 */
@@ -68,6 +69,7 @@
 /* OCR bits */
 #define MMC_OCR_MEM_READY		(1U<<31)/* memory power-up status bit */
 #define MMC_OCR_HCS			(1<<30)
+#define MMC_OCR_S18A			(1<<24)
 #define MMC_OCR_3_5V_3_6V		(1<<23)
 #define MMC_OCR_3_4V_3_5V		(1<<22)
 #define MMC_OCR_3_3V_3_4V		(1<<21)

Index: src/sys/dev/sdmmc/sdmmcvar.h
diff -u src/sys/dev/sdmmc/sdmmcvar.h:1.16 src/sys/dev/sdmmc/sdmmcvar.h:1.17
--- src/sys/dev/sdmmc/sdmmcvar.h:1.16	Fri Feb 27 16:08:17 2015
+++ src/sys/dev/sdmmc/sdmmcvar.h	Sun Aug  2 21:44:36 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmcvar.h,v 1.16 2015/02/27 16:08:17 nonaka Exp $	*/
+/*	$NetBSD: sdmmcvar.h,v 1.17 2015/08/02 21:44:36 jmcneill Exp $	*/
 /*	$OpenBSD: sdmmcvar.h,v 1.13 2009/01/09 10:55:22 jsg Exp $	*/
 
 /*
@@ -216,6 +216,7 @@ struct sdmmc_softc {
 #define SMF_MEM_MODE		0x0008	/* host in memory mode (SD or MMC) */
 #define SMF_CARD_PRESENT	0x4000	/* card presence noticed */
 #define SMF_CARD_ATTACHED	0x8000	/* card driver(s) attached */
+#define SMF_UHS_MODE		0x10000	/* host in UHS mode */
 
 	uint32_t sc_caps;		/* host capability */
 #define SMC_CAPS_AUTO_STOP	0x0001	/* send CMD12 automagically by host */

Reply via email to