[U-Boot] [PATCH 0/4] sunxi: various musb host related fixes

Hi All,
Here is a bunch of sunxi musb fixes, note I plan to send a pull-req for the first patch for inclusion in v2015.04 as soon as it is acked, the other 3 depend on the axp vbus-det / vbus-ctrl -> gpio changes currently in next, and since they fix only a few corner cases I plan to add them to next, and merge them the next cycle.
Regards,
Hans

The usb0 / otg phy on sunxi boards has a bug where it wrongly detects a high speed squelch on usb reset deassert when a lo speed device is plugged in.
The android kernel has a work around for this in the form of temporary disabling the phy's squelch detection on reset deassert, this commit adds the same workaround to the u-boot sunxi musb code, thereby fixing various usb lo speed devices not working.
Tested with a (before non working) usb keyboard and a usb 2.4 GHz wireless keyboard/mouse combo receiver.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- arch/arm/cpu/armv7/sunxi/usbc.c | 7 +++++++ arch/arm/include/asm/arch-sunxi/usbc.h | 1 + drivers/usb/musb-new/musb_uboot.c | 14 ++++++++++++++ 3 files changed, 22 insertions(+)
diff --git a/arch/arm/cpu/armv7/sunxi/usbc.c b/arch/arm/cpu/armv7/sunxi/usbc.c index d2d9891..1c777aa 100644 --- a/arch/arm/cpu/armv7/sunxi/usbc.c +++ b/arch/arm/cpu/armv7/sunxi/usbc.c @@ -182,6 +182,13 @@ static void sunxi_usb_passby(struct sunxi_usbc_hcd *sunxi_usbc, int enable) return; }
+void sunxi_usbc_enable_squelch_detect(int index, int enable) +{ + struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index]; + + usb_phy_write(sunxi_usbc, 0x3c, enable ? 0 : 2, 2); +} + int sunxi_usbc_request_resources(int index) { struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index]; diff --git a/arch/arm/include/asm/arch-sunxi/usbc.h b/arch/arm/include/asm/arch-sunxi/usbc.h index 67281ec..ab0f272 100644 --- a/arch/arm/include/asm/arch-sunxi/usbc.h +++ b/arch/arm/include/asm/arch-sunxi/usbc.h @@ -21,3 +21,4 @@ void sunxi_usbc_disable(int index); void sunxi_usbc_vbus_enable(int index); void sunxi_usbc_vbus_disable(int index); int sunxi_usbc_vbus_detect(int index); +void sunxi_usbc_enable_squelch_detect(int index, int enable); diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c index 6e58ddf..51fb3fd 100644 --- a/drivers/usb/musb-new/musb_uboot.c +++ b/drivers/usb/musb-new/musb_uboot.c @@ -1,5 +1,8 @@ #include <common.h> #include <watchdog.h> +#ifdef CONFIG_ARCH_SUNXI +#include <asm/arch/usbc.h> +#endif #include <asm/errno.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> @@ -186,8 +189,19 @@ void usb_reset_root_port(void) power &= 0xf0; musb_writeb(mbase, MUSB_POWER, MUSB_POWER_RESET | power); mdelay(50); +#ifdef CONFIG_ARCH_SUNXI + /* + * sunxi phy has a bug and it will wrongly detect high speed squelch + * when clearing reset on low-speed devices, temporary disable + * squelch detection to work around this. + */ + sunxi_usbc_enable_squelch_detect(0, 0); +#endif power = musb_readb(mbase, MUSB_POWER); musb_writeb(mbase, MUSB_POWER, ~MUSB_POWER_RESET & power); +#ifdef CONFIG_ARCH_SUNXI + sunxi_usbc_enable_squelch_detect(0, 1); +#endif host->isr(0, host); host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ? USB_SPEED_HIGH :

