Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 26 Feb 2018 21:27:42 +0000 (UTC)
From:      Emmanuel Vadot <manu@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r330037 - head/sys/dev/mmc/host
Message-ID:  <201802262127.w1QLRg4i089936@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: manu
Date: Mon Feb 26 21:27:42 2018
New Revision: 330037
URL: https://svnweb.freebsd.org/changeset/base/330037

Log:
  dwmmc: Add clock support and other improvements
  
  * If compiled with EXT_RESOURCES look up the "biu" and "ciu" clocks in
    the DT
  * Don't use custom property "bus-frequency" but the standard one
    "clock-frequency"
  * Use the DT property max-frequency and fall back to 200Mhz if it don't exists
  * Add more mmc caps suported by the controller
  * Always ack all interrupts
  * Subclassed driver can supply an update_ios so they can handle update
    the clocks accordingly
  * Take care of the DDR bit in update_ios (no functional change since we
    do not support voltage change for now)
  * Make use of the FDT bus-width property

Modified:
  head/sys/dev/mmc/host/dwmmc.c
  head/sys/dev/mmc/host/dwmmc_var.h

Modified: head/sys/dev/mmc/host/dwmmc.c
==============================================================================
--- head/sys/dev/mmc/host/dwmmc.c	Mon Feb 26 21:25:50 2018	(r330036)
+++ head/sys/dev/mmc/host/dwmmc.c	Mon Feb 26 21:27:42 2018	(r330037)
@@ -56,6 +56,10 @@ __FBSDID("$FreeBSD$");
 #include <machine/cpu.h>
 #include <machine/intr.h>
 
+#ifdef EXT_RESOURCES
+#include <dev/extres/clk/clk.h>
+#endif
+
 #include <dev/mmc/host/dwmmc_reg.h>
 #include <dev/mmc/host/dwmmc_var.h>
 
@@ -341,14 +345,12 @@ dwmmc_intr(void *arg)
 		dprintf("%s 0x%08x\n", __func__, reg);
 
 		if (reg & DWMMC_CMD_ERR_FLAGS) {
-			WRITE4(sc, SDMMC_RINTSTS, DWMMC_CMD_ERR_FLAGS);
 			dprintf("cmd err 0x%08x cmd 0x%08x\n",
 				reg, cmd->opcode);
 			cmd->error = MMC_ERR_TIMEOUT;
 		}
 
 		if (reg & DWMMC_DATA_ERR_FLAGS) {
-			WRITE4(sc, SDMMC_RINTSTS, DWMMC_DATA_ERR_FLAGS);
 			dprintf("data err 0x%08x cmd 0x%08x\n",
 				reg, cmd->opcode);
 			cmd->error = MMC_ERR_FAILED;
@@ -361,25 +363,22 @@ dwmmc_intr(void *arg)
 		if (reg & SDMMC_INTMASK_CMD_DONE) {
 			dwmmc_cmd_done(sc);
 			sc->cmd_done = 1;
-			WRITE4(sc, SDMMC_RINTSTS, SDMMC_INTMASK_CMD_DONE);
 		}
 
-		if (reg & SDMMC_INTMASK_ACD) {
+		if (reg & SDMMC_INTMASK_ACD)
 			sc->acd_rcvd = 1;
-			WRITE4(sc, SDMMC_RINTSTS, SDMMC_INTMASK_ACD);
-		}
 
-		if (reg & SDMMC_INTMASK_DTO) {
+		if (reg & SDMMC_INTMASK_DTO)
 			sc->dto_rcvd = 1;
-			WRITE4(sc, SDMMC_RINTSTS, SDMMC_INTMASK_DTO);
-		}
 
 		if (reg & SDMMC_INTMASK_CD) {
 			/* XXX: Handle card detect */
-			WRITE4(sc, SDMMC_RINTSTS, SDMMC_INTMASK_CD);
 		}
 	}
 
