Commit 420e5c05 authored by Carles Cufi's avatar Carles Cufi Committed by Kumar Gala
Browse files

arm: nvic: Fix exception priority access on Cortex-M0(+)



The Cortex-M0(+) and in general processors that support only the ARMv6-M
instruction set can only access the NVIC_IPRn registers with word
accesses, and not with byte ones like the Cortex-M3 and onwards. This
patch addresses the issue by modifying the way that _NvicIrqPrioSet()
writes to the IPRn register, using a word access for Cortex-M0(+).
A similar issue is addressed for internal exceptions, this time for the
SHPR registers that are accessed differently on ARMv6-M.

Reference code taken from CMSIS.

Jira: ZEP-1497

Change-id: I08e1bf60b3b70579b42f4ab926ee835c18bb65bb
Signed-off-by: default avatarVinayak Chettimada <vinayak.kariappa.chettimada@nordicsemi.no>
Signed-off-by: default avatarCarles Cufi <carles.cufi@nordicsemi.no>
Signed-off-by: default avatarKumar Gala <kumar.gala@linaro.org>
parent 4ef1d4e1
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -184,7 +184,13 @@ static inline void _NvicIrqUnpend(unsigned int irq)

static inline void _NvicIrqPrioSet(unsigned int irq, uint8_t prio)
{
#if defined(CONFIG_CPU_CORTEX_M0_M0PLUS)
	volatile uint32_t * const ipr = &__scs.nvic.ipr[_PRIO_IP_IDX(irq)];
	*ipr = ((*ipr & ~((uint32_t)0xff << _PRIO_BIT_SHIFT(irq))) |
		((uint32_t)prio << _PRIO_BIT_SHIFT(irq)));
#else
	__scs.nvic.ipr[irq] = prio;
#endif /* CONFIG_CPU_CORTEX_M0_M0PLUS */
}

/**
@@ -200,7 +206,11 @@ static inline void _NvicIrqPrioSet(unsigned int irq, uint8_t prio)

static inline uint8_t _NvicIrqPrioGet(unsigned int irq)
{
#if defined(CONFIG_CPU_CORTEX_M0_M0PLUS)
	return (__scs.nvic.ipr[_PRIO_IP_IDX(irq)] >> _PRIO_BIT_SHIFT(irq));
#else
	return __scs.nvic.ipr[irq];
#endif /* CONFIG_CPU_CORTEX_M0_M0PLUS */
}

#if !defined(CONFIG_CPU_CORTEX_M0_M0PLUS)
+21 −5
Original line number Diff line number Diff line
@@ -557,10 +557,12 @@ static inline void ScbCcrSet(uint32_t val)
 *
 * @brief Obtain priority of an exception
 *
 * Only works with exceptions 4 to 15; i.e. do not use this for interrupts, which
 * Only works with exceptions; i.e. do not use this for interrupts, which
 * are exceptions 16+.
 *
 * Exceptions 1 to 3 priorities are fixed (-3, -2, -1).
 * ARMv6-M: Exceptions 1 to 3 priorities are fixed (-3, -2, -1) and 4 to 9 are
 * reserved exceptions.
 * ARMv7-M: Exceptions 1 to 3 priorities are fixed (-3, -2, -1).
 *
 * @param exc exception number, 4 to 15
 * @return priority of exception @a exc
@@ -568,33 +570,47 @@ static inline void ScbCcrSet(uint32_t val)

static inline uint8_t _ScbExcPrioGet(uint8_t exc)
{
#if defined(CONFIG_CPU_CORTEX_M0_M0PLUS)
	__ASSERT((exc > 10) && (exc < 16), "");
	return (__scs.scb.shpr[_PRIO_SHP_IDX(exc)] >> _PRIO_BIT_SHIFT(exc));
#else
	/* For priority exception handler 4-15 */
	__ASSERT((exc > 3) && (exc < 16), "");
	return __scs.scb.shpr[exc - 4];
#endif /* CONFIG_CPU_CORTEX_M0_M0PLUS */
}

/**
 *
 * @brief Set priority of an exception
 *
 * Only works with exceptions 4 to 15; i.e. do not use this for interrupts, which
 * Only works with exceptions; i.e. do not use this for interrupts, which
 * are exceptions 16+.
 *
 * Note that the processor might not implement all 8 bits, in which case the
 * lower N bits are ignored.
 *
 * Exceptions 1 to 3 priorities are fixed (-3, -2, -1).
 * ARMv6-M: Exceptions 1 to 3 priorities are fixed (-3, -2, -1) and 4 to 9 are
 * reserved exceptions.
 * ARMv7-M: Exceptions 1 to 3 priorities are fixed (-3, -2, -1).
 *
 * @param exc  exception number, 4 to 15
 * @param exc  exception number, 10 to 15 on ARMv6-M and 4 to 15 on ARMv7-M
 * @param pri  priority, 0 to 255
 * @return N/A
 */

static inline void _ScbExcPrioSet(uint8_t exc, uint8_t pri)
{
#if defined(CONFIG_CPU_CORTEX_M0_M0PLUS)
	volatile uint32_t * const shpr = &__scs.scb.shpr[_PRIO_SHP_IDX(exc)];
	__ASSERT((exc > 10) && (exc < 16), "");
	*shpr = ((*shpr & ~((uint32_t)0xff << _PRIO_BIT_SHIFT(exc))) |
		 ((uint32_t)pri << _PRIO_BIT_SHIFT(exc)));
#else
	/* For priority exception handler 4-15 */
	__ASSERT((exc > 3) && (exc < 16), "");
	__scs.scb.shpr[exc - 4] = pri;
#endif /* CONFIG_CPU_CORTEX_M0_M0PLUS */
}

#if !defined(CONFIG_CPU_CORTEX_M0_M0PLUS)
+18 −1
Original line number Diff line number Diff line
@@ -454,9 +454,13 @@ struct __scs {
		uint32_t rsvd__320_37f[24];

		uint32_t rsvd__380_3ff[32];

#if defined(CONFIG_CPU_CORTEX_M0_M0PLUS)
		uint32_t ipr[8];
		uint32_t rsvd__420_4ff[56];
#else
		uint8_t ipr[240]; /* 0x400 Interrupt Priority Registers */
		uint32_t rsvd__4f0_4ff[4];
#endif /* CONFIG_CPU_CORTEX_M0_M0PLUS */
	} nvic; /* offset: 0x100, size 0x400 */

	uint32_t rsvd__500_cff[(0xd00 - 0x500) / 4];
@@ -470,10 +474,15 @@ struct __scs {
			aircr;    /* 0xd0c App IRQ and Reset Control Register */
		union __scr scr;  /* 0xd10 System Control Register */
		union __ccr ccr;  /* 0xd14 Configuration and Control Register */
#if defined(CONFIG_CPU_CORTEX_M0_M0PLUS)
		uint32_t rsvd_24_27;
		uint32_t shpr[2];
#else
		uint8_t shpr[12]; /* 0xd18 System Handler Priority Registers
				   *   Use ('exception number' - 4) to
				   *   get index into array
				   */
#endif /* CONFIG_CPU_CORTEX_M0_M0PLUS */
		union __shcsr
			shcsr;     /* 0xd24 Sys Handler Control and State Reg */
		union __cfsr cfsr; /* 0xd28 Configurable Fault Status Register
@@ -530,6 +539,14 @@ struct __scs {
/* the linker always puts this object at 0xe000e000 */
extern volatile struct __scs __scs;

#if defined(CONFIG_CPU_CORTEX_M0_M0PLUS)
/* Interrupt Priorities are WORD accessible only under ARMv6M */
/* The following MACROS handle generation of the register offset and masks */
#define _PRIO_BIT_SHIFT(IRQn) (((((uint32_t)(IRQn))) & 0x03UL) * 8UL)
#define _PRIO_SHP_IDX(IRQn)   ((((((uint32_t)(IRQn)) & 0x0FUL)-8UL) >> 2UL))
#define _PRIO_IP_IDX(IRQn)    ((((uint32_t)(IRQn)) >> 2UL))
#endif /* CONFIG_CPU_CORTEX_M0_M0PLUS */

/* API */

/**