mirror of
https://github.com/hardkernel/linux.git
synced 2026-03-24 19:40:21 +09:00
Revert "C1: USB FIQ driver (Not ready)"
This commit is contained in:
@@ -110,7 +110,6 @@ void root_func(){
|
||||
reg = <0xc4301000 0x1000
|
||||
0xc4300100 0x0100>;
|
||||
interrupt-controller;
|
||||
gic_fiq_enable;
|
||||
#interrupt-cells = <3>;
|
||||
#address-cells = <0>;
|
||||
};
|
||||
@@ -876,7 +875,6 @@ sdio{
|
||||
port-config = <0>; /** 0: default */
|
||||
port-dma = <0>; /** 0: default, 1: single, 2: incr, 3: incr4, 4: incr8, 5: incr16, 6: disable*/
|
||||
port-id-mode = <1>; /** 0: hardware, 1: sw_host, 2: sw_slave*/
|
||||
fiq_use = <1>; /**0:no use 1: use**/
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
@@ -110,7 +110,6 @@ void root_func(){
|
||||
reg = <0xc4301000 0x1000
|
||||
0xc4300100 0x0100>;
|
||||
interrupt-controller;
|
||||
gic_fiq_enable;
|
||||
#interrupt-cells = <3>;
|
||||
#address-cells = <0>;
|
||||
};
|
||||
@@ -864,7 +863,6 @@ sdio{
|
||||
port-config = <0>; /** 0: default */
|
||||
port-dma = <0>; /** 0: default, 1: single, 2: incr, 3: incr4, 4: incr8, 5: incr16, 6: disable*/
|
||||
port-id-mode = <1>; /** 0: hardware, 1: sw_host, 2: sw_slave*/
|
||||
fiq_use = <1>; /**0:no use 1: use**/
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
@@ -99,7 +99,6 @@ void root_func(){
|
||||
reg = <0xc4301000 0x1000
|
||||
0xc4300100 0x0100>;
|
||||
interrupt-controller;
|
||||
gic_fiq_enable;
|
||||
#interrupt-cells = <3>;
|
||||
#address-cells = <0>;
|
||||
};
|
||||
@@ -853,7 +852,6 @@ void root_func(){
|
||||
port-config = <0>; /** 0: default */
|
||||
port-dma = <0>; /** 0: default, 1: single, 2: incr, 3: incr4, 4: incr8, 5: incr16, 6: disable*/
|
||||
port-id-mode = <1>; /** 0: hardware, 1: sw_host, 2: sw_slave*/
|
||||
fiq_use = <1>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
@@ -69,7 +69,6 @@
|
||||
reg = <0xc4301000 0x1000
|
||||
0xc4300100 0x0100>;
|
||||
interrupt-controller;
|
||||
gic_fiq_enable;
|
||||
#interrupt-cells = <3>;
|
||||
#address-cells = <0>;
|
||||
};
|
||||
@@ -366,7 +365,6 @@
|
||||
port-dma = <0>; /** 0: default, 1: single, 2: incr, 3: incr4, 4: incr8, 5: incr16, 6: disable*/
|
||||
port-id-mode = <1>; /** 0: hardware, 1: sw_host, 2: sw_slave*/
|
||||
gpio-hub-rst = "GPIOAO_4";
|
||||
fiq_use = <1>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
@@ -526,7 +526,6 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
|
||||
# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
|
||||
CONFIG_AMLOGIC_MESON_CPUFREQ=y
|
||||
CONFIG_FIX_SYSPLL=y
|
||||
CONFIG_MESON_GIC_FIQ=y
|
||||
# CONFIG_CPU_IDLE is not set
|
||||
# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
|
||||
|
||||
|
||||
2
arch/arm/include/asm/fiq.h
Executable file → Normal file
2
arch/arm/include/asm/fiq.h
Executable file → Normal file
@@ -38,12 +38,10 @@ extern void release_fiq(struct fiq_handler *f);
|
||||
extern void set_fiq_handler(void *start, unsigned int length);
|
||||
extern void enable_fiq(int fiq);
|
||||
extern void disable_fiq(int fiq);
|
||||
extern int get_fiq_index(void);
|
||||
|
||||
/* helpers defined in fiqasm.S: */
|
||||
extern void __set_fiq_regs(unsigned long const *regs);
|
||||
extern void __get_fiq_regs(unsigned long *regs);
|
||||
extern void __FIQ_Branch(unsigned long *regs);
|
||||
|
||||
static inline void set_fiq_regs(struct pt_regs const *regs)
|
||||
{
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
#define GIC_DIST_CTRL 0x000
|
||||
#define GIC_DIST_CTR 0x004
|
||||
#define GIC_DIST_IGROUP 0x080
|
||||
#define GIC_DIST_ENABLE_SET 0x100
|
||||
#define GIC_DIST_ENABLE_CLEAR 0x180
|
||||
#define GIC_DIST_PENDING_SET 0x200
|
||||
|
||||
9
arch/arm/kernel/fiq.c
Executable file → Normal file
9
arch/arm/kernel/fiq.c
Executable file → Normal file
@@ -53,7 +53,6 @@
|
||||
})
|
||||
|
||||
static unsigned long no_fiq_insn;
|
||||
static int fiqno = 0x4000;
|
||||
|
||||
/* Default reacquire function
|
||||
* - we always relinquish FIQ control
|
||||
@@ -135,19 +134,12 @@ static int fiq_start;
|
||||
|
||||
void enable_fiq(int fiq)
|
||||
{
|
||||
fiqno = fiq;
|
||||
enable_irq(fiq + fiq_start);
|
||||
}
|
||||
|
||||
void disable_fiq(int fiq)
|
||||
{
|
||||
disable_irq(fiq + fiq_start);
|
||||
fiqno = 0x4000;
|
||||
}
|
||||
|
||||
int get_fiq_index(void)
|
||||
{
|
||||
return fiqno;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(set_fiq_handler);
|
||||
@@ -157,7 +149,6 @@ EXPORT_SYMBOL(claim_fiq);
|
||||
EXPORT_SYMBOL(release_fiq);
|
||||
EXPORT_SYMBOL(enable_fiq);
|
||||
EXPORT_SYMBOL(disable_fiq);
|
||||
EXPORT_SYMBOL(get_fiq_index);
|
||||
|
||||
void __init init_FIQ(int start)
|
||||
{
|
||||
|
||||
@@ -25,9 +25,6 @@
|
||||
ENTRY(__set_fiq_regs)
|
||||
mov r2, #PSR_I_BIT | PSR_F_BIT | FIQ_MODE
|
||||
mrs r1, cpsr
|
||||
@@@@@@@@@@@@@@@ hack: enable the fiq here to keep usb driver happy
|
||||
and r1, #~PSR_F_BIT
|
||||
@@@@@@@@@@@@@@@ endhack: (need to find better place for this to happen)
|
||||
msr cpsr_c, r2 @ select FIQ mode
|
||||
mov r0, r0 @ avoid hazard prior to ARMv4
|
||||
ldmia r0!, {r8 - r12}
|
||||
@@ -50,21 +47,3 @@ ENTRY(__get_fiq_regs)
|
||||
mov r0, r0 @ avoid hazard prior to ARMv4
|
||||
mov pc, lr
|
||||
ENDPROC(__get_fiq_regs)
|
||||
|
||||
ENTRY(__FIQ_Branch)
|
||||
mov pc, r8
|
||||
ENDPROC(__FIQ_Branch)
|
||||
|
||||
ENTRY(__fiq_ll_setup)
|
||||
stmdb sp!, {r4}
|
||||
mrs r4, cpsr
|
||||
@ and r4, #~PSR_F_BIT
|
||||
msr cpsr_c, #(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)
|
||||
mov r8, r0
|
||||
mov r9, r1
|
||||
mov fp, r2
|
||||
mov sp, r3
|
||||
msr cpsr_c, r4
|
||||
ldmia sp!, {r4}
|
||||
mov pc, lr
|
||||
ENDPROC(__fiq_ll_setup)
|
||||
|
||||
@@ -70,10 +70,4 @@ config GPIO_TEST
|
||||
help
|
||||
support gpio group test
|
||||
|
||||
config MESON_GIC_FIQ
|
||||
bool "MESON support GIC FIQ"
|
||||
default n
|
||||
depends on FIQ
|
||||
help
|
||||
support GIC FIQ
|
||||
endif # ARCH_MESON8
|
||||
|
||||
@@ -193,7 +193,7 @@
|
||||
|
||||
|
||||
/* All interrupts are FIQ capable */
|
||||
#define FIQ_START 0
|
||||
#define FIQ_START AM_IRQ0(0)
|
||||
extern void request_fiq(unsigned fiq, void (*isr)(void));
|
||||
extern void free_fiq(unsigned fiq, void (*isr)(void));
|
||||
|
||||
|
||||
@@ -24,13 +24,6 @@ config MESON_TRUSTZONE
|
||||
default n
|
||||
help
|
||||
Enable ARM Trustzone secure extension
|
||||
|
||||
config MESON_GIC_FIQ
|
||||
bool "MESON support GIC FIQ"
|
||||
default n
|
||||
depends on FIQ
|
||||
help
|
||||
support GIC FIQ
|
||||
endif # ARCH_MESON8
|
||||
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@
|
||||
|
||||
|
||||
/* All interrupts are FIQ capable */
|
||||
#define FIQ_START 0
|
||||
#define FIQ_START AM_IRQ0(0)
|
||||
extern void request_fiq(unsigned fiq, void (*isr)(void));
|
||||
extern void free_fiq(unsigned fiq, void (*isr)(void));
|
||||
|
||||
|
||||
22
arch/arm/plat-meson/gic-irq.c
Executable file → Normal file
22
arch/arm/plat-meson/gic-irq.c
Executable file → Normal file
@@ -31,7 +31,6 @@
|
||||
#include <asm/mach/time.h>
|
||||
#include <asm/mach/irq.h>
|
||||
#include <asm/hardware/gic.h>
|
||||
#include <asm/fiq.h>
|
||||
#include <plat/io.h>
|
||||
#include <mach/io.h>
|
||||
#ifdef CONFIG_OF
|
||||
@@ -49,20 +48,19 @@ static void meson_gic_unmask(struct irq_data *data)
|
||||
* Set irq to edge rising and proi to low
|
||||
*/
|
||||
uint32_t dist_base=(uint32_t)(IO_PERIPH_BASE+0x1000);
|
||||
int edge = 0x3;//edge
|
||||
int irq=data->irq;
|
||||
int edge = 0x3;//edge
|
||||
|
||||
int irq=data->irq;
|
||||
if(irq<32)
|
||||
return;
|
||||
|
||||
if(irq >= FIQ_START)
|
||||
irq -= FIQ_START;
|
||||
/**
|
||||
* Deal with IRQ type: IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH
|
||||
*/
|
||||
if(data->state_use_accessors & IRQ_TYPE_LEVEL_MASK)
|
||||
edge = 0x1;//level
|
||||
|
||||
if((irq == 62)||(irq == 63))
|
||||
if((irq == 62)||(irq == 63))
|
||||
edge = 0x1;//level
|
||||
|
||||
/**
|
||||
@@ -72,15 +70,10 @@ static void meson_gic_unmask(struct irq_data *data)
|
||||
/**
|
||||
* Set prority
|
||||
*/
|
||||
|
||||
aml_set_reg32_bits(dist_base+GIC_DIST_PRI + (irq / 4)* 4,0xff,(irq%4)*8,irq_level);
|
||||
|
||||
if(data->irq == get_fiq_index())
|
||||
aml_set_reg32_bits(dist_base + GIC_DIST_IGROUP + (irq / 32) * 4, 0, (irq%32), 1);
|
||||
else
|
||||
aml_set_reg32_bits(dist_base + GIC_DIST_IGROUP + (irq / 32) * 4, 1, (irq%32), 1);
|
||||
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id mesnon_dt_irq_match[] __initconst = {
|
||||
{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init },
|
||||
@@ -99,8 +92,9 @@ void __init meson_init_gic_irq(void)
|
||||
|
||||
aml_write_reg32(IO_PERIPH_BASE+0x100 +GIC_CPU_PRIMASK,0xff);
|
||||
|
||||
#ifdef CONFIG_MESON_GIC_FIQ
|
||||
init_FIQ(FIQ_START);
|
||||
#ifdef CONFIG_MESON_ARM_GIC_FIQ
|
||||
extern void init_fiq(void) ;
|
||||
init_fiq();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,6 @@ $(DWC_OTG_NAME)-objs += dwc_otg_cil.o dwc_otg_cil_intr.o
|
||||
$(DWC_OTG_NAME)-objs += dwc_otg_pcd_linux.o dwc_otg_pcd.o dwc_otg_pcd_intr.o
|
||||
$(DWC_OTG_NAME)-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_NAME)-objs += dwc_otg_adp.o
|
||||
$(DWC_OTG_NAME)-objs += dwc_otg_fiq_fsm.o
|
||||
$(DWC_OTG_NAME)-objs += dwc_otg_fiq_stub.o
|
||||
ifneq ($(CFI),)
|
||||
$(DWC_OTG_NAME)-objs += dwc_otg_cfi.o
|
||||
endif
|
||||
|
||||
@@ -580,13 +580,7 @@ void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value)
|
||||
|
||||
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
|
||||
@@ -997,11 +991,6 @@ void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
|
||||
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)
|
||||
|
||||
@@ -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) \
|
||||
(DWC_TAILQ_FIRST(head) == DWC_TAILQ_END(head))
|
||||
(TAILQ_FIRST(head) == TAILQ_END(head))
|
||||
|
||||
#define DWC_TAILQ_FOREACH(var, head, field) \
|
||||
for ((var) = DWC_TAILQ_FIRST(head); \
|
||||
(var) != DWC_TAILQ_END(head); \
|
||||
(var) = DWC_TAILQ_NEXT(var, field))
|
||||
for((var) = TAILQ_FIRST(head); \
|
||||
(var) != TAILQ_END(head); \
|
||||
(var) = TAILQ_NEXT(var, field))
|
||||
|
||||
#define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||
for ((var) = DWC_TAILQ_LAST(head, headname); \
|
||||
(var) != DWC_TAILQ_END(head); \
|
||||
(var) = DWC_TAILQ_PREV(var, headname, field))
|
||||
for((var) = TAILQ_LAST(head, headname); \
|
||||
(var) != TAILQ_END(head); \
|
||||
(var) = TAILQ_PREV(var, headname, field))
|
||||
|
||||
/*
|
||||
* Tail queue functions.
|
||||
|
||||
@@ -960,8 +960,6 @@ extern void DWC_TASK_FREE(dwc_tasklet_t *task);
|
||||
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
|
||||
*
|
||||
|
||||
0
drivers/amlogic/usb/dwc_otg/310/dwc_otg_adp.c
Executable file → Normal file
0
drivers/amlogic/usb/dwc_otg/310/dwc_otg_adp.c
Executable file → Normal file
0
drivers/amlogic/usb/dwc_otg/310/dwc_otg_attr.c
Executable file → Normal file
0
drivers/amlogic/usb/dwc_otg/310/dwc_otg_attr.c
Executable file → Normal file
6
drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.c
Executable file → Normal file
6
drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.c
Executable file → Normal file
@@ -2444,9 +2444,9 @@ void dwc_otg_hc_init(dwc_otg_core_if_t * core_if, dwc_hc_t * hc)
|
||||
hcchar.b.epnum = hc->ep_num;
|
||||
hcchar.b.epdir = hc->ep_is_in;
|
||||
hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
|
||||
//if((hc->ep_type == DWC_OTG_EP_TYPE_INTR) && hc->do_split && (hc->speed == DWC_OTG_EP_SPEED_FULL))
|
||||
// hcchar.b.eptype = DWC_OTG_EP_TYPE_BULK;
|
||||
//else
|
||||
if((hc->ep_type == DWC_OTG_EP_TYPE_INTR) && hc->do_split && (hc->speed == DWC_OTG_EP_SPEED_FULL))
|
||||
hcchar.b.eptype = DWC_OTG_EP_TYPE_BULK;
|
||||
else
|
||||
hcchar.b.eptype = hc->ep_type;
|
||||
hcchar.b.mps = hc->max_packet;
|
||||
|
||||
|
||||
5
drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.h
Executable file → Normal file
5
drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil.h
Executable file → Normal file
@@ -959,8 +959,6 @@ struct dwc_otg_core_if {
|
||||
/* Host only flag */
|
||||
int host_only;
|
||||
|
||||
int use_fiq_flag;
|
||||
|
||||
/** Device mode Periodic Tx FIFO Mask */
|
||||
uint32_t p_tx_msk;
|
||||
/** Device mode Periodic Tx FIFO Mask */
|
||||
@@ -1391,8 +1389,7 @@ typedef struct dwc_otg_cil_callbacks {
|
||||
/** Sleep (switch to L0 state) */
|
||||
int (*sleep) (void *_p);
|
||||
#endif
|
||||
/** Pointer passed to start() and stop() */
|
||||
void *p;
|
||||
|
||||
} dwc_otg_cil_callbacks_t;
|
||||
|
||||
extern void dwc_otg_cil_register_pcd_callbacks(dwc_otg_core_if_t * _core_if,
|
||||
|
||||
49
drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil_intr.c
Executable file → Normal file
49
drivers/amlogic/usb/dwc_otg/310/dwc_otg_cil_intr.c
Executable file → Normal file
@@ -1518,7 +1518,7 @@ static int32_t dwc_otg_handle_lpm_intr(dwc_otg_core_if_t * core_if)
|
||||
/**
|
||||
* This function returns the Core Interrupt register.
|
||||
*/
|
||||
static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if, gintmsk_data_t *reenable_gintmsk, dwc_otg_hcd_t *hcd)
|
||||
static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if)
|
||||
{
|
||||
gahbcfg_data_t gahbcfg = {.d32 = 0 };
|
||||
gintsts_data_t gintsts;
|
||||
@@ -1535,45 +1535,26 @@ static inline uint32_t dwc_otg_read_common_intr(dwc_otg_core_if_t * core_if, gin
|
||||
gintmsk_common.b.lpmtranrcvd = 1;
|
||||
#endif
|
||||
gintmsk_common.b.restoredone = 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);
|
||||
if(fiq_enable && core_if->use_fiq_flag) {
|
||||
local_fiq_disable();
|
||||
/* Pull in the interrupts that the FIQ has masked */
|
||||
gintmsk.d32 |= ~(hcd->fiq_state->gintmsk_saved.d32);
|
||||
gintmsk.d32 |= gintmsk_common.d32;
|
||||
/* for the upstairs function to reenable - have to read it here in case FIQ triggers again */
|
||||
reenable_gintmsk->d32 = gintmsk.d32;
|
||||
local_fiq_enable();
|
||||
}
|
||||
|
||||
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, "common_intr: gintsts=%08x gintmsk=%08x\n",
|
||||
DWC_DEBUGPL(DBG_ANY, "gintsts=%08x gintmsk=%08x\n",
|
||||
gintsts.d32, gintmsk.d32);
|
||||
}
|
||||
#endif
|
||||
if (!(fiq_enable&&core_if->use_fiq_flag)){
|
||||
if (gahbcfg.b.glblintrmsk)
|
||||
return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32);
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
/* Our IRQ kicker is no longer the USB hardware, it's the MPHI interface.
|
||||
* Can't trust the global interrupt mask bit in this case.
|
||||
*/
|
||||
return ((gintsts.d32 & gintmsk.d32) & gintmsk_common.d32);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1605,7 +1586,7 @@ int32_t dwc_otg_handle_common_intr(void *dev)
|
||||
{
|
||||
int retval = 0;
|
||||
gintsts_data_t gintsts;
|
||||
gintmsk_data_t gintmsk_reenable = { .d32 = 0 };
|
||||
gintsts_data_t gintsts_tmp;
|
||||
gpwrdn_data_t gpwrdn = {.d32 = 0 };
|
||||
dwc_otg_device_t *otg_dev = dev;
|
||||
dwc_otg_core_if_t *core_if = otg_dev->core_if;
|
||||
@@ -1633,10 +1614,7 @@ int32_t dwc_otg_handle_common_intr(void *dev)
|
||||
}
|
||||
|
||||
if (core_if->hibernation_suspend <= 0) {
|
||||
/* read_common will have to poke the FIQ's saved mask. We must then clear this mask at the end
|
||||
* of this handler - god only knows why it's done like this
|
||||
*/
|
||||
gintsts.d32 = dwc_otg_read_common_intr(core_if, &gintmsk_reenable, otg_dev->hcd);
|
||||
gintsts.d32 = dwc_otg_read_common_intr(core_if);
|
||||
|
||||
if (gintsts.b.modemismatch) {
|
||||
retval |= dwc_otg_handle_mode_mismatch_intr(core_if);
|
||||
@@ -1648,7 +1626,15 @@ int32_t dwc_otg_handle_common_intr(void *dev)
|
||||
retval |= dwc_otg_handle_conn_id_status_change_intr(core_if);
|
||||
}
|
||||
if (gintsts.b.disconnect) {
|
||||
if (gintsts.b.portintr && dwc_otg_is_host_mode(core_if))
|
||||
retval |= dwc_otg_handle_disconnect_intr(core_if);
|
||||
else
|
||||
{
|
||||
gintsts_tmp.d32 = 0;
|
||||
gintsts_tmp.b.disconnect = 1;
|
||||
DWC_WRITE_REG32(&core_if->core_global_regs->gintsts, gintsts_tmp.d32);
|
||||
retval |= 1;
|
||||
}
|
||||
}
|
||||
if (gintsts.b.sessreqintr) {
|
||||
retval |= dwc_otg_handle_session_req_intr(core_if);
|
||||
@@ -1732,17 +1718,8 @@ int32_t dwc_otg_handle_common_intr(void *dev)
|
||||
gintsts.b.portintr = 1;
|
||||
DWC_WRITE_REG32(&core_if->core_global_regs->gintsts,gintsts.d32);
|
||||
retval |= 1;
|
||||
gintmsk_reenable.b.portintr = 1;
|
||||
|
||||
}
|
||||
/* Did we actually handle anything? if so, unmask the interrupt */
|
||||
// fiq_print(FIQDBG_INT, otg_dev->hcd->fiq_state, "CILOUT %1d", retval);
|
||||
// fiq_print(FIQDBG_INT, otg_dev->hcd->fiq_state, "%08x", gintsts.d32);
|
||||
// fiq_print(FIQDBG_INT, otg_dev->hcd->fiq_state, "%08x", gintmsk_reenable.d32);
|
||||
if (retval && fiq_enable &&core_if->use_fiq_flag) {
|
||||
DWC_WRITE_REG32(&core_if->core_global_regs->gintmsk, gintmsk_reenable.d32);
|
||||
}
|
||||
|
||||
} else {
|
||||
DWC_DEBUGPL(DBG_ANY, "gpwrdn=%08x\n", gpwrdn.d32);
|
||||
|
||||
|
||||
0
drivers/amlogic/usb/dwc_otg/310/dwc_otg_core_if.h
Executable file → Normal file
0
drivers/amlogic/usb/dwc_otg/310/dwc_otg_core_if.h
Executable file → Normal file
@@ -57,7 +57,6 @@
|
||||
#include "dwc_otg_cil.h"
|
||||
#include "dwc_otg_pcd_if.h"
|
||||
#include "dwc_otg_hcd_if.h"
|
||||
#include "dwc_otg_fiq_fsm.h"
|
||||
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/amlogic/of_lm.h>
|
||||
@@ -73,7 +72,6 @@
|
||||
|
||||
#define DWC_DRIVER_VERSION "3.10a 12-MAY-2014"
|
||||
#define DWC_DRIVER_DESC "HS OTG USB Controller driver"
|
||||
bool microframe_schedule=true;
|
||||
|
||||
static const char dwc_driver_name[] = "dwc_otg";
|
||||
|
||||
@@ -271,17 +269,6 @@ static const char *dma_config_name[] = {
|
||||
"BURST_INCR16"
|
||||
"DISABLE",
|
||||
};
|
||||
|
||||
|
||||
//Global variable to switch the fiq fix on or off
|
||||
bool fiq_enable = 1;
|
||||
// Global variable to enable the split transaction fix
|
||||
bool fiq_fsm_enable = true;
|
||||
//Bulk split-transaction NAK holdoff in microframes
|
||||
uint16_t nak_holdoff = 8;
|
||||
|
||||
unsigned short fiq_fsm_mask = 0x07;
|
||||
|
||||
/**
|
||||
* This function shows the Driver Version.
|
||||
*/
|
||||
@@ -905,7 +892,6 @@ static int dwc_otg_driver_probe(
|
||||
int charger_detect = 0;
|
||||
int host_only_core = 0;
|
||||
int pmu_apply_power = 0;
|
||||
int use_fiq_flag = 0;
|
||||
unsigned int phy_reg_addr = 0;
|
||||
unsigned int ctrl_reg_addr = 0;
|
||||
const char *s_clock_name = NULL;
|
||||
@@ -914,8 +900,6 @@ static int dwc_otg_driver_probe(
|
||||
struct clk * clock;
|
||||
dwc_otg_device_t *dwc_otg_device;
|
||||
struct dwc_otg_driver_module_params *pcore_para;
|
||||
int irqno;
|
||||
unsigned long flags = IRQF_SHARED | IRQF_DISABLED;
|
||||
|
||||
dev_dbg(&_dev->dev, "dwc_otg_driver_probe(%p)\n", _dev);
|
||||
|
||||
@@ -949,15 +933,6 @@ static int dwc_otg_driver_probe(
|
||||
struct device_node *of_node = _dev->dev.of_node;
|
||||
match = of_lm_match_node(dwc_otg_dt_match, of_node);
|
||||
if(match){
|
||||
gpio_name = of_get_property(of_node, "gpio-pwr", NULL);
|
||||
if (gpio_name) {
|
||||
int nr = amlogic_gpio_name_map_num(gpio_name);
|
||||
amlogic_gpio_request_one(nr,
|
||||
GPIOF_OUT_INIT_LOW,
|
||||
"usb_pwr_en");
|
||||
amlogic_set_value(nr, 1, "usb_pwr_en");
|
||||
}
|
||||
|
||||
s_clock_name = of_get_property(of_node, "clock-src", NULL);
|
||||
prop = of_get_property(of_node, "port-id", NULL);
|
||||
if(prop)
|
||||
@@ -1017,11 +992,7 @@ static int dwc_otg_driver_probe(
|
||||
prop = of_get_property(of_node, "pmu-apply-power", NULL);
|
||||
if(prop)
|
||||
pmu_apply_power = of_read_ulong(prop,1);
|
||||
|
||||
prop = of_get_property(of_node, "fiq_use", NULL);
|
||||
if(prop)
|
||||
use_fiq_flag = of_read_ulong(prop,1);
|
||||
|
||||
|
||||
ctrl_reg_addr = (unsigned long)usb_platform_data.ctrl_regaddr[port_index];
|
||||
phy_reg_addr = (unsigned long)usb_platform_data.phy_regaddr[port_index];
|
||||
_dev->irq = usb_platform_data.irq_no[port_index];
|
||||
@@ -1229,20 +1200,14 @@ static int dwc_otg_driver_probe(
|
||||
*/
|
||||
dwc_otg_disable_global_interrupts(dwc_otg_device->core_if);
|
||||
|
||||
if(fiq_enable && use_fiq_flag) {
|
||||
irqno= MESON_USB_FIQ_BRIDGE;
|
||||
} else {
|
||||
irqno = _dev->irq;
|
||||
flags |= IRQ_TYPE_LEVEL_HIGH;
|
||||
}
|
||||
/*
|
||||
* Install the interrupt handler for the common interrupts before
|
||||
* enabling common interrupts in core_init below.
|
||||
*/
|
||||
DWC_DEBUGPL(DBG_CIL, "registering (common) handler for irq%d\n",
|
||||
irqno);
|
||||
retval = request_irq(irqno, dwc_otg_common_irq,
|
||||
flags, "dwc_otg",
|
||||
_dev->irq);
|
||||
retval = request_irq(_dev->irq, dwc_otg_common_irq,
|
||||
IRQF_SHARED | IRQF_DISABLED | IRQ_LEVEL, "dwc_otg",
|
||||
dwc_otg_device);
|
||||
if (retval) {
|
||||
DWC_ERROR("request of irq%d failed\n", _dev->irq);
|
||||
@@ -1252,6 +1217,11 @@ static int dwc_otg_driver_probe(
|
||||
dwc_otg_device->common_irq_installed = 1;
|
||||
}
|
||||
|
||||
if (irq_set_affinity(_dev->irq, cpumask_of(3))) {
|
||||
pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
|
||||
_dev->irq, 3);
|
||||
}
|
||||
|
||||
#ifdef LM_INTERFACE
|
||||
// set_irq_type(_dev->irq, IRQT_LOW);
|
||||
#endif
|
||||
@@ -1286,7 +1256,6 @@ static int dwc_otg_driver_probe(
|
||||
if(host_only_core&&pmu_apply_power)
|
||||
dwc_otg_device->core_if->swicth_int_reg = 1;
|
||||
|
||||
dwc_otg_device->core_if->use_fiq_flag = use_fiq_flag;
|
||||
if (port_type == USB_PORT_TYPE_HOST) {
|
||||
/*
|
||||
* Initialize the HCD
|
||||
@@ -1437,11 +1406,6 @@ static int __init dwc_otg_driver_init(void)
|
||||
{
|
||||
int retval = 0;
|
||||
int error;
|
||||
|
||||
if(fiq_fsm_enable && !fiq_enable) {
|
||||
printk(KERN_WARNING "dwc_otg: fiq_fsm_enable was set without fiq_enable! Correcting.\n");
|
||||
fiq_enable = 1;
|
||||
}
|
||||
printk(KERN_INFO "%s: version %s\n", dwc_driver_name,
|
||||
DWC_DRIVER_VERSION);
|
||||
#ifdef LM_INTERFACE
|
||||
@@ -1453,10 +1417,6 @@ static int __init dwc_otg_driver_init(void)
|
||||
printk(KERN_ERR "%s retval=%d\n", __func__, retval);
|
||||
return retval;
|
||||
}
|
||||
printk(KERN_DEBUG "dwc_otg: FIQ %s\n", fiq_enable ? "enabled":"disabled");
|
||||
printk(KERN_DEBUG "dwc_otg: NAK holdoff %s\n", nak_holdoff ? "enabled":"disabled");
|
||||
printk(KERN_DEBUG "dwc_otg: FIQ split-transaction FSM %s\n", fiq_fsm_enable ? "enabled":"disabled");
|
||||
|
||||
#ifdef LM_INTERFACE
|
||||
error = driver_create_file(&dwc_otg_driver.drv, &driver_attr_version);
|
||||
error = driver_create_file(&dwc_otg_driver.drv, &driver_attr_debuglevel);
|
||||
@@ -1740,22 +1700,6 @@ module_param_named(adp_enable, dwc_otg_module_params.adp_enable, int, 0444);
|
||||
MODULE_PARM_DESC(adp_enable, "ADP Enable 0=ADP Disabled 1=ADP Enabled");
|
||||
module_param_named(otg_ver, dwc_otg_module_params.otg_ver, int, 0444);
|
||||
MODULE_PARM_DESC(otg_ver, "OTG revision supported 0=OTG 1.3 1=OTG 2.0");
|
||||
module_param(microframe_schedule, bool, 0444);
|
||||
MODULE_PARM_DESC(microframe_schedule, "Enable the microframe scheduler");
|
||||
|
||||
module_param(fiq_enable, bool, 0444);
|
||||
MODULE_PARM_DESC(fiq_enable, "Enable the FIQ");
|
||||
module_param(nak_holdoff, ushort, 0644);
|
||||
MODULE_PARM_DESC(nak_holdoff, "Throttle duration for bulk split-transaction endpoints on a NAK. Default 8");
|
||||
module_param(fiq_fsm_enable, bool, 0444);
|
||||
MODULE_PARM_DESC(fiq_fsm_enable, "Enable the FIQ to perform split transactions as defined by fiq_fsm_mask");
|
||||
module_param(fiq_fsm_mask, ushort, 0444);
|
||||
MODULE_PARM_DESC(fiq_fsm_mask, "Bitmask of transactions to perform in the FIQ.\n"
|
||||
"Bit 0 : Non-periodic split transactions\n"
|
||||
"Bit 1 : Periodic split transactions\n"
|
||||
"Bit 2 : High-speed multi-transfer isochronous\n"
|
||||
"All other bits should be set 0.");
|
||||
|
||||
|
||||
/** @page "Module Parameters"
|
||||
*
|
||||
|
||||
1
drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.h
Executable file → Normal file
1
drivers/amlogic/usb/dwc_otg/310/dwc_otg_driver.h
Executable file → Normal file
@@ -46,7 +46,6 @@
|
||||
struct dwc_otg_pcd;
|
||||
struct dwc_otg_hcd;
|
||||
|
||||
#define MESON_USB_FIQ_BRIDGE INT_TIMER_D
|
||||
/**
|
||||
* This structure is a wrapper that encapsulates the driver components used to
|
||||
* manage a single DWC_otg controller.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,354 +0,0 @@
|
||||
/*
|
||||
* dwc_otg_fiq_fsm.h - Finite state machine FIQ header definitions
|
||||
*
|
||||
* Copyright (c) 2013 Raspberry Pi Foundation
|
||||
*
|
||||
* Author: Jonathan Bell <jonathan@raspberrypi.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Raspberry Pi nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This FIQ implements functionality that performs split transactions on
|
||||
* the dwc_otg hardware without any outside intervention. A split transaction
|
||||
* is "queued" by nominating a specific host channel to perform the entirety
|
||||
* of a split transaction. This FIQ will then perform the microframe-precise
|
||||
* scheduling required in each phase of the transaction until completion.
|
||||
*
|
||||
* The FIQ functionality has been surgically implanted into the Synopsys
|
||||
* vendor-provided driver.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DWC_OTG_FIQ_FSM_H_
|
||||
#define DWC_OTG_FIQ_FSM_H_
|
||||
|
||||
#include "dwc_otg_regs.h"
|
||||
#include "dwc_otg_cil.h"
|
||||
#include "dwc_otg_hcd.h"
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/irqflags.h>
|
||||
#include <linux/string.h>
|
||||
#include <asm/barrier.h>
|
||||
|
||||
#if 0
|
||||
#define FLAME_ON(x) \
|
||||
do { \
|
||||
int gpioreg; \
|
||||
\
|
||||
gpioreg = readl(__io_address(0x20200000+0x8)); \
|
||||
gpioreg &= ~(7 << (x-20)*3); \
|
||||
gpioreg |= 0x1 << (x-20)*3; \
|
||||
writel(gpioreg, __io_address(0x20200000+0x8)); \
|
||||
\
|
||||
writel(1<<x, __io_address(0x20200000+(0x1C))); \
|
||||
} while (0)
|
||||
|
||||
#define FLAME_OFF(x) \
|
||||
do { \
|
||||
writel(1<<x, __io_address(0x20200000+(0x28))); \
|
||||
} while (0)
|
||||
#else
|
||||
#define FLAME_ON(x) do { } while (0)
|
||||
#define FLAME_OFF(X) do { } while (0)
|
||||
#endif
|
||||
|
||||
/* This is a quick-and-dirty arch-specific register read/write. We know that
|
||||
* writes to a peripheral on BCM2835 will always arrive in-order, also that
|
||||
* reads and writes are executed in-order therefore the need for memory barriers
|
||||
* is obviated if we're only talking to USB.
|
||||
*/
|
||||
#define FIQ_WRITE(_addr_,_data_) (*(volatile unsigned int *) (_addr_) = (_data_))
|
||||
#define FIQ_READ(_addr_) (*(volatile unsigned int *) (_addr_))
|
||||
|
||||
/* FIQ-ified register definitions. Offsets are from dwc_regs_base. */
|
||||
#define GINTSTS 0x014
|
||||
#define GINTMSK 0x018
|
||||
/* Debug register. Poll the top of the received packets FIFO. */
|
||||
#define GRXSTSR 0x01C
|
||||
#define HFNUM 0x408
|
||||
#define HAINT 0x414
|
||||
#define HAINTMSK 0x418
|
||||
#define HPRT0 0x440
|
||||
|
||||
/* HC_regs start from an offset of 0x500 */
|
||||
#define HC_START 0x500
|
||||
#define HC_OFFSET 0x020
|
||||
|
||||
#define HC_DMA 0x514
|
||||
|
||||
#define HCCHAR 0x00
|
||||
#define HCSPLT 0x04
|
||||
#define HCINT 0x08
|
||||
#define HCINTMSK 0x0C
|
||||
#define HCTSIZ 0x10
|
||||
|
||||
#define ISOC_XACTPOS_ALL 0b11
|
||||
#define ISOC_XACTPOS_BEGIN 0b10
|
||||
#define ISOC_XACTPOS_MID 0b00
|
||||
#define ISOC_XACTPOS_END 0b01
|
||||
|
||||
#define DWC_PID_DATA2 0b01
|
||||
#define DWC_PID_MDATA 0b11
|
||||
#define DWC_PID_DATA1 0b10
|
||||
#define DWC_PID_DATA0 0b00
|
||||
|
||||
typedef struct {
|
||||
volatile void* base;
|
||||
volatile void* ctrl;
|
||||
volatile void* outdda;
|
||||
volatile void* outddb;
|
||||
volatile void* intstat;
|
||||
} mphi_regs_t;
|
||||
|
||||
|
||||
enum fiq_debug_level {
|
||||
FIQDBG_SCHED = (1 << 0),
|
||||
FIQDBG_INT = (1 << 1),
|
||||
FIQDBG_ERR = (1 << 2),
|
||||
FIQDBG_PORTHUB = (1 << 3),
|
||||
};
|
||||
|
||||
struct fiq_state;
|
||||
|
||||
extern void _fiq_print (enum fiq_debug_level dbg_lvl, volatile struct fiq_state *state, char *fmt, ...);
|
||||
#if 0
|
||||
#define fiq_print _fiq_print
|
||||
#else
|
||||
#define fiq_print(x, y, ...)
|
||||
#endif
|
||||
|
||||
extern bool fiq_enable, fiq_fsm_enable;
|
||||
extern ushort nak_holdoff;
|
||||
|
||||
/**
|
||||
* enum fiq_fsm_state - The FIQ FSM states.
|
||||
*
|
||||
* This is the "core" of the FIQ FSM. Broadly, the FSM states follow the
|
||||
* USB2.0 specification for host responses to various transaction states.
|
||||
* There are modifications to this host state machine because of a variety of
|
||||
* quirks and limitations in the dwc_otg hardware.
|
||||
*
|
||||
* The fsm state is also used to communicate back to the driver on completion of
|
||||
* a split transaction. The end states are used in conjunction with the interrupts
|
||||
* raised by the final transaction.
|
||||
*/
|
||||
enum fiq_fsm_state {
|
||||
/* FIQ isn't enabled for this host channel */
|
||||
FIQ_PASSTHROUGH = 0,
|
||||
/* For the first interrupt received for this channel,
|
||||
* the FIQ has to ack any interrupts indicating success. */
|
||||
FIQ_PASSTHROUGH_ERRORSTATE = 31,
|
||||
/* Nonperiodic state groups */
|
||||
FIQ_NP_SSPLIT_STARTED = 1,
|
||||
FIQ_NP_SSPLIT_RETRY = 2,
|
||||
FIQ_NP_OUT_CSPLIT_RETRY = 3,
|
||||
FIQ_NP_IN_CSPLIT_RETRY = 4,
|
||||
FIQ_NP_SPLIT_DONE = 5,
|
||||
FIQ_NP_SPLIT_LS_ABORTED = 6,
|
||||
/* This differentiates a HS transaction error from a LS one
|
||||
* (handling the hub state is different) */
|
||||
FIQ_NP_SPLIT_HS_ABORTED = 7,
|
||||
|
||||
/* Periodic state groups */
|
||||
/* Periodic transactions are either started directly by the IRQ handler
|
||||
* or deferred if the TT is already in use.
|
||||
*/
|
||||
FIQ_PER_SSPLIT_QUEUED = 8,
|
||||
FIQ_PER_SSPLIT_STARTED = 9,
|
||||
FIQ_PER_SSPLIT_LAST = 10,
|
||||
|
||||
|
||||
FIQ_PER_ISO_OUT_PENDING = 11,
|
||||
FIQ_PER_ISO_OUT_ACTIVE = 12,
|
||||
FIQ_PER_ISO_OUT_LAST = 13,
|
||||
FIQ_PER_ISO_OUT_DONE = 27,
|
||||
|
||||
FIQ_PER_CSPLIT_WAIT = 14,
|
||||
FIQ_PER_CSPLIT_NYET1 = 15,
|
||||
FIQ_PER_CSPLIT_BROKEN_NYET1 = 28,
|
||||
FIQ_PER_CSPLIT_NYET_FAFF = 29,
|
||||
/* For multiple CSPLITs (large isoc IN, or delayed interrupt) */
|
||||
FIQ_PER_CSPLIT_POLL = 16,
|
||||
/* The last CSPLIT for a transaction has been issued, differentiates
|
||||
* for the state machine to queue the next packet.
|
||||
*/
|
||||
FIQ_PER_CSPLIT_LAST = 17,
|
||||
|
||||
FIQ_PER_SPLIT_DONE = 18,
|
||||
FIQ_PER_SPLIT_LS_ABORTED = 19,
|
||||
FIQ_PER_SPLIT_HS_ABORTED = 20,
|
||||
FIQ_PER_SPLIT_NYET_ABORTED = 21,
|
||||
/* Frame rollover has occurred without the transaction finishing. */
|
||||
FIQ_PER_SPLIT_TIMEOUT = 22,
|
||||
|
||||
/* FIQ-accelerated HS Isochronous state groups */
|
||||
FIQ_HS_ISOC_TURBO = 23,
|
||||
/* For interval > 1, SOF wakes up the isochronous FSM */
|
||||
FIQ_HS_ISOC_SLEEPING = 24,
|
||||
FIQ_HS_ISOC_DONE = 25,
|
||||
FIQ_HS_ISOC_ABORTED = 26,
|
||||
FIQ_DEQUEUE_ISSUED = 30,
|
||||
FIQ_TEST = 32,
|
||||
};
|
||||
|
||||
struct fiq_stack {
|
||||
int magic1;
|
||||
uint8_t stack[2048];
|
||||
int magic2;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* struct fiq_dma_info - DMA bounce buffer utilisation information (per-channel)
|
||||
* @index: Number of slots reported used for IN transactions / number of slots
|
||||
* transmitted for an OUT transaction
|
||||
* @slot_len[6]: Number of actual transfer bytes in each slot (255 if unused)
|
||||
*
|
||||
* Split transaction transfers can have variable length depending on other bus
|
||||
* traffic. The OTG core DMA engine requires 4-byte aligned addresses therefore
|
||||
* each transaction needs a guaranteed aligned address. A maximum of 6 split transfers
|
||||
* can happen per-frame.
|
||||
*/
|
||||
struct fiq_dma_info {
|
||||
u8 index;
|
||||
u8 slot_len[6];
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) fiq_split_dma_slot {
|
||||
u8 buf[188];
|
||||
};
|
||||
|
||||
struct fiq_dma_channel {
|
||||
struct __attribute__((packed)) fiq_split_dma_slot index[6];
|
||||
};
|
||||
|
||||
struct fiq_dma_blob {
|
||||
struct __attribute__((packed)) fiq_dma_channel channel[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct fiq_hs_isoc_info - USB2.0 isochronous data
|
||||
* @iso_frame: Pointer to the array of OTG URB iso_frame_descs.
|
||||
* @nrframes: Total length of iso_frame_desc array
|
||||
* @index: Current index (FIQ-maintained)
|
||||
*
|
||||
*/
|
||||
struct fiq_hs_isoc_info {
|
||||
struct dwc_otg_hcd_iso_packet_desc *iso_desc;
|
||||
unsigned int nrframes;
|
||||
unsigned int index;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct fiq_channel_state - FIQ state machine storage
|
||||
* @fsm: Current state of the channel as understood by the FIQ
|
||||
* @nr_errors: Number of transaction errors on this split-transaction
|
||||
* @hub_addr: SSPLIT/CSPLIT destination hub
|
||||
* @port_addr: SSPLIT/CSPLIT destination port - always 1 if single TT hub
|
||||
* @nrpackets: For isoc OUT, the number of split-OUT packets to transmit. For
|
||||
* split-IN, number of CSPLIT data packets that were received.
|
||||
* @hcchar_copy:
|
||||
* @hcsplt_copy:
|
||||
* @hcintmsk_copy:
|
||||
* @hctsiz_copy: Copies of the host channel registers.
|
||||
* For use as scratch, or for returning state.
|
||||
*
|
||||
* The fiq_channel_state is state storage between interrupts for a host channel. The
|
||||
* FSM state is stored here. Members of this structure must only be set up by the
|
||||
* driver prior to enabling the FIQ for this host channel, and not touched until the FIQ
|
||||
* has updated the state to either a COMPLETE state group or ABORT state group.
|
||||
*/
|
||||
|
||||
struct fiq_channel_state {
|
||||
enum fiq_fsm_state fsm;
|
||||
unsigned int nr_errors;
|
||||
unsigned int hub_addr;
|
||||
unsigned int port_addr;
|
||||
/* Hardware bug workaround: sometimes channel halt interrupts are
|
||||
* delayed until the next SOF. Keep track of when we expected to get interrupted. */
|
||||
unsigned int expected_uframe;
|
||||
/* in/out for communicating number of dma buffers used, or number of ISOC to do */
|
||||
unsigned int nrpackets;
|
||||
struct fiq_dma_info dma_info;
|
||||
struct fiq_hs_isoc_info hs_isoc_info;
|
||||
/* Copies of HC registers - in/out communication from/to IRQ handler
|
||||
* and for ease of channel setup. A bit of mungeing is performed - for
|
||||
* example the hctsiz.b.maxp is _always_ the max packet size of the endpoint.
|
||||
*/
|
||||
hcchar_data_t hcchar_copy;
|
||||
hcsplt_data_t hcsplt_copy;
|
||||
hcint_data_t hcint_copy;
|
||||
hcintmsk_data_t hcintmsk_copy;
|
||||
hctsiz_data_t hctsiz_copy;
|
||||
hcdma_data_t hcdma_copy;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct fiq_state - top-level FIQ state machine storage
|
||||
* @mphi_regs: virtual address of the MPHI peripheral register file
|
||||
* @dwc_regs_base: virtual address of the base of the DWC core register file
|
||||
* @dma_base: physical address for the base of the DMA bounce buffers
|
||||
* @dummy_send: Scratch area for sending a fake message to the MPHI peripheral
|
||||
* @gintmsk_saved: Top-level mask of interrupts that the FIQ has not handled.
|
||||
* Used for determining which interrupts fired to set off the IRQ handler.
|
||||
* @haintmsk_saved: Mask of interrupts from host channels that the FIQ did not handle internally.
|
||||
* @np_count: Non-periodic transactions in the active queue
|
||||
* @np_sent: Count of non-periodic transactions that have completed
|
||||
* @next_sched_frame: For periodic transactions handled by the driver's SOF-driven queuing mechanism,
|
||||
* this is the next frame on which a SOF interrupt is required. Used to hold off
|
||||
* passing SOF through to the driver until necessary.
|
||||
* @channel[n]: Per-channel FIQ state. Allocated during init depending on the number of host
|
||||
* channels configured into the core logic.
|
||||
*
|
||||
* This is passed as the first argument to the dwc_otg_fiq_fsm top-level FIQ handler from the asm stub.
|
||||
* It contains top-level state information.
|
||||
*/
|
||||
struct fiq_state {
|
||||
mphi_regs_t mphi_regs;
|
||||
void *dwc_regs_base;
|
||||
dma_addr_t dma_base;
|
||||
struct fiq_dma_blob *fiq_dmab;
|
||||
void *dummy_send;
|
||||
gintmsk_data_t gintmsk_saved;
|
||||
haintmsk_data_t haintmsk_saved;
|
||||
int mphi_int_count;
|
||||
unsigned int fiq_done;
|
||||
unsigned int kick_np_queues;
|
||||
unsigned int next_sched_frame;
|
||||
#ifdef FIQ_DEBUG
|
||||
char * buffer;
|
||||
unsigned int bufsiz;
|
||||
#endif
|
||||
struct fiq_channel_state channel[0];
|
||||
};
|
||||
|
||||
extern int fiq_fsm_too_late(struct fiq_state *st, int n);
|
||||
|
||||
extern int fiq_fsm_tt_in_use(struct fiq_state *st, int num_channels, int n);
|
||||
|
||||
extern void dwc_otg_fiq_fsm(struct fiq_state *state, int num_channels);
|
||||
|
||||
extern void dwc_otg_fiq_nop(struct fiq_state *state);
|
||||
extern void set_fiq_init(unsigned int fiq,long data);
|
||||
|
||||
#endif /* DWC_OTG_FIQ_FSM_H_ */
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* dwc_otg_fiq_fsm.S - assembly stub for the FSM FIQ
|
||||
*
|
||||
* Copyright (c) 2013 Raspberry Pi Foundation
|
||||
*
|
||||
* Author: Jonathan Bell <jonathan@raspberrypi.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Raspberry Pi nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include <asm/assembler.h>
|
||||
#include <linux/linkage.h>
|
||||
|
||||
|
||||
.text
|
||||
|
||||
.global _dwc_otg_fiq_stub_end;
|
||||
|
||||
/**
|
||||
* _dwc_otg_fiq_stub() - entry copied to the FIQ vector page to allow
|
||||
* a C-style function call with arguments from the FIQ banked registers.
|
||||
* r0 = &hcd->fiq_state
|
||||
* r1 = &hcd->num_channels
|
||||
* r2 = &hcd->dma_buffers
|
||||
* Tramples: r0, r1, r2, r4, fp, ip
|
||||
*/
|
||||
|
||||
ENTRY(_dwc_otg_fiq_stub)
|
||||
/* Stash unbanked regs - SP will have been set up for us */
|
||||
mov ip, sp;
|
||||
stmdb sp!, {r0-r12, lr};
|
||||
#ifdef FIQ_DEBUG
|
||||
// Cycle profiling - read cycle counter at start
|
||||
mrc p15, 0, r5, c15, c12, 1;
|
||||
#endif
|
||||
/* r11 = fp, don't trample it */
|
||||
mov r4, fp;
|
||||
/* set EABI frame size */
|
||||
sub fp, ip, #512;
|
||||
|
||||
/* for fiq NOP mode - just need state */
|
||||
mov r0, r8;
|
||||
/* r9 = num_channels */
|
||||
mov r1, r9;
|
||||
/* r10 = struct *dma_bufs */
|
||||
// mov r2, r10;
|
||||
|
||||
/* r4 = &fiq_c_function */
|
||||
blx r4;
|
||||
#ifdef FIQ_DEBUG
|
||||
mrc p15, 0, r4, c15, c12, 1;
|
||||
subs r5, r5, r4;
|
||||
// r5 is now the cycle count time for executing the FIQ. Store it somewhere?
|
||||
#endif
|
||||
ldmia sp!, {r0-r12, lr};
|
||||
subs pc, lr, #4;
|
||||
_dwc_otg_fiq_stub_end:
|
||||
END(_dwc_otg_fiq_stub)
|
||||
|
||||
1036
drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd.c
Executable file → Normal file
1036
drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd.c
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
92
drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd.h
Executable file → Normal file
92
drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd.h
Executable file → Normal file
@@ -40,8 +40,6 @@
|
||||
#include "dwc_otg_core_if.h"
|
||||
#include "dwc_list.h"
|
||||
#include "dwc_otg_cil.h"
|
||||
#include "dwc_otg_fiq_fsm.h"
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
@@ -86,10 +84,21 @@ struct dwc_otg_hcd_urb {
|
||||
uint32_t packet_count;
|
||||
uint32_t flags;
|
||||
uint16_t interval;
|
||||
uint8_t qh_state;
|
||||
#define URB_STATE_IDLE 1 /* QH is not being used */
|
||||
#define URB_STATE_ACTIVE 2 /* QH is on the schedule */
|
||||
#define URB_STATE_SETED 3 /* QH had finished setting reg */
|
||||
#define URB_STATE_DQUEUE 4 /* QH had been pushed into tasklet, just used for isoc */
|
||||
#define URB_STATE_UNLINK 5 /* QH has been removed from the schedule */
|
||||
struct dwc_otg_hcd_pipe_info pipe_info;
|
||||
struct dwc_otg_hcd_iso_packet_desc iso_descs[0];
|
||||
};
|
||||
|
||||
typedef struct dwc_otg_hcd_urb_list{
|
||||
struct dwc_otg_hcd_urb * urb;
|
||||
dwc_list_link_t urb_list_entry;
|
||||
} dwc_otg_hcd_urb_list_t;
|
||||
|
||||
static inline uint8_t dwc_otg_hcd_get_ep_num(struct dwc_otg_hcd_pipe_info *pipe)
|
||||
{
|
||||
return pipe->ep_num;
|
||||
@@ -170,10 +179,10 @@ typedef enum dwc_otg_control_phase {
|
||||
|
||||
/** Transaction types. */
|
||||
typedef enum dwc_otg_transaction_type {
|
||||
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_NONE,
|
||||
DWC_OTG_TRANSACTION_PERIODIC,
|
||||
DWC_OTG_TRANSACTION_NON_PERIODIC,
|
||||
DWC_OTG_TRANSACTION_ALL
|
||||
} dwc_otg_transaction_type_e;
|
||||
|
||||
struct dwc_otg_qh;
|
||||
@@ -323,11 +332,6 @@ 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;
|
||||
|
||||
@@ -370,22 +374,10 @@ typedef struct dwc_otg_qh {
|
||||
struct dwc_otg_hcd_urb *dwc_otg_urb;
|
||||
/** @} */
|
||||
|
||||
|
||||
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.
|
||||
@@ -486,19 +478,6 @@ struct dwc_otg_hcd {
|
||||
*/
|
||||
uint16_t periodic_usecs;
|
||||
|
||||
/**
|
||||
* Total bandwidth claimed so far for all periodic transfers
|
||||
* in a frame.
|
||||
* This will include a mixture of HS and FS transfers.
|
||||
* Units are microseconds per (micro)frame.
|
||||
* We have a budget per frame and have to schedule
|
||||
* transactions accordingly.
|
||||
* Watch out for the fact that things are actually scheduled for the
|
||||
* "next frame".
|
||||
*/
|
||||
uint16_t frame_usecs[8];
|
||||
|
||||
|
||||
/**
|
||||
* Frame number read from the core at SOF. The value ranges from 0 to
|
||||
* DWC_HFNUM_MAX_FRNUM.
|
||||
@@ -521,17 +500,12 @@ struct dwc_otg_hcd {
|
||||
* transaction and at least one host channel available for
|
||||
* non-periodic transactions.
|
||||
*/
|
||||
int periodic_channels; /* microframe_schedule==0 */
|
||||
int periodic_channels;
|
||||
|
||||
/**
|
||||
* Number of host channels assigned to non-periodic transfers.
|
||||
*/
|
||||
int non_periodic_channels; /* microframe_schedule==0 */
|
||||
|
||||
/**
|
||||
* Number of host channels assigned to non-periodic transfers.
|
||||
*/
|
||||
int available_host_channels;
|
||||
int non_periodic_channels;
|
||||
|
||||
/**
|
||||
* Array of pointers to the host channel descriptors. Allows accessing
|
||||
@@ -562,13 +536,13 @@ struct dwc_otg_hcd {
|
||||
|
||||
/* Tasket to do a reset */
|
||||
dwc_tasklet_t *reset_tasklet;
|
||||
dwc_tasklet_t *isoc_complete_tasklet;
|
||||
|
||||
dwc_tasklet_t *completion_tasklet;
|
||||
struct urb_list completed_urb_list;
|
||||
|
||||
dwc_list_link_t isoc_comp_urbs_list;
|
||||
/* */
|
||||
dwc_spinlock_t *lock;
|
||||
dwc_spinlock_t *channel_lock;
|
||||
dwc_spinlock_t * isoc_comp_urbs_lock;
|
||||
void * isoc_comp_urbs[MAX_EPS_CHANNELS];
|
||||
/**
|
||||
* Private data that could be used by OS wrapper.
|
||||
*/
|
||||
@@ -579,21 +553,9 @@ 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;
|
||||
|
||||
struct fiq_stack *fiq_stack;
|
||||
struct fiq_state *fiq_state;
|
||||
|
||||
/** Virtual address for split transaction DMA bounce buffers */
|
||||
struct fiq_dma_blob *fiq_dmab;
|
||||
|
||||
#ifdef DEBUG
|
||||
uint32_t frrem_samples;
|
||||
uint64_t frrem_accum;
|
||||
@@ -612,8 +574,8 @@ struct dwc_otg_hcd {
|
||||
uint32_t hfnum_other_samples_b;
|
||||
uint64_t hfnum_other_frrem_accum_b;
|
||||
#endif
|
||||
uint8_t ssplit_lock;
|
||||
uint8_t auto_pm_suspend_flag;
|
||||
uint8_t pm_freeze_flag;
|
||||
};
|
||||
|
||||
/** @name Transaction Execution Functions */
|
||||
@@ -623,13 +585,6 @@ extern dwc_otg_transaction_type_e dwc_otg_hcd_select_transactions(dwc_otg_hcd_t
|
||||
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);
|
||||
|
||||
extern int fiq_fsm_queue_transaction(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh);
|
||||
extern int fiq_fsm_transaction_suitable(dwc_otg_qh_t *qh);
|
||||
extern void dwc_otg_cleanup_fiq_channel(dwc_otg_hcd_t *hcd, uint32_t num);
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @name Interrupt Handler Functions */
|
||||
@@ -869,5 +824,4 @@ void dwc_otg_hcd_save_data_toggle(dwc_hc_t * hc,
|
||||
#define dwc_sample_frrem(_hcd, _qh, _letter)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
/* DWC_DEVICE_ONLY */
|
||||
#endif /* DWC_DEVICE_ONLY */
|
||||
@@ -39,8 +39,6 @@
|
||||
#include "dwc_otg_hcd.h"
|
||||
#include "dwc_otg_regs.h"
|
||||
|
||||
extern bool microframe_schedule;
|
||||
|
||||
static inline uint8_t frame_list_idx(uint16_t frame)
|
||||
{
|
||||
return (frame & (MAX_FRLIST_EN_NUM - 1));
|
||||
@@ -275,18 +273,10 @@ 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 = hcd->channel_lock;
|
||||
|
||||
dwc_hc_t *hc = qh->channel;
|
||||
if (dwc_qh_is_non_per(qh)) {
|
||||
DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
|
||||
if (!microframe_schedule)
|
||||
if (dwc_qh_is_non_per(qh))
|
||||
hcd->non_periodic_channels--;
|
||||
else
|
||||
hcd->available_host_channels++;
|
||||
DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
|
||||
} else
|
||||
update_frame_list(hcd, qh, 0);
|
||||
|
||||
/*
|
||||
@@ -368,7 +358,7 @@ void dwc_otg_hcd_qh_free_ddma(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
|
||||
release_channel_ddma(hcd, qh);
|
||||
|
||||
if ((qh->ep_type == UE_ISOCHRONOUS || qh->ep_type == UE_INTERRUPT)
|
||||
&& (microframe_schedule || !hcd->periodic_channels) && hcd->frame_list) {
|
||||
&& !hcd->periodic_channels && hcd->frame_list) {
|
||||
|
||||
per_sched_disable(hcd);
|
||||
frame_list_free(hcd);
|
||||
|
||||
7
drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_if.h
Executable file → Normal file
7
drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_if.h
Executable file → Normal file
@@ -79,6 +79,8 @@ struct dwc_otg_hcd_function_ops {
|
||||
dwc_otg_hcd_hub_info_from_urb_cb_t hub_info;
|
||||
dwc_otg_hcd_speed_from_urb_cb_t speed;
|
||||
dwc_otg_hcd_complete_urb_cb_t complete;
|
||||
dwc_otg_hcd_complete_urb_cb_t complete_in_tasklet;
|
||||
dwc_otg_hcd_complete_urb_cb_t hcd_isoc_complete;
|
||||
dwc_otg_hcd_get_b_hnp_enable get_b_hnp_enable;
|
||||
};
|
||||
/** @} */
|
||||
@@ -113,11 +115,6 @@ extern void dwc_otg_hcd_remove(dwc_otg_hcd_t * hcd);
|
||||
*/
|
||||
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.
|
||||
|
||||
710
drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_intr.c
Executable file → Normal file
710
drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_intr.c
Executable file → Normal file
@@ -35,99 +35,38 @@
|
||||
#include "dwc_otg_hcd.h"
|
||||
#include "dwc_otg_regs.h"
|
||||
|
||||
#include <linux/jiffies.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/fiq.h>
|
||||
|
||||
|
||||
extern bool microframe_schedule;
|
||||
|
||||
/** @file
|
||||
* This file contains the implementation of the HCD Interrupt handlers.
|
||||
*/
|
||||
|
||||
int fiq_done, int_done;
|
||||
|
||||
#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) };
|
||||
|
||||
if(dbg_lvl & dbg_lvl_req || dbg_lvl == FIQDBG_ERR)
|
||||
{
|
||||
local_fiq_disable();
|
||||
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_fiq_enable();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/** 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;
|
||||
haintmsk_data_t haintmsk;
|
||||
|
||||
#ifdef DEBUG
|
||||
dwc_otg_core_global_regs_t *global_regs = core_if->core_global_regs;
|
||||
#endif
|
||||
|
||||
DWC_SPINLOCK(dwc_otg_hcd->lock);
|
||||
|
||||
gintsts.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintsts);
|
||||
gintmsk.d32 = DWC_READ_REG32(&core_if->core_global_regs->gintmsk);
|
||||
|
||||
|
||||
if (dwc_otg_check_haps_status(core_if) == -1 ) {
|
||||
DWC_WARN("HAPS is disconnected");
|
||||
goto exit_handler_routine;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/* Exit from ISR if core is hibernated */
|
||||
if (core_if->hibernation_suspend == 1) {
|
||||
goto exit_handler_routine;
|
||||
return retval;
|
||||
}
|
||||
|
||||
DWC_SPINLOCK(dwc_otg_hcd->lock);
|
||||
/* Check if HOST Mode */
|
||||
if (dwc_otg_is_host_mode(core_if)) {
|
||||
if (fiq_enable&&dwc_otg_hcd->core_if->use_fiq_flag) {
|
||||
local_fiq_disable();
|
||||
/* Pull in from the FIQ's disabled mask */
|
||||
gintmsk.d32 = gintmsk.d32 | ~(dwc_otg_hcd->fiq_state->gintmsk_saved.d32);
|
||||
dwc_otg_hcd->fiq_state->gintmsk_saved.d32 = ~0;
|
||||
}
|
||||
|
||||
if (fiq_fsm_enable && dwc_otg_hcd->core_if->use_fiq_flag && ( 0x0000FFFF & ~(dwc_otg_hcd->fiq_state->haintmsk_saved.b2.chint))) {
|
||||
gintsts.b.hcintr = 1;
|
||||
}
|
||||
|
||||
/* Danger will robinson: fake a SOF if necessary */
|
||||
if (fiq_fsm_enable && dwc_otg_hcd->core_if->use_fiq_flag && (dwc_otg_hcd->fiq_state->gintmsk_saved.b.sofintr == 1)) {
|
||||
gintsts.b.sofintr = 1;
|
||||
}
|
||||
gintsts.d32 &= gintmsk.d32;
|
||||
|
||||
if (fiq_enable&&dwc_otg_hcd->core_if->use_fiq_flag)
|
||||
local_fiq_enable();
|
||||
|
||||
gintsts.d32 = dwc_otg_read_core_intr(core_if);
|
||||
if (!gintsts.d32) {
|
||||
goto exit_handler_routine;
|
||||
DWC_SPINUNLOCK(dwc_otg_hcd->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Don't print debug message in the interrupt handler on SOF */
|
||||
#ifndef DEBUG_SOF
|
||||
@@ -144,6 +83,7 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd)
|
||||
"DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x\n",
|
||||
gintsts.d32);
|
||||
#endif
|
||||
|
||||
if (gintsts.b.sofintr) {
|
||||
retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd);
|
||||
}
|
||||
@@ -161,10 +101,7 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd)
|
||||
/** @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);
|
||||
@@ -196,50 +133,6 @@ int32_t dwc_otg_hcd_handle_intr(dwc_otg_hcd_t * dwc_otg_hcd)
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
exit_handler_routine:
|
||||
if (fiq_enable && dwc_otg_hcd->core_if->use_fiq_flag) {
|
||||
gintmsk_data_t gintmsk_new;
|
||||
haintmsk_data_t haintmsk_new;
|
||||
local_fiq_disable();
|
||||
gintmsk_new.d32 = *(volatile uint32_t *)&dwc_otg_hcd->fiq_state->gintmsk_saved.d32;
|
||||
if(fiq_fsm_enable)
|
||||
haintmsk_new.d32 = *(volatile uint32_t *)&dwc_otg_hcd->fiq_state->haintmsk_saved.d32;
|
||||
else
|
||||
haintmsk_new.d32 = 0x0000FFFF;
|
||||
|
||||
/* The FIQ could have sneaked another interrupt in. If so, don't clear MPHI */
|
||||
if ((gintmsk_new.d32 == ~0) && (haintmsk_new.d32 == 0x0000FFFF)) {
|
||||
#if 0
|
||||
DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.intstat, (1<<16));
|
||||
if (dwc_otg_hcd->fiq_state->mphi_int_count >= 50) {
|
||||
fiq_print(FIQDBG_INT, dwc_otg_hcd->fiq_state, "MPHI CLR");
|
||||
DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl, ((1<<31) + (1<<16)));
|
||||
while (!(DWC_READ_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & (1 << 17)))
|
||||
;
|
||||
DWC_WRITE_REG32(dwc_otg_hcd->fiq_state->mphi_regs.ctrl, (1<<31));
|
||||
dwc_otg_hcd->fiq_state->mphi_int_count = 0;
|
||||
}
|
||||
#endif
|
||||
int_done++;
|
||||
}
|
||||
haintmsk.d32 = DWC_READ_REG32(&core_if->host_if->host_global_regs->haintmsk);
|
||||
/* Re-enable interrupts that the FIQ masked (first time round) */
|
||||
FIQ_WRITE(dwc_otg_hcd->fiq_state->dwc_regs_base + GINTMSK, gintmsk.d32);
|
||||
local_fiq_enable();
|
||||
|
||||
if ((jiffies / HZ) > last_time) {
|
||||
//dwc_otg_qh_t *qh;
|
||||
//dwc_list_link_t *cur;
|
||||
/* Once a second output the fiq and irq numbers, useful for debug */
|
||||
last_time = jiffies / HZ;
|
||||
// DWC_WARN("np_kick=%d AHC=%d sched_frame=%d cur_frame=%d int_done=%d fiq_done=%d",
|
||||
// dwc_otg_hcd->fiq_state->kick_np_queues, dwc_otg_hcd->available_host_channels,
|
||||
// dwc_otg_hcd->fiq_state->next_sched_frame, hfnum.b.frnum, int_done, dwc_otg_hcd->fiq_state->fiq_done);
|
||||
//printk(KERN_WARNING "Periodic queues:\n");
|
||||
}
|
||||
}
|
||||
|
||||
DWC_SPINUNLOCK(dwc_otg_hcd->lock);
|
||||
return retval;
|
||||
}
|
||||
@@ -247,22 +140,20 @@ exit_handler_routine:
|
||||
#ifdef DWC_TRACK_MISSED_SOFS
|
||||
#warning Compiling code to track missed SOFs
|
||||
#define FRAME_NUM_ARRAY_SIZE 1000
|
||||
|
||||
/**
|
||||
* This function is for debug only.
|
||||
*/
|
||||
void track_missed_sofs(uint16_t curr_frame_number)
|
||||
static inline void track_missed_sofs(uint16_t curr_frame_number)
|
||||
{
|
||||
|
||||
static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM;
|
||||
static int dumped_frame_num_array = 0;
|
||||
static uint16_t frame_num_array[FRAME_NUM_ARRAY_SIZE];
|
||||
static uint16_t last_frame_num_array[FRAME_NUM_ARRAY_SIZE];
|
||||
static int frame_num_idx = 0;
|
||||
static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM;
|
||||
static int dumped_frame_num_array = 0;
|
||||
|
||||
if (frame_num_idx < FRAME_NUM_ARRAY_SIZE) {
|
||||
if ((((last_frame_num + 1) & 0x3fff) !=
|
||||
curr_frame_number)&&(last_frame_num!=curr_frame_number)){
|
||||
if (((last_frame_num + 1) & DWC_HFNUM_MAX_FRNUM) !=
|
||||
curr_frame_number) {
|
||||
frame_num_array[frame_num_idx] = curr_frame_number;
|
||||
last_frame_num_array[frame_num_idx++] = last_frame_num;
|
||||
}
|
||||
@@ -289,12 +180,10 @@ void track_missed_sofs(uint16_t curr_frame_number)
|
||||
int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd)
|
||||
{
|
||||
hfnum_data_t hfnum;
|
||||
gintsts_data_t gintsts = { .d32 = 0 };
|
||||
dwc_list_link_t *qh_entry;
|
||||
dwc_otg_qh_t *qh;
|
||||
dwc_otg_transaction_type_e tr_type;
|
||||
int did_something = 0;
|
||||
int32_t next_sched_frame = -1;
|
||||
gintsts_data_t gintsts = {.d32 = 0 };
|
||||
|
||||
hfnum.d32 =
|
||||
DWC_READ_REG32(&hcd->core_if->host_if->host_global_regs->hfnum);
|
||||
@@ -324,31 +213,17 @@ int32_t dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd_t * hcd)
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fiq_enable&&hcd->core_if->use_fiq_flag)
|
||||
hcd->fiq_state->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 - but do not trample on the FIQ sof */
|
||||
if (!(fiq_fsm_enable&&hcd->core_if->use_fiq_flag)) {
|
||||
/* Clear interrupt */
|
||||
gintsts.b.sofintr = 1;
|
||||
DWC_WRITE_REG32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -638,24 +513,13 @@ int32_t dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd_t * dwc_otg_hcd)
|
||||
{
|
||||
int i;
|
||||
int retval = 0;
|
||||
haint_data_t haint = { .d32 = 0 } ;
|
||||
haint_data_t haint;
|
||||
|
||||
/* Clear appropriate bits in HCINTn to clear the interrupt bit in
|
||||
* GINTSTS */
|
||||
|
||||
if (!(fiq_fsm_enable&&dwc_otg_hcd->core_if->use_fiq_flag))
|
||||
haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if);
|
||||
|
||||
// Overwrite with saved interrupts from fiq handler
|
||||
if(fiq_fsm_enable&&dwc_otg_hcd->core_if->use_fiq_flag)
|
||||
{
|
||||
/* check the mask? */
|
||||
local_fiq_disable();
|
||||
haint.b2.chint |= ~(dwc_otg_hcd->fiq_state->haintmsk_saved.b2.chint);
|
||||
dwc_otg_hcd->fiq_state->haintmsk_saved.b2.chint = ~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);
|
||||
@@ -754,7 +618,7 @@ static int update_urb_state_xfer_comp(dwc_hc_t * hc,
|
||||
&& (urb->actual_length == urb->length)
|
||||
&& !(urb->length % hc->max_packet)) {
|
||||
xfer_done = 0;
|
||||
} else if (short_read || urb->actual_length >= urb->length) {
|
||||
} else if (short_read || urb->actual_length == urb->length) {
|
||||
xfer_done = 1;
|
||||
urb->status = 0;
|
||||
}else if(urb->actual_length > urb->length){
|
||||
@@ -831,7 +695,9 @@ update_isoc_urb_state(dwc_otg_hcd_t * hcd,
|
||||
dwc_otg_hcd_urb_t *urb = qtd->urb;
|
||||
dwc_otg_halt_status_e ret_val = halt_status;
|
||||
struct dwc_otg_hcd_iso_packet_desc *frame_desc;
|
||||
|
||||
#if 0
|
||||
dwc_otg_hcd_urb_list_t * urb_list;
|
||||
#endif
|
||||
frame_desc = &urb->iso_descs[qtd->isoc_frame_index];
|
||||
switch (halt_status) {
|
||||
case DWC_OTG_HC_XFER_COMPLETE:
|
||||
@@ -883,12 +749,33 @@ update_isoc_urb_state(dwc_otg_hcd_t * hcd,
|
||||
DWC_ASSERT(1, "Unhandled _halt_status (%d)\n", halt_status);
|
||||
break;
|
||||
}
|
||||
if (++qtd->isoc_frame_index == urb->packet_count) {
|
||||
if ((++qtd->isoc_frame_index == urb->packet_count) ||(urb->qh_state == URB_STATE_DQUEUE)){
|
||||
/*
|
||||
* urb->status is not used for isoc transfers.
|
||||
* The individual frame_desc statuses are used instead.
|
||||
*/
|
||||
hcd->fops->complete(hcd, urb->priv, urb, 0);
|
||||
|
||||
#if 0
|
||||
urb_list = DWC_ALLOC(sizeof(dwc_otg_hcd_urb_list_t));
|
||||
if (urb_list == NULL) {
|
||||
DWC_ASSERT(1, "No memory alloc in update_isoc_urb_state\n");
|
||||
}
|
||||
urb_list->urb = urb;
|
||||
DWC_SPINLOCK(hcd->isoc_comp_urbs_lock);
|
||||
DWC_LIST_INSERT_TAIL(&hcd->isoc_comp_urbs_list, &urb_list->urb_list_entry);
|
||||
DWC_SPINUNLOCK(hcd->isoc_comp_urbs_lock);
|
||||
#else
|
||||
int i;
|
||||
for(i = 0; i < MAX_EPS_CHANNELS; i++){
|
||||
if(hcd->isoc_comp_urbs[i] == NULL){
|
||||
hcd->isoc_comp_urbs[i] = urb->priv;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
hcd->fops->hcd_isoc_complete(hcd,urb->priv,urb,0);
|
||||
DWC_TASK_SCHEDULE(hcd->isoc_complete_tasklet);
|
||||
#endif
|
||||
ret_val = DWC_OTG_HC_XFER_URB_COMPLETE;
|
||||
} else {
|
||||
ret_val = DWC_OTG_HC_XFER_COMPLETE;
|
||||
@@ -946,22 +833,9 @@ static void release_channel(dwc_otg_hcd_t * hcd,
|
||||
{
|
||||
dwc_otg_transaction_type_e tr_type;
|
||||
int free_qtd;
|
||||
dwc_irqflags_t flags;
|
||||
dwc_spinlock_t *channel_lock = hcd->channel_lock;
|
||||
|
||||
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_fsm_enable && hcd->core_if->use_fiq_flag && 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 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
DWC_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d\n",
|
||||
__func__, hc->hc_num, halt_status);
|
||||
|
||||
switch (halt_status) {
|
||||
case DWC_OTG_HC_XFER_URB_COMPLETE:
|
||||
@@ -1015,12 +889,9 @@ cleanup:
|
||||
* function clears the channel interrupt enables and conditions, so
|
||||
* there's no need to clear the Channel Halted interrupt separately.
|
||||
*/
|
||||
if (fiq_fsm_enable && hcd->core_if->use_fiq_flag && hcd->fiq_state->channel[hc->hc_num].fsm != FIQ_PASSTHROUGH)
|
||||
dwc_otg_cleanup_fiq_channel(hcd, hc->hc_num);
|
||||
dwc_otg_hc_cleanup(hcd->core_if, hc);
|
||||
DWC_CIRCLEQ_INSERT_TAIL(&hcd->free_hc_list, hc, hc_list_entry);
|
||||
|
||||
if (!microframe_schedule) {
|
||||
switch (hc->ep_type) {
|
||||
case DWC_OTG_EP_TYPE_CONTROL:
|
||||
case DWC_OTG_EP_TYPE_BULK:
|
||||
@@ -1035,13 +906,6 @@ cleanup:
|
||||
*/
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
||||
DWC_SPINLOCK_IRQSAVE(channel_lock, &flags);
|
||||
hcd->available_host_channels++;
|
||||
fiq_print(FIQDBG_INT, hcd->fiq_state, "AHC = %d ", hcd->available_host_channels);
|
||||
DWC_SPINUNLOCK_IRQRESTORE(channel_lock, flags);
|
||||
}
|
||||
|
||||
/* Try to queue more transfers now that there's a free channel. */
|
||||
tr_type = dwc_otg_hcd_select_transactions(hcd);
|
||||
@@ -1256,6 +1120,8 @@ static int32_t handle_hc_xfercomp_intr(dwc_otg_hcd_t * hcd,
|
||||
*/
|
||||
|
||||
if (hc->qh->do_split) {
|
||||
if(hc->ep_type == DWC_OTG_EP_TYPE_INTR)
|
||||
hcd->ssplit_lock = 0;
|
||||
if ((hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && hc->ep_is_in
|
||||
&& hcd->core_if->dma_enable) {
|
||||
if (qtd->complete_split
|
||||
@@ -1378,6 +1244,9 @@ static int32_t handle_hc_stall_intr(dwc_otg_hcd_t * hcd,
|
||||
goto handle_stall_done;
|
||||
}
|
||||
|
||||
if(pipe_type == UE_INTERRUPT)
|
||||
hcd->ssplit_lock = 0;
|
||||
|
||||
if (pipe_type == UE_CONTROL) {
|
||||
hcd->fops->complete(hcd, urb->priv, urb, -DWC_E_PIPE);
|
||||
}
|
||||
@@ -1457,17 +1326,6 @@ static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd,
|
||||
DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
|
||||
"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 && qtd->qh->do_split)
|
||||
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.
|
||||
@@ -1476,6 +1334,11 @@ static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd,
|
||||
if (hc->complete_split) {
|
||||
qtd->error_count = 0;
|
||||
}
|
||||
|
||||
if((hcd->ssplit_lock == dwc_otg_hcd_get_dev_addr(&qtd->urb->pipe_info)) &&
|
||||
(dwc_otg_hcd_get_pipe_type(&qtd->urb->pipe_info) == UE_INTERRUPT))
|
||||
hcd->ssplit_lock = 0;
|
||||
|
||||
qtd->complete_split = 0;
|
||||
halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
|
||||
goto handle_nak_done;
|
||||
@@ -1490,11 +1353,7 @@ static int32_t handle_hc_nak_intr(dwc_otg_hcd_t * hcd,
|
||||
* 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;
|
||||
}
|
||||
@@ -1606,15 +1465,6 @@ static int32_t handle_hc_ack_intr(dwc_otg_hcd_t * hcd,
|
||||
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) {
|
||||
@@ -1677,10 +1527,8 @@ static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * hcd,
|
||||
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) ||
|
||||
(fiq_fsm_enable&&hcd->core_if->use_fiq_flag)) {
|
||||
dwc_full_frame_num(hc->qh->sched_frame)) {
|
||||
/*
|
||||
* No longer in the same full speed frame.
|
||||
* Treat this as a transaction error.
|
||||
@@ -1695,6 +1543,7 @@ static int32_t handle_hc_nyet_intr(dwc_otg_hcd_t * hcd,
|
||||
qtd->error_count++;
|
||||
#endif
|
||||
qtd->complete_split = 0;
|
||||
hcd->ssplit_lock = 0;
|
||||
halt_channel(hcd, hc, qtd,
|
||||
DWC_OTG_HC_XFER_XACT_ERR);
|
||||
/** @todo add support for isoc release */
|
||||
@@ -1899,8 +1748,10 @@ static int32_t handle_hc_xacterr_intr(dwc_otg_hcd_t * hcd,
|
||||
break;
|
||||
case UE_INTERRUPT:
|
||||
qtd->error_count++;
|
||||
if (hc->do_split && hc->complete_split) {
|
||||
if (hc->do_split){
|
||||
if(hc->complete_split)
|
||||
qtd->complete_split = 0;
|
||||
hcd->ssplit_lock = 0;
|
||||
}
|
||||
halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
|
||||
break;
|
||||
@@ -1967,28 +1818,13 @@ static int32_t handle_hc_datatglerr_intr(dwc_otg_hcd_t * hcd,
|
||||
dwc_otg_qtd_t * qtd)
|
||||
{
|
||||
DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
|
||||
"Data Toggle Error on %s transfer--\n",
|
||||
hc->hc_num, (hc->ep_is_in ? "IN" : "OUT"));
|
||||
"Data Toggle Error--\n", hc->hc_num);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
if (hc->ep_is_in) {
|
||||
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);
|
||||
@@ -2141,8 +1977,6 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd,
|
||||
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) {
|
||||
/*
|
||||
@@ -2182,6 +2016,8 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd,
|
||||
("%s: Halt channel %d (assume incomplete periodic transfer)\n",
|
||||
__func__, hc->hc_num);
|
||||
#endif
|
||||
if (hc->do_split && (hc->ep_type == DWC_OTG_EP_TYPE_INTR))
|
||||
hcd->ssplit_lock = 0;
|
||||
halt_channel(hcd, hc, qtd,
|
||||
DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE);
|
||||
} else {
|
||||
@@ -2192,24 +2028,14 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * hcd,
|
||||
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);
|
||||
clear_hc_int(hc_regs, chhltd);
|
||||
}
|
||||
|
||||
}
|
||||
} 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);
|
||||
clear_hc_int(hc_regs, chhltd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2246,367 +2072,6 @@ static int32_t handle_hc_chhltd_intr(dwc_otg_hcd_t * hcd,
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* dwc_otg_fiq_unmangle_isoc() - Update the iso_frame_desc structure on
|
||||
* FIQ transfer completion
|
||||
* @hcd: Pointer to dwc_otg_hcd struct
|
||||
* @num: Host channel number
|
||||
*
|
||||
* 1. Un-mangle the status as recorded in each iso_frame_desc status
|
||||
* 2. Copy it from the dwc_otg_urb into the real URB
|
||||
*/
|
||||
void dwc_otg_fiq_unmangle_isoc(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, dwc_otg_qtd_t *qtd, uint32_t num)
|
||||
{
|
||||
struct dwc_otg_hcd_urb *dwc_urb = qtd->urb;
|
||||
int nr_frames = dwc_urb->packet_count;
|
||||
int i;
|
||||
hcint_data_t frame_hcint;
|
||||
|
||||
for (i = 0; i < nr_frames; i++) {
|
||||
frame_hcint.d32 = dwc_urb->iso_descs[i].status;
|
||||
if (frame_hcint.b.xfercomp) {
|
||||
dwc_urb->iso_descs[i].status = 0;
|
||||
dwc_urb->actual_length += dwc_urb->iso_descs[i].actual_length;
|
||||
} else if (frame_hcint.b.frmovrun) {
|
||||
if (qh->ep_is_in)
|
||||
dwc_urb->iso_descs[i].status = -DWC_E_NO_STREAM_RES;
|
||||
else
|
||||
dwc_urb->iso_descs[i].status = -DWC_E_COMMUNICATION;
|
||||
dwc_urb->error_count++;
|
||||
dwc_urb->iso_descs[i].actual_length = 0;
|
||||
} else if (frame_hcint.b.xacterr) {
|
||||
dwc_urb->iso_descs[i].status = -DWC_E_PROTOCOL;
|
||||
dwc_urb->error_count++;
|
||||
dwc_urb->iso_descs[i].actual_length = 0;
|
||||
} else if (frame_hcint.b.bblerr) {
|
||||
dwc_urb->iso_descs[i].status = -DWC_E_OVERFLOW;
|
||||
dwc_urb->error_count++;
|
||||
dwc_urb->iso_descs[i].actual_length = 0;
|
||||
} else {
|
||||
/* Something went wrong */
|
||||
dwc_urb->iso_descs[i].status = -1;
|
||||
dwc_urb->iso_descs[i].actual_length = 0;
|
||||
dwc_urb->error_count++;
|
||||
}
|
||||
}
|
||||
//printk_ratelimited(KERN_INFO "%s: HS isochronous of %d/%d frames with %d errors complete\n",
|
||||
// __FUNCTION__, i, dwc_urb->packet_count, dwc_urb->error_count);
|
||||
hcd->fops->complete(hcd, dwc_urb->priv, dwc_urb, 0);
|
||||
release_channel(hcd, qh->channel, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc_otg_fiq_unsetup_per_dma() - Remove data from bounce buffers for split transactions
|
||||
* @hcd: Pointer to dwc_otg_hcd struct
|
||||
* @num: Host channel number
|
||||
*
|
||||
* Copies data from the FIQ bounce buffers into the URB's transfer buffer. Does not modify URB state.
|
||||
* Returns total length of data or -1 if the buffers were not used.
|
||||
*
|
||||
*/
|
||||
int dwc_otg_fiq_unsetup_per_dma(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, dwc_otg_qtd_t *qtd, uint32_t num)
|
||||
{
|
||||
dwc_hc_t *hc = qh->channel;
|
||||
struct fiq_dma_blob *blob = hcd->fiq_dmab;
|
||||
struct fiq_channel_state *st = &hcd->fiq_state->channel[num];
|
||||
uint8_t *ptr = NULL;
|
||||
int index = 0, len = 0;
|
||||
int i = 0;
|
||||
if (hc->ep_is_in) {
|
||||
/* Copy data out of the DMA bounce buffers to the URB's buffer.
|
||||
* The align_buf is ignored as this is ignored on FSM enqueue. */
|
||||
ptr = qtd->urb->buf;
|
||||
if (qh->ep_type == UE_ISOCHRONOUS) {
|
||||
/* Isoc IN transactions - grab the offset of the iso_frame_desc into the URB transfer buffer */
|
||||
index = qtd->isoc_frame_index;
|
||||
ptr += qtd->urb->iso_descs[index].offset;
|
||||
} else {
|
||||
/* Need to increment by actual_length for interrupt IN */
|
||||
ptr += qtd->urb->actual_length;
|
||||
}
|
||||
|
||||
for (i = 0; i < st->dma_info.index; i++) {
|
||||
len += st->dma_info.slot_len[i];
|
||||
dwc_memcpy(ptr, &blob->channel[num].index[i].buf[0], st->dma_info.slot_len[i]);
|
||||
ptr += st->dma_info.slot_len[i];
|
||||
}
|
||||
return len;
|
||||
} else {
|
||||
/* OUT endpoints - nothing to do. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* dwc_otg_hcd_handle_hc_fsm() - handle an unmasked channel interrupt
|
||||
* from a channel handled in the FIQ
|
||||
* @hcd: Pointer to dwc_otg_hcd struct
|
||||
* @num: Host channel number
|
||||
*
|
||||
* If a host channel interrupt was received by the IRQ and this was a channel
|
||||
* used by the FIQ, the execution flow for transfer completion is substantially
|
||||
* different from the normal (messy) path. This function and its friends handles
|
||||
* channel cleanup and transaction completion from a FIQ transaction.
|
||||
*/
|
||||
int32_t dwc_otg_hcd_handle_hc_fsm(dwc_otg_hcd_t *hcd, uint32_t num)
|
||||
{
|
||||
struct fiq_channel_state *st = &hcd->fiq_state->channel[num];
|
||||
dwc_hc_t *hc = hcd->hc_ptr_array[num];
|
||||
dwc_otg_qtd_t *qtd = DWC_CIRCLEQ_FIRST(&hc->qh->qtd_list);
|
||||
dwc_otg_qh_t *qh = hc->qh;
|
||||
dwc_otg_hc_regs_t *hc_regs = hcd->core_if->host_if->hc_regs[num];
|
||||
hcint_data_t hcint = hcd->fiq_state->channel[num].hcint_copy;
|
||||
int hostchannels = 0;
|
||||
int ret = 0;
|
||||
fiq_print(FIQDBG_INT, hcd->fiq_state, "OUT %01d %01d ", num , st->fsm);
|
||||
|
||||
hostchannels = hcd->available_host_channels;
|
||||
switch (st->fsm) {
|
||||
case FIQ_TEST:
|
||||
break;
|
||||
|
||||
case FIQ_DEQUEUE_ISSUED:
|
||||
/* hc_halt was called. QTD no longer exists. */
|
||||
/* TODO: for a nonperiodic split transaction, need to issue a
|
||||
* CLEAR_TT_BUFFER hub command if we were in the start-split phase.
|
||||
*/
|
||||
release_channel(hcd, hc, NULL, hc->halt_status);
|
||||
ret = 1;
|
||||
break;
|
||||
|
||||
case FIQ_NP_SPLIT_DONE:
|
||||
/* Nonperiodic transaction complete. */
|
||||
if (!hc->ep_is_in) {
|
||||
qtd->ssplit_out_xfer_count = hc->xfer_len;
|
||||
}
|
||||
if (hcint.b.xfercomp) {
|
||||
handle_hc_xfercomp_intr(hcd, hc, hc_regs, qtd);
|
||||
} else if (hcint.b.nak) {
|
||||
handle_hc_nak_intr(hcd, hc, hc_regs, qtd);
|
||||
}
|
||||
ret = 1;
|
||||
break;
|
||||
|
||||
case FIQ_NP_SPLIT_HS_ABORTED:
|
||||
/* A HS abort is a 3-strikes on the HS bus at any point in the transaction.
|
||||
* Normally a CLEAR_TT_BUFFER hub command would be required: we can't do that
|
||||
* because there's no guarantee which order a non-periodic split happened in.
|
||||
* We could end up clearing a perfectly good transaction out of the buffer.
|
||||
*/
|
||||
if (hcint.b.xacterr) {
|
||||
qtd->error_count += st->nr_errors;
|
||||
handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
|
||||
} else if (hcint.b.ahberr) {
|
||||
handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd);
|
||||
} else {
|
||||
local_fiq_disable();
|
||||
BUG();
|
||||
}
|
||||
break;
|
||||
|
||||
case FIQ_NP_SPLIT_LS_ABORTED:
|
||||
/* A few cases can cause this - either an unknown state on a SSPLIT or
|
||||
* STALL/data toggle error response on a CSPLIT */
|
||||
if (hcint.b.stall) {
|
||||
handle_hc_stall_intr(hcd, hc, hc_regs, qtd);
|
||||
} else if (hcint.b.datatglerr) {
|
||||
handle_hc_datatglerr_intr(hcd, hc, hc_regs, qtd);
|
||||
} else if (hcint.b.bblerr) {
|
||||
handle_hc_babble_intr(hcd, hc, hc_regs, qtd);
|
||||
} else if (hcint.b.ahberr) {
|
||||
handle_hc_ahberr_intr(hcd, hc, hc_regs, qtd);
|
||||
} else {
|
||||
local_fiq_disable();
|
||||
BUG();
|
||||
}
|
||||
break;
|
||||
|
||||
case FIQ_PER_SPLIT_DONE:
|
||||
/* Isoc IN or Interrupt IN/OUT */
|
||||
|
||||
/* Flow control here is different from the normal execution by the driver.
|
||||
* We need to completely ignore most of the driver's method of handling
|
||||
* split transactions and do it ourselves.
|
||||
*/
|
||||
if (hc->ep_type == UE_INTERRUPT) {
|
||||
if (hcint.b.nak) {
|
||||
handle_hc_nak_intr(hcd, hc, hc_regs, qtd);
|
||||
} else if (hc->ep_is_in) {
|
||||
int len;
|
||||
len = dwc_otg_fiq_unsetup_per_dma(hcd, hc->qh, qtd, num);
|
||||
//printk(KERN_NOTICE "FIQ Transaction: hc=%d len=%d urb_len = %d\n", num, len, qtd->urb->length);
|
||||
qtd->urb->actual_length += len;
|
||||
if (qtd->urb->actual_length >= qtd->urb->length) {
|
||||
qtd->urb->status = 0;
|
||||
hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, qtd->urb->status);
|
||||
release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
|
||||
} else {
|
||||
/* Interrupt transfer not complete yet - is it a short read? */
|
||||
if (len < hc->max_packet) {
|
||||
/* Interrupt transaction complete */
|
||||
qtd->urb->status = 0;
|
||||
hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, qtd->urb->status);
|
||||
release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
|
||||
} else {
|
||||
/* Further transactions required */
|
||||
release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Interrupt OUT complete. */
|
||||
dwc_otg_hcd_save_data_toggle(hc, hc_regs, qtd);
|
||||
qtd->urb->actual_length += hc->xfer_len;
|
||||
if (qtd->urb->actual_length >= qtd->urb->length) {
|
||||
qtd->urb->status = 0;
|
||||
hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, qtd->urb->status);
|
||||
release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
|
||||
} else {
|
||||
release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* ISOC IN complete. */
|
||||
struct dwc_otg_hcd_iso_packet_desc *frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
|
||||
int len = 0;
|
||||
/* Record errors, update qtd. */
|
||||
if (st->nr_errors) {
|
||||
frame_desc->actual_length = 0;
|
||||
frame_desc->status = -DWC_E_PROTOCOL;
|
||||
} else {
|
||||
frame_desc->status = 0;
|
||||
/* Unswizzle dma */
|
||||
len = dwc_otg_fiq_unsetup_per_dma(hcd, qh, qtd, num);
|
||||
frame_desc->actual_length = len;
|
||||
}
|
||||
qtd->isoc_frame_index++;
|
||||
if (qtd->isoc_frame_index == qtd->urb->packet_count) {
|
||||
hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
|
||||
release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
|
||||
} else {
|
||||
release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FIQ_PER_ISO_OUT_DONE: {
|
||||
struct dwc_otg_hcd_iso_packet_desc *frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
|
||||
/* Record errors, update qtd. */
|
||||
if (st->nr_errors) {
|
||||
frame_desc->actual_length = 0;
|
||||
frame_desc->status = -DWC_E_PROTOCOL;
|
||||
} else {
|
||||
frame_desc->status = 0;
|
||||
frame_desc->actual_length = frame_desc->length;
|
||||
}
|
||||
qtd->isoc_frame_index++;
|
||||
qtd->isoc_split_offset = 0;
|
||||
if (qtd->isoc_frame_index == qtd->urb->packet_count) {
|
||||
hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
|
||||
release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
|
||||
} else {
|
||||
release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FIQ_PER_SPLIT_NYET_ABORTED:
|
||||
/* Doh. lost the data. */
|
||||
printk_ratelimited(KERN_INFO "Transfer to device %d endpoint 0x%x frame %d failed "
|
||||
"- FIQ reported NYET. Data may have been lost.\n",
|
||||
hc->dev_addr, hc->ep_num, dwc_otg_hcd_get_frame_number(hcd) >> 3);
|
||||
if (hc->ep_type == UE_ISOCHRONOUS) {
|
||||
struct dwc_otg_hcd_iso_packet_desc *frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
|
||||
/* Record errors, update qtd. */
|
||||
frame_desc->actual_length = 0;
|
||||
frame_desc->status = -DWC_E_PROTOCOL;
|
||||
qtd->isoc_frame_index++;
|
||||
qtd->isoc_split_offset = 0;
|
||||
if (qtd->isoc_frame_index == qtd->urb->packet_count) {
|
||||
hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
|
||||
release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
|
||||
} else {
|
||||
release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE);
|
||||
}
|
||||
} else {
|
||||
release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
|
||||
}
|
||||
break;
|
||||
|
||||
case FIQ_HS_ISOC_DONE:
|
||||
/* The FIQ has performed a whole pile of isochronous transactions.
|
||||
* The status is recorded as the interrupt state should the transaction
|
||||
* fail.
|
||||
*/
|
||||
dwc_otg_fiq_unmangle_isoc(hcd, qh, qtd, num);
|
||||
break;
|
||||
|
||||
case FIQ_PER_SPLIT_LS_ABORTED:
|
||||
if (hcint.b.xacterr) {
|
||||
/* Hub has responded with an ERR packet. Device
|
||||
* has been unplugged or the port has been disabled.
|
||||
* TODO: need to issue a reset to the hub port. */
|
||||
qtd->error_count += 3;
|
||||
handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
|
||||
} else if (hcint.b.stall) {
|
||||
handle_hc_stall_intr(hcd, hc, hc_regs, qtd);
|
||||
} else if (hcint.b.bblerr) {
|
||||
handle_hc_babble_intr(hcd, hc, hc_regs, qtd);
|
||||
} else {
|
||||
printk_ratelimited(KERN_INFO "Transfer to device %d endpoint 0x%x failed "
|
||||
"- FIQ reported FSM=%d. Data may have been lost.\n",
|
||||
st->fsm, hc->dev_addr, hc->ep_num);
|
||||
release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
|
||||
}
|
||||
break;
|
||||
|
||||
case FIQ_PER_SPLIT_HS_ABORTED:
|
||||
/* Either the SSPLIT phase suffered transaction errors or something
|
||||
* unexpected happened.
|
||||
*/
|
||||
qtd->error_count += 3;
|
||||
handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
|
||||
release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
|
||||
break;
|
||||
|
||||
case FIQ_PER_SPLIT_TIMEOUT:
|
||||
/* Couldn't complete in the nominated frame */
|
||||
printk(KERN_INFO "Transfer to device %d endpoint 0x%x frame %d failed "
|
||||
"- FIQ timed out. Data may have been lost.\n",
|
||||
hc->dev_addr, hc->ep_num, dwc_otg_hcd_get_frame_number(hcd) >> 3);
|
||||
if (hc->ep_type == UE_ISOCHRONOUS) {
|
||||
struct dwc_otg_hcd_iso_packet_desc *frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index];
|
||||
/* Record errors, update qtd. */
|
||||
frame_desc->actual_length = 0;
|
||||
if (hc->ep_is_in) {
|
||||
frame_desc->status = -DWC_E_NO_STREAM_RES;
|
||||
} else {
|
||||
frame_desc->status = -DWC_E_COMMUNICATION;
|
||||
}
|
||||
qtd->isoc_frame_index++;
|
||||
if (qtd->isoc_frame_index == qtd->urb->packet_count) {
|
||||
hcd->fops->complete(hcd, qtd->urb->priv, qtd->urb, 0);
|
||||
release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_URB_COMPLETE);
|
||||
} else {
|
||||
release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_COMPLETE);
|
||||
}
|
||||
} else {
|
||||
release_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
local_fiq_disable();
|
||||
DWC_WARN("unexpected state received on hc=%d fsm=%d", hc->hc_num, st->fsm);
|
||||
BUG();
|
||||
}
|
||||
//if (hostchannels != hcd->available_host_channels) {
|
||||
/* should have incremented by now! */
|
||||
// BUG();
|
||||
// }
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Handles interrupt for a specific Host Channel */
|
||||
int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num)
|
||||
{
|
||||
@@ -2621,38 +2086,8 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num)
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
* FSM mode: Check to see if this is a HC interrupt from a channel handled by the FIQ.
|
||||
* Execution path is fundamentally different for the channels after a FIQ has completed
|
||||
* a split transaction.
|
||||
*/
|
||||
if (fiq_fsm_enable&&dwc_otg_hcd->core_if->use_fiq_flag) {
|
||||
switch (dwc_otg_hcd->fiq_state->channel[num].fsm) {
|
||||
case FIQ_PASSTHROUGH:
|
||||
break;
|
||||
case FIQ_PASSTHROUGH_ERRORSTATE:
|
||||
/* Hook into the error count */
|
||||
fiq_print(FIQDBG_ERR, dwc_otg_hcd->fiq_state, "HCDERR%02d", num);
|
||||
if (!dwc_otg_hcd->fiq_state->channel[num].nr_errors) {
|
||||
qtd->error_count = 0;
|
||||
fiq_print(FIQDBG_ERR, dwc_otg_hcd->fiq_state, "RESET ");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dwc_otg_hcd_handle_hc_fsm(dwc_otg_hcd, num);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
hcint.d32 = DWC_READ_REG32(&hc_regs->hcint);
|
||||
hcintmsk.d32 = DWC_READ_REG32(&hc_regs->hcintmsk);
|
||||
DWC_DEBUGPL(DBG_HCDV,
|
||||
@@ -2689,7 +2124,6 @@ int32_t dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd_t * dwc_otg_hcd, uint32_t num)
|
||||
retval |= handle_hc_nak_intr(dwc_otg_hcd, hc, hc_regs, qtd);
|
||||
}
|
||||
if (hcint.b.ack) {
|
||||
if(!hcint.b.chhltd)
|
||||
retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd);
|
||||
}
|
||||
if (hcint.b.nyet) {
|
||||
|
||||
@@ -50,10 +50,7 @@
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/version.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/fiq.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/io.h>
|
||||
#include <mach/am_regs.h>
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
|
||||
#include <../drivers/usb/core/hcd.h>
|
||||
#else
|
||||
@@ -64,12 +61,6 @@
|
||||
#include "dwc_otg_dbg.h"
|
||||
#include "dwc_otg_driver.h"
|
||||
#include "dwc_otg_hcd.h"
|
||||
|
||||
extern unsigned char _dwc_otg_fiq_stub, _dwc_otg_fiq_stub_end;
|
||||
|
||||
DEFINE_PER_CPU(void *, fiq_stack_cpu);
|
||||
static DEFINE_MUTEX(fiq_lock);
|
||||
|
||||
/**
|
||||
* Gets the endpoint number from a _bEndpointAddress argument. The endpoint is
|
||||
* qualified with its direction (possible 32 endpoints per device).
|
||||
@@ -79,8 +70,6 @@ static DEFINE_MUTEX(fiq_lock);
|
||||
|
||||
static const char dwc_otg_hcd_name[] = "dwc_otg_hcd";
|
||||
|
||||
extern bool fiq_enable;
|
||||
|
||||
/** @name Linux HC Driver API Functions */
|
||||
/** @{ */
|
||||
static int urb_enqueue(struct usb_hcd *hcd,
|
||||
@@ -234,6 +223,77 @@ static void free_bus_bandwidth(struct usb_hcd *hcd, uint32_t bw,
|
||||
hcd_to_bus(hcd)->bandwidth_int_reqs--;
|
||||
}
|
||||
}
|
||||
int _hcd_isoc_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;
|
||||
|
||||
if(dwc_otg_urb->qh_state == URB_STATE_DQUEUE)
|
||||
status = -ENOENT;
|
||||
|
||||
urb->actual_length = dwc_otg_urb->actual_length;
|
||||
/* Convert status value. */
|
||||
switch (status) {
|
||||
case -DWC_E_PROTOCOL:
|
||||
status = -EPROTO;
|
||||
break;
|
||||
case -DWC_E_IN_PROGRESS:
|
||||
status = -EINPROGRESS;
|
||||
break;
|
||||
case -DWC_E_PIPE:
|
||||
status = -EPIPE;
|
||||
break;
|
||||
case -DWC_E_IO:
|
||||
status = -EIO;
|
||||
break;
|
||||
case -DWC_E_TIMEOUT:
|
||||
status = -ETIMEDOUT;
|
||||
break;
|
||||
case -DWC_E_OVERFLOW:
|
||||
status = -EOVERFLOW;
|
||||
break;
|
||||
default:
|
||||
if (status) {
|
||||
printk(KERN_DEBUG "%s:Uknown urb status %d\n",__func__, status);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
|
||||
int i;
|
||||
|
||||
urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb);
|
||||
for (i = 0; i < urb->number_of_packets; ++i) {
|
||||
urb->iso_frame_desc[i].actual_length = dwc_otg_urb->iso_descs[i].actual_length;
|
||||
urb->iso_frame_desc[i].status = dwc_otg_urb->iso_descs[i].status;
|
||||
}
|
||||
}
|
||||
|
||||
urb->status = status;
|
||||
|
||||
if (!status) {
|
||||
if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
|
||||
(urb->actual_length < urb->transfer_buffer_length)) {
|
||||
urb->status = -EREMOTEIO;
|
||||
}
|
||||
}
|
||||
|
||||
if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) ||
|
||||
(usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
|
||||
struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb);
|
||||
if (ep) {
|
||||
free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd),
|
||||
dwc_otg_hcd_get_ep_bandwidth(hcd,
|
||||
ep->hcpriv),
|
||||
urb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DWC_FREE(dwc_otg_urb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* Sets the final status of an URB and returns it to the device driver. Any
|
||||
* required cleanup of the URB is performed.
|
||||
@@ -242,8 +302,6 @@ 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;
|
||||
#ifdef DEBUG
|
||||
if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
|
||||
DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n",
|
||||
@@ -259,7 +317,7 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
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) {
|
||||
@@ -304,6 +362,108 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
|
||||
}
|
||||
}
|
||||
|
||||
urb->status = status;
|
||||
if (!status) {
|
||||
if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
|
||||
(urb->actual_length < urb->transfer_buffer_length)) {
|
||||
urb->status = -EREMOTEIO;
|
||||
}
|
||||
}
|
||||
|
||||
if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) ||
|
||||
(usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
|
||||
struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb);
|
||||
if (ep) {
|
||||
free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd),
|
||||
dwc_otg_hcd_get_ep_bandwidth(hcd,
|
||||
ep->hcpriv),
|
||||
urb);
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
|
||||
#endif
|
||||
DWC_FREE(dwc_otg_urb);
|
||||
dwc_otg_urb = NULL;
|
||||
|
||||
DWC_SPINUNLOCK(hcd->lock);
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
|
||||
usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb);
|
||||
#else
|
||||
usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, status);
|
||||
#endif
|
||||
DWC_SPINLOCK(hcd->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*copy from _complete,not use spinlock*/
|
||||
/**
|
||||
* Sets the final status of an URB and returns it to the device driver. Any
|
||||
* required cleanup of the URB is performed.
|
||||
*/
|
||||
int _complete_in_tasklet(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;
|
||||
#if 0
|
||||
#ifdef DEBUG
|
||||
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),
|
||||
usb_pipeendpoint(urb->pipe),
|
||||
usb_pipein(urb->pipe) ? "IN" : "OUT", status);
|
||||
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
|
||||
int i;
|
||||
for (i = 0; i < urb->number_of_packets; i++) {
|
||||
DWC_PRINTF(" ISO Desc %d status: %d\n",
|
||||
i, urb->iso_frame_desc[i].status);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb);
|
||||
/* Convert status value. */
|
||||
switch (status) {
|
||||
case -DWC_E_PROTOCOL:
|
||||
status = -EPROTO;
|
||||
break;
|
||||
case -DWC_E_IN_PROGRESS:
|
||||
status = -EINPROGRESS;
|
||||
break;
|
||||
case -DWC_E_PIPE:
|
||||
status = -EPIPE;
|
||||
break;
|
||||
case -DWC_E_IO:
|
||||
status = -EIO;
|
||||
break;
|
||||
case -DWC_E_TIMEOUT:
|
||||
status = -ETIMEDOUT;
|
||||
break;
|
||||
case -DWC_E_OVERFLOW:
|
||||
status = -EOVERFLOW;
|
||||
break;
|
||||
default:
|
||||
if (status) {
|
||||
DWC_PRINTF("Uknown urb status %d\n", status);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
|
||||
int i;
|
||||
|
||||
urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb);
|
||||
for (i = 0; i < urb->number_of_packets; ++i) {
|
||||
urb->iso_frame_desc[i].actual_length =
|
||||
dwc_otg_hcd_urb_get_iso_desc_actual_length
|
||||
(dwc_otg_urb, i);
|
||||
urb->iso_frame_desc[i].status =
|
||||
dwc_otg_hcd_urb_get_iso_desc_status(dwc_otg_urb, i);
|
||||
}
|
||||
}
|
||||
|
||||
urb->status = status;
|
||||
urb->hcpriv = NULL;
|
||||
if (!status) {
|
||||
@@ -323,37 +483,19 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
|
||||
urb);
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
|
||||
#endif
|
||||
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 0
|
||||
usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
|
||||
#endif
|
||||
|
||||
DWC_SPINUNLOCK(hcd->lock);
|
||||
//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, 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 0
|
||||
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);
|
||||
}
|
||||
}
|
||||
//DWC_SPINLOCK(hcd->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -363,25 +505,11 @@ static struct dwc_otg_hcd_function_ops hcd_fops = {
|
||||
.hub_info = _hub_info,
|
||||
.speed = _speed,
|
||||
.complete = _complete,
|
||||
//.complete_in_tasklet = _complete_in_tasklet,
|
||||
//.hcd_isoc_complete = _hcd_isoc_complete,
|
||||
.complete_in_tasklet = _complete_in_tasklet,
|
||||
.hcd_isoc_complete = _hcd_isoc_complete,
|
||||
.get_b_hnp_enable = _get_b_hnp_enable,
|
||||
};
|
||||
|
||||
static struct fiq_handler fh = {
|
||||
.name = "usb_fiq",
|
||||
};
|
||||
|
||||
extern void __fiq_ll_setup(long r8, long r9, long fp, void *sp);
|
||||
static void fiq_setup_helper(void *regs)
|
||||
{
|
||||
struct pt_regs *fiq_regs = regs;
|
||||
|
||||
__fiq_ll_setup(fiq_regs->ARM_r8, fiq_regs->ARM_r9, fiq_regs->ARM_fp,
|
||||
__get_cpu_var(fiq_stack_cpu) + THREAD_START_SP);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -403,11 +531,8 @@ int hcd_init(
|
||||
#elif defined(PCI_INTERFACE)
|
||||
dwc_otg_device_t *otg_dev = pci_get_drvdata(_dev);
|
||||
#endif
|
||||
|
||||
int retval = 0;
|
||||
int irqno;
|
||||
struct pt_regs regs;
|
||||
unsigned long flags = IRQF_SHARED | IRQF_DISABLED;
|
||||
int cpu;
|
||||
|
||||
DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT\n");
|
||||
|
||||
@@ -464,74 +589,6 @@ int hcd_init(
|
||||
goto error2;
|
||||
}
|
||||
|
||||
if (fiq_enable && dwc_otg_hcd->core_if->use_fiq_flag)
|
||||
{
|
||||
if (claim_fiq(&fh)) {
|
||||
DWC_ERROR("Can't claim FIQ");
|
||||
goto error2;
|
||||
}
|
||||
|
||||
DWC_WARN("FIQ at 0x%08x", (fiq_fsm_enable ? (int)&dwc_otg_fiq_fsm : (int)&dwc_otg_fiq_nop));
|
||||
DWC_WARN("FIQ ASM at 0x%08x length %d", (int)&_dwc_otg_fiq_stub, (int)(&_dwc_otg_fiq_stub_end - &_dwc_otg_fiq_stub));
|
||||
|
||||
memset(®s,0,sizeof(regs));
|
||||
|
||||
regs.ARM_r8 = (long) dwc_otg_hcd->fiq_state;
|
||||
if (fiq_fsm_enable) {
|
||||
regs.ARM_r9 = dwc_otg_hcd->core_if->core_params->host_channels;
|
||||
//regs.ARM_r10 = dwc_otg_hcd->dma;
|
||||
regs.ARM_fp = (long) dwc_otg_fiq_fsm;
|
||||
DWC_WARN("FIQ r8=0x%08x r9=0x%08x", (unsigned int)regs.ARM_r8,(unsigned int)regs.ARM_r9);
|
||||
} else {
|
||||
regs.ARM_fp = (long) dwc_otg_fiq_nop;
|
||||
}
|
||||
|
||||
mutex_lock(&fiq_lock);
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
void *stack;
|
||||
stack = (void *) __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER);
|
||||
if (WARN_ON(!stack)) {
|
||||
retval = -ENOMEM;
|
||||
mutex_unlock(&fiq_lock);
|
||||
goto error3;
|
||||
}
|
||||
per_cpu(fiq_stack_cpu, cpu) = stack;
|
||||
}
|
||||
|
||||
on_each_cpu(fiq_setup_helper, ®s, true);
|
||||
set_fiq_handler((void *) &_dwc_otg_fiq_stub, &_dwc_otg_fiq_stub_end - &_dwc_otg_fiq_stub);
|
||||
|
||||
mutex_unlock(&fiq_lock);
|
||||
|
||||
// __show_regs(®s);
|
||||
|
||||
//Set the mphi periph to the required registers
|
||||
//dwc_otg_hcd->fiq_state->mphi_regs.base = otg_dev->os_dep.mphi_base;
|
||||
//dwc_otg_hcd->fiq_state->mphi_regs.ctrl = otg_dev->os_dep.mphi_base + 0x4c;
|
||||
//dwc_otg_hcd->fiq_state->mphi_regs.outdda = otg_dev->os_dep.mphi_base + 0x28;
|
||||
//dwc_otg_hcd->fiq_state->mphi_regs.outddb = otg_dev->os_dep.mphi_base + 0x2c;
|
||||
//dwc_otg_hcd->fiq_state->mphi_regs.intstat = otg_dev->os_dep.mphi_base + 0x50;
|
||||
dwc_otg_hcd->fiq_state->dwc_regs_base = otg_dev->os_dep.base;
|
||||
//DWC_WARN("MPHI regs_base at 0x%08x", (int)dwc_otg_hcd->fiq_state->mphi_regs.base);
|
||||
//Enable mphi peripheral
|
||||
//writel((1<<31),dwc_otg_hcd->fiq_state->mphi_regs.ctrl);
|
||||
#ifdef DEBUG
|
||||
//if (readl(dwc_otg_hcd->fiq_state->mphi_regs.ctrl) & 0x80000000)
|
||||
// DWC_WARN("MPHI periph has been enabled");
|
||||
//else
|
||||
// DWC_WARN("MPHI periph has NOT been enabled");
|
||||
#endif
|
||||
//clear Timer D register
|
||||
aml_clr_reg32_mask(P_ISA_TIMER_MUX, ((3<<6)|(1<<15)|(1<<19)));
|
||||
aml_set_reg32_mask(P_ISA_TIMER_MUX, ((0<<6) | (0<<15) | (1<<19)));
|
||||
printk("enable fiq %d\n",_dev->irq);
|
||||
set_fiq_init(_dev->irq,(long)dwc_otg_hcd);
|
||||
local_fiq_enable();
|
||||
|
||||
}
|
||||
|
||||
|
||||
otg_dev->hcd->otg_dev = otg_dev;
|
||||
hcd->self.otg_port = dwc_otg_hcd_otg_port(dwc_otg_hcd);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) //don't support for LM(with 2.6.20.1 kernel)
|
||||
@@ -544,32 +601,19 @@ int hcd_init(
|
||||
// if (otg_dev->core_if->otg_ver)
|
||||
// hcd->self.is_hnp_cap = dwc_otg_get_hnpcapable(otg_dev->core_if);
|
||||
#endif
|
||||
if (fiq_enable && dwc_otg_hcd->core_if->use_fiq_flag) {
|
||||
irqno = MESON_USB_FIQ_BRIDGE;
|
||||
} else {
|
||||
irqno = _dev->irq;
|
||||
flags |= IRQ_TYPE_LEVEL_HIGH;
|
||||
}
|
||||
/*
|
||||
* Finish generic HCD initialization and start the HCD. This function
|
||||
* allocates the DMA buffer pool, registers the USB bus, requests the
|
||||
* IRQ line, and calls hcd_start method.
|
||||
*/
|
||||
retval = usb_add_hcd(hcd, irqno, flags);
|
||||
retval = usb_add_hcd(hcd, _dev->irq, IRQF_SHARED | IRQF_DISABLED);
|
||||
if (retval < 0) {
|
||||
goto error3;
|
||||
goto error2;
|
||||
}
|
||||
|
||||
dwc_otg_hcd_set_priv_data(dwc_otg_hcd, hcd);
|
||||
return 0;
|
||||
|
||||
error3:
|
||||
mutex_lock(&fiq_lock);
|
||||
for_each_possible_cpu(cpu) {
|
||||
__free_pages(per_cpu(fiq_stack_cpu, cpu), THREAD_SIZE_ORDER);
|
||||
per_cpu(fiq_stack_cpu, cpu) = NULL;
|
||||
}
|
||||
mutex_unlock(&fiq_lock);
|
||||
error2:
|
||||
usb_put_hcd(hcd);
|
||||
error1:
|
||||
@@ -673,13 +717,11 @@ int hcd_suspend(struct usb_hcd *hcd)
|
||||
{
|
||||
dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
|
||||
dwc_otg_hcd->auto_pm_suspend_flag = (hcd->flags>>31)&1;
|
||||
dwc_otg_hcd->pm_freeze_flag = (hcd->flags >> 30) & 1;
|
||||
|
||||
DWC_DEBUGPL(DBG_HCD, "HCD SUSPEND\n");
|
||||
|
||||
dwc_otg_hcd_suspend(dwc_otg_hcd);
|
||||
hcd->flags &= (~(1<<31));
|
||||
hcd->flags &= (~(1<<30));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -689,26 +731,19 @@ int hcd_resume(struct usb_hcd *hcd)
|
||||
{
|
||||
dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
|
||||
dwc_otg_hcd->auto_pm_suspend_flag = (hcd->flags>>31)&1;
|
||||
dwc_otg_hcd->pm_freeze_flag = (hcd->flags >> 30) & 1;
|
||||
|
||||
|
||||
DWC_DEBUGPL(DBG_HCD, "HCD RESUME\n");
|
||||
|
||||
dwc_otg_hcd_resume(dwc_otg_hcd);
|
||||
hcd->flags &= (~(1<<31));
|
||||
hcd->flags &= (~(1<<30));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Returns the current frame number. */
|
||||
static int get_frame_number(struct usb_hcd *hcd)
|
||||
{
|
||||
hprt0_data_t hprt0;
|
||||
dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
|
||||
hprt0.d32 = DWC_READ_REG32(dwc_otg_hcd->core_if->host_if->hprt0);
|
||||
if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED)
|
||||
return dwc_otg_hcd_get_frame_number(dwc_otg_hcd) >> 3;
|
||||
else
|
||||
|
||||
return dwc_otg_hcd_get_frame_number(dwc_otg_hcd);
|
||||
}
|
||||
|
||||
@@ -836,15 +871,16 @@ static int urb_enqueue(struct usb_hcd *hcd,
|
||||
usb_maxpacket(urb->dev, urb->pipe,
|
||||
!(usb_pipein(urb->pipe))));
|
||||
|
||||
if (hcd->self.uses_dma && (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) &&
|
||||
!urb->transfer_buffer)
|
||||
{
|
||||
DWC_ERROR("dwc_otg_hcd: urb->transfer_buffer not set. Bailing out.\n");
|
||||
DWC_FREE(dwc_otg_urb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
buf = urb->transfer_buffer;
|
||||
if (hcd->self.uses_dma) {
|
||||
/*
|
||||
* Calculate virtual address from physical address,
|
||||
* because some class driver may not fill transfer_buffer.
|
||||
* In Buffer DMA mode virual address is used,
|
||||
* when handling non DWORD aligned buffers.
|
||||
*/
|
||||
buf = phys_to_virt(urb->transfer_dma);
|
||||
}
|
||||
|
||||
if (!(urb->transfer_flags & URB_NO_INTERRUPT))
|
||||
flags |= URB_GIVEBACK_ASAP;
|
||||
@@ -919,6 +955,10 @@ static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
|
||||
if(unlikely(retval))
|
||||
goto EXIT;
|
||||
#endif
|
||||
if(usb_pipeint(urb->pipe) && (dwc_otg_hcd->ssplit_lock == usb_pipedevice(urb->pipe))){
|
||||
DWC_DEBUGPL(DBG_HCD, "addr=%d(%p)\n",usb_pipedevice(urb->pipe),urb->hcpriv);
|
||||
dwc_otg_hcd->ssplit_lock = 0;
|
||||
}
|
||||
|
||||
if(urb->hcpriv == NULL){
|
||||
DWC_WARN("urb->hcpriv == NULL! urb = %p status=%d\n",urb,status);
|
||||
@@ -961,6 +1001,8 @@ static void endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
|
||||
"endpoint=%d,is_intr=%d\n", ep->desc.bEndpointAddress,
|
||||
dwc_ep_addr_to_endpoint(ep->desc.bEndpointAddress),
|
||||
usb_endpoint_xfer_int(&ep->desc));
|
||||
if(usb_endpoint_xfer_int(&ep->desc))
|
||||
dwc_otg_hcd->ssplit_lock = 0;
|
||||
dwc_otg_hcd_endpoint_disable(dwc_otg_hcd, ep->hcpriv, 250);
|
||||
ep->hcpriv = NULL;
|
||||
}
|
||||
@@ -974,6 +1016,9 @@ static void endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
|
||||
dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
|
||||
|
||||
DWC_SPINLOCK_IRQSAVE(dwc_otg_hcd->lock, &flags);
|
||||
|
||||
if(usb_endpoint_xfer_int(&ep->desc))
|
||||
dwc_otg_hcd->ssplit_lock = 0;
|
||||
|
||||
if (ep->hcpriv) {
|
||||
dwc_otg_hcd_endpoint_reset(dwc_otg_hcd, ep->hcpriv);
|
||||
|
||||
242
drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_queue.c
Executable file → Normal file
242
drivers/amlogic/usb/dwc_otg/310/dwc_otg_hcd_queue.c
Executable file → Normal file
@@ -42,8 +42,6 @@
|
||||
#include "dwc_otg_hcd.h"
|
||||
#include "dwc_otg_regs.h"
|
||||
|
||||
extern bool microframe_schedule;
|
||||
|
||||
/**
|
||||
* Free each QTD in the QH's QTD-list then free the QH. QH should already be
|
||||
* removed from a list. QTD list should already be empty if called from URB
|
||||
@@ -155,6 +153,7 @@ static uint32_t calc_bus_time(int speed, int is_in, int is_isoc, int bytecount)
|
||||
* to initialize the QH.
|
||||
*/
|
||||
#define SCHEDULE_SLOP 10
|
||||
#define SCHEDULE_SPLIT_SLOP 10
|
||||
void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb)
|
||||
{
|
||||
char *speed, *type;
|
||||
@@ -179,10 +178,6 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb)
|
||||
|
||||
hcd->fops->hub_info(hcd, urb->priv, &hub_addr, &hub_port);
|
||||
qh->do_split = 0;
|
||||
if (microframe_schedule)
|
||||
qh->speed = dev_speed;
|
||||
|
||||
qh->nak_frame = 0xffff;
|
||||
|
||||
if (((dev_speed == USB_SPEED_LOW) ||
|
||||
(dev_speed == USB_SPEED_FULL)) &&
|
||||
@@ -192,7 +187,6 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb)
|
||||
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) {
|
||||
@@ -227,6 +221,10 @@ void qh_init(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh, dwc_otg_hcd_urb_t * urb)
|
||||
qh->start_split_frame = qh->sched_frame;
|
||||
}
|
||||
|
||||
}else if(qh->do_split){
|
||||
qh->interval = SCHEDULE_SPLIT_SLOP;
|
||||
qh->sched_frame = dwc_frame_num_inc(hcd->frame_number,
|
||||
SCHEDULE_SPLIT_SLOP);
|
||||
}
|
||||
|
||||
DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
|
||||
@@ -319,8 +317,6 @@ dwc_otg_qh_t *dwc_otg_hcd_qh_create(dwc_otg_hcd_t * hcd,
|
||||
return qh;
|
||||
}
|
||||
|
||||
/* microframe_schedule=0 start */
|
||||
|
||||
/**
|
||||
* Checks that a channel is available for a periodic transfer.
|
||||
*
|
||||
@@ -389,162 +385,6 @@ static int check_periodic_bandwidth(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* microframe_schedule=0 end */
|
||||
|
||||
/**
|
||||
* Microframe scheduler
|
||||
* track the total use in hcd->frame_usecs
|
||||
* keep each qh use in qh->frame_usecs
|
||||
* when surrendering the qh then donate the time back
|
||||
*/
|
||||
const unsigned short max_uframe_usecs[]={ 100, 100, 100, 100, 100, 100, 30, 0 };
|
||||
|
||||
/*
|
||||
* called from dwc_otg_hcd.c:dwc_otg_hcd_init
|
||||
*/
|
||||
int init_hcd_usecs(dwc_otg_hcd_t *_hcd)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<8; i++) {
|
||||
_hcd->frame_usecs[i] = max_uframe_usecs[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_single_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
|
||||
{
|
||||
int i;
|
||||
unsigned short utime;
|
||||
int t_left;
|
||||
int ret;
|
||||
int done;
|
||||
|
||||
ret = -1;
|
||||
utime = _qh->usecs;
|
||||
t_left = utime;
|
||||
i = 0;
|
||||
done = 0;
|
||||
while (done == 0) {
|
||||
/* At the start _hcd->frame_usecs[i] = max_uframe_usecs[i]; */
|
||||
if (utime <= _hcd->frame_usecs[i]) {
|
||||
_hcd->frame_usecs[i] -= utime;
|
||||
_qh->frame_usecs[i] += utime;
|
||||
t_left -= utime;
|
||||
ret = i;
|
||||
done = 1;
|
||||
return ret;
|
||||
} else {
|
||||
i++;
|
||||
if (i == 8) {
|
||||
done = 1;
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* use this for FS apps that can span multiple uframes
|
||||
*/
|
||||
static int find_multi_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
unsigned short utime;
|
||||
int t_left;
|
||||
int ret;
|
||||
int done;
|
||||
unsigned short xtime;
|
||||
|
||||
ret = -1;
|
||||
utime = _qh->usecs;
|
||||
t_left = utime;
|
||||
i = 0;
|
||||
done = 0;
|
||||
loop:
|
||||
while (done == 0) {
|
||||
if(_hcd->frame_usecs[i] <= 0) {
|
||||
i++;
|
||||
if (i == 8) {
|
||||
done = 1;
|
||||
ret = -1;
|
||||
}
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/*
|
||||
* we need n consecutive slots
|
||||
* so use j as a start slot j plus j+1 must be enough time (for now)
|
||||
*/
|
||||
xtime= _hcd->frame_usecs[i];
|
||||
for (j = i+1 ; j < 8 ; j++ ) {
|
||||
/*
|
||||
* if we add this frame remaining time to xtime we may
|
||||
* be OK, if not we need to test j for a complete frame
|
||||
*/
|
||||
if ((xtime+_hcd->frame_usecs[j]) < utime) {
|
||||
if (_hcd->frame_usecs[j] < max_uframe_usecs[j]) {
|
||||
j = 8;
|
||||
ret = -1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (xtime >= utime) {
|
||||
ret = i;
|
||||
j = 8; /* stop loop with a good value ret */
|
||||
continue;
|
||||
}
|
||||
/* add the frame time to x time */
|
||||
xtime += _hcd->frame_usecs[j];
|
||||
/* we must have a fully available next frame or break */
|
||||
if ((xtime < utime)
|
||||
&& (_hcd->frame_usecs[j] == max_uframe_usecs[j])) {
|
||||
ret = -1;
|
||||
j = 8; /* stop loop with a bad value ret */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ret >= 0) {
|
||||
t_left = utime;
|
||||
for (j = i; (t_left>0) && (j < 8); j++ ) {
|
||||
t_left -= _hcd->frame_usecs[j];
|
||||
if ( t_left <= 0 ) {
|
||||
_qh->frame_usecs[j] += _hcd->frame_usecs[j] + t_left;
|
||||
_hcd->frame_usecs[j]= -t_left;
|
||||
ret = i;
|
||||
done = 1;
|
||||
} else {
|
||||
_qh->frame_usecs[j] += _hcd->frame_usecs[j];
|
||||
_hcd->frame_usecs[j] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
i++;
|
||||
if (i == 8) {
|
||||
done = 1;
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int find_uframe(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh)
|
||||
{
|
||||
int ret;
|
||||
ret = -1;
|
||||
|
||||
if (_qh->speed == USB_SPEED_HIGH) {
|
||||
/* if this is a hs transaction we need a full frame */
|
||||
ret = find_single_uframe(_hcd, _qh);
|
||||
} else {
|
||||
/* if this is a fs transaction we may need a sequence of frames */
|
||||
ret = find_multi_uframe(_hcd, _qh);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the max transfer size allowed in a host channel is large enough
|
||||
* to handle the maximum data transfer in a single (micro)frame for a periodic
|
||||
@@ -575,8 +415,6 @@ static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Schedules an interrupt or isochronous transfer in the periodic schedule.
|
||||
*
|
||||
@@ -589,27 +427,8 @@ static int check_max_xfer_size(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
|
||||
static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
|
||||
{
|
||||
int status = 0;
|
||||
uint16_t frame_number;
|
||||
|
||||
if (microframe_schedule) {
|
||||
int frame;
|
||||
status = find_uframe(hcd, qh);
|
||||
frame = -1;
|
||||
if (status == 0) {
|
||||
frame = 7;
|
||||
} else {
|
||||
if (status > 0 )
|
||||
frame = status-1;
|
||||
}
|
||||
|
||||
/* Set the new frame up */
|
||||
if (frame > -1) {
|
||||
qh->sched_frame &= ~0x7;
|
||||
qh->sched_frame |= (frame & 7);
|
||||
}
|
||||
|
||||
if (status != -1)
|
||||
status = 0;
|
||||
} else {
|
||||
status = periodic_channel_available(hcd);
|
||||
if (status) {
|
||||
DWC_INFO("%s: No host channel available for periodic " "transfer.\n", __func__); //NOTICE
|
||||
@@ -617,35 +436,39 @@ static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
|
||||
}
|
||||
|
||||
status = check_periodic_bandwidth(hcd, qh);
|
||||
}
|
||||
if (status) {
|
||||
DWC_INFO("%s: Insufficient periodic bandwidth for " "periodic transfer.\n", __func__); //NOTICE
|
||||
return status;
|
||||
}
|
||||
|
||||
status = check_max_xfer_size(hcd, qh);
|
||||
if (status) {
|
||||
DWC_INFO("%s: Channel max transfer size too small " "for periodic transfer.\n", __func__); //NOTICE
|
||||
return status;
|
||||
}
|
||||
|
||||
frame_number = dwc_otg_hcd_get_frame_number(hcd);
|
||||
if((qh->ep_type == UE_INTERRUPT) && !(qh->ep_is_in)){
|
||||
//if(((frame_sched - frame_number) > _qh->interval) || dwc_frame_num_le(frame_number,DWC_HFNUM_MAX_FRNUM + frame_sched)){
|
||||
qh->sched_frame = dwc_frame_num_inc(frame_number, SCHEDULE_SLOP);
|
||||
//}//fix it in future
|
||||
}
|
||||
|
||||
if((qh->ep_type == UE_INTERRUPT) && !qh->do_split &&
|
||||
!dwc_frame_num_le(qh->sched_frame,dwc_frame_num_inc(frame_number,qh->interval)))
|
||||
qh->sched_frame = dwc_frame_num_inc(frame_number, qh->interval);
|
||||
|
||||
if (hcd->core_if->dma_desc_enable) {
|
||||
/* Don't rely on SOF and start in ready schedule */
|
||||
DWC_LIST_INSERT_TAIL(&hcd->periodic_sched_ready, &qh->qh_list_entry);
|
||||
}
|
||||
else {
|
||||
if(fiq_enable &&hcd->core_if->use_fiq_flag && (DWC_LIST_EMPTY(&hcd->periodic_sched_inactive) || dwc_frame_num_le(qh->sched_frame, hcd->fiq_state->next_sched_frame)))
|
||||
{
|
||||
hcd->fiq_state->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) {
|
||||
/* Reserve the periodic channel. */
|
||||
hcd->periodic_channels++;
|
||||
}
|
||||
|
||||
/* Update claimed usecs per (micro)frame. */
|
||||
hcd->periodic_usecs += qh->usecs;
|
||||
@@ -653,7 +476,6 @@ static int schedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
|
||||
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
|
||||
@@ -697,21 +519,13 @@ int dwc_otg_hcd_qh_add(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
|
||||
*/
|
||||
static void deschedule_periodic(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
|
||||
{
|
||||
int i;
|
||||
DWC_LIST_REMOVE_INIT(&qh->qh_list_entry);
|
||||
|
||||
/* Release the periodic channel reservation. */
|
||||
hcd->periodic_channels--;
|
||||
|
||||
/* Update claimed usecs per (micro)frame. */
|
||||
hcd->periodic_usecs -= qh->usecs;
|
||||
|
||||
if (!microframe_schedule) {
|
||||
/* Release the periodic channel reservation. */
|
||||
hcd->periodic_channels--;
|
||||
} else {
|
||||
for (i = 0; i < 8; i++) {
|
||||
hcd->frame_usecs[i] += qh->frame_usecs[i];
|
||||
qh->frame_usecs[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -738,7 +552,7 @@ void dwc_otg_hcd_qh_remove(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh)
|
||||
} else {
|
||||
deschedule_periodic(hcd, qh);
|
||||
hcd->periodic_qh_count--;
|
||||
if( !hcd->periodic_qh_count && !(fiq_fsm_enable &&hcd->core_if->use_fiq_flag)) {
|
||||
if( !hcd->periodic_qh_count ) {
|
||||
intr_mask.b.sofintr = 1;
|
||||
DWC_MODIFY_REG32(&hcd->core_if->core_global_regs->gintmsk,
|
||||
intr_mask.d32, 0);
|
||||
@@ -818,16 +632,10 @@ void dwc_otg_hcd_qh_deactivate(dwc_otg_hcd_t * hcd, dwc_otg_qh_t * qh,
|
||||
* Remove from periodic_sched_queued and move to
|
||||
* appropriate queue.
|
||||
*/
|
||||
if ((microframe_schedule && dwc_frame_num_le(qh->sched_frame, frame_number)) ||
|
||||
(!microframe_schedule && qh->sched_frame == frame_number)) {
|
||||
if (qh->sched_frame == frame_number) {
|
||||
DWC_LIST_MOVE_HEAD(&hcd->periodic_sched_ready,
|
||||
&qh->qh_list_entry);
|
||||
} else {
|
||||
if(fiq_enable && hcd->core_if->use_fiq_flag && !dwc_frame_num_le(hcd->fiq_state->next_sched_frame, qh->sched_frame))
|
||||
{
|
||||
hcd->fiq_state->next_sched_frame = qh->sched_frame;
|
||||
}
|
||||
|
||||
DWC_LIST_MOVE_HEAD
|
||||
(&hcd->periodic_sched_inactive,
|
||||
&qh->qh_list_entry);
|
||||
@@ -884,6 +692,7 @@ void dwc_otg_hcd_qtd_init(dwc_otg_qtd_t * qtd, dwc_otg_hcd_urb_t * urb)
|
||||
|
||||
/* Store the qtd ptr in the urb to reference what QTD. */
|
||||
urb->qtd = qtd;
|
||||
urb->qh_state = URB_STATE_IDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -917,9 +726,6 @@ int dwc_otg_hcd_qtd_add(dwc_otg_qtd_t * qtd,
|
||||
if (*qh == NULL) {
|
||||
retval = -1;
|
||||
goto done;
|
||||
} else {
|
||||
if (fiq_enable && hcd->core_if->use_fiq_flag)
|
||||
hcd->fiq_state->kick_np_queues = 1;
|
||||
}
|
||||
}
|
||||
// DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
|
||||
|
||||
0
drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd.c
Executable file → Normal file
0
drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd.c
Executable file → Normal file
0
drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd.h
Executable file → Normal file
0
drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd.h
Executable file → Normal file
0
drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_if.h
Executable file → Normal file
0
drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_if.h
Executable file → Normal file
0
drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_intr.c
Executable file → Normal file
0
drivers/amlogic/usb/dwc_otg/310/dwc_otg_pcd_intr.c
Executable file → Normal file
@@ -1282,7 +1282,7 @@ int pcd_init(
|
||||
*/
|
||||
DWC_DEBUGPL(DBG_ANY, "registering handler for irq%d\n", _dev->irq);
|
||||
retval = request_irq(_dev->irq, dwc_otg_pcd_irq,
|
||||
IRQF_SHARED | IRQF_DISABLED | IRQ_TYPE_LEVEL_HIGH,
|
||||
IRQF_SHARED | IRQF_DISABLED,
|
||||
gadget_wrapper->gadget.name, otg_dev->pcd);
|
||||
if (retval != 0) {
|
||||
DWC_ERROR("request of irq%d failed\n", _dev->irq);
|
||||
@@ -1290,6 +1290,11 @@ int pcd_init(
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (irq_set_affinity(_dev->irq, cpumask_of(3))) {
|
||||
pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
|
||||
_dev->irq, 3);
|
||||
}
|
||||
|
||||
dwc_otg_pcd_start(gadget_wrapper->pcd, &fops);
|
||||
|
||||
return retval;
|
||||
|
||||
0
drivers/amlogic/usb/dwc_otg/310/dwc_otg_regs.h
Executable file → Normal file
0
drivers/amlogic/usb/dwc_otg/310/dwc_otg_regs.h
Executable file → Normal file
@@ -47,9 +47,6 @@
|
||||
#include <asm/exception.h>
|
||||
#include <asm/smp_plat.h>
|
||||
|
||||
#ifdef CONFIG_MESON_GIC_FIQ
|
||||
#include <mach/am_regs.h>
|
||||
#endif
|
||||
#include "irqchip.h"
|
||||
|
||||
union gic_base {
|
||||
@@ -83,9 +80,6 @@ static DEFINE_RAW_SPINLOCK(irq_controller_lock);
|
||||
*/
|
||||
#define NR_GIC_CPU_IF 8
|
||||
static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
|
||||
#ifdef CONFIG_MESON_GIC_FIQ
|
||||
static int gic_fiq_enable __read_mostly;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Supported arch specific GIC irq extension.
|
||||
@@ -105,9 +99,6 @@ struct irq_chip gic_arch_extn = {
|
||||
#endif
|
||||
|
||||
static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly;
|
||||
#ifdef CONFIG_MESON_GIC_FIQ
|
||||
static int gic_fiq_enable __read_mostly;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_GIC_NON_BANKED
|
||||
static void __iomem *gic_get_percpu_base(union gic_base *base)
|
||||
@@ -303,7 +294,7 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
|
||||
do {
|
||||
irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
|
||||
irqnr = irqstat & ~0x1c00;
|
||||
|
||||
|
||||
if (likely(irqnr > 15 && irqnr < 1021)) {
|
||||
irqnr = irq_find_mapping(gic->domain, irqnr);
|
||||
handle_IRQ(irqnr, regs);
|
||||
@@ -430,21 +421,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
|
||||
for (i = 32; i < gic_irqs; i += 32)
|
||||
writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
|
||||
|
||||
#ifdef CONFIG_MESON_GIC_FIQ
|
||||
if(gic_fiq_enable == 1)
|
||||
writel_relaxed(3, base + GIC_DIST_CTRL);
|
||||
else
|
||||
writel_relaxed(1, base + GIC_DIST_CTRL);
|
||||
#else
|
||||
writel_relaxed(1, base + GIC_DIST_CTRL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void gic_set_fiq_fake(unsigned fiq,irq_flow_handler_t handle)
|
||||
{
|
||||
if((fiq>=32) && (fiq<=1020)){
|
||||
irq_set_chip_and_handler(fiq, &gic_chip, handle);
|
||||
}
|
||||
writel_relaxed(1, base + GIC_DIST_CTRL);
|
||||
}
|
||||
|
||||
static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
|
||||
@@ -453,20 +430,7 @@ static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
|
||||
void __iomem *base = gic_data_cpu_base(gic);
|
||||
unsigned int cpu_mask, cpu = smp_processor_id();
|
||||
int i;
|
||||
#ifdef CONFIG_MESON_GIC_FIQ
|
||||
/*********************************************
|
||||
* suspend/resume need save&restore GIC FIQ setting
|
||||
*********************************************/
|
||||
unsigned int it_lines_number;
|
||||
unsigned cmd;
|
||||
char c=0;
|
||||
unsigned temp;
|
||||
|
||||
if(gic_fiq_enable == 1){
|
||||
cmd = readl_relaxed((const volatile void *)P_AO_RTI_STATUS_REG1);
|
||||
c = (char)cmd;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Get what the GIC says our CPU mask is.
|
||||
*/
|
||||
@@ -489,51 +453,14 @@ static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
|
||||
writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
|
||||
writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
|
||||
|
||||
#ifdef CONFIG_MESON_GIC_FIQ
|
||||
if(gic_fiq_enable == 1){
|
||||
/* Set the Per-CPU interrupts 15-8 as Secure and the rest
|
||||
* as Non-secure */
|
||||
it_lines_number = readl_relaxed(dist_base + GIC_DIST_CTR) & 0x1f;
|
||||
writel_relaxed(0xffff00ff, dist_base + GIC_DIST_IGROUP);
|
||||
|
||||
if(c != 'r'){
|
||||
/* Set ALL interrupts as non-secure interrupts */
|
||||
for(i = 1; i <= it_lines_number; i++) {
|
||||
temp = readl_relaxed(dist_base + GIC_DIST_IGROUP + i * 4);
|
||||
if(temp == 0)
|
||||
writel_relaxed(0xffffffff, dist_base + GIC_DIST_IGROUP + i * 4);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Set priority on PPI and SGI interrupts
|
||||
*/
|
||||
for (i = 0; i < 32; i += 4){
|
||||
temp = readl_relaxed(dist_base + GIC_DIST_PRI + i * 4 / 4);
|
||||
if(temp == 0)
|
||||
writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
|
||||
}
|
||||
}
|
||||
else{
|
||||
for (i = 0; i < 32; i += 4)
|
||||
writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* Set priority on PPI and SGI interrupts
|
||||
*/
|
||||
for (i = 0; i < 32; i += 4)
|
||||
writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
|
||||
#endif
|
||||
|
||||
writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
|
||||
#ifdef CONFIG_MESON_GIC_FIQ
|
||||
if(gic_fiq_enable == 1)
|
||||
writel_relaxed(0xf, base + GIC_CPU_CTRL); //??GICC_ACTR maybe set 0
|
||||
else
|
||||
writel_relaxed(1, base + GIC_CPU_CTRL);
|
||||
#else
|
||||
writel_relaxed(1, base + GIC_CPU_CTRL);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_PM
|
||||
@@ -611,14 +538,7 @@ static void gic_dist_restore(unsigned int gic_nr)
|
||||
writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
|
||||
dist_base + GIC_DIST_ENABLE_SET + i * 4);
|
||||
|
||||
#ifdef CONFIG_MESON_GIC_FIQ
|
||||
if(gic_fiq_enable == 1)
|
||||
writel_relaxed(3, dist_base + GIC_DIST_CTRL);
|
||||
else
|
||||
writel_relaxed(1, dist_base + GIC_DIST_CTRL);
|
||||
#else
|
||||
writel_relaxed(1, dist_base + GIC_DIST_CTRL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void gic_cpu_save(unsigned int gic_nr)
|
||||
@@ -675,14 +595,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
|
||||
writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
|
||||
|
||||
writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
|
||||
#ifdef CONFIG_MESON_GIC_FIQ
|
||||
if(gic_fiq_enable == 1)
|
||||
writel_relaxed(0xf, cpu_base + GIC_CPU_CTRL);
|
||||
else
|
||||
writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
|
||||
#else
|
||||
writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v)
|
||||
@@ -756,14 +669,7 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
|
||||
dsb();
|
||||
|
||||
/* this always happens on GIC0 */
|
||||
#ifdef CONFIG_MESON_GIC_FIQ
|
||||
if(gic_fiq_enable == 1)
|
||||
writel_relaxed(map << 16 | 1<<15 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
|
||||
else
|
||||
writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
|
||||
#else
|
||||
writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -948,13 +854,6 @@ int __init gic_of_init(struct device_node *node, struct device_node *parent)
|
||||
|
||||
if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
|
||||
percpu_offset = 0;
|
||||
|
||||
#ifdef CONFIG_MESON_GIC_FIQ
|
||||
if(of_property_read_bool(node, "gic_fiq_enable"))
|
||||
gic_fiq_enable=1;
|
||||
else
|
||||
gic_fiq_enable = 0;
|
||||
#endif
|
||||
|
||||
gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
|
||||
|
||||
@@ -971,11 +870,4 @@ IRQCHIP_DECLARE(cortex_a7_gic, "arm,cortex-a7-gic", gic_of_init);
|
||||
IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init);
|
||||
IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init);
|
||||
|
||||
#ifdef CONFIG_MESON_GIC_FIQ
|
||||
int get_gic_fiq_enable_flag(void)
|
||||
{
|
||||
return gic_fiq_enable;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
4
kernel/irq/chip.c
Executable file → Normal file
4
kernel/irq/chip.c
Executable file → Normal file
@@ -15,7 +15,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <asm/fiq.h>
|
||||
|
||||
#include <trace/events/irq.h>
|
||||
|
||||
#include "internals.h"
|
||||
@@ -454,7 +454,7 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((irq!=get_fiq_index()) && (desc->istate & IRQS_ONESHOT))
|
||||
if (desc->istate & IRQS_ONESHOT)
|
||||
mask_irq(desc);
|
||||
|
||||
preflow_handler(desc);
|
||||
|
||||
Reference in New Issue
Block a user