Commit cf40b86b authored by John Youn's avatar John Youn Committed by Felipe Balbi

usb: dwc3: Implement interrupt moderation

Implement interrupt moderation which allows the interrupt rate to be
throttled. To enable this feature the dwc->imod_interval must be set to
1 or greater. This value specifies the minimum inter-interrupt interval,
in 250 ns increments. A value of 0 disables interrupt moderation.

This applies for DWC_usb3 version 3.00a and higher and for DWC_usb31
version 1.20a and higher.
Signed-off-by: default avatarJohn Youn <johnyoun@synopsys.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent 3922fb46
...@@ -982,12 +982,28 @@ static void dwc3_get_properties(struct dwc3 *dwc) ...@@ -982,12 +982,28 @@ static void dwc3_get_properties(struct dwc3 *dwc)
dwc->hird_threshold = hird_threshold dwc->hird_threshold = hird_threshold
| (dwc->is_utmi_l1_suspend << 4); | (dwc->is_utmi_l1_suspend << 4);
dwc->imod_interval = 0;
}
/* check whether the core supports IMOD */
bool dwc3_has_imod(struct dwc3 *dwc)
{
return ((dwc3_is_usb3(dwc) &&
dwc->revision >= DWC3_REVISION_300A) ||
(dwc3_is_usb31(dwc) &&
dwc->revision >= DWC3_USB31_REVISION_120A));
} }
static void dwc3_check_params(struct dwc3 *dwc) static void dwc3_check_params(struct dwc3 *dwc)
{ {
struct device *dev = dwc->dev; struct device *dev = dwc->dev;
/* Check for proper value of imod_interval */
if (dwc->imod_interval && !dwc3_has_imod(dwc)) {
dev_warn(dwc->dev, "Interrupt moderation not supported\n");
dwc->imod_interval = 0;
}
/* Check the maximum_speed parameter */ /* Check the maximum_speed parameter */
switch (dwc->maximum_speed) { switch (dwc->maximum_speed) {
case USB_SPEED_LOW: case USB_SPEED_LOW:
......
...@@ -67,6 +67,7 @@ ...@@ -67,6 +67,7 @@
#define DWC3_DEVICE_EVENT_OVERFLOW 11 #define DWC3_DEVICE_EVENT_OVERFLOW 11
#define DWC3_GEVNTCOUNT_MASK 0xfffc #define DWC3_GEVNTCOUNT_MASK 0xfffc
#define DWC3_GEVNTCOUNT_EHB (1 << 31)
#define DWC3_GSNPSID_MASK 0xffff0000 #define DWC3_GSNPSID_MASK 0xffff0000
#define DWC3_GSNPSREV_MASK 0xffff #define DWC3_GSNPSREV_MASK 0xffff
...@@ -149,6 +150,8 @@ ...@@ -149,6 +150,8 @@
#define DWC3_DEPCMDPAR0 0x08 #define DWC3_DEPCMDPAR0 0x08
#define DWC3_DEPCMD 0x0c #define DWC3_DEPCMD 0x0c
#define DWC3_DEV_IMOD(n) (0xca00 + (n * 0x4))
/* OTG Registers */ /* OTG Registers */
#define DWC3_OCFG 0xcc00 #define DWC3_OCFG 0xcc00
#define DWC3_OCTL 0xcc04 #define DWC3_OCTL 0xcc04
...@@ -465,6 +468,11 @@ ...@@ -465,6 +468,11 @@
#define DWC3_DEPCMD_TYPE_BULK 2 #define DWC3_DEPCMD_TYPE_BULK 2
#define DWC3_DEPCMD_TYPE_INTR 3 #define DWC3_DEPCMD_TYPE_INTR 3
#define DWC3_DEV_IMOD_COUNT_SHIFT 16
#define DWC3_DEV_IMOD_COUNT_MASK (0xffff << 16)
#define DWC3_DEV_IMOD_INTERVAL_SHIFT 0
#define DWC3_DEV_IMOD_INTERVAL_MASK (0xffff << 0)
/* Structures */ /* Structures */
struct dwc3_trb; struct dwc3_trb;
...@@ -846,6 +854,8 @@ struct dwc3_scratchpad_array { ...@@ -846,6 +854,8 @@ struct dwc3_scratchpad_array {
* 1 - -3.5dB de-emphasis * 1 - -3.5dB de-emphasis
* 2 - No de-emphasis * 2 - No de-emphasis
* 3 - Reserved * 3 - Reserved
* @imod_interval: set the interrupt moderation interval in 250ns
* increments or 0 to disable.
*/ */
struct dwc3 { struct dwc3 {
struct usb_ctrlrequest *ctrl_req; struct usb_ctrlrequest *ctrl_req;
...@@ -933,6 +943,7 @@ struct dwc3 { ...@@ -933,6 +943,7 @@ struct dwc3 {
*/ */
#define DWC3_REVISION_IS_DWC31 0x80000000 #define DWC3_REVISION_IS_DWC31 0x80000000
#define DWC3_USB31_REVISION_110A (0x3131302a | DWC3_REVISION_IS_DWC31) #define DWC3_USB31_REVISION_110A (0x3131302a | DWC3_REVISION_IS_DWC31)
#define DWC3_USB31_REVISION_120A (0x3132302a | DWC3_REVISION_IS_DWC31)
enum dwc3_ep0_next ep0_next_event; enum dwc3_ep0_next ep0_next_event;
enum dwc3_ep0_state ep0state; enum dwc3_ep0_state ep0state;
...@@ -991,6 +1002,8 @@ struct dwc3 { ...@@ -991,6 +1002,8 @@ struct dwc3 {
unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis_quirk:1;
unsigned tx_de_emphasis:2; unsigned tx_de_emphasis:2;
u16 imod_interval;
}; };
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
...@@ -1162,6 +1175,8 @@ static inline bool dwc3_is_usb31(struct dwc3 *dwc) ...@@ -1162,6 +1175,8 @@ static inline bool dwc3_is_usb31(struct dwc3 *dwc)
return !!(dwc->revision & DWC3_REVISION_IS_DWC31); return !!(dwc->revision & DWC3_REVISION_IS_DWC31);
} }
bool dwc3_has_imod(struct dwc3 *dwc);
#if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) #if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
int dwc3_host_init(struct dwc3 *dwc); int dwc3_host_init(struct dwc3 *dwc);
void dwc3_host_exit(struct dwc3 *dwc); void dwc3_host_exit(struct dwc3 *dwc);
......
...@@ -1685,6 +1685,17 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) ...@@ -1685,6 +1685,17 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
int ret = 0; int ret = 0;
u32 reg; u32 reg;
/*
* Use IMOD if enabled via dwc->imod_interval. Otherwise, if
* the core supports IMOD, disable it.
*/
if (dwc->imod_interval) {
dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval);
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB);
} else if (dwc3_has_imod(dwc)) {
dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), 0);
}
reg = dwc3_readl(dwc->regs, DWC3_DCFG); reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg &= ~(DWC3_DCFG_SPEED_MASK); reg &= ~(DWC3_DCFG_SPEED_MASK);
...@@ -2847,6 +2858,11 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt) ...@@ -2847,6 +2858,11 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt)
reg &= ~DWC3_GEVNTSIZ_INTMASK; reg &= ~DWC3_GEVNTSIZ_INTMASK;
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg); dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg);
if (dwc->imod_interval) {
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB);
dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval);
}
return ret; return ret;
} }
......
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