svn commit: r294989 - in head/sys: arm/freescale/vybrid arm/xilinx dev/usb/controller mips/atheros powerpc/ps3

Michal Meloun mmel at FreeBSD.org
Thu Jan 28 14:12:01 UTC 2016


Author: mmel
Date: Thu Jan 28 14:11:59 2016
New Revision: 294989
URL: https://svnweb.freebsd.org/changeset/base/294989

Log:
  EHCI: Make core reset and port speed reading more generic.
  
  Use driver settable callbacks for handling of:
  - core post reset
  - reading actual port speed
  
  Typically, OTG enabled EHCI cores wants setting of USBMODE register,
  but this register is not defined in EHCI specification and different
  cores can have it on different offset.
  
  Also, for cores with TT extension, actual port speed must be determinable.
  But again, EHCI specification not covers this so this patch provides
  function for two most common variant of speed bits layout.
  
  Reviewed by: hselasky
  Differential Revision: https://reviews.freebsd.org/D5088

Modified:
  head/sys/arm/freescale/vybrid/vf_ehci.c
  head/sys/arm/xilinx/zy7_ehci.c
  head/sys/dev/usb/controller/ehci.c
  head/sys/dev/usb/controller/ehci.h
  head/sys/dev/usb/controller/ehci_ixp4xx.c
  head/sys/dev/usb/controller/ehci_mv.c
  head/sys/dev/usb/controller/ehcireg.h
  head/sys/mips/atheros/ar71xx_ehci.c
  head/sys/powerpc/ps3/ehci_ps3.c

Modified: head/sys/arm/freescale/vybrid/vf_ehci.c
==============================================================================
--- head/sys/arm/freescale/vybrid/vf_ehci.c	Thu Jan 28 13:32:00 2016	(r294988)
+++ head/sys/arm/freescale/vybrid/vf_ehci.c	Thu Jan 28 14:11:59 2016	(r294989)
@@ -169,6 +169,18 @@ static devclass_t ehci_devclass;
 DRIVER_MODULE(ehci, simplebus, ehci_driver, ehci_devclass, 0, 0);
 MODULE_DEPEND(ehci, usb, 1, 1, 1);
 
+static void
+vybrid_ehci_post_reset(struct ehci_softc *ehci_softc)
+{
+	uint32_t usbmode;
+
+	/* Force HOST mode */
+	usbmode = EOREAD4(ehci_softc, EHCI_USBMODE_NOLPM);
+	usbmode &= ~EHCI_UM_CM;
+	usbmode |= EHCI_UM_CM_HOST;
+	EOWRITE4(ehci_softc, EHCI_USBMODE_NOLPM, usbmode);
+}
+
 /*
  * Public methods
  */
@@ -343,8 +355,10 @@ vybrid_ehci_attach(device_t dev)
 	reg |= 0x3;
 	bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, 0xA8, reg);
 
-	/* Set flags */
-	sc->sc_flags |= EHCI_SCFLG_SETMODE | EHCI_SCFLG_NORESTERM;
+	/* Set flags  and callbacks*/
+	sc->sc_flags |= EHCI_SCFLG_TT | EHCI_SCFLG_NORESTERM;
+	sc->sc_vendor_post_reset = vybrid_ehci_post_reset;
+	sc->sc_vendor_get_port_speed = ehci_get_port_speed_portsc;
 
 	err = ehci_init(sc);
 	if (!err) {

Modified: head/sys/arm/xilinx/zy7_ehci.c
==============================================================================
--- head/sys/arm/xilinx/zy7_ehci.c	Thu Jan 28 13:32:00 2016	(r294988)
+++ head/sys/arm/xilinx/zy7_ehci.c	Thu Jan 28 14:11:59 2016	(r294989)
@@ -138,6 +138,18 @@ __FBSDID("$FreeBSD$");
 #define EHCI_REG_OFFSET	ZY7_USB_CAPLENGTH_HCIVERSION
 #define EHCI_REG_SIZE	0x100
 
+static void
+zy7_ehci_post_reset(struct ehci_softc *ehci_softc)
+{
+	uint32_t usbmode;
+
+	/* Force HOST mode */
+	usbmode = EOREAD4(ehci_softc, EHCI_USBMODE_NOLPM);
+	usbmode &= ~EHCI_UM_CM;
+	usbmode |= EHCI_UM_CM_HOST;
+	EOWRITE4(ehci_softc, EHCI_USBMODE_NOLPM, usbmode);
+}
+
 static int
 zy7_phy_config(device_t dev, bus_space_tag_t io_tag, bus_space_handle_t bsh)
 {
@@ -275,8 +287,9 @@ zy7_ehci_attach(device_t dev)
 	}
 
 	/* Customization. */
-	sc->sc_flags |= EHCI_SCFLG_SETMODE | EHCI_SCFLG_TT |
-		EHCI_SCFLG_NORESTERM;
+	sc->sc_flags |= EHCI_SCFLG_TT |	EHCI_SCFLG_NORESTERM;
+	sc->sc_vendor_post_reset = zy7_ehci_post_reset;
+	sc->sc_vendor_get_port_speed = ehci_get_port_speed_portsc;
 
 	/* Modify FIFO burst threshold from 2 to 8. */
 	bus_space_write_4(sc->sc_io_tag, bsh,

Modified: head/sys/dev/usb/controller/ehci.c
==============================================================================
--- head/sys/dev/usb/controller/ehci.c	Thu Jan 28 13:32:00 2016	(r294988)
+++ head/sys/dev/usb/controller/ehci.c	Thu Jan 28 14:11:59 2016	(r294989)
@@ -189,24 +189,8 @@ ehci_reset(ehci_softc_t *sc)
 		usb_pause_mtx(NULL, hz / 128);
 		hcr = EOREAD4(sc, EHCI_USBCMD) & EHCI_CMD_HCRESET;
 		if (!hcr) {
-			if (sc->sc_flags & (EHCI_SCFLG_SETMODE | EHCI_SCFLG_BIGEMMIO)) {
-				/*
-				 * Force USBMODE as requested.  Controllers
-				 * may have multiple operating modes.
-				 */
-				uint32_t usbmode = EOREAD4(sc, EHCI_USBMODE);
-				if (sc->sc_flags & EHCI_SCFLG_SETMODE) {
-					usbmode = (usbmode &~ EHCI_UM_CM) | EHCI_UM_CM_HOST;
-					device_printf(sc->sc_bus.bdev,
-					    "set host controller mode\n");
-				}
-				if (sc->sc_flags & EHCI_SCFLG_BIGEMMIO) {
-					usbmode = (usbmode &~ EHCI_UM_ES) | EHCI_UM_ES_BE;
-					device_printf(sc->sc_bus.bdev,
-					    "set big-endian mode\n");
-				}
-				EOWRITE4(sc,  EHCI_USBMODE, usbmode);
-			}
+			if (sc->sc_vendor_post_reset != NULL)
+				sc->sc_vendor_post_reset(sc);
 			return (0);
 		}
 	}
@@ -3066,6 +3050,36 @@ struct usb_hub_descriptor ehci_hubd =
 	.bDescriptorType = UDESC_HUB,
 };
 
+uint16_t
+ehci_get_port_speed_portsc(struct ehci_softc *sc, uint16_t index)
+{
+	uint32_t v;
+
+	v = EOREAD4(sc, EHCI_PORTSC(index));
+	v = (v >> EHCI_PORTSC_PSPD_SHIFT) & EHCI_PORTSC_PSPD_MASK;
+
+	if (v == EHCI_PORT_SPEED_HIGH)
+		return (UPS_HIGH_SPEED);
+	if (v == EHCI_PORT_SPEED_LOW)
+		return (UPS_LOW_SPEED);
+	return (0);
+}
+
+uint16_t
+ehci_get_port_speed_hostc(struct ehci_softc *sc, uint16_t index)
+{
+	uint32_t v;
+
+	v = EOREAD4(sc, EHCI_HOSTC(index));
+	v = (v >> EHCI_HOSTC_PSPD_SHIFT) & EHCI_HOSTC_PSPD_MASK;
+
+	if (v == EHCI_PORT_SPEED_HIGH)
+		return (UPS_HIGH_SPEED);
+	if (v == EHCI_PORT_SPEED_LOW)
+		return (UPS_LOW_SPEED);
+	return (0);
+}
+
 static void
 ehci_disown(ehci_softc_t *sc, uint16_t index, uint8_t lowspeed)
 {
@@ -3330,13 +3344,15 @@ ehci_roothub_exec(struct usb_device *ude
 		}
 		v = EOREAD4(sc, EHCI_PORTSC(index));
 		DPRINTFN(9, "port status=0x%04x\n", v);
-		if (sc->sc_flags & (EHCI_SCFLG_FORCESPEED | EHCI_SCFLG_TT)) {
-			if ((v & 0xc000000) == 0x8000000)
+		if (sc->sc_flags & EHCI_SCFLG_TT) {
+			if (sc->sc_vendor_get_port_speed != NULL) {
+				i = sc->sc_vendor_get_port_speed(sc, index);
+			} else {
+				device_printf(sc->sc_bus.bdev,
+				    "EHCI_SCFLG_TT quirk is set but "
+				    "sc_vendor_get_hub_speed() is NULL\n");
 				i = UPS_HIGH_SPEED;
-			else if ((v & 0xc000000) == 0x4000000)
-				i = UPS_LOW_SPEED;
-			else
-				i = 0;
+			}
 		} else {
 			i = UPS_HIGH_SPEED;
 		}

Modified: head/sys/dev/usb/controller/ehci.h
==============================================================================
--- head/sys/dev/usb/controller/ehci.h	Thu Jan 28 13:32:00 2016	(r294988)
+++ head/sys/dev/usb/controller/ehci.h	Thu Jan 28 14:11:59 2016	(r294989)
@@ -337,11 +337,8 @@ typedef struct ehci_softc {
 	uint16_t sc_intr_stat[EHCI_VIRTUAL_FRAMELIST_COUNT];
 	uint16_t sc_id_vendor;		/* vendor ID for root hub */
 	uint16_t sc_flags;		/* chip specific flags */
-#define	EHCI_SCFLG_SETMODE	0x0001	/* set bridge mode again after init */
-#define	EHCI_SCFLG_FORCESPEED	0x0002	/* force speed */
 #define	EHCI_SCFLG_NORESTERM	0x0004	/* don't terminate reset sequence */
 #define	EHCI_SCFLG_BIGEDESC	0x0008	/* big-endian byte order descriptors */
-#define	EHCI_SCFLG_BIGEMMIO	0x0010	/* big-endian byte order MMIO */
 #define	EHCI_SCFLG_TT		0x0020	/* transaction translator present */
 #define	EHCI_SCFLG_LOSTINTRBUG	0x0040	/* workaround for VIA / ATI chipsets */
 #define	EHCI_SCFLG_IAADBUG	0x0080	/* workaround for nVidia chipsets */
@@ -358,6 +355,10 @@ typedef struct ehci_softc {
 
 	char	sc_vendor[16];		/* vendor string for root hub */
 
+	void	(*sc_vendor_post_reset)(struct ehci_softc *sc);
+	uint16_t (*sc_vendor_get_port_speed)(struct ehci_softc *sc,
+	    uint16_t index);
+
 } ehci_softc_t;
 
 #define	EREAD1(sc, a)	bus_space_read_1((sc)->sc_io_tag, (sc)->sc_io_hdl, (a))
@@ -446,5 +447,7 @@ usb_error_t ehci_reset(ehci_softc_t *sc)
 usb_error_t ehci_init(ehci_softc_t *sc);
 void	ehci_detach(struct ehci_softc *sc);
 void	ehci_interrupt(ehci_softc_t *sc);
+uint16_t ehci_get_port_speed_portsc(struct ehci_softc *sc, uint16_t index);
+uint16_t ehci_get_port_speed_hostc(struct ehci_softc *sc, uint16_t index);
 
 #endif					/* _EHCI_H_ */

Modified: head/sys/dev/usb/controller/ehci_ixp4xx.c
==============================================================================
--- head/sys/dev/usb/controller/ehci_ixp4xx.c	Thu Jan 28 13:32:00 2016	(r294988)
+++ head/sys/dev/usb/controller/ehci_ixp4xx.c	Thu Jan 28 14:11:59 2016	(r294989)
@@ -86,6 +86,19 @@ static void ehci_bs_w_2(bus_space_tag_t 
 static uint32_t ehci_bs_r_4(bus_space_tag_t tag, bus_space_handle_t, bus_size_t);
 static void ehci_bs_w_4(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, uint32_t);
 
+static void
+ehci_ixp_post_reset(struct ehci_softc *ehci_softc)
+{
+	uint32_t usbmode;
+
+	/* Force HOST mode, select big-endian mode */
+	usbmode = EOREAD4(ehci_softc, EHCI_USBMODE_NOLPM);
+	usbmode &= ~EHCI_UM_CM;
+	usbmode |= EHCI_UM_CM_HOST;
+	usbmode |= EHCI_UM_ES_BE;
+	EOWRITE4(ehci_softc, EHCI_USBMODE_NOLPM, usbmode);
+}
+
 static int
 ehci_ixp_probe(device_t self)
 {
@@ -173,20 +186,21 @@ ehci_ixp_attach(device_t self)
 	}
 
 	/*
-	 * Arrange to force Host mode, select big-endian byte alignment,
-	 * and arrange to not terminate reset operations (the adapter
-	 * will ignore it if we do but might as well save a reg write).
-	 * Also, the controller has an embedded Transaction Translator
-	 * which means port speed must be read from the Port Status
-	 * register following a port enable.
+	 * Select big-endian byte alignment and arrange to not terminate
+	 * reset operations (the adapter will ignore it if we do but might
+	 * as well save a reg write). Also, the controller has an embedded
+	 * Transaction Translator which means port speed must be read from
+	 * the Port Status register following a port enable.
 	 */
 	sc->sc_flags |= EHCI_SCFLG_TT
-		     | EHCI_SCFLG_SETMODE
 		     | EHCI_SCFLG_BIGEDESC
-		     | EHCI_SCFLG_BIGEMMIO
 		     | EHCI_SCFLG_NORESTERM
 		     ;
 
+	/* Setup callbacks. */
+	sc->sc_vendor_post_reset = ehci_ixp_post_reset;
+	sc->sc_vendor_get_port_speed = ehci_get_port_speed_portsc;
+
 	err = ehci_init(sc);
 	if (!err) {
 		err = device_probe_and_attach(sc->sc_bus.bdev);

Modified: head/sys/dev/usb/controller/ehci_mv.c
==============================================================================
--- head/sys/dev/usb/controller/ehci_mv.c	Thu Jan 28 13:32:00 2016	(r294988)
+++ head/sys/dev/usb/controller/ehci_mv.c	Thu Jan 28 14:11:59 2016	(r294989)
@@ -105,6 +105,18 @@ static struct ofw_compat_data compat_dat
 	{NULL,			false}
 };
 
+static void
+mv_ehci_post_reset(struct ehci_softc *ehci_softc)
+{
+	uint32_t usbmode;
+
+	/* Force HOST mode */
+	usbmode = EOREAD4(ehci_softc, EHCI_USBMODE_NOLPM);
+	usbmode &= ~EHCI_UM_CM;
+	usbmode |= EHCI_UM_CM_HOST;
+	EOWRITE4(ehci_softc, EHCI_USBMODE_NOLPM, usbmode);
+}
+
 static int
 mv_ehci_probe(device_t self)
 {
@@ -226,13 +238,13 @@ mv_ehci_attach(device_t self)
 	 * Refer to errata document MV-S500832-00D.pdf (p. 5.24 GL USB-2) for
 	 * details.
 	 */
-	sc->sc_flags |= EHCI_SCFLG_SETMODE;
+	sc->sc_vendor_post_reset = mv_ehci_post_reset;
 	if (bootverbose)
 		device_printf(self, "5.24 GL USB-2 workaround enabled\n");
 
 	/* XXX all MV chips need it? */
-	sc->sc_flags |= EHCI_SCFLG_FORCESPEED | EHCI_SCFLG_NORESTERM;
-
+	sc->sc_flags |= EHCI_SCFLG_TT | EHCI_SCFLG_NORESTERM;
+	sc->sc_vendor_get_port_speed = ehci_get_port_speed_portsc;
 	err = ehci_init(sc);
 	if (!err) {
 		err = device_probe_and_attach(sc->sc_bus.bdev);

Modified: head/sys/dev/usb/controller/ehcireg.h
==============================================================================
--- head/sys/dev/usb/controller/ehcireg.h	Thu Jan 28 13:32:00 2016	(r294988)
+++ head/sys/dev/usb/controller/ehcireg.h	Thu Jan 28 14:11:59 2016	(r294989)
@@ -157,7 +157,17 @@
 #define	EHCI_PS_CS		0x00000001	/* RO connect status */
 #define	EHCI_PS_CLEAR		(EHCI_PS_OCC | EHCI_PS_PEC | EHCI_PS_CSC)
 
-#define	EHCI_USBMODE		0x68	/* RW USB Device mode register */
+#define	EHCI_PORT_RESET_COMPLETE	2	/* ms */
+
+/*
+ * Registers not covered by EHCI specification
+ *
+ *
+ * EHCI_USBMODE register offset is different for cores with LPM support,
+ * bits are equal
+ */
+#define	EHCI_USBMODE_NOLPM	0x68	/* RW USB Device mode reg (no LPM) */
+#define	EHCI_USBMODE_LPM	0xA8	/* RW USB Device mode reg (LPM) */
 #define	EHCI_UM_CM		0x00000003	/* R/WO Controller Mode */
 #define	EHCI_UM_CM_IDLE		0x0	/* Idle */
 #define	EHCI_UM_CM_HOST		0x3	/* Host Controller */
@@ -166,6 +176,18 @@
 #define	EHCI_UM_ES_BE		0x4	/* Big-endian byte alignment */
 #define	EHCI_UM_SDIS		0x00000010	/* R/WO Stream Disable Mode */
 
-#define	EHCI_PORT_RESET_COMPLETE	2	/* ms */
+/*
+ * Actual port speed bits depends on EHCI_HOSTC(n) registers presence,
+ * speed encoding is equal
+ */
+#define	EHCI_HOSTC(n)		(0x80+(4*(n)))	/* RO, RW Host mode control reg */
+#define	EHCI_HOSTC_PSPD_SHIFT	25
+#define	EHCI_HOSTC_PSPD_MASK	0x3
+
+#define	EHCI_PORTSC_PSPD_SHIFT	26
+#define	EHCI_PORTSC_PSPD_MASK	0x3
 
+#define	EHCI_PORT_SPEED_FULL	0
+#define	EHCI_PORT_SPEED_LOW	1
+#define	EHCI_PORT_SPEED_HIGH	2
 #endif	/* _EHCIREG_H_ */

Modified: head/sys/mips/atheros/ar71xx_ehci.c
==============================================================================
--- head/sys/mips/atheros/ar71xx_ehci.c	Thu Jan 28 13:32:00 2016	(r294988)
+++ head/sys/mips/atheros/ar71xx_ehci.c	Thu Jan 28 14:11:59 2016	(r294989)
@@ -61,6 +61,10 @@ __FBSDID("$FreeBSD$");
 
 #define EHCI_HC_DEVSTR		"AR71XX Integrated USB 2.0 controller"
 
+#define	EHCI_USBMODE		0x68	/* USB Device mode register */
+#define	EHCI_UM_CM		0x00000003	/* R/WO Controller Mode */
+#define	EHCI_UM_CM_HOST		0x3	/* Host Controller */
+
 struct ar71xx_ehci_softc {
 	ehci_softc_t		base;	/* storage for EHCI code */
 };
@@ -71,6 +75,18 @@ static device_detach_t ar71xx_ehci_detac
 bs_r_1_proto(reversed);
 bs_w_1_proto(reversed);
 
+static void
+ar71xx_ehci_post_reset(struct ehci_softc *ehci_softc)
+{
+	uint32_t usbmode;
+
+	/* Force HOST mode */
+	usbmode = EOREAD4(ehci_softc, EHCI_USBMODE_NOLPM);
+	usbmode &= ~EHCI_UM_CM;
+	usbmode |= EHCI_UM_CM_HOST;
+	EOWRITE4(ehci_softc, EHCI_USBMODE_NOLPM, usbmode);
+}
+
 static int
 ar71xx_ehci_probe(device_t self)
 {
@@ -161,7 +177,8 @@ ar71xx_ehci_attach(device_t self)
 	 * which means port speed must be read from the Port Status
 	 * register following a port enable.
 	 */
-	sc->sc_flags = EHCI_SCFLG_SETMODE;
+	sc->sc_flags = 0;
+	sc->sc_vendor_post_reset = ar71xx_ehci_post_reset;
 
 	switch (ar71xx_soc) {
 		case AR71XX_SOC_AR7241:
@@ -178,6 +195,8 @@ ar71xx_ehci_attach(device_t self)
 		case AR71XX_SOC_QCA9556:
 		case AR71XX_SOC_QCA9558:
 			sc->sc_flags |= EHCI_SCFLG_TT | EHCI_SCFLG_NORESTERM;
+			sc->sc_vendor_get_port_speed =
+			    ehci_get_port_speed_portsc;
 			break;
 		default:
 			/* fallthrough */

Modified: head/sys/powerpc/ps3/ehci_ps3.c
==============================================================================
--- head/sys/powerpc/ps3/ehci_ps3.c	Thu Jan 28 13:32:00 2016	(r294988)
+++ head/sys/powerpc/ps3/ehci_ps3.c	Thu Jan 28 14:11:59 2016	(r294989)
@@ -69,6 +69,17 @@ struct ps3_ehci_softc {
 	struct bus_space         tag;
 };
 
+static void
+ehci_ps3_post_reset(struct ehci_softc *ehci_softc)
+{
+	uint32_t usbmode;
+
+	/* Select big-endian mode */
+	usbmode = EOREAD4(ehci_softc, EHCI_USBMODE_NOLPM);
+	usbmode |= EHCI_UM_ES_BE;
+	EOWRITE4(ehci_softc, EHCI_USBMODE_NOLPM, usbmode);
+}
+
 static int
 ehci_ps3_probe(device_t dev)
 {
@@ -135,7 +146,7 @@ ehci_ps3_attach(device_t dev)
 		goto error;
 	}
 
-	sc->sc_flags |= EHCI_SCFLG_BIGEMMIO;
+	sc->sc_vendor_post_reset = ehci_ps3_post_reset;
 	err = ehci_init(sc);
 	if (err) {
 		device_printf(dev, "USB init failed err=%d\n", err);


More information about the svn-src-all mailing list