Module Name:    src
Committed By:   jmcneill
Date:           Wed Aug  5 12:28:47 UTC 2015

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

Log Message:
support re-tuning modes 1 and 2


To generate a diff of this commit:
cvs rdiff -u -r1.79 -r1.80 src/sys/dev/sdmmc/sdhc.c
cvs rdiff -u -r1.16 -r1.17 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.79 src/sys/dev/sdmmc/sdhc.c:1.80
--- src/sys/dev/sdmmc/sdhc.c:1.79	Wed Aug  5 10:30:25 2015
+++ src/sys/dev/sdmmc/sdhc.c	Wed Aug  5 12:28:47 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdhc.c,v 1.79 2015/08/05 10:30:25 jmcneill Exp $	*/
+/*	$NetBSD: sdhc.c,v 1.80 2015/08/05 12:28:47 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.79 2015/08/05 10:30:25 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.80 2015/08/05 12:28:47 jmcneill Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -36,6 +36,7 @@ __KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.7
 #include <sys/systm.h>
 #include <sys/mutex.h>
 #include <sys/condvar.h>
+#include <sys/atomic.h>
 
 #include <dev/sdmmc/sdhcreg.h>
 #include <dev/sdmmc/sdhcvar.h>
@@ -78,6 +79,11 @@ struct sdhc_host {
 	kmutex_t intr_lock;
 	kcondvar_t intr_cv;
 
+	callout_t tuning_timer;
+	int tuning_timing;
+	u_int tuning_timer_count;
+	u_int tuning_timer_pending;
+
 	int specver;			/* spec. version */
 
 	uint32_t flags;			/* flags for this host */
@@ -184,6 +190,7 @@ static void	sdhc_exec_command(sdmmc_chip
 		    struct sdmmc_command *);
 static int	sdhc_signal_voltage(sdmmc_chipset_handle_t, int);
 static int	sdhc_execute_tuning(sdmmc_chipset_handle_t, int);
+static void	sdhc_tuning_timer(void *);
 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);
@@ -279,6 +286,8 @@ sdhc_host_found(struct sdhc_softc *sc, b
 
 	mutex_init(&hp->intr_lock, MUTEX_DEFAULT, IPL_SDMMC);
 	cv_init(&hp->intr_cv, "sdhcintr");
+	callout_init(&hp->tuning_timer, CALLOUT_MPSAFE);
+	callout_setfunc(&hp->tuning_timer, sdhc_tuning_timer, hp);
 
 	if (ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
 		sdhcver = HREAD4(hp, SDHC_ESDHC_HOST_CTL_VERSION);
@@ -329,6 +338,18 @@ sdhc_host_found(struct sdhc_softc *sc, b
 		}
 	}
 
+	const u_int retuning_mode = (caps2 >> SDHC_RETUNING_MODES_SHIFT) &
+	    SDHC_RETUNING_MODES_MASK;
+	if (retuning_mode == SDHC_RETUNING_MODE_1) {
+		hp->tuning_timer_count = (caps2 >> SDHC_TIMER_COUNT_SHIFT) &
+		    SDHC_TIMER_COUNT_MASK;
+		if (hp->tuning_timer_count == 0xf)
+			hp->tuning_timer_count = 0;
+		if (hp->tuning_timer_count)
+			hp->tuning_timer_count =
+			    1 << (hp->tuning_timer_count - 1);
+	}
+
 	/*
 	 * Use DMA if the host system and the controller support it.
 	 * Suports integrated or external DMA egine, with or without
@@ -442,6 +463,11 @@ sdhc_host_found(struct sdhc_softc *sc, b
 		SET(hp->ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V);
 		aprint_normal(" 3.3V");
 	}
+	if (hp->specver >= SDHC_SPEC_VERS_300) {
+		aprint_normal(", re-tuning mode %d", retuning_mode + 1);
+		if (hp->tuning_timer_count)
+			aprint_normal(" (%us timer)", hp->tuning_timer_count);
+	}
 
 	/*
 	 * Determine the maximum block length supported by the host
@@ -560,6 +586,7 @@ adma_done:
 	return 0;
 
 err:
+	callout_destroy(&hp->tuning_timer);
 	cv_destroy(&hp->intr_cv);
 	mutex_destroy(&hp->intr_lock);
 	free(hp, M_DEVBUF);
@@ -595,6 +622,8 @@ sdhc_detach(struct sdhc_softc *sc, int f
 			sdhc_soft_reset(hp, SDHC_RESET_ALL);
 			mutex_exit(&hp->intr_lock);
 		}
+		callout_halt(&hp->tuning_timer, NULL);
+		callout_destroy(&hp->tuning_timer);
 		cv_destroy(&hp->intr_cv);
 		mutex_destroy(&hp->intr_lock);
 		if (hp->ios > 0) {
@@ -841,6 +870,7 @@ sdhc_bus_power(sdmmc_chipset_handle_t sc
 	/* If power is disabled, reset the host and return now. */
 	if (ocr == 0) {
 		(void)sdhc_host_reset1(hp);
+		callout_halt(&hp->tuning_timer, &hp->intr_lock);
 		goto out;
 	}
 
@@ -1241,6 +1271,8 @@ sdhc_execute_tuning(sdmmc_chipset_handle
 	uint8_t hostctl;
 	int opcode, error, retry = 40;
 
+	hp->tuning_timing = timing;
+
 	switch (timing) {
 	case SDMMC_TIMING_MMC_HS200:
 		opcode = MMC_SEND_TUNING_BLOCK_HS200;
@@ -1318,9 +1350,22 @@ sdhc_execute_tuning(sdmmc_chipset_handle
 		return EIO;		/* tuning failed */
 	}
 
+	if (hp->tuning_timer_count) {
+		callout_schedule(&hp->tuning_timer,
+		    hz * hp->tuning_timer_count);
+	}
+
 	return 0;		/* tuning completed */
 }
 
+static void
+sdhc_tuning_timer(void *arg)
+{
+	struct sdhc_host *hp = arg;
+
+	atomic_swap_uint(&hp->tuning_timer_pending, 1);
+}
+
 static int
 sdhc_wait_state(struct sdhc_host *hp, uint32_t mask, uint32_t value)
 {
@@ -1345,6 +1390,10 @@ sdhc_exec_command(sdmmc_chipset_handle_t
 
 	mutex_enter(&hp->intr_lock);
 
+	if (atomic_cas_uint(&hp->tuning_timer_pending, 1, 0) == 1) {
+		(void)sdhc_execute_tuning(hp, hp->tuning_timing);
+	}
+
 	if (cmd->c_data && ISSET(hp->sc->sc_flags, SDHC_FLAG_ENHANCED)) {
 		const uint16_t ready = SDHC_BUFFER_READ_READY | SDHC_BUFFER_WRITE_READY;
 		if (ISSET(hp->flags, SHF_USE_DMA)) {
@@ -2097,6 +2146,13 @@ sdhc_intr(void *arg)
 		}
 
 		/*
+		 * Schedule re-tuning process (UHS).
+		 */
+		if (ISSET(status, SDHC_RETUNING_EVENT)) {
+			atomic_swap_uint(&hp->tuning_timer_pending, 1);
+		}
+
+		/*
 		 * Wake up the blocking process to service command
 		 * related interrupt(s).
 		 */

Index: src/sys/dev/sdmmc/sdhcreg.h
diff -u src/sys/dev/sdmmc/sdhcreg.h:1.16 src/sys/dev/sdmmc/sdhcreg.h:1.17
--- src/sys/dev/sdmmc/sdhcreg.h:1.16	Wed Aug  5 10:30:25 2015
+++ src/sys/dev/sdmmc/sdhcreg.h	Wed Aug  5 12:28:47 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdhcreg.h,v 1.16 2015/08/05 10:30:25 jmcneill Exp $	*/
+/*	$NetBSD: sdhcreg.h,v 1.17 2015/08/05 12:28:47 jmcneill Exp $	*/
 /*	$OpenBSD: sdhcreg.h,v 1.4 2006/07/30 17:20:40 fgsch Exp $	*/
 
 /*
@@ -112,6 +112,7 @@
 #define  SDHC_RESET_ALL			(1<<0)
 #define SDHC_NINTR_STATUS		0x30
 #define  SDHC_ERROR_INTERRUPT		(1<<15)
+#define  SDHC_RETUNING_EVENT		(1<<12)
 #define  SDHC_CARD_INTERRUPT		(1<<8)
 #define  SDHC_CARD_REMOVAL		(1<<7)
 #define  SDHC_CARD_INSERTION		(1<<6)
@@ -121,7 +122,7 @@
 #define  SDHC_BLOCK_GAP_EVENT		(1<<2)
 #define  SDHC_TRANSFER_COMPLETE		(1<<1)
 #define  SDHC_COMMAND_COMPLETE		(1<<0)
-#define  SDHC_NINTR_STATUS_MASK		0x81ff
+#define  SDHC_NINTR_STATUS_MASK		0x91ff
 #define SDHC_EINTR_STATUS		0x32
 #define  SDHC_DMA_ERROR			(1<<12)
 #define  SDHC_ADMA_ERROR		(1<<9)
@@ -190,6 +191,9 @@
 #define  SDHC_TUNING_SDR50		(1<<13)
 #define  SDHC_RETUNING_MODES_SHIFT	14
 #define  SDHC_RETUNING_MODES_MASK	0x3
+#define  SDHC_RETUNING_MODE_1		(0 << SDHC_RETUNING_MODES_SHIFT)
+#define  SDHC_RETUNING_MODE_2		(1 << SDHC_RETUNING_MODES_SHIFT)
+#define  SDHC_RETUNING_MODE_3		(2 << SDHC_RETUNING_MODES_SHIFT)
 #define  SDHC_CLOCK_MULTIPLIER_SHIFT	16
 #define  SDHC_CLOCK_MULTIPLIER_MASK	0xff
 #define SDHC_ADMA_ERROR_STATUS		0x54

Reply via email to