2019-09-19 14:43:19 +00:00
|
|
|
From 856c8fdf68e589c89ed0518aab727c54fdff5afa Mon Sep 17 00:00:00 2001
|
2019-07-09 18:32:28 +00:00
|
|
|
From: Phil Elwell <phil@raspberrypi.org>
|
|
|
|
Date: Tue, 21 May 2019 13:36:52 +0100
|
2019-09-19 14:43:19 +00:00
|
|
|
Subject: [PATCH 545/806] dwc_otg: Choose appropriate IRQ handover strategy
|
2019-07-09 18:32:28 +00:00
|
|
|
|
|
|
|
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(®s);
|
|
|
|
#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;
|
|
|
|
|