summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/dwc2/core.c14
-rw-r--r--drivers/usb/dwc2/core.h4
-rw-r--r--drivers/usb/dwc2/gadget.c12
-rw-r--r--drivers/usb/dwc2/hcd.c5
-rw-r--r--drivers/usb/dwc2/hw.h5
-rw-r--r--drivers/usb/dwc2/params.c3
6 files changed, 41 insertions, 2 deletions
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index e85f2d230da4..204506f92620 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -498,6 +498,20 @@ int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg)
return 0;
}
+/*
+ * dwc2_enable_acg - enable active clock gating feature
+ */
+void dwc2_enable_acg(struct dwc2_hsotg *hsotg)
+{
+ if (hsotg->params.acg_enable) {
+ u32 pcgcctl1 = dwc2_readl(hsotg->regs + PCGCCTL1);
+
+ dev_dbg(hsotg->dev, "Enabling Active Clock Gating\n");
+ pcgcctl1 |= PCGCCTL1_GATEEN;
+ dwc2_writel(pcgcctl1, hsotg->regs + PCGCCTL1);
+ }
+}
+
/**
* dwc2_dump_host_registers() - Prints the host registers
*
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index db5c02bd4420..a7033b9f20f5 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -479,6 +479,7 @@ struct dwc2_core_params {
bool enable_dynamic_fifo;
bool en_multiple_tx_fifo;
bool i2c_enable;
+ bool acg_enable;
bool ulpi_fs_ls;
bool ts_dline;
bool reload_ctl;
@@ -587,6 +588,7 @@ struct dwc2_hw_params {
unsigned hs_phy_type:2;
unsigned fs_phy_type:2;
unsigned i2c_enable:1;
+ unsigned acg_enable:1;
unsigned num_dev_ep:4;
unsigned num_dev_in_eps : 4;
unsigned num_dev_perio_in_ep:4;
@@ -1115,6 +1117,8 @@ void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg);
void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd);
void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd);
+void dwc2_enable_acg(struct dwc2_hsotg *hsotg);
+
/* This function should be called on every hardware interrupt. */
irqreturn_t dwc2_handle_common_intr(int irq, void *dev);
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 481684385bfe..47b098380f10 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -4346,6 +4346,8 @@ static int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on)
if (is_on) {
hsotg->enabled = 1;
dwc2_hsotg_core_init_disconnected(hsotg, false);
+ /* Enable ACG feature in device mode,if supported */
+ dwc2_enable_acg(hsotg);
dwc2_hsotg_core_connect(hsotg);
} else {
dwc2_hsotg_core_disconnect(hsotg);
@@ -4378,8 +4380,11 @@ static int dwc2_hsotg_vbus_session(struct usb_gadget *gadget, int is_active)
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
dwc2_hsotg_core_init_disconnected(hsotg, false);
- if (hsotg->enabled)
+ if (hsotg->enabled) {
+ /* Enable ACG feature in device mode,if supported */
+ dwc2_enable_acg(hsotg);
dwc2_hsotg_core_connect(hsotg);
+ }
} else {
dwc2_hsotg_core_disconnect(hsotg);
dwc2_hsotg_disconnect(hsotg);
@@ -4744,8 +4749,11 @@ int dwc2_hsotg_resume(struct dwc2_hsotg *hsotg)
spin_lock_irqsave(&hsotg->lock, flags);
dwc2_hsotg_core_init_disconnected(hsotg, false);
- if (hsotg->enabled)
+ if (hsotg->enabled) {
+ /* Enable ACG feature in device mode,if supported */
+ dwc2_enable_acg(hsotg);
dwc2_hsotg_core_connect(hsotg);
+ }
spin_unlock_irqrestore(&hsotg->lock, flags);
}
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 6f7f9c73b596..edcc9058274a 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -2436,6 +2436,9 @@ static void dwc2_core_host_init(struct dwc2_hsotg *hsotg)
}
}
+ /* Enable ACG feature in host mode, if supported */
+ dwc2_enable_acg(hsotg);
+
/* Turn on the vbus power */
dev_dbg(hsotg->dev, "Init: Port Power? op_state=%d\n", hsotg->op_state);
if (hsotg->op_state == OTG_STATE_A_HOST) {
@@ -3302,6 +3305,8 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
spin_lock_irqsave(&hsotg->lock, flags);
dwc2_hsotg_core_init_disconnected(hsotg, false);
spin_unlock_irqrestore(&hsotg->lock, flags);
+ /* Enable ACG feature in device mode,if supported */
+ dwc2_enable_acg(hsotg);
dwc2_hsotg_core_connect(hsotg);
} else {
host:
diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h
index 43a3fb00f14f..bfb85519af32 100644
--- a/drivers/usb/dwc2/hw.h
+++ b/drivers/usb/dwc2/hw.h
@@ -310,6 +310,7 @@
#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT 16
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK (0x3 << 14)
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 14
+#define GHWCFG4_ACG_SUPPORTED BIT(12)
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2
@@ -645,6 +646,10 @@
#define PCGCTL_GATEHCLK BIT(1)
#define PCGCTL_STOPPCLK BIT(0)
+#define PCGCCTL1 HSOTG_REG(0xe04)
+#define PCGCCTL1_TIMER (0x3 << 1)
+#define PCGCCTL1_GATEEN BIT(0)
+
#define EPFIFO(_a) HSOTG_REG(0x1000 + ((_a) * 0x1000))
/* Host Mode Registers */
diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
index 430325510812..f0f877c4528d 100644
--- a/drivers/usb/dwc2/params.c
+++ b/drivers/usb/dwc2/params.c
@@ -272,6 +272,7 @@ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg)
p->enable_dynamic_fifo = hw->enable_dynamic_fifo;
p->en_multiple_tx_fifo = hw->en_multiple_tx_fifo;
p->i2c_enable = hw->i2c_enable;
+ p->acg_enable = hw->acg_enable;
p->ulpi_fs_ls = false;
p->ts_dline = false;
p->reload_ctl = (hw->snpsid >= DWC2_CORE_REV_2_92a);
@@ -526,6 +527,7 @@ static void dwc2_check_params(struct dwc2_hsotg *hsotg)
CHECK_BOOL(enable_dynamic_fifo, hw->enable_dynamic_fifo);
CHECK_BOOL(en_multiple_tx_fifo, hw->en_multiple_tx_fifo);
CHECK_BOOL(i2c_enable, hw->i2c_enable);
+ CHECK_BOOL(acg_enable, hw->acg_enable);
CHECK_BOOL(reload_ctl, (hsotg->hw_params.snpsid > DWC2_CORE_REV_2_92a));
CHECK_RANGE(max_packet_count,
15, hw->max_packet_count,
@@ -716,6 +718,7 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
hw->power_optimized = !!(hwcfg4 & GHWCFG4_POWER_OPTIMIZ);
hw->utmi_phy_data_width = (hwcfg4 & GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK) >>
GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT;
+ hw->acg_enable = !!(hwcfg4 & GHWCFG4_ACG_SUPPORTED);
/* fifo sizes */
hw->rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >>