Module Name:    src
Committed By:   jmcneill
Date:           Wed Aug  5 10:30:25 UTC 2015

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

Log Message:
Implement SDHC sampling clock tuning procedure.


To generate a diff of this commit:
cvs rdiff -u -r1.78 -r1.79 src/sys/dev/sdmmc/sdhc.c
cvs rdiff -u -r1.15 -r1.16 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.78 src/sys/dev/sdmmc/sdhc.c:1.79
--- src/sys/dev/sdmmc/sdhc.c:1.78	Wed Aug  5 07:31:52 2015
+++ src/sys/dev/sdmmc/sdhc.c	Wed Aug  5 10:30:25 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdhc.c,v 1.78 2015/08/05 07:31:52 mlelstv Exp $	*/
+/*	$NetBSD: sdhc.c,v 1.79 2015/08/05 10:30:25 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.78 2015/08/05 07:31:52 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.79 2015/08/05 10:30:25 jmcneill Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -55,6 +55,7 @@ void	sdhc_dump_regs(struct sdhc_host *);
 #define SDHC_BUFFER_TIMEOUT	hz
 #define SDHC_TRANSFER_TIMEOUT	hz
 #define SDHC_DMA_TIMEOUT	(hz*3)
+#define SDHC_TUNING_TIMEOUT	hz
 
 struct sdhc_host {
 	struct sdhc_softc *sc;		/* host controller device */
@@ -182,6 +183,7 @@ static void	sdhc_card_intr_ack(sdmmc_chi
 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_execute_tuning(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);
@@ -224,6 +226,7 @@ static struct sdmmc_chip_functions sdhc_
 	/* UHS functions */
 	.signal_voltage = sdhc_signal_voltage,
 	.bus_clock_ddr = sdhc_bus_clock_ddr,
+	.execute_tuning = sdhc_execute_tuning,
 };
 
 static int
@@ -318,11 +321,11 @@ sdhc_host_found(struct sdhc_softc *sc, b
 		caps = sc->sc_caps;
 		caps2 = sc->sc_caps2;
 	} else {
-		caps = HREAD4(hp, SDHC_CAPABILITIES);
+		caps = sc->sc_caps = HREAD4(hp, SDHC_CAPABILITIES);
 		if (hp->specver >= SDHC_SPEC_VERS_300) {
-			caps2 = HREAD4(hp, SDHC_CAPABILITIES2);
+			caps2 = sc->sc_caps2 = HREAD4(hp, SDHC_CAPABILITIES2);
 		} else {
-			caps2 = 0;
+			caps2 = sc->sc_caps2 = 0;
 		}
 	}
 
@@ -1227,6 +1230,97 @@ sdhc_signal_voltage(sdmmc_chipset_handle
 	return 0;
 }
 
+/*
+ * Sampling clock tuning procedure (UHS)
+ */
+static int
+sdhc_execute_tuning(sdmmc_chipset_handle_t sch, int timing)
+{
+	struct sdhc_host *hp = (struct sdhc_host *)sch;
+	struct sdmmc_command cmd;
+	uint8_t hostctl;
+	int opcode, error, retry = 40;
+
+	switch (timing) {
+	case SDMMC_TIMING_MMC_HS200:
+		opcode = MMC_SEND_TUNING_BLOCK_HS200;
+		break;
+	case SDMMC_TIMING_UHS_SDR50:
+		if (!ISSET(hp->sc->sc_caps2, SDHC_TUNING_SDR50))
+			return 0;
+		/* FALLTHROUGH */
+	case SDMMC_TIMING_UHS_SDR104:
+		opcode = MMC_SEND_TUNING_BLOCK;
+		break;
+	default:
+		return EINVAL;
+	}
+
+	hostctl = HREAD1(hp, SDHC_HOST_CTL);
+
+	/* enable buffer read ready interrupt */
+	HSET2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_BUFFER_READ_READY);
+	HSET2(hp, SDHC_NINTR_STATUS_EN, SDHC_BUFFER_READ_READY);
+
+	/* disable DMA */
+	HCLR1(hp, SDHC_HOST_CTL, SDHC_DMA_SELECT);
+
+	/* reset tuning circuit */
+	HCLR2(hp, SDHC_HOST_CTL2, SDHC_SAMPLING_CLOCK_SEL);
+
+	/* start of tuning */
+	HWRITE2(hp, SDHC_HOST_CTL2, SDHC_EXECUTE_TUNING);
+
+	mutex_enter(&hp->intr_lock);
+	do {
+		memset(&cmd, 0, sizeof(cmd));
+		cmd.c_opcode = opcode;
+		cmd.c_arg = 0;
+		cmd.c_flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1;
+		if (ISSET(hostctl, SDHC_8BIT_MODE)) {
+			cmd.c_blklen = cmd.c_datalen = 128;
+		} else {
+			cmd.c_blklen = cmd.c_datalen = 64;
+		}
+
+		error = sdhc_start_command(hp, &cmd);
+		if (error)
+			break;
+
+		if (!sdhc_wait_intr(hp, SDHC_BUFFER_READ_READY,
+		    SDHC_TUNING_TIMEOUT)) {
+			break;
+		}
+
+		delay(1000);
+	} while (HREAD2(hp, SDHC_HOST_CTL2) & SDHC_EXECUTE_TUNING && --retry);
+	mutex_exit(&hp->intr_lock);
+
+	/* disable buffer read ready interrupt */
+	HCLR2(hp, SDHC_NINTR_SIGNAL_EN, SDHC_BUFFER_READ_READY);
+	HCLR2(hp, SDHC_NINTR_STATUS_EN, SDHC_BUFFER_READ_READY);
+
+	if (HREAD2(hp, SDHC_HOST_CTL2) & SDHC_EXECUTE_TUNING) {
+		HCLR2(hp, SDHC_HOST_CTL2,
+		    SDHC_SAMPLING_CLOCK_SEL|SDHC_EXECUTE_TUNING);
+		sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
+		aprint_error_dev(hp->sc->sc_dev,
+		    "tuning did not complete, using fixed sampling clock\n");
+		return EIO;		/* tuning did not complete */
+	}
+
+	if ((HREAD2(hp, SDHC_HOST_CTL2) & SDHC_SAMPLING_CLOCK_SEL) == 0) {
+		HCLR2(hp, SDHC_HOST_CTL2,
+		    SDHC_SAMPLING_CLOCK_SEL|SDHC_EXECUTE_TUNING);
+		sdhc_soft_reset(hp, SDHC_RESET_DAT|SDHC_RESET_CMD);
+		aprint_error_dev(hp->sc->sc_dev,
+		    "tuning failed, using fixed sampling clock\n");
+		return EIO;		/* tuning failed */
+	}
+
+	return 0;		/* tuning completed */
+}
+
 static int
 sdhc_wait_state(struct sdhc_host *hp, uint32_t mask, uint32_t value)
 {
@@ -1405,7 +1499,7 @@ sdhc_start_command(struct sdhc_host *hp,
 		command |= SDHC_CRC_CHECK_ENABLE;
 	if (ISSET(cmd->c_flags, SCF_RSP_IDX))
 		command |= SDHC_INDEX_CHECK_ENABLE;
-	if (cmd->c_data != NULL)
+	if (cmd->c_datalen > 0)
 		command |= SDHC_DATA_PRESENT_SELECT;
 
 	if (!ISSET(cmd->c_flags, SCF_RSP_PRESENT))
@@ -1438,7 +1532,7 @@ sdhc_start_command(struct sdhc_host *hp,
 	}
 
 	/* Set DMA start address. */
-	if (ISSET(hp->flags, SHF_USE_ADMA2_MASK) && cmd->c_datalen > 0) {
+	if (ISSET(hp->flags, SHF_USE_ADMA2_MASK) && cmd->c_data != NULL) {
 		for (int seg = 0; seg < cmd->c_dmamap->dm_nsegs; seg++) {
 			bus_addr_t paddr =
 			    cmd->c_dmamap->dm_segs[seg].ds_addr;

Index: src/sys/dev/sdmmc/sdhcreg.h
diff -u src/sys/dev/sdmmc/sdhcreg.h:1.15 src/sys/dev/sdmmc/sdhcreg.h:1.16
--- src/sys/dev/sdmmc/sdhcreg.h:1.15	Sun Aug  2 21:45:12 2015
+++ src/sys/dev/sdmmc/sdhcreg.h	Wed Aug  5 10:30:25 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdhcreg.h,v 1.15 2015/08/02 21:45:12 jmcneill Exp $	*/
+/*	$NetBSD: sdhcreg.h,v 1.16 2015/08/05 10:30:25 jmcneill Exp $	*/
 /*	$OpenBSD: sdhcreg.h,v 1.4 2006/07/30 17:20:40 fgsch Exp $	*/
 
 /*
@@ -143,6 +143,8 @@
 #define  SDHC_EINTR_SIGNAL_MASK		0x03ff	/* excluding vendor signals */
 #define SDHC_CMD12_ERROR_STATUS		0x3c
 #define SDHC_HOST_CTL2			0x3e
+#define  SDHC_SAMPLING_CLOCK_SEL	(1<<7)
+#define  SDHC_EXECUTE_TUNING		(1<<6)
 #define  SDHC_1_8V_SIGNAL_EN		(1<<3)
 #define  SDHC_UHS_MODE_SELECT_SHIFT	0
 #define  SDHC_UHS_MODE_SELECT_MASK	0x7

Reply via email to