]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
usb: dwc2: gadget: Fix dwc2_restore_device_registers
authorVardan Mikayelyan <mvardan@synopsys.com>
Fri, 16 Feb 2018 10:08:00 +0000 (14:08 +0400)
committerFelipe Balbi <felipe.balbi@linux.intel.com>
Tue, 13 Mar 2018 08:47:54 +0000 (10:47 +0200)
Add parameter remote_wakeup to dwc2_restore_device_registers()
to be able to restore device registers according to programming
guide for dwc-otg. It says that in case of rem_wakeup DCTL must not
be restored here.

Remove setting of DCTL_PWRONPRGDONE from this function, because it
will be done in function responsible for exiting from hibernation.

WA for enabled EPx's IN and OUT in DDMA mode. On entering to
hibernation wrong value read and saved from DIEPDMAx,
as result BNA interrupt asserted on hibernation exit
by restoring from saved area.

Signed-off-by: Vardan Mikayelyan <mvardan@synopsys.com>
Signed-off-by: John Youn <johnyoun@synopsys.com>
Signed-off-by: Artur Petrosyan <arturp@synopsys.com>
Signed-off-by: Minas Harutyunyan <hminas@synopsys.com>
Signed-off-by: Grigor Tovmasyan <tovmasya@synopsys.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
drivers/usb/dwc2/core.c
drivers/usb/dwc2/core.h
drivers/usb/dwc2/gadget.c

index 84990a82363b86cba972571c961628281f41ece0..bb17a45779028cbbdbfb2d1eb848d4f59c0d5cd4 100644 (file)
@@ -165,7 +165,7 @@ int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore)
                                return ret;
                        }
                } else {
-                       ret = dwc2_restore_device_registers(hsotg);
+                       ret = dwc2_restore_device_registers(hsotg, 0);
                        if (ret) {
                                dev_err(hsotg->dev, "%s: failed to restore device registers\n",
                                        __func__);
index aa69f2838fcd3ad26a25a34c8e3a01e7ade7bca6..85e083f021dcd456e5b2123e12e41510cfef8b1d 100644 (file)
@@ -1213,7 +1213,7 @@ void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2);
 int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode);
 #define dwc2_is_device_connected(hsotg) (hsotg->connected)
 int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg);
-int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg);
+int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup);
 int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg);
 int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg);
 int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg);
@@ -1237,7 +1237,8 @@ static inline int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg,
 #define dwc2_is_device_connected(hsotg) (0)
 static inline int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
 { return 0; }
-static inline int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
+static inline int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg,
+                                               int remote_wakeup)
 { return 0; }
 static inline int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg)
 { return 0; }
index 89c6714241ee5ce9770ecacc744ea0d8d0881db6..379d6e1baaaa4b7bbf885283512b2d67efff3ab1 100644 (file)
@@ -4827,11 +4827,13 @@ int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
  * if controller power were disabled.
  *
  * @hsotg: Programming view of the DWC_otg controller
+ * @remote_wakeup: Indicates whether resume is initiated by Device or Host.
+ *
+ * Return: 0 if successful, negative error code otherwise
  */
-int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
+int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup)
 {
        struct dwc2_dregs_backup *dr;
-       u32 dctl;
        int i;
 
        dev_dbg(hsotg->dev, "%s\n", __func__);
@@ -4845,30 +4847,42 @@ int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg)
        }
        dr->valid = false;
 
-       dwc2_writel(dr->dcfg, hsotg->regs + DCFG);
-       dwc2_writel(dr->dctl, hsotg->regs + DCTL);
+       if (!remote_wakeup)
+               dwc2_writel(dr->dctl, hsotg->regs + DCTL);
+
        dwc2_writel(dr->daintmsk, hsotg->regs + DAINTMSK);
        dwc2_writel(dr->diepmsk, hsotg->regs + DIEPMSK);
        dwc2_writel(dr->doepmsk, hsotg->regs + DOEPMSK);
 
        for (i = 0; i < hsotg->num_of_eps; i++) {
                /* Restore IN EPs */
-               dwc2_writel(dr->diepctl[i], hsotg->regs + DIEPCTL(i));
                dwc2_writel(dr->dieptsiz[i], hsotg->regs + DIEPTSIZ(i));
                dwc2_writel(dr->diepdma[i], hsotg->regs + DIEPDMA(i));
+               dwc2_writel(dr->doeptsiz[i], hsotg->regs + DOEPTSIZ(i));
+               /** WA for enabled EPx's IN in DDMA mode. On entering to
+                * hibernation wrong value read and saved from DIEPDMAx,
+                * as result BNA interrupt asserted on hibernation exit
+                * by restoring from saved area.
+                */
+               if (hsotg->params.g_dma_desc &&
+                   (dr->diepctl[i] & DXEPCTL_EPENA))
+                       dr->diepdma[i] = hsotg->eps_in[i]->desc_list_dma;
                dwc2_writel(dr->dtxfsiz[i], hsotg->regs + DPTXFSIZN(i));
-
+               dwc2_writel(dr->diepctl[i], hsotg->regs + DIEPCTL(i));
                /* Restore OUT EPs */
-               dwc2_writel(dr->doepctl[i], hsotg->regs + DOEPCTL(i));
                dwc2_writel(dr->doeptsiz[i], hsotg->regs + DOEPTSIZ(i));
+               /* WA for enabled EPx's OUT in DDMA mode. On entering to
+                * hibernation wrong value read and saved from DOEPDMAx,
+                * as result BNA interrupt asserted on hibernation exit
+                * by restoring from saved area.
+                */
+               if (hsotg->params.g_dma_desc &&
+                   (dr->doepctl[i] & DXEPCTL_EPENA))
+                       dr->doepdma[i] = hsotg->eps_out[i]->desc_list_dma;
                dwc2_writel(dr->doepdma[i], hsotg->regs + DOEPDMA(i));
+               dwc2_writel(dr->doepctl[i], hsotg->regs + DOEPCTL(i));
        }
 
-       /* Set the Power-On Programming done bit */
-       dctl = dwc2_readl(hsotg->regs + DCTL);
-       dctl |= DCTL_PWRONPRGDONE;
-       dwc2_writel(dctl, hsotg->regs + DCTL);
-
        return 0;
 }