svn commit: r320928 - in head/sys: arm/freescale/imx dev/usb/controller

Ian Lepore ian at FreeBSD.org
Thu Jul 13 02:16:16 UTC 2017


Author: ian
Date: Thu Jul 13 02:16:15 2017
New Revision: 320928
URL: https://svnweb.freebsd.org/changeset/base/320928

Log:
  Support the "disable-over-current" property for imx ehci controllers.
  
  It turns out that this is more than a power optization.  The OTG port
  won't work on boards that have this property unless this setting is honored.
  
  Also ensure that the usb phy device attaches before ehci.

Modified:
  head/sys/arm/freescale/imx/imx6_usbphy.c
  head/sys/dev/usb/controller/ehci_imx.c

Modified: head/sys/arm/freescale/imx/imx6_usbphy.c
==============================================================================
--- head/sys/arm/freescale/imx/imx6_usbphy.c	Thu Jul 13 00:28:36 2017	(r320927)
+++ head/sys/arm/freescale/imx/imx6_usbphy.c	Thu Jul 13 02:16:15 2017	(r320928)
@@ -198,5 +198,11 @@ static driver_t usbphy_driver = {
 
 static devclass_t usbphy_devclass;
 
-DRIVER_MODULE(usbphy, simplebus, usbphy_driver, usbphy_devclass, 0, 0);
+/*
+ * This driver needs to start before the ehci driver, but later than the usual
+ * "special" drivers like clocks and cpu.  Ehci starts at DEFAULT so
+ * DEFAULT-1000 seems good.
+ */
+EARLY_DRIVER_MODULE(usbphy, simplebus, usbphy_driver, usbphy_devclass, 0, 0,
+    BUS_PASS_DEFAULT - 1000);
 

Modified: head/sys/dev/usb/controller/ehci_imx.c
==============================================================================
--- head/sys/dev/usb/controller/ehci_imx.c	Thu Jul 13 00:28:36 2017	(r320927)
+++ head/sys/dev/usb/controller/ehci_imx.c	Thu Jul 13 02:16:15 2017	(r320928)
@@ -83,12 +83,11 @@ __FBSDID("$FreeBSD$");
  * data, this means that the resources (memory-mapped register range) for the
  * non-core registers belongs to a device other than the echi devices.
  *
- * At the moment we have no need to access the non-core registers, so all of
- * this amounts to documenting what's known.  The following compat strings have
- * been seen in existing FDT data:
- *   - "fsl,imx25-usbmisc"
- *   - "fsl,imx51-usbmisc";
- *   - "fsl,imx6q-usbmisc";
+ * Because the main ehci device cannot access registers in a range that's
+ * defined in the fdt data as belonging to another device, we implement a teeny
+ * little "usbmisc" driver which exists only to provide access to the usbmisc
+ * control register for each of the 4 usb controller instances.  That little
+ * driver is implemented here in this file, before the main driver.
  *
  * In addition to the single usbmisc device, the existing FDT data defines a
  * separate device for each of the OTG or EHCI cores within the USBOH3.  Each of
@@ -133,18 +132,127 @@ __FBSDID("$FreeBSD$");
  *
  */
 
-static struct ofw_compat_data compat_data[] = {
-	{"fsl,imx6q-usb",	1},
-	{"fsl,imx53-usb",	1},
-	{"fsl,imx51-usb",	1},
-	{"fsl,imx28-usb",	1},
-	{"fsl,imx27-usb",	1},
-	{"fsl,imx25-usb",	1},
-	{"fsl,imx23-usb",	1},
-	{NULL,		 	0},
+/*-----------------------------------------------------------------------------
+ * imx_usbmisc driver
+ *---------------------------------------------------------------------------*/
+
+#define	USBNC_OVER_CUR_POL	  (1u << 8)
+#define	USBNC_OVER_CUR_DIS	  (1u << 7)
+
+struct imx_usbmisc_softc {
+	device_t	dev;
+	struct resource	*mmio;
 };
 
+static struct ofw_compat_data usbmisc_compat_data[] = {
+	{"fsl,imx6q-usbmisc",	true},
+	{"fsl,imx51-usbmisc",	true},
+	{"fsl,imx25-usbmisc",	true},
+	{NULL, 			false},
+};
+
+static void
+imx_usbmisc_set_ctrl(device_t dev, u_int index, uint32_t bits)
+{
+	struct imx_usbmisc_softc *sc;
+	uint32_t reg;
+
+	sc = device_get_softc(dev);
+	reg = bus_read_4(sc->mmio, index * sizeof(uint32_t));
+	bus_write_4(sc->mmio, index * sizeof(uint32_t), reg | bits);
+}
+
+static void
+imx_usbmisc_clr_ctrl(device_t dev, u_int index, uint32_t bits)
+{
+	struct imx_usbmisc_softc *sc;
+	uint32_t reg;
+
+	sc = device_get_softc(dev);
+	reg = bus_read_4(sc->mmio, index * sizeof(uint32_t));
+	bus_write_4(sc->mmio, index * sizeof(uint32_t), reg & ~bits);
+}
+
+static int
+imx_usbmisc_probe(device_t dev)
+{
+
+	if (!ofw_bus_status_okay(dev))
+		return (ENXIO);
+
+	if (ofw_bus_search_compatible(dev, usbmisc_compat_data)->ocd_data) {
+		device_set_desc(dev, "i.MX USB Misc Control");
+		return (BUS_PROBE_DEFAULT);
+	}
+	return (ENXIO);
+}
+
+static int
+imx_usbmisc_detach(device_t dev)
+{
+	struct imx_usbmisc_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	if (sc->mmio != NULL)
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mmio);
+
+	return (0);
+}
+
+static int
+imx_usbmisc_attach(device_t dev)
+{
+	struct imx_usbmisc_softc *sc;
+	int err, rid;
+
+	sc = device_get_softc(dev);
+	err = 0;
+
+	/* Allocate bus_space resources. */
+	rid = 0;
+	sc->mmio = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+	    RF_ACTIVE);
+	if (sc->mmio == NULL) {
+		device_printf(dev, "Cannot allocate memory resources\n");
+		return (ENXIO);
+	}
+
+	OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev);
+
+	return (0);
+}
+
+static device_method_t imx_usbmisc_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe, 	imx_usbmisc_probe),
+	DEVMETHOD(device_attach,	imx_usbmisc_attach),
+	DEVMETHOD(device_detach,	imx_usbmisc_detach),
+
+	DEVMETHOD_END
+};
+
+static driver_t imx_usbmisc_driver = {
+	"imx_usbmisc",
+	imx_usbmisc_methods,
+	sizeof(struct imx_usbmisc_softc)
+};
+
+static devclass_t imx_usbmisc_devclass;
+
 /*
+ * This driver needs to start before the ehci driver, but later than the usual
+ * "special" drivers like clocks and cpu.  Ehci starts at DEFAULT so
+ * DEFAULT-1000 seems good.
+ */
+EARLY_DRIVER_MODULE(imx_usbmisc, simplebus, imx_usbmisc_driver,
+    imx_usbmisc_devclass, 0, 0, BUS_PASS_DEFAULT - 1000);
+
+/*-----------------------------------------------------------------------------
+ * imx_ehci driver...
+ *---------------------------------------------------------------------------*/
+
+/*
  * Each EHCI device in the SoC has some SoC-specific per-device registers at an
  * offset of 0, then the standard EHCI registers begin at an offset of 0x100.
  */
