usb: chipidea: introduce ITC tuning interface
authorPeter Chen <peter.chen@freescale.com>
Mon, 22 Sep 2014 08:45:39 +0000 (16:45 +0800)
committerPeter Chen <peter.chen@freescale.com>
Fri, 14 Aug 2015 01:13:11 +0000 (09:13 +0800)
ITC (Interrupt Threshold Control) is used to set the maximum rate at which
the host/device controller will issue interrupts. The default value is 8 (1ms)
for it. EHCI core will modify it to 1, but device mode keeps it as default
value.

In some use cases like Android ADB, it only has one usb request for each
direction, and maximum payload data is only 4KB, so the speed is 4MB/s
at most, it needs controller to trigger interrupt as fast as possible
to increase the speed. The USB performance will be better if the interrupt
can be triggered faster.

Reduce ITC value is benefit for USB performance, but the interrupt number
is increased at the same time, it may increase cpu utilization too.
Most of use case cares about performance, but some may care about
cpu utilization, so, we leave a platform interface for user.
We set ITC as 1 (1 micro-frame) as default value which is aligned
with ehci core default value.

Signed-off-by: Peter Chen <peter.chen@freescale.com>
drivers/usb/chipidea/core.c
include/linux/usb/chipidea.h

index 1b1dd80897f75d09e13acbf2102f1c19c020dcc7..845d0d7d28e6f8a92caef51fb6ae5b8cc61e118f 100644 (file)
@@ -425,6 +425,9 @@ void ci_platform_configure(struct ci_hdrc *ci)
 
        if (ci->platdata->flags & CI_HDRC_SET_NON_ZERO_TTHA)
                hw_write(ci, OP_TTCTRL, TTCTRL_TTHA_MASK, TTCTRL_TTHA);
+
+       hw_write(ci, OP_USBCMD, 0xff0000, ci->platdata->itc_setting << 16);
+
 }
 
 /**
@@ -576,6 +579,8 @@ static irqreturn_t ci_irq(int irq, void *data)
 static int ci_get_platdata(struct device *dev,
                struct ci_hdrc_platform_data *platdata)
 {
+       int ret;
+
        if (!platdata->phy_mode)
                platdata->phy_mode = of_usb_get_phy_mode(dev->of_node);
 
@@ -607,6 +612,17 @@ static int ci_get_platdata(struct device *dev,
        if (of_usb_get_maximum_speed(dev->of_node) == USB_SPEED_FULL)
                platdata->flags |= CI_HDRC_FORCE_FULLSPEED;
 
+       platdata->itc_setting = 1;
+       if (of_find_property(dev->of_node, "itc-setting", NULL)) {
+               ret = of_property_read_u32(dev->of_node, "itc-setting",
+                       &platdata->itc_setting);
+               if (ret) {
+                       dev_err(dev,
+                               "failed to get itc-setting\n");
+                       return ret;
+               }
+       }
+
        return 0;
 }
 
index d1e1285a971dffc60f00ba5196d29d523a41cfdf..1c5d7763990ae8cb00064200945ccb9ecd4f33bd 100644 (file)
@@ -36,6 +36,8 @@ struct ci_hdrc_platform_data {
        void    (*notify_event) (struct ci_hdrc *ci, unsigned event);
        struct regulator        *reg_vbus;
        bool                    tpl_support;
+       /* interrupt threshold setting */
+       u32                     itc_setting;
 };
 
 /* Default offset of capability registers */