/branches/gl-inet/target/linux/brcm2708/patches-4.9/950-0130-ARM64-DWC_OTG-Port-dwc_otg-driver-to-ARM64.patch |
@@ -0,0 +1,329 @@ |
From 99c33b6e418cefebb461fee0ad3a927a0c4127f1 Mon Sep 17 00:00:00 2001 |
From: Michael Zoran <mzoran@crowfest.net> |
Date: Sat, 14 Jan 2017 21:33:51 -0800 |
Subject: [PATCH] ARM64/DWC_OTG: Port dwc_otg driver to ARM64 |
|
In ARM64, the FIQ mechanism used by this driver is not current |
implemented. As a workaround, reqular IRQ is used instead |
of FIQ. |
|
In a separate change, the IRQ-CPU mapping is round robined |
on ARM64 to increase concurrency and allow multiple interrupts |
to be serviced at a time. This reduces the need for FIQ. |
|
Tests Run: |
|
This mechanism is most likely to break when multiple USB devices |
are attached at the same time. So the system was tested under |
stress. |
|
Devices: |
|
1. USB Speakers playing back a FLAC audio through VLC |
at 96KHz.(Higher then typically, but supported on my speakers). |
|
2. sftp transferring large files through the buildin ethernet |
connection which is connected through USB. |
|
3. Keyboard and mouse attached and being used. |
|
Although I do occasionally hear some glitches, the music seems to |
play quite well. |
|
Signed-off-by: Michael Zoran <mzoran@crowfest.net> |
--- |
drivers/usb/host/dwc_otg/Makefile | 3 ++ |
drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 17 +++++++ |
drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h | 24 ++++++++++ |
drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 4 ++ |
drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h | 4 ++ |
drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 3 +- |
drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 72 ++++++++++++++++++++++++++++ |
drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 2 + |
8 files changed, 128 insertions(+), 1 deletion(-) |
|
--- a/drivers/usb/host/dwc_otg/Makefile |
+++ b/drivers/usb/host/dwc_otg/Makefile |
@@ -37,7 +37,10 @@ dwc_otg-objs += dwc_otg_pcd_linux.o dwc_ |
dwc_otg-objs += dwc_otg_hcd.o dwc_otg_hcd_linux.o dwc_otg_hcd_intr.o dwc_otg_hcd_queue.o dwc_otg_hcd_ddma.o |
dwc_otg-objs += dwc_otg_adp.o |
dwc_otg-objs += dwc_otg_fiq_fsm.o |
+ifneq ($(CONFIG_ARM64),y) |
dwc_otg-objs += dwc_otg_fiq_stub.o |
+endif |
+ |
ifneq ($(CFI),) |
dwc_otg-objs += dwc_otg_cfi.o |
endif |
--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c |
+++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c |
@@ -74,6 +74,21 @@ void notrace _fiq_print(enum fiq_debug_l |
} |
} |
|
+ |
+#ifdef CONFIG_ARM64 |
+ |
+inline void fiq_fsm_spin_lock(fiq_lock_t *lock) |
+{ |
+ spin_lock((spinlock_t *)lock); |
+} |
+ |
+inline void fiq_fsm_spin_unlock(fiq_lock_t *lock) |
+{ |
+ spin_unlock((spinlock_t *)lock); |
+} |
+ |
+#else |
+ |
/** |
* fiq_fsm_spin_lock() - ARMv6+ bare bones spinlock |
* Must be called with local interrupts and FIQ disabled. |
@@ -122,6 +137,8 @@ inline void fiq_fsm_spin_unlock(fiq_lock |
inline void fiq_fsm_spin_unlock(fiq_lock_t *lock) { } |
#endif |
|
+#endif |
+ |
/** |
* fiq_fsm_restart_channel() - Poke channel enable bit for a split transaction |
* @channel: channel to re-enable |
--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h |
+++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h |
@@ -127,6 +127,12 @@ enum fiq_debug_level { |
FIQDBG_PORTHUB = (1 << 3), |
}; |
|
+#ifdef CONFIG_ARM64 |
+ |
+typedef spinlock_t fiq_lock_t; |
+ |
+#else |
+ |
typedef struct { |
union { |
uint32_t slock; |
@@ -137,6 +143,8 @@ typedef struct { |
}; |
} fiq_lock_t; |
|
+#endif |
+ |
struct fiq_state; |
|
extern void _fiq_print (enum fiq_debug_level dbg_lvl, volatile struct fiq_state *state, char *fmt, ...); |
@@ -355,6 +363,22 @@ struct fiq_state { |
struct fiq_channel_state channel[0]; |
}; |
|
+#ifdef CONFIG_ARM64 |
+ |
+#ifdef local_fiq_enable |
+#undef local_fiq_enable |
+#endif |
+ |
+#ifdef local_fiq_disable |
+#undef local_fiq_disable |
+#endif |
+ |
+extern void local_fiq_enable(void); |
+ |
+extern void local_fiq_disable(void); |
+ |
+#endif |
+ |
extern void fiq_fsm_spin_lock(fiq_lock_t *lock); |
|
extern void fiq_fsm_spin_unlock(fiq_lock_t *lock); |
--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c |
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c |
@@ -1021,6 +1021,10 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd |
} |
DWC_MEMSET(hcd->fiq_state, 0, (sizeof(struct fiq_state) + (sizeof(struct fiq_channel_state) * num_channels))); |
|
+#ifdef CONFIG_ARM64 |
+ spin_lock_init(&hcd->fiq_state->lock); |
+#endif |
+ |
for (i = 0; i < num_channels; i++) { |
hcd->fiq_state->channel[i].fsm = FIQ_PASSTHROUGH; |
} |
--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h |
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h |
@@ -116,7 +116,11 @@ extern int32_t dwc_otg_hcd_handle_intr(d |
/** This function is used to handle the fast interrupt |
* |
*/ |
+#ifdef CONFIG_ARM64 |
+extern void dwc_otg_hcd_handle_fiq(void); |
+#else |
extern void __attribute__ ((naked)) dwc_otg_hcd_handle_fiq(void); |
+#endif |
|
/** |
* Returns private data set by |
--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c |
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c |
@@ -36,8 +36,9 @@ |
#include "dwc_otg_regs.h" |
|
#include <linux/jiffies.h> |
+#ifdef CONFIG_ARM |
#include <asm/fiq.h> |
- |
+#endif |
|
extern bool microframe_schedule; |
|
--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c |
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c |
@@ -51,7 +51,9 @@ |
#include <linux/dma-mapping.h> |
#include <linux/version.h> |
#include <asm/io.h> |
+#ifdef CONFIG_ARM |
#include <asm/fiq.h> |
+#endif |
#include <linux/usb.h> |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) |
#include <../drivers/usb/core/hcd.h> |
@@ -71,6 +73,13 @@ |
#include "dwc_otg_driver.h" |
#include "dwc_otg_hcd.h" |
|
+#ifndef __virt_to_bus |
+#define __virt_to_bus __virt_to_phys |
+#define __bus_to_virt __phys_to_virt |
+#define __pfn_to_bus(x) __pfn_to_phys(x) |
+#define __bus_to_pfn(x) __phys_to_pfn(x) |
+#endif |
+ |
extern unsigned char _dwc_otg_fiq_stub, _dwc_otg_fiq_stub_end; |
|
/** |
@@ -393,14 +402,49 @@ static struct dwc_otg_hcd_function_ops h |
.get_b_hnp_enable = _get_b_hnp_enable, |
}; |
|
+#ifdef CONFIG_ARM64 |
+ |
+static int simfiq_irq = -1; |
+ |
+void local_fiq_enable(void) |
+{ |
+ if (simfiq_irq >= 0) |
+ enable_irq(simfiq_irq); |
+} |
+ |
+void local_fiq_disable(void) |
+{ |
+ if (simfiq_irq >= 0) |
+ disable_irq(simfiq_irq); |
+} |
+ |
+irqreturn_t fiq_irq_handler(int irq, void *dev_id) |
+{ |
+ dwc_otg_hcd_t *dwc_otg_hcd = (dwc_otg_hcd_t *)dev_id; |
+ |
+ if (fiq_fsm_enable) |
+ dwc_otg_fiq_fsm(dwc_otg_hcd->fiq_state, dwc_otg_hcd->core_if->core_params->host_channels); |
+ else |
+ dwc_otg_fiq_nop(dwc_otg_hcd->fiq_state); |
+ |
+ return IRQ_HANDLED; |
+} |
+ |
+#else |
static struct fiq_handler fh = { |
.name = "usb_fiq", |
}; |
|
+#endif |
+ |
static void hcd_init_fiq(void *cookie) |
{ |
dwc_otg_device_t *otg_dev = cookie; |
dwc_otg_hcd_t *dwc_otg_hcd = otg_dev->hcd; |
+#ifdef CONFIG_ARM64 |
+ int retval = 0; |
+ int irq; |
+#else |
struct pt_regs regs; |
int irq; |
|
@@ -428,6 +472,7 @@ static void hcd_init_fiq(void *cookie) |
|
// __show_regs(®s); |
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; |
@@ -446,6 +491,23 @@ static void hcd_init_fiq(void *cookie) |
DWC_WARN("MPHI periph has NOT been enabled"); |
#endif |
// Enable FIQ interrupt from USB peripheral |
+#ifdef CONFIG_ARM64 |
+ irq = platform_get_irq(otg_dev->os_dep.platformdev, 1); |
+ |
+ if (irq < 0) { |
+ DWC_ERROR("Can't get SIM-FIQ irq"); |
+ return; |
+ } |
+ |
+ retval = request_irq(irq, fiq_irq_handler, 0, "dwc_otg_sim-fiq", dwc_otg_hcd); |
+ |
+ if (retval < 0) { |
+ DWC_ERROR("Unable to request SIM-FIQ irq\n"); |
+ return; |
+ } |
+ |
+ simfiq_irq = irq; |
+#else |
#ifdef CONFIG_MULTI_IRQ_HANDLER |
irq = platform_get_irq(otg_dev->os_dep.platformdev, 1); |
#else |
@@ -457,6 +519,8 @@ static void hcd_init_fiq(void *cookie) |
} |
enable_fiq(irq); |
local_fiq_enable(); |
+#endif |
+ |
} |
|
/** |
@@ -519,6 +583,13 @@ int hcd_init(dwc_bus_dev_t *_dev) |
otg_dev->hcd = dwc_otg_hcd; |
otg_dev->hcd->otg_dev = otg_dev; |
|
+#ifdef CONFIG_ARM64 |
+ if (dwc_otg_hcd_init(dwc_otg_hcd, otg_dev->core_if)) |
+ goto error2; |
+ |
+ if (fiq_enable) |
+ hcd_init_fiq(otg_dev); |
+#else |
if (dwc_otg_hcd_init(dwc_otg_hcd, otg_dev->core_if)) { |
goto error2; |
} |
@@ -531,6 +602,7 @@ int hcd_init(dwc_bus_dev_t *_dev) |
smp_call_function_single(0, hcd_init_fiq, otg_dev, 1); |
} |
} |
+#endif |
|
hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd); |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) //don't support for LM(with 2.6.20.1 kernel) |
--- a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h |
+++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h |
@@ -76,8 +76,10 @@ |
|
#ifdef PLATFORM_INTERFACE |
#include <linux/platform_device.h> |
+#ifdef CONFIG_ARM |
#include <asm/mach/map.h> |
#endif |
+#endif |
|
/** The OS page size */ |
#define DWC_OS_PAGE_SIZE PAGE_SIZE |