diff options
Diffstat (limited to 'sys/dev/usb/controller')
-rw-r--r-- | sys/dev/usb/controller/ehci.c | 64 | ||||
-rw-r--r-- | sys/dev/usb/controller/ehci.h | 9 | ||||
-rw-r--r-- | sys/dev/usb/controller/ehci_ixp4xx.c | 30 | ||||
-rw-r--r-- | sys/dev/usb/controller/ehci_mv.c | 18 | ||||
-rw-r--r-- | sys/dev/usb/controller/ehcireg.h | 26 |
5 files changed, 107 insertions, 40 deletions
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_ */ |