summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-06-21 09:55:09 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-06-21 09:55:09 -0600
commit3085c0bab8588e2704eb452eb030deeb1843541a (patch)
tree2964b8ce6d2410ce1aafca1493dda0039acce1ed
parent1ab0e68865d471fdb26fb143c88876e7e8fe4c48 (diff)
downloadnuttx-3085c0bab8588e2704eb452eb030deeb1843541a.tar.gz
nuttx-3085c0bab8588e2704eb452eb030deeb1843541a.tar.bz2
nuttx-3085c0bab8588e2704eb452eb030deeb1843541a.zip
Need to enable FIQ in initial task state; Improve H32/64 test in IRQ handling
-rwxr-xr-xnuttx/arch/arm/include/armv7-a/irq.h28
-rw-r--r--nuttx/arch/arm/src/armv7-a/arm_head.S2
-rw-r--r--nuttx/arch/arm/src/armv7-a/arm_initialstate.c43
-rw-r--r--nuttx/arch/arm/src/armv7-a/arm_pghead.S2
-rw-r--r--nuttx/arch/arm/src/armv7-a/arm_schedulesigaction.c47
-rw-r--r--nuttx/arch/arm/src/sama5/chip/sam_aic.h22
-rw-r--r--nuttx/arch/arm/src/sama5/chip/sam_matrix.h21
-rw-r--r--nuttx/arch/arm/src/sama5/sam_irq.c71
8 files changed, 130 insertions, 106 deletions
diff --git a/nuttx/arch/arm/include/armv7-a/irq.h b/nuttx/arch/arm/include/armv7-a/irq.h
index 157542e23..0b7b0589e 100755
--- a/nuttx/arch/arm/include/armv7-a/irq.h
+++ b/nuttx/arch/arm/include/armv7-a/irq.h
@@ -44,7 +44,9 @@
* Included Files
****************************************************************************/
+#include <nuttx/config.h>
#include <nuttx/irq.h>
+
#ifndef __ASSEMBLY__
# include <stdint.h>
#endif
@@ -93,7 +95,7 @@
* The FPU provides an extension register file containing 32 single-
* precision registers. These can be viewed as:
*
- * - Sixteen 64-bit doubleword registers, D0-D15
+ * - Sixteen 64-bit double word registers, D0-D15
* - Thirty-two 32-bit single-word registers, S0-S31
* S<2n> maps to the least significant half of D<n>
* S<2n+1> maps to the most significant half of D<n>.
@@ -190,8 +192,7 @@
* Public Types
****************************************************************************/
-/* This struct defines the way the registers are stored. We
- * need to save:
+/* This struct defines the way the registers are stored. We need to save:
*
* 1 CPSR
* 7 Static registers, v1-v7 (aka r4-r10)
@@ -213,16 +214,14 @@
#ifndef __ASSEMBLY__
struct xcptcontext
{
- /* The following function pointer is non-zero if there
- * are pending signals to be processed.
+ /* The following function pointer is non-zero if there are pending signals
+ * to be processed.
*/
#ifndef CONFIG_DISABLE_SIGNALS
void *sigdeliver; /* Actual type is sig_deliver_t */
- /* These are saved copies of LR and CPSR used during
- * signal processing.
- */
+ /* These are saved copies of LR and CPSR used during signal processing. */
uint32_t saved_pc;
uint32_t saved_cpsr;
@@ -233,7 +232,7 @@ struct xcptcontext
uint32_t regs[XCPTCONTEXT_REGS];
/* Extra fault address register saved for common paging logic. In the
- * case of the prefetch abort, this value is the same as regs[REG_R15];
+ * case of the pre-fetch abort, this value is the same as regs[REG_R15];
* For the case of the data abort, this value is the value of the fault
* address register (FAR) at the time of data abort exception.
*/
@@ -328,18 +327,19 @@ static inline void irqrestore(irqstate_t flags)
* Public Variables
****************************************************************************/
-/****************************************************************************
- * Public Function Prototypes
- ****************************************************************************/
-
#ifndef __ASSEMBLY__
#ifdef __cplusplus
#define EXTERN extern "C"
-extern "C" {
+extern "C"
+{
#else
#define EXTERN extern
#endif
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
#undef EXTERN
#ifdef __cplusplus
}
diff --git a/nuttx/arch/arm/src/armv7-a/arm_head.S b/nuttx/arch/arm/src/armv7-a/arm_head.S
index 79f4552f5..705304c8f 100644
--- a/nuttx/arch/arm/src/armv7-a/arm_head.S
+++ b/nuttx/arch/arm/src/armv7-a/arm_head.S
@@ -185,7 +185,7 @@
.type __start, #function
__start:
- /* Make sure that we are in SVC mode with all IRQs disabled */
+ /* Make sure that we are in SVC mode with IRQs and FIQs disabled */
mov r0, #(PSR_MODE_SVC | PSR_I_BIT | PSR_F_BIT)
msr cpsr_c, r0
diff --git a/nuttx/arch/arm/src/armv7-a/arm_initialstate.c b/nuttx/arch/arm/src/armv7-a/arm_initialstate.c
index f9d7f234c..d42062941 100644
--- a/nuttx/arch/arm/src/armv7-a/arm_initialstate.c
+++ b/nuttx/arch/arm/src/armv7-a/arm_initialstate.c
@@ -1,7 +1,7 @@
/****************************************************************************
* arch/arm/src/armv7-a/arm_initialstate.c
*
- * Copyright (C) 2013 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2013-2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -68,13 +68,13 @@
* Name: up_initial_state
*
* Description:
- * A new thread is being started and a new TCB
- * has been created. This function is called to initialize
- * the processor specific portions of the new TCB.
+ * A new thread is being started and a new TCB has been created. This
+ * function is called to initialize the processor specific portions of
+ * the new TCB.
*
- * This function must setup the intial architecture registers
- * and/or stack so that execution will begin at tcb->start
- * on the next context switch.
+ * This function must setup the initial architecture registers and/or
+ * stack so that execution will begin at tcb->start on the next context
+ * switch.
*
****************************************************************************/
@@ -89,11 +89,11 @@ void up_initial_state(struct tcb_s *tcb)
/* Save the initial stack pointer */
- xcp->regs[REG_SP] = (uint32_t)tcb->adj_stack_ptr;
+ xcp->regs[REG_SP] = (uint32_t)tcb->adj_stack_ptr;
/* Save the task entry point */
- xcp->regs[REG_PC] = (uint32_t)tcb->start;
+ xcp->regs[REG_PC] = (uint32_t)tcb->start;
/* If this task is running PIC, then set the PIC base register to the
* address of the allocated D-Space region.
@@ -119,28 +119,39 @@ void up_initial_state(struct tcb_s *tcb)
{
/* It is a kernel thread.. set supervisor mode */
- cpsr = PSR_MODE_SVC | PSR_F_BIT;
+ cpsr = PSR_MODE_SVC;
}
else
{
/* It is a normal task or a pthread. Set user mode */
- cpsr = PSR_MODE_USR | PSR_F_BIT;
+ cpsr = PSR_MODE_USR;
}
#else
/* If the kernel build is not selected, then all threads run in
* supervisor-mode.
*/
- cpsr = PSR_MODE_SVC | PSR_F_BIT;
+ cpsr = PSR_MODE_SVC;
#endif
/* Enable or disable interrupts, based on user configuration */
-# ifdef CONFIG_SUPPRESS_INTERRUPTS
- cpsr |= PSR_I_BIT;
-# endif
+#ifdef CONFIG_SUPPRESS_INTERRUPTS
+ /* Disable interrupts (both IRQs and FIQs) */
- xcp->regs[REG_CPSR] = cpsr;
+ cpsr |= (PSR_I_BIT | PSR_F_BIT);
+
+#else /* CONFIG_SUPPRESS_INTERRUPTS */
+ /* Leave IRQs enabled (Also FIQs if CONFIG_ARMV7A_DECODEFIQ is selected) */
+
+#ifndef CONFIG_ARMV7A_DECODEFIQ
+
+ cpsr |= PSR_F_BIT;
+
+#endif /* !CONFIG_ARMV7A_DECODEFIQ */
+#endif /* CONFIG_SUPPRESS_INTERRUPTS */
+
+ xcp->regs[REG_CPSR] = cpsr;
}
diff --git a/nuttx/arch/arm/src/armv7-a/arm_pghead.S b/nuttx/arch/arm/src/armv7-a/arm_pghead.S
index c191c24ef..e985f6eba 100644
--- a/nuttx/arch/arm/src/armv7-a/arm_pghead.S
+++ b/nuttx/arch/arm/src/armv7-a/arm_pghead.S
@@ -213,7 +213,7 @@
.type __start, #function
__start:
- /* Make sure that we are in SVC mode with all IRQs disabled */
+ /* Make sure that we are in SVC mode with IRQs and FIQs disabled */
mov r0, #(PSR_MODE_SVC | PSR_I_BIT | PSR_F_BIT)
msr cpsr_c, r0
diff --git a/nuttx/arch/arm/src/armv7-a/arm_schedulesigaction.c b/nuttx/arch/arm/src/armv7-a/arm_schedulesigaction.c
index 119d50e0b..819fe16fd 100644
--- a/nuttx/arch/arm/src/armv7-a/arm_schedulesigaction.c
+++ b/nuttx/arch/arm/src/armv7-a/arm_schedulesigaction.c
@@ -115,16 +115,16 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
flags = irqsave();
- /* First, handle some special cases when the signal is
- * being delivered to the currently executing task.
+ /* First, handle some special cases when the signal is being delivered
+ * to the currently executing task.
*/
sdbg("rtcb=0x%p current_regs=0x%p\n", g_readytorun.head, current_regs);
if (tcb == (struct tcb_s*)g_readytorun.head)
{
- /* CASE 1: We are not in an interrupt handler and
- * a task is signalling itself for some reason.
+ /* CASE 1: We are not in an interrupt handler and a task is
+ * signalling itself for some reason.
*/
if (!current_regs)
@@ -134,16 +134,16 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
sigdeliver(tcb);
}
- /* CASE 2: We are in an interrupt handler AND the
- * interrupted task is the same as the one that
- * must receive the signal, then we will have to modify
- * the return state as well as the state in the TCB.
+ /* CASE 2: We are in an interrupt handler AND the interrupted
+ * task is the same as the one that must receive the signal, then
+ * we will have to modify the return state as well as the state
+ * in the TCB.
*
- * Hmmm... there looks like a latent bug here: The following
- * logic would fail in the strange case where we are in an
- * interrupt handler, the thread is signalling itself, but
- * a context switch to another task has occurred so that
- * current_regs does not refer to the thread at g_readytorun.head!
+ * Hmmm... there looks like a latent bug here: The following logic
+ * would fail in the strange case where we are in an interrupt
+ * handler, the thread is signalling itself, but a context switch
+ * to another task has occurred so that current_regs does not
+ * refer to the thread at g_readytorun.head!
*/
else
@@ -162,27 +162,26 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
*/
current_regs[REG_PC] = (uint32_t)up_sigdeliver;
- current_regs[REG_CPSR] = PSR_MODE_SVC | PSR_I_BIT | PSR_F_BIT;
+ current_regs[REG_CPSR] = (PSR_MODE_SVC | PSR_I_BIT | PSR_F_BIT);
- /* And make sure that the saved context in the TCB
- * is the same as the interrupt return context.
+ /* And make sure that the saved context in the TCB is the same
+ * as the interrupt return context.
*/
up_savestate(tcb->xcp.regs);
}
}
- /* Otherwise, we are (1) signaling a task is not running
- * from an interrupt handler or (2) we are not in an
- * interrupt handler and the running task is signalling
- * some non-running task.
+ /* Otherwise, we are (1) signaling a task is not running from an
+ * interrupt handler or (2) we are not in an interrupt handler and the
+ * running task is signalling some non-running task.
*/
else
{
- /* Save the return lr and cpsr and one scratch register
- * These will be restored by the signal trampoline after
- * the signals have been delivered.
+ /* Save the return lr and cpsr and one scratch register. These
+ * will be restored by the signal trampoline after the signals
+ * have been delivered.
*/
tcb->xcp.sigdeliver = sigdeliver;
@@ -194,7 +193,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
*/
tcb->xcp.regs[REG_PC] = (uint32_t)up_sigdeliver;
- tcb->xcp.regs[REG_CPSR] = PSR_MODE_SVC | PSR_I_BIT | PSR_F_BIT;
+ tcb->xcp.regs[REG_CPSR] = (PSR_MODE_SVC | PSR_I_BIT | PSR_F_BIT);
}
irqrestore(flags);
diff --git a/nuttx/arch/arm/src/sama5/chip/sam_aic.h b/nuttx/arch/arm/src/sama5/chip/sam_aic.h
index 8f909fd18..776b74f6c 100644
--- a/nuttx/arch/arm/src/sama5/chip/sam_aic.h
+++ b/nuttx/arch/arm/src/sama5/chip/sam_aic.h
@@ -163,10 +163,10 @@
/* Interrupt Pending Register 0-3 */
-#define AIC_IPR0(pid) (1 << (pid))
-#define AIC_IPR1(pid) (1 << ((pid) - 32)
-#define AIC_IPR2(pid) (1 << ((pid) - 64)
-#define AIC_IPR3(pid) (1 << ((pid) - 96)
+#define AIC_IPR0(pid) (1 << (pid))
+#define AIC_IPR1(pid) (1 << ((pid) - 32)
+#define AIC_IPR2(pid) (1 << ((pid) - 64)
+#define AIC_IPR3(pid) (1 << ((pid) - 96)
/* Interrupt Mask Register */
@@ -220,15 +220,15 @@
/* Write Protect Mode Register */
-#define AIC_WPMR_WPEN (1 << 0) /* Bit 0: Write Protect Enable */
-#define AIC_WPMR_WPKEY_SHIFT (8) /* Bits 8-31: Write Protect KEY */
-#define AIC_WPMR_WPKEY_MASK (0x00ffffff << AIC_WPMR_WPKEY_SHIFT)
-# define AIC_WPMR_WPKEY (0x00414943 << AIC_WPMR_WPKEY_SHIFT)
+#define AIC_WPMR_WPEN (1 << 0) /* Bit 0: Write Protect Enable */
+#define AIC_WPMR_WPKEY_SHIFT (8) /* Bits 8-31: Write Protect KEY */
+#define AIC_WPMR_WPKEY_MASK (0x00ffffff << AIC_WPMR_WPKEY_SHIFT)
+# define AIC_WPMR_WPKEY (0x00414943 << AIC_WPMR_WPKEY_SHIFT)
/* Write Protect Status Register */
-#define AIC_WPSR_WPVS (1 << 0) /* Bit 0: Write Protect Violation Status */
-#define AIC_WPSR_WPVSRC_SHIFT (8) /* Bits 8-23: Write Protect Violation Source */
-#define AIC_WPSR_WPVSRC_MASK (0x0000ffff << AIC_WPSR_WPVSRC_SHIFT)
+#define AIC_WPSR_WPVS (1 << 0) /* Bit 0: Write Protect Violation Status */
+#define AIC_WPSR_WPVSRC_SHIFT (8) /* Bits 8-23: Write Protect Violation Source */
+#define AIC_WPSR_WPVSRC_MASK (0x0000ffff << AIC_WPSR_WPVSRC_SHIFT)
#endif /* __ARCH_ARM_SRC_SAMA5_CHIP_SAM_AIC_H */
diff --git a/nuttx/arch/arm/src/sama5/chip/sam_matrix.h b/nuttx/arch/arm/src/sama5/chip/sam_matrix.h
index d75118b8c..dd4c8b6e8 100644
--- a/nuttx/arch/arm/src/sama5/chip/sam_matrix.h
+++ b/nuttx/arch/arm/src/sama5/chip/sam_matrix.h
@@ -52,6 +52,27 @@
#ifdef ATSAMA5D4
# define H64MX_DDR_SLAVE_PORT0 3
+
+/* These are bits maps of PIDs in the H64MX SPSELR registers. These are used by
+ * application code to quickly determine if a given PID is served by H32MX or H64MX
+ * which, in turn, is needed to know if the peripheral secured in SPSELR).
+ *
+ * NOTE that these hard-code bit values must match the PID assignments in
+ * arch/arm/include/sama5/sama5*_irq.h.
+ */
+
+/* ARM=2, XDMAC0=8, CPKCC=10, AESB=13, MPDDRC=16, MATRIX0=18, VDEC=19 */
+
+# define H64MX_SPSELR0_PIDS 0x000d2504
+
+/* XDMAC1=50, LCDC=51, ISI=52 */
+
+# define H64MX_SPSELR1_PIDS 0x001c0000
+
+/* L2CC=67 */
+
+# define H64MX_SPSELR2_PIDS 0x00000008
+
#endif
/* MATRIX register offsets **************************************************************/
diff --git a/nuttx/arch/arm/src/sama5/sam_irq.c b/nuttx/arch/arm/src/sama5/sam_irq.c
index 78d791fd9..6c5ee0a53 100644
--- a/nuttx/arch/arm/src/sama5/sam_irq.c
+++ b/nuttx/arch/arm/src/sama5/sam_irq.c
@@ -94,6 +94,19 @@ static const uint8_t g_srctype[SCRTYPE_NTYPES] =
0, 0, 1, 1, 2, 3
};
+/* This is an arry of bit maps that can be used to quickly determine is the
+ * peripheral identified by its PID is served by H64MX or H32MX. Then the
+ * appropriate MATRIX SPSELR register can be consulted to determine if the
+ * peripheral interrupts are secured or not.
+ */
+
+#if defined(CONFIG_SAMA5_HAVE_SAIC)
+static const uint32_t g_h64mxpids[3] =
+{
+ H64MX_SPSELR0_PIDS, H64MX_SPSELR1_PIDS, H64MX_SPSELR2_PIDS
+};
+#endif
+
/****************************************************************************
* Private Functions
****************************************************************************/
@@ -231,43 +244,10 @@ static uint32_t *sam_spurious(int irq, uint32_t *regs)
static uint32_t *sam_fiqhandler(int irq, uint32_t *regs)
{
- /* This is probably irrelevant since FIQs are not used in this
- * implementation.
- */
-
-#if defined(CONFIG_DEBUG_IRQ) || defined(CONFIG_ARCH_STACKDUMP)
- lldbg("FIQ?: IRQ: %d\n");
-#endif
- PANIC();
- return regs; /* Won't get here */
-}
-
-/****************************************************************************
- * Name: sam_aic_ish64mx
- *
- * Description:
- * Return true if the peripheral is H64 Matrix.
- *
- * Input Parameter:
- * PID = IRQ number
- *
- ****************************************************************************/
+ /* Dispatch the FIQ */
-#if defined(CONFIG_SAMA5_HAVE_SAIC)
-static inline bool sam_aic_ish64mx(uint32_t irq)
-{
- return (irq == SAM_IRQ_ARM ||
- irq == SAM_IRQ_XDMAC0 ||
- /* irq == SAM_IRQ_CPKCC || */
- irq == SAM_IRQ_AESB ||
- irq == SAM_IRQ_MPDDRC ||
- irq == SAM_IRQ_VDEC ||
- irq == SAM_IRQ_XDMAC1 ||
- irq == SAM_IRQ_LCDC ||
- irq == SAM_IRQ_ISI ||
- irq == SAM_IRQ_L2CC);
+ return arm_doirq(SAM_IRQ_FIQ, regs);
}
-#endif
/****************************************************************************
* Name: sam_aic_issecure
@@ -285,7 +265,7 @@ static bool sam_aic_issecure(uint32_t irq)
{
uintptr_t regaddr;
uint32_t bit;
- int regndx;
+ unsigned int regndx;
/* Get the register index and bit mask */
@@ -294,7 +274,8 @@ static bool sam_aic_issecure(uint32_t irq)
/* Get the SPSELR register address */
- if (sam_aic_ish64mx(irq))
+ DEBUGASSERT(regndx < 3);
+ if ((g_h64mxpids[regndx] & bit) != 0)
{
/* H64MX. Use Matrix 0 */
@@ -626,18 +607,30 @@ uint32_t *arm_decodeirq(uint32_t *regs)
uint32_t *arm_decodefiq(FAR uint32_t *regs)
{
+ uint32_t ret;
+
/* In order to distinguish a FIQ from a true secure interrupt we need to
* check the state of the FIQ line in the SAIC_CISR register.
*/
if ((getreg32(SAM_SAIC_CISR) & AIC_CISR_NFIQ) != 0)
{
- return arm_doirq(SAM_IRQ_FIQ, regs);
+ /* Handle the FIQ */
+
+ ret = arm_doirq(SAM_IRQ_FIQ, regs);
+
+ /* Acknowledge interrupt */
+
+ putreg32(AIC_EOICR_ENDIT, SAM_SAIC_EOICR);
}
else
{
- return sam_decodeirq(SAM_SAIC_VBASE, regs);
+ /* Handle the IRQ */
+
+ ret = sam_decodeirq(SAM_SAIC_VBASE, regs);
}
+
+ return ret;
}
#endif