aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm2708/patches-4.9/0135-ARM64-DWC_OTG-Port-dwc_otg-driver-to-ARM64.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm2708/patches-4.9/0135-ARM64-DWC_OTG-Port-dwc_otg-driver-to-ARM64.patch')
-rw-r--r--target/linux/brcm2708/patches-4.9/0135-ARM64-DWC_OTG-Port-dwc_otg-driver-to-ARM64.patch329
1 files changed, 329 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.9/0135-ARM64-DWC_OTG-Port-dwc_otg-driver-to-ARM64.patch b/target/linux/brcm2708/patches-4.9/0135-ARM64-DWC_OTG-Port-dwc_otg-driver-to-ARM64.patch
new file mode 100644
index 0000000000..4bb85d01c2
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.9/0135-ARM64-DWC_OTG-Port-dwc_otg-driver-to-ARM64.patch
@@ -0,0 +1,329 @@
+From 2f15deb5ab0fafa71f00bcf840cd01893b829555 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(&regs);
+ 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;
+@@ -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