This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RTOS/AM5726: INTC issue

Part Number: AM5726

Tool/software: TI-RTOS

Dear all!

Using tools:

  • ti-processor-sdk-rtos-am57xx-evm-04.02.00.09-Linux-x86-Install.bin
    • pdk_am57xx_1_0_9

I have problem to use MPU0 software interrupts via CSL interface for A15.

When interrupt is emmited, the PENDING (GICD_SPENDSGIR, GICD_ISPR) is turn on, high priority interrupt register (GICC_HPIR) show correct value, but no interrupt is happend (GICC_IAR show 0x3ff). Interrupt handler exseptionhanler.asm:IRQHandler() is not started.

Here is my example:

#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>

#include <HAL/board.h>

#include <ti/csl/hw_types.h>
#include <ti/csl/soc.h>
#include <ti/csl/csl_a15.h>
#include <ti/csl/arch/csl_arch.h>


#define INTERRUPT_NUMBER 1
#define PRIORITY         5

// Forward the interrupt to the CPU interfaces specified in the CPUTargetList field.
#define TARGET_LIST_FILTER 0x00000000
// MPU0
#define CPU_TARGET_LIST 0x00010000


static inline void print_register(const char *name, uint32_t address)
{
    printf("0x%08x | %s:\t0x%08x\n", address, name, HW_RD_REG32(address));
}

static int print_SGI_registers()
{
    // DISTRIBUTOR
    // ~~~~~~~~~~~~~~~~

    // Distributor control register
    print_register("GICD_DCR (CTRL)", SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_DCR);

    // Interrupt controller type register
    print_register("GICD_ICTR (TYPER)", SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_ICTR);

    // Distributor Implementer Identification Register
    print_register("GICD_IIDR (IIDR)", SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_IIDR);

    // Interrupt Group Register
    print_register("GICD_ISR0 (IGROUPR0)", SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_ISR0);

    // Interrupt Set-Enable Register
    print_register("GICD_ISER0 (ISENABLE0)", SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_ISER0);

    // Interrupt Clear-Enable Register
    print_register("GICD_ICER0 (ICENABLE0)", SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_ICER0);

    // Interrupt Set-Pending Register
    print_register("GICD_ISPR0 (ISPENDR0)", SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_ISPR0);

    // Interrupt Clear-Pending Register
    print_register("GICD_ICPR0 (ICPENDR0)", SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_ICPR0);

    // GICv2 Interrupt Set-Active Register
    print_register("GICD_ISACTIVER0 (ISACTIVER0)",SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_ISACTIVER0);

    // GICv2 Interrupt Clear-Active Register
    print_register("GICD_ICACTIVER0 (ICACTIVER0)",SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_ICACTIVER0);

    // Interrupt Priority Register
    print_register("GICD_IPR0 (IPRIORITYR0)", SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_IPR0);

    // Interrupt Configuration Register
    print_register("GICD_ICFR0 (ICFGR0)", SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_ICFR0);

    // SGI Clear-Pending Registers
    print_register("GICD_CPENDSGIR0 (CPENDSGIR0)",SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_CPENDSGIR0);
    print_register("GICD_CPENDSGIR1 (CPENDSGIR1)",SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_CPENDSGIR1);
    print_register("GICD_CPENDSGIR2 (CPENDSGIR2)",SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_CPENDSGIR2);
    print_register("GICD_CPENDSGIR3 (CPENDSGIR3)",SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_CPENDSGIR3);

    // SGI Set-Pending Registers
    print_register("GICD_SPENDSGIR0 (SPENDSGIR0)",SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_SPENDSGIR0);
    print_register("GICD_SPENDSGIR1 (SPENDSGIR1)",SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_SPENDSGIR1);
    print_register("GICD_SPENDSGIR2 (SPENDSGIR2)",SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_SPENDSGIR2);
    print_register("GICD_SPENDSGIR3 (SPENDSGIR3)",SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_SPENDSGIR3);

    
    // CPU INTERFACE
    // ~~~~~~~~~~~~~~~~
    DebugPrintf("\n\n");

    // CPU Interface Control Register
    print_register("GICC_ICR (CTRL)", SOC_INTC_MPU_PHYS_CPU_IF_BASE + MPU_GICC_ICR);

    // Interrupt Priority Mask Register
    print_register("GICC_PMR (PMR)", SOC_INTC_MPU_PHYS_CPU_IF_BASE + MPU_GICC_PMR);

    // Binary Point Register
    print_register("GICC_BPR (BPR)", SOC_INTC_MPU_PHYS_CPU_IF_BASE + MPU_GICC_BPR);

    // Interrupt Acknowledge Register
    print_register("GICC_IAR (IAR)", SOC_INTC_MPU_PHYS_CPU_IF_BASE + MPU_GICC_IAR);

    // Running Priority Register
    print_register("GICC_RPR (RPR)", SOC_INTC_MPU_PHYS_CPU_IF_BASE + MPU_GICC_RPR);

    // Highest Priority Pending Interrupt Register
    print_register("GICC_HPIR (HPPIR)", SOC_INTC_MPU_PHYS_CPU_IF_BASE + MPU_GICC_HPIR);

    // Aliased Binary Point Register
    print_register("GICC_ABPR (ABPR)", SOC_INTC_MPU_PHYS_CPU_IF_BASE + MPU_GICC_ABPR);

    // Aliased Interrupt Acknowledge Register
    print_register("GICC_AIAR (AIAR)", SOC_INTC_MPU_PHYS_CPU_IF_BASE + MPU_GICC_AIAR);

    // Aliased Highest Priority Pending Interrupt Register
    print_register("GICC_AHPPIR (AHPPIR)", SOC_INTC_MPU_PHYS_CPU_IF_BASE + MPU_GICC_AHPPIR);

    // Active Priorities Register
    print_register("GICC_APR0 (APR0)", SOC_INTC_MPU_PHYS_CPU_IF_BASE + MPU_GICC_APR0);

    // Non-secure Active Priorities Registers
    print_register("GICC_NSAPR0 (NSAPR0)", SOC_INTC_MPU_PHYS_CPU_IF_BASE + MPU_GICC_NSAPR0);

    // CPU Interface Identification Register
    print_register("GICC_IIDR (IIDR)", SOC_INTC_MPU_PHYS_CPU_IF_BASE + MPU_GICC_IIDR);

    return 0;
}


