From f02765086dbb51df6dc24942cd2d5cc02db77af6 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Thu, 30 May 2013 16:23:06 +0000 Subject: [PATCH] ar71xx: add USB workarounds for AR934x/QCA955x SoCs Signed-off-by: Gabor Juhos SVN-Revision: 36787 --- ...490-usb-ehci-add-quirks-for-qca-socs.patch | 101 ++++++++++++++++++ ...525-MIPS-ath79-enable-qca-usb-quirks.patch | 86 +++++++++++++++ 2 files changed, 187 insertions(+) create mode 100644 target/linux/ar71xx/patches-3.8/490-usb-ehci-add-quirks-for-qca-socs.patch create mode 100644 target/linux/ar71xx/patches-3.8/525-MIPS-ath79-enable-qca-usb-quirks.patch diff --git a/target/linux/ar71xx/patches-3.8/490-usb-ehci-add-quirks-for-qca-socs.patch b/target/linux/ar71xx/patches-3.8/490-usb-ehci-add-quirks-for-qca-socs.patch new file mode 100644 index 00000000000..98d6c0b37a9 --- /dev/null +++ b/target/linux/ar71xx/patches-3.8/490-usb-ehci-add-quirks-for-qca-socs.patch @@ -0,0 +1,101 @@ +--- a/drivers/usb/host/ehci-hcd.c ++++ b/drivers/usb/host/ehci-hcd.c +@@ -249,6 +249,37 @@ static int ehci_reset (struct ehci_hcd * + command |= CMD_RESET; + dbg_cmd (ehci, "reset", command); + ehci_writel(ehci, command, &ehci->regs->command); ++ ++ if (ehci->qca_force_host_mode) { ++ u32 usbmode; ++ ++ udelay(1000); ++ ++ usbmode = ehci_readl(ehci, &ehci->regs->usbmode); ++ usbmode |= USBMODE_CM_HC | (1 << 4); ++ ehci_writel(ehci, usbmode, &ehci->regs->usbmode); ++ ++ ehci_dbg(ehci, "forced host mode, usbmode: %08x\n", ++ ehci_readl(ehci, &ehci->regs->usbmode)); ++ } ++ ++ if (ehci->qca_force_16bit_ptw) { ++ u32 port_status; ++ ++ udelay(1000); ++ ++ /* enable 16-bit UTMI interface */ ++ port_status = ehci_readl(ehci, &ehci->regs->port_status[0]); ++ port_status |= BIT(28); ++ ehci_writel(ehci, port_status, &ehci->regs->port_status[0]); ++ ++ ehci_dbg(ehci, "16-bit UTMI interface enabled, status: %08x\n", ++ ehci_readl(ehci, &ehci->regs->port_status[0])); ++ } ++ ++ if (ehci->reset_notifier) ++ ehci->reset_notifier(ehci_to_hcd(ehci)); ++ + ehci->rh_state = EHCI_RH_HALTED; + ehci->next_statechange = jiffies; + retval = handshake (ehci, &ehci->regs->command, +--- a/drivers/usb/host/ehci.h ++++ b/drivers/usb/host/ehci.h +@@ -201,6 +201,10 @@ struct ehci_hcd { /* one per controlle + unsigned has_synopsys_hc_bug:1; /* Synopsys HC */ + unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */ + unsigned ignore_oc:1; ++ unsigned qca_force_host_mode:1; ++ unsigned qca_force_16bit_ptw:1; /* force 16 bit UTMI */ ++ ++ void (*reset_notifier)(struct usb_hcd *hcd); + + /* required for usb32 quirk */ + #define OHCI_CTRL_HCFS (3 << 6) +--- a/include/linux/usb/ehci_pdriver.h ++++ b/include/linux/usb/ehci_pdriver.h +@@ -43,6 +43,8 @@ struct usb_ehci_pdata { + unsigned big_endian_mmio:1; + unsigned no_io_watchdog:1; + unsigned ignore_oc:1; ++ unsigned qca_force_host_mode:1; ++ unsigned qca_force_16bit_ptw:1; + + /* Turn on all power and clocks */ + int (*power_on)(struct platform_device *pdev); +@@ -51,6 +53,7 @@ struct usb_ehci_pdata { + /* Turn on only VBUS suspend power and hotplug detection, + * turn off everything else */ + void (*power_suspend)(struct platform_device *pdev); ++ void (*reset_notifier)(struct platform_device *pdev); + }; + + #endif /* __USB_CORE_EHCI_PDRIVER_H */ +--- a/drivers/usb/host/ehci-platform.c ++++ b/drivers/usb/host/ehci-platform.c +@@ -33,6 +33,14 @@ + + static const char hcd_name[] = "ehci-platform"; + ++static void ehci_platform_reset_notifier(struct usb_hcd *hcd) ++{ ++ struct platform_device *pdev = to_platform_device(hcd->self.controller); ++ struct usb_ehci_pdata *pdata = pdev->dev.platform_data; ++ ++ pdata->reset_notifier(pdev); ++} ++ + static int ehci_platform_reset(struct usb_hcd *hcd) + { + struct platform_device *pdev = to_platform_device(hcd->self.controller); +@@ -45,6 +53,11 @@ static int ehci_platform_reset(struct us + ehci->big_endian_desc = pdata->big_endian_desc; + ehci->big_endian_mmio = pdata->big_endian_mmio; + ehci->ignore_oc = pdata->ignore_oc; ++ ehci->qca_force_host_mode = pdata->qca_force_host_mode; ++ ehci->qca_force_16bit_ptw = pdata->qca_force_16bit_ptw; ++ ++ if (pdata->reset_notifier) ++ ehci->reset_notifier = ehci_platform_reset_notifier; + + ehci->caps = hcd->regs + pdata->caps_offset; + retval = ehci_setup(hcd); diff --git a/target/linux/ar71xx/patches-3.8/525-MIPS-ath79-enable-qca-usb-quirks.patch b/target/linux/ar71xx/patches-3.8/525-MIPS-ath79-enable-qca-usb-quirks.patch new file mode 100644 index 00000000000..ede8035c7ce --- /dev/null +++ b/target/linux/ar71xx/patches-3.8/525-MIPS-ath79-enable-qca-usb-quirks.patch @@ -0,0 +1,86 @@ +--- a/arch/mips/ath79/dev-usb.c ++++ b/arch/mips/ath79/dev-usb.c +@@ -182,14 +182,34 @@ static void __init ar933x_usb_setup(void + &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2)); + } + +-static void __init ar934x_usb_setup(void) ++static void enable_tx_tx_idp_violation_fix(unsigned base) + { +- u32 bootstrap; ++ void __iomem *phy_reg; ++ u32 t; ++ ++ phy_reg = ioremap(base, 4); ++ if (!phy_reg) ++ return; ++ ++ t = ioread32(phy_reg); ++ t &= ~0xff; ++ t |= 0x58; ++ iowrite32(t, phy_reg); ++ ++ iounmap(phy_reg); ++} + +- bootstrap = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP); +- if (bootstrap & AR934X_BOOTSTRAP_USB_MODE_DEVICE) ++static void ar934x_usb_reset_notifier(struct platform_device *pdev) ++{ ++ if (pdev->id != -1) + return; + ++ enable_tx_tx_idp_violation_fix(0x18116c94); ++ dev_info(&pdev->dev, "TX-TX IDP fix enabled\n"); ++} ++ ++static void __init ar934x_usb_setup(void) ++{ + ath79_device_reset_set(AR934X_RESET_USBSUS_OVERRIDE); + udelay(1000); + +@@ -202,14 +222,44 @@ static void __init ar934x_usb_setup(void + ath79_device_reset_clear(AR934X_RESET_USB_HOST); + udelay(1000); + ++ ath79_ehci_pdata_v2.qca_force_host_mode = 1; ++ ath79_ehci_pdata_v2.qca_force_16bit_ptw = 1; ++ if (ath79_soc_rev >= 3) ++ ath79_ehci_pdata_v2.reset_notifier = ar934x_usb_reset_notifier; ++ + ath79_usb_register("ehci-platform", -1, + AR934X_EHCI_BASE, AR934X_EHCI_SIZE, + ATH79_CPU_IRQ(3), + &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2)); + } + ++static void qca955x_usb_reset_notifier(struct platform_device *pdev) ++{ ++ u32 base; ++ ++ switch (pdev->id) { ++ case 0: ++ base = 0x18116c94; ++ break; ++ ++ case 1: ++ base = 0x18116e54; ++ break; ++ ++ default: ++ return; ++ } ++ ++ enable_tx_tx_idp_violation_fix(base); ++ dev_info(&pdev->dev, "TX-TX IDP fix enabled\n"); ++} ++ + static void __init qca955x_usb_setup(void) + { ++ ath79_ehci_pdata_v2.qca_force_host_mode = 1; ++ ath79_ehci_pdata_v2.qca_force_16bit_ptw = 1; ++ ath79_ehci_pdata_v2.reset_notifier = qca955x_usb_reset_notifier; ++ + ath79_usb_register("ehci-platform", 0, + QCA955X_EHCI0_BASE, QCA955X_EHCI_SIZE, + ATH79_IP3_IRQ(0), -- 2.30.2