brcm2708: update to latest patches from RPi Foundation
[openwrt/staging/wigyori.git] / target / linux / brcm2708 / patches-4.19 / 950-0476-dwc_otg-Choose-appropriate-IRQ-handover-strategy.patch
diff --git a/target/linux/brcm2708/patches-4.19/950-0476-dwc_otg-Choose-appropriate-IRQ-handover-strategy.patch b/target/linux/brcm2708/patches-4.19/950-0476-dwc_otg-Choose-appropriate-IRQ-handover-strategy.patch
new file mode 100644 (file)
index 0000000..083e0c7
--- /dev/null
@@ -0,0 +1,181 @@
+From 856c8fdf68e589c89ed0518aab727c54fdff5afa Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 21 May 2019 13:36:52 +0100
+Subject: [PATCH] dwc_otg: Choose appropriate IRQ handover strategy
+
+2711 has no MPHI peripheral, but the ARM Control block can fake
+interrupts. Use the size of the DTB "mphi" reg block to determine
+which is required.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/usb/host/dwc_otg/dwc_otg_driver.c    |  9 +++--
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c   | 21 ++++++----
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h   |  2 +
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c  | 12 ++++--
+ drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 41 +++++++++++++-------
+ drivers/usb/host/dwc_otg/dwc_otg_os_dep.h    |  3 ++
+ 6 files changed, 60 insertions(+), 28 deletions(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
+@@ -806,14 +806,15 @@ static int dwc_otg_driver_probe(
+               if (!request_mem_region(_dev->resource[1].start,
+                                       _dev->resource[1].end - _dev->resource[1].start + 1,
+                                       "dwc_otg")) {
+-                dev_dbg(&_dev->dev, "error reserving mapped memory\n");
+-                retval = -EFAULT;
+-                goto fail;
+-      }
++                      dev_dbg(&_dev->dev, "error reserving mapped memory\n");
++                      retval = -EFAULT;
++                      goto fail;
++              }
+               dwc_otg_device->os_dep.mphi_base = ioremap_nocache(_dev->resource[1].start,
+                                                           _dev->resource[1].end -
+                                                           _dev->resource[1].start + 1);
++              dwc_otg_device->os_dep.use_swirq = (_dev->resource[1].end - _dev->resource[1].start) == 0x200;
+       }
+ #else
+--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
+@@ -1347,8 +1347,12 @@ void notrace dwc_otg_fiq_fsm(struct fiq_
+       /* We got an interrupt, didn't handle it. */
+       if (kick_irq) {
+               state->mphi_int_count++;
+-              FIQ_WRITE(state->mphi_regs.outdda, state->dummy_send_dma);
+-              FIQ_WRITE(state->mphi_regs.outddb, (1<<29));
++              if (state->mphi_regs.swirq_set) {
++                      FIQ_WRITE(state->mphi_regs.swirq_set, 1);
++              } else {
++                      FIQ_WRITE(state->mphi_regs.outdda, state->dummy_send_dma);
++                      FIQ_WRITE(state->mphi_regs.outddb, (1<<29));
++              }
+       }
+       state->fiq_done++;
+@@ -1406,11 +1410,14 @@ void notrace dwc_otg_fiq_nop(struct fiq_
+               state->mphi_int_count++;
+               gintmsk.d32 &= state->gintmsk_saved.d32;
+               FIQ_WRITE(state->dwc_regs_base + GINTMSK, gintmsk.d32);
+-              /* Force a clear before another dummy send */
+-              FIQ_WRITE(state->mphi_regs.intstat, (1<<29));
+-              FIQ_WRITE(state->mphi_regs.outdda, state->dummy_send_dma);
+-              FIQ_WRITE(state->mphi_regs.outddb, (1<<29));
+-
++              if (state->mphi_regs.swirq_set) {
++                      FIQ_WRITE(state->mphi_regs.swirq_set, 1);
++              } else {
++                      /* Force a clear before another dummy send */
++                      FIQ_WRITE(state->mphi_regs.intstat, (1<<29));
++                      FIQ_WRITE(state->mphi_regs.outdda, state->dummy_send_dma);
++                      FIQ_WRITE(state->mphi_regs.outddb, (1<<29));
++              }
+       }
+       state->fiq_done++;
+       mb();
+--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
++++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
+@@ -118,6 +118,8 @@ typedef struct {
+       volatile void* outdda;
+       volatile void* outddb;
+       volatile void* intstat;
++      volatile void* swirq_set;
++      volatile void* swirq_clr;
+ } mphi_regs_t;
+ enum fiq_debug_level {
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
+@@ -220,16 +220,20 @@ exit_handler_routine:
+               /* The FIQ could have sneaked another interrupt in. If so, don't clear MPHI */
+               if ((gintmsk_new.d32 == ~0) && (haintmsk_new.d32 == 0x0000FFFF)) {
++                      if (dwc_otg_hcd->fiq_state->mphi_regs.swirq_clr) {
++                              DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.swirq_clr, 1);
++                      } else {
+                               DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.intstat, (1<<16));
+-                              if (dwc_otg_hcd->fiq_state->mphi_int_count >= 50) {
+-                                      fiq_print(FIQDBG_INT, dwc_otg_hcd->fiq_state, "MPHI CLR");
++                      }
++                      if (dwc_otg_hcd->fiq_state->mphi_int_count >= 50) {
++                              fiq_print(FIQDBG_INT, dwc_otg_hcd->fiq_state, "MPHI CLR");
+                                       DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl, ((1<<31) + (1<<16)));
+                                       while (!(DWC_READ_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & (1 << 17)))
+                                               ;
+                                       DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl, (1<<31));
+                                       dwc_otg_hcd->fiq_state->mphi_int_count = 0;
+-                              }
+-                              int_done++;
++                      }
++                      int_done++;
+               }
+               haintmsk.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->haintmsk);
+               /* Re-enable interrupts that the FIQ masked (first time round) */
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
+@@ -474,22 +474,37 @@ static void hcd_init_fiq(void *cookie)
+       set_fiq_regs(&regs);
+ #endif
+-      //Set the mphi periph to  the required registers
+-      dwc_otg_hcd->fiq_state->mphi_regs.base    = otg_dev->os_dep.mphi_base;
+-      dwc_otg_hcd->fiq_state->mphi_regs.ctrl    = otg_dev->os_dep.mphi_base + 0x4c;
+-      dwc_otg_hcd->fiq_state->mphi_regs.outdda  = otg_dev->os_dep.mphi_base + 0x28;
+-      dwc_otg_hcd->fiq_state->mphi_regs.outddb  = otg_dev->os_dep.mphi_base + 0x2c;
+-      dwc_otg_hcd->fiq_state->mphi_regs.intstat = otg_dev->os_dep.mphi_base + 0x50;
+       dwc_otg_hcd->fiq_state->dwc_regs_base = otg_dev->os_dep.base;
+-      DWC_WARN("MPHI regs_base at %px", dwc_otg_hcd->fiq_state->mphi_regs.base);
+-      //Enable mphi peripheral
+-      writel((1<<31),dwc_otg_hcd->fiq_state->mphi_regs.ctrl);
++      //Set the mphi periph to the required registers
++      dwc_otg_hcd->fiq_state->mphi_regs.base    = otg_dev->os_dep.mphi_base;
++      if (otg_dev->os_dep.use_swirq) {
++              dwc_otg_hcd->fiq_state->mphi_regs.swirq_set =
++                      otg_dev->os_dep.mphi_base + 0x1f0;
++              dwc_otg_hcd->fiq_state->mphi_regs.swirq_clr =
++                      otg_dev->os_dep.mphi_base + 0x1f4;
++              DWC_WARN("Fake MPHI regs_base at 0x%08x",
++                       (int)dwc_otg_hcd->fiq_state->mphi_regs.base);
++      } else {
++              dwc_otg_hcd->fiq_state->mphi_regs.ctrl =
++                      otg_dev->os_dep.mphi_base + 0x4c;
++              dwc_otg_hcd->fiq_state->mphi_regs.outdda
++                      = otg_dev->os_dep.mphi_base + 0x28;
++              dwc_otg_hcd->fiq_state->mphi_regs.outddb
++                      = otg_dev->os_dep.mphi_base + 0x2c;
++              dwc_otg_hcd->fiq_state->mphi_regs.intstat
++                      = otg_dev->os_dep.mphi_base + 0x50;
++              DWC_WARN("MPHI regs_base at %px",
++                       dwc_otg_hcd->fiq_state->mphi_regs.base);
++
++              //Enable mphi peripheral
++              writel((1<<31),dwc_otg_hcd->fiq_state->mphi_regs.ctrl);
+ #ifdef DEBUG
+-      if (readl(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & 0x80000000)
+-              DWC_WARN("MPHI periph has been enabled");
+-      else
+-              DWC_WARN("MPHI periph has NOT been enabled");
++              if (readl(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & 0x80000000)
++                      DWC_WARN("MPHI periph has been enabled");
++              else
++                      DWC_WARN("MPHI periph has NOT been enabled");
+ #endif
++      }
+       // Enable FIQ interrupt from USB peripheral
+ #ifdef CONFIG_ARM64
+       irq = otg_dev->os_dep.fiq_num;
+--- a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
++++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
+@@ -102,6 +102,9 @@ typedef struct os_dependent {
+       /** Base address for MPHI peripheral */
+       void *mphi_base;
++      /** mphi_base actually points to the SWIRQ block */
++      bool use_swirq;
++
+       /** IRQ number (<0 if not valid) */
+       int irq_num;