svn commit: r305120 - head/sys/arm/allwinner

Jared McNeill jmcneill at FreeBSD.org
Wed Aug 31 10:45:54 UTC 2016


Author: jmcneill
Date: Wed Aug 31 10:45:53 2016
New Revision: 305120
URL: https://svnweb.freebsd.org/changeset/base/305120

Log:
  Add support for Allwinner A64 USB PHY.
  
  Reviewed by:	manu

Modified:
  head/sys/arm/allwinner/aw_usbphy.c

Modified: head/sys/arm/allwinner/aw_usbphy.c
==============================================================================
--- head/sys/arm/allwinner/aw_usbphy.c	Wed Aug 31 10:45:33 2016	(r305119)
+++ head/sys/arm/allwinner/aw_usbphy.c	Wed Aug 31 10:45:53 2016	(r305120)
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/kernel.h>
 #include <sys/module.h>
 #include <sys/gpio.h>
+#include <machine/bus.h>
 
 #include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
@@ -53,25 +54,89 @@ __FBSDID("$FreeBSD$");
 #include "phy_if.h"
 
 #define	USBPHY_NPHYS	4
+#define	USBPHY_NRES	USBPHY_NPHYS
+
+enum awusbphy_type {
+	AWUSBPHY_TYPE_A10 = 1,
+	AWUSBPHY_TYPE_A13,
+	AWUSBPHY_TYPE_A20,
+	AWUSBPHY_TYPE_A31,
+	AWUSBPHY_TYPE_A83T,
+	AWUSBPHY_TYPE_H3,
+	AWUSBPHY_TYPE_A64
+};
 
 static struct ofw_compat_data compat_data[] = {
-	{ "allwinner,sun4i-a10-usb-phy",	1 },
-	{ "allwinner,sun5i-a13-usb-phy",	1 },
-	{ "allwinner,sun6i-a31-usb-phy",	1 },
-	{ "allwinner,sun7i-a20-usb-phy",	1 },
-	{ "allwinner,sun8i-a83t-usb-phy",	1 },
-	{ "allwinner,sun8i-h3-usb-phy",		1 },
+	{ "allwinner,sun4i-a10-usb-phy",	AWUSBPHY_TYPE_A10 },
+	{ "allwinner,sun5i-a13-usb-phy",	AWUSBPHY_TYPE_A13 },
+	{ "allwinner,sun6i-a31-usb-phy",	AWUSBPHY_TYPE_A31 },
+	{ "allwinner,sun7i-a20-usb-phy",	AWUSBPHY_TYPE_A20 },
+	{ "allwinner,sun8i-a83t-usb-phy",	AWUSBPHY_TYPE_A83T },
+	{ "allwinner,sun8i-h3-usb-phy",		AWUSBPHY_TYPE_H3 },
+	{ "allwinner,sun50i-a64-usb-phy",	AWUSBPHY_TYPE_A64 },
 	{ NULL,					0 }
 };
 
 struct awusbphy_softc {
+	struct resource *	res[USBPHY_NRES];
 	regulator_t		reg[USBPHY_NPHYS];
 	gpio_pin_t		id_det_pin;
 	int			id_det_valid;
 	gpio_pin_t		vbus_det_pin;
 	int			vbus_det_valid;
+	enum awusbphy_type	phy_type;
 };
 
+static struct resource_spec awusbphy_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },
+	{ SYS_RES_MEMORY,	2,	RF_ACTIVE | RF_OPTIONAL },
+	{ SYS_RES_MEMORY,	3,	RF_ACTIVE | RF_OPTIONAL },
+	{ -1, 0 }
+};
+
+#define	RD4(sc, i, o)		bus_read_4((sc)->res[(i)], (o))
+#define	WR4(sc, i, o, v)	bus_write_4((sc)->res[(i)], (o), (v))
+#define	CLR4(sc, i, o, m)	WR4(sc, i, o, RD4(sc, i, o) & ~(m))
+#define	SET4(sc, i, o, m)	WR4(sc, i, o, RD4(sc, i, o) | (m))
+
+#define	OTG_PHY_CFG	0x20
+#define	 OTG_PHY_ROUTE_OTG	(1 << 0)
+#define	PMU_IRQ_ENABLE	0x00
+#define	 PMU_AHB_INCR8		(1 << 10)
+#define	 PMU_AHB_INCR4		(1 << 9)
+#define	 PMU_AHB_INCRX_ALIGN	(1 << 8)
+#define	 PMU_ULPI_BYPASS	(1 << 0)
+#define	PMU_UNK_H3	0x10
+#define	 PMU_UNK_H3_CLR		0x2
+
+static void
+awusbphy_configure(device_t dev, int phyno)
+{
+	struct awusbphy_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	if (sc->res[phyno] == NULL)
+		return;
+
+	if (sc->phy_type == AWUSBPHY_TYPE_A64)  {
+		CLR4(sc, phyno, PMU_UNK_H3, PMU_UNK_H3_CLR);
+
+		/* EHCI0 and OTG share a PHY */
+		if (phyno == 0)
+			SET4(sc, 0, OTG_PHY_CFG, OTG_PHY_ROUTE_OTG);
+		else if (phyno == 1)
+			CLR4(sc, 0, OTG_PHY_CFG, OTG_PHY_ROUTE_OTG);
+	}
+
+	if (phyno > 0) {
+		/* Enable passby */
+		SET4(sc, phyno, PMU_IRQ_ENABLE, PMU_ULPI_BYPASS |
+		    PMU_AHB_INCR8 | PMU_AHB_INCR4 | PMU_AHB_INCRX_ALIGN);
+	}
+}
+
 static int
 awusbphy_init(device_t dev)
 {
@@ -86,6 +151,8 @@ awusbphy_init(device_t dev)
 	sc = device_get_softc(dev);
 	node = ofw_bus_get_node(dev);
 
+	sc->phy_type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+
 	/* Enable clocks */
 	for (off = 0; clk_get_by_ofw_index(dev, 0, off, &clk) == 0; off++) {
 		error = clk_enable(clk);
@@ -123,6 +190,10 @@ awusbphy_init(device_t dev)
 	if (error == 0)
 		sc->vbus_det_valid = 1;
 
+	/* Allocate resources */
+	if (bus_alloc_resources(dev, awusbphy_spec, sc->res) != 0)
+		device_printf(dev, "couldn't allocate resources\n");
+
 	return (0);
 }
 
@@ -159,6 +230,9 @@ awusbphy_phy_enable(device_t dev, intptr
 
 	sc = device_get_softc(dev);
 
+	/* Configure PHY */
+	awusbphy_configure(dev, phy);
+
 	/* Regulators are optional. If not found, return success. */
 	reg = sc->reg[phy];
 	if (reg == NULL)


More information about the svn-src-all mailing list