static void SGI_handler(void *p)
{
    uint32_t register_number  = INTERRUPT_NUMBER / 4;
    uint32_t byte_number      = INTERRUPT_NUMBER % 4;

    DebugPrintf("Hello from SGI handler: %d!\n", INTERRUPT_NUMBER);

    // clear pend
    HW_WR_REG32(SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_CPENDSGIR0 + (register_number * 4),
                1 << (byte_number * 8));
}


int main()
{
	// Init Board
	// 1. unlock_MMR
	// 2. PLL init
	// 3. clock init
	// 4. pinmux config
	// 5. watchdog disable
    BoardInit();

	// Config UART debug output
    DebugInit();

	// GIC init
    Intc_Init();
    Intc_IntEnable(0);

    // GIC enable SGI interrupt
    Intc_IntRegister(INTERRUPT_NUMBER, SGI_handler, NULL);
    IntEnableSecureMode(INTERRUPT_NUMBER);
    Intc_IntPrioritySet(INTERRUPT_NUMBER, PRIORITY, 0);
    Intc_SystemEnable(INTERRUPT_NUMBER);


    // Do SGI
	HW_WR_REG32(SOC_INTC_MPU_DISTRIBUTOR_BASE + MPU_GICD_SGIR,
	            TARGET_LIST_FILTER | CPU_TARGET_LIST | INTERRUPT_NUMBER);


	// Print registers
	print_SGI_registers();

	while(true)
	    {}
}

Here is example result:

0x48211000 | GICD_DCR (CTRL): 0x00000001
0x48211004 | GICD_ICTR (TYPER): 0x0000fc25
0x48211008 | GICD_IIDR (IIDR): 0x0000043b
0x48211080 | GICD_ISR0 (IGROUPR0): 0x00000000
0x48211100 | GICD_ISER0 (ISENABLE0): 0x0000ffff
0x48211180 | GICD_ICER0 (ICENABLE0): 0x0000ffff
0x48211200 | GICD_ISPR0 (ISPENDR0): 0x00000002
0x48211280 | GICD_ICPR0 (ICPENDR0): 0x00000002
0x48211300 | GICD_ISACTIVER0 (ISACTIVER0): 0x00000000
0x48211380 | GICD_ICACTIVER0 (ICACTIVER0): 0x00000000
0x48211400 | GICD_IPR0 (IPRIORITYR0): 0xf0f0f0f0
0x48211c00 | GICD_ICFR0 (ICFGR0): 0xaaaaaaaa
0x48211f10 | GICD_CPENDSGIR0 (CPENDSGIR0): 0x00000100
0x48211f14 | GICD_CPENDSGIR1 (CPENDSGIR1): 0x00000000
0x48211f18 | GICD_CPENDSGIR2 (CPENDSGIR2): 0x00000000
0x48211f1c | GICD_CPENDSGIR3 (CPENDSGIR3): 0x00000000
0x48211f20 | GICD_SPENDSGIR0 (SPENDSGIR0): 0x00000100
0x48211f24 | GICD_SPENDSGIR1 (SPENDSGIR1): 0x00000000
0x48211f28 | GICD_SPENDSGIR2 (SPENDSGIR2): 0x00000000
0x48211f2c | GICD_SPENDSGIR3 (SPENDSGIR3): 0x00000000


0x48212000 | GICC_ICR (CTRL): 0x00000001
0x48212004 | GICC_PMR (PMR): 0x000000f0
0x48212008 | GICC_BPR (BPR): 0x00000003
0x4821200c | GICC_IAR (IAR): 0x000003ff
0x48212014 | GICC_RPR (RPR): 0x000000ff
0x48212018 | GICC_HPIR (HPPIR): 0x00000001
0x4821201c | GICC_ABPR (ABPR): 0x00000000
0x48212020 | GICC_AIAR (AIAR): 0x00000000
0x48212028 | GICC_AHPPIR (AHPPIR): 0x00000000
0x482120d0 | GICC_APR0 (APR0): 0x00000000
0x482120e0 | GICC_NSAPR0 (NSAPR0): 0x00000000
0x482120fc | GICC_IIDR (IIDR): 0x0002043b

Have any idea? Thx.

  • The RTOS team have been notified. They will respond here.
  • Hi,

    Under Processor SDK RTOS package, we have timer interrupt example on A15 using CSL, maybe you can check that example?
    packages\ti\csl\example\timer\timer_app

    Regards, Eric
  • Hi, Eric

    Thank's for example. I don't seen it before.

    If i understood correctly, in this example is use Control Module crossbar subsystem for linking IRQ lines with TIMER4 crossbar instance number.

    Than the timer module will alert, selected IRQ line is triggered and ISL handler is lounch. All moderation is processed via TIMER4 hardware IRQ (enable/disable).


    How can i use only SGI and emit interrupt via GICD_SGIR (or GICD_SPENDSGIRn) ? It is need to interconnect software on MPU cernels

    There is the example for what i want to do (same GIC on iMX6 platform): github.com/.../gic_test.c

    Thank's

  • Hello again!

    I think I found the reason.

    The registers GICD_IPR[0-3] has incorrect value. This registers must be configured by function csl/arch/a15/src/interrupt.c:Intc_IntPrioritySet()

    Here is the source code of the function:

    void Intc_IntPrioritySet(uint16_t intrNum, uint16_t priority,
                             uint8_t hostIntRoute)
    {
        uint32_t index, mask;
        uint32_t gicIntrId = (uint32_t)intrNum + (uint32_t)32U;
    
        if (intrNum < NUM_INTERRUPTS_EXTERNAL)
        {
            index = ((uint32_t) gicIntrId >> 2) + 1U;
            mask  = (uint32_t) gicIntrId % 4U;
    
            /*Sets the priority of shared peripheral interrupt*/
            HW_WR_REG32(SOC_INTC_MPU_DISTRIBUTOR_BASE +
                        (MPU_GICD_IPR0 + (NUM_BYTES_REG * index)),
                        ((priority & (uint32_t) 0xFF) << (mask * 8U)));
        }
    }

    As you can see, this function is skiped first 4 registers.

    I configure this registers by myself. Now, if i emit SGI, the scl/arch/a15/src/exceptionhandler.asm:IRQHandler() is triggered.
    But function is go to AbortHandler()

    Here is IQHandler function source:

    @******************************************************************************
    @*                  Function Definition of IRQ Handler
    @******************************************************************************
    @
    @ The IRQ handler jumps to the ISR of highest priority pending IRQ.
    @ This handler doesnot support nesting.
    @
    IRQHandler:
            STMFD    r13!, {r0-r3, r12, r14}  @ Save context in IRQ stack
            FMRX      r0, FPEXC                @ Check Neon/VFP Enable bit
            UBFX      r0, r0, #30, #1          @ Bit 30 extract for check
            CMP       r0, #0                   @ Compare for zero
            BEQ       vfp_disabled_irq_save    @ VFP bit is not enabled
            MRS       r12, spsr                @ Copy spsr
            VMRS      r1, FPSCR                @ Copy fpscr
            VMRS      r2, FPEXC                @ Copy fpexc
            STMFD     r13!, {r1-r2, r12}       @ Save spsr, fpscr and fpexc
            VSTMDB    r13!, {d0-d7}            @ Save D0-D7 Neon/VFP registers
            VSTMDB    r13!, {d16-d31}          @ Save D16-D31 Neon/VFP registers
    vfp_disabled_irq_save:
    
            LDR      r1, =addrIar             @ Load global variable addrIar address into r1
            LDR      r0, [r1]                 @ Load IAR address into r0
            LDR      r1, [r0]                 @ Get the Active IRQ
            MOV      r2, r1                   @ save active IRQ in r2
            AND      r1, r1, #IAR_INT_ID_MASK @ Mask the Active IRQ number
            SUB      r1, r1, #PPI_SGI_MASK    @ Get Shared pheriperal int number
            LDR      r3, =fnRAMVectors        @ Load the base of the vector table
            LDR      r0, =argArray            @ Load base of argument
            LDR      r0, [r0, r1, lsl #2]     @ Load argument
            STMFD    r13!, {r2}               @ Save active IRO in stack
            ADD      r14, pc, #0              @ Save return address in LR
            LDR      pc, [r3, r1, lsl #2]     @ Jump to the ISR
            LDMFD    r13!, {r2}               @ Get active IRO from stack
            LDR      r1, =addrEoi             @ Load global variable addrEoi address into r1
            LDR      r3, [r1]                 @ Acknowledge the current IRQ
            STR      r2, [r3]
            DMB                               @ Barrier to complete the data write
    
            FMRX      r0, FPEXC                @ Check Neon/VFP Enable bit
            UBFX      r0, r0, #30, #1          @ Bit 30 extract for check
            CMP       r0, #0                   @ Compare for zero
            BEQ       vfp_disabled_irq_restore @ VFP bit is not enabled
            VLDMIA    r13!, {d16-d31}          @ Restore D16-D31 Neon/VFP registers
            VLDMIA    r13!, {d0-d7}            @ Restore D0-D7 Neon/VFP registers
            LDMFD     r13!, {r1-r2, r12}       @ Get fpscr, fpexc and spsr
            MSR       spsr, r12                @ Restore spsr
            VMSR      fpscr, r1                @ Restore fpscr
            VMSR      fpexc, r2                @ Restore fpexc
    vfp_disabled_irq_restore:
    
            LDMFD    r13!, {r0-r3, r12, r14}  @ Restore registers from IRQ stack
            SUBS     pc, r14, #0x4            @ Return to program before IRQ

    Look at this snippet:

            SUB      r1, r1, #PPI_SGI_MASK    @ Get Shared pheriperal int number
            LDR      r3, =fnRAMVectors        @ Load the base of the vector table
            LDR      r0, =argArray            @ Load base of argument
            LDR      r0, [r0, r1, lsl #2]     @ Load argument

    In this moment, r1=SGI_number, PPI_SGI_MASK=0x20.
    So, we try to load in r0 negative integer.

    Can you fix it?
    Thanks