@@ -153,10 +261,22 @@ static struct ofw_compat_data compat_data[] = {
 
 struct imx_ehci_softc {
 	ehci_softc_t	ehci_softc;
+	device_t	dev;
 	struct resource	*ehci_mem_res;	/* EHCI core regs. */
 	struct resource	*ehci_irq_res;	/* EHCI core IRQ. */ 
 };
 
+static struct ofw_compat_data compat_data[] = {
+	{"fsl,imx6q-usb",	1},
+	{"fsl,imx53-usb",	1},
+	{"fsl,imx51-usb",	1},
+	{"fsl,imx28-usb",	1},
+	{"fsl,imx27-usb",	1},
+	{"fsl,imx25-usb",	1},
+	{"fsl,imx23-usb",	1},
+	{NULL,		 	0},
+};
+
 static void
 imx_ehci_post_reset(struct ehci_softc *ehci_softc)
 {
@@ -215,6 +335,36 @@ imx_ehci_detach(device_t dev)
 	return (0);
 }
 
+static void
+imx_ehci_disable_oc(struct imx_ehci_softc *sc)
+{
+	device_t usbmdev;
+	pcell_t usbmprops[2];
+	phandle_t node;
+	ssize_t size;
+	int index;
+
+	/* Get the reference to the usbmisc driver from the fdt data */
+	node = ofw_bus_get_node(sc->dev);
+	size = OF_getencprop(node, "fsl,usbmisc", usbmprops,
+	    sizeof(usbmprops));
+	if (size < sizeof(usbmprops)) {
+		device_printf(sc->dev, "failed to retrieve fsl,usbmisc "
+		   "property, cannot disable overcurrent protection");
+		return;
+	}
+	/* Retrieve the device_t via the xref handle. */
+	usbmdev = OF_device_from_xref(usbmprops[0]);
+	if (usbmdev == NULL) {
+		device_printf(sc->dev, "usbmisc device not found, "
+		    "cannot disable overcurrent protection");
+		return;
+	}
+	/* Call the device routine to set the overcurrent disable bit. */
+	index = usbmprops[1];
+	imx_usbmisc_set_ctrl(usbmdev, index, USBNC_OVER_CUR_DIS);
+}
+
 static int
 imx_ehci_attach(device_t dev)
 {
@@ -223,6 +373,7 @@ imx_ehci_attach(device_t dev)
 	int err, rid;
 
 	sc = device_get_softc(dev);
+	sc->dev = dev;
 	esc = &sc->ehci_softc;
 	err = 0;
 
@@ -282,6 +433,10 @@ imx_ehci_attach(device_t dev)
 
 	/* Turn on clocks. */
 	imx_ccm_usb_enable(dev);
+
+	/* Disable overcurrent detection, if configured to do so. */
+	if (OF_hasprop(ofw_bus_get_node(sc->dev), "disable-over-current"))
+		imx_ehci_disable_oc(sc);
 
 	/* Add USB bus device. */
 	esc->sc_bus.bdev = device_add_child(dev, "usbus", -1);


More information about the svn-src-all mailing list