usb: dwc2: Add eUSB2 PHY disconnect flow support
authorMinas Harutyunyan <Minas.Harutyunyan@synopsys.com>
Wed, 13 Mar 2024 09:19:42 +0000 (09:19 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 26 Mar 2024 09:44:53 +0000 (10:44 +0100)
To support eUSB2 PHY disconnect flow required in Soft disconnect
state set GOTGCTL_EUSB2_DISC_SUPP bit, if applicable.

On Session End Detected interrupt clear PCGCTL_GATEHCLK and
PCGCTL_STOPPCLK bits if eusb2_disc parameter true.

Signed-off-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
Link: https://lore.kernel.org/r/9d50b83df693cda8c391313e90048df8dd611c04.1708948356.git.Minas.Harutyunyan@synopsys.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/dwc2/core_intr.c
drivers/usb/dwc2/gadget.c

index 158ede7538548e4d6daba4fc08d543f434b3ec6d..bb6bb771375aeedd9d50d768cda11d18f1d6e1a4 100644 (file)
@@ -84,6 +84,7 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
        u32 gotgint;
        u32 gotgctl;
        u32 gintmsk;
+       u32 pcgctl;
 
        gotgint = dwc2_readl(hsotg, GOTGINT);
        gotgctl = dwc2_readl(hsotg, GOTGCTL);
@@ -96,8 +97,22 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
                        dwc2_op_state_str(hsotg));
                gotgctl = dwc2_readl(hsotg, GOTGCTL);
 
-               if (dwc2_is_device_mode(hsotg))
+               if (dwc2_is_device_mode(hsotg)) {
+                       if (hsotg->params.eusb2_disc) {
+                               /* Clear the Gate hclk. */
+                               pcgctl = dwc2_readl(hsotg, PCGCTL);
+                               pcgctl &= ~PCGCTL_GATEHCLK;
+                               dwc2_writel(hsotg, pcgctl, PCGCTL);
+                               udelay(5);
+
+                               /* Clear Phy Clock bit. */
+                               pcgctl = dwc2_readl(hsotg, PCGCTL);
+                               pcgctl &= ~PCGCTL_STOPPCLK;
+                               dwc2_writel(hsotg, pcgctl, PCGCTL);
+                               udelay(5);
+                       }
                        dwc2_hsotg_disconnect(hsotg);
+               }
 
                if (hsotg->op_state == OTG_STATE_B_HOST) {
                        hsotg->op_state = OTG_STATE_B_PERIPHERAL;
@@ -117,7 +132,7 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
                         * disconnected
                         */
                        /* Reset to a clean state */
-                       hsotg->lx_state = DWC2_L0;
+                       hsotg->lx_state = DWC2_L3;
                }
 
                gotgctl = dwc2_readl(hsotg, GOTGCTL);
@@ -286,7 +301,7 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
                hsotg->lx_state);
 
        if (dwc2_is_device_mode(hsotg)) {
-               if (hsotg->lx_state == DWC2_L2) {
+               if (hsotg->lx_state != DWC2_L0) {
                        if (hsotg->in_ppd) {
                                ret = dwc2_exit_partial_power_down(hsotg, 0,
                                                                   true);
index b517a7216de22ae420405ae7ceae2fd04f74f2b3..680737d471c1280d87d89b1ccfbb48346345958d 100644 (file)
@@ -3420,8 +3420,11 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
 
        dwc2_hsotg_init_fifo(hsotg);
 
-       if (!is_usb_reset)
+       if (!is_usb_reset) {
                dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON);
+               if (hsotg->params.eusb2_disc)
+                       dwc2_set_bit(hsotg, GOTGCTL, GOTGCTL_EUSB2_DISC_SUPP);
+       }
 
        dcfg |= DCFG_EPMISCNT(1);