Module Name:    src
Committed By:   jmcneill
Date:           Sun Aug  2 21:45:12 UTC 2015

Modified Files:
        src/sys/dev/sdmmc: sdhc.c sdhcreg.h

Log Message:
add support for UHS-I modes on capable 3.0+ controllers


To generate a diff of this commit:
cvs rdiff -u -r1.70 -r1.71 src/sys/dev/sdmmc/sdhc.c
cvs rdiff -u -r1.14 -r1.15 src/sys/dev/sdmmc/sdhcreg.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.70 src/sys/dev/sdmmc/sdhc.c:1.71
--- src/sys/dev/sdmmc/sdhc.c:1.70	Sun Aug  2 11:28:01 2015
+++ src/sys/dev/sdmmc/sdhc.c	Sun Aug  2 21:45:12 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdhc.c,v 1.70 2015/08/02 11:28:01 jmcneill Exp $	*/
+/*	$NetBSD: sdhc.c,v 1.71 2015/08/02 21:45:12 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.70 2015/08/02 11:28:01 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.71 2015/08/02 21:45:12 jmcneill Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -181,6 +181,7 @@ static void	sdhc_card_enable_intr(sdmmc_
 static void	sdhc_card_intr_ack(sdmmc_chipset_handle_t);
 static void	sdhc_exec_command(sdmmc_chipset_handle_t,
 		    struct sdmmc_command *);
+static int	sdhc_signal_voltage(sdmmc_chipset_handle_t, int);
 static int	sdhc_start_command(struct sdhc_host *, struct sdmmc_command *);
 static int	sdhc_wait_state(struct sdhc_host *, uint32_t, uint32_t);
 static int	sdhc_soft_reset(struct sdhc_host *, int);
@@ -218,7 +219,10 @@ static struct sdmmc_chip_functions sdhc_
 
 	/* card interrupt */
 	.card_enable_intr = sdhc_card_enable_intr,
-	.card_intr_ack = sdhc_card_intr_ack
+	.card_intr_ack = sdhc_card_intr_ack,
+
+	/* UHS functions */
+	.signal_voltage = sdhc_signal_voltage,
 };
 
 static int
