From 9dfb3bdef2dceae556e8079e744c317163ac0dcd Mon Sep 17 00:00:00 2001 From: Christian Mauderer Date: Mon, 11 Feb 2019 09:35:37 +0100 Subject: ehci_imx: Set/clear ENHOSTDISCONNECT in USB PHY. This is not a nice solution but it should work on all chips. As soon as FreeBSD has a nice solution via the USB PHY driver, this should be replaced. Update #3869. --- freebsd/sys/dev/usb/controller/ehci_imx.c | 59 +++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to 'freebsd') diff --git a/freebsd/sys/dev/usb/controller/ehci_imx.c b/freebsd/sys/dev/usb/controller/ehci_imx.c index d158df1d..544a63b5 100644 --- a/freebsd/sys/dev/usb/controller/ehci_imx.c +++ b/freebsd/sys/dev/usb/controller/ehci_imx.c @@ -50,6 +50,9 @@ __FBSDID("$FreeBSD$"); #include #include +#ifdef __rtems__ +#include +#endif /* __rtems__ */ #include #include @@ -270,6 +273,9 @@ struct imx_ehci_softc { device_t dev; struct resource *ehci_mem_res; /* EHCI core regs. */ struct resource *ehci_irq_res; /* EHCI core IRQ. */ +#ifdef __rtems__ + void *phy_regs; +#endif /* __rtems__ */ }; static struct ofw_compat_data compat_data[] = { @@ -380,6 +386,32 @@ imx_ehci_disable_oc(struct imx_ehci_softc *sc) index = usbmprops[1]; imx_usbmisc_set_ctrl(usbmdev, index, USBNC_OVER_CUR_DIS); } +#ifdef __rtems__ +#define BUS_SPACE_PHYSADDR(res, offs) \ + ((u_int)(rman_get_start(res)+(offs))) + +static uint16_t +imx_ehci_get_port_speed_portsc(struct ehci_softc *sc, uint16_t index) +{ + uint32_t v; + struct imx_ehci_softc *isc = (struct imx_ehci_softc *)sc; + + v = ehci_get_port_speed_portsc(sc, index); + + /* Set/clear ENHOSTDISCONDETECT in USBPHY CTRL register */ + /* FIXME: This is a very hacky method. It should be done by the phy + * driver instead. */ + volatile uint32_t *ctrl_set = isc->phy_regs + 0x34; + volatile uint32_t *ctrl_clr = isc->phy_regs + 0x38; + if (v == UPS_HIGH_SPEED) { + *ctrl_set = 0x2; + } else { + *ctrl_clr = 0x2; + } + + return (v); +} +#endif /* __rtems__ */ static int imx_ehci_attach(device_t dev) @@ -474,6 +506,33 @@ imx_ehci_attach(device_t dev) esc->sc_flags |= EHCI_SCFLG_NORESTERM | EHCI_SCFLG_TT; esc->sc_vendor_post_reset = imx_ehci_post_reset; esc->sc_vendor_get_port_speed = ehci_get_port_speed_portsc; +#ifdef __rtems__ + /* + * FIXME: This is a big hack to get the PHY regs and set one bit during + * changes of the port speed. + */ + sc->phy_regs = 0; + if (OF_hasprop(ofw_bus_get_node(sc->dev), "fsl,usbphy")) { + phandle_t *cells; + int len; + phandle_t phynode; + + cells = NULL; + len = OF_getencprop_alloc_multi(ofw_bus_get_node(sc->dev), + "fsl,usbphy", sizeof(*cells), (void **)&cells); + if (len > 0 + && (phynode = OF_node_from_xref(cells[0])) != -1 && + ofw_bus_node_is_compatible(phynode, "fsl,imx6ul-usbphy")) { + u_long base, size; + if (fdt_regsize(phynode, &base, &size) == 0) { + sc->phy_regs = (void*)base; + esc->sc_vendor_get_port_speed = + imx_ehci_get_port_speed_portsc; + } + } + OF_prop_free(cells); + } +#endif /* __rtems__ */ err = ehci_init(esc); if (err != 0) { -- cgit v1.2.3