Module Name:    src
Committed By:   jmcneill
Date:           Wed Jan  1 11:21:16 UTC 2020

Modified Files:
        src/sys/dev/fdt: dwcmmc_fdt.c
        src/sys/dev/ic: dwc_mmc.c dwc_mmc_var.h

Log Message:
dwcmmc improvements:
 - Use mmcpwrseq resources if available
 - Only set 4- or 8-bit mode if specified in the dt properties
 - Add quirk for implementations with inverted power enable logic
 - Support switching signal voltage between 1.8V and 3.3V
 - Fix a clock divider issue on Rockchip SoCs


To generate a diff of this commit:
cvs rdiff -u -r1.8 -r1.9 src/sys/dev/fdt/dwcmmc_fdt.c
cvs rdiff -u -r1.18 -r1.19 src/sys/dev/ic/dwc_mmc.c
cvs rdiff -u -r1.9 -r1.10 src/sys/dev/ic/dwc_mmc_var.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/fdt/dwcmmc_fdt.c
diff -u src/sys/dev/fdt/dwcmmc_fdt.c:1.8 src/sys/dev/fdt/dwcmmc_fdt.c:1.9
--- src/sys/dev/fdt/dwcmmc_fdt.c:1.8	Tue Apr 30 23:10:33 2019
+++ src/sys/dev/fdt/dwcmmc_fdt.c	Wed Jan  1 11:21:15 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: dwcmmc_fdt.c,v 1.8 2019/04/30 23:10:33 jmcneill Exp $ */
+/* $NetBSD: dwcmmc_fdt.c,v 1.9 2020/01/01 11:21:15 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015-2018 Jared McNeill <[email protected]>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwcmmc_fdt.c,v 1.8 2019/04/30 23:10:33 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwcmmc_fdt.c,v 1.9 2020/01/01 11:21:15 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -40,20 +40,28 @@ __KERNEL_RCSID(0, "$NetBSD: dwcmmc_fdt.c
 #include <sys/gpio.h>
 
 #include <dev/ic/dwc_mmc_var.h>
+#include <dev/sdmmc/sdmmcchip.h>
 #include <dev/fdt/fdtvar.h>
 
 static int	dwcmmc_fdt_match(device_t, cfdata_t, void *);
 static void	dwcmmc_fdt_attach(device_t, device_t, void *);
 
+static void	dwcmmc_fdt_pre_power_on(struct dwc_mmc_softc *);
+static void	dwcmmc_fdt_post_power_on(struct dwc_mmc_softc *);
+
 static int	dwcmmc_fdt_card_detect(struct dwc_mmc_softc *);
 static int	dwcmmc_fdt_bus_clock(struct dwc_mmc_softc *, int);
+static int	dwcmmc_fdt_signal_voltage(struct dwc_mmc_softc *, int);
 
 struct dwcmmc_fdt_config {
 	u_int		ciu_div;
+	u_int		flags;
 };
 
 static const struct dwcmmc_fdt_config dwcmmc_rk3288_config = {
 	.ciu_div = 2,
+	.flags = DWC_MMC_F_USE_HOLD_REG |
+		 DWC_MMC_F_DMA,
 };
 
 static const struct of_compat_data compat_data[] = {
@@ -68,6 +76,8 @@ struct dwcmmc_fdt_softc {
 	struct fdtbus_gpio_pin	*sc_pin_cd;
 	const struct dwcmmc_fdt_config *sc_conf;
 	u_int			sc_ciu_div;
+	struct fdtbus_regulator	*sc_vqmmc;
+	struct fdtbus_mmc_pwrseq *sc_pwrseq;
 };
 
 CFATTACH_DECL_NEW(dwcmmc_fdt, sizeof(struct dwcmmc_fdt_softc),
@@ -126,6 +136,9 @@ dwcmmc_fdt_attach(device_t parent, devic
 		return;
 	}
 
+	esc->sc_vqmmc = fdtbus_regulator_acquire(phandle, "vqmmc-supply");
+	esc->sc_pwrseq = fdtbus_mmc_pwrseq_get(phandle);
+
 	sc->sc_dev = self;
 	sc->sc_bst = faa->faa_bst;
 	sc->sc_dmat = faa->faa_dmat;
@@ -137,13 +150,17 @@ dwcmmc_fdt_attach(device_t parent, devic
 	}
 	esc->sc_conf = (void *)of_search_compatible(phandle, compat_data)->data;
 
-
 	if (of_getprop_uint32(phandle, "max-frequency", &sc->sc_clock_freq) != 0)
 		sc->sc_clock_freq = UINT_MAX;
+	if (of_getprop_uint32(phandle, "bus-width", &sc->sc_bus_width) != 0)
+		sc->sc_bus_width = 4;
 
 	sc->sc_fifo_depth = fifo_depth;
-	sc->sc_flags = DWC_MMC_F_USE_HOLD_REG | DWC_MMC_F_DMA;
+	sc->sc_flags = esc->sc_conf->flags;
+	sc->sc_pre_power_on = dwcmmc_fdt_pre_power_on;
+	sc->sc_post_power_on = dwcmmc_fdt_post_power_on;
 	sc->sc_bus_clock = dwcmmc_fdt_bus_clock;
+	sc->sc_signal_voltage = dwcmmc_fdt_signal_voltage;
 
 	esc->sc_pin_cd = fdtbus_gpio_acquire(phandle, "cd-gpios",
 	    GPIO_PIN_INPUT);
@@ -171,6 +188,24 @@ dwcmmc_fdt_attach(device_t parent, devic
 	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
 }
 
+static void
+dwcmmc_fdt_pre_power_on(struct dwc_mmc_softc *sc)
+{
+	struct dwcmmc_fdt_softc *esc = device_private(sc->sc_dev);
+
+	if (esc->sc_pwrseq != NULL)
+		fdtbus_mmc_pwrseq_pre_power_on(esc->sc_pwrseq);
+}
+
+static void
+dwcmmc_fdt_post_power_on(struct dwc_mmc_softc *sc)
+{
+	struct dwcmmc_fdt_softc *esc = device_private(sc->sc_dev);
+
+	if (esc->sc_pwrseq != NULL)
+		fdtbus_mmc_pwrseq_post_power_on(esc->sc_pwrseq);
+}
+
 static int
 dwcmmc_fdt_card_detect(struct dwc_mmc_softc *sc)
 {
@@ -195,10 +230,42 @@ dwcmmc_fdt_bus_clock(struct dwc_mmc_soft
 		return error;
 	}
 
-	sc->sc_clock_freq = clk_get_rate(esc->sc_clk_ciu) / ciu_div;
+	sc->sc_clock_freq = clk_get_rate(esc->sc_clk_ciu);
 
 	aprint_debug_dev(sc->sc_dev, "set clock rate to %u kHz (target %u kHz)\n",
 	    sc->sc_clock_freq, rate);
 
 	return 0;
 }
+
+static int
+dwcmmc_fdt_signal_voltage(struct dwc_mmc_softc *sc, int signal_voltage)
+{
+	struct dwcmmc_fdt_softc *esc = device_private(sc->sc_dev);
+	u_int uvol;
+	int error;
+
+	if (esc->sc_vqmmc == NULL)
+		return 0;
+
+	switch (signal_voltage) {
+	case SDMMC_SIGNAL_VOLTAGE_180:
+		uvol = 1800000;
+		break;
+	case SDMMC_SIGNAL_VOLTAGE_330:
+		uvol = 3300000;
+		break;
+	default:
+		return EINVAL;
+	}
+
+	error = fdtbus_regulator_supports_voltage(esc->sc_vqmmc, uvol, uvol);
+	if (error != 0)
+		return 0;
+
+	error = fdtbus_regulator_set_voltage(esc->sc_vqmmc, uvol, uvol);
+	if (error != 0)
+		return error;
+
+	return fdtbus_regulator_enable(esc->sc_vqmmc);
+}

Index: src/sys/dev/ic/dwc_mmc.c
diff -u src/sys/dev/ic/dwc_mmc.c:1.18 src/sys/dev/ic/dwc_mmc.c:1.19
--- src/sys/dev/ic/dwc_mmc.c:1.18	Sat Oct  5 12:27:14 2019
+++ src/sys/dev/ic/dwc_mmc.c	Wed Jan  1 11:21:15 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc_mmc.c,v 1.18 2019/10/05 12:27:14 jmcneill Exp $ */
+/* $NetBSD: dwc_mmc.c,v 1.19 2020/01/01 11:21:15 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2014-2017 Jared McNeill <[email protected]>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dwc_mmc.c,v 1.18 2019/10/05 12:27:14 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dwc_mmc.c,v 1.19 2020/01/01 11:21:15 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -54,6 +54,7 @@ static int	dwc_mmc_bus_power(sdmmc_chips
 static int	dwc_mmc_bus_clock(sdmmc_chipset_handle_t, int);
 static int	dwc_mmc_bus_width(sdmmc_chipset_handle_t, int);
 static int	dwc_mmc_bus_rod(sdmmc_chipset_handle_t, int);
+static int	dwc_mmc_signal_voltage(sdmmc_chipset_handle_t, int);
 static void	dwc_mmc_exec_command(sdmmc_chipset_handle_t,
 				      struct sdmmc_command *);
 static void	dwc_mmc_card_enable_intr(sdmmc_chipset_handle_t, int);
@@ -69,6 +70,7 @@ static struct sdmmc_chip_functions dwc_m
 	.bus_clock = dwc_mmc_bus_clock,
 	.bus_width = dwc_mmc_bus_width,
 	.bus_rod = dwc_mmc_bus_rod,
+	.signal_voltage = dwc_mmc_signal_voltage,
 	.exec_command = dwc_mmc_exec_command,
 	.card_enable_intr = dwc_mmc_card_enable_intr,
 	.card_intr_ack = dwc_mmc_card_intr_ack,
@@ -160,9 +162,16 @@ dwc_mmc_attach_i(device_t self)
 	struct dwc_mmc_softc *sc = device_private(self);
 	struct sdmmcbus_attach_args saa;
 
+	if (sc->sc_pre_power_on)
+		sc->sc_pre_power_on(sc);
+
+	dwc_mmc_signal_voltage(sc, SDMMC_SIGNAL_VOLTAGE_330);
 	dwc_mmc_host_reset(sc);
 	dwc_mmc_bus_width(sc, 1);
 
+	if (sc->sc_post_power_on)
+		sc->sc_post_power_on(sc);
+
 	memset(&saa, 0, sizeof(saa));
 	saa.saa_busname = "sdmmc";
 	saa.saa_sct = &dwc_mmc_chip_functions;
@@ -170,13 +179,15 @@ dwc_mmc_attach_i(device_t self)
 	saa.saa_clkmin = 400;
 	saa.saa_clkmax = sc->sc_clock_freq / 1000;
 	saa.saa_dmat = sc->sc_dmat;
-	saa.saa_caps = SMC_CAPS_4BIT_MODE|
-		       SMC_CAPS_8BIT_MODE|
-		       SMC_CAPS_SD_HIGHSPEED|
-		       SMC_CAPS_MMC_HIGHSPEED|
+	saa.saa_caps = SMC_CAPS_SD_HIGHSPEED |
+		       SMC_CAPS_MMC_HIGHSPEED |
 		       SMC_CAPS_AUTO_STOP |
 		       SMC_CAPS_DMA |
 		       SMC_CAPS_MULTI_SEG_DMA;
+	if (sc->sc_bus_width == 8)
+		saa.saa_caps |= SMC_CAPS_8BIT_MODE;
+	else
+		saa.saa_caps |= SMC_CAPS_4BIT_MODE;
 	if (sc->sc_card_detect)
 		saa.saa_caps |= SMC_CAPS_POLL_CARD_DET;
 
@@ -201,7 +212,16 @@ dwc_mmc_host_reset(sdmmc_chipset_handle_
 	aprint_normal_dev(sc->sc_dev, "host reset\n");
 #endif
 
-	MMC_WRITE(sc, DWC_MMC_PWREN, 1);
+	if (ISSET(sc->sc_flags, DWC_MMC_F_PWREN_INV))
+		MMC_WRITE(sc, DWC_MMC_PWREN, 0);
+	else
+		MMC_WRITE(sc, DWC_MMC_PWREN, 1);
+
+	ctrl = MMC_READ(sc, DWC_MMC_GCTRL);
+	ctrl &= ~DWC_MMC_GCTRL_USE_INTERNAL_DMAC;
+	MMC_WRITE(sc, DWC_MMC_GCTRL, ctrl);
+
+	MMC_WRITE(sc, DWC_MMC_DMAC, DWC_MMC_DMAC_SOFTRESET);
 
 	MMC_WRITE(sc, DWC_MMC_GCTRL,
 	    MMC_READ(sc, DWC_MMC_GCTRL) | DWC_MMC_GCTRL_RESET);
@@ -280,6 +300,17 @@ dwc_mmc_bus_power(sdmmc_chipset_handle_t
 }
 
 static int
+dwc_mmc_signal_voltage(sdmmc_chipset_handle_t sch, int signal_voltage)
+{
+	struct dwc_mmc_softc *sc = sch;
+
+	if (sc->sc_signal_voltage == NULL)
+		return 0;
+
+	return sc->sc_signal_voltage(sc, signal_voltage);
+}
+
+static int
 dwc_mmc_update_clock(struct dwc_mmc_softc *sc)
 {
 	uint32_t cmd;

Index: src/sys/dev/ic/dwc_mmc_var.h
diff -u src/sys/dev/ic/dwc_mmc_var.h:1.9 src/sys/dev/ic/dwc_mmc_var.h:1.10
--- src/sys/dev/ic/dwc_mmc_var.h:1.9	Sat Oct  5 12:27:14 2019
+++ src/sys/dev/ic/dwc_mmc_var.h	Wed Jan  1 11:21:15 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: dwc_mmc_var.h,v 1.9 2019/10/05 12:27:14 jmcneill Exp $ */
+/* $NetBSD: dwc_mmc_var.h,v 1.10 2020/01/01 11:21:15 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2014-2017 Jared McNeill <[email protected]>
@@ -39,9 +39,11 @@ struct dwc_mmc_softc {
 	u_int sc_flags;
 #define	DWC_MMC_F_DMA		__BIT(0)
 #define	DWC_MMC_F_USE_HOLD_REG	__BIT(1)
+#define	DWC_MMC_F_PWREN_INV	__BIT(2)
 	uint32_t sc_fifo_reg;
 	uint32_t sc_fifo_depth;
 	u_int sc_clock_freq;
+	u_int sc_bus_width;
 
 	void *sc_ih;
 	kmutex_t sc_intr_lock;
@@ -70,10 +72,14 @@ struct dwc_mmc_softc {
 	bool sc_wait_cmd;
 	bool sc_wait_data;
 
+	void (*sc_pre_power_on)(struct dwc_mmc_softc *);
+	void (*sc_post_power_on)(struct dwc_mmc_softc *);
+
 	int (*sc_card_detect)(struct dwc_mmc_softc *);
 	int (*sc_write_protect)(struct dwc_mmc_softc *);
 	void (*sc_set_led)(struct dwc_mmc_softc *, int);
 	int (*sc_bus_clock)(struct dwc_mmc_softc *, int);
+	int (*sc_signal_voltage)(struct dwc_mmc_softc *, int);
 };
 
 int	dwc_mmc_init(struct dwc_mmc_softc *);

Reply via email to