@@ -249,7 +253,7 @@ sdhc_host_found(struct sdhc_softc *sc, b
 {
 	struct sdmmcbus_attach_args saa;
 	struct sdhc_host *hp;
-	uint32_t caps;
+	uint32_t caps, caps2;
 	uint16_t sdhcver;
 	int error;
 
@@ -314,6 +318,11 @@ sdhc_host_found(struct sdhc_softc *sc, b
 	} else {
 		caps = HREAD4(hp, SDHC_CAPABILITIES);
 	}
+	if (hp->specver >= SDHC_SPEC_VERS_300) {
+		caps2 = HREAD4(hp, SDHC_CAPABILITIES2);
+	} else {
+		caps2 = 0;
+	}
 
 	/*
 	 * Use DMA if the host system and the controller support it.
@@ -402,11 +411,21 @@ sdhc_host_found(struct sdhc_softc *sc, b
 	aprint_normal(",");
 	if (ISSET(caps, SDHC_HIGH_SPEED_SUPP)) {
 		SET(hp->ocr, MMC_OCR_HCS);
-		aprint_normal(" High-Speed");
+		aprint_normal(" HS");
+	}
+	if (ISSET(caps2, SDHC_SDR50_SUPP)) {
+		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(caps, SDHC_VOLTAGE_SUPP_1_8V) &&
-	    (hp->specver < SDHC_SPEC_VERS_300 ||
-	     ISSET(caps, SDHC_EMBEDDED_SLOT))) {
+	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");
 	}
@@ -812,7 +831,7 @@ sdhc_bus_power(sdmmc_chipset_handle_t sc
 	 * Select the lowest voltage according to capabilities.
 	 */
 	ocr &= hp->ocr;
-	if (ISSET(ocr, MMC_OCR_1_7V_1_8V|MMC_OCR_1_8V_1_9V)) {
+	if (ISSET(ocr, MMC_OCR_1_7V_1_8V|MMC_OCR_1_8V_1_9V|MMC_OCR_S18A)) {
 		vdd = SDHC_VOLTAGE_1_8V;
 	} else if (ISSET(ocr, MMC_OCR_2_9V_3_0V|MMC_OCR_3_0V_3_1V)) {
 		vdd = SDHC_VOLTAGE_3_0V;
@@ -986,6 +1005,20 @@ sdhc_bus_clock(sdmmc_chipset_handle_t sc
 			goto out;
 	}
 
+	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);
+		} else {
+			HSET2(hp, SDHC_HOST_CTL2, SDHC_UHS_MODE_SELECT_SDR12);
+		}
+	}
+
 	/*
 	 * Set the minimum base clock frequency divisor.
 	 */
@@ -1155,6 +1188,25 @@ sdhc_card_intr_ack(sdmmc_chipset_handle_
 }
 
 static int
+sdhc_signal_voltage(sdmmc_chipset_handle_t sch, int signal_voltage)
+{
+	struct sdhc_host *hp = (struct sdhc_host *)sch;
+
+	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;
+	}
+
+	return 0;
+}
+
+static int
 sdhc_wait_state(struct sdhc_host *hp, uint32_t mask, uint32_t value)
 {
 	uint32_t state;

Index: src/sys/dev/sdmmc/sdhcreg.h
diff -u src/sys/dev/sdmmc/sdhcreg.h:1.14 src/sys/dev/sdmmc/sdhcreg.h:1.15
--- src/sys/dev/sdmmc/sdhcreg.h:1.14	Wed Jul 29 12:11:14 2015
+++ src/sys/dev/sdmmc/sdhcreg.h	Sun Aug  2 21:45:12 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdhcreg.h,v 1.14 2015/07/29 12:11:14 jmcneill Exp $	*/
+/*	$NetBSD: sdhcreg.h,v 1.15 2015/08/02 21:45:12 jmcneill Exp $	*/
 /*	$OpenBSD: sdhcreg.h,v 1.4 2006/07/30 17:20:40 fgsch Exp $	*/
 
 /*
@@ -142,6 +142,15 @@
 #define SDHC_EINTR_SIGNAL_EN		0x3a
 #define  SDHC_EINTR_SIGNAL_MASK		0x03ff	/* excluding vendor signals */
 #define SDHC_CMD12_ERROR_STATUS		0x3c
+#define SDHC_HOST_CTL2			0x3e
+#define  SDHC_1_8V_SIGNAL_EN		(1<<3)
+#define  SDHC_UHS_MODE_SELECT_SHIFT	0
+#define  SDHC_UHS_MODE_SELECT_MASK	0x7
+#define  SDHC_UHS_MODE_SELECT_SDR12	0
+#define  SDHC_UHS_MODE_SELECT_SDR25	1
+#define  SDHC_UHS_MODE_SELECT_SDR50	2
+#define  SDHC_UHS_MODE_SELECT_SDR104	3
+#define  SDHC_UHS_MODE_SELECT_DDR50	4
 #define SDHC_CAPABILITIES		0x40
 #define  SDHC_SHARED_BUS_SLOT		(1<<31)
 #define  SDHC_EMBEDDED_SLOT		(1<<30)
@@ -167,6 +176,20 @@
 #define  SDHC_TIMEOUT_FREQ_UNIT		(1<<7)	/* 0=KHz, 1=MHz */
 #define  SDHC_TIMEOUT_FREQ_SHIFT	0
 #define  SDHC_TIMEOUT_FREQ_MASK		0x1f
+#define SDHC_CAPABILITIES2		0x44
+#define  SDHC_SDR50_SUPP		(1<<0)
+#define  SDHC_SDR104_SUPP		(1<<1)
+#define  SDHC_DDR50_SUPP		(1<<2)
+#define  SDHC_DRIVER_TYPE_A		(1<<4)
+#define  SDHC_DRIVER_TYPE_C		(1<<5)
+#define  SDHC_DRIVER_TYPE_D		(1<<6)
+#define  SDHC_TIMER_COUNT_SHIFT		8
+#define  SDHC_TIMER_COUNT_MASK		0xf
+#define  SDHC_TUNING_SDR50		(1<<13)
+#define  SDHC_RETUNING_MODES_SHIFT	14
+#define  SDHC_RETUNING_MODES_MASK	0x3
+#define  SDHC_CLOCK_MULTIPLIER_SHIFT	16
+#define  SDHC_CLOCK_MULTIPLIER_MASK	0xff
 #define SDHC_ADMA_ERROR_STATUS		0x54
 #define  SDHC_ADMA_LENGTH_MISMATCH	(1<<2)
 #define  SDHC_ADMA_ERROR_STATE		(3<<0)

Reply via email to