diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 51adc49fc8f..6b105bad099 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -90,7 +90,8 @@ config ARCH_CHIP_FVP_ARMV8R_AARCH32 select ARCH_CORTEXR52 select ARCH_HAVE_LOWVECTORS select ARCH_HAVE_FETCHADD - select ARMV8R_HAVE_DECODEFIQ + select ARCH_HAVE_IRQPRIO + select ARCH_HAVE_HIPRI_INTERRUPT select ARCH_HAVE_FPU ---help--- ARM FVP virt platform (ARMv8r) diff --git a/arch/arm/include/armv8-r/cp15.h b/arch/arm/include/armv8-r/cp15.h index 7ad3fa42507..5865f242f09 100644 --- a/arch/arm/include/armv8-r/cp15.h +++ b/arch/arm/include/armv8-r/cp15.h @@ -170,10 +170,13 @@ #define CP15_DCIALLU(r) _CP15(0, r, c15, c5, 0) /* Invalidate data cache */ #define CP15_ICC_PMR(r) _CP15(0, r, c4, c6, 0) /* ICC_PMR */ +#define CP15_ICC_IAR0(r) _CP15(0, r, c12, c8, 0) /* ICC_IAR0 */ #define CP15_ICC_IAR1(r) _CP15(0, r, c12, c12, 0) /* ICC_IAR1 */ +#define CP15_ICC_EOIR0(r) _CP15(0, r, c12, c8, 1) /* ICC_EOIR0 */ #define CP15_ICC_EOIR1(r) _CP15(0, r, c12, c12, 1) /* ICC_EOIR1 */ #define CP15_ICC_SRE(r) _CP15(0, r, c12, c12, 5) /* ICC_SRE */ #define CP15_ICC_HSRE(r) _CP15(4, r, c12, c9, 5) /* ICC_HSRE */ +#define CP15_ICC_IGRPEN0(r) _CP15(0, r, c12, c12, 6) /* ICC_IGRPEN0 */ #define CP15_ICC_IGRPEN1(r) _CP15(0, r, c12, c12, 7) /* ICC_IGRPEN1 */ #define CP15_ICC_SGI1R(lo,hi) _CP15_64(0, lo, hi, c12) /* ICC_SGI1R */ diff --git a/arch/arm/include/armv8-r/irq.h b/arch/arm/include/armv8-r/irq.h index a142b4bfbb0..30de6ca2a92 100644 --- a/arch/arm/include/armv8-r/irq.h +++ b/arch/arm/include/armv8-r/irq.h @@ -365,7 +365,7 @@ noinstrument_function static inline irqstate_t up_irq_save(void) ( "\tmrs %0, cpsr\n" "\tcpsid i\n" -#if defined(CONFIG_ARMV8R_DECODEFIQ) +#if defined(CONFIG_ARCH_HIPRI_INTERRUPT) "\tcpsid f\n" #endif : "=r" (cpsr) @@ -386,7 +386,7 @@ static inline irqstate_t up_irq_enable(void) ( "\tmrs %0, cpsr\n" "\tcpsie i\n" -#if defined(CONFIG_ARMV8R_DECODEFIQ) +#if defined(CONFIG_ARCH_HIPRI_INTERRUPT) "\tcpsie f\n" #endif : "=r" (cpsr) diff --git a/arch/arm/src/armv8-r/CMakeLists.txt b/arch/arm/src/armv8-r/CMakeLists.txt index 79a08e37f86..a32ef6c04e5 100644 --- a/arch/arm/src/armv8-r/CMakeLists.txt +++ b/arch/arm/src/armv8-r/CMakeLists.txt @@ -51,4 +51,8 @@ if(CONFIG_ARCH_FPU) list(APPEND SRCS arm_fpucmp.c arm_fpuconfig.S) endif() +if(CONFIG_ARCH_HIPRI_INTERRUPT) + list(APPEND SRCS arm_dofiq.c) +endif() + target_sources(arch PRIVATE ${SRCS}) diff --git a/arch/arm/src/armv8-r/Kconfig b/arch/arm/src/armv8-r/Kconfig index 8dc77ec88a6..e232b07f876 100644 --- a/arch/arm/src/armv8-r/Kconfig +++ b/arch/arm/src/armv8-r/Kconfig @@ -43,18 +43,6 @@ config ARMV8R_MEMINIT the memory initialization first, then explicitly call arm_data_initialize(). -config ARMV8R_HAVE_DECODEFIQ - bool - default n - -config ARMV8R_DECODEFIQ - bool "FIQ Handler" - default n - depends on ARMV8R_HAVE_DECODEFIQ - ---help--- - Select this option if your platform supports the function - arm_decodefiq(). - config ARMV8R_ALIGNMENT_TRAP bool "Enable Alignment Check at __start" default n diff --git a/arch/arm/src/armv8-r/Make.defs b/arch/arm/src/armv8-r/Make.defs index 2e994acd62c..31de2d98f88 100644 --- a/arch/arm/src/armv8-r/Make.defs +++ b/arch/arm/src/armv8-r/Make.defs @@ -52,3 +52,7 @@ endif ifeq ($(CONFIG_ARMV8R_L2CC_PL310),y) CMN_CSRCS += arm_l2cc_pl310.c endif + +ifeq ($(CONFIG_ARCH_HIPRI_INTERRUPT),y) + CMN_CSRCS += arm_dofiq.c +endif diff --git a/arch/arm/src/armv8-r/arm_dofiq.c b/arch/arm/src/armv8-r/arm_dofiq.c new file mode 100644 index 00000000000..5bc5ec009fa --- /dev/null +++ b/arch/arm/src/armv8-r/arm_dofiq.c @@ -0,0 +1,61 @@ +/**************************************************************************** + * arch/arm/src/armv8-r/arm_dofiq.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm_dofiq + * + * Description: + * Receives the decoded GIC interrupt information and dispatches control + * to the attached fiq handler. It is not allowed to call OS functions + * within a FIQ handler. + * + ****************************************************************************/ + +uint32_t *arm_dofiq(int fiq, uint32_t *regs) +{ + board_autoled_on(LED_INIRQ); + +#ifdef CONFIG_SUPPRESS_INTERRUPTS + PANIC(); +#else + irq_dispatch(fiq, regs); +#endif + + board_autoled_off(LED_INIRQ); + return regs; +} diff --git a/arch/arm/src/armv8-r/arm_gic.h b/arch/arm/src/armv8-r/arm_gic.h index 6aee95dff5c..743ccbb61be 100644 --- a/arch/arm/src/armv8-r/arm_gic.h +++ b/arch/arm/src/armv8-r/arm_gic.h @@ -328,6 +328,11 @@ bool arm_gic_irq_is_enabled(unsigned int intid); int arm_gic_initialize(void); void arm_gic_irq_set_priority(unsigned int intid, unsigned int prio, uint32_t flags); + +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT +void arm_gic_set_group(unsigned int intid, unsigned int group); +#endif + int arm_gic_irq_trigger(unsigned int intid, uint32_t flags); int arm_gic_raise_sgi(unsigned int sgi_id, uint16_t target_list); diff --git a/arch/arm/src/armv8-r/arm_gicv3.c b/arch/arm/src/armv8-r/arm_gicv3.c index 1cd20ee9729..af3ec11a986 100644 --- a/arch/arm/src/armv8-r/arm_gicv3.c +++ b/arch/arm/src/armv8-r/arm_gicv3.c @@ -279,6 +279,68 @@ bool arm_gic_irq_is_enabled(unsigned int intid) return (val & mask) != 0; } +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT +void arm_gic_set_group(unsigned int intid, unsigned int group) +{ + uint32_t mask = BIT(intid & (GIC_NUM_INTR_PER_REG - 1)); + uint32_t idx = intid / GIC_NUM_INTR_PER_REG; + unsigned long base = GET_DIST_BASE(intid); + uint32_t igroupr_val; + uint32_t igroupmodr_val; + + igroupr_val = getreg32(IGROUPR(base, idx)); + igroupmodr_val = getreg32(IGROUPMODR(base, idx)); + if (group == 0) + { + igroupr_val &= ~mask; + igroupmodr_val &= ~mask; + } + else + { + igroupr_val |= mask; + igroupmodr_val |= mask; + } + + putreg32(igroupr_val, IGROUPR(base, idx)); + putreg32(igroupmodr_val, IGROUPMODR(base, idx)); +} + +static unsigned int arm_gic_get_active_group0(void) +{ + int intid; + + /* (Pending -> Active / AP) or (AP -> AP) + * Read a Group 0 INTID on an interrupt acknowledge. + */ + + intid = CP15_GET(ICC_IAR0); + + return intid; +} + +static void arm_gic_eoi_group0(unsigned int intid) +{ + /* Interrupt request deassertion from peripheral to GIC happens + * by clearing interrupt condition by a write to the peripheral + * register. It is desired that the write transfer is complete + * before the core tries to change GIC state from 'AP/Active' to + * a new state on seeing 'EOI write'. + * Since ICC interface writes are not ordered against Device + * memory writes, a barrier is required to ensure the ordering. + * The dsb will also ensure *completion* of previous writes with + * DEVICE nGnRnE attribute. + */ + + ARM_DSB(); + + /* (AP -> Pending) Or (Active -> Inactive) or (AP to AP) nested case + * Write a Group 0 interrupt completion + */ + + CP15_SET(ICC_EOIR0, intid); +} +#endif + unsigned int arm_gic_get_active(void) { int intid; @@ -458,6 +520,12 @@ static void gicv3_cpuif_init(void) CP15_SET(ICC_PMR, GIC_IDLE_PRIO); +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT + /* Allow group0 interrupts */ + + CP15_SET(ICC_IGRPEN0, 1); +#endif + /* Allow group1 interrupts */ CP15_SET(ICC_IGRPEN1, 1); @@ -560,14 +628,23 @@ static void gicv3_dist_init(void) * BIT(1), we can reuse them. */ - putreg32(BIT(GICD_CTRL_ARE_S) | BIT(GICD_CTLR_ENABLE_G1NS), - GICD_CTLR); +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT + putreg32(BIT(GICD_CTRL_ARE_S) | BIT(GICD_CTLR_ENABLE_G1NS) | + BIT(GICD_CTLR_ENABLE_G0), GICD_CTLR); +#else + putreg32(BIT(GICD_CTRL_ARE_S) | BIT(GICD_CTLR_ENABLE_G1NS), GICD_CTLR); +#endif /* CONFIG_ARCH_HIPRI_INTERRUPT */ #else /* Enable distributor with ARE */ - putreg32(BIT(GICD_CTRL_ARE_NS) | BIT(GICD_CTLR_ENABLE_G1NS), - GICD_CTLR); +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT + putreg32(BIT(GICD_CTRL_ARE_NS) | BIT(GICD_CTLR_ENABLE_G1NS) | + BIT(GICD_CTLR_ENABLE_G0), GICD_CTLR); +#else + putreg32(BIT(GICD_CTRL_ARE_NS) | BIT(GICD_CTLR_ENABLE_G1NS), GICD_CTLR); +#endif /* CONFIG_ARCH_HIPRI_INTERRUPT */ + #endif #ifdef CONFIG_SMP @@ -676,11 +753,56 @@ void up_trigger_irq(int irq, cpu_set_t cpuset) } } +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT /*************************************************************************** - * Name: arm64_decodeirq + * Name: arm_decodefiq * * Description: - * This function is called from the IRQ vector handler in arm64_vectors.S. + * This function is called from the FIQ vector handler in arm_vectors.S. + * At this point, the interrupt has been taken and the registers have + * been saved on the stack. This function simply needs to determine the + * the irq number of the interrupt and then to call arm_dofiq to dispatch + * the interrupt. + * + * Input Parameters: + * regs - A pointer to the register save area on the stack. + ***************************************************************************/ + +uint32_t *arm_decodefiq(uint32_t *regs) +{ + int fiq; + + /* Read the Group0 interrupt acknowledge register + * and get the interrupt ID + */ + + fiq = arm_gic_get_active_group0(); + + /* Ignore spurions FIQs. ICCIAR will report 1023 if there is no pending + * interrupt. + */ + + DEBUGASSERT(fiq < NR_IRQS || fiq == 1023); + if (fiq < NR_IRQS) + { + /* Dispatch the fiq interrupt */ + + regs = arm_dofiq(fiq, regs); + } + + /* Write to Group0 the end-of-interrupt register */ + + arm_gic_eoi_group0(fiq); + + return regs; +} +#endif + +/*************************************************************************** + * Name: arm_decodeirq + * + * Description: + * This function is called from the IRQ vector handler in arm_vectors.S. * At this point, the interrupt has been taken and the registers have * been saved on the stack. This function simply needs to determine the * the irq number of the interrupt and then to call arm_doirq to dispatch diff --git a/arch/arm/src/armv8-r/arm_initialstate.c b/arch/arm/src/armv8-r/arm_initialstate.c index 079eba403d8..71f9b4f130a 100644 --- a/arch/arm/src/armv8-r/arm_initialstate.c +++ b/arch/arm/src/armv8-r/arm_initialstate.c @@ -131,13 +131,13 @@ void up_initial_state(struct tcb_s *tcb) cpsr |= (PSR_I_BIT | PSR_F_BIT); #else /* CONFIG_SUPPRESS_INTERRUPTS */ - /* Leave IRQs enabled (Also FIQs if CONFIG_ARMV8R_DECODEFIQ is selected) */ + /* Leave IRQs enabled (Also FIQs if CONFIG_ARCH_HIPRI_INTERRUPT is selected) */ -#ifndef CONFIG_ARMV8R_DECODEFIQ +#ifndef CONFIG_ARCH_HIPRI_INTERRUPT cpsr |= PSR_F_BIT; -#endif /* !CONFIG_ARMV8R_DECODEFIQ */ +#endif /* !CONFIG_ARCH_HIPRI_INTERRUPT */ #ifdef CONFIG_ARM_THUMB cpsr |= PSR_T_BIT; diff --git a/arch/arm/src/armv8-r/arm_vectors.S b/arch/arm/src/armv8-r/arm_vectors.S index 4c2d051da3f..891bf904d23 100644 --- a/arch/arm/src/armv8-r/arm_vectors.S +++ b/arch/arm/src/armv8-r/arm_vectors.S @@ -163,7 +163,7 @@ arm_vectorirq: /* Switch to SYS mode */ -#ifdef CONFIG_ARMV8R_DECODEFIQ +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT cpsid if, #PSR_MODE_SYS #else cpsid i, #PSR_MODE_SYS @@ -273,7 +273,7 @@ arm_vectorsvc: /* Switch to SYS mode */ -#ifdef CONFIG_ARMV8R_DECODEFIQ +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT cpsid if, #PSR_MODE_SYS #else cpsid i, #PSR_MODE_SYS @@ -384,7 +384,7 @@ arm_vectordata: /* Switch to SYS mode */ -#ifdef CONFIG_ARMV8R_DECODEFIQ +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT cpsid if, #PSR_MODE_SYS #else cpsid i, #PSR_MODE_SYS @@ -625,14 +625,14 @@ arm_vectorundefinsn: * ****************************************************************************/ -#ifdef CONFIG_ARMV8R_DECODEFIQ +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT .globl arm_decodefiq #endif .globl arm_vectorfiq .type arm_vectorfiq, %function arm_vectorfiq: -#ifdef CONFIG_ARMV8R_DECODEFIQ +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT /* Save the LR and SPSR onto the SYS mode stack before switch. */ @@ -754,7 +754,7 @@ g_intstacktop: * Name: g_fiqstackalloc/g_fiqstacktop ****************************************************************************/ -#ifdef CONFIG_ARMV8R_DECODEFIQ +#ifdef CONFIG_ARCH_HIPRI_INTERRUPT .globl g_fiqstackalloc .type g_fiqstackalloc, object .globl g_fiqstacktop