Module Name:    src
Committed By:   jmcneill
Date:           Mon Sep 11 22:00:05 UTC 2017

Modified Files:
        src/sys/arch/arm/sunxi: sunxi_mmc.c sunxi_mmc.h

Log Message:
Add support for sun50i new timing mode and calibration.


To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 src/sys/arch/arm/sunxi/sunxi_mmc.c
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/arm/sunxi/sunxi_mmc.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/arch/arm/sunxi/sunxi_mmc.c
diff -u src/sys/arch/arm/sunxi/sunxi_mmc.c:1.6 src/sys/arch/arm/sunxi/sunxi_mmc.c:1.7
--- src/sys/arch/arm/sunxi/sunxi_mmc.c:1.6	Thu Sep  7 01:07:04 2017
+++ src/sys/arch/arm/sunxi/sunxi_mmc.c	Mon Sep 11 22:00:05 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: sunxi_mmc.c,v 1.6 2017/09/07 01:07:04 jmcneill Exp $ */
+/* $NetBSD: sunxi_mmc.c,v 1.7 2017/09/11 22:00:05 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2014-2017 Jared McNeill <jmcne...@invisible.ca>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sunxi_mmc.c,v 1.6 2017/09/07 01:07:04 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sunxi_mmc.c,v 1.7 2017/09/11 22:00:05 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -67,8 +67,6 @@ static const struct sunxi_mmc_delay sunx
 };
 
 #define SUNXI_MMC_NDESC		16
-#define	SUNXI_MMC_DMA_XFERLEN	0x10000
-#define	SUNXI_MMC_DMA_FTRGLEVEL	0x20070008
 
 struct sunxi_mmc_softc;
 
@@ -110,6 +108,16 @@ static struct sdmmc_chip_functions sunxi
 	.card_intr_ack = sunxi_mmc_card_intr_ack,
 };
 
+struct sunxi_mmc_config {
+	u_int idma_xferlen;
+	u_int flags;
+#define	SUNXI_MMC_FLAG_CALIB_REG	0x01
+#define	SUNXI_MMC_FLAG_NEW_TIMINGS	0x02
+#define	SUNXI_MMC_FLAG_MASK_DATA0	0x04
+	const struct sunxi_mmc_delay *delays;
+	uint32_t dma_ftrglevel;
+};
+
 struct sunxi_mmc_softc {
 	device_t sc_dev;
 	bus_space_tag_t sc_bst;
@@ -127,9 +135,8 @@ struct sunxi_mmc_softc {
 
 	device_t sc_sdmmc_dev;
 
-	uint32_t sc_dma_ftrglevel;
+	struct sunxi_mmc_config *sc_config;
 
-	uint32_t sc_idma_xferlen;
 	bus_dma_segment_t sc_idma_segs[1];
 	int sc_idma_nsegs;
 	bus_size_t sc_idma_size;
@@ -164,11 +171,34 @@ CFATTACH_DECL_NEW(sunxi_mmc, sizeof(stru
 #define MMC_READ(sc, reg) \
 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
 
-static const char * const compatible[] = {
-	"allwinner,sun5i-a13-mmc",
-	"allwinner,sun7i-a20-mmc",
-	"allwinner,sun50i-a64-mmc",
-	NULL
+static const struct sunxi_mmc_config sun5i_a13_mmc_config = {
+	.idma_xferlen = 0x10000,
+	.dma_ftrglevel = 0x20070008,
+	.delays = NULL,
+	.flags = 0,
+};
+
+static const struct sunxi_mmc_config sun7i_a20_mmc_config = {
+	.idma_xferlen = 0x10000,
+	.dma_ftrglevel = 0x20070008,
+	.delays = sunxi_mmc_delays,
+	.flags = 0,
+};
+
+static const struct sunxi_mmc_config sun50i_a64_mmc_config = {
+	.idma_xferlen = 0x10000,
+	.dma_ftrglevel = 0x20070008,
+	.delays = NULL,
+	.flags = SUNXI_MMC_FLAG_CALIB_REG |
+		 SUNXI_MMC_FLAG_NEW_TIMINGS |
+		 SUNXI_MMC_FLAG_MASK_DATA0,
+};
+
+static const struct of_compat_data compat_data[] = {
+	{ "allwinner,sun5i-a13-mmc",	(uintptr_t)&sun5i_a13_mmc_config },
+	{ "allwinner,sun7i-a20-mmc",	(uintptr_t)&sun7i_a20_mmc_config },
+	{ "allwinner,sun50i-a64-mmc",	(uintptr_t)&sun50i_a64_mmc_config },
+	{ NULL }
 };
 
 static int
@@ -176,7 +206,7 @@ sunxi_mmc_match(device_t parent, cfdata_
 {
 	struct fdt_attach_args * const faa = aux;
 
-	return of_match_compatible(faa->faa_phandle, compatible);
+	return of_match_compat_data(faa->faa_phandle, compat_data);
 }
 
 static void
@@ -228,6 +258,7 @@ sunxi_mmc_attach(device_t parent, device
 
 	sc->sc_dev = self;
 	sc->sc_phandle = phandle;
+	sc->sc_config = (void *)of_search_compatible(phandle, compat_data)->data;
 	sc->sc_bst = faa->faa_bst;
 	sc->sc_dmat = faa->faa_dmat;
 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_BIO);
@@ -250,8 +281,6 @@ sunxi_mmc_attach(device_t parent, device
 	sc->sc_gpio_cd_inverted = of_hasprop(phandle, "cd-inverted") ? 0 : 1;
 	sc->sc_gpio_wp_inverted = of_hasprop(phandle, "wp-inverted") ? 0 : 1;
 
-	sc->sc_dma_ftrglevel = SUNXI_MMC_DMA_FTRGLEVEL;
-
 	if (sunxi_mmc_idma_setup(sc) != 0) {
 		aprint_error_dev(self, "failed to setup DMA\n");
 		return;
@@ -279,8 +308,6 @@ sunxi_mmc_idma_setup(struct sunxi_mmc_so
 {
 	int error;
 
-	sc->sc_idma_xferlen = SUNXI_MMC_DMA_XFERLEN;
-
 	sc->sc_idma_ndesc = SUNXI_MMC_NDESC;
 	sc->sc_idma_size = sizeof(struct sunxi_mmc_idma_descriptor) *
 	    sc->sc_idma_ndesc;
@@ -334,12 +361,15 @@ sunxi_mmc_set_clock(struct sunxi_mmc_sof
 	} else
 		return EINVAL;
 
-	delays = &sunxi_mmc_delays[timing];
-
 	error = clk_set_rate(sc->sc_clk_mmc, (freq * 1000) << ddr);
 	if (error != 0)
 		return error;
 
+	if (sc->sc_config->delays == NULL)
+		return 0;
+
+	delays = &sc->sc_config->delays[timing];
+
 	if (sc->sc_clk_sample) {
 		error = clk_set_rate(sc->sc_clk_sample, delays->sample_phase);
 		if (error != 0)
@@ -601,14 +631,22 @@ static int
 sunxi_mmc_bus_clock(sdmmc_chipset_handle_t sch, int freq, bool ddr)
 {
 	struct sunxi_mmc_softc *sc = sch;
-	uint32_t clkcr, gctrl;
+	uint32_t clkcr, gctrl, ntsr;
+	const u_int flags = sc->sc_config->flags;
 
 	clkcr = MMC_READ(sc, SUNXI_MMC_CLKCR);
 	if (clkcr & SUNXI_MMC_CLKCR_CARDCLKON) {
 		clkcr &= ~SUNXI_MMC_CLKCR_CARDCLKON;
+		if (flags & SUNXI_MMC_CLKCR_MASK_DATA0)
+			clkcr |= SUNXI_MMC_CLKCR_MASK_DATA0;
 		MMC_WRITE(sc, SUNXI_MMC_CLKCR, clkcr);
 		if (sunxi_mmc_update_clock(sc) != 0)
 			return 1;
+		if (flags & SUNXI_MMC_CLKCR_MASK_DATA0) {
+			clkcr = MMC_READ(sc, SUNXI_MMC_CLKCR);
+			clkcr &= ~SUNXI_MMC_CLKCR_MASK_DATA0;
+			MMC_WRITE(sc, SUNXI_MMC_CLKCR, clkcr);
+		}
 	}
 
 	if (freq) {
@@ -616,6 +654,16 @@ sunxi_mmc_bus_clock(sdmmc_chipset_handle
 		clkcr &= ~SUNXI_MMC_CLKCR_DIV;
 		clkcr |= __SHIFTIN(ddr, SUNXI_MMC_CLKCR_DIV);
 		MMC_WRITE(sc, SUNXI_MMC_CLKCR, clkcr);
+
+		if (flags & SUNXI_MMC_FLAG_NEW_TIMINGS) {
+			ntsr = MMC_READ(sc, SUNXI_MMC_NTSR);
+			ntsr |= SUNXI_MMC_NTSR_MODE_SELECT;
+			MMC_WRITE(sc, SUNXI_MMC_NTSR, ntsr);
+		}
+
+		if (flags & SUNXI_MMC_FLAG_CALIB_REG)
+			MMC_WRITE(sc, SUNXI_MMC_SAMP_DL, SUNXI_MMC_SAMP_DL_SW_EN);
+
 		if (sunxi_mmc_update_clock(sc) != 0)
 			return 1;
 
@@ -630,9 +678,16 @@ sunxi_mmc_bus_clock(sdmmc_chipset_handle
 			return 1;
 
 		clkcr |= SUNXI_MMC_CLKCR_CARDCLKON;
+		if (flags & SUNXI_MMC_CLKCR_MASK_DATA0)
+			clkcr |= SUNXI_MMC_CLKCR_MASK_DATA0;
 		MMC_WRITE(sc, SUNXI_MMC_CLKCR, clkcr);
 		if (sunxi_mmc_update_clock(sc) != 0)
 			return 1;
+		if (flags & SUNXI_MMC_CLKCR_MASK_DATA0) {
+			clkcr = MMC_READ(sc, SUNXI_MMC_CLKCR);
+			clkcr &= ~SUNXI_MMC_CLKCR_MASK_DATA0;
+			MMC_WRITE(sc, SUNXI_MMC_CLKCR, clkcr);
+		}
 	}
 
 	return 0;
@@ -718,7 +773,7 @@ sunxi_mmc_dma_prepare(struct sunxi_mmc_s
 		while (resid > 0) {
 			if (desc == sc->sc_idma_ndesc)
 				break;
-			len = min(sc->sc_idma_xferlen, resid);
+			len = min(sc->sc_config->idma_xferlen, resid);
 			dma[desc].dma_buf_size = htole32(len);
 			dma[desc].dma_buf_addr = htole32(paddr + off);
 			dma[desc].dma_config = htole32(SUNXI_MMC_IDMA_CONFIG_CH |
@@ -772,7 +827,7 @@ sunxi_mmc_dma_prepare(struct sunxi_mmc_s
 		val |= SUNXI_MMC_IDST_TRANSMIT_INT;
 	MMC_WRITE(sc, SUNXI_MMC_IDIE, val);
 	MMC_WRITE(sc, SUNXI_MMC_DLBA, desc_paddr);
-	MMC_WRITE(sc, SUNXI_MMC_FTRGLEVEL, sc->sc_dma_ftrglevel);
+	MMC_WRITE(sc, SUNXI_MMC_FTRGLEVEL, sc->sc_config->dma_ftrglevel);
 
 	return 0;
 }

Index: src/sys/arch/arm/sunxi/sunxi_mmc.h
diff -u src/sys/arch/arm/sunxi/sunxi_mmc.h:1.2 src/sys/arch/arm/sunxi/sunxi_mmc.h:1.3
--- src/sys/arch/arm/sunxi/sunxi_mmc.h:1.2	Mon Jul 17 23:31:05 2017
+++ src/sys/arch/arm/sunxi/sunxi_mmc.h	Mon Sep 11 22:00:05 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: sunxi_mmc.h,v 1.2 2017/07/17 23:31:05 jmcneill Exp $ */
+/* $NetBSD: sunxi_mmc.h,v 1.3 2017/09/11 22:00:05 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2017 Jared McNeill <jmcne...@invisible.ca>
@@ -59,6 +59,7 @@
 #define SUNXI_MMC_IDIE			0x008C
 #define SUNXI_MMC_CHDA			0x0090
 #define SUNXI_MMC_CBDA			0x0094
+#define	SUNXI_MMC_SAMP_DL		0x0144
 
 #define SUNXI_MMC_GCTRL_ACCESS_BY_AHB	__BIT(31)
 #define SUNXI_MMC_GCTRL_WAIT_MEM_ACCESS_DONE __BIT(30)
@@ -72,6 +73,7 @@
 #define SUNXI_MMC_GCTRL_RESET \
 	(SUNXI_MMC_GCTRL_SOFTRESET | SUNXI_MMC_GCTRL_FIFORESET | \
 	 SUNXI_MMC_GCTRL_DMARESET)
+#define	SUNXI_MMC_CLKCR_MASK_DATA0	__BIT(31)
 #define SUNXI_MMC_CLKCR_LOWPOWERON	__BIT(17)
 #define SUNXI_MMC_CLKCR_CARDCLKON	__BIT(16)
 #define SUNXI_MMC_CLKCR_DIV		__BITS(7,0)
@@ -165,6 +167,7 @@
 #define SUNXI_MMC_IDMA_CONFIG_ER	__BIT(5)
 #define SUNXI_MMC_IDMA_CONFIG_CES	__BIT(30)
 #define SUNXI_MMC_IDMA_CONFIG_OWN	__BIT(31)
+#define	SUNXI_MMC_SAMP_DL_SW_EN		__BIT(7)
 
 struct sunxi_mmc_idma_descriptor {
 	uint32_t        dma_config;

Reply via email to