summaryrefslogtreecommitdiff
path: root/target/linux/brcm2708/patches-3.18/0025-Add-FIQ-patch-to-dwc_otg-driver.-Enable-with-dwc_otg.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm2708/patches-3.18/0025-Add-FIQ-patch-to-dwc_otg-driver.-Enable-with-dwc_otg.patch')
-rw-r--r--target/linux/brcm2708/patches-3.18/0025-Add-FIQ-patch-to-dwc_otg-driver.-Enable-with-dwc_otg.patch3244
1 files changed, 0 insertions, 3244 deletions
diff --git a/target/linux/brcm2708/patches-3.18/0025-Add-FIQ-patch-to-dwc_otg-driver.-Enable-with-dwc_otg.patch b/target/linux/brcm2708/patches-3.18/0025-Add-FIQ-patch-to-dwc_otg-driver.-Enable-with-dwc_otg.patch
deleted file mode 100644
index 8d3464f..0000000
--- a/target/linux/brcm2708/patches-3.18/0025-Add-FIQ-patch-to-dwc_otg-driver.-Enable-with-dwc_otg.patch
+++ /dev/null
@@ -1,3244 +0,0 @@
-From a29a51d9320d44124fe13457c45663d3051a9452 Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Wed, 3 Jul 2013 00:46:42 +0100
-Subject: [PATCH 025/114] Add FIQ patch to dwc_otg driver. Enable with
- dwc_otg.fiq_fix_enable=1. Should give about 10% more ARM performance. Thanks
- to Gordon and Costas
-
-Avoid dynamic memory allocation for channel lock in USB driver. Thanks ddv2005.
-
-Add NAK holdoff scheme. Enabled by default, disable with dwc_otg.nak_holdoff_enable=0. Thanks gsh
-
-Make sure we wait for the reset to finish
-
-dwc_otg: fix bug in dwc_otg_hcd.c resulting in silent kernel
- memory corruption, escalating to OOPS under high USB load.
-
-dwc_otg: Fix unsafe access of QTD during URB enqueue
-
-In dwc_otg_hcd_urb_enqueue during qtd creation, it was possible that the
-transaction could complete almost immediately after the qtd was assigned
-to a host channel during URB enqueue, which meant the qtd pointer was no
-longer valid having been completed and removed. Usually, this resulted in
-an OOPS during URB submission. By predetermining whether transactions
-need to be queued or not, this unsafe pointer access is avoided.
-
-This bug was only evident on the Pi model A where a device was attached
-that had no periodic endpoints (e.g. USB pendrive or some wlan devices).
-
-dwc_otg: Fix incorrect URB allocation error handling
-
-If the memory allocation for a dwc_otg_urb failed, the kernel would OOPS
-because for some reason a member of the *unallocated* struct was set to
-zero. Error handling changed to fail correctly.
-
-dwc_otg: fix potential use-after-free case in interrupt handler
-
-If a transaction had previously aborted, certain interrupts are
-enabled to track error counts and reset where necessary. On IN
-endpoints the host generates an ACK interrupt near-simultaneously
-with completion of transfer. In the case where this transfer had
-previously had an error, this results in a use-after-free on
-the QTD memory space with a 1-byte length being overwritten to
-0x00.
-
-dwc_otg: add handling of SPLIT transaction data toggle errors
-
-Previously a data toggle error on packets from a USB1.1 device behind
-a TT would result in the Pi locking up as the driver never handled
-the associated interrupt. Patch adds basic retry mechanism and
-interrupt acknowledgement to cater for either a chance toggle error or
-for devices that have a broken initial toggle state (FT8U232/FT232BM).
-
-dwc_otg: implement tasklet for returning URBs to usbcore hcd layer
-
-The dwc_otg driver interrupt handler for transfer completion will spend
-a very long time with interrupts disabled when a URB is completed -
-this is because usb_hcd_giveback_urb is called from within the handler
-which for a USB device driver with complicated processing (e.g. webcam)
-will take an exorbitant amount of time to complete. This results in
-missed completion interrupts for other USB packets which lead to them
-being dropped due to microframe overruns.
-
-This patch splits returning the URB to the usb hcd layer into a
-high-priority tasklet. This will have most benefit for isochronous IN
-transfers but will also have incidental benefit where multiple periodic
-devices are active at once.
-
-dwc_otg: fix NAK holdoff and allow on split transactions only
-
-This corrects a bug where if a single active non-periodic endpoint
-had at least one transaction in its qh, on frnum == MAX_FRNUM the qh
-would get skipped and never get queued again. This would result in
-a silent device until error detection (automatic or otherwise) would
-either reset the device or flush and requeue the URBs.
-
-Additionally the NAK holdoff was enabled for all transactions - this
-would potentially stall a HS endpoint for 1ms if a previous error state
-enabled this interrupt and the next response was a NAK. Fix so that
-only split transactions get held off.
-
-dwc_otg: Call usb_hcd_unlink_urb_from_ep with lock held in completion handler
-
-usb_hcd_unlink_urb_from_ep must be called with the HCD lock held. Calling it
-asynchronously in the tasklet was not safe (regression in
-c4564d4a1a0a9b10d4419e48239f5d99e88d2667).
-
-This change unlinks it from the endpoint prior to queueing it for handling in
-the tasklet, and also adds a check to ensure the urb is OK to be unlinked
-before doing so.
-
-NULL pointer dereference kernel oopses had been observed in usb_hcd_giveback_urb
-when a USB device was unplugged/replugged during data transfer. This effect
-was reproduced using automated USB port power control, hundreds of replug
-events were performed during active transfers to confirm that the problem was
-eliminated.
-
-USB fix using a FIQ to implement split transactions
-
-This commit adds a FIQ implementaion that schedules
-the split transactions using a FIQ so we don't get
-held off by the interrupt latency of Linux
-
-dwc_otg: fix device attributes and avoid kernel warnings on boot
-
-dcw_otg: avoid logging function that can cause panics
-
-See: https://github.com/raspberrypi/firmware/issues/21
-Thanks to cleverca22 for fix
-
-dwc_otg: mask correct interrupts after transaction error recovery
-
-The dwc_otg driver will unmask certain interrupts on a transaction
-that previously halted in the error state in order to reset the
-QTD error count. The various fine-grained interrupt handlers do not
-consider that other interrupts besides themselves were unmasked.
-
-By disabling the two other interrupts only ever enabled in DMA mode
-for this purpose, we can avoid unnecessary function calls in the
-IRQ handler. This will also prevent an unneccesary FIQ interrupt
-from being generated if the FIQ is enabled.
-
-dwc_otg: fiq: prevent FIQ thrash and incorrect state passing to IRQ
-
-In the case of a transaction to a device that had previously aborted
-due to an error, several interrupts are enabled to reset the error
-count when a device responds. This has the side-effect of making the
-FIQ thrash because the hardware will generate multiple instances of
-a NAK on an IN bulk/interrupt endpoint and multiple instances of ACK
-on an OUT bulk/interrupt endpoint. Make the FIQ mask and clear the
-associated interrupts.
-
-Additionally, on non-split transactions make sure that only unmasked
-interrupts are cleared. This caused a hard-to-trigger but serious
-race condition when you had the combination of an endpoint awaiting
-error recovery and a transaction completed on an endpoint - due to
-the sequencing and timing of interrupts generated by the dwc_otg core,
-it was possible to confuse the IRQ handler.
-
-Fix function tracing
-
-dwc_otg: whitespace cleanup in dwc_otg_urb_enqueue
-
-dwc_otg: prevent OOPSes during device disconnects
-
-The dwc_otg_urb_enqueue function is thread-unsafe. In particular the
-access of urb->hcpriv, usb_hcd_link_urb_to_ep, dwc_otg_urb->qtd and
-friends does not occur within a critical section and so if a device
-was unplugged during activity there was a high chance that the
-usbcore hub_thread would try to disable the endpoint with partially-
-formed entries in the URB queue. This would result in BUG() or null
-pointer dereferences.
-
-Fix so that access of urb->hcpriv, enqueuing to the hardware and
-adding to usbcore endpoint URB lists is contained within a single
-critical section.
-
-dwc_otg: prevent BUG() in TT allocation if hub address is > 16
-
-A fixed-size array is used to track TT allocation. This was
-previously set to 16 which caused a crash because
-dwc_otg_hcd_allocate_port would read past the end of the array.
-
-This was hit if a hub was plugged in which enumerated as addr > 16,
-due to previous device resets or unplugs.
-
-Also add #ifdef FIQ_DEBUG around hcd->hub_port_alloc[], which grows
-to a large size if 128 hub addresses are supported. This field is
-for debug only for tracking which frame an allocate happened in.
-
-dwc_otg: make channel halts with unknown state less damaging
-
-If the IRQ received a channel halt interrupt through the FIQ
-with no other bits set, the IRQ would not release the host
-channel and never complete the URB.
-
-Add catchall handling to treat as a transaction error and retry.
-
-dwc_otg: fiq_split: use TTs with more granularity
-
-This fixes certain issues with split transaction scheduling.
-
-- Isochronous multi-packet OUT transactions now hog the TT until
- they are completed - this prevents hubs aborting transactions
- if they get a periodic start-split out-of-order
-- Don't perform TT allocation on non-periodic endpoints - this
- allows simultaneous use of the TT's bulk/control and periodic
- transaction buffers
-
-This commit will mainly affect USB audio playback.
-
-dwc_otg: fix potential sleep while atomic during urb enqueue
-
-Fixes a regression introduced with eb1b482a. Kmalloc called from
-dwc_otg_hcd_qtd_add / dwc_otg_hcd_qtd_create did not always have
-the GPF_ATOMIC flag set. Force this flag when inside the larger
-critical section.
-
-dwc_otg: make fiq_split_enable imply fiq_fix_enable
-
-Failing to set up the FIQ correctly would result in
-"IRQ 32: nobody cared" errors in dmesg.
-
-dwc_otg: prevent crashes on host port disconnects
-
-Fix several issues resulting in crashes or inconsistent state
-if a Model A root port was disconnected.
-
-- Clean up queue heads properly in kill_urbs_in_qh_list by
- removing the empty QHs from the schedule lists
-- Set the halt status properly to prevent IRQ handlers from
- using freed memory
-- Add fiq_split related cleanup for saved registers
-- Make microframe scheduling reclaim host channels if
- active during a disconnect
-- Abort URBs with -ESHUTDOWN status response, informing
- device drivers so they respond in a more correct fashion
- and don't try to resubmit URBs
-- Prevent IRQ handlers from attempting to handle channel
- interrupts if the associated URB was dequeued (and the
- driver state was cleared)
-
-dwc_otg: prevent leaking URBs during enqueue
-
-A dwc_otg_urb would get leaked if the HCD enqueue function
-failed for any reason. Free the URB at the appropriate points.
-
-dwc_otg: Enable NAK holdoff for control split transactions
-
-Certain low-speed devices take a very long time to complete a
-data or status stage of a control transaction, producing NAK
-responses until they complete internal processing - the USB2.0
-spec limit is up to 500mS. This causes the same type of interrupt
-storm as seen with USB-serial dongles prior to c8edb238.
-
-In certain circumstances, usually while booting, this interrupt
-storm could cause SD card timeouts.
-
-dwc_otg: Fix for occasional lockup on boot when doing a USB reset
-
-dwc_otg: Don't issue traffic to LS devices in FS mode
-
-Issuing low-speed packets when the root port is in full-speed mode
-causes the root port to stop responding. Explicitly fail when
-enqueuing URBs to a LS endpoint on a FS bus.
-
-Fix ARM architecture issue with local_irq_restore()
-
-If local_fiq_enable() is called before a local_irq_restore(flags) where
-the flags variable has the F bit set, the FIQ will be erroneously disabled.
-
-Fixup arch_local_irq_restore to avoid trampling the F bit in CPSR.
-
-Also fix some of the hacks previously implemented for previous dwc_otg
-incarnations.
----
- arch/arm/Kconfig | 1 +
- arch/arm/include/asm/irqflags.h | 16 +-
- arch/arm/kernel/fiqasm.S | 4 +
- arch/arm/mach-bcm2708/armctrl.c | 19 +-
- arch/arm/mach-bcm2708/bcm2708.c | 29 +-
- arch/arm/mach-bcm2708/include/mach/irqs.h | 153 ++---
- .../usb/host/dwc_common_port/dwc_common_linux.c | 11 +
- drivers/usb/host/dwc_common_port/dwc_list.h | 14 +-
- drivers/usb/host/dwc_common_port/dwc_os.h | 2 +
- drivers/usb/host/dwc_otg/Makefile | 1 +
- drivers/usb/host/dwc_otg/dwc_otg_attr.c | 14 +-
- drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c | 47 +-
- drivers/usb/host/dwc_otg/dwc_otg_dbg.h | 1 +
- drivers/usb/host/dwc_otg/dwc_otg_driver.c | 52 +-
- drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 303 +++++++--
- drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 37 +-
- drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c | 3 +-
- drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h | 5 +
- drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 705 ++++++++++++++++++++-
- drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 159 +++--
- drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 53 +-
- drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c | 113 ++++
- drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h | 48 ++
- drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 3 +
- drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c | 2 +-
- 25 files changed, 1544 insertions(+), 251 deletions(-)
- create mode 100755 drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c
- create mode 100755 drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h
-
---- a/arch/arm/Kconfig
-+++ b/arch/arm/Kconfig
-@@ -395,6 +395,7 @@ config ARCH_BCM2708
- select ARM_ERRATA_411920
- select MACH_BCM2708
- select VC4
-+ select FIQ
- help
- This enables support for Broadcom BCM2708 boards.
-
---- a/arch/arm/include/asm/irqflags.h
-+++ b/arch/arm/include/asm/irqflags.h
-@@ -145,12 +145,22 @@ static inline unsigned long arch_local_s
- }
-
- /*
-- * restore saved IRQ & FIQ state
-+ * restore saved IRQ state
- */
- static inline void arch_local_irq_restore(unsigned long flags)
- {
-- asm volatile(
-- " msr " IRQMASK_REG_NAME_W ", %0 @ local_irq_restore"
-+ unsigned long temp = 0;
-+ flags &= ~(1 << 6);
-+ asm volatile (
-+ " mrs %0, cpsr"
-+ : "=r" (temp)
-+ :
-+ : "memory", "cc");
-+ /* Preserve FIQ bit */
-+ temp &= (1 << 6);
-+ flags = flags | temp;
-+ asm volatile (
-+ " msr cpsr_c, %0 @ local_irq_restore"
- :
- : "r" (flags)
- : "memory", "cc");
---- a/arch/arm/kernel/fiqasm.S
-+++ b/arch/arm/kernel/fiqasm.S
-@@ -47,3 +47,7 @@ ENTRY(__get_fiq_regs)
- mov r0, r0 @ avoid hazard prior to ARMv4
- ret lr
- ENDPROC(__get_fiq_regs)
-+
-+ENTRY(__FIQ_Branch)
-+ mov pc, r8
-+ENDPROC(__FIQ_Branch)
---- a/arch/arm/mach-bcm2708/armctrl.c
-+++ b/arch/arm/mach-bcm2708/armctrl.c
-@@ -52,8 +52,12 @@ static void armctrl_mask_irq(struct irq_
- 0
- };
-
-- unsigned int data = (unsigned int)irq_get_chip_data(d->irq);
-- writel(1 << (data & 0x1f), __io_address(disables[(data >> 5) & 0x3]));
-+ if (d->irq >= FIQ_START) {
-+ writel(0, __io_address(ARM_IRQ_FAST));
-+ } else {
-+ unsigned int data = (unsigned int)irq_get_chip_data(d->irq);
-+ writel(1 << (data & 0x1f), __io_address(disables[(data >> 5) & 0x3]));
-+ }
- }
-
- static void armctrl_unmask_irq(struct irq_data *d)
-@@ -65,8 +69,14 @@ static void armctrl_unmask_irq(struct ir
- 0
- };
-
-- unsigned int data = (unsigned int)irq_get_chip_data(d->irq);
-- writel(1 << (data & 0x1f), __io_address(enables[(data >> 5) & 0x3]));
-+ if (d->irq >= FIQ_START) {
-+ unsigned int data =
-+ (unsigned int)irq_get_chip_data(d->irq) - FIQ_START;
-+ writel(0x80 | data, __io_address(ARM_IRQ_FAST));
-+ } else {
-+ unsigned int data = (unsigned int)irq_get_chip_data(d->irq);
-+ writel(1 << (data & 0x1f), __io_address(enables[(data >> 5) & 0x3]));
-+ }
- }
-
- #if defined(CONFIG_PM)
-@@ -204,5 +214,6 @@ int __init armctrl_init(void __iomem * b
- }
-
- armctrl_pm_register(base, irq_start, resume_sources);
-+ init_FIQ(FIQ_START);
- return 0;
- }
---- a/arch/arm/mach-bcm2708/bcm2708.c
-+++ b/arch/arm/mach-bcm2708/bcm2708.c
-@@ -321,12 +321,32 @@ static struct resource bcm2708_usb_resou
- .flags = IORESOURCE_MEM,
- },
- [1] = {
-- .start = IRQ_USB,
-- .end = IRQ_USB,
-+ .start = MPHI_BASE,
-+ .end = MPHI_BASE + SZ_4K - 1,
-+ .flags = IORESOURCE_MEM,
-+ },
-+ [2] = {
-+ .start = IRQ_HOSTPORT,
-+ .end = IRQ_HOSTPORT,
- .flags = IORESOURCE_IRQ,
- },
- };
-
-+bool fiq_fix_enable = true;
-+
-+static struct resource bcm2708_usb_resources_no_fiq_fix[] = {
-+ [0] = {
-+ .start = USB_BASE,
-+ .end = USB_BASE + SZ_128K - 1,
-+ .flags = IORESOURCE_MEM,
-+ },
-+ [1] = {
-+ .start = IRQ_USB,
-+ .end = IRQ_USB,
-+ .flags = IORESOURCE_IRQ,
-+ },
-+};
-+
- static u64 usb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
-
- static struct platform_device bcm2708_usb_device = {
-@@ -681,6 +701,11 @@ void __init bcm2708_init(void)
- #endif
- bcm_register_device(&bcm2708_systemtimer_device);
- bcm_register_device(&bcm2708_fb_device);
-+ if (!fiq_fix_enable)
-+ {
-+ bcm2708_usb_device.resource = bcm2708_usb_resources_no_fiq_fix;
-+ bcm2708_usb_device.num_resources = ARRAY_SIZE(bcm2708_usb_resources_no_fiq_fix);
-+ }
- bcm_register_device(&bcm2708_usb_device);
- bcm_register_device(&bcm2708_uart1_device);
- bcm_register_device(&bcm2708_powerman_device);
---- a/arch/arm/mach-bcm2708/include/mach/irqs.h
-+++ b/arch/arm/mach-bcm2708/include/mach/irqs.h
-@@ -106,87 +106,90 @@
- #define IRQ_PENDING1 (IRQ_ARMCTRL_START + INTERRUPT_PENDING1)
- #define IRQ_PENDING2 (IRQ_ARMCTRL_START + INTERRUPT_PENDING2)
-
-+#define FIQ_START HARD_IRQS
-+
- /*
- * FIQ interrupts definitions are the same as the INT definitions.
- */
--#define FIQ_TIMER0 INT_TIMER0
--#define FIQ_TIMER1 INT_TIMER1
--#define FIQ_TIMER2 INT_TIMER2
--#define FIQ_TIMER3 INT_TIMER3
--#define FIQ_CODEC0 INT_CODEC0
--#define FIQ_CODEC1 INT_CODEC1
--#define FIQ_CODEC2 INT_CODEC2
--#define FIQ_JPEG INT_JPEG
--#define FIQ_ISP INT_ISP
--#define FIQ_USB INT_USB
--#define FIQ_3D INT_3D
--#define FIQ_TRANSPOSER INT_TRANSPOSER
--#define FIQ_MULTICORESYNC0 INT_MULTICORESYNC0
--#define FIQ_MULTICORESYNC1 INT_MULTICORESYNC1
--#define FIQ_MULTICORESYNC2 INT_MULTICORESYNC2
--#define FIQ_MULTICORESYNC3 INT_MULTICORESYNC3
--#define FIQ_DMA0 INT_DMA0
--#define FIQ_DMA1 INT_DMA1
--#define FIQ_DMA2 INT_DMA2
--#define FIQ_DMA3 INT_DMA3
--#define FIQ_DMA4 INT_DMA4
--#define FIQ_DMA5 INT_DMA5
--#define FIQ_DMA6 INT_DMA6
--#define FIQ_DMA7 INT_DMA7
--#define FIQ_DMA8 INT_DMA8
--#define FIQ_DMA9 INT_DMA9
--#define FIQ_DMA10 INT_DMA10
--#define FIQ_DMA11 INT_DMA11
--#define FIQ_DMA12 INT_DMA12
--#define FIQ_AUX INT_AUX
--#define FIQ_ARM INT_ARM
--#define FIQ_VPUDMA INT_VPUDMA
--#define FIQ_HOSTPORT INT_HOSTPORT
--#define FIQ_VIDEOSCALER INT_VIDEOSCALER
--#define FIQ_CCP2TX INT_CCP2TX
--#define FIQ_SDC INT_SDC
--#define FIQ_DSI0 INT_DSI0
--#define FIQ_AVE INT_AVE
--#define FIQ_CAM0 INT_CAM0
--#define FIQ_CAM1 INT_CAM1
--#define FIQ_HDMI0 INT_HDMI0
--#define FIQ_HDMI1 INT_HDMI1
--#define FIQ_PIXELVALVE1 INT_PIXELVALVE1
--#define FIQ_I2CSPISLV INT_I2CSPISLV
--#define FIQ_DSI1 INT_DSI1
--#define FIQ_PWA0 INT_PWA0
--#define FIQ_PWA1 INT_PWA1
--#define FIQ_CPR INT_CPR
--#define FIQ_SMI INT_SMI
--#define FIQ_GPIO0 INT_GPIO0
--#define FIQ_GPIO1 INT_GPIO1
--#define FIQ_GPIO2 INT_GPIO2
--#define FIQ_GPIO3 INT_GPIO3
--#define FIQ_I2C INT_I2C
--#define FIQ_SPI INT_SPI
--#define FIQ_I2SPCM INT_I2SPCM
--#define FIQ_SDIO INT_SDIO
--#define FIQ_UART INT_UART
--#define FIQ_SLIMBUS INT_SLIMBUS
--#define FIQ_VEC INT_VEC
--#define FIQ_CPG INT_CPG
--#define FIQ_RNG INT_RNG
--#define FIQ_ARASANSDIO INT_ARASANSDIO
--#define FIQ_AVSPMON INT_AVSPMON
-+#define FIQ_TIMER0 (FIQ_START+INTERRUPT_TIMER0)
-+#define FIQ_TIMER1 (FIQ_START+INTERRUPT_TIMER1)
-+#define FIQ_TIMER2 (FIQ_START+INTERRUPT_TIMER2)
-+#define FIQ_TIMER3 (FIQ_START+INTERRUPT_TIMER3)
-+#define FIQ_CODEC0 (FIQ_START+INTERRUPT_CODEC0)
-+#define FIQ_CODEC1 (FIQ_START+INTERRUPT_CODEC1)
-+#define FIQ_CODEC2 (FIQ_START+INTERRUPT_CODEC2)
-+#define FIQ_JPEG (FIQ_START+INTERRUPT_JPEG)
-+#define FIQ_ISP (FIQ_START+INTERRUPT_ISP)
-+#define FIQ_USB (FIQ_START+INTERRUPT_USB)
-+#define FIQ_3D (FIQ_START+INTERRUPT_3D)
-+#define FIQ_TRANSPOSER (FIQ_START+INTERRUPT_TRANSPOSER)
-+#define FIQ_MULTICORESYNC0 (FIQ_START+INTERRUPT_MULTICORESYNC0)
-+#define FIQ_MULTICORESYNC1 (FIQ_START+INTERRUPT_MULTICORESYNC1)
-+#define FIQ_MULTICORESYNC2 (FIQ_START+INTERRUPT_MULTICORESYNC2)
-+#define FIQ_MULTICORESYNC3 (FIQ_START+INTERRUPT_MULTICORESYNC3)
-+#define FIQ_DMA0 (FIQ_START+INTERRUPT_DMA0)
-+#define FIQ_DMA1 (FIQ_START+INTERRUPT_DMA1)
-+#define FIQ_DMA2 (FIQ_START+INTERRUPT_DMA2)
-+#define FIQ_DMA3 (FIQ_START+INTERRUPT_DMA3)
-+#define FIQ_DMA4 (FIQ_START+INTERRUPT_DMA4)
-+#define FIQ_DMA5 (FIQ_START+INTERRUPT_DMA5)
-+#define FIQ_DMA6 (FIQ_START+INTERRUPT_DMA6)
-+#define FIQ_DMA7 (FIQ_START+INTERRUPT_DMA7)
-+#define FIQ_DMA8 (FIQ_START+INTERRUPT_DMA8)
-+#define FIQ_DMA9 (FIQ_START+INTERRUPT_DMA9)
-+#define FIQ_DMA10 (FIQ_START+INTERRUPT_DMA10)
-+#define FIQ_DMA11 (FIQ_START+INTERRUPT_DMA11)
-+#define FIQ_DMA12 (FIQ_START+INTERRUPT_DMA12)
-+#define FIQ_AUX (FIQ_START+INTERRUPT_AUX)
-+#define FIQ_ARM (FIQ_START+INTERRUPT_ARM)
-+#define FIQ_VPUDMA (FIQ_START+INTERRUPT_VPUDMA)
-+#define FIQ_HOSTPORT (FIQ_START+INTERRUPT_HOSTPORT)
-+#define FIQ_VIDEOSCALER (FIQ_START+INTERRUPT_VIDEOSCALER)
-+#define FIQ_CCP2TX (FIQ_START+INTERRUPT_CCP2TX)
-+#define FIQ_SDC (FIQ_START+INTERRUPT_SDC)
-+#define FIQ_DSI0 (FIQ_START+INTERRUPT_DSI0)
-+#define FIQ_AVE (FIQ_START+INTERRUPT_AVE)
-+#define FIQ_CAM0 (FIQ_START+INTERRUPT_CAM0)
-+#define FIQ_CAM1 (FIQ_START+INTERRUPT_CAM1)
-+#define FIQ_HDMI0 (FIQ_START+INTERRUPT_HDMI0)
-+#define FIQ_HDMI1 (FIQ_START+INTERRUPT_HDMI1)
-+#define FIQ_PIXELVALVE1 (FIQ_START+INTERRUPT_PIXELVALVE1)
-+#define FIQ_I2CSPISLV (FIQ_START+INTERRUPT_I2CSPISLV)
-+#define FIQ_DSI1 (FIQ_START+INTERRUPT_DSI1)
-+#define FIQ_PWA0 (FIQ_START+INTERRUPT_PWA0)
-+#define FIQ_PWA1 (FIQ_START+INTERRUPT_PWA1)
-+#define FIQ_CPR (FIQ_START+INTERRUPT_CPR)
-+#define FIQ_SMI (FIQ_START+INTERRUPT_SMI)
-+#define FIQ_GPIO0 (FIQ_START+INTERRUPT_GPIO0)
-+#define FIQ_GPIO1 (FIQ_START+INTERRUPT_GPIO1)
-+#define FIQ_GPIO2 (FIQ_START+INTERRUPT_GPIO2)
-+#define FIQ_GPIO3 (FIQ_START+INTERRUPT_GPIO3)
-+#define FIQ_I2C (FIQ_START+INTERRUPT_I2C)
-+#define FIQ_SPI (FIQ_START+INTERRUPT_SPI)
-+#define FIQ_I2SPCM (FIQ_START+INTERRUPT_I2SPCM)
-+#define FIQ_SDIO (FIQ_START+INTERRUPT_SDIO)
-+#define FIQ_UART (FIQ_START+INTERRUPT_UART)
-+#define FIQ_SLIMBUS (FIQ_START+INTERRUPT_SLIMBUS)
-+#define FIQ_VEC (FIQ_START+INTERRUPT_VEC)
-+#define FIQ_CPG (FIQ_START+INTERRUPT_CPG)
-+#define FIQ_RNG (FIQ_START+INTERRUPT_RNG)
-+#define FIQ_ARASANSDIO (FIQ_START+INTERRUPT_ARASANSDIO)
-+#define FIQ_AVSPMON (FIQ_START+INTERRUPT_AVSPMON)
-
--#define FIQ_ARM_TIMER INT_ARM_TIMER
--#define FIQ_ARM_MAILBOX INT_ARM_MAILBOX
--#define FIQ_ARM_DOORBELL_0 INT_ARM_DOORBELL_0
--#define FIQ_ARM_DOORBELL_1 INT_ARM_DOORBELL_1
--#define FIQ_VPU0_HALTED INT_VPU0_HALTED
--#define FIQ_VPU1_HALTED INT_VPU1_HALTED
--#define FIQ_ILLEGAL_TYPE0 INT_ILLEGAL_TYPE0
--#define FIQ_ILLEGAL_TYPE1 INT_ILLEGAL_TYPE1
--#define FIQ_PENDING1 INT_PENDING1
--#define FIQ_PENDING2 INT_PENDING2
-+#define FIQ_ARM_TIMER (FIQ_START+INTERRUPT_ARM_TIMER)
-+#define FIQ_ARM_MAILBOX (FIQ_START+INTERRUPT_ARM_MAILBOX)
-+#define FIQ_ARM_DOORBELL_0 (FIQ_START+INTERRUPT_ARM_DOORBELL_0)
-+#define FIQ_ARM_DOORBELL_1 (FIQ_START+INTERRUPT_ARM_DOORBELL_1)
-+#define FIQ_VPU0_HALTED (FIQ_START+INTERRUPT_VPU0_HALTED)
-+#define FIQ_VPU1_HALTED (FIQ_START+INTERRUPT_VPU1_HALTED)
-+#define FIQ_ILLEGAL_TYPE0 (FIQ_START+INTERRUPT_ILLEGAL_TYPE0)
-+#define FIQ_ILLEGAL_TYPE1 (FIQ_START+INTERRUPT_ILLEGAL_TYPE1)
-+#define FIQ_PENDING1 (FIQ_START+INTERRUPT_PENDING1)
-+#define FIQ_PENDING2 (FIQ_START+INTERRUPT_PENDING2)
-
- #define HARD_IRQS (64 + 21)
--#define GPIO_IRQ_START (HARD_IRQS)
-+#define FIQ_IRQS (64 + 21)
-+#define GPIO_IRQ_START (HARD_IRQS + FIQ_IRQS)
- #define GPIO_IRQS (32*5)
- #define SPARE_ALLOC_IRQS 64
- #define BCM2708_ALLOC_IRQS (HARD_IRQS+FIQ_IRQS+GPIO_IRQS+SPARE_ALLOC_IRQS)
---- a/drivers/usb/host/dwc_common_port/dwc_common_linux.c
-+++ b/drivers/usb/host/dwc_common_port/dwc_common_linux.c
-@@ -580,7 +580,13 @@ void DWC_WRITE_REG64(uint64_t volatile *
-
- void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask)
- {
-+ unsigned long flags;
-+
-+ local_irq_save(flags);
-+ local_fiq_disable();
- writel((readl(reg) & ~clear_mask) | set_mask, reg);
-+ local_fiq_enable();
-+ local_irq_restore(flags);
- }
-
- #if 0
-@@ -995,6 +1001,11 @@ void DWC_TASK_SCHEDULE(dwc_tasklet_t *ta
- tasklet_schedule(&task->t);
- }
-
-+void DWC_TASK_HI_SCHEDULE(dwc_tasklet_t *task)
-+{
-+ tasklet_hi_schedule(&task->t);
-+}
-+
-
- /* workqueues
- - run in process context (can sleep)
---- a/drivers/usb/host/dwc_common_port/dwc_list.h
-+++ b/drivers/usb/host/dwc_common_port/dwc_list.h
-@@ -384,17 +384,17 @@ struct { \
- #define DWC_TAILQ_PREV(elm, headname, field) \
- (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
- #define DWC_TAILQ_EMPTY(head) \
-- (TAILQ_FIRST(head) == TAILQ_END(head))
-+ (DWC_TAILQ_FIRST(head) == DWC_TAILQ_END(head))
-
- #define DWC_TAILQ_FOREACH(var, head, field) \
-- for((var) = TAILQ_FIRST(head); \
-- (var) != TAILQ_END(head); \
-- (var) = TAILQ_NEXT(var, field))
-+ for ((var) = DWC_TAILQ_FIRST(head); \
-+ (var) != DWC_TAILQ_END(head); \
-+ (var) = DWC_TAILQ_NEXT(var, field))
-
- #define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field) \
-- for((var) = TAILQ_LAST(head, headname); \
-- (var) != TAILQ_END(head); \
-- (var) = TAILQ_PREV(var, headname, field))
-+ for ((var) = DWC_TAILQ_LAST(head, headname); \
-+ (var) != DWC_TAILQ_END(head); \
-+ (var) = DWC_TAILQ_PREV(var, headname, field))
-
- /*
- * Tail queue functions.
---- a/drivers/usb/host/dwc_common_port/dwc_os.h
-+++ b/drivers/usb/host/dwc_common_port/dwc_os.h
-@@ -982,6 +982,8 @@ extern void DWC_TASK_FREE(dwc_tasklet_t
- extern void DWC_TASK_SCHEDULE(dwc_tasklet_t *task);
- #define dwc_task_schedule DWC_TASK_SCHEDULE
-
-+extern void DWC_TASK_HI_SCHEDULE(dwc_tasklet_t *task);
-+#define dwc_task_hi_schedule DWC_TASK_HI_SCHEDULE
-
- /** @name Timer
- *
---- a/drivers/usb/host/dwc_otg/Makefile
-+++ b/drivers/usb/host/dwc_otg/Makefile
-@@ -36,6 +36,7 @@ dwc_otg-objs += dwc_otg_cil.o dwc_otg_ci
- 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_mphi_fix.o
- ifneq ($(CFI),)
- dwc_otg-objs += dwc_otg_cfi.o
- endif
---- a/drivers/usb/host/dwc_otg/dwc_otg_attr.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.c
-@@ -909,7 +909,7 @@ static ssize_t regdump_show(struct devic
- return sprintf(buf, "Register Dump\n");
- }
-
--DEVICE_ATTR(regdump, S_IRUGO | S_IWUSR, regdump_show, 0);
-+DEVICE_ATTR(regdump, S_IRUGO, regdump_show, 0);
-
- /**
- * Dump global registers and either host or device registers (depending on the
-@@ -920,12 +920,12 @@ static ssize_t spramdump_show(struct dev
- {
- dwc_otg_device_t *otg_dev = dwc_otg_drvdev(_dev);
-
-- dwc_otg_dump_spram(otg_dev->core_if);
-+ //dwc_otg_dump_spram(otg_dev->core_if);
-
- return sprintf(buf, "SPRAM Dump\n");
- }
-
--DEVICE_ATTR(spramdump, S_IRUGO | S_IWUSR, spramdump_show, 0);
-+DEVICE_ATTR(spramdump, S_IRUGO, spramdump_show, 0);
-
- /**
- * Dump the current hcd state.
-@@ -940,7 +940,7 @@ static ssize_t hcddump_show(struct devic
- return sprintf(buf, "HCD Dump\n");
- }
-
--DEVICE_ATTR(hcddump, S_IRUGO | S_IWUSR, hcddump_show, 0);
-+DEVICE_ATTR(hcddump, S_IRUGO, hcddump_show, 0);
-
- /**
- * Dump the average frame remaining at SOF. This can be used to
-@@ -958,7 +958,7 @@ static ssize_t hcd_frrem_show(struct dev
- return sprintf(buf, "HCD Dump Frame Remaining\n");
- }
-
--DEVICE_ATTR(hcd_frrem, S_IRUGO | S_IWUSR, hcd_frrem_show, 0);
-+DEVICE_ATTR(hcd_frrem, S_IRUGO, hcd_frrem_show, 0);
-
- /**
- * Displays the time required to read the GNPTXFSIZ register many times (the
-@@ -986,7 +986,7 @@ static ssize_t rd_reg_test_show(struct d
- RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
- }
-
--DEVICE_ATTR(rd_reg_test, S_IRUGO | S_IWUSR, rd_reg_test_show, 0);
-+DEVICE_ATTR(rd_reg_test, S_IRUGO, rd_reg_test_show, 0);
-
- /**
- * Displays the time required to write the GNPTXFSIZ register many times (the
-@@ -1014,7 +1014,7 @@ static ssize_t wr_reg_test_show(struct d
- RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
- }
-
--DEVICE_ATTR(wr_reg_test, S_IRUGO | S_IWUSR, wr_reg_test_show, 0);
-+DEVICE_ATTR(wr_reg_test, S_IRUGO, wr_reg_test_show, 0);
-
- #ifdef CONFIG_USB_DWC_OTG_LPM
-
---- a/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
-@@ -45,6 +45,7 @@
- #include "dwc_otg_driver.h"
- #include "dwc_otg_pcd.h"
- #include "dwc_otg_hcd.h"
-+#include "dwc_otg_mphi_fix.h"
-
- #ifdef DEBUG
- inline const char *op_state_str(dwc_otg_core_if_t * core_if)
-@@ -1318,7 +1319,7 @@ static int32_t dwc_otg_handle_lpm_intr(d
- /**
- * This function returns the Core Interrupt register.
- */
--static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if)
-+static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if, gintmsk_data_t *reenable_gintmsk)
- {
- gahbcfg_data_t gahbcfg = {.d32 = 0 };
- gintsts_data_t gintsts;
-@@ -1335,26 +1336,45 @@ static inline uint32_t dwc_otg_read_comm
- gintmsk_common.b.lpmtranrcvd = 1;
- #endif
- gintmsk_common.b.restoredone = 1;
-- /** @todo: The port interrupt occurs while in device
-- * mode. Added code to CIL to clear the interrupt for now!
-- */
-- gintmsk_common.b.portintr = 1;
--
-+ if(dwc_otg_is_device_mode(core_if))
-+ {
-+ /** @todo: The port interrupt occurs while in device
-+ * mode. Added code to CIL to clear the interrupt for now!
-+ */
-+ gintmsk_common.b.portintr = 1;
-+ }
- gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
- gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
-+ {
-+ unsigned long flags;
-+
-+ // Re-enable the saved interrupts
-+ local_irq_save(flags);
-+ local_fiq_disable();
-+ gintmsk.d32 |= gintmsk_common.d32;
-+ gintsts_saved.d32 &= ~gintmsk_common.d32;
-+ reenable_gintmsk->d32 = gintmsk.d32;
-+ local_irq_restore(flags);
-+ }
-+
- gahbcfg.d32 = DWC_READ_REG32(&core_if->core_global_regs->gahbcfg);
-
- #ifdef DEBUG
- /* if any common interrupts set */
- if (gintsts.d32 & gintmsk_common.d32) {
-- DWC_DEBUGPL(DBG_ANY, "gintsts=%08x gintmsk=%08x\n",
-+ DWC_DEBUGPL(DBG_ANY, "common_intr: gintsts=%08x gintmsk=%08x\n",
- gintsts.d32, gintmsk.d32);
- }
- #endif
-- if (gahbcfg.b.glblintrmsk)
-+ if (!fiq_fix_enable){
-+ if (gahbcfg.b.glblintrmsk)
-+ return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32);
-+ else
-+ return 0;
-+ }
-+ else {
- return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32);
-- else
-- return 0;
-+ }
-
- }
-
-@@ -1386,6 +1406,7 @@ int32_t dwc_otg_handle_common_intr(void
- {
- int retval = 0;
- gintsts_data_t gintsts;
-+ gintmsk_data_t reenable_gintmsk;
- gpwrdn_data_t gpwrdn = {.d32 = 0 };
- dwc_otg_device_t *otg_dev = dev;
- dwc_otg_core_if_t *core_if = otg_dev->core_if;
-@@ -1407,7 +1428,7 @@ int32_t dwc_otg_handle_common_intr(void
- }
-
- if (core_if->hibernation_suspend <= 0) {
-- gintsts.d32 = dwc_otg_read_common_intr(core_if);
-+ gintsts.d32 = dwc_otg_read_common_intr(core_if, &reenable_gintmsk);
-
- if (gintsts.b.modemismatch) {
- retval |= dwc_otg_handle_mode_mismatch_intr(core_if);
-@@ -1504,8 +1525,12 @@ int32_t dwc_otg_handle_common_intr(void
- gintsts.b.portintr = 1;
- DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32);
- retval |= 1;
-+ reenable_gintmsk.b.portintr = 1;
-
- }
-+
-+ DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, reenable_gintmsk.d32);
-+
- } else {
- DWC_DEBUGPL(DBG_ANY, "gpwrdn=%08x\n", gpwrdn.d32);
-
---- a/drivers/usb/host/dwc_otg/dwc_otg_dbg.h
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_dbg.h
-@@ -49,6 +49,7 @@ static inline uint32_t SET_DEBUG_LEVEL(c
- return old;
- }
-
-+#define DBG_USER (0x1)
- /** When debug level has the DBG_CIL bit set, display CIL Debug messages. */
- #define DBG_CIL (0x2)
- /** When debug level has the DBG_CILV bit set, display CIL Verbose debug
---- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c
-@@ -64,6 +64,8 @@ bool microframe_schedule=true;
-
- static const char dwc_driver_name[] = "dwc_otg";
-
-+extern void* dummy_send;
-+
- extern int pcd_init(
- #ifdef LM_INTERFACE
- struct lm_device *_dev
-@@ -238,6 +240,14 @@ static struct dwc_otg_driver_module_para
- .adp_enable = -1,
- };
-
-+//Global variable to switch the fiq fix on or off (declared in bcm2708.c)
-+extern bool fiq_fix_enable;
-+// Global variable to enable the split transaction fix
-+bool fiq_split_enable = true;
-+//Global variable to switch the nak holdoff on or off
-+bool nak_holdoff_enable = true;
-+
-+
- /**
- * This function shows the Driver Version.
- */
-@@ -779,17 +789,33 @@ static int dwc_otg_driver_probe(
- _dev->resource->start,
- _dev->resource->end - _dev->resource->start + 1);
- #if 1
-- if (!request_mem_region(_dev->resource->start,
-- _dev->resource->end - _dev->resource->start + 1,
-+ if (!request_mem_region(_dev->resource[0].start,
-+ _dev->resource[0].end - _dev->resource[0].start + 1,
- "dwc_otg")) {
- dev_dbg(&_dev->dev, "error reserving mapped memory\n");
- retval = -EFAULT;
- goto fail;
- }
-
-- dwc_otg_device->os_dep.base = ioremap_nocache(_dev->resource->start,
-- _dev->resource->end -
-- _dev->resource->start+1);
-+ dwc_otg_device->os_dep.base = ioremap_nocache(_dev->resource[0].start,
-+ _dev->resource[0].end -
-+ _dev->resource[0].start+1);
-+ if (fiq_fix_enable)
-+ {
-+ 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;
-+ }
-+
-+ dwc_otg_device->os_dep.mphi_base = ioremap_nocache(_dev->resource[1].start,
-+ _dev->resource[1].end -
-+ _dev->resource[1].start + 1);
-+ dummy_send = (void *) kmalloc(16, GFP_ATOMIC);
-+ }
-+
- #else
- {
- struct map_desc desc = {
-@@ -1044,6 +1070,12 @@ static int __init dwc_otg_driver_init(vo
- int retval = 0;
- int error;
- struct device_driver *drv;
-+
-+ if(fiq_split_enable && !fiq_fix_enable) {
-+ printk(KERN_WARNING "dwc_otg: fiq_split_enable was set without fiq_fix_enable! Correcting.\n");
-+ fiq_fix_enable = 1;
-+ }
-+
- printk(KERN_INFO "%s: version %s (%s bus)\n", dwc_driver_name,
- DWC_DRIVER_VERSION,
- #ifdef LM_INTERFACE
-@@ -1063,6 +1095,9 @@ static int __init dwc_otg_driver_init(vo
- printk(KERN_ERR "%s retval=%d\n", __func__, retval);
- return retval;
- }
-+ printk(KERN_DEBUG "dwc_otg: FIQ %s\n", fiq_fix_enable ? "enabled":"disabled");
-+ printk(KERN_DEBUG "dwc_otg: NAK holdoff %s\n", nak_holdoff_enable ? "enabled":"disabled");
-+ printk(KERN_DEBUG "dwc_otg: FIQ split fix %s\n", fiq_split_enable ? "enabled":"disabled");
-
- error = driver_create_file(drv, &driver_attr_version);
- #ifdef DEBUG
-@@ -1343,6 +1378,13 @@ MODULE_PARM_DESC(otg_ver, "OTG revision
- module_param(microframe_schedule, bool, 0444);
- MODULE_PARM_DESC(microframe_schedule, "Enable the microframe scheduler");
-
-+module_param(fiq_fix_enable, bool, 0444);
-+MODULE_PARM_DESC(fiq_fix_enable, "Enable the fiq fix");
-+module_param(nak_holdoff_enable, bool, 0444);
-+MODULE_PARM_DESC(nak_holdoff_enable, "Enable the NAK holdoff");
-+module_param(fiq_split_enable, bool, 0444);
-+MODULE_PARM_DESC(fiq_split_enable, "Enable the FIQ fix on split transactions");
-+
- /** @page "Module Parameters"
- *
- * The following parameters may be specified when starting the module.
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
-@@ -40,10 +40,14 @@
- * header file.
- */
-
-+#include <linux/usb.h>
-+#include <linux/usb/hcd.h>
-+
- #include "dwc_otg_hcd.h"
- #include "dwc_otg_regs.h"
-+#include "dwc_otg_mphi_fix.h"
-
--extern bool microframe_schedule;
-+extern bool microframe_schedule, nak_holdoff_enable;
-
- //#define DEBUG_HOST_CHANNELS
- #ifdef DEBUG_HOST_CHANNELS
-@@ -53,6 +57,13 @@ static int last_sel_trans_num_avail_hc_a
- static int last_sel_trans_num_avail_hc_at_end = 0;
- #endif /* DEBUG_HOST_CHANNELS */
-
-+extern int g_next_sched_frame, g_np_count, g_np_sent;
-+
-+extern haint_data_t haint_saved;
-+extern hcintmsk_data_t hcintmsk_saved[MAX_EPS_CHANNELS];
-+extern hcint_data_t hcint_saved[MAX_EPS_CHANNELS];
-+extern gintsts_data_t ginsts_saved;
-+
- dwc_otg_hcd_t *dwc_otg_hcd_alloc_hcd(void)
- {
- return DWC_ALLOC(sizeof(dwc_otg_hcd_t));
-@@ -162,31 +173,43 @@ static void del_timers(dwc_otg_hcd_t * h
-
- /**
- * Processes all the URBs in a single list of QHs. Completes them with
-- * -ETIMEDOUT and frees the QTD.
-+ * -ESHUTDOWN and frees the QTD.
- */
- static void kill_urbs_in_qh_list(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
- {
-- dwc_list_link_t *qh_item;
-+ dwc_list_link_t *qh_item, *qh_tmp;
- dwc_otg_qh_t *qh;
- dwc_otg_qtd_t *qtd, *qtd_tmp;
-
-- DWC_LIST_FOREACH(qh_item, qh_list) {
-+ DWC_LIST_FOREACH_SAFE(qh_item, qh_tmp, qh_list) {
- qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
- DWC_CIRCLEQ_FOREACH_SAFE(qtd, qtd_tmp,
- &qh->qtd_list, qtd_list_entry) {
- qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
- if (qtd->urb != NULL) {
- hcd->fops->complete(hcd, qtd->urb->priv,
-- qtd->urb, -DWC_E_TIMEOUT);
-+ qtd->urb, -DWC_E_SHUTDOWN);
- dwc_otg_hcd_qtd_remove_and_free(hcd, qtd, qh);
- }
-
- }
-+ if(qh->channel) {
-+ /* Using hcchar.chen == 1 is not a reliable test.
-+ * It is possible that the channel has already halted
-+ * but not yet been through the IRQ handler.
-+ */
-+ dwc_otg_hc_halt(hcd->core_if, qh->channel,
-+ DWC_OTG_HC_XFER_URB_DEQUEUE);
-+ if(microframe_schedule)
-+ hcd->available_host_channels++;
-+ qh->channel = NULL;
-+ }
-+ dwc_otg_hcd_qh_remove(hcd, qh);
- }
- }
-
- /**
-- * Responds with an error status of ETIMEDOUT to all URBs in the non-periodic
-+ * Responds with an error status of ESHUTDOWN to all URBs in the non-periodic
- * and periodic schedules. The QTD associated with each URB is removed from
- * the schedule and freed. This function may be called when a disconnect is
- * detected or when the HCD is being stopped.
-@@ -272,7 +295,8 @@ static int32_t dwc_otg_hcd_disconnect_cb
- */
- dwc_otg_hcd->flags.b.port_connect_status_change = 1;
- dwc_otg_hcd->flags.b.port_connect_status = 0;
--
-+ if(fiq_fix_enable)
-+ local_fiq_disable();
- /*
- * Shutdown any transfers in process by clearing the Tx FIFO Empty
- * interrupt mask and status bits and disabling subsequent host
-@@ -368,8 +392,22 @@ static int32_t dwc_otg_hcd_disconnect_cb
- channel->qh = NULL;
- }
- }
-+ if(fiq_split_enable) {
-+ for(i=0; i < 128; i++) {
-+ dwc_otg_hcd->hub_port[i] = 0;
-+ }
-+ haint_saved.d32 = 0;
-+ for(i=0; i < MAX_EPS_CHANNELS; i++) {
-+ hcint_saved[i].d32 = 0;
-+ hcintmsk_saved[i].d32 = 0;
-+ }
-+ }
-+
- }
-
-+ if(fiq_fix_enable)
-+ local_fiq_enable();
-+
- if (dwc_otg_hcd->fops->disconnect) {
- dwc_otg_hcd->fops->disconnect(dwc_otg_hcd);
- }
-@@ -407,6 +445,7 @@ static int dwc_otg_hcd_sleep_cb(void *p)
- }
- #endif
-
-+
- /**
- * HCD Callback function for Remote Wakeup.
- *
-@@ -457,10 +496,12 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_
- dwc_otg_hcd_urb_t * dwc_otg_urb, void **ep_handle,
- int atomic_alloc)
- {
-- dwc_irqflags_t flags;
- int retval = 0;
-+ uint8_t needs_scheduling = 0;
-+ dwc_otg_transaction_type_e tr_type;
- dwc_otg_qtd_t *qtd;
- gintmsk_data_t intr_mask = {.d32 = 0 };
-+ hprt0_data_t hprt0 = { .d32 = 0 };
-
- #ifdef DEBUG /* integrity checks (Broadcom) */
- if (NULL == hcd->core_if) {
-@@ -475,6 +516,16 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_
- return -DWC_E_NO_DEVICE;
- }
-
-+ /* Some core configurations cannot support LS traffic on a FS root port */
-+ if ((hcd->fops->speed(hcd, dwc_otg_urb->priv) == USB_SPEED_LOW) &&
-+ (hcd->core_if->hwcfg2.b.fs_phy_type == 1) &&
-+ (hcd->core_if->hwcfg2.b.hs_phy_type == 1)) {
-+ hprt0.d32 = DWC_READ_REG32(hcd->core_if->host_if->hprt0);
-+ if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_FULL_SPEED) {
-+ return -DWC_E_NO_DEVICE;
-+ }
-+ }
-+
- qtd = dwc_otg_hcd_qtd_create(dwc_otg_urb, atomic_alloc);
- if (qtd == NULL) {
- DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n");
-@@ -490,32 +541,27 @@ int dwc_otg_hcd_urb_enqueue(dwc_otg_hcd_
- return -DWC_E_NO_MEMORY;
- }
- #endif
-- retval =
-- dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
-+ intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
-+ if(!intr_mask.b.sofintr) needs_scheduling = 1;
-+ if((((dwc_otg_qh_t *)ep_handle)->ep_type == UE_BULK) && !(qtd->urb->flags & URB_GIVEBACK_ASAP))
-+ /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */
-+ needs_scheduling = 0;
-+
-+ retval = dwc_otg_hcd_qtd_add(qtd, hcd, (dwc_otg_qh_t **) ep_handle, atomic_alloc);
- // creates a new queue in ep_handle if it doesn't exist already
- if (retval < 0) {
- DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. "
- "Error status %d\n", retval);
- dwc_otg_hcd_qtd_free(qtd);
-- } else {
-- qtd->qh = *ep_handle;
-+ return retval;
- }
-- intr_mask.d32 = DWC_READ_REG32(&hcd->core_if->core_global_regs->gintmsk);
-- if (!intr_mask.b.sofintr && retval == 0) {
-- dwc_otg_transaction_type_e tr_type;
-- if ((qtd->qh->ep_type == UE_BULK)
-- && !(qtd->urb->flags & URB_GIVEBACK_ASAP)) {
-- /* Do not schedule SG transactions until qtd has URB_GIVEBACK_ASAP set */
-- return 0;
-- }
-- DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
-+
-+ if(needs_scheduling) {
- tr_type = dwc_otg_hcd_select_transactions(hcd);
- if (tr_type != DWC_OTG_TRANSACTION_NONE) {
- dwc_otg_hcd_queue_transactions(hcd, tr_type);
- }
-- DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
- }
--
- return retval;
- }
-
-@@ -524,6 +570,8 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_
- {
- dwc_otg_qh_t *qh;
- dwc_otg_qtd_t *urb_qtd;
-+ BUG_ON(!hcd);
-+ BUG_ON(!dwc_otg_urb);
-
- #ifdef DEBUG /* integrity checks (Broadcom) */
-
-@@ -540,14 +588,17 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_
- return -DWC_E_INVALID;
- }
- urb_qtd = dwc_otg_urb->qtd;
-+ BUG_ON(!urb_qtd);
- if (urb_qtd->qh == NULL) {
- DWC_ERROR("**** DWC OTG HCD URB Dequeue with QTD with NULL Q handler\n");
- return -DWC_E_INVALID;
- }
- #else
- urb_qtd = dwc_otg_urb->qtd;
-+ BUG_ON(!urb_qtd);
- #endif
- qh = urb_qtd->qh;
-+ BUG_ON(!qh);
- if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
- if (urb_qtd->in_process) {
- dump_channel_info(hcd, qh);
-@@ -571,6 +622,8 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_
- */
- dwc_otg_hc_halt(hcd->core_if, qh->channel,
- DWC_OTG_HC_XFER_URB_DEQUEUE);
-+
-+ dwc_otg_hcd_release_port(hcd, qh);
- }
- }
-
-@@ -687,6 +740,33 @@ static void reset_tasklet_func(void *dat
- dwc_otg_hcd->flags.b.port_reset_change = 1;
- }
-
-+static void completion_tasklet_func(void *ptr)
-+{
-+ dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) ptr;
-+ struct urb *urb;
-+ urb_tq_entry_t *item;
-+ dwc_irqflags_t flags;
-+
-+ /* This could just be spin_lock_irq */
-+ DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
-+ while (!DWC_TAILQ_EMPTY(&hcd->completed_urb_list)) {
-+ item = DWC_TAILQ_FIRST(&hcd->completed_urb_list);
-+ urb = item->urb;
-+ DWC_TAILQ_REMOVE(&hcd->completed_urb_list, item,
-+ urb_tq_entries);
-+ DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
-+ DWC_FREE(item);
-+
-+ usb_hcd_giveback_urb(hcd->priv, urb, urb->status);
-+
-+ fiq_print(FIQDBG_PORTHUB, "COMPLETE");
-+
-+ DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
-+ }
-+ DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
-+ return;
-+}
-+
- static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
- {
- dwc_list_link_t *item;
-@@ -819,12 +899,14 @@ static void dwc_otg_hcd_free(dwc_otg_hcd
- } else if (dwc_otg_hcd->status_buf != NULL) {
- DWC_FREE(dwc_otg_hcd->status_buf);
- }
-+ DWC_SPINLOCK_FREE(dwc_otg_hcd->channel_lock);
- DWC_SPINLOCK_FREE(dwc_otg_hcd->lock);
- /* Set core_if's lock pointer to NULL */
- dwc_otg_hcd->core_if->lock = NULL;
-
- DWC_TIMER_FREE(dwc_otg_hcd->conn_timer);
- DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet);
-+ DWC_TASK_FREE(dwc_otg_hcd->completion_tasklet);
-
- #ifdef DWC_DEV_SRPCAP
- if (dwc_otg_hcd->core_if->power_down == 2 &&
-@@ -874,7 +956,7 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd
- DWC_LIST_INIT(&hcd->periodic_sched_ready);
- DWC_LIST_INIT(&hcd->periodic_sched_assigned);
- DWC_LIST_INIT(&hcd->periodic_sched_queued);
--
-+ DWC_TAILQ_INIT(&hcd->completed_urb_list);
- /*
- * Create a host channel descriptor for each host channel implemented
- * in the controller. Initialize the channel descriptor array.
-@@ -912,6 +994,9 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd
-
- /* Initialize reset tasklet. */
- hcd->reset_tasklet = DWC_TASK_ALLOC("reset_tasklet", reset_tasklet_func, hcd);
-+
-+ hcd->completion_tasklet = DWC_TASK_ALLOC("completion_tasklet",
-+ completion_tasklet_func, hcd);
- #ifdef DWC_DEV_SRPCAP
- if (hcd->core_if->power_down == 2) {
- /* Initialize Power on timer for Host power up in case hibernation */
-@@ -944,6 +1029,12 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd
- hcd->frame_list = NULL;
- hcd->frame_list_dma = 0;
- hcd->periodic_qh_count = 0;
-+
-+ DWC_MEMSET(hcd->hub_port, 0, sizeof(hcd->hub_port));
-+#ifdef FIQ_DEBUG
-+ DWC_MEMSET(hcd->hub_port_alloc, -1, sizeof(hcd->hub_port_alloc));
-+#endif
-+
- out:
- return retval;
- }
-@@ -1089,7 +1180,12 @@ static void assign_and_init_hc(dwc_otg_h
- uint32_t hub_addr, port_addr;
- hc->do_split = 1;
- hc->xact_pos = qtd->isoc_split_pos;
-- hc->complete_split = qtd->complete_split;
-+ /* We don't need to do complete splits anymore */
-+ if(fiq_split_enable)
-+ hc->complete_split = qtd->complete_split = 0;
-+ else
-+ hc->complete_split = qtd->complete_split;
-+
- hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &port_addr);
- hc->hub_addr = (uint8_t) hub_addr;
- hc->port_addr = (uint8_t) port_addr;
-@@ -1236,6 +1332,65 @@ static void assign_and_init_hc(dwc_otg_h
- hc->qh = qh;
- }
-
-+/*
-+** Check the transaction to see if the port / hub has already been assigned for
-+** a split transaction
-+**
-+** Return 0 - Port is already in use
-+*/
-+int dwc_otg_hcd_allocate_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh)
-+{
-+ uint32_t hub_addr, port_addr;
-+
-+ if(!fiq_split_enable)
-+ return 0;
-+
-+ hcd->fops->hub_info(hcd, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->priv, &hub_addr, &port_addr);
-+
-+ if(hcd->hub_port[hub_addr] & (1 << port_addr))
-+ {
-+ fiq_print(FIQDBG_PORTHUB, "H%dP%d:S%02d", hub_addr, port_addr, qh->skip_count);
-+
-+ qh->skip_count++;
-+
-+ if(qh->skip_count > 40000)
-+ {
-+ printk_once(KERN_ERR "Error: Having to skip port allocation");
-+ local_fiq_disable();
-+ BUG();
-+ return 0;
-+ }
-+ return 1;
-+ }
-+ else
-+ {
-+ qh->skip_count = 0;
-+ hcd->hub_port[hub_addr] |= 1 << port_addr;
-+ fiq_print(FIQDBG_PORTHUB, "H%dP%d:A %d", hub_addr, port_addr, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->pipe_info.ep_num);
-+#ifdef FIQ_DEBUG
-+ hcd->hub_port_alloc[hub_addr * 16 + port_addr] = dwc_otg_hcd_get_frame_number(hcd);
-+#endif
-+ return 0;
-+ }
-+}
-+void dwc_otg_hcd_release_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh)
-+{
-+ uint32_t hub_addr, port_addr;
-+
-+ if(!fiq_split_enable)
-+ return;
-+
-+ hcd->fops->hub_info(hcd, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->priv, &hub_addr, &port_addr);
-+
-+ hcd->hub_port[hub_addr] &= ~(1 << port_addr);
-+#ifdef FIQ_DEBUG
-+ hcd->hub_port_alloc[hub_addr * 16 + port_addr] = -1;
-+#endif
-+ fiq_print(FIQDBG_PORTHUB, "H%dP%d:RO%d", hub_addr, port_addr, DWC_CIRCLEQ_FIRST(&qh->qtd_list)->urb->pipe_info.ep_num);
-+
-+}
-+
-+
- /**
- * This function selects transactions from the HCD transfer schedule and
- * assigns them to available host channels. It is called from HCD interrupt
-@@ -1249,9 +1404,10 @@ dwc_otg_transaction_type_e dwc_otg_hcd_s
- {
- dwc_list_link_t *qh_ptr;
- dwc_otg_qh_t *qh;
-+ dwc_otg_qtd_t *qtd;
- int num_channels;
- dwc_irqflags_t flags;
-- dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC();
-+ dwc_spinlock_t *channel_lock = hcd->channel_lock;
- dwc_otg_transaction_type_e ret_val = DWC_OTG_TRANSACTION_NONE;
-
- #ifdef DEBUG_SOF
-@@ -1269,11 +1425,29 @@ dwc_otg_transaction_type_e dwc_otg_hcd_s
-
- while (qh_ptr != &hcd->periodic_sched_ready &&
- !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
-+
-+ qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
-+
-+ if(qh->do_split) {
-+ qtd = DWC_CIRCLEQ_FIRST(&qh->qtd_list);
-+ if(!(qh->ep_type == UE_ISOCHRONOUS &&
-+ (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID ||
-+ qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END))) {
-+ if(dwc_otg_hcd_allocate_port(hcd, qh))
-+ {
-+ qh_ptr = DWC_LIST_NEXT(qh_ptr);
-+ g_next_sched_frame = dwc_frame_num_inc(dwc_otg_hcd_get_frame_number(hcd), 1);
-+ continue;
-+ }
-+ }
-+ }
-+
- if (microframe_schedule) {
- // Make sure we leave one channel for non periodic transactions.
- DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
- if (hcd->available_host_channels <= 1) {
- DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
-+ if(qh->do_split) dwc_otg_hcd_release_port(hcd, qh);
- break;
- }
- hcd->available_host_channels--;
-@@ -1294,8 +1468,6 @@ dwc_otg_transaction_type_e dwc_otg_hcd_s
- DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_assigned,
- &qh->qh_list_entry);
- DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
--
-- ret_val = DWC_OTG_TRANSACTION_PERIODIC;
- }
-
- /*
-@@ -1310,6 +1482,31 @@ dwc_otg_transaction_type_e dwc_otg_hcd_s
- num_channels - hcd->periodic_channels) &&
- !DWC_CIRCLEQ_EMPTY(&hcd->free_hc_list)) {
-
-+ qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
-+
-+ /*
-+ * Check to see if this is a NAK'd retransmit, in which case ignore for retransmission
-+ * we hold off on bulk retransmissions to reduce NAK interrupt overhead for full-speed
-+ * cheeky devices that just hold off using NAKs
-+ */
-+ if (nak_holdoff_enable && qh->do_split) {
-+ if (qh->nak_frame != 0xffff &&
-+ dwc_full_frame_num(qh->nak_frame) ==
-+ dwc_full_frame_num(dwc_otg_hcd_get_frame_number(hcd))) {
-+ /*
-+ * Revisit: Need to avoid trampling on periodic scheduling.
-+ * Currently we are safe because g_np_count != g_np_sent whenever we hit this,
-+ * but if this behaviour is changed then periodic endpoints will get a slower
-+ * polling rate.
-+ */
-+ g_next_sched_frame = ((qh->nak_frame + 8) & ~7) & DWC_HFNUM_MAX_FRNUM;
-+ qh_ptr = DWC_LIST_NEXT(qh_ptr);
-+ continue;
-+ } else {
-+ qh->nak_frame = 0xffff;
-+ }
-+ }
-+
- if (microframe_schedule) {
- DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
- if (hcd->available_host_channels < 1) {
-@@ -1322,7 +1519,6 @@ dwc_otg_transaction_type_e dwc_otg_hcd_s
- last_sel_trans_num_nonper_scheduled++;
- #endif /* DEBUG_HOST_CHANNELS */
- }
-- qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
-
- assign_and_init_hc(hcd, qh);
-
-@@ -1336,21 +1532,22 @@ dwc_otg_transaction_type_e dwc_otg_hcd_s
- &qh->qh_list_entry);
- DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
-
-- if (ret_val == DWC_OTG_TRANSACTION_NONE) {
-- ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC;
-- } else {
-- ret_val = DWC_OTG_TRANSACTION_ALL;
-- }
-+ g_np_sent++;
-
- if (!microframe_schedule)
- hcd->non_periodic_channels++;
- }
-
-+ if(!DWC_LIST_EMPTY(&hcd->periodic_sched_assigned))
-+ ret_val |= DWC_OTG_TRANSACTION_PERIODIC;
-+
-+ if(!DWC_LIST_EMPTY(&hcd->non_periodic_sched_active))
-+ ret_val |= DWC_OTG_TRANSACTION_NON_PERIODIC;
-+
-+
- #ifdef DEBUG_HOST_CHANNELS
- last_sel_trans_num_avail_hc_at_end = hcd->available_host_channels;
- #endif /* DEBUG_HOST_CHANNELS */
--
-- DWC_SPINLOCK_FREE(channel_lock);
- return ret_val;
- }
-
-@@ -1464,6 +1661,15 @@ static void process_periodic_channels(dw
-
- qh = DWC_LIST_ENTRY(qh_ptr, dwc_otg_qh_t, qh_list_entry);
-
-+ // Do not send a split start transaction any later than frame .6
-+ // Note, we have to schedule a periodic in .5 to make it go in .6
-+ if(fiq_split_enable && qh->do_split && ((dwc_otg_hcd_get_frame_number(hcd) + 1) & 7) > 6)
-+ {
-+ qh_ptr = qh_ptr->next;
-+ g_next_sched_frame = dwc_otg_hcd_get_frame_number(hcd) | 7;
-+ continue;
-+ }
-+
- /*
- * Set a flag if we're queuing high-bandwidth in slave mode.
- * The flag prevents any halts to get into the request queue in
-@@ -1593,6 +1799,15 @@ static void process_non_periodic_channel
-
- qh = DWC_LIST_ENTRY(hcd->non_periodic_qh_ptr, dwc_otg_qh_t,
- qh_list_entry);
-+
-+ // Do not send a split start transaction any later than frame .5
-+ // non periodic transactions will start immediately in this uframe
-+ if(fiq_split_enable && qh->do_split && ((dwc_otg_hcd_get_frame_number(hcd) + 1) & 7) > 6)
-+ {
-+ g_next_sched_frame = dwc_otg_hcd_get_frame_number(hcd) | 7;
-+ break;
-+ }
-+
- status =
- queue_transaction(hcd, qh->channel,
- tx_status.b.nptxfspcavail);
-@@ -3118,17 +3333,13 @@ dwc_otg_hcd_urb_t *dwc_otg_hcd_urb_alloc
- else
- dwc_otg_urb = DWC_ALLOC(size);
-
-- if (NULL != dwc_otg_urb)
-- dwc_otg_urb->packet_count = iso_desc_count;
-+ if (dwc_otg_urb)
-+ dwc_otg_urb->packet_count = iso_desc_count;
- else {
-- dwc_otg_urb->packet_count = 0;
-- if (size != 0) {
-- DWC_ERROR("**** DWC OTG HCD URB alloc - "
-- "%salloc of %db failed\n",
-- atomic_alloc?"atomic ":"", size);
-- }
-- }
--
-+ DWC_ERROR("**** DWC OTG HCD URB alloc - "
-+ "%salloc of %db failed\n",
-+ atomic_alloc?"atomic ":"", size);
-+ }
- return dwc_otg_urb;
- }
-
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h
-@@ -168,10 +168,10 @@ typedef enum dwc_otg_control_phase {
-
- /** Transaction types. */
- typedef enum dwc_otg_transaction_type {
-- DWC_OTG_TRANSACTION_NONE,
-- DWC_OTG_TRANSACTION_PERIODIC,
-- DWC_OTG_TRANSACTION_NON_PERIODIC,
-- DWC_OTG_TRANSACTION_ALL
-+ DWC_OTG_TRANSACTION_NONE = 0,
-+ DWC_OTG_TRANSACTION_PERIODIC = 1,
-+ DWC_OTG_TRANSACTION_NON_PERIODIC = 2,
-+ DWC_OTG_TRANSACTION_ALL = DWC_OTG_TRANSACTION_PERIODIC + DWC_OTG_TRANSACTION_NON_PERIODIC
- } dwc_otg_transaction_type_e;
-
- struct dwc_otg_qh;
-@@ -321,6 +321,11 @@ typedef struct dwc_otg_qh {
- */
- uint16_t sched_frame;
-
-+ /*
-+ ** Frame a NAK was received on this queue head, used to minimise NAK retransmission
-+ */
-+ uint16_t nak_frame;
-+
- /** (micro)frame at which last start split was initialized. */
- uint16_t start_split_frame;
-
-@@ -365,10 +370,19 @@ typedef struct dwc_otg_qh {
-
- uint16_t speed;
- uint16_t frame_usecs[8];
-+
-+ uint32_t skip_count;
- } dwc_otg_qh_t;
-
- DWC_CIRCLEQ_HEAD(hc_list, dwc_hc);
-
-+typedef struct urb_tq_entry {
-+ struct urb *urb;
-+ DWC_TAILQ_ENTRY(urb_tq_entry) urb_tq_entries;
-+} urb_tq_entry_t;
-+
-+DWC_TAILQ_HEAD(urb_list, urb_tq_entry);
-+
- /**
- * This structure holds the state of the HCD, including the non-periodic and
- * periodic schedules.
-@@ -546,9 +560,12 @@ struct dwc_otg_hcd {
- /* Tasket to do a reset */
- dwc_tasklet_t *reset_tasklet;
-
-+ dwc_tasklet_t *completion_tasklet;
-+ struct urb_list completed_urb_list;
-+
- /* */
- dwc_spinlock_t *lock;
--
-+ dwc_spinlock_t *channel_lock;
- /**
- * Private data that could be used by OS wrapper.
- */
-@@ -559,6 +576,12 @@ struct dwc_otg_hcd {
- /** Frame List */
- uint32_t *frame_list;
-
-+ /** Hub - Port assignment */
-+ int hub_port[128];
-+#ifdef FIQ_DEBUG
-+ int hub_port_alloc[2048];
-+#endif
-+
- /** Frame List DMA address */
- dma_addr_t frame_list_dma;
-
-@@ -589,6 +612,10 @@ extern dwc_otg_transaction_type_e dwc_ot
- extern void dwc_otg_hcd_queue_transactions(dwc_otg_hcd_t * hcd,
- dwc_otg_transaction_type_e tr_type);
-
-+int dwc_otg_hcd_allocate_port(dwc_otg_hcd_t * hcd, dwc_otg_qh_t *qh);
-+void dwc_otg_hcd_release_port(dwc_otg_hcd_t * dwc_otg_hcd, dwc_otg_qh_t *qh);
-+
-+
- /** @} */
-
- /** @name Interrupt Handler Functions */
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c
-@@ -276,7 +276,7 @@ void dump_frame_list(dwc_otg_hcd_t * hcd
- static void release_channel_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
- {
- dwc_irqflags_t flags;
-- dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC();
-+ dwc_spinlock_t *channel_lock = hcd->channel_lock;
-
- dwc_hc_t *hc = qh->channel;
- if (dwc_qh_is_non_per(qh)) {
-@@ -306,7 +306,6 @@ static void release_channel_ddma(dwc_otg
- dwc_memset(qh->desc_list, 0x00,
- sizeof(dwc_otg_host_dma_desc_t) * max_desc_num(qh));
- }
-- DWC_SPINLOCK_FREE(channel_lock);
- }
-
- /**
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h
-@@ -113,6 +113,11 @@ extern void dwc_otg_hcd_remove(dwc_otg_h
- */
- extern int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd);
-
-+/** This function is used to handle the fast interrupt
-+ *
-+ */
-+extern void __attribute__ ((naked)) dwc_otg_hcd_handle_fiq(void);
-+
- /**
- * Returns private data set by
- * dwc_otg_hcd_set_priv_data function.
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
-@@ -34,6 +34,12 @@
-
- #include "dwc_otg_hcd.h"
- #include "dwc_otg_regs.h"
-+#include "dwc_otg_mphi_fix.h"
-+
-+#include <linux/jiffies.h>
-+#include <mach/hardware.h>
-+#include <asm/fiq.h>
-+
-
- extern bool microframe_schedule;
-
-@@ -41,38 +47,487 @@ extern bool microframe_schedule;
- * This file contains the implementation of the HCD Interrupt handlers.
- */
-
-+/*
-+ * Some globals to communicate between the FIQ and INTERRUPT
-+ */
-+
-+void * dummy_send;
-+mphi_regs_t c_mphi_regs;
-+volatile void *dwc_regs_base;
-+int fiq_done, int_done;
-+
-+gintsts_data_t gintsts_saved = {.d32 = 0};
-+hcint_data_t hcint_saved[MAX_EPS_CHANNELS];
-+hcintmsk_data_t hcintmsk_saved[MAX_EPS_CHANNELS];
-+int split_out_xfersize[MAX_EPS_CHANNELS];
-+haint_data_t haint_saved;
-+
-+int g_next_sched_frame, g_np_count, g_np_sent;
-+static int mphi_int_count = 0 ;
-+
-+hcchar_data_t nak_hcchar;
-+hctsiz_data_t nak_hctsiz;
-+hcsplt_data_t nak_hcsplt;
-+int nak_count;
-+
-+int complete_sched[MAX_EPS_CHANNELS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
-+int split_start_frame[MAX_EPS_CHANNELS];
-+int queued_port[MAX_EPS_CHANNELS];
-+
-+#ifdef FIQ_DEBUG
-+char buffer[1000*16];
-+int wptr;
-+void notrace _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...)
-+{
-+ FIQDBG_T dbg_lvl_req = FIQDBG_PORTHUB;
-+ va_list args;
-+ char text[17];
-+ hfnum_data_t hfnum = { .d32 = FIQ_READ(dwc_regs_base + 0x408) };
-+ unsigned long flags;
-+
-+ local_irq_save(flags);
-+ local_fiq_disable();
-+ if(dbg_lvl & dbg_lvl_req || dbg_lvl == FIQDBG_ERR)
-+ {
-+ snprintf(text, 9, "%4d%d:%d ", hfnum.b.frnum/8, hfnum.b.frnum%8, 8 - hfnum.b.frrem/937);
-+ va_start(args, fmt);
-+ vsnprintf(text+8, 9, fmt, args);
-+ va_end(args);
-+
-+ memcpy(buffer + wptr, text, 16);
-+ wptr = (wptr + 16) % sizeof(buffer);
-+ }
-+ local_irq_restore(flags);
-+}
-+#endif
-+
-+void notrace fiq_queue_request(int channel, int odd_frame)
-+{
-+ hcchar_data_t hcchar = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x0) };
-+ hcsplt_data_t hcsplt = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x4) };
-+ hctsiz_data_t hctsiz = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x10) };
-+
-+ if(hcsplt.b.spltena == 0)
-+ {
-+ fiq_print(FIQDBG_ERR, "SPLTENA ");
-+ BUG();
-+ }
-+
-+ if(hcchar.b.epdir == 1)
-+ {
-+ fiq_print(FIQDBG_SCHED, "IN Ch %d", channel);
-+ }
-+ else
-+ {
-+ hctsiz.b.xfersize = 0;
-+ fiq_print(FIQDBG_SCHED, "OUT Ch %d", channel);
-+ }
-+ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x10), hctsiz.d32);
-+
-+ hcsplt.b.compsplt = 1;
-+ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x4), hcsplt.d32);
-+
-+ // Send the Split complete
-+ hcchar.b.chen = 1;
-+ hcchar.b.oddfrm = odd_frame ? 1 : 0;
-+
-+ // Post this for transmit on the next frame for periodic or this frame for non-periodic
-+ fiq_print(FIQDBG_SCHED, "SND_%s", odd_frame ? "ODD " : "EVEN");
-+
-+ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x0), hcchar.d32);
-+}
-+
-+static int last_sof = -1;
-+
-+/*
-+** Function to handle the start of frame interrupt, choose whether we need to do anything and
-+** therefore trigger the main interrupt
-+**
-+** returns int != 0 - interrupt has been handled
-+*/
-+int diff;
-+
-+int notrace fiq_sof_handle(hfnum_data_t hfnum)
-+{
-+ int handled = 0;
-+ int i;
-+
-+ // Just check that once we're running we don't miss a SOF
-+ /*if(last_sof != -1 && (hfnum.b.frnum != ((last_sof + 1) & 0x3fff)))
-+ {
-+ fiq_print(FIQDBG_ERR, "LASTSOF ");
-+ fiq_print(FIQDBG_ERR, "%4d%d ", last_sof / 8, last_sof & 7);
-+ fiq_print(FIQDBG_ERR, "%4d%d ", hfnum.b.frnum / 8, hfnum.b.frnum & 7);
-+ BUG();
-+ }*/
-+
-+ // Only start remembering the last sof when the interrupt has been
-+ // enabled (we don't check the mask to come in here...)
-+ if(last_sof != -1 || FIQ_READ(dwc_regs_base + 0x18) & (1<<3))
-+ last_sof = hfnum.b.frnum;
-+
-+ for(i = 0; i < MAX_EPS_CHANNELS; i++)
-+ {
-+ if(complete_sched[i] != -1)
-+ {
-+ if(complete_sched[i] <= hfnum.b.frnum || (complete_sched[i] > 0x3f00 && hfnum.b.frnum < 0xf0))
-+ {
-+ fiq_queue_request(i, hfnum.b.frnum & 1);
-+ complete_sched[i] = -1;
-+ }
-+ }
-+
-+ if(complete_sched[i] != -1)
-+ {
-+ // This is because we've seen a split complete occur with no start...
-+ // most likely because missed the complete 0x3fff frames ago!
-+
-+ diff = (hfnum.b.frnum + 0x3fff - complete_sched[i]) & 0x3fff ;
-+ if(diff > 32 && diff < 0x3f00)
-+ {
-+ fiq_print(FIQDBG_ERR, "SPLTMISS");
-+ BUG();
-+ }
-+ }
-+ }
-+
-+ if(g_np_count == g_np_sent && dwc_frame_num_gt(g_next_sched_frame, hfnum.b.frnum))
-+ {
-+ /*
-+ * If np_count != np_sent that means we need to queue non-periodic (bulk) packets this packet
-+ * g_next_sched_frame is the next frame we have periodic packets for
-+ *
-+ * if neither of these are required for this frame then just clear the interrupt
-+ */
-+ handled = 1;
-+
-+ }
-+
-+ return handled;
-+}
-+
-+int notrace port_id(hcsplt_data_t hcsplt)
-+{
-+ return hcsplt.b.prtaddr + (hcsplt.b.hubaddr << 8);
-+}
-+
-+int notrace fiq_hcintr_handle(int channel, hfnum_data_t hfnum)
-+{
-+ hcchar_data_t hcchar = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x0) };
-+ hcsplt_data_t hcsplt = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x4) };
-+ hcint_data_t hcint = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x8) };
-+ hcintmsk_data_t hcintmsk = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0xc) };
-+ hctsiz_data_t hctsiz = { .d32 = FIQ_READ(dwc_regs_base + 0x500 + (channel * 0x20) + 0x10)};
-+
-+ hcint_saved[channel].d32 |= hcint.d32;
-+ hcintmsk_saved[channel].d32 = hcintmsk.d32;
-+
-+ if(hcsplt.b.spltena)
-+ {
-+ fiq_print(FIQDBG_PORTHUB, "ph: %4x", port_id(hcsplt));
-+ if(hcint.b.chhltd)
-+ {
-+ fiq_print(FIQDBG_SCHED, "CH HLT %d", channel);
-+ fiq_print(FIQDBG_SCHED, "%08x", hcint_saved[channel]);
-+ }
-+ if(hcint.b.stall || hcint.b.xacterr || hcint.b.bblerr || hcint.b.frmovrun || hcint.b.datatglerr)
-+ {
-+ queued_port[channel] = 0;
-+ fiq_print(FIQDBG_ERR, "CHAN ERR");
-+ }
-+ if(hcint.b.xfercomp)
-+ {
-+ // Clear the port allocation and transmit anything also on this port
-+ queued_port[channel] = 0;
-+ fiq_print(FIQDBG_SCHED, "XFERCOMP");
-+ }
-+ if(hcint.b.nak)
-+ {
-+ queued_port[channel] = 0;
-+ fiq_print(FIQDBG_SCHED, "NAK");
-+ }
-+ if(hcint.b.ack && !hcsplt.b.compsplt)
-+ {
-+ int i;
-+
-+ // Do not complete isochronous out transactions
-+ if(hcchar.b.eptype == 1 && hcchar.b.epdir == 0)
-+ {
-+ queued_port[channel] = 0;
-+ fiq_print(FIQDBG_SCHED, "ISOC_OUT");
-+ }
-+ else
-+ {
-+ // Make sure we check the port / hub combination that we sent this split on.
-+ // Do not queue a second request to the same port
-+ for(i = 0; i < MAX_EPS_CHANNELS; i++)
-+ {
-+ if(port_id(hcsplt) == queued_port[i])
-+ {
-+ fiq_print(FIQDBG_ERR, "PORTERR ");
-+ //BUG();
-+ }
-+ }
-+
-+ split_start_frame[channel] = (hfnum.b.frnum + 1) & ~7;
-+
-+ // Note, the size of an OUT is in the start split phase, not
-+ // the complete split
-+ split_out_xfersize[channel] = hctsiz.b.xfersize;
-+
-+ hcint_saved[channel].b.chhltd = 0;
-+ hcint_saved[channel].b.ack = 0;
-+
-+ queued_port[channel] = port_id(hcsplt);
-+
-+ if(hcchar.b.eptype & 1)
-+ {
-+ // Send the periodic complete in the same oddness frame as the ACK went...
-+ fiq_queue_request(channel, !(hfnum.b.frnum & 1));
-+ // complete_sched[channel] = dwc_frame_num_inc(hfnum.b.frnum, 1);
-+ }
-+ else
-+ {
-+ // Schedule the split complete to occur later
-+ complete_sched[channel] = dwc_frame_num_inc(hfnum.b.frnum, 2);
-+ fiq_print(FIQDBG_SCHED, "ACK%04d%d", complete_sched[channel]/8, complete_sched[channel]%8);
-+ }
-+ }
-+ }
-+ if(hcint.b.nyet)
-+ {
-+ fiq_print(FIQDBG_ERR, "NYETERR1");
-+ //BUG();
-+ // Can transmit a split complete up to uframe .0 of the next frame
-+ if(hfnum.b.frnum <= dwc_frame_num_inc(split_start_frame[channel], 8))
-+ {
-+ // Send it next frame
-+ if(hcchar.b.eptype & 1) // type 1 & 3 are interrupt & isoc
-+ {
-+ fiq_print(FIQDBG_SCHED, "NYT:SEND");
-+ fiq_queue_request(channel, !(hfnum.b.frnum & 1));
-+ }
-+ else
-+ {
-+ // Schedule non-periodic access for next frame (the odd-even bit doesn't effect NP)
-+ complete_sched[channel] = dwc_frame_num_inc(hfnum.b.frnum, 1);
-+ fiq_print(FIQDBG_SCHED, "NYT%04d%d", complete_sched[channel]/8, complete_sched[channel]%8);
-+ }
-+ hcint_saved[channel].b.chhltd = 0;
-+ hcint_saved[channel].b.nyet = 0;
-+ }
-+ else
-+ {
-+ queued_port[channel] = 0;
-+ fiq_print(FIQDBG_ERR, "NYETERR2");
-+ //BUG();
-+ }
-+ }
-+ }
-+ else
-+ {
-+ /*
-+ * If we have any of NAK, ACK, Datatlgerr active on a
-+ * non-split channel, the sole reason is to reset error
-+ * counts for a previously broken transaction. The FIQ
-+ * will thrash on NAK IN and ACK OUT in particular so
-+ * handle it "once" and allow the IRQ to do the rest.
-+ */
-+ hcint.d32 &= hcintmsk.d32;
-+ if(hcint.b.nak)
-+ {
-+ hcintmsk.b.nak = 0;
-+ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0xc), hcintmsk.d32);
-+ }
-+ if (hcint.b.ack)
-+ {
-+ hcintmsk.b.ack = 0;
-+ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0xc), hcintmsk.d32);
-+ }
-+ }
-+
-+ // Clear the interrupt, this will also clear the HAINT bit
-+ FIQ_WRITE((dwc_regs_base + 0x500 + (channel * 0x20) + 0x8), hcint.d32);
-+ return hcint_saved[channel].d32 == 0;
-+}
-+
-+gintsts_data_t gintsts;
-+gintmsk_data_t gintmsk;
-+// triggered: The set of interrupts that were triggered
-+// handled: The set of interrupts that have been handled (no IRQ is
-+// required)
-+// keep: The set of interrupts we want to keep unmasked even though we
-+// want to trigger an IRQ to handle it (SOF and HCINTR)
-+gintsts_data_t triggered, handled, keep;
-+hfnum_data_t hfnum;
-+
-+void __attribute__ ((naked)) notrace dwc_otg_hcd_handle_fiq(void)
-+{
-+
-+ /* entry takes care to store registers we will be treading on here */
-+ asm __volatile__ (
-+ "mov ip, sp ;"
-+ /* stash FIQ and normal regs */
-+ "stmdb sp!, {r0-r12, lr};"
-+ /* !! THIS SETS THE FRAME, adjust to > sizeof locals */
-+ "sub fp, ip, #512 ;"
-+ );
-+
-+ // Cannot put local variables at the beginning of the function
-+ // because otherwise 'C' will play with the stack pointer. any locals
-+ // need to be inside the following block
-+ do
-+ {
-+ fiq_done++;
-+ gintsts.d32 = FIQ_READ(dwc_regs_base + 0x14);
-+ gintmsk.d32 = FIQ_READ(dwc_regs_base + 0x18);
-+ hfnum.d32 = FIQ_READ(dwc_regs_base + 0x408);
-+ triggered.d32 = gintsts.d32 & gintmsk.d32;
-+ handled.d32 = 0;
-+ keep.d32 = 0;
-+ fiq_print(FIQDBG_INT, "FIQ ");
-+ fiq_print(FIQDBG_INT, "%08x", gintsts.d32);
-+ fiq_print(FIQDBG_INT, "%08x", gintmsk.d32);
-+ if(gintsts.d32)
-+ {
-+ // If port enabled
-+ if((FIQ_READ(dwc_regs_base + 0x440) & 0xf) == 0x5)
-+ {
-+ if(gintsts.b.sofintr)
-+ {
-+ if(fiq_sof_handle(hfnum))
-+ {
-+ handled.b.sofintr = 1; /* Handled in FIQ */
-+ }
-+ else
-+ {
-+ /* Keer interrupt unmasked */
-+ keep.b.sofintr = 1;
-+ }
-+ {
-+ // Need to make sure the read and clearing of the SOF interrupt is as close as possible to avoid the possibility of missing
-+ // a start of frame interrupt
-+ gintsts_data_t gintsts = { .b.sofintr = 1 };
-+ FIQ_WRITE((dwc_regs_base + 0x14), gintsts.d32);
-+ }
-+ }
-+
-+ if(fiq_split_enable && gintsts.b.hcintr)
-+ {
-+ int i;
-+ haint_data_t haint;
-+ haintmsk_data_t haintmsk;
-+
-+ haint.d32 = FIQ_READ(dwc_regs_base + 0x414);
-+ haintmsk.d32 = FIQ_READ(dwc_regs_base + 0x418);
-+ haint.d32 &= haintmsk.d32;
-+ haint_saved.d32 |= haint.d32;
-+
-+ fiq_print(FIQDBG_INT, "hcintr");
-+ fiq_print(FIQDBG_INT, "%08x", FIQ_READ(dwc_regs_base + 0x414));
-+
-+ // Go through each channel that has an enabled interrupt
-+ for(i = 0; i < 16; i++)
-+ if((haint.d32 >> i) & 1)
-+ if(fiq_hcintr_handle(i, hfnum))
-+ haint_saved.d32 &= ~(1 << i); /* this was handled */
-+
-+ /* If we've handled all host channel interrupts then don't trigger the interrupt */
-+ if(haint_saved.d32 == 0)
-+ {
-+ handled.b.hcintr = 1;
-+ }
-+ else
-+ {
-+ /* Make sure we keep the channel interrupt unmasked when triggering the IRQ */
-+ keep.b.hcintr = 1;
-+ }
-+
-+ {
-+ gintsts_data_t gintsts = { .b.hcintr = 1 };
-+
-+ // Always clear the channel interrupt
-+ FIQ_WRITE((dwc_regs_base + 0x14), gintsts.d32);
-+ }
-+ }
-+ }
-+ else
-+ {
-+ last_sof = -1;
-+ }
-+ }
-+
-+ // Mask out the interrupts triggered - those handled - don't mask out the ones we want to keep
-+ gintmsk.d32 = keep.d32 | (gintmsk.d32 & ~(triggered.d32 & ~handled.d32));
-+ // Save those that were triggered but not handled
-+ gintsts_saved.d32 |= triggered.d32 & ~handled.d32;
-+ FIQ_WRITE(dwc_regs_base + 0x18, gintmsk.d32);
-+
-+ // Clear and save any unhandled interrupts and trigger the interrupt
-+ if(gintsts_saved.d32)
-+ {
-+ /* To enable the MPHI interrupt (INT 32)
-+ */
-+ FIQ_WRITE( c_mphi_regs.outdda, (int) dummy_send);
-+ FIQ_WRITE( c_mphi_regs.outddb, (1 << 29));
-+
-+ mphi_int_count++;
-+ }
-+ }
-+ while(0);
-+
-+ mb();
-+
-+ /* exit back to normal mode restoring everything */
-+ asm __volatile__ (
-+ /* return FIQ regs back to pristine state
-+ * and get normal regs back
-+ */
-+ "ldmia sp!, {r0-r12, lr};"
-+
-+ /* return */
-+ "subs pc, lr, #4;"
-+ );
-+}
-+
- /** This function handles interrupts for the HCD. */
- int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd)
- {
- int retval = 0;
-+ static int last_time;
-
- dwc_otg_core_if_t *core_if = dwc_otg_hcd->core_if;
- gintsts_data_t gintsts;
-+ gintmsk_data_t gintmsk;
-+ hfnum_data_t hfnum;
-+
- #ifdef DEBUG
- dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
-
-- //GRAYG: debugging
-- if (NULL == global_regs) {
-- DWC_DEBUGPL(DBG_HCD, "**** NULL regs: dwc_otg_hcd=%p "
-- "core_if=%p\n",
-- dwc_otg_hcd, global_regs);
-- return retval;
-- }
- #endif
-
-+ gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
-+ gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
-+
- /* Exit from ISR if core is hibernated */
- if (core_if->hibernation_suspend == 1) {
-- return retval;
-+ goto exit_handler_routine;
- }
- DWC_SPINLOCK(dwc_otg_hcd->lock);
- /* Check if HOST Mode */
- if (dwc_otg_is_host_mode(core_if)) {
-- gintsts.d32 = dwc_otg_read_core_intr(core_if);
-+ local_fiq_disable();
-+ gintmsk.d32 |= gintsts_saved.d32;
-+ gintsts.d32 |= gintsts_saved.d32;
-+ gintsts_saved.d32 = 0;
-+ local_fiq_enable();
- if (!gintsts.d32) {
-- DWC_SPINUNLOCK(dwc_otg_hcd->lock);
-- return 0;
-+ goto exit_handler_routine;
- }
-+ gintsts.d32 &= gintmsk.d32;
-+
- #ifdef DEBUG
-+ // We should be OK doing this because the common interrupts should already have been serviced
- /* Don't print debug message in the interrupt handler on SOF */
- #ifndef DEBUG_SOF
- if (gintsts.d32 != DWC_SOF_INTR_MASK)
-@@ -88,10 +543,16 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_
- "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x core_if=%p\n",
- gintsts.d32, core_if);
- #endif
--
-- if (gintsts.b.sofintr) {
-+ hfnum.d32 = DWC_READ_REG32(&dwc_otg_hcd->core_if->host_if->host_global_regs->hfnum);
-+ if (gintsts.b.sofintr && g_np_count == g_np_sent && dwc_frame_num_gt(g_next_sched_frame, hfnum.b.frnum))
-+ {
-+ /* Note, we should never get here if the FIQ is doing it's job properly*/
- retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd);
- }
-+ else if (gintsts.b.sofintr) {
-+ retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd);
-+ }
-+
- if (gintsts.b.rxstsqlvl) {
- retval |=
- dwc_otg_hcd_handle_rx_status_q_level_intr
-@@ -106,7 +567,10 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_
- /** @todo Implement i2cintr handler. */
- }
- if (gintsts.b.portintr) {
-+
-+ gintmsk_data_t gintmsk = { .b.portintr = 1};
- retval |= dwc_otg_hcd_handle_port_intr(dwc_otg_hcd);
-+ DWC_MODIFY_REG32(&core_if->core_global_regs->gintmsk, 0, gintmsk.d32);
- }
- if (gintsts.b.hcintr) {
- retval |= dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd);
-@@ -138,11 +602,48 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_
- #endif
-
- }
-+
-+exit_handler_routine:
-+
-+ if (fiq_fix_enable)
-+ {
-+ local_fiq_disable();
-+ // Make sure that we don't clear the interrupt if we've still got pending work to do
-+ if(gintsts_saved.d32 == 0)
-+ {
-+ /* Clear the MPHI interrupt */
-+ DWC_WRITE_REG32(c_mphi_regs.intstat, (1<<16));
-+ if (mphi_int_count >= 60)
-+ {
-+ DWC_WRITE_REG32(c_mphi_regs.ctrl, ((1<<31) + (1<<16)));
-+ while(!(DWC_READ_REG32(c_mphi_regs.ctrl) & (1 << 17)))
-+ ;
-+ DWC_WRITE_REG32(c_mphi_regs.ctrl, (1<<31));
-+ mphi_int_count = 0;
-+ }
-+ int_done++;
-+ }
-+
-+ // Unmask handled interrupts
-+ FIQ_WRITE(dwc_regs_base + 0x18, gintmsk.d32);
-+ //DWC_MODIFY_REG32((uint32_t *)IO_ADDRESS(USB_BASE + 0x8), 0 , 1);
-+
-+ local_fiq_enable();
-+
-+ if((jiffies / HZ) > last_time)
-+ {
-+ /* Once a second output the fiq and irq numbers, useful for debug */
-+ last_time = jiffies / HZ;
-+ DWC_DEBUGPL(DBG_USER, "int_done = %d fiq_done = %d\n", int_done, fiq_done);
-+ }
-+ }
-+
- DWC_SPINUNLOCK(dwc_otg_hcd->lock);
- return retval;
- }
-
- #ifdef DWC_TRACK_MISSED_SOFS
-+
- #warning Compiling code to track missed SOFs
- #define FRAME_NUM_ARRAY_SIZE 1000
- /**
-@@ -188,7 +689,8 @@ int32_t dwc_otg_hcd_handle_sof_intr(dwc_
- dwc_list_link_t *qh_entry;
- dwc_otg_qh_t *qh;
- dwc_otg_transaction_type_e tr_type;
-- gintsts_data_t gintsts = {.d32 = 0 };
-+ int did_something = 0;
-+ int32_t next_sched_frame = -1;
-
- hfnum.d32 =
- DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum);
-@@ -212,17 +714,31 @@ int32_t dwc_otg_hcd_handle_sof_intr(dwc_
- qh = DWC_LIST_ENTRY(qh_entry, dwc_otg_qh_t, qh_list_entry);
- qh_entry = qh_entry->next;
- if (dwc_frame_num_le(qh->sched_frame, hcd->frame_number)) {
-+
- /*
- * Move QH to the ready list to be executed next
- * (micro)frame.
- */
- DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
- &qh->qh_list_entry);
-+
-+ did_something = 1;
-+ }
-+ else
-+ {
-+ if(next_sched_frame < 0 || dwc_frame_num_le(qh->sched_frame, next_sched_frame))
-+ {
-+ next_sched_frame = qh->sched_frame;
-+ }
- }
- }
-+
-+ g_next_sched_frame = next_sched_frame;
-+
- tr_type = dwc_otg_hcd_select_transactions(hcd);
- if (tr_type != DWC_OTG_TRANSACTION_NONE) {
- dwc_otg_hcd_queue_transactions(hcd, tr_type);
-+ did_something = 1;
- }
-
- /* Clear interrupt */
-@@ -511,6 +1027,15 @@ int32_t dwc_otg_hcd_handle_hc_intr(dwc_o
-
- haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if);
-
-+ // Overwrite with saved interrupts from fiq handler
-+ if(fiq_split_enable)
-+ {
-+ local_fiq_disable();
-+ haint.d32 = haint_saved.d32;
-+ haint_saved.d32 = 0;
-+ local_fiq_enable();
-+ }
-+
- for (i = 0; i < dwc_otg_hcd->core_if->core_params->host_channels; i++) {
- if (haint.b2.chint & (1 << i)) {
- retval |= dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd, i);
-@@ -551,7 +1076,10 @@ static uint32_t get_actual_xfer_length(d
- *short_read = (hctsiz.b.xfersize != 0);
- }
- } else if (hc->qh->do_split) {
-- length = qtd->ssplit_out_xfer_count;
-+ if(fiq_split_enable)
-+ length = split_out_xfersize[hc->hc_num];
-+ else
-+ length = qtd->ssplit_out_xfer_count;
- } else {
- length = hc->xfer_len;
- }
-@@ -595,7 +1123,6 @@ static int update_urb_state_xfer_comp(dw
- DWC_OTG_HC_XFER_COMPLETE,
- &short_read);
-
--
- /* non DWORD-aligned buffer case handling. */
- if (hc->align_buff && xfer_length && hc->ep_is_in) {
- dwc_memcpy(urb->buf + urb->actual_length, hc->qh->dw_align_buf,
-@@ -797,11 +1324,24 @@ static void release_channel(dwc_otg_hcd_
- dwc_otg_transaction_type_e tr_type;
- int free_qtd;
- dwc_irqflags_t flags;
-- dwc_spinlock_t *channel_lock = DWC_SPINLOCK_ALLOC();
-+ dwc_spinlock_t *channel_lock = hcd->channel_lock;
-+#ifdef FIQ_DEBUG
-+ int endp = qtd->urb ? qtd->urb->pipe_info.ep_num : 0;
-+#endif
-+ int hog_port = 0;
-
- DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d, xfer_len %d\n",
- __func__, hc->hc_num, halt_status, hc->xfer_len);
-
-+ if(fiq_split_enable && hc->do_split) {
-+ if(!hc->ep_is_in && hc->ep_type == UE_ISOCHRONOUS) {
-+ if(hc->xact_pos == DWC_HCSPLIT_XACTPOS_MID ||
-+ hc->xact_pos == DWC_HCSPLIT_XACTPOS_BEGIN) {
-+ hog_port = 1;
-+ }
-+ }
-+ }
-+
- switch (halt_status) {
- case DWC_OTG_HC_XFER_URB_COMPLETE:
- free_qtd = 1;
-@@ -876,15 +1416,32 @@ cleanup:
-
- DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
- hcd->available_host_channels++;
-+ fiq_print(FIQDBG_PORTHUB, "AHC = %d ", hcd->available_host_channels);
- DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
- }
-
-+ if(fiq_split_enable && hc->do_split)
-+ {
-+ if(!(hcd->hub_port[hc->hub_addr] & (1 << hc->port_addr)))
-+ {
-+ fiq_print(FIQDBG_ERR, "PRTNOTAL");
-+ //BUG();
-+ }
-+ if(!hog_port && (hc->ep_type == DWC_OTG_EP_TYPE_ISOC ||
-+ hc->ep_type == DWC_OTG_EP_TYPE_INTR)) {
-+ hcd->hub_port[hc->hub_addr] &= ~(1 << hc->port_addr);
-+#ifdef FIQ_DEBUG
-+ hcd->hub_port_alloc[hc->hub_addr * 16 + hc->port_addr] = -1;
-+#endif
-+ fiq_print(FIQDBG_PORTHUB, "H%dP%d:RR%d", hc->hub_addr, hc->port_addr, endp);
-+ }
-+ }
-+
- /* Try to queue more transfers now that there's a free channel. */
- tr_type = dwc_otg_hcd_select_transactions(hcd);
- if (tr_type != DWC_OTG_TRANSACTION_NONE) {
- dwc_otg_hcd_queue_transactions(hcd, tr_type);
- }
-- DWC_SPINLOCK_FREE(channel_lock);
- }
-
- /**
-@@ -1295,6 +1852,17 @@ static int32_t handle_hc_nak_intr(dwc_ot
- "NAK Received--\n", hc->hc_num);
-
- /*
-+ * When we get bulk NAKs then remember this so we holdoff on this qh until
-+ * the beginning of the next frame
-+ */
-+ switch(dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info)) {
-+ case UE_BULK:
-+ case UE_CONTROL:
-+ if (nak_holdoff_enable)
-+ hc->qh->nak_frame = dwc_otg_hcd_get_frame_number(hcd);
-+ }
-+
-+ /*
- * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
- * interrupt. Re-start the SSPLIT transfer.
- */
-@@ -1316,7 +1884,11 @@ static int32_t handle_hc_nak_intr(dwc_ot
- * transfers in DMA mode for the sole purpose of
- * resetting the error count after a transaction error
- * occurs. The core will continue transferring data.
-+ * Disable other interrupts unmasked for the same
-+ * reason.
- */
-+ disable_hc_int(hc_regs, datatglerr);
-+ disable_hc_int(hc_regs, ack);
- qtd->error_count = 0;
- goto handle_nak_done;
- }
-@@ -1428,6 +2000,15 @@ static int32_t handle_hc_ack_intr(dwc_ot
- halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
- }
- } else {
-+ /*
-+ * An unmasked ACK on a non-split DMA transaction is
-+ * for the sole purpose of resetting error counts. Disable other
-+ * interrupts unmasked for the same reason.
-+ */
-+ if(hcd->core_if->dma_enable) {
-+ disable_hc_int(hc_regs, datatglerr);
-+ disable_hc_int(hc_regs, nak);
-+ }
- qtd->error_count = 0;
-
- if (hc->qh->ping_state) {
-@@ -1490,8 +2071,10 @@ static int32_t handle_hc_nyet_intr(dwc_o
- hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
- int frnum = dwc_otg_hcd_get_frame_number(hcd);
-
-+ // With the FIQ running we only ever see the failed NYET
- if (dwc_full_frame_num(frnum) !=
-- dwc_full_frame_num(hc->qh->sched_frame)) {
-+ dwc_full_frame_num(hc->qh->sched_frame) ||
-+ fiq_split_enable) {
- /*
- * No longer in the same full speed frame.
- * Treat this as a transaction error.
-@@ -1778,13 +2361,28 @@ static int32_t handle_hc_datatglerr_intr
- dwc_otg_qtd_t * qtd)
- {
- DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
-- "Data Toggle Error--\n", hc->hc_num);
-+ "Data Toggle Error on %s transfer--\n",
-+ hc->hc_num, (hc->ep_is_in ? "IN" : "OUT"));
-
-- if (hc->ep_is_in) {
-+ /* Data toggles on split transactions cause the hc to halt.
-+ * restart transfer */
-+ if(hc->qh->do_split)
-+ {
-+ qtd->error_count++;
-+ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
-+ update_urb_state_xfer_intr(hc, hc_regs,
-+ qtd->urb, qtd, DWC_OTG_HC_XFER_XACT_ERR);
-+ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
-+ } else if (hc->ep_is_in) {
-+ /* An unmasked data toggle error on a non-split DMA transaction is
-+ * for the sole purpose of resetting error counts. Disable other
-+ * interrupts unmasked for the same reason.
-+ */
-+ if(hcd->core_if->dma_enable) {
-+ disable_hc_int(hc_regs, ack);
-+ disable_hc_int(hc_regs, nak);
-+ }
- qtd->error_count = 0;
-- } else {
-- DWC_ERROR("Data Toggle Error on OUT transfer,"
-- "channel %d\n", hc->hc_num);
- }
-
- disable_hc_int(hc_regs, datatglerr);
-@@ -1862,10 +2460,10 @@ static inline int halt_status_ok(dwc_otg
- static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd,
- dwc_hc_t * hc,
- dwc_otg_hc_regs_t * hc_regs,
-- dwc_otg_qtd_t * qtd)
-+ dwc_otg_qtd_t * qtd,
-+ hcint_data_t hcint,
-+ hcintmsk_data_t hcintmsk)
- {
-- hcint_data_t hcint;
-- hcintmsk_data_t hcintmsk;
- int out_nak_enh = 0;
-
- /* For core with OUT NAK enhancement, the flow for high-
-@@ -1897,8 +2495,11 @@ static void handle_hc_chhltd_intr_dma(dw
- }
-
- /* Read the HCINTn register to determine the cause for the halt. */
-- hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
-- hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
-+ if(!fiq_split_enable)
-+ {
-+ hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
-+ hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
-+ }
-
- if (hcint.b.xfercomp) {
- /** @todo This is here because of a possible hardware bug. Spec
-@@ -1937,6 +2538,8 @@ static void handle_hc_chhltd_intr_dma(dw
- handle_hc_babble_intr(hcd, hc, hc_regs, qtd);
- } else if (hcint.b.frmovrun) {
- handle_hc_frmovrun_intr(hcd, hc, hc_regs, qtd);
-+ } else if (hcint.b.datatglerr) {
-+ handle_hc_datatglerr_intr(hcd, hc, hc_regs, qtd);
- } else if (!out_nak_enh) {
- if (hcint.b.nyet) {
- /*
-@@ -1986,12 +2589,24 @@ static void handle_hc_chhltd_intr_dma(dw
- DWC_READ_REG32(&hcd->
- core_if->core_global_regs->
- gintsts));
-+ /* Failthrough: use 3-strikes rule */
-+ qtd->error_count++;
-+ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
-+ update_urb_state_xfer_intr(hc, hc_regs,
-+ qtd->urb, qtd, DWC_OTG_HC_XFER_XACT_ERR);
-+ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
- }
-
- }
- } else {
- DWC_PRINTF("NYET/NAK/ACK/other in non-error case, 0x%08x\n",
- hcint.d32);
-+ /* Failthrough: use 3-strikes rule */
-+ qtd->error_count++;
-+ dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
-+ update_urb_state_xfer_intr(hc, hc_regs,
-+ qtd->urb, qtd, DWC_OTG_HC_XFER_XACT_ERR);
-+ halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
- }
- }
-
-@@ -2009,13 +2624,15 @@ static void handle_hc_chhltd_intr_dma(dw
- static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd,
- dwc_hc_t * hc,
- dwc_otg_hc_regs_t * hc_regs,
-- dwc_otg_qtd_t * qtd)
-+ dwc_otg_qtd_t * qtd,
-+ hcint_data_t hcint,
-+ hcintmsk_data_t hcintmsk)
- {
- DWC_DEBUGPL(DBG_HCDI, "--Host Channel %d Interrupt: "
- "Channel Halted--\n", hc->hc_num);
-
- if (hcd->core_if->dma_enable) {
-- handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd);
-+ handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd, hcint, hcintmsk);
- } else {
- #ifdef DEBUG
- if (!halt_status_ok(hcd, hc, hc_regs, qtd)) {
-@@ -2032,7 +2649,7 @@ static int32_t handle_hc_chhltd_intr(dwc
- int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num)
- {
- int retval = 0;
-- hcint_data_t hcint;
-+ hcint_data_t hcint, hcint_orig;
- hcintmsk_data_t hcintmsk;
- dwc_hc_t *hc;
- dwc_otg_hc_regs_t *hc_regs;
-@@ -2042,15 +2659,33 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc
-
- hc = dwc_otg_hcd->hc_ptr_array[num];
- hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[num];
-+ if(hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE) {
-+ /* We are responding to a channel disable. Driver
-+ * state is cleared - our qtd has gone away.
-+ */
-+ release_channel(dwc_otg_hcd, hc, NULL, hc->halt_status);
-+ return 1;
-+ }
- qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list);
-
- hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
-+ hcint_orig = hcint;
- hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
- DWC_DEBUGPL(DBG_HCDV,
- " hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",
- hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32));
- hcint.d32 = hcint.d32 & hcintmsk.d32;
-
-+ if(fiq_split_enable)
-+ {
-+ // replace with the saved interrupts from the fiq handler
-+ local_fiq_disable();
-+ hcint_orig.d32 = hcint_saved[num].d32;
-+ hcint.d32 = hcint_orig.d32 & hcintmsk_saved[num].d32;
-+ hcint_saved[num].d32 = 0;
-+ local_fiq_enable();
-+ }
-+
- if (!dwc_otg_hcd->core_if->dma_enable) {
- if (hcint.b.chhltd && hcint.d32 != 0x2) {
- hcint.b.chhltd = 0;
-@@ -2068,7 +2703,7 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc
- hcint.b.nyet = 0;
- }
- if (hcint.b.chhltd) {
-- retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd);
-+ retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd, hcint_orig, hcintmsk_saved[num]);
- }
- if (hcint.b.ahberr) {
- retval |= handle_hc_ahberr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
-@@ -2080,7 +2715,8 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc
- retval |= handle_hc_nak_intr(dwc_otg_hcd, hc, hc_regs, qtd);
- }
- if (hcint.b.ack) {
-- retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd);
-+ if(!hcint.b.chhltd)
-+ retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd);
- }
- if (hcint.b.nyet) {
- retval |= handle_hc_nyet_intr(dwc_otg_hcd, hc, hc_regs, qtd);
-@@ -2102,5 +2738,4 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc
-
- return retval;
- }
--
- #endif /* DWC_DEVICE_ONLY */
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
-@@ -1,3 +1,4 @@
-+
- /* ==========================================================================
- * $File: //dwh/usb_iip/dev/software/otg/linux/drivers/dwc_otg_hcd_linux.c $
- * $Revision: #20 $
-@@ -50,6 +51,7 @@
- #include <linux/dma-mapping.h>
- #include <linux/version.h>
- #include <asm/io.h>
-+#include <asm/fiq.h>
- #include <linux/usb.h>
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
- #include <../drivers/usb/core/hcd.h>
-@@ -67,6 +69,8 @@
- #include "dwc_otg_dbg.h"
- #include "dwc_otg_driver.h"
- #include "dwc_otg_hcd.h"
-+#include "dwc_otg_mphi_fix.h"
-+
- /**
- * Gets the endpoint number from a _bEndpointAddress argument. The endpoint is
- * qualified with its direction (possible 32 endpoints per device).
-@@ -76,6 +80,8 @@
-
- static const char dwc_otg_hcd_name[] = "dwc_otg_hcd";
-
-+extern bool fiq_fix_enable;
-+
- /** @name Linux HC Driver API Functions */
- /** @{ */
- /* manage i/o requests, device state */
-@@ -259,13 +265,15 @@ static void free_bus_bandwidth(struct us
-
- /**
- * Sets the final status of an URB and returns it to the device driver. Any
-- * required cleanup of the URB is performed.
-+ * required cleanup of the URB is performed. The HCD lock should be held on
-+ * entry.
- */
- static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
- dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status)
- {
- struct urb *urb = (struct urb *)urb_handle;
--
-+ urb_tq_entry_t *new_entry;
-+ int rc = 0;
- if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
- DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n",
- __func__, urb, usb_pipedevice(urb->pipe),
-@@ -279,7 +287,7 @@ static int _complete(dwc_otg_hcd_t * hcd
- }
- }
- }
--
-+ new_entry = DWC_ALLOC_ATOMIC(sizeof(urb_tq_entry_t));
- urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb);
- /* Convert status value. */
- switch (status) {
-@@ -301,6 +309,9 @@ static int _complete(dwc_otg_hcd_t * hcd
- case -DWC_E_OVERFLOW:
- status = -EOVERFLOW;
- break;
-+ case -DWC_E_SHUTDOWN:
-+ status = -ESHUTDOWN;
-+ break;
- default:
- if (status) {
- DWC_PRINTF("Uknown urb status %d\n", status);
-@@ -342,18 +353,33 @@ static int _complete(dwc_otg_hcd_t * hcd
- }
-
- DWC_FREE(dwc_otg_urb);
--
-+ if (!new_entry) {
-+ DWC_ERROR("dwc_otg_hcd: complete: cannot allocate URB TQ entry\n");
-+ urb->status = -EPROTO;
-+ /* don't schedule the tasklet -
-+ * directly return the packet here with error. */
- #if USB_URB_EP_LINKING
-- usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
-+ usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
- #endif
-- DWC_SPINUNLOCK(hcd->lock);
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-- usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb);
-+ usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb);
- #else
-- usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, status);
-+ usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, urb->status);
- #endif
-- DWC_SPINLOCK(hcd->lock);
--
-+ } else {
-+ new_entry->urb = urb;
-+#if USB_URB_EP_LINKING
-+ rc = usb_hcd_check_unlink_urb(dwc_otg_hcd_to_hcd(hcd), urb, urb->status);
-+ if(0 == rc) {
-+ usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
-+ }
-+#endif
-+ if(0 == rc) {
-+ DWC_TAILQ_INSERT_TAIL(&hcd->completed_urb_list, new_entry,
-+ urb_tq_entries);
-+ DWC_TASK_HI_SCHEDULE(hcd->completion_tasklet);
-+ }
-+ }
- return 0;
- }
-
-@@ -366,6 +392,16 @@ static struct dwc_otg_hcd_function_ops h
- .get_b_hnp_enable = _get_b_hnp_enable,
- };
-
-+static struct fiq_handler fh = {
-+ .name = "usb_fiq",
-+};
-+struct fiq_stack_s {
-+ int magic1;
-+ uint8_t stack[2048];
-+ int magic2;
-+} fiq_stack;
-+
-+extern mphi_regs_t c_mphi_regs;
- /**
- * Initializes the HCD. This function allocates memory for and initializes the
- * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the
-@@ -379,6 +415,7 @@ int hcd_init(dwc_bus_dev_t *_dev)
- dwc_otg_device_t *otg_dev = DWC_OTG_BUSDRVDATA(_dev);
- int retval = 0;
- u64 dmamask;
-+ struct pt_regs regs;
-
- DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT otg_dev=%p\n", otg_dev);
-
-@@ -396,6 +433,20 @@ int hcd_init(dwc_bus_dev_t *_dev)
- pci_set_consistent_dma_mask(_dev, dmamask);
- #endif
-
-+ if (fiq_fix_enable)
-+ {
-+ // Set up fiq
-+ claim_fiq(&fh);
-+ set_fiq_handler(__FIQ_Branch, 4);
-+ memset(&regs,0,sizeof(regs));
-+ regs.ARM_r8 = (long)dwc_otg_hcd_handle_fiq;
-+ regs.ARM_r9 = (long)0;
-+ regs.ARM_sp = (long)fiq_stack.stack + sizeof(fiq_stack.stack) - 4;
-+ set_fiq_regs(&regs);
-+ fiq_stack.magic1 = 0xdeadbeef;
-+ fiq_stack.magic2 = 0xaa995566;
-+ }
-+
- /*
- * Allocate memory for the base HCD plus the DWC OTG HCD.
- * Initialize the base HCD.
-@@ -415,6 +466,30 @@ int hcd_init(dwc_bus_dev_t *_dev)
-
- hcd->regs = otg_dev->os_dep.base;
-
-+ if (fiq_fix_enable)
-+ {
-+ volatile extern void *dwc_regs_base;
-+
-+ //Set the mphi periph to the required registers
-+ c_mphi_regs.base = otg_dev->os_dep.mphi_base;
-+ c_mphi_regs.ctrl = otg_dev->os_dep.mphi_base + 0x4c;
-+ c_mphi_regs.outdda = otg_dev->os_dep.mphi_base + 0x28;
-+ c_mphi_regs.outddb = otg_dev->os_dep.mphi_base + 0x2c;
-+ c_mphi_regs.intstat = otg_dev->os_dep.mphi_base + 0x50;
-+
-+ dwc_regs_base = otg_dev->os_dep.base;
-+
-+ //Enable mphi peripheral
-+ writel((1<<31),c_mphi_regs.ctrl);
-+#ifdef DEBUG
-+ if (readl(c_mphi_regs.ctrl) & 0x80000000)
-+ DWC_DEBUGPL(DBG_USER, "MPHI periph has been enabled\n");
-+ else
-+ DWC_DEBUGPL(DBG_USER, "MPHI periph has NOT been enabled\n");
-+#endif
-+ // Enable FIQ interrupt from USB peripheral
-+ enable_fiq(INTERRUPT_VC_USB);
-+ }
- /* Initialize the DWC OTG HCD. */
- dwc_otg_hcd = dwc_otg_hcd_alloc_hcd();
- if (!dwc_otg_hcd) {
-@@ -607,9 +682,7 @@ static int dwc_otg_urb_enqueue(struct us
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
- struct usb_host_endpoint *ep = urb->ep;
- #endif
--#if USB_URB_EP_LINKING
- dwc_irqflags_t irqflags;
--#endif
- void **ref_ep_hcpriv = &ep->hcpriv;
- dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
- dwc_otg_hcd_urb_t *dwc_otg_urb;
-@@ -661,9 +734,8 @@ static int dwc_otg_urb_enqueue(struct us
- if(dwc_otg_urb == NULL)
- return -ENOMEM;
-
-- urb->hcpriv = dwc_otg_urb;
-- if (!dwc_otg_urb && urb->number_of_packets)
-- return -ENOMEM;
-+ if (!dwc_otg_urb && urb->number_of_packets)
-+ return -ENOMEM;
-
- dwc_otg_hcd_urb_set_pipeinfo(dwc_otg_urb, usb_pipedevice(urb->pipe),
- usb_pipeendpoint(urb->pipe), ep_type,
-@@ -703,37 +775,42 @@ static int dwc_otg_urb_enqueue(struct us
- iso_frame_desc[i].length);
- }
-
-+ DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
-+ urb->hcpriv = dwc_otg_urb;
- #if USB_URB_EP_LINKING
-- DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
- retval = usb_hcd_link_urb_to_ep(hcd, urb);
-- DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
- if (0 == retval)
- #endif
-- {
-- retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb,
-- /*(dwc_otg_qh_t **)*/
-- ref_ep_hcpriv,
-- mem_flags == GFP_ATOMIC ? 1 : 0);
-- if (0 == retval) {
-- if (alloc_bandwidth) {
-- allocate_bus_bandwidth(hcd,
-- dwc_otg_hcd_get_ep_bandwidth(
-- dwc_otg_hcd, *ref_ep_hcpriv),
-- urb);
-- }
-- } else {
-+ {
-+ retval = dwc_otg_hcd_urb_enqueue(dwc_otg_hcd, dwc_otg_urb,
-+ /*(dwc_otg_qh_t **)*/
-+ ref_ep_hcpriv, 1);
-+ if (0 == retval) {
-+ if (alloc_bandwidth) {
-+ allocate_bus_bandwidth(hcd,
-+ dwc_otg_hcd_get_ep_bandwidth(
-+ dwc_otg_hcd, *ref_ep_hcpriv),
-+ urb);
-+ }
-+ } else {
-+ DWC_DEBUGPL(DBG_HCD, "DWC OTG dwc_otg_hcd_urb_enqueue failed rc %d\n", retval);
- #if USB_URB_EP_LINKING
-- dwc_irqflags_t irqflags;
-- DWC_DEBUGPL(DBG_HCD, "DWC OTG dwc_otg_hcd_urb_enqueue failed rc %d\n", retval);
-- DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &irqflags);
-- usb_hcd_unlink_urb_from_ep(hcd, urb);
-- DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
--#endif
-- if (retval == -DWC_E_NO_DEVICE) {
-- retval = -ENODEV;
-- }
-- }
-- }
-+ usb_hcd_unlink_urb_from_ep(hcd, urb);
-+#endif
-+ DWC_FREE(dwc_otg_urb);
-+ urb->hcpriv = NULL;
-+ if (retval == -DWC_E_NO_DEVICE)
-+ retval = -ENODEV;
-+ }
-+ }
-+#if USB_URB_EP_LINKING
-+ else
-+ {
-+ DWC_FREE(dwc_otg_urb);
-+ urb->hcpriv = NULL;
-+ }
-+#endif
-+ DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, irqflags);
- return retval;
- }
-
-@@ -777,6 +854,8 @@ static int dwc_otg_urb_dequeue(struct us
- usb_hcd_unlink_urb_from_ep(hcd, urb);
- #endif
- DWC_SPINUNLOCK_IRQRESTORE(dwc_otg_hcd->lock, flags);
-+
-+
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
- usb_hcd_giveback_urb(hcd, urb);
- #else
---- a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
-@@ -41,6 +41,7 @@
-
- #include "dwc_otg_hcd.h"
- #include "dwc_otg_regs.h"
-+#include "dwc_otg_mphi_fix.h"
-
- extern bool microframe_schedule;
-
-@@ -182,6 +183,7 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_ot
- if (microframe_schedule)
- qh->speed = dev_speed;
-
-+ qh->nak_frame = 0xffff;
-
- if (((dev_speed == USB_SPEED_LOW) ||
- (dev_speed == USB_SPEED_FULL)) &&
-@@ -191,6 +193,7 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_ot
- dwc_otg_hcd_get_ep_num(&urb->pipe_info), hub_addr,
- hub_port);
- qh->do_split = 1;
-+ qh->skip_count = 0;
- }
-
- if (qh->ep_type == UE_INTERRUPT || qh->ep_type == UE_ISOCHRONOUS) {
-@@ -573,6 +576,9 @@ static int check_max_xfer_size(dwc_otg_h
- return status;
- }
-
-+
-+extern int g_next_sched_frame, g_np_count, g_np_sent;
-+
- /**
- * Schedules an interrupt or isochronous transfer in the periodic schedule.
- *
-@@ -631,8 +637,13 @@ static int schedule_periodic(dwc_otg_hcd
- DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry);
- }
- else {
-- /* Always start in the inactive schedule. */
-- DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry);
-+ if(DWC_LIST_EMPTY(&hcd->periodic_sched_inactive) || dwc_frame_num_le(qh->sched_frame, g_next_sched_frame))
-+ {
-+ g_next_sched_frame = qh->sched_frame;
-+
-+ }
-+ /* Always start in the inactive schedule. */
-+ DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_inactive, &qh->qh_list_entry);
- }
-
- if (!microframe_schedule) {
-@@ -646,6 +657,7 @@ static int schedule_periodic(dwc_otg_hcd
- return status;
- }
-
-+
- /**
- * This function adds a QH to either the non periodic or periodic schedule if
- * it is not already in the schedule. If the QH is already in the schedule, no
-@@ -668,6 +680,7 @@ int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * h
- /* Always start in the inactive schedule. */
- DWC_LIST_INSERT_TAIL(&hcd->non_periodic_sched_inactive,
- &qh->qh_list_entry);
-+ g_np_count++;
- } else {
- status = schedule_periodic(hcd, qh);
- if ( !hcd->periodic_qh_count ) {
-@@ -727,6 +740,9 @@ void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t
- hcd->non_periodic_qh_ptr->next;
- }
- DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
-+
-+ // If we've removed the last non-periodic entry then there are none left!
-+ g_np_count = g_np_sent;
- } else {
- deschedule_periodic(hcd, qh);
- hcd->periodic_qh_count--;
-@@ -755,6 +771,24 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_h
- int sched_next_periodic_split)
- {
- if (dwc_qh_is_non_per(qh)) {
-+
-+ dwc_otg_qh_t *qh_tmp;
-+ dwc_list_link_t *qh_list;
-+ DWC_LIST_FOREACH(qh_list, &hcd->non_periodic_sched_inactive)
-+ {
-+ qh_tmp = DWC_LIST_ENTRY(qh_list, struct dwc_otg_qh, qh_list_entry);
-+ if(qh_tmp == qh)
-+ {
-+ /*
-+ * FIQ is being disabled because this one nevers gets a np_count increment
-+ * This is still not absolutely correct, but it should fix itself with
-+ * just an unnecessary extra interrupt
-+ */
-+ g_np_sent = g_np_count;
-+ }
-+ }
-+
-+
- dwc_otg_hcd_qh_remove(hcd, qh);
- if (!DWC_CIRCLEQ_EMPTY(&qh->qtd_list)) {
- /* Add back to inactive non-periodic schedule. */
-@@ -768,6 +802,7 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_h
- if (sched_next_periodic_split) {
-
- qh->sched_frame = frame_number;
-+
- if (dwc_frame_num_le(frame_number,
- dwc_frame_num_inc
- (qh->start_split_frame,
-@@ -816,6 +851,11 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_h
- DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
- &qh->qh_list_entry);
- } else {
-+ if(!dwc_frame_num_le(g_next_sched_frame, qh->sched_frame))
-+ {
-+ g_next_sched_frame = qh->sched_frame;
-+ }
-+
- DWC_LIST_MOVE_HEAD
- (&hcd->periodic_sched_inactive,
- &qh->qh_list_entry);
-@@ -880,6 +920,7 @@ void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t
- * QH to place the QTD into. If it does not find a QH, then it will create a
- * new QH. If the QH to which the QTD is added is not currently scheduled, it
- * is placed into the proper schedule based on its EP type.
-+ * HCD lock must be held and interrupts must be disabled on entry
- *
- * @param[in] qtd The QTD to add
- * @param[in] hcd The DWC HCD structure
-@@ -892,8 +933,6 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t *
- dwc_otg_hcd_t * hcd, dwc_otg_qh_t ** qh, int atomic_alloc)
- {
- int retval = 0;
-- dwc_irqflags_t flags;
--
- dwc_otg_hcd_urb_t *urb = qtd->urb;
-
- /*
-@@ -903,18 +942,16 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t *
- if (*qh == NULL) {
- *qh = dwc_otg_hcd_qh_create(hcd, urb, atomic_alloc);
- if (*qh == NULL) {
-- retval = -1;
-+ retval = -DWC_E_NO_MEMORY;
- goto done;
- }
- }
-- DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
- retval = dwc_otg_hcd_qh_add(hcd, *qh);
- if (retval == 0) {
- DWC_CIRCLEQ_INSERT_TAIL(&((*qh)->qtd_list), qtd,
- qtd_list_entry);
-+ qtd->qh = *qh;
- }
-- DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
--
- done:
-
- return retval;
---- /dev/null
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.c
-@@ -0,0 +1,113 @@
-+#include "dwc_otg_regs.h"
-+#include "dwc_otg_dbg.h"
-+
-+void dwc_debug_print_core_int_reg(gintsts_data_t gintsts, const char* function_name)
-+{
-+ DWC_DEBUGPL(DBG_USER, "*** Debugging from within the %s function: ***\n"
-+ "curmode: %1i Modemismatch: %1i otgintr: %1i sofintr: %1i\n"
-+ "rxstsqlvl: %1i nptxfempty : %1i ginnakeff: %1i goutnakeff: %1i\n"
-+ "ulpickint: %1i i2cintr: %1i erlysuspend:%1i usbsuspend: %1i\n"
-+ "usbreset: %1i enumdone: %1i isooutdrop: %1i eopframe: %1i\n"
-+ "restoredone: %1i epmismatch: %1i inepint: %1i outepintr: %1i\n"
-+ "incomplisoin:%1i incomplisoout:%1i fetsusp: %1i resetdet: %1i\n"
-+ "portintr: %1i hcintr: %1i ptxfempty: %1i lpmtranrcvd:%1i\n"
-+ "conidstschng:%1i disconnect: %1i sessreqintr:%1i wkupintr: %1i\n",
-+ function_name,
-+ gintsts.b.curmode,
-+ gintsts.b.modemismatch,
-+ gintsts.b.otgintr,
-+ gintsts.b.sofintr,
-+ gintsts.b.rxstsqlvl,
-+ gintsts.b.nptxfempty,
-+ gintsts.b.ginnakeff,
-+ gintsts.b.goutnakeff,
-+ gintsts.b.ulpickint,
-+ gintsts.b.i2cintr,
-+ gintsts.b.erlysuspend,
-+ gintsts.b.usbsuspend,
-+ gintsts.b.usbreset,
-+ gintsts.b.enumdone,
-+ gintsts.b.isooutdrop,
-+ gintsts.b.eopframe,
-+ gintsts.b.restoredone,
-+ gintsts.b.epmismatch,
-+ gintsts.b.inepint,
-+ gintsts.b.outepintr,
-+ gintsts.b.incomplisoin,
-+ gintsts.b.incomplisoout,
-+ gintsts.b.fetsusp,
-+ gintsts.b.resetdet,
-+ gintsts.b.portintr,
-+ gintsts.b.hcintr,
-+ gintsts.b.ptxfempty,
-+ gintsts.b.lpmtranrcvd,
-+ gintsts.b.conidstschng,
-+ gintsts.b.disconnect,
-+ gintsts.b.sessreqintr,
-+ gintsts.b.wkupintr);
-+ return;
-+}
-+
-+void dwc_debug_core_int_mask(gintmsk_data_t gintmsk, const char* function_name)
-+{
-+ DWC_DEBUGPL(DBG_USER, "Interrupt Mask status (called from %s) :\n"
-+ "modemismatch: %1i otgintr: %1i sofintr: %1i rxstsqlvl: %1i\n"
-+ "nptxfempty: %1i ginnakeff: %1i goutnakeff: %1i ulpickint: %1i\n"
-+ "i2cintr: %1i erlysuspend:%1i usbsuspend: %1i usbreset: %1i\n"
-+ "enumdone: %1i isooutdrop: %1i eopframe: %1i restoredone: %1i\n"
-+ "epmismatch: %1i inepintr: %1i outepintr: %1i incomplisoin:%1i\n"
-+ "incomplisoout:%1i fetsusp: %1i resetdet: %1i portintr: %1i\n"
-+ "hcintr: %1i ptxfempty: %1i lpmtranrcvd:%1i conidstschng:%1i\n"
-+ "disconnect: %1i sessreqintr:%1i wkupintr: %1i\n",
-+ function_name,
-+ gintmsk.b.modemismatch,
-+ gintmsk.b.otgintr,
-+ gintmsk.b.sofintr,
-+ gintmsk.b.rxstsqlvl,
-+ gintmsk.b.nptxfempty,
-+ gintmsk.b.ginnakeff,
-+ gintmsk.b.goutnakeff,
-+ gintmsk.b.ulpickint,
-+ gintmsk.b.i2cintr,
-+ gintmsk.b.erlysuspend,
-+ gintmsk.b.usbsuspend,
-+ gintmsk.b.usbreset,
-+ gintmsk.b.enumdone,
-+ gintmsk.b.isooutdrop,
-+ gintmsk.b.eopframe,
-+ gintmsk.b.restoredone,
-+ gintmsk.b.epmismatch,
-+ gintmsk.b.inepintr,
-+ gintmsk.b.outepintr,
-+ gintmsk.b.incomplisoin,
-+ gintmsk.b.incomplisoout,
-+ gintmsk.b.fetsusp,
-+ gintmsk.b.resetdet,
-+ gintmsk.b.portintr,
-+ gintmsk.b.hcintr,
-+ gintmsk.b.ptxfempty,
-+ gintmsk.b.lpmtranrcvd,
-+ gintmsk.b.conidstschng,
-+ gintmsk.b.disconnect,
-+ gintmsk.b.sessreqintr,
-+ gintmsk.b.wkupintr);
-+ return;
-+}
-+
-+void dwc_debug_otg_int(gotgint_data_t gotgint, const char* function_name)
-+{
-+ DWC_DEBUGPL(DBG_USER, "otg int register (from %s function):\n"
-+ "sesenddet:%1i sesreqsucstschung:%2i hstnegsucstschng:%1i\n"
-+ "hstnegdet:%1i adevtoutchng: %2i debdone: %1i\n"
-+ "mvic: %1i\n",
-+ function_name,
-+ gotgint.b.sesenddet,
-+ gotgint.b.sesreqsucstschng,
-+ gotgint.b.hstnegsucstschng,
-+ gotgint.b.hstnegdet,
-+ gotgint.b.adevtoutchng,
-+ gotgint.b.debdone,
-+ gotgint.b.mvic);
-+
-+ return;
-+}
---- /dev/null
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h
-@@ -0,0 +1,48 @@
-+#ifndef __DWC_OTG_MPHI_FIX_H__
-+#define __DWC_OTG_MPHI_FIX_H__
-+#define FIQ_WRITE(_addr_,_data_) (*(volatile uint32_t *) (_addr_) = (_data_))
-+#define FIQ_READ(_addr_) (*(volatile uint32_t *) (_addr_))
-+
-+typedef struct {
-+ volatile void* base;
-+ volatile void* ctrl;
-+ volatile void* outdda;
-+ volatile void* outddb;
-+ volatile void* intstat;
-+} mphi_regs_t;
-+
-+void dwc_debug_print_core_int_reg(gintsts_data_t gintsts, const char* function_name);
-+void dwc_debug_core_int_mask(gintsts_data_t gintmsk, const char* function_name);
-+void dwc_debug_otg_int(gotgint_data_t gotgint, const char* function_name);
-+
-+extern gintsts_data_t gintsts_saved;
-+
-+#ifdef DEBUG
-+#define DWC_DBG_PRINT_CORE_INT(_arg_) dwc_debug_print_core_int_reg(_arg_,__func__)
-+#define DWC_DBG_PRINT_CORE_INT_MASK(_arg_) dwc_debug_core_int_mask(_arg_,__func__)
-+#define DWC_DBG_PRINT_OTG_INT(_arg_) dwc_debug_otg_int(_arg_,__func__)
-+
-+#else
-+#define DWC_DBG_PRINT_CORE_INT(_arg_)
-+#define DWC_DBG_PRINT_CORE_INT_MASK(_arg_)
-+#define DWC_DBG_PRINT_OTG_INT(_arg_)
-+
-+#endif
-+
-+typedef enum {
-+ FIQDBG_SCHED = (1 << 0),
-+ FIQDBG_INT = (1 << 1),
-+ FIQDBG_ERR = (1 << 2),
-+ FIQDBG_PORTHUB = (1 << 3),
-+} FIQDBG_T;
-+
-+void _fiq_print(FIQDBG_T dbg_lvl, char *fmt, ...);
-+#ifdef FIQ_DEBUG
-+#define fiq_print _fiq_print
-+#else
-+#define fiq_print(x, y, ...)
-+#endif
-+
-+extern bool fiq_fix_enable, nak_holdoff_enable, fiq_split_enable;
-+
-+#endif
---- a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
-@@ -97,6 +97,9 @@ typedef struct os_dependent {
- /** Register offset for Diagnostic API */
- uint32_t reg_offset;
-
-+ /** Base address for MPHI peripheral */
-+ void *mphi_base;
-+
- #ifdef LM_INTERFACE
- struct lm_device *lmdev;
- #elif defined(PCI_INTERFACE)
---- a/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c
-+++ b/drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c
-@@ -4276,7 +4276,7 @@ do { \
- && (pcd->ep0state == EP0_OUT_DATA_PHASE))
- status.d32 = core_if->dev_if->out_desc_addr->status.d32;
- if (pcd->ep0state == EP0_OUT_STATUS_PHASE)
-- status.d32 = status.d32 = core_if->dev_if->
-+ status.d32 = core_if->dev_if->
- out_desc_addr->status.d32;
-
- if (status.b.sr) {