usb: dwc2: Add exit partial power down when port is resumed

Added flow of exiting Partial Power Down in
"dwc2_port_resume()" function when core receives resume.

NOTE: Switch case statement is used for hibernation partial
power down and clock gating mode determination. In this patch
only Partial Power Down is implemented the Hibernation and
clock gating implementations are planned to be added.

Acked-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
Signed-off-by: Artur Petrosyan <Arthur.Petrosyan@synopsys.com>
Link: https://lore.kernel.org/r/20210408094518.6DA1DA022E@mailhost.synopsys.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Artur Petrosyan 2021-04-08 13:45:17 +04:00 committed by Greg Kroah-Hartman
parent 22ff0c8e52
commit 1e0890ebaa
2 changed files with 42 additions and 24 deletions

View File

@ -1471,7 +1471,7 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force);
void dwc2_hcd_start(struct dwc2_hsotg *hsotg); void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup); int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup);
int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex); int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex);
void dwc2_port_resume(struct dwc2_hsotg *hsotg); int dwc2_port_resume(struct dwc2_hsotg *hsotg);
int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg); int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg);
int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg); int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg);
int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg); int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg);
@ -1497,7 +1497,8 @@ static inline int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
{ return 0; } { return 0; }
static inline int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) static inline int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
{ return 0; } { return 0; }
static inline void dwc2_port_resume(struct dwc2_hsotg *hsotg) {} static inline int dwc2_port_resume(struct dwc2_hsotg *hsotg)
{ return 0; }
static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg) static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
{ return 0; } { return 0; }
static inline int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg) static inline int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)

View File

@ -3353,44 +3353,61 @@ int dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
* *
* @hsotg: Programming view of the DWC_otg controller * @hsotg: Programming view of the DWC_otg controller
* *
* Return: non-zero if failed to exit suspend mode for host.
*
* This function is for exiting Host mode suspend. * This function is for exiting Host mode suspend.
* Must NOT be called with interrupt disabled or spinlock held. * Must NOT be called with interrupt disabled or spinlock held.
*/ */
void dwc2_port_resume(struct dwc2_hsotg *hsotg) int dwc2_port_resume(struct dwc2_hsotg *hsotg)
{ {
unsigned long flags; unsigned long flags;
u32 hprt0; u32 hprt0;
u32 pcgctl; u32 pcgctl;
int ret = 0;
spin_lock_irqsave(&hsotg->lock, flags); spin_lock_irqsave(&hsotg->lock, flags);
/* switch (hsotg->params.power_down) {
* If power_down is supported, Phy clock is already resumed case DWC2_POWER_DOWN_PARAM_PARTIAL:
* after registers restore. ret = dwc2_exit_partial_power_down(hsotg, 0, true);
*/ if (ret)
if (!hsotg->params.power_down) { dev_err(hsotg->dev,
pcgctl = dwc2_readl(hsotg, PCGCTL); "exit partial_power_down failed.\n");
pcgctl &= ~PCGCTL_STOPPCLK; break;
dwc2_writel(hsotg, pcgctl, PCGCTL); case DWC2_POWER_DOWN_PARAM_HIBERNATION:
case DWC2_POWER_DOWN_PARAM_NONE:
default:
/*
* If power_down is supported, Phy clock is already resumed
* after registers restore.
*/
if (!hsotg->params.power_down) {
pcgctl = dwc2_readl(hsotg, PCGCTL);
pcgctl &= ~PCGCTL_STOPPCLK;
dwc2_writel(hsotg, pcgctl, PCGCTL);
spin_unlock_irqrestore(&hsotg->lock, flags);
msleep(20);
spin_lock_irqsave(&hsotg->lock, flags);
}
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 |= HPRT0_RES;
hprt0 &= ~HPRT0_SUSP;
dwc2_writel(hsotg, hprt0, HPRT0);
spin_unlock_irqrestore(&hsotg->lock, flags); spin_unlock_irqrestore(&hsotg->lock, flags);
msleep(20);
msleep(USB_RESUME_TIMEOUT);
spin_lock_irqsave(&hsotg->lock, flags); spin_lock_irqsave(&hsotg->lock, flags);
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 &= ~(HPRT0_RES | HPRT0_SUSP);
dwc2_writel(hsotg, hprt0, HPRT0);
hsotg->bus_suspended = false;
} }
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 |= HPRT0_RES;
hprt0 &= ~HPRT0_SUSP;
dwc2_writel(hsotg, hprt0, HPRT0);
spin_unlock_irqrestore(&hsotg->lock, flags); spin_unlock_irqrestore(&hsotg->lock, flags);
msleep(USB_RESUME_TIMEOUT); return ret;
spin_lock_irqsave(&hsotg->lock, flags);
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 &= ~(HPRT0_RES | HPRT0_SUSP);
dwc2_writel(hsotg, hprt0, HPRT0);
hsotg->bus_suspended = false;
spin_unlock_irqrestore(&hsotg->lock, flags);
} }
/* Handles hub class-specific requests */ /* Handles hub class-specific requests */