Le vendredi 27 mars 2015 à 22:06 +0100, Hans de Goede a écrit :
The usb0 / otg phy on sunxi boards has a bug where it wrongly detects a high speed squelch on usb reset deassert when a lo speed device is plugged in.
The android kernel has a work around for this in the form of temporary disabling the phy's squelch detection on reset deassert, this commit adds the same workaround to the u-boot sunxi musb code, thereby fixing various usb lo speed devices not working.
Tested with a (before non working) usb keyboard and a usb 2.4 GHz wireless keyboard/mouse combo receiver.
This also made my USB low speed keyboard work with U-Boot, but I'm getting the following message after USB init: musb_h_ep0_irq 1069: no URB for end 0
In addition, enabling caps lock or num lock (which should trigger a LED) makes the keyboard stop working until I reset the board. On an USB2 keyboard, caps lock and num lock work just fine.
I'll try to investigate that when I have time, thanks for working on this!
Signed-off-by: Hans de Goede hdegoede@redhat.com
arch/arm/cpu/armv7/sunxi/usbc.c | 7 +++++++ arch/arm/include/asm/arch-sunxi/usbc.h | 1 + drivers/usb/musb-new/musb_uboot.c | 14 ++++++++++++++ 3 files changed, 22 insertions(+)
diff --git a/arch/arm/cpu/armv7/sunxi/usbc.c b/arch/arm/cpu/armv7/sunxi/usbc.c index d2d9891..1c777aa 100644 --- a/arch/arm/cpu/armv7/sunxi/usbc.c +++ b/arch/arm/cpu/armv7/sunxi/usbc.c @@ -182,6 +182,13 @@ static void sunxi_usb_passby(struct sunxi_usbc_hcd *sunxi_usbc, int enable) return; }
+void sunxi_usbc_enable_squelch_detect(int index, int enable) +{
- struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index];
- usb_phy_write(sunxi_usbc, 0x3c, enable ? 0 : 2, 2);
+}
int sunxi_usbc_request_resources(int index) { struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index]; diff --git a/arch/arm/include/asm/arch-sunxi/usbc.h b/arch/arm/include/asm/arch-sunxi/usbc.h index 67281ec..ab0f272 100644 --- a/arch/arm/include/asm/arch-sunxi/usbc.h +++ b/arch/arm/include/asm/arch-sunxi/usbc.h @@ -21,3 +21,4 @@ void sunxi_usbc_disable(int index); void sunxi_usbc_vbus_enable(int index); void sunxi_usbc_vbus_disable(int index); int sunxi_usbc_vbus_detect(int index); +void sunxi_usbc_enable_squelch_detect(int index, int enable); diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c index 6e58ddf..51fb3fd 100644 --- a/drivers/usb/musb-new/musb_uboot.c +++ b/drivers/usb/musb-new/musb_uboot.c @@ -1,5 +1,8 @@ #include <common.h> #include <watchdog.h> +#ifdef CONFIG_ARCH_SUNXI +#include <asm/arch/usbc.h> +#endif #include <asm/errno.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> @@ -186,8 +189,19 @@ void usb_reset_root_port(void) power &= 0xf0; musb_writeb(mbase, MUSB_POWER, MUSB_POWER_RESET | power); mdelay(50); +#ifdef CONFIG_ARCH_SUNXI
- /*
* sunxi phy has a bug and it will wrongly detect high speed squelch
* when clearing reset on low-speed devices, temporary disable
* squelch detection to work around this.
*/
- sunxi_usbc_enable_squelch_detect(0, 0);
+#endif power = musb_readb(mbase, MUSB_POWER); musb_writeb(mbase, MUSB_POWER, ~MUSB_POWER_RESET & power); +#ifdef CONFIG_ARCH_SUNXI
- sunxi_usbc_enable_squelch_detect(0, 1);
+#endif host->isr(0, host); host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ? USB_SPEED_HIGH :

On boards which use the pmic to enable/disable vbus on the otg port, the vbus value is not reset to 0 on reset, as reset only resets the SoC and not the pmic, so explicitly set vbus to 0 on init (request_resources) by moving the gpio_direction_output call into request_resources.
For consistency also move the gpio_direction_input call for vbus-detect into request_resources.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- arch/arm/cpu/armv7/sunxi/usbc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/arch/arm/cpu/armv7/sunxi/usbc.c b/arch/arm/cpu/armv7/sunxi/usbc.c index 1c777aa..6285fa5 100644 --- a/arch/arm/cpu/armv7/sunxi/usbc.c +++ b/arch/arm/cpu/armv7/sunxi/usbc.c @@ -195,12 +195,16 @@ int sunxi_usbc_request_resources(int index) int ret = 0;
sunxi_usbc->gpio_vbus = get_vbus_gpio(index); - if (sunxi_usbc->gpio_vbus != -1) + if (sunxi_usbc->gpio_vbus != -1) { ret |= gpio_request(sunxi_usbc->gpio_vbus, "usbc_vbus"); + ret |= gpio_direction_output(sunxi_usbc->gpio_vbus, 0); + }
sunxi_usbc->gpio_vbus_det = get_vbus_detect_gpio(index); - if (sunxi_usbc->gpio_vbus_det != -1) + if (sunxi_usbc->gpio_vbus_det != -1) { ret |= gpio_request(sunxi_usbc->gpio_vbus_det, "usbc_vbus_det"); + ret |= gpio_direction_input(sunxi_usbc->gpio_vbus_det); + }
return ret; } @@ -268,7 +272,7 @@ void sunxi_usbc_vbus_enable(int index) struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index];
if (sunxi_usbc->gpio_vbus != -1) - gpio_direction_output(sunxi_usbc->gpio_vbus, 1); + gpio_set_value(sunxi_usbc->gpio_vbus, 1); }
void sunxi_usbc_vbus_disable(int index) @@ -276,7 +280,7 @@ void sunxi_usbc_vbus_disable(int index) struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index];
if (sunxi_usbc->gpio_vbus != -1) - gpio_direction_output(sunxi_usbc->gpio_vbus, 0); + gpio_set_value(sunxi_usbc->gpio_vbus, 0); }
int sunxi_usbc_vbus_detect(int index) @@ -289,9 +293,5 @@ int sunxi_usbc_vbus_detect(int index) return -1; }
- err = gpio_direction_input(sunxi_usbc->gpio_vbus_det); - if (err) - return err; - return gpio_get_value(sunxi_usbc->gpio_vbus_det); }

When u-boot boots the board may be powering vbus, we turn off vbus in sunxi_usbc_request_resources, if we are too quick with reading vusb-detect after this we may see a residual charge and assume we've an external vusb connected even though we do not. So when we see an external vusb wait a bit and try again.
Without this when dealing with a pmic controller vbus and doing "reset" on the u-boot console the musb host will only init once every other boot, because the other boot it thinks an external vbus is present, this commit fixes this.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- arch/arm/cpu/armv7/sunxi/usbc.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/arch/arm/cpu/armv7/sunxi/usbc.c b/arch/arm/cpu/armv7/sunxi/usbc.c index 6285fa5..a0e9604 100644 --- a/arch/arm/cpu/armv7/sunxi/usbc.c +++ b/arch/arm/cpu/armv7/sunxi/usbc.c @@ -286,12 +286,23 @@ void sunxi_usbc_vbus_disable(int index) int sunxi_usbc_vbus_detect(int index) { struct sunxi_usbc_hcd *sunxi_usbc = &sunxi_usbc_hcd[index]; - int err; + int err, retries = 3;
if (sunxi_usbc->gpio_vbus_det == -1) { eprintf("Error: invalid vbus detection pin\n"); return -1; }
- return gpio_get_value(sunxi_usbc->gpio_vbus_det); + err = gpio_get_value(sunxi_usbc->gpio_vbus_det); + /* + * Vbus may have been provided by the board and just been turned of + * some milliseconds ago on reset, what we're measuring then is a + * residual charge on Vbus, sleep a bit and try again. + */ + while (err > 0 && retries--) { + mdelay(100); + err = gpio_get_value(sunxi_usbc->gpio_vbus_det); + } + + return err; }

vbus-usable may not get set if power is provided through both the power barrel connector and external 5v is also present on the otg connector, at least on boards where vbus is also controlled through the axp221-pmic.
One way to reproduce this is to bootup an Ippo-q8h board with a usb-host cable plugged into the otg (so that it will get powered), then unplug the usb-host cable and plug in a charger, and then do "reset" on the u-boot console, vbus-usable will then report 0, leading to uboot trying to provide power to the otg port even though external 5v is present, this commit fixes this.
Signed-off-by: Hans de Goede hdegoede@redhat.com --- drivers/power/axp221.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/power/axp221.c b/drivers/power/axp221.c index f758a75..dc3a7f1 100644 --- a/drivers/power/axp221.c +++ b/drivers/power/axp221.c @@ -424,7 +424,7 @@ int axp_gpio_get_value(unsigned int pin) if (ret) return ret;
- return !!(val & AXP221_POWER_STATUS_VBUS_USABLE); + return !!(val & AXP221_POWER_STATUS_VBUS_AVAIL); default: return -EINVAL; }

On Fri, 2015-03-27 at 22:06 +0100, Hans de Goede wrote:
Hi All,
Here is a bunch of sunxi musb fixes, note I plan to send a pull-req for the first patch for inclusion in v2015.04 as soon as it is acked, the other 3 depend on the axp vbus-det / vbus-ctrl -> gpio changes currently in next, and since they fix only a few corner cases I plan to add them to next, and merge them the next cycle.
All 4 patches: Acked-by: Ian Campbell ijc@hellion.org.uk
participants (3)
-
Hans de Goede
-
Ian Campbell
-
Paul Kocialkowski