You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
329 lines
8.2 KiB
329 lines
8.2 KiB
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
|
|
|