lkml.org 
[lkml]   [2021]   [Apr]   [8]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH v3 03/14] usb: dwc2: Update enter and exit partial power down functions
    These are wrapper functions which are calling device or host
    enter/exit partial power down functions.

    This change is done because we need to separate device and
    host partial power down functions as the programming flow
    has a lot of difference between host and device. With this
    update during partial power down exit driver relies on
    backup value of "GOTGCTL_CURMODE_HOST" to determine the
    mode of core before entering to PPD.

    Signed-off-by: Artur Petrosyan <Arthur.Petrosyan@synopsys.com>
    Acked-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
    ---
    drivers/usb/dwc2/core.c | 113 ++++++-----------------------------
    drivers/usb/dwc2/core.h | 3 +-
    drivers/usb/dwc2/core_intr.c | 21 ++++---
    drivers/usb/dwc2/gadget.c | 20 ++++---
    drivers/usb/dwc2/hcd.c | 2 +-
    drivers/usb/dwc2/hw.h | 1 +
    6 files changed, 45 insertions(+), 115 deletions(-)

    diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
    index fec17a2d2447..cb65f7f60573 100644
    --- a/drivers/usb/dwc2/core.c
    +++ b/drivers/usb/dwc2/core.c
    @@ -131,54 +131,26 @@ int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg)
    * dwc2_exit_partial_power_down() - Exit controller from Partial Power Down.
    *
    * @hsotg: Programming view of the DWC_otg controller
    + * @rem_wakeup: indicates whether resume is initiated by Reset.
    * @restore: Controller registers need to be restored
    */
    -int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore)
    +int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, int rem_wakeup,
    + bool restore)
    {
    - u32 pcgcctl;
    - int ret = 0;
    -
    - if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL)
    - return -ENOTSUPP;
    -
    - pcgcctl = dwc2_readl(hsotg, PCGCTL);
    - pcgcctl &= ~PCGCTL_STOPPCLK;
    - dwc2_writel(hsotg, pcgcctl, PCGCTL);
    -
    - pcgcctl = dwc2_readl(hsotg, PCGCTL);
    - pcgcctl &= ~PCGCTL_PWRCLMP;
    - dwc2_writel(hsotg, pcgcctl, PCGCTL);
    -
    - pcgcctl = dwc2_readl(hsotg, PCGCTL);
    - pcgcctl &= ~PCGCTL_RSTPDWNMODULE;
    - dwc2_writel(hsotg, pcgcctl, PCGCTL);
    + struct dwc2_gregs_backup *gr;

    - udelay(100);
    - if (restore) {
    - ret = dwc2_restore_global_registers(hsotg);
    - if (ret) {
    - dev_err(hsotg->dev, "%s: failed to restore registers\n",
    - __func__);
    - return ret;
    - }
    - if (dwc2_is_host_mode(hsotg)) {
    - ret = dwc2_restore_host_registers(hsotg);
    - if (ret) {
    - dev_err(hsotg->dev, "%s: failed to restore host registers\n",
    - __func__);
    - return ret;
    - }
    - } else {
    - ret = dwc2_restore_device_registers(hsotg, 0);
    - if (ret) {
    - dev_err(hsotg->dev, "%s: failed to restore device registers\n",
    - __func__);
    - return ret;
    - }
    - }
    - }
    + gr = &hsotg->gr_backup;

    - return ret;
    + /*
    + * Restore host or device regisers with the same mode core enterted
    + * to partial power down by checking "GOTGCTL_CURMODE_HOST" backup
    + * value of the "gotgctl" register.
    + */
    + if (gr->gotgctl & GOTGCTL_CURMODE_HOST)
    + return dwc2_host_exit_partial_power_down(hsotg, rem_wakeup,
    + restore);
    + else
    + return dwc2_gadget_exit_partial_power_down(hsotg, restore);
    }

    /**
    @@ -188,57 +160,10 @@ int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore)
    */
    int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg)
    {
    - u32 pcgcctl;
    - int ret = 0;
    -
    - if (!hsotg->params.power_down)
    - return -ENOTSUPP;
    -
    - /* Backup all registers */
    - ret = dwc2_backup_global_registers(hsotg);
    - if (ret) {
    - dev_err(hsotg->dev, "%s: failed to backup global registers\n",
    - __func__);
    - return ret;
    - }
    -
    - if (dwc2_is_host_mode(hsotg)) {
    - ret = dwc2_backup_host_registers(hsotg);
    - if (ret) {
    - dev_err(hsotg->dev, "%s: failed to backup host registers\n",
    - __func__);
    - return ret;
    - }
    - } else {
    - ret = dwc2_backup_device_registers(hsotg);
    - if (ret) {
    - dev_err(hsotg->dev, "%s: failed to backup device registers\n",
    - __func__);
    - return ret;
    - }
    - }
    -
    - /*
    - * Clear any pending interrupts since dwc2 will not be able to
    - * clear them after entering partial_power_down.
    - */
    - dwc2_writel(hsotg, 0xffffffff, GINTSTS);
    -
    - /* Put the controller in low power state */
    - pcgcctl = dwc2_readl(hsotg, PCGCTL);
    -
    - pcgcctl |= PCGCTL_PWRCLMP;
    - dwc2_writel(hsotg, pcgcctl, PCGCTL);
    - ndelay(20);
    -
    - pcgcctl |= PCGCTL_RSTPDWNMODULE;
    - dwc2_writel(hsotg, pcgcctl, PCGCTL);
    - ndelay(20);
    -
    - pcgcctl |= PCGCTL_STOPPCLK;
    - dwc2_writel(hsotg, pcgcctl, PCGCTL);
    -
    - return ret;
    + if (dwc2_is_host_mode(hsotg))
    + return dwc2_host_enter_partial_power_down(hsotg);
    + else
    + return dwc2_gadget_enter_partial_power_down(hsotg);
    }

    /**
    diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
    index 1a97df8bf5cb..39037709a2ad 100644
    --- a/drivers/usb/dwc2/core.h
    +++ b/drivers/usb/dwc2/core.h
    @@ -1303,7 +1303,8 @@ static inline bool dwc2_is_hs_iot(struct dwc2_hsotg *hsotg)
    */
    int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait);
    int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg);
    -int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore);
    +int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, int rem_wakeup,
    + bool restore);
    int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host);
    int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
    int reset, int is_host);
    diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
    index 55f1d14fc414..1fb957ce6c25 100644
    --- a/drivers/usb/dwc2/core_intr.c
    +++ b/drivers/usb/dwc2/core_intr.c
    @@ -315,9 +315,10 @@ 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) {
    - ret = dwc2_exit_partial_power_down(hsotg, true);
    - if (ret && (ret != -ENOTSUPP))
    + if (hsotg->lx_state == DWC2_L2 && hsotg->in_ppd) {
    + ret = dwc2_exit_partial_power_down(hsotg, 0,
    + true);
    + if (ret)
    dev_err(hsotg->dev,
    "exit power_down failed\n");
    }
    @@ -406,18 +407,16 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
    if (dwc2_is_device_mode(hsotg)) {
    dev_dbg(hsotg->dev, "DSTS=0x%0x\n",
    dwc2_readl(hsotg, DSTS));
    - if (hsotg->lx_state == DWC2_L2) {
    + if (hsotg->lx_state == DWC2_L2 && hsotg->in_ppd) {
    u32 dctl = dwc2_readl(hsotg, DCTL);
    -
    /* Clear Remote Wakeup Signaling */
    dctl &= ~DCTL_RMTWKUPSIG;
    dwc2_writel(hsotg, dctl, DCTL);
    - ret = dwc2_exit_partial_power_down(hsotg, true);
    - if (ret && (ret != -ENOTSUPP))
    - dev_err(hsotg->dev, "exit power_down failed\n");
    -
    - /* Change to L0 state */
    - hsotg->lx_state = DWC2_L0;
    + ret = dwc2_exit_partial_power_down(hsotg, 1,
    + true);
    + if (ret)
    + dev_err(hsotg->dev,
    + "exit partial_power_down failed\n");
    call_gadget(hsotg, resume);
    } else {
    /* Change to L0 state */
    diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
    index 98a2a63c67ae..e08baee4987b 100644
    --- a/drivers/usb/dwc2/gadget.c
    +++ b/drivers/usb/dwc2/gadget.c
    @@ -3689,10 +3689,10 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw)
    dwc2_writel(hsotg, GINTSTS_RESETDET, GINTSTS);

    /* This event must be used only if controller is suspended */
    - if (hsotg->lx_state == DWC2_L2) {
    - dwc2_exit_partial_power_down(hsotg, true);
    - hsotg->lx_state = DWC2_L0;
    - }
    + if (hsotg->in_ppd && hsotg->lx_state == DWC2_L2)
    + dwc2_exit_partial_power_down(hsotg, 0, true);
    +
    + hsotg->lx_state = DWC2_L0;
    }

    if (gintsts & (GINTSTS_USBRST | GINTSTS_RESETDET)) {
    @@ -4615,11 +4615,15 @@ static int dwc2_hsotg_vbus_session(struct usb_gadget *gadget, int is_active)
    spin_lock_irqsave(&hsotg->lock, flags);

    /*
    - * If controller is hibernated, it must exit from power_down
    - * before being initialized / de-initialized
    + * If controller is in partial power down state, it must exit from
    + * that state before being initialized / de-initialized
    */
    - if (hsotg->lx_state == DWC2_L2)
    - dwc2_exit_partial_power_down(hsotg, false);
    + if (hsotg->lx_state == DWC2_L2 && hsotg->in_ppd)
    + /*
    + * No need to check the return value as
    + * registers are not being restored.
    + */
    + dwc2_exit_partial_power_down(hsotg, 0, false);

    if (is_active) {
    hsotg->op_state = OTG_STATE_B_PERIPHERAL;
    diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
    index 35e617be4bc3..dd0362e07444 100644
    --- a/drivers/usb/dwc2/hcd.c
    +++ b/drivers/usb/dwc2/hcd.c
    @@ -4418,7 +4418,7 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)


    /* Exit partial_power_down */
    - ret = dwc2_exit_partial_power_down(hsotg, true);
    + ret = dwc2_exit_partial_power_down(hsotg, 0, true);
    if (ret && (ret != -ENOTSUPP))
    dev_err(hsotg->dev, "exit partial_power_down failed\n");
    } else {
    diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h
    index c3d6dde2aca4..6b16fbf98bc6 100644
    --- a/drivers/usb/dwc2/hw.h
    +++ b/drivers/usb/dwc2/hw.h
    @@ -44,6 +44,7 @@
    #define GOTGCTL_CHIRPEN BIT(27)
    #define GOTGCTL_MULT_VALID_BC_MASK (0x1f << 22)
    #define GOTGCTL_MULT_VALID_BC_SHIFT 22
    +#define GOTGCTL_CURMODE_HOST BIT(21)
    #define GOTGCTL_OTGVER BIT(20)
    #define GOTGCTL_BSESVLD BIT(19)
    #define GOTGCTL_ASESVLD BIT(18)
    --
    2.25.1
    \
     
     \ /
      Last update: 2021-04-08 11:45    [W:4.183 / U:0.028 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site