Linux-USB Archive on lore.kernel.org
 help / color / Atom feed
From: Artur Petrosyan <Arthur.Petrosyan@synopsys.com>
To: Felipe Balbi <balbi@kernel.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>,
	linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: John Youn <John.Youn@synopsys.com>,
	Artur Petrosyan <Arthur.Petrosyan@synopsys.com>,
	Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
Subject: [PATCH v3 03/14] usb: dwc2: Update enter and exit partial power down functions
Date: Thu, 08 Apr 2021 13:44:45 +0400
Message-ID: <20210408094446.6491BA022E@mailhost.synopsys.com> (raw)
In-Reply-To: <cover.1617782102.git.Arthur.Petrosyan@synopsys.com>

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


  parent reply index

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-07 10:00 [PATCH 00/14] usb: dwc2: Fix Partial Power down issues Artur Petrosyan
2021-04-07 10:08 ` [PATCH 13/14] usb: dwc2: Fix partial power down exiting by system resume Artur Petrosyan
2021-04-08  5:57 ` [PATCH 00/14] usb: dwc2: Fix Partial Power down issues Artur Petrosyan
2021-04-08  6:09   ` Greg Kroah-Hartman
2021-04-08  7:28 ` [PATCH v2 " Artur Petrosyan
2021-04-08  9:17   ` Artur Petrosyan
2021-04-08 10:09     ` Artur Petrosyan
2021-04-08 11:00       ` Greg Kroah-Hartman
2021-04-08  7:30 ` [PATCH v2 13/14] usb: dwc2: Fix partial power down exiting by system resume Artur Petrosyan
2021-04-08  9:44 ` [PATCH v3 00/14] usb: dwc2: Fix Partial Power down issues Artur Petrosyan
2021-04-08  9:44 ` [PATCH v3 01/14] usb: dwc2: Add device partial power down functions Artur Petrosyan
2021-04-08  9:44 ` [PATCH v3 02/14] usb: dwc2: Add host " Artur Petrosyan
2021-04-08  9:44 ` Artur Petrosyan [this message]
2021-04-08  9:44 ` [PATCH v3 04/14] usb: dwc2: Add partial power down exit flow in wakeup intr Artur Petrosyan
2021-04-08  9:45 ` [PATCH v3 05/14] usb: dwc2: Update port suspend/resume function definitions Artur Petrosyan
2021-04-08 13:39   ` Minas Harutyunyan
2021-04-08  9:45 ` [PATCH v3 06/14] usb: dwc2: Add enter partial power down when port is suspended Artur Petrosyan
2021-04-08 13:39   ` Minas Harutyunyan
2021-04-08  9:45 ` [PATCH v3 07/14] usb: dwc2: Add exit partial power down when port is resumed Artur Petrosyan
2021-04-08 13:39   ` Minas Harutyunyan
2021-04-08  9:45 ` [PATCH v3 08/14] usb: dwc2: Add exit partial power down when port reset is asserted Artur Petrosyan
2021-04-08 13:39   ` Minas Harutyunyan
2021-04-08  9:45 ` [PATCH v3 09/14] usb: dwc2: Add part. power down exit from dwc2_conn_id_status_change() Artur Petrosyan
2021-04-08  9:45 ` [PATCH v3 10/14] usb: dwc2: Allow exit partial power down in urb enqueue Artur Petrosyan
2021-04-08 13:40   ` Minas Harutyunyan
2021-04-08  9:45 ` [PATCH v3 11/14] usb: dwc2: Fix session request interrupt handler Artur Petrosyan
2021-04-08  9:45 ` [PATCH v3 12/14] usb: dwc2: Update partial power down entering by system suspend Artur Petrosyan
2021-04-08 13:40   ` Minas Harutyunyan
2021-04-08  9:46 ` [PATCH v3 13/14] usb: dwc2: Fix partial power down exiting by system resume Artur Petrosyan
2021-04-08 13:40   ` Minas Harutyunyan
2021-04-08  9:46 ` [PATCH v3 14/14] usb: dwc2: Add exit partial power down before removing driver Artur Petrosyan
2021-04-08 13:41   ` Minas Harutyunyan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210408094446.6491BA022E@mailhost.synopsys.com \
    --to=arthur.petrosyan@synopsys.com \
    --cc=John.Youn@synopsys.com \
    --cc=Minas.Harutyunyan@synopsys.com \
    --cc=balbi@kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Linux-USB Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-usb/0 linux-usb/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-usb linux-usb/ https://lore.kernel.org/linux-usb \
		linux-usb@vger.kernel.org
	public-inbox-index linux-usb

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-usb


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git