From: Razmik Karapetyan <razmik@xxxxxxxxxxxx> Added function for supporting Active Clock Gating functionality. New acg_enable field in dwc2_hw_params checks ACG support from hardware side. Similar acg_enable field in dwc2_core_params used for dynamicly disabling/enabling ACG functionality from driver. dwc2_enable_acg() function sets GATEEN bit in PCGCCTL1 register and enables ACG, if supported. According to ACG functional specification, enabling of ACG feature in host mode done in host initialization, before turning Vbus on, specifically in dwc2_core_host_init function. Enabling of ACG feature in device mode done in device initialization, before clearing the SftDiscon bit in DCTL. This bit was cleared in dwc2_hsotg_core_connect() function.So dwc2_enable_acg() called before dwc2_core_connect() calls. Signed-off-by: Razmik Karapetyan <razmik@xxxxxxxxxxxx> Signed-off-by: Grigor Tovmasyan <tovmasya@xxxxxxxxxxxx> --- drivers/usb/dwc2/core.c | 14 ++++++++++++++ drivers/usb/dwc2/core.h | 4 ++++ drivers/usb/dwc2/gadget.c | 12 ++++++++++-- drivers/usb/dwc2/hcd.c | 5 +++++ drivers/usb/dwc2/params.c | 2 ++ 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index dbca3b8890da..c8bbdb51e1c6 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -492,6 +492,20 @@ void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg) } } +/* + * 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 382d8d9f402f..da302a2ef58a 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -480,6 +480,7 @@ struct dwc2_core_params { bool en_multiple_tx_fifo; bool i2c_enable; bool ulpi_fs_ls; + bool acg_enable; bool ts_dline; bool reload_ctl; bool uframe_sched; @@ -585,6 +586,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_perio_in_ep:4; unsigned total_fifo_size:16; @@ -1125,6 +1127,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 5c9d63d5f9fc..cf0070cbaf17 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -4384,6 +4384,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); @@ -4416,8 +4418,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); @@ -4782,8 +4787,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 fafbba4e79e8..6e9f3fdff9c5 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -2407,6 +2407,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) { @@ -3273,6 +3276,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/params.c b/drivers/usb/dwc2/params.c index 0ff7dce1ca3b..427e7afe2b8d 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); @@ -703,6 +704,7 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg) hw->num_dev_perio_in_ep = (hwcfg4 & GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK) >> GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT; hw->dma_desc_enable = !!(hwcfg4 & GHWCFG4_DESC_DMA); + hw->acg_enable = !!(hwcfg4 & GHWCFG4_ACG_SUPPORTED); 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; -- 2.11.0 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html