On Fri, Jun 22, 2018 at 07:46:57PM +0300, Nikita Yushchenko wrote: > This is needed when host is known to not work properly in high speed > mode. > > In linux, chipidea driver supports 'maximum-speed' device tree property. > When that is set to "full-speed", driver sets PFSC bit in PORTSC > register, which disallows use of high speed mode. > > This patch implements same support for barebox. > > Important technical detail is that PFSC bit is cleared by port reset, > thus setting it has to be done in ehci->init() callback which is called > after ehci_reset(). > > Signed-off-by: Nikita Yushchenko <nikita.yoush@xxxxxxxxxxxxxxxxxx> > --- Applied, thanks Sascha > drivers/usb/core/common.c | 12 ++++++++++++ > drivers/usb/core/of.c | 24 ++++++++++++++++++++++++ > drivers/usb/imx/chipidea-imx.c | 13 +++++++++++++ > include/usb/ch9.h | 6 ++++++ > include/usb/chipidea-imx.h | 1 + > include/usb/usb.h | 3 +++ > 6 files changed, 59 insertions(+) > > diff --git a/drivers/usb/core/common.c b/drivers/usb/core/common.c > index 690d5a39e..bcbe3a155 100644 > --- a/drivers/usb/core/common.c > +++ b/drivers/usb/core/common.c > @@ -17,3 +17,15 @@ const char *usb_speed_string(enum usb_device_speed speed) > return speed_names[speed]; > } > EXPORT_SYMBOL_GPL(usb_speed_string); > + > +enum usb_device_speed usb_speed_by_string(const char *string) > +{ > + unsigned int i; > + > + for (i = 0; i < ARRAY_SIZE(speed_names); i++) > + if (!strcmp(string, speed_names[i])) > + return i; > + > + return USB_SPEED_UNKNOWN; > +} > +EXPORT_SYMBOL_GPL(usb_speed_by_string); > diff --git a/drivers/usb/core/of.c b/drivers/usb/core/of.c > index fd2036842..979088ef4 100644 > --- a/drivers/usb/core/of.c > +++ b/drivers/usb/core/of.c > @@ -90,3 +90,27 @@ enum usb_phy_interface of_usb_get_phy_mode(struct device_node *np, > return USBPHY_INTERFACE_MODE_UNKNOWN; > } > EXPORT_SYMBOL_GPL(of_usb_get_phy_mode); > + > +/** > + * of_usb_get_maximum_speed - Get maximum speed for given device_node > + * @np: Pointer to the given device_node > + * > + * The function gets maximum speed string from property 'maximum-speed', > + * and returns the correspondig enum usb_device_speed > + */ > +enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np, > + const char *propname) > +{ > + const char *maximum_speed; > + int err; > + > + if (!propname) > + propname = "maximum-speed"; > + > + err = of_property_read_string(np, propname, &maximum_speed); > + if (err < 0) > + return USB_SPEED_UNKNOWN; > + > + return usb_speed_by_string(maximum_speed); > +} > +EXPORT_SYMBOL_GPL(of_usb_get_maximum_speed); > diff --git a/drivers/usb/imx/chipidea-imx.c b/drivers/usb/imx/chipidea-imx.c > index 505f5eb35..3e3e6a365 100644 > --- a/drivers/usb/imx/chipidea-imx.c > +++ b/drivers/usb/imx/chipidea-imx.c > @@ -51,6 +51,7 @@ struct imx_chipidea { > static int imx_chipidea_port_init(void *drvdata) > { > struct imx_chipidea *ci = drvdata; > + uint32_t portsc; > int ret; > > if ((ci->flags & MXC_EHCI_PORTSC_MASK) == MXC_EHCI_MODE_ULPI) { > @@ -74,6 +75,14 @@ static int imx_chipidea_port_init(void *drvdata) > if (ret) > dev_err(ci->dev, "misc init failed: %s\n", strerror(-ret)); > > + /* PFSC bit is reset by ehci_reset(), thus have to set it not in > + * probe but here, after ehci_reset() is already called */ > + if (ci->flags & MXC_EHCI_PFSC) { > + portsc = readl(ci->base + 0x184); > + portsc |= MXC_EHCI_PFSC; > + writel(portsc, ci->base + 0x184); > + } > + > return ret; > } > > @@ -159,6 +168,10 @@ static int imx_chipidea_probe_dt(struct imx_chipidea *ci) > "over-current-active-high", NULL)) > ci->flags |= MXC_EHCI_OC_PIN_ACTIVE_LOW; > > + if (of_usb_get_maximum_speed(ci->dev->device_node, NULL) == > + USB_SPEED_FULL) > + ci->flags |= MXC_EHCI_PFSC; > + > return 0; > } > > diff --git a/include/usb/ch9.h b/include/usb/ch9.h > index ab5d53192..b44d41e85 100644 > --- a/include/usb/ch9.h > +++ b/include/usb/ch9.h > @@ -1004,6 +1004,12 @@ struct usb_set_sel_req { > */ > const char *usb_speed_string(enum usb_device_speed speed); > > +/** > + * usb_speed_by_string() - Get speed from human readable name. > + * @string: The human readable name for the speed. If it is not one of known > + * names, USB_SPEED_UNKNOWN will be returned. > + */ > +enum usb_device_speed usb_speed_by_string(const char *string); > > /** > * usb_state_string - Returns human readable name for the state. > diff --git a/include/usb/chipidea-imx.h b/include/usb/chipidea-imx.h > index 640ae0694..973aee6a0 100644 > --- a/include/usb/chipidea-imx.h > +++ b/include/usb/chipidea-imx.h > @@ -13,6 +13,7 @@ > #define MXC_EHCI_MODE_ULPI (2 << 30) > #define MXC_EHCI_MODE_HSIC (1 << 25) > #define MXC_EHCI_MODE_SERIAL (3 << 30) > +#define MXC_EHCI_PFSC (1 << 24) > > /* > * USB misc flags > diff --git a/include/usb/usb.h b/include/usb/usb.h > index 93308cec0..9aab06c87 100644 > --- a/include/usb/usb.h > +++ b/include/usb/usb.h > @@ -438,6 +438,9 @@ enum usb_dr_mode { > enum usb_phy_interface of_usb_get_phy_mode(struct device_node *np, > const char *propname); > > +enum usb_device_speed of_usb_get_maximum_speed(struct device_node *np, > + const char *propname); > + > extern struct list_head usb_device_list; > > #endif /*_USB_H_ */ > -- > 2.11.0 > > -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox