* [PATCH] usb: imx: implement support for limiting host to full speed
@ 2018-06-22 16:46 Nikita Yushchenko
2018-06-26 4:56 ` Sascha Hauer
0 siblings, 1 reply; 2+ messages in thread
From: Nikita Yushchenko @ 2018-06-22 16:46 UTC (permalink / raw)
To: Sascha Hauer; +Cc: Andrey Smirnov, barebox, Nikita Yushchenko, Chris Healy
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@cogentembedded.com>
---
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
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] usb: imx: implement support for limiting host to full speed
2018-06-22 16:46 [PATCH] usb: imx: implement support for limiting host to full speed Nikita Yushchenko
@ 2018-06-26 4:56 ` Sascha Hauer
0 siblings, 0 replies; 2+ messages in thread
From: Sascha Hauer @ 2018-06-26 4:56 UTC (permalink / raw)
To: Nikita Yushchenko; +Cc: Andrey Smirnov, barebox, Chris Healy
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@cogentembedded.com>
> ---
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@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2018-06-26 4:57 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-22 16:46 [PATCH] usb: imx: implement support for limiting host to full speed Nikita Yushchenko
2018-06-26 4:56 ` Sascha Hauer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox