mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-05 00:20:32 +00:00
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. Acked-by: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com> Signed-off-by: Artur Petrosyan <Arthur.Petrosyan@synopsys.com> Link: https://lore.kernel.org/r/20210408094446.6491BA022E@mailhost.synopsys.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
9ce9e5ad17
commit
c9c394abfa
6 changed files with 45 additions and 115 deletions
|
@ -131,54 +131,26 @@ int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg)
|
||||||
* dwc2_exit_partial_power_down() - Exit controller from Partial Power Down.
|
* dwc2_exit_partial_power_down() - Exit controller from Partial Power Down.
|
||||||
*
|
*
|
||||||
* @hsotg: Programming view of the DWC_otg controller
|
* @hsotg: Programming view of the DWC_otg controller
|
||||||
|
* @rem_wakeup: indicates whether resume is initiated by Reset.
|
||||||
* @restore: Controller registers need to be restored
|
* @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;
|
struct dwc2_gregs_backup *gr;
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL)
|
gr = &hsotg->gr_backup;
|
||||||
return -ENOTSUPP;
|
|
||||||
|
|
||||||
pcgcctl = dwc2_readl(hsotg, PCGCTL);
|
/*
|
||||||
pcgcctl &= ~PCGCTL_STOPPCLK;
|
* Restore host or device regisers with the same mode core enterted
|
||||||
dwc2_writel(hsotg, pcgcctl, PCGCTL);
|
* to partial power down by checking "GOTGCTL_CURMODE_HOST" backup
|
||||||
|
* value of the "gotgctl" register.
|
||||||
pcgcctl = dwc2_readl(hsotg, PCGCTL);
|
*/
|
||||||
pcgcctl &= ~PCGCTL_PWRCLMP;
|
if (gr->gotgctl & GOTGCTL_CURMODE_HOST)
|
||||||
dwc2_writel(hsotg, pcgcctl, PCGCTL);
|
return dwc2_host_exit_partial_power_down(hsotg, rem_wakeup,
|
||||||
|
restore);
|
||||||
pcgcctl = dwc2_readl(hsotg, PCGCTL);
|
else
|
||||||
pcgcctl &= ~PCGCTL_RSTPDWNMODULE;
|
return dwc2_gadget_exit_partial_power_down(hsotg, restore);
|
||||||
dwc2_writel(hsotg, pcgcctl, PCGCTL);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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)
|
int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg)
|
||||||
{
|
{
|
||||||
u32 pcgcctl;
|
if (dwc2_is_host_mode(hsotg))
|
||||||
int ret = 0;
|
return dwc2_host_enter_partial_power_down(hsotg);
|
||||||
|
else
|
||||||
if (!hsotg->params.power_down)
|
return dwc2_gadget_enter_partial_power_down(hsotg);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait);
|
||||||
int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg);
|
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_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host);
|
||||||
int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
|
int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
|
||||||
int reset, int is_host);
|
int reset, int is_host);
|
||||||
|
|
|
@ -315,9 +315,10 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
|
||||||
hsotg->lx_state);
|
hsotg->lx_state);
|
||||||
|
|
||||||
if (dwc2_is_device_mode(hsotg)) {
|
if (dwc2_is_device_mode(hsotg)) {
|
||||||
if (hsotg->lx_state == DWC2_L2) {
|
if (hsotg->lx_state == DWC2_L2 && hsotg->in_ppd) {
|
||||||
ret = dwc2_exit_partial_power_down(hsotg, true);
|
ret = dwc2_exit_partial_power_down(hsotg, 0,
|
||||||
if (ret && (ret != -ENOTSUPP))
|
true);
|
||||||
|
if (ret)
|
||||||
dev_err(hsotg->dev,
|
dev_err(hsotg->dev,
|
||||||
"exit power_down failed\n");
|
"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)) {
|
if (dwc2_is_device_mode(hsotg)) {
|
||||||
dev_dbg(hsotg->dev, "DSTS=0x%0x\n",
|
dev_dbg(hsotg->dev, "DSTS=0x%0x\n",
|
||||||
dwc2_readl(hsotg, DSTS));
|
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);
|
u32 dctl = dwc2_readl(hsotg, DCTL);
|
||||||
|
|
||||||
/* Clear Remote Wakeup Signaling */
|
/* Clear Remote Wakeup Signaling */
|
||||||
dctl &= ~DCTL_RMTWKUPSIG;
|
dctl &= ~DCTL_RMTWKUPSIG;
|
||||||
dwc2_writel(hsotg, dctl, DCTL);
|
dwc2_writel(hsotg, dctl, DCTL);
|
||||||
ret = dwc2_exit_partial_power_down(hsotg, true);
|
ret = dwc2_exit_partial_power_down(hsotg, 1,
|
||||||
if (ret && (ret != -ENOTSUPP))
|
true);
|
||||||
dev_err(hsotg->dev, "exit power_down failed\n");
|
if (ret)
|
||||||
|
dev_err(hsotg->dev,
|
||||||
/* Change to L0 state */
|
"exit partial_power_down failed\n");
|
||||||
hsotg->lx_state = DWC2_L0;
|
|
||||||
call_gadget(hsotg, resume);
|
call_gadget(hsotg, resume);
|
||||||
} else {
|
} else {
|
||||||
/* Change to L0 state */
|
/* Change to L0 state */
|
||||||
|
|
|
@ -3689,10 +3689,10 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw)
|
||||||
dwc2_writel(hsotg, GINTSTS_RESETDET, GINTSTS);
|
dwc2_writel(hsotg, GINTSTS_RESETDET, GINTSTS);
|
||||||
|
|
||||||
/* This event must be used only if controller is suspended */
|
/* This event must be used only if controller is suspended */
|
||||||
if (hsotg->lx_state == DWC2_L2) {
|
if (hsotg->in_ppd && hsotg->lx_state == DWC2_L2)
|
||||||
dwc2_exit_partial_power_down(hsotg, true);
|
dwc2_exit_partial_power_down(hsotg, 0, true);
|
||||||
hsotg->lx_state = DWC2_L0;
|
|
||||||
}
|
hsotg->lx_state = DWC2_L0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gintsts & (GINTSTS_USBRST | GINTSTS_RESETDET)) {
|
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);
|
spin_lock_irqsave(&hsotg->lock, flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If controller is hibernated, it must exit from power_down
|
* If controller is in partial power down state, it must exit from
|
||||||
* before being initialized / de-initialized
|
* that state before being initialized / de-initialized
|
||||||
*/
|
*/
|
||||||
if (hsotg->lx_state == DWC2_L2)
|
if (hsotg->lx_state == DWC2_L2 && hsotg->in_ppd)
|
||||||
dwc2_exit_partial_power_down(hsotg, false);
|
/*
|
||||||
|
* No need to check the return value as
|
||||||
|
* registers are not being restored.
|
||||||
|
*/
|
||||||
|
dwc2_exit_partial_power_down(hsotg, 0, false);
|
||||||
|
|
||||||
if (is_active) {
|
if (is_active) {
|
||||||
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
|
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
|
||||||
|
|
|
@ -4418,7 +4418,7 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
|
||||||
|
|
||||||
|
|
||||||
/* Exit partial_power_down */
|
/* 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))
|
if (ret && (ret != -ENOTSUPP))
|
||||||
dev_err(hsotg->dev, "exit partial_power_down failed\n");
|
dev_err(hsotg->dev, "exit partial_power_down failed\n");
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#define GOTGCTL_CHIRPEN BIT(27)
|
#define GOTGCTL_CHIRPEN BIT(27)
|
||||||
#define GOTGCTL_MULT_VALID_BC_MASK (0x1f << 22)
|
#define GOTGCTL_MULT_VALID_BC_MASK (0x1f << 22)
|
||||||
#define GOTGCTL_MULT_VALID_BC_SHIFT 22
|
#define GOTGCTL_MULT_VALID_BC_SHIFT 22
|
||||||
|
#define GOTGCTL_CURMODE_HOST BIT(21)
|
||||||
#define GOTGCTL_OTGVER BIT(20)
|
#define GOTGCTL_OTGVER BIT(20)
|
||||||
#define GOTGCTL_BSESVLD BIT(19)
|
#define GOTGCTL_BSESVLD BIT(19)
|
||||||
#define GOTGCTL_ASESVLD BIT(18)
|
#define GOTGCTL_ASESVLD BIT(18)
|
||||||
|
|
Loading…
Reference in a new issue