Skip to content

Commit

Permalink
dwc_otg: Choose appropriate IRQ handover strategy
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Phil Elwell committed Jun 26, 2019
1 parent 3430dd7 commit b53a604
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 28 deletions.
9 changes: 5 additions & 4 deletions drivers/usb/host/dwc_otg/dwc_otg_driver.c
Expand Up @@ -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
Expand Down
21 changes: 14 additions & 7 deletions drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
Expand Up @@ -1347,8 +1347,12 @@ void notrace dwc_otg_fiq_fsm(struct fiq_state *state, int num_channels)
/* 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++;
Expand Down Expand Up @@ -1406,11 +1410,14 @@ void notrace dwc_otg_fiq_nop(struct fiq_state *state)
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();
Expand Down
2 changes: 2 additions & 0 deletions drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h
Expand Up @@ -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 {
Expand Down
12 changes: 8 additions & 4 deletions drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
Expand Up @@ -220,16 +220,20 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd)

/* 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) */
Expand Down
41 changes: 28 additions & 13 deletions drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
Expand Up @@ -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;

Expand Down

0 comments on commit b53a604

Please sign in to comment.