zephyr/include/nanokernel/arm/CortexM/nvic.h
Inaky Perez-Gonzalez 8ddf82cf70 First commit
Signed-off-by:  <inaky.perez-gonzalez@intel.com>
2015-04-10 16:44:37 -07:00

238 lines
6.7 KiB
C

/* nvic.c - ARM CORTEX-M Series Nested Vector Interrupt Controller */
/*
* Copyright (c) 2013-2014 Wind River Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2) Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3) Neither the name of Wind River Systems nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
DESCRIPTION
Provide an interface to the Nested Vectored Interrupt Controller found on
ARM Cortex-M processors.
The API does not account for all possible usages of the NVIC, only the
functionalities needed by the VxMicro kernel.
The same effect can be achieved by directly writing in the registers of the
NVIC, with the layout available from scs.h, using the __scs.nvic data
structure (or hardcoded values), but these APIs are less error-prone,
especially for registers with multiple instances to account for potentially
240 interrupt lines. If access to a missing functionality is needed, this is
the way to implement it.
Supports up to 240 IRQs and 256 priority levels.
*/
#ifndef _NVIC_H_
#define _NVIC_H_
#include <misc/__assert.h>
#include <nanokernel/arm/CortexM/scs.h>
/* for assembler, only works with constants */
#define _EXC_PRIO(pri) (((pri) << (8 - CONFIG_NUM_IRQ_PRIO_BITS)) & 0xff)
#if defined(CONFIG_ZERO_LATENCY_IRQS)
#define _EXC_IRQ_DEFAULT_PRIO _EXC_PRIO(0x03)
#else
#define _EXC_IRQ_DEFAULT_PRIO _EXC_PRIO(0x02)
#endif
/* no exc #0 */
#define _EXC_RESET 1
#define _EXC_NMI 2
#define _EXC_HARD_FAULT 3
#define _EXC_MPU_FAULT 4
#define _EXC_BUS_FAULT 5
#define _EXC_USAGE_FAULT 6
/* 7-10 reserved */
#define _EXC_SVC 11
#define _EXC_DEBUG 12
/* 13 reserved */
#define _EXC_PENDSV 14
#define _EXC_SYSTICK 15
/* 16+ IRQs */
#define NUM_IRQS_PER_REG 32
#define REG_FROM_IRQ(irq) (irq / NUM_IRQS_PER_REG)
#define BIT_FROM_IRQ(irq) (irq % NUM_IRQS_PER_REG)
#if !defined(_ASMLANGUAGE)
#include <stdint.h>
/*******************************************************************************
*
* _NvicIrqEnable - enable an IRQ
*
* Enable IRQ #<irq>, which is equivalent to exception #<irq>+16
*
* RETURNS: N/A
*/
static inline void _NvicIrqEnable(unsigned int irq /* IRQ number */
)
{
__scs.nvic.iser[REG_FROM_IRQ(irq)] = 1 << BIT_FROM_IRQ(irq);
}
/*******************************************************************************
*
* _NvicIsIrqEnabled - find out if an IRQ is enabled
*
* Find out if IRQ #<irq> is enabled.
*
* RETURNS: 1 if IRQ is enabled, 0 otherwise
*/
static inline int _NvicIsIrqEnabled(unsigned int irq /* IRQ number */
)
{
return __scs.nvic.iser[REG_FROM_IRQ(irq)] & (1 << BIT_FROM_IRQ(irq));
}
/*******************************************************************************
*
* _NvicIrqEnable - disable an IRQ
*
* Disable IRQ #<irq>, which is equivalent to exception #<irq>+16
*
* RETURNS: N/A
*/
static inline void _NvicIrqDisable(unsigned int irq /* IRQ number */
)
{
__scs.nvic.icer[REG_FROM_IRQ(irq)] = 1 << BIT_FROM_IRQ(irq);
}
/*******************************************************************************
*
* _NvicIrqPend - pend an IRQ
*
* Pend IRQ #<irq>, which is equivalent to exception #<irq>+16. CPU will handle
* the IRQ when interrupts are enabled and/or returning from a higher priority
* interrupt.
*
* RETURNS: N/A
*/
static inline void _NvicIrqPend(unsigned int irq /* IRQ number */
)
{
__scs.nvic.ispr[REG_FROM_IRQ(irq)] = 1 << BIT_FROM_IRQ(irq);
}
/*******************************************************************************
*
* _NvicIsIrqPending - find out if an IRQ is pending
*
* Find out if IRQ #<irq> is pending
*
* RETURNS: 1 if IRQ is pending, 0 otherwise
*/
static inline int _NvicIsIrqPending(unsigned int irq /* IRQ number */
)
{
return __scs.nvic.ispr[REG_FROM_IRQ(irq)] & (1 << BIT_FROM_IRQ(irq));
}
/*******************************************************************************
*
* _NvicIrqUnpend - unpend an IRQ
*
* Unpend IRQ #<irq>, which is equivalent to exception #<irq>+16. The previously
* pending interrupt will be ignored when either unlocking interrupts or
* returning from a higher priority exception.
*
* RETURNS: N/A
*/
static inline void _NvicIrqUnpend(unsigned int irq /* IRQ number */
)
{
__scs.nvic.icpr[REG_FROM_IRQ(irq)] = 1 << BIT_FROM_IRQ(irq);
}
/*******************************************************************************
*
* _NvicIrqPrioSet - set priority of an IRQ
*
* Set priority of IRQ #<irq> to <prio>. There are 256 priority levels.
*
* RETURNS: N/A
*/
static inline void _NvicIrqPrioSet(unsigned int irq, /* IRQ number */
unsigned int prio /* priority */
)
{
__ASSERT(prio < 256, "invalid priority\n");
__scs.nvic.ipr[irq] = prio;
}
/*******************************************************************************
*
* _NvicIrqPrioGet - get priority of an IRQ
*
* Get priority of IRQ #<irq>.
*
* RETURNS: the priority level of the IRQ
*/
static inline uint32_t _NvicIrqPrioGet(unsigned int irq /* IRQ number */
)
{
return __scs.nvic.ipr[irq];
}
/*******************************************************************************
*
* _NvicSwInterruptTrigger - trigger an interrupt via software
*
* Trigger interrupt #<irq>. The CPU will handle the IRQ when interrupts are
* enabled and/or returning from a higher priority interrupt.
*
* RETURNS: N/A
*/
static inline void _NvicSwInterruptTrigger(unsigned int irq /* IRQ number */
)
{
#if defined(CONFIG_BSP_TI_LM3S6965_QEMU)
/* the QEMU does not simulate the STIR register: this is a workaround */
_NvicIrqPend(irq);
#else
__scs.stir = irq;
#endif
}
#endif /* !_ASMLANGUAGE */
#endif /* _NVIC_H_ */