armv8-r/gicv3: support fiq
1. support fiq decoding and dispatch 2. replace CONFIG_ARMV8R_DECODEFIQ with CONFIG_ARCH_HIPRI_INTERRUPT Signed-off-by: Jinliang Li <lijinliang1@lixiang.com>
This commit is contained in:
parent
825ba8ed7b
commit
37a0445ddb
11 changed files with 218 additions and 30 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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})
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
61
arch/arm/src/armv8-r/arm_dofiq.c
Normal file
61
arch/arm/src/armv8-r/arm_dofiq.c
Normal file
|
|
@ -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 <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/board.h>
|
||||
#include <arch/board/board.h>
|
||||
|
||||
/****************************************************************************
|
||||
* 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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue