The sunxi otg phy has a bug where it wrongly detects a high speed squelch
when reset on the root port gets de-asserted with a lo-speed device.

The workaround for this is to disable squelch detect before de-asserting
reset, and re-enabling it after the reset de-assert is done. Add a sunxi
specific phy function to allow the sunxi-musb glue to do this.

Signed-off-by: Jagan Teki <ja...@amarulasolutions.com>
---
 drivers/phy/allwinner/phy-sun4i-usb.c |  6 ++++++
 drivers/usb/musb-new/musb_core.h      |  4 ++++
 drivers/usb/musb-new/musb_uboot.c     | 19 ++++++++-----------
 drivers/usb/musb-new/sunxi.c          | 16 ++++++++++++++++
 include/phy-sun4i-usb.h               |  8 ++++++++
 5 files changed, 42 insertions(+), 11 deletions(-)

diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c 
b/drivers/phy/allwinner/phy-sun4i-usb.c
index 4194a15007..2b3cf48025 100644
--- a/drivers/phy/allwinner/phy-sun4i-usb.c
+++ b/drivers/phy/allwinner/phy-sun4i-usb.c
@@ -36,6 +36,7 @@
 #define PHY_TX_AMPLITUDE_TUNE          0x20
 #define PHY_TX_SLEWRATE_TUNE           0x22
 #define PHY_DISCON_TH_SEL              0x2a
+#define PHY_SQUELCH_DETECT             0x3c
 
 #define PHYCTL_DATA                    BIT(7)
 #define OTGCTL_ROUTE_MUSB              BIT(0)
@@ -383,6 +384,11 @@ int sun4i_usb_phy_id_detect(struct phy *phy)
        return gpio_get_value(usb_phy->gpio_id_det);
 }
 
+void sun4i_usb_phy_set_squelch_detect(struct phy *phy, bool enabled)
+{
+       sun4i_usb_phy_write(phy, PHY_SQUELCH_DETECT, enabled ? 0 : 2, 2);
+}
+
 static struct phy_ops sun4i_usb_phy_ops = {
        .of_xlate = sun4i_usb_phy_xlate,
        .init = sun4i_usb_phy_init,
diff --git a/drivers/usb/musb-new/musb_core.h b/drivers/usb/musb-new/musb_core.h
index 6394bb052b..713a3cf30c 100644
--- a/drivers/usb/musb-new/musb_core.h
+++ b/drivers/usb/musb-new/musb_core.h
@@ -201,6 +201,8 @@ enum musb_g_ep0_state {
  * @vbus_status: returns vbus status if possible
  * @set_vbus:  forces vbus status
  * @adjust_channel_params: pre check for standard dma channel_program func
+ * @pre_root_reset_end: called before the root usb port reset flag gets cleared
+ * @post_root_reset_end: called after the root usb port reset flag gets cleared
  */
 struct musb_platform_ops {
        int     (*init)(struct musb *musb);
@@ -222,6 +224,8 @@ struct musb_platform_ops {
        int     (*adjust_channel_params)(struct dma_channel *channel,
                                u16 packet_sz, u8 *mode,
                                dma_addr_t *dma_addr, u32 *len);
+       void    (*pre_root_reset_end)(struct musb *musb);
+       void    (*post_root_reset_end)(struct musb *musb);
 };
 
 /*
diff --git a/drivers/usb/musb-new/musb_uboot.c 
b/drivers/usb/musb-new/musb_uboot.c
index 8662c0ff70..48242c0475 100644
--- a/drivers/usb/musb-new/musb_uboot.c
+++ b/drivers/usb/musb-new/musb_uboot.c
@@ -193,19 +193,16 @@ static int _musb_reset_root_port(struct musb_host_data 
*host,
        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_usb_phy_enable_squelch_detect(0, 0);
-#endif
+
+       if (host->host->ops->pre_root_reset_end)
+               host->host->ops->pre_root_reset_end(host->host);
+
        power = musb_readb(mbase, MUSB_POWER);
        musb_writeb(mbase, MUSB_POWER, ~MUSB_POWER_RESET & power);
-#ifdef CONFIG_ARCH_SUNXI
-       sunxi_usb_phy_enable_squelch_detect(0, 1);
-#endif
+
+       if (host->host->ops->post_root_reset_end)
+               host->host->ops->post_root_reset_end(host->host);
+
        host->host->isr(0, host->host);
        host->host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ?
                        USB_SPEED_HIGH :
diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c
index 16551c7cf8..349653cd33 100644
--- a/drivers/usb/musb-new/sunxi.c
+++ b/drivers/usb/musb-new/sunxi.c
@@ -305,10 +305,26 @@ static int sunxi_musb_init(struct musb *musb)
        return 0;
 }
 
+static void sunxi_musb_pre_root_reset_end(struct musb *musb)
+{
+       struct sunxi_glue *glue = to_sunxi_glue(musb->controller);
+
+       sun4i_usb_phy_set_squelch_detect(glue->phy, false);
+}
+
+static void sunxi_musb_post_root_reset_end(struct musb *musb)
+{
+       struct sunxi_glue *glue = to_sunxi_glue(musb->controller);
+
+       sun4i_usb_phy_set_squelch_detect(glue->phy, true);
+}
+
 static const struct musb_platform_ops sunxi_musb_ops = {
        .init           = sunxi_musb_init,
        .enable         = sunxi_musb_enable,
        .disable        = sunxi_musb_disable,
+       .pre_root_reset_end = sunxi_musb_pre_root_reset_end,
+       .post_root_reset_end = sunxi_musb_post_root_reset_end,
 };
 
 /* Allwinner OTG supports up to 5 endpoints */
diff --git a/include/phy-sun4i-usb.h b/include/phy-sun4i-usb.h
index 040e9d3750..b0a45b2058 100644
--- a/include/phy-sun4i-usb.h
+++ b/include/phy-sun4i-usb.h
@@ -23,4 +23,12 @@ int sun4i_usb_phy_id_detect(struct phy *phy);
  */
 int sun4i_usb_phy_vbus_detect(struct phy *phy);
 
+/**
+ * sun4i_usb_phy_set_squelch_detect() - Enable/disable squelch detect
+ *
+ * @phy: reference to a sun4i usb phy
+ * @enabled: wether to enable or disable squelch detect
+ */
+void sun4i_usb_phy_set_squelch_detect(struct phy *phy, bool enabled);
+
 #endif /*__GENERIC_PHY_SUN4I_USB_H */
-- 
2.14.3

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to