/*
* vectors - Generic ARM exception table code
*
* Copyright (c) 1998 Dan Malek <dmalek@jlc.net>
* Copyright (c) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se>
* Copyright (c) 2000 Wolfgang Denk <wd@denx.de>
* Copyright (c) 2001 Alex Züpke <azu@sysgo.de>
* Copyright (c) 2001 Marius Gr?ger <mag@sysgo.de>
* Copyright (c) 2002 Alex Züpke <azu@sysgo.de>
* Copyright (c) 2002 Gary Jennejohn <garyj@denx.de>
* Copyright (c) 2002 Kyle Harris <kharris@nexus-tech.net>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
/*
*************************************************************************
*
* Symbol _start is referenced elsewhere, so make it global
*
*************************************************************************
*/
.globl _start
/*
*************************************************************************
*
* Vectors have their own section so linker script can map them easily
*
*************************************************************************
*/
.section ".vectors", "x"
/*
*************************************************************************
*
* Exception vectors as described in ARM reference manuals
*
* Uses indirect branch to allow reaching handlers anywhere in memory.
*
*************************************************************************
*/
#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
.word CONFIG_SYS_DV_NOR_BOOT_CFG
#endif
_start:
ldr pc, _reset_vec
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
/*
*************************************************************************
*
* Indirect vectors table
*
* Symbols referenced here must be defined somewhere else
*
*************************************************************************
*/
/*
*use _reset_vec as the variable name because the name "_reset" has been used in other place
*export _reset_vec for fix the vector table after code relocate
*modify by wangwei. 2014-12-01
*/
.globl _reset_vec
.globl _undefined_instruction
.globl _software_interrupt
.globl _prefetch_abort
.globl _data_abort
.globl _not_used
.globl _irq
.globl _fiq
_reset_vec: .word reset
_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word fiq
.balignl 16,0xdeadbeef
/*
*************************************************************************
*
* Interrupt handling
*
*************************************************************************
*/
/* SPL interrupt handling: just hang */
#ifdef CONFIG_SPL_BUILD
.align 5
undefined_instruction:
software_interrupt:
prefetch_abort:
data_abort:
not_used:
irq:
fiq:
1:
bl 1b /* hang and never return */
#else /* !CONFIG_SPL_BUILD */
/* IRQ stack memory (calculated at run-time) + 8 bytes */
.globl IRQ_STACK_START_IN
IRQ_STACK_START_IN:
.word 0x0badc0de
#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de
/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif /* CONFIG_USE_IRQ */
@
@ IRQ stack frame.
@
#define S_FRAME_SIZE 72
#define S_OLD_R0 68
#define S_PSR 64
#define S_PC 60
#define S_LR 56
#define S_SP 52
#define S_IP 48
#define S_FP 44
#define S_R10 40
#define S_R9 36
#define S_R8 32
#define S_R7 28
#define S_R6 24
#define S_R5 20
#define S_R4 16
#define S_R3 12
#define S_R2 8
#define S_R1 4
#define S_R0 0
#define MODE_SVC 0x13
#define I_BIT 0x80
/*
* use bad_save_user_regs for abort/prefetch/undef/swi ...
* use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
*/
.macro bad_save_user_regs
@ carve out a frame on current user stack
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Save user registers (now in svc mode) r0-r12
ldr r2, IRQ_STACK_START_IN
@ get values for "aborted" pc and cpsr (into parm regs)
ldmia r2, {r2 - r3}
add r0, sp, #S_FRAME_SIZE @ grab pointer to old stack
add r5, sp, #S_SP
mov r1, lr
stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr
mov r0, sp @ save current stack into r0 (param register)
.endm
.macro irq_save_user_regs
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12} @ Calling r0-r12
@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
add r8, sp, #S_PC
stmdb r8, {sp, lr}^ @ Calling SP, LR
str lr, [r8, #0] @ Save calling PC
mrs r6, spsr
str r6, [r8, #4] @ Save CPSR
str r0, [r8, #8] @ Save OLD_R0
mov r0, sp
.endm
.macro irq_restore_user_regs
ldmia sp, {r0 - lr}^ @ Calling r0 - lr
mov r0, r0
ldr lr, [sp, #S_PC] @ Get PC
add sp, sp, #S_FRAME_SIZE
subs pc, lr, #4 @ return & move spsr_svc into cpsr
.endm
.macro get_bad_stack
ldr r13, IRQ_STACK_START_IN @ setup our mode stack
str lr, [r13] @ save caller lr in position 0 of saved stack
mrs lr, spsr @ get the spsr
str lr, [r13, #4] @ save spsr in position 1 of saved stack
mov r13, #MODE_SVC @ prepare SVC-Mode
@ msr spsr_c, r13
msr spsr, r13 @ switch modes, make sure moves will execute
mov lr, pc @ capture return pc
movs pc, lr @ jump to next instruction & switch modes.
.endm
.macro get_irq_stack @ setup IRQ stack
ldr sp, IRQ_STACK_START
.endm
.macro get_fiq_stack @ setup FIQ stack
ldr sp, FIQ_STACK_START
.endm
/*
* exception handlers
*/
.align 5
undefined_instruction:
get_bad_stack
bad_save_user_regs
bl do_undefined_instruction
.align 5
software_interrupt:
get_bad_stack
bad_save_user_regs
bl do_software_interrupt
.align 5
prefetch_abort:
get_bad_stack
bad_save_user_regs
bl do_prefetch_abort
.align 5
data_abort:
get_bad_stack
bad_save_user_regs
bl do_data_abort
.align 5
not_used:
get_bad_stack
bad_save_user_regs
bl do_not_used
#ifdef CONFIG_USE_IRQ
.align 5
irq:
@get_irq_stack kkkkk
@irq_save_user_regs xxxxx
//陷入irq模式后 cpsr = irq, spsr=svc, lr=从svc模式普通代码中断处的 返回点
sub sp, sp, #S_FRAME_SIZE @72
stmia sp, {r0 - r12} @ Calling r0-r12
//调用者(svc)的r0-r12,也是irq的(r0-r12)
//此时用的sp是irq模式的sp_irq
@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
add r8, sp, #S_PC @60
//stmdb r8, {sp, lr}^ @ Calling SP, LR
//保存用户态的堆栈和lr 现在是在irq态 uboot没有使用用户态 都是svc,irq态
//但是 堆栈设置了2个 普通程序堆栈(svc)和irq中断模式的堆栈
//'^'是一个后缀标志,不能在User模式和Sys系统模式下使用该标志.
//该标志有两个存在目的:
//a.对于LDM操作,同时恢复的寄存器中含有pc(r15)寄存器,
//那么指令执行的同时cpu自动将spsr拷贝到cpsr中
//如:在UND中断返回代码中ldmfd sp!, {r0-r13,pc}^
//当指令执行完毕,pc跳转之前,将spsr的值自动拷贝到cpsr中
//b.数据的送入,送出发生在User用户模式下的寄存器,而非当前模式寄存器
//如:ldmdb sp, {r0 - lr}^;
//表示sp栈中的数据恢复到User分组寄存器r0-lr中,
//而不是恢复到当前模式寄存器r0-lr
//当然对于User,System,IRQ,SVC,Abort,Undefined这6种模式来说r0-r12是共用的,
//只是r13和r14为分别独有,对于FIQ模式,仅仅r0-r7是和前6中模式的r0-r7共用,r8-r14都是FIQ模式下专有.
//其实usr模式的 lr和sp的保存 应该没有啥鸟用 因为用的是svc模式
//把上面一行注释 程序正常运行
ldr r1, =(0x88888888)
str r1, [r8, #-4]
ldr r1, =(0x99999999)
str r1, [r8, #-8]
//确实没有卵用 我加上上面几行代码 程序正常运行
str lr, [r8, #0] @ Save calling PC
//svc返回地址 中断点 从lr的上一条指令陷入irq模式
mrs r6, spsr
//保存 spsr寄存器 其值等于svc模式,因为是从svc模式进入的
@mrs r6, cpsr
str r6, [r8, #4] @ Save CPSR
str r0, [r8, #8] @ Save OLD_R0
mov r0, sp
stmdb sp!, {r0-r12}
bl do_irq_before_hook
ldmia sp!, {r0-r12}
//do_irq_before_hook
bl do_irq
@irq_restore_user_regs xxxxx
ldmia sp, {r0 - lr}^ @ Calling r0 - lr
mov r0, r0
ldr lr, [sp, #S_PC] @ Get PC
add sp, sp, #S_FRAME_SIZE
subs pc, lr, #4 @ return & move spsr_svc into cpsr
//流水线跨过了2条指令 回退一条指令(-4)
//注意这里有个 sub+s 表示更新cpsr
//把spsr的值去覆盖cpsr
//此时工作于irq模式 cpsr=irq,但是spsr=svc,因为是从svc模式陷入irq中断服务程序的
//所以可以从irq模式返回到svc模式
//MOV一般不影响CPSR,
//除非执行类似MOV pc, lr 效果上等同于BX lr
//可能会影响到T标志位
//MOVS总是会影响CPSR,
//包括N,Z,C标志位,执行 MOVS pc, lr时,
//CPSR会被SPSR覆盖(内核态,USER和SYSTEM模式下没有SPSR)
//举例,当USER模式下有一条未定义指令,CPU在译码阶段会发现指令未定义
//这时会跳转到相应的处理函数,切换到UND模式,并把未定义指令下一条指令的地址保存到lr寄存器
//当处理函数执行完成后,怎样去返回的同时把状态寄存器等恢复是个问题
//因为UND模式下sp和lr寄存器是该模式下特有的
//这时候就可以可以直接用MOVS pc, lr来返回并切换回USER模式
.align 5
fiq:
get_fiq_stack
/* someone ought to write a more effiction fiq_save_user_regs */
irq_save_user_regs
bl do_fiq
irq_restore_user_regs
#else
.align 5
irq:
get_bad_stackxxxx
bad_save_user_regs
bl do_irq
.align 5
fiq:
get_bad_stack
bad_save_user_regs
bl do_fiq
#endif /* CONFIG_USE_IRQ */
#endif /* CONFIG_SPL_BUILD */
/*
* (C) Copyright 2007-2013
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* Jerry Wang <wangflord@allwinnertech.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/ccmu.h>
#include <asm/arch/gic.h>
#include <sunxi_board.h>
DECLARE_GLOBAL_DATA_PTR;
struct _irq_handler
{
void *m_data;
void (*m_func)( void * data);
};
struct _irq_handler sunxi_int_handlers[GIC_IRQ_NUM];
extern int interrupts_is_open(void);
static void gic_spi_set_target(int irq_no, int cpu_id);
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void default_isr(void *data)
{
pr_msg("default_isr(): called from IRQ %d\n", (uint)data);
while(1);
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int irq_enable(int irq_no)
{
uint reg_val;
uint offset;
if (irq_no >= GIC_IRQ_NUM)
{
pr_msg("irq NO.(%d) > GIC_IRQ_NUM(%d) !!\n", irq_no, GIC_IRQ_NUM);
return -1;
}
if(irq_no == AW_IRQ_NMI)
{
*(volatile unsigned int *)(0x01f00c00 + 0x10) |= 1;
*(volatile unsigned int *)(0x01f00c00 + 0x40) |= 1;
}
gic_spi_set_target(irq_no, get_core_pos());
offset = irq_no >> 5; // 除32
reg_val = readl(GIC_SET_EN(offset));
reg_val |= 1 << (irq_no & 0x1f);
writel(reg_val, GIC_SET_EN(offset));
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int irq_disable(int irq_no)
{
uint reg_val;
uint offset;
if (irq_no >= GIC_IRQ_NUM)
{
pr_msg("irq NO.(%d) > GIC_IRQ_NUM(%d) !!\n", irq_no, GIC_IRQ_NUM);
return -1;
}
if(irq_no == AW_IRQ_NMI)
{
*(volatile unsigned int *)(0x01f00c00 + 0x10) |= 1;
*(volatile unsigned int *)(0x01f00c00 + 0x40) &= ~1;
}
gic_spi_set_target(irq_no, 0);
offset = irq_no >> 5; // 除32
reg_val = (1 << (irq_no & 0x1f));
writel(reg_val, GIC_CLR_EN(offset));
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void gic_sgi_handler(uint irq_no)
{
pr_msg("SGI irq %d coming... \n", irq_no);
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void gic_ppi_handler(uint irq_no)
{
pr_msg("PPI irq %d coming... \n", irq_no);
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void gic_spi_handler(uint irq_no)
{
if (sunxi_int_handlers[irq_no].m_func != default_isr)
{
sunxi_int_handlers[irq_no].m_func(sunxi_int_handlers[irq_no].m_data);
}
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void gic_clear_pending(uint irq_no)
{
uint reg_val;
uint offset;
offset = irq_no >> 5; // 除32
//reg_val = readl(GIC_PEND_CLR(offset));
reg_val = (1 << (irq_no & 0x1f));
writel(reg_val, GIC_PEND_CLR(offset));
return ;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
void irq_install_handler (int irq, interrupt_handler_t handle_irq, void *data)
{
pr_msg("install irq %d \n", irq);
debug("install irqx %d \n", irq);
//error!!!
int flag = interrupts_is_open();
//when irq_handler call this function , irq enable bit has already disabled in irq_mode,so don't need to enable I bit
if(flag)
{
disable_interrupts();
}
if (irq >= GIC_IRQ_NUM || !handle_irq)
{
goto __END;
}
sunxi_int_handlers[irq].m_data = data;
sunxi_int_handlers[irq].m_func = handle_irq;
__END:
if(flag)
{
enable_interrupts();
}
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
void irq_free_handler(int irq)
{
disable_interrupts();
if (irq >= GIC_IRQ_NUM)
{
enable_interrupts();
return;
}
sunxi_int_handlers[irq].m_data = NULL;
sunxi_int_handlers[irq].m_func = default_isr;
enable_interrupts();
}
extern int printf(const char *fmt, ...);
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
#ifdef CONFIG_USE_IRQ
__maybe_unused unsigned long get_cpsr( void )
{
unsigned long reg_var;
//mrs r0, cpsr
asm volatile("mrs %0, cpsr" :"=r"(reg_var): :);
return reg_var;
}
__maybe_unused unsigned long get_spsr( void )
{
unsigned long reg_var;
//mrs r0, cpsr
asm volatile("mrs %0, spsr" :"=r"(reg_var): :);
return reg_var;
}
__maybe_unused unsigned long get_lr( void )
{
unsigned long reg_var;
asm volatile("mov %0, lr" :"=r"(reg_var): :);
return reg_var;
}
__maybe_unused unsigned long get_sp( void )
{
unsigned long reg_var;
asm volatile("mov %0, sp" :"=r"(reg_var): :);
return reg_var;
}
extern int macdbg_dmphex(const char* buff, int len);
void do_asm_test_func(struct pt_regs *pt_regs)
{
char *p;
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");
asm volatile( "ldr r0, =(0x12345678)" );
asm volatile( "ldr r1, =(0x11111111)" );
asm volatile( "ldr r2, =(0x22222222)" );
asm volatile( "ldr r3, =(0x33333333)" );
asm volatile( "ldr r4, =(0x44444444)" );
asm volatile( "ldr r5, =(0x55555555)" );
asm volatile( "ldr r6, =(0x66666666)" );
asm volatile( "ldr r7, =(0x77777777)" );
asm volatile( "ldr r8, =(0x88888888)" );
//asm volatile( "ldr r9, =(0x99999999)" );
asm volatile( "ldr r10, =(0xAAAAAAAA)" );
asm volatile( "ldr r11, =(0xbbbbbbbb)" );
asm volatile( "ldr r12, =(0xcccccccc)" );
asm volatile("stmdb sp!, {r0-r12}");
p = (char *)get_sp();
debug( "do_asm_test_func p2 = %p\n", p );
macdbg_dmphex((char *)p, 0x40);
asm volatile("ldmia sp!, {r0-r12}");
}
void do_irq_before_hook( struct pt_regs *pt_regs )
{
u32 idnum;
//volatile u32 secmode;
//debug( "in do_irq_before_hook = %d\n", 456 );
idnum = readl(GIC_INT_ACK_REG);
//debug( "idnum1 = %d\n", idnum );
char *p =NULL;
if( idnum == 85 || idnum == 84 ){
;
}else{
p=p;
show_regs (pt_regs);
//debug( "do_irq xxxc idnum = %d\n", idnum );
//p = (char *)get_sp();
//debug( "do_irq xxxc p = %p\n", p );
debug( "do_irq xxxc pt_regs = %p\n", pt_regs );
macdbg_dmphex((char *)pt_regs, 0x100);
debug( "do_irq xxxc get_sp() = %lx\n", get_sp() );
debug( "do_irq xxxc get_cpsr() = %lx\n", get_cpsr() );
debug( "do_irq xxxc get_spsr() = %lx\n", get_spsr() );
debug( "do_irq xxxc get_sp() = %lx\n", get_sp() );
//macdbg_dmphex((char *)p, 0x100);
//do_asm_test_func(pt_regs);
//do_timer_test
//pr_msg("spurious irq !!\n");
}
if( (idnum == 1022) || (idnum == 1023) ){
pr_msg("spurious irq !!\n");
return;
}
if (idnum >= GIC_IRQ_NUM) {
pr_msg("irq NO.(%d) > GIC_IRQ_NUM(%d) !!\n", idnum, GIC_IRQ_NUM-32);
return;
}
if (idnum < 16)
gic_sgi_handler(idnum);
else if (idnum < 32)
gic_ppi_handler(idnum);
else
gic_spi_handler(idnum);
writel(idnum, GIC_END_INT_REG);
writel(idnum, GIC_DEACT_INT_REG);
//writel(idnum, GIC_DEACT_INT_REG);
gic_clear_pending(idnum);
}
void do_irq (struct pt_regs *pt_regs)
{
//debug( "do_irq idnum = %d\n", 123 );
return;
}
int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
int irq;
pr_msg("Interrupt-Information:\n");
pr_msg("Nr(Max) Routine Arg\n");
for (irq = 0; irq < GIC_IRQ_NUM; irq ++)
{
if (sunxi_int_handlers[irq].m_func != NULL)
{
pr_msg("%d(%d) 0x%08lx 0x%08lx\n",
irq, GIC_IRQ_NUM,
(ulong)sunxi_int_handlers[irq].m_func,
(ulong)sunxi_int_handlers[irq].m_data);
}
}
return 0;
}
#endif
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void gic_distributor_init(void)
{
__u32 cpumask = 0x01010101;
__u32 gic_irqs;
__u32 i;
writel(0, GIC_DIST_CON);
/* check GIC hardware configutation */
gic_irqs = ((readl(GIC_CON_TYPE) & 0x1f) + 1) * 32;
if (gic_irqs > 1020)
{
gic_irqs = 1020;
}
if (gic_irqs < GIC_IRQ_NUM)
{
pr_error("GIC parameter config error, only support %d"
" irqs < %d(spec define)!!\n", gic_irqs, GIC_IRQ_NUM);
return ;
}
/* set trigger type to be level-triggered, active low */
for (i=0; i<GIC_IRQ_NUM; i+=16)
{
writel(0, GIC_IRQ_MOD_CFG(i>>4));
}
/* set priority */
for (i=GIC_SRC_SPI(0); i<GIC_IRQ_NUM; i+=4)
{
writel(0xa0a0a0a0, GIC_SPI_PRIO((i-32)>>2));
}
/* set processor target */
for (i=32; i<GIC_IRQ_NUM; i+=4)
{
writel(cpumask, GIC_SPI_PROC_TARG((i-32)>>2));
}
/* disable all interrupts */
for (i=32; i<GIC_IRQ_NUM; i+=32)
{
writel(0xffffffff, GIC_CLR_EN(i>>5));
}
/* clear all interrupt active state */
for (i=32; i<GIC_IRQ_NUM; i+=32)
{
writel(0xffffffff, GIC_ACT_CLR(i>>5));
}
writel(1, GIC_DIST_CON);
return ;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void gic_cpuif_init(void)
{
uint i;
writel(0, GIC_CPU_IF_CTRL);
/*
* Deal with the banked PPI and SGI interrupts - disable all
* PPI interrupts, ensure all SGI interrupts are enabled.
*/
writel(0xffff0000, GIC_CLR_EN(0));
writel(0x0000ffff, GIC_SET_EN(0));
/* Set priority on PPI and SGI interrupts */
for (i=0; i<16; i+=4)
{
writel(0xa0a0a0a0, GIC_SGI_PRIO(i>>2));
}
for (i=16; i<32; i+=4)
{
writel(0xa0a0a0a0, GIC_PPI_PRIO((i-16)>>2));
}
writel(0xf0, GIC_INT_PRIO_MASK);
writel(1, GIC_CPU_IF_CTRL);
return ;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
static void gic_spi_set_target(int irq_no, int cpu_id)
{
uint reg_val, addr, offset;
irq_no -= 32;
/* dispatch the usb interrupt to CPU1 */
addr = GIC_SPI_PROC_TARG(irq_no>>2);
reg_val = readl(addr);
offset = 8 * (irq_no & 3);
reg_val &= ~(0xff<<offset);
reg_val |= (((1<<cpu_id) & 0xf) <<offset);
writel(reg_val, addr);
return ;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int arch_interrupt_init (void)
{
int i;
for (i=0; i<GIC_IRQ_NUM; i++)
sunxi_int_handlers[i].m_data = default_isr;
if (sunxi_probe_secure_monitor() || sunxi_probe_secure_os())
pr_msg("gic: sec monitor mode\n");
else {
pr_msg("gic: normal mode\n");
gic_distributor_init();
gic_cpuif_init();
}
return 0;
}
/*
************************************************************************************************************
*
* function
*
* name :
*
* parmeters :
*
* return :
*
* note :
*
*
************************************************************************************************************
*/
int arch_interrupt_exit(void)
{
if (!(sunxi_probe_secure_monitor() || sunxi_probe_secure_os())) {
gic_distributor_init();
gic_cpuif_init();
}
return 0;
}
int sunxi_gic_cpu_interface_init(int cpu)
{
gic_cpuif_init();
return 0;
}
int sunxi_gic_cpu_interface_exit(void)
{
writel(0, GIC_CPU_IF_CTRL);
return 0;
}