xhci: mediatek: support MTK xHCI host controller
There some vendor quirks for MTK xhci host controller:
1. It defines some extra SW scheduling parameters for HW
to minimize the scheduling effort for synchronous and
interrupt endpoints. The parameters are put into reseved
DWs of slot context and endpoint context.
2. Its IMODI unit for Interrupter Moderation register is
8 times as much as that defined in xHCI spec.
3. Its TDS in Normal TRB defines a number of packets that
remains to be transferred for a TD after processing all
Max packets in all previous TRBs.
Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
Tested-by: Daniel Thompson <daniel.thompson@linaro.org>
Reviewed-by: Daniel Thompson <daniel.thompson@linaro.org>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index ac25e90..887f308 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -31,6 +31,7 @@
#include "xhci.h"
#include "xhci-trace.h"
+#include "xhci-mtk.h"
#define DRIVER_AUTHOR "Sarah Sharp"
#define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
@@ -634,7 +635,11 @@
"// Set the interrupt modulation register");
temp = readl(&xhci->ir_set->irq_control);
temp &= ~ER_IRQ_INTERVAL_MASK;
- temp |= (u32) 160;
+ /*
+ * the increment interval is 8 times as much as that defined
+ * in xHCI spec on MTK's controller
+ */
+ temp |= (u32) ((xhci->quirks & XHCI_MTK_HOST) ? 20 : 160);
writel(temp, &xhci->ir_set->irq_control);
/* Set the HCD state before we enable the irqs */
@@ -1698,6 +1703,9 @@
xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep);
+ if (xhci->quirks & XHCI_MTK_HOST)
+ xhci_mtk_drop_ep_quirk(hcd, udev, ep);
+
xhci_dbg(xhci, "drop ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x\n",
(unsigned int) ep->desc.bEndpointAddress,
udev->slot_id,
@@ -1793,6 +1801,15 @@
return -ENOMEM;
}
+ if (xhci->quirks & XHCI_MTK_HOST) {
+ ret = xhci_mtk_add_ep_quirk(hcd, udev, ep);
+ if (ret < 0) {
+ xhci_free_or_cache_endpoint_ring(xhci,
+ virt_dev, ep_index);
+ return ret;
+ }
+ }
+
ctrl_ctx->add_flags |= cpu_to_le32(added_ctxs);
new_add_flags = le32_to_cpu(ctrl_ctx->add_flags);