summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/arm/freescale/vybrid/vf_ehci.c18
-rw-r--r--sys/arm/xilinx/zy7_ehci.c17
-rw-r--r--sys/dev/usb/controller/ehci.c64
-rw-r--r--sys/dev/usb/controller/ehci.h9
-rw-r--r--sys/dev/usb/controller/ehci_ixp4xx.c30
-rw-r--r--sys/dev/usb/controller/ehci_mv.c18
-rw-r--r--sys/dev/usb/controller/ehcireg.h26
-rw-r--r--sys/mips/atheros/ar71xx_ehci.c21
-rw-r--r--sys/powerpc/ps3/ehci_ps3.c13
9 files changed, 170 insertions, 46 deletions
diff --git a/sys/arm/freescale/vybrid/vf_ehci.c b/sys/arm/freescale/vybrid/vf_ehci.c
index 122513f..0a7dc94 100644
--- a/sys/arm/freescale/vybrid/vf_ehci.c
+++ b/sys/arm/freescale/vybrid/vf_ehci.c
@@ -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) {
diff --git a/sys/arm/xilinx/zy7_ehci.c b/sys/arm/xilinx/zy7_ehci.c
index f74a02f..f03c131 100644
--- a/sys/arm/xilinx/zy7_ehci.c
+++ b/sys/arm/xilinx/zy7_ehci.c
@@ -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,
diff --git a/sys/dev/usb/controller/ehci.c b/sys/dev/usb/controller/ehci.c
index 0f93725..eb4ccb9 100644
--- a/sys/dev/usb/controller/ehci.c
+++ b/sys/dev/usb/controller/ehci.c
@@ -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 *udev,
}
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;
}
diff --git a/sys/dev/usb/controller/ehci.h b/sys/dev/usb/controller/ehci.h
index 808ff9f..0d1e19a 100644
--- a/sys/dev/usb/controller/ehci.h
+++ b/sys/dev/usb/controller/ehci.h
@@ -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_ */
diff --git a/sys/dev/usb/controller/ehci_ixp4xx.c b/sys/dev/usb/controller/ehci_ixp4xx.c
index 301032e..05efbb5 100644
--- a/sys/dev/usb/controller/ehci_ixp4xx.c
+++ b/sys/dev/usb/controller/ehci_ixp4xx.c
@@ -86,6 +86,19 @@ static void ehci_bs_w_2(bus_space_tag_t tag, bus_space_handle_t, bus_size_t, uin
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);
diff --git a/sys/dev/usb/controller/ehci_mv.c b/sys/dev/usb/controller/ehci_mv.c
index f06a830..cd7d549 100644
--- a/sys/dev/usb/controller/ehci_mv.c
+++ b/sys/dev/usb/controller/ehci_mv.c
@@ -105,6 +105,18 @@ static struct ofw_compat_data compat_data[] = {
{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);
diff --git a/sys/dev/usb/controller/ehcireg.h b/sys/dev/usb/controller/ehcireg.h
index 1f5fc5c..1bfda90 100644
--- a/sys/dev/usb/controller/ehcireg.h
+++ b/sys/dev/usb/controller/ehcireg.h
@@ -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_ */
diff --git a/sys/mips/atheros/ar71xx_ehci.c b/sys/mips/atheros/ar71xx_ehci.c
index 5b7b3e2..07e06b9 100644
--- a/sys/mips/atheros/ar71xx_ehci.c
+++ b/sys/mips/atheros/ar71xx_ehci.c
@@ -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_detach;
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 */
diff --git a/sys/powerpc/ps3/ehci_ps3.c b/sys/powerpc/ps3/ehci_ps3.c
index 2d57943..63c31a5 100644
--- a/sys/powerpc/ps3/ehci_ps3.c
+++ b/sys/powerpc/ps3/ehci_ps3.c
@@ -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);
OpenPOWER on IntegriCloud