Commit 66e77a24 authored by Razmik Karapetyan's avatar Razmik Karapetyan Committed by Felipe Balbi

usb: dwc2: Add ACG support to the driver

Added function for supporting Active Clock Gating functionality
in the driver.

PCGCCTL1 (Power and Clock Control) register will be used
for controlling the core`s active clock gating feature, and
the previously reserved 12th bit in GHWCFG4 now indicates that the
controller supports the Dynamic Power Reduction (Active Clock Gating)
during no traffic scenarios such as L0, idle, resume and suspend
states.

dwc2_enable_acg() function sets GATEEN bit in PCGCCTL1 register
and enables ACG, if it 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: default avatarRazmik Karapetyan <razmik@synopsys.com>
Signed-off-by: default avatarGrigor Tovmasyan <tovmasya@synopsys.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent 42c6a252
...@@ -498,6 +498,20 @@ int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg) ...@@ -498,6 +498,20 @@ int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg)
return 0; 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 * dwc2_dump_host_registers() - Prints the host registers
* *
......
...@@ -479,6 +479,7 @@ struct dwc2_core_params { ...@@ -479,6 +479,7 @@ struct dwc2_core_params {
bool enable_dynamic_fifo; bool enable_dynamic_fifo;
bool en_multiple_tx_fifo; bool en_multiple_tx_fifo;
bool i2c_enable; bool i2c_enable;
bool acg_enable;
bool ulpi_fs_ls; bool ulpi_fs_ls;
bool ts_dline; bool ts_dline;
bool reload_ctl; bool reload_ctl;
...@@ -587,6 +588,7 @@ struct dwc2_hw_params { ...@@ -587,6 +588,7 @@ struct dwc2_hw_params {
unsigned hs_phy_type:2; unsigned hs_phy_type:2;
unsigned fs_phy_type:2; unsigned fs_phy_type:2;
unsigned i2c_enable:1; unsigned i2c_enable:1;
unsigned acg_enable:1;
unsigned num_dev_ep:4; unsigned num_dev_ep:4;
unsigned num_dev_in_eps : 4; unsigned num_dev_in_eps : 4;
unsigned num_dev_perio_in_ep:4; unsigned num_dev_perio_in_ep:4;
...@@ -1115,6 +1117,8 @@ void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg); ...@@ -1115,6 +1117,8 @@ void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg);
void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd); void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd);
void dwc2_disable_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. */ /* This function should be called on every hardware interrupt. */
irqreturn_t dwc2_handle_common_intr(int irq, void *dev); irqreturn_t dwc2_handle_common_intr(int irq, void *dev);
......
...@@ -4346,6 +4346,8 @@ static int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on) ...@@ -4346,6 +4346,8 @@ static int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on)
if (is_on) { if (is_on) {
hsotg->enabled = 1; hsotg->enabled = 1;
dwc2_hsotg_core_init_disconnected(hsotg, false); dwc2_hsotg_core_init_disconnected(hsotg, false);
/* Enable ACG feature in device mode,if supported */
dwc2_enable_acg(hsotg);
dwc2_hsotg_core_connect(hsotg); dwc2_hsotg_core_connect(hsotg);
} else { } else {
dwc2_hsotg_core_disconnect(hsotg); dwc2_hsotg_core_disconnect(hsotg);
...@@ -4378,8 +4380,11 @@ static int dwc2_hsotg_vbus_session(struct usb_gadget *gadget, int is_active) ...@@ -4378,8 +4380,11 @@ static int dwc2_hsotg_vbus_session(struct usb_gadget *gadget, int is_active)
hsotg->op_state = OTG_STATE_B_PERIPHERAL; hsotg->op_state = OTG_STATE_B_PERIPHERAL;
dwc2_hsotg_core_init_disconnected(hsotg, false); 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); dwc2_hsotg_core_connect(hsotg);
}
} else { } else {
dwc2_hsotg_core_disconnect(hsotg); dwc2_hsotg_core_disconnect(hsotg);
dwc2_hsotg_disconnect(hsotg); dwc2_hsotg_disconnect(hsotg);
...@@ -4744,8 +4749,11 @@ int dwc2_hsotg_resume(struct dwc2_hsotg *hsotg) ...@@ -4744,8 +4749,11 @@ int dwc2_hsotg_resume(struct dwc2_hsotg *hsotg)
spin_lock_irqsave(&hsotg->lock, flags); spin_lock_irqsave(&hsotg->lock, flags);
dwc2_hsotg_core_init_disconnected(hsotg, false); 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); dwc2_hsotg_core_connect(hsotg);
}
spin_unlock_irqrestore(&hsotg->lock, flags); spin_unlock_irqrestore(&hsotg->lock, flags);
} }
......
...@@ -2436,6 +2436,9 @@ static void dwc2_core_host_init(struct dwc2_hsotg *hsotg) ...@@ -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 */ /* Turn on the vbus power */
dev_dbg(hsotg->dev, "Init: Port Power? op_state=%d\n", hsotg->op_state); dev_dbg(hsotg->dev, "Init: Port Power? op_state=%d\n", hsotg->op_state);
if (hsotg->op_state == OTG_STATE_A_HOST) { if (hsotg->op_state == OTG_STATE_A_HOST) {
...@@ -3302,6 +3305,8 @@ static void dwc2_conn_id_status_change(struct work_struct *work) ...@@ -3302,6 +3305,8 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
spin_lock_irqsave(&hsotg->lock, flags); spin_lock_irqsave(&hsotg->lock, flags);
dwc2_hsotg_core_init_disconnected(hsotg, false); dwc2_hsotg_core_init_disconnected(hsotg, false);
spin_unlock_irqrestore(&hsotg->lock, flags); spin_unlock_irqrestore(&hsotg->lock, flags);
/* Enable ACG feature in device mode,if supported */
dwc2_enable_acg(hsotg);
dwc2_hsotg_core_connect(hsotg); dwc2_hsotg_core_connect(hsotg);
} else { } else {
host: host:
......
...@@ -310,6 +310,7 @@ ...@@ -310,6 +310,7 @@
#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT 16 #define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT 16
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK (0x3 << 14) #define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK (0x3 << 14)
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 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_8 0
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1 #define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1
#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2 #define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2
...@@ -645,6 +646,10 @@ ...@@ -645,6 +646,10 @@
#define PCGCTL_GATEHCLK BIT(1) #define PCGCTL_GATEHCLK BIT(1)
#define PCGCTL_STOPPCLK BIT(0) #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)) #define EPFIFO(_a) HSOTG_REG(0x1000 + ((_a) * 0x1000))
/* Host Mode Registers */ /* Host Mode Registers */
......
...@@ -272,6 +272,7 @@ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg) ...@@ -272,6 +272,7 @@ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg)
p->enable_dynamic_fifo = hw->enable_dynamic_fifo; p->enable_dynamic_fifo = hw->enable_dynamic_fifo;
p->en_multiple_tx_fifo = hw->en_multiple_tx_fifo; p->en_multiple_tx_fifo = hw->en_multiple_tx_fifo;
p->i2c_enable = hw->i2c_enable; p->i2c_enable = hw->i2c_enable;
p->acg_enable = hw->acg_enable;
p->ulpi_fs_ls = false; p->ulpi_fs_ls = false;
p->ts_dline = false; p->ts_dline = false;
p->reload_ctl = (hw->snpsid >= DWC2_CORE_REV_2_92a); p->reload_ctl = (hw->snpsid >= DWC2_CORE_REV_2_92a);
...@@ -526,6 +527,7 @@ static void dwc2_check_params(struct dwc2_hsotg *hsotg) ...@@ -526,6 +527,7 @@ static void dwc2_check_params(struct dwc2_hsotg *hsotg)
CHECK_BOOL(enable_dynamic_fifo, hw->enable_dynamic_fifo); CHECK_BOOL(enable_dynamic_fifo, hw->enable_dynamic_fifo);
CHECK_BOOL(en_multiple_tx_fifo, hw->en_multiple_tx_fifo); CHECK_BOOL(en_multiple_tx_fifo, hw->en_multiple_tx_fifo);
CHECK_BOOL(i2c_enable, hw->i2c_enable); 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_BOOL(reload_ctl, (hsotg->hw_params.snpsid > DWC2_CORE_REV_2_92a));
CHECK_RANGE(max_packet_count, CHECK_RANGE(max_packet_count,
15, hw->max_packet_count, 15, hw->max_packet_count,
...@@ -716,6 +718,7 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg) ...@@ -716,6 +718,7 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
hw->power_optimized = !!(hwcfg4 & GHWCFG4_POWER_OPTIMIZ); hw->power_optimized = !!(hwcfg4 & GHWCFG4_POWER_OPTIMIZ);
hw->utmi_phy_data_width = (hwcfg4 & GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK) >> hw->utmi_phy_data_width = (hwcfg4 & GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK) >>
GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT; GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT;
hw->acg_enable = !!(hwcfg4 & GHWCFG4_ACG_SUPPORTED);
/* fifo sizes */ /* fifo sizes */
hw->rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >> hw->rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment