ehci->next_uframe = now_uframe;
now = ehci_readl(ehci, &ehci->regs->frame_index) &
(mod - 1);
- if (now_uframe == now)
+ if (now_uframe == now) {
+ quirk_usb_periodic_hw_bug_workaround(
+ &ehci->next_uframe, ehci->periodic_size);
break;
+ }
/* rescan the rest of this frame, then ... */
clock = now;
quirk_usb_handoff_xhci(pdev);
}
DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
+
+/**
+ * This quirk is a hardware workaround. On Intel Medfield platform,
+ * EHCI hardware update FRINDEX register before update completed
+ * QH's active flag. This behavior cause EHCI driver can't find the
+ * completed QH which need to handle.
+ *
+ * Let EHCI driver to roll back 160 uframes to check the completed QH.
+ */
+void quirk_usb_periodic_hw_bug_workaround(int *next_uframe, int periodic_size)
+{
+#ifdef CONFIG_USB_PENWELL_OTG
+#define ROLLBACK_UFRAME 160
+ if (*next_uframe < ROLLBACK_UFRAME)
+ *next_uframe = (periodic_size << 3)
+ - (ROLLBACK_UFRAME - *next_uframe);
+ else
+ *next_uframe -= ROLLBACK_UFRAME;
+#endif
+}
+EXPORT_SYMBOL_GPL(quirk_usb_periodic_hw_bug_workaround);
static inline void usb_amd_quirk_pll_enable(void) {}
static inline void usb_amd_dev_put(void) {}
#endif /* CONFIG_PCI */
+void quirk_usb_periodic_hw_bug_workaround(int *next_uframe, int periodic_size);
#endif /* __LINUX_USB_PCI_QUIRKS_H */