+	/* Ack interrupts */
+	WRITE4(sc, SDMMC_RINTSTS, reg);
+
 	if (sc->use_pio) {
 		if (reg & (SDMMC_INTMASK_RXDR|SDMMC_INTMASK_DTO)) {
 			pio_read(sc, cmd);
@@ -411,37 +410,88 @@ parse_fdt(struct dwmmc_softc *sc)
 {
 	pcell_t dts_value[3];
 	phandle_t node;
+	uint32_t bus_hz = 0, bus_width;
 	int len;
+#ifdef EXT_RESOURCES
+	int error;
+#endif
 
 	if ((node = ofw_bus_get_node(sc->dev)) == -1)
 		return (ENXIO);
 
+	/* bus-width */
+	if (OF_getencprop(node, "bus-width", &bus_width, sizeof(uint32_t)) <= 0)
+		bus_width = 4;
+	if (bus_width >= 4)
+		sc->host.caps |= MMC_CAP_4_BIT_DATA;
+	if (bus_width >= 8)
+		sc->host.caps |= MMC_CAP_8_BIT_DATA;
+
+	/* max-frequency */
+	if (OF_getencprop(node, "max-frequency", &sc->max_hz, sizeof(uint32_t)) <= 0)
+		sc->max_hz = 200000000;
+
 	/* fifo-depth */
 	if ((len = OF_getproplen(node, "fifo-depth")) > 0) {
 		OF_getencprop(node, "fifo-depth", dts_value, len);
 		sc->fifo_depth = dts_value[0];
 	}
 
-	/* num-slots */
+	/* num-slots (Deprecated) */
 	sc->num_slots = 1;
 	if ((len = OF_getproplen(node, "num-slots")) > 0) {
+		device_printf(sc->dev, "num-slots property is deprecated\n");
 		OF_getencprop(node, "num-slots", dts_value, len);
 		sc->num_slots = dts_value[0];
 	}
 
+	/* clock-frequency */
+	if ((len = OF_getproplen(node, "clock-frequency")) > 0) {
+		OF_getencprop(node, "clock-frequency", dts_value, len);
+		bus_hz = dts_value[0];
+	}
+
+#ifdef EXT_RESOURCES
+	/* BIU (Bus Interface Unit clock) is optional */
+	error = clk_get_by_ofw_name(sc->dev, 0, "biu", &sc->biu);
+	if (sc->biu) {
+		error = clk_enable(sc->biu);
+		if (error != 0) {
+			device_printf(sc->dev, "cannot enable biu clock\n");
+			goto fail;
+		}
+	}
+
 	/*
-	 * We need some platform-specific code to know
-	 * what the clock is supplied for our device.
-	 * For now rely on the value specified in FDT.
+	 * CIU (Controller Interface Unit clock) is mandatory
+	 * if no clock-frequency property is given
 	 */
+	error = clk_get_by_ofw_name(sc->dev, 0, "ciu", &sc->ciu);
+	if (sc->ciu) {
+		error = clk_enable(sc->ciu);
+		if (error != 0) {
+			device_printf(sc->dev, "cannot enable ciu clock\n");
+			goto fail;
+		}
+		if (bus_hz != 0) {
+			error = clk_set_freq(sc->ciu, bus_hz, 0);
+			if (error != 0)
+				device_printf(sc->dev,
+				    "cannot set ciu clock to %u\n", bus_hz);
+		}
+		clk_get_freq(sc->ciu, &sc->bus_hz);
+	}
+#endif /* EXT_RESOURCES */
+
 	if (sc->bus_hz == 0) {
-		if ((len = OF_getproplen(node, "bus-frequency")) <= 0)
-			return (ENXIO);
-		OF_getencprop(node, "bus-frequency", dts_value, len);
-		sc->bus_hz = dts_value[0];
+		device_printf(sc->dev, "No bus speed provided\n");
+		goto fail;
 	}
 
 	return (0);
+
+fail:
+	return (ENXIO);
 }
 
 int
@@ -541,9 +591,10 @@ dwmmc_attach(device_t dev)
 	WRITE4(sc, SDMMC_CTRL, SDMMC_CTRL_INT_ENABLE);
 
 	sc->host.f_min = 400000;
-	sc->host.f_max = min(200000000, sc->bus_hz);
+	sc->host.f_max = sc->max_hz;
 	sc->host.host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340;
-	sc->host.caps = MMC_CAP_4_BIT_DATA;
+	sc->host.caps |= MMC_CAP_HSPEED;
+	sc->host.caps |= MMC_CAP_SIGNALING_330;
 
 	device_add_child(dev, "mmc", -1);
 	return (bus_generic_attach(dev));
@@ -608,6 +659,8 @@ dwmmc_update_ios(device_t brdev, device_t reqdev)
 {
 	struct dwmmc_softc *sc;
 	struct mmc_ios *ios;
+	uint32_t reg;
+	int ret = 0;
 
 	sc = device_get_softc(brdev);
 	ios = &sc->host.ios;
@@ -615,8 +668,6 @@ dwmmc_update_ios(device_t brdev, device_t reqdev)
 	dprintf("Setting up clk %u bus_width %d\n",
 		ios->clock, ios->bus_width);
 
-	dwmmc_setup_bus(sc, ios->clock);
-
 	if (ios->bus_width == bus_width_8)
 		WRITE4(sc, SDMMC_CTYPE, SDMMC_CTYPE_8BIT);
 	else if (ios->bus_width == bus_width_4)
@@ -629,15 +680,22 @@ dwmmc_update_ios(device_t brdev, device_t reqdev)
 		WRITE4(sc, SDMMC_CLKSEL, sc->sdr_timing);
 	}
 
-	/*
-	 * XXX: take care about DDR bit
-	 *
-	 * reg = READ4(sc, SDMMC_UHS_REG);
-	 * reg |= (SDMMC_UHS_REG_DDR);
-	 * WRITE4(sc, SDMMC_UHS_REG, reg);
-	 */
+	/* Set DDR mode */
+	reg = READ4(sc, SDMMC_UHS_REG);
+	if (ios->timing == bus_timing_uhs_ddr50 ||
+	    ios->timing == bus_timing_mmc_ddr52 ||
+	    ios->timing == bus_timing_mmc_hs400)
+		reg |= (SDMMC_UHS_REG_DDR);
+	else
+		reg &= ~(SDMMC_UHS_REG_DDR);
+	WRITE4(sc, SDMMC_UHS_REG, reg);
 
-	return (0);
+	if (sc->update_ios)
+		ret = sc->update_ios(sc, ios);
+
+	dwmmc_setup_bus(sc, ios->clock);
+
+	return (ret);
 }
 
 static int
@@ -1032,7 +1090,6 @@ dwmmc_read_ivar(device_t bus, device_t child, int whic
 		*(int *)result = sc->host.ios.vdd;
 		break;
 	case MMCBR_IVAR_CAPS:
-		sc->host.caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
 		*(int *)result = sc->host.caps;
 		break;
 	case MMCBR_IVAR_MAX_DATA:

Modified: head/sys/dev/mmc/host/dwmmc_var.h
==============================================================================
--- head/sys/dev/mmc/host/dwmmc_var.h	Mon Feb 26 21:25:50 2018	(r330036)
+++ head/sys/dev/mmc/host/dwmmc_var.h	Mon Feb 26 21:27:42 2018	(r330037)
@@ -33,6 +33,10 @@
 #ifndef DEV_MMC_HOST_DWMMC_VAR_H
 #define DEV_MMC_HOST_DWMMC_VAR_H
 
+#ifdef EXT_RESOURCES
+#include <dev/extres/clk/clk.h>
+#endif
+
 enum {
 	HWTYPE_NONE,
 	HWTYPE_ALTERA,
@@ -56,6 +60,8 @@ struct dwmmc_softc {
 	uint32_t		pwren_inverted;
 	u_int			desc_count;
 
+	int			(*update_ios)(struct dwmmc_softc *sc, struct mmc_ios *ios);
+
 	bus_dma_tag_t		desc_tag;
 	bus_dmamap_t		desc_map;
 	struct idmac_desc	*desc_ring;
@@ -67,11 +73,17 @@ struct dwmmc_softc {
 	uint32_t		dto_rcvd;
 	uint32_t		acd_rcvd;
 	uint32_t		cmd_done;
-	uint32_t		bus_hz;
+	uint64_t		bus_hz;
+	uint32_t		max_hz;
 	uint32_t		fifo_depth;
 	uint32_t		num_slots;
 	uint32_t		sdr_timing;
 	uint32_t		ddr_timing;
+
+#ifdef EXT_RESOURCES
+	clk_t			biu;
+	clk_t			ciu;
+#endif
 };
 
 DECLARE_CLASS(dwmmc_driver);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201802262127.w1QLRg4i089936>