uboot irq流程理解

2021/5/14 18:25:36

本文主要是介绍uboot irq流程理解,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

/*
 *  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;
}

 

 



这篇关于uboot irq流程理解的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程