diff --git a/drivers/usb/host/dwc_otg/Makefile b/drivers/usb/host/dwc_otg/Makefile index e7bdd12015fe..4872b8113b68 100644 --- 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_otg_pcd.o dwc_otg_pcd_intr.o 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 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c index 5f3c60aca625..3ac4c7984ce5 100644 --- 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_level dbg_lvl, volatile struct fiq_state } } + +#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. @@ -121,6 +136,8 @@ inline void fiq_fsm_spin_unlock(fiq_lock_t *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 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h index 152388f4cc2e..f51737142188 100644 --- 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, ...); @@ -358,6 +366,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); diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c index 064205a2bfdf..cdfb9a6b7c59 100644 --- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c +++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c @@ -1012,6 +1012,10 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if) } 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; } diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h b/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h index fb57db09378f..a384db5e7ac2 100644 --- 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(dwc_otg_hcd_t * dwc_otg_hcd); /** 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 diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c index 082159b64b34..6947e98b87ad 100644 --- 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 +#ifdef CONFIG_ARM #include - +#endif extern bool microframe_schedule; diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c index ac074ef165a2..028f7fd22ba9 100644 --- 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 #include #include +#ifdef CONFIG_ARM #include +#endif #include #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; /** @@ -395,14 +404,49 @@ static struct dwc_otg_hcd_function_ops hcd_fops = { .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_GENERIC_IRQ_MULTI_HANDLER irq = platform_get_irq(otg_dev->os_dep.platformdev, 1); #else @@ -462,6 +524,8 @@ static void hcd_init_fiq(void *cookie) smp_mb(); enable_fiq(irq); local_fiq_enable(); +#endif + } /** @@ -524,6 +588,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; } @@ -540,6 +611,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) diff --git a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h index 6b2c7d0c93f3..d7b700ff1782 100644 --- 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 +#ifdef CONFIG_ARM #include #endif +#endif /** The OS page size */ #define DWC_OS_PAGE_SIZE PAGE_SIZE