diff options
-rw-r--r-- | c/src/lib/libbsp/arm/lpc24xx/include/i2c.h | 41 | ||||
-rw-r--r-- | c/src/lib/libbsp/arm/lpc24xx/include/idle.h | 41 | ||||
-rw-r--r-- | c/src/lib/libbsp/arm/lpc24xx/include/io.h | 166 | ||||
-rw-r--r-- | c/src/lib/libbsp/arm/lpc24xx/misc/idle.c | 38 | ||||
-rw-r--r-- | c/src/lib/libbsp/arm/lpc24xx/misc/io.c | 499 | ||||
-rw-r--r-- | c/src/lib/libbsp/shared/include/stackalloc.h | 45 | ||||
-rw-r--r-- | c/src/lib/libbsp/shared/src/stackalloc.c | 71 | ||||
-rw-r--r-- | cpukit/score/cpu/arm/arm_exc_handler_high.c | 115 | ||||
-rw-r--r-- | cpukit/score/cpu/arm/arm_exc_handler_low.S | 176 | ||||
-rw-r--r-- | cpukit/score/cpu/arm/arm_exc_interrupt.S | 229 |
10 files changed, 1421 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/arm/lpc24xx/include/i2c.h b/c/src/lib/libbsp/arm/lpc24xx/include/i2c.h new file mode 100644 index 0000000000..f15ade1aad --- /dev/null +++ b/c/src/lib/libbsp/arm/lpc24xx/include/i2c.h @@ -0,0 +1,41 @@ +/** + * @file + * + * @ingroup lpc24xx + * + * LibI2C bus driver for the I2C modules. + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#ifndef LIBBSP_ARM_LPC24XX_I2C_H +#define LIBBSP_ARM_LPC24XX_I2C_H + +#include <rtems/libi2c.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +extern rtems_libi2c_bus_t * const lpc24xx_i2c_0; + +extern rtems_libi2c_bus_t * const lpc24xx_i2c_1; + +extern rtems_libi2c_bus_t * const lpc24xx_i2c_2; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIBBSP_ARM_LPC24XX_I2C_H */ diff --git a/c/src/lib/libbsp/arm/lpc24xx/include/idle.h b/c/src/lib/libbsp/arm/lpc24xx/include/idle.h new file mode 100644 index 0000000000..116842b465 --- /dev/null +++ b/c/src/lib/libbsp/arm/lpc24xx/include/idle.h @@ -0,0 +1,41 @@ +/** + * @file + * + * @author Sebastian Huber <sebastian.huber@embedded-brains.de> + * + * @ingroup lpc24xx + * + * @brief Idle task + */ + +/* + * Copyright (c) 2009 + * Embedded Brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * rtems@embedded-brains.de + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#ifndef LIBBSP_ARM_LPC24XX_IDLE_H +#define LIBBSP_ARM_LPC24XX_IDLE_H + +#include <rtems.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +Thread lpc24xx_idle( uint32_t ignored); + +#define BSP_IDLE_TASK_BODY lpc24xx_idle + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIBBSP_ARM_LPC24XX_IDLE_H */ diff --git a/c/src/lib/libbsp/arm/lpc24xx/include/io.h b/c/src/lib/libbsp/arm/lpc24xx/include/io.h new file mode 100644 index 0000000000..c40d29e631 --- /dev/null +++ b/c/src/lib/libbsp/arm/lpc24xx/include/io.h @@ -0,0 +1,166 @@ +/** + * @file + * + * @ingroup lpc24xx + * + * Input and output module. + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#ifndef LIBBSP_ARM_LPC24XX_IO_H +#define LIBBSP_ARM_LPC24XX_IO_H + +#include <rtems.h> + +#include <bsp/lpc24xx.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define LPC24XX_IO_PORT_COUNT 5U + +#define LPC24XX_IO_INDEX_MAX (LPC24XX_IO_PORT_COUNT * 32U) + +#define LPC24XX_IO_INDEX_BY_PORT( port, bit) (((port) << 5U) + (bit)) + +#define LPC24XX_IO_PORT( index) (index >> 5U) + +#define LPC24XX_IO_PORT_BIT( index) (index & 0x1fU) + +typedef enum { + LPC24XX_MODULE_ACF, + LPC24XX_MODULE_ADC, + LPC24XX_MODULE_BAT_RAM, + LPC24XX_MODULE_CAN, + LPC24XX_MODULE_DAC, + LPC24XX_MODULE_EMC, + LPC24XX_MODULE_ETHERNET, + LPC24XX_MODULE_GPDMA, + LPC24XX_MODULE_GPIO, + LPC24XX_MODULE_I2C, + LPC24XX_MODULE_I2S, + LPC24XX_MODULE_LCD, + LPC24XX_MODULE_MCI, + LPC24XX_MODULE_PCB, + LPC24XX_MODULE_PWM, + LPC24XX_MODULE_RTC, + LPC24XX_MODULE_SPI, + LPC24XX_MODULE_SSP, + LPC24XX_MODULE_SYSCON, + LPC24XX_MODULE_TIMER, + LPC24XX_MODULE_UART, + LPC24XX_MODULE_USB, + LPC24XX_MODULE_WDT, + LPC24XX_MODULE_NUMBER +} lpc24xx_module; + +typedef enum { + LPC24XX_MODULE_PCLK_DEFAULT = 0x0U, + LPC24XX_MODULE_CCLK = 0x1U, + LPC24XX_MODULE_CCLK_2 = 0x2U, + LPC24XX_MODULE_CCLK_4 = 0x0U, + LPC24XX_MODULE_CCLK_6 = 0x3U, + LPC24XX_MODULE_CCLK_8 = 0x3U +} lpc24xx_module_clock; + +#define LPC24XX_MODULE_CLOCK_MASK 0x3U + +typedef enum { + LPC24XX_GPIO_DEFAULT = 0x0U, + LPC24XX_GPIO_RESISTOR_DEFAULT = 0x0U, + LPC24XX_GPIO_RESISTOR_NONE = 0x1U, + LPC24XX_GPIO_RESISTOR_PULL_UP = 0x2U, + LPC24XX_GPIO_RESISTOR_PULL_DOWN = 0x3U, + LPC24XX_GPIO_INPUT = 0x0U, + LPC24XX_GPIO_OUTPUT = 0x8U +} lpc24xx_gpio_settings; + +#define LPC24XX_GPIO_RESISTOR_MASK 0x3U + +rtems_status_code lpc24xx_module_enable( + lpc24xx_module module, + unsigned index, + lpc24xx_module_clock clock +); + +rtems_status_code lpc24xx_module_disable( + lpc24xx_module module, + unsigned index +); + +rtems_status_code lpc24xx_io_config( + lpc24xx_module module, + unsigned index, + unsigned config +); + +rtems_status_code lpc24xx_io_release( + lpc24xx_module module, + unsigned index, + unsigned config +); + +rtems_status_code lpc24xx_gpio_config( + unsigned index, + lpc24xx_gpio_settings settings +); + +static inline void lpc24xx_gpio_set( unsigned index) +{ + if (index <= LPC24XX_IO_INDEX_MAX) { + unsigned port = LPC24XX_IO_PORT( index); + unsigned bit = LPC24XX_IO_PORT_BIT( index); + + LPC24XX_FIO [port].set = 1U << bit; + } +} + +static inline void lpc24xx_gpio_clear( unsigned index) +{ + if (index <= LPC24XX_IO_INDEX_MAX) { + unsigned port = LPC24XX_IO_PORT( index); + unsigned bit = LPC24XX_IO_PORT_BIT( index); + + LPC24XX_FIO [port].clr = 1U << bit; + } +} + +static inline void lpc24xx_gpio_write( unsigned index, bool value) +{ + if (value) { + lpc24xx_gpio_set( index); + } else { + lpc24xx_gpio_clear( index); + } +} + +static inline bool lpc24xx_gpio_get( unsigned index) +{ + if (index <= LPC24XX_IO_INDEX_MAX) { + unsigned port = LPC24XX_IO_PORT( index); + unsigned bit = LPC24XX_IO_PORT_BIT( index); + + return (LPC24XX_FIO [port].pin & (1U << bit)) != 0; + } else { + return false; + } +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIBBSP_ARM_LPC24XX_IO_H */ diff --git a/c/src/lib/libbsp/arm/lpc24xx/misc/idle.c b/c/src/lib/libbsp/arm/lpc24xx/misc/idle.c new file mode 100644 index 0000000000..84d9a8c107 --- /dev/null +++ b/c/src/lib/libbsp/arm/lpc24xx/misc/idle.c @@ -0,0 +1,38 @@ +/** + * @file + * + * @author Sebastian Huber <sebastian.huber@embedded-brains.de> + * + * @ingroup lpc24xx + * + * @brief Idle task. + */ + +/* + * Copyright (c) 2008 + * Embedded Brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * rtems@embedded-brains.de + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#include <bsp/idle.h> +#include <bsp/lpc24xx.h> + +Thread lpc24xx_idle( uint32_t ignored) +{ + while (true) { + /* + * Set power mode to idle. Causes the processor clock to be stopped, while + * on-chip peripherals remain active. Any enabled interrupt from a + * peripheral or an external interrupt source will cause the processor to + * resume execution. + */ + PCON = 0x1; + } +} diff --git a/c/src/lib/libbsp/arm/lpc24xx/misc/io.c b/c/src/lib/libbsp/arm/lpc24xx/misc/io.c new file mode 100644 index 0000000000..d1b46b7289 --- /dev/null +++ b/c/src/lib/libbsp/arm/lpc24xx/misc/io.c @@ -0,0 +1,499 @@ +/** + * @file + * + * @ingroup lpc24xx + * + * Input and output module. + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#include <bsp/io.h> + +#define LPC24XX_IO_SELECT( index) (index >> 4U) + +#define LPC24XX_IO_SELECT_SHIFT( index) ((index & 0xfU) << 1U) + +#define LPC24XX_IO_SELECT_MASK 0x3U + +#define LPC24XX_IO_PRIMARY 0x0U + +#define LPC24XX_IO_ALTERNATE_0 0x1U + +#define LPC24XX_IO_ALTERNATE_1 0x2U + +#define LPC24XX_IO_ALTERNATE_2 0x3U + +#define LPC24XX_IO_HEADER_FLAG 0x80U + +#define LPC24XX_IO_ENTRY( b, e, f) \ + { .function = f, .begin = b, .end = e } + +#define LPC24XX_IO_HEADER( module, index, config) \ + { .function = config | LPC24XX_IO_HEADER_FLAG, .begin = module, .end = index } + +typedef struct __attribute__ ((__packed__)) { + unsigned char function; + unsigned char begin; + unsigned char end; +} lpc24xx_io_entry; + +typedef void (*lpc24xx_io_iterate_routine)( unsigned /* index */, unsigned /* function */); + +static const lpc24xx_io_entry lpc24xx_io_config_table [] = { + /* EMC */ + LPC24XX_IO_HEADER( LPC24XX_MODULE_EMC, 0, 0), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 2, 16), LPC24XX_IO_INDEX_BY_PORT( 2, 22), LPC24XX_IO_ALTERNATE_0), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 2, 24), LPC24XX_IO_INDEX_BY_PORT( 2, 26), LPC24XX_IO_ALTERNATE_0), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 2, 26), LPC24XX_IO_INDEX_BY_PORT( 2, 30), LPC24XX_IO_ALTERNATE_0), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 3, 0), LPC24XX_IO_INDEX_BY_PORT( 3, 16), LPC24XX_IO_ALTERNATE_0), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 4, 0), LPC24XX_IO_INDEX_BY_PORT( 4, 28), LPC24XX_IO_ALTERNATE_0), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 4, 30), LPC24XX_IO_INDEX_BY_PORT( 5, 0), LPC24XX_IO_ALTERNATE_0), + + /* UART */ + LPC24XX_IO_HEADER( LPC24XX_MODULE_UART, 0, 0), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 2), LPC24XX_IO_INDEX_BY_PORT( 0, 4), LPC24XX_IO_ALTERNATE_0), + LPC24XX_IO_HEADER( LPC24XX_MODULE_UART, 1, 0), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 15), LPC24XX_IO_INDEX_BY_PORT( 0, 17), LPC24XX_IO_ALTERNATE_1), + LPC24XX_IO_HEADER( LPC24XX_MODULE_UART, 1, 1), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 2, 0), LPC24XX_IO_INDEX_BY_PORT( 2, 2), LPC24XX_IO_ALTERNATE_2), + LPC24XX_IO_HEADER( LPC24XX_MODULE_UART, 1, 2), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 3, 16), LPC24XX_IO_INDEX_BY_PORT( 3, 18), LPC24XX_IO_ALTERNATE_1), + LPC24XX_IO_HEADER( LPC24XX_MODULE_UART, 2, 0), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 10), LPC24XX_IO_INDEX_BY_PORT( 0, 12), LPC24XX_IO_ALTERNATE_1), + LPC24XX_IO_HEADER( LPC24XX_MODULE_UART, 2, 1), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 2, 8), LPC24XX_IO_INDEX_BY_PORT( 2, 10), LPC24XX_IO_ALTERNATE_1), + LPC24XX_IO_HEADER( LPC24XX_MODULE_UART, 2, 2), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 4, 22), LPC24XX_IO_INDEX_BY_PORT( 4, 24), LPC24XX_IO_ALTERNATE_1), + LPC24XX_IO_HEADER( LPC24XX_MODULE_UART, 3, 0), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 0), LPC24XX_IO_INDEX_BY_PORT( 0, 2), LPC24XX_IO_ALTERNATE_2), + LPC24XX_IO_HEADER( LPC24XX_MODULE_UART, 3, 1), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 25), LPC24XX_IO_INDEX_BY_PORT( 0, 27), LPC24XX_IO_ALTERNATE_2), + LPC24XX_IO_HEADER( LPC24XX_MODULE_UART, 3, 2), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 4, 28), LPC24XX_IO_INDEX_BY_PORT( 4, 30), LPC24XX_IO_ALTERNATE_2), + + /* Ethernet */ + LPC24XX_IO_HEADER( LPC24XX_MODULE_ETHERNET, 0, 0), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 1, 0), LPC24XX_IO_INDEX_BY_PORT( 1, 18), LPC24XX_IO_ALTERNATE_0), + LPC24XX_IO_HEADER( LPC24XX_MODULE_ETHERNET, 0, 1), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 1, 0), LPC24XX_IO_INDEX_BY_PORT( 1, 2), LPC24XX_IO_ALTERNATE_0), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 1, 4), LPC24XX_IO_INDEX_BY_PORT( 1, 5), LPC24XX_IO_ALTERNATE_0), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 1, 8), LPC24XX_IO_INDEX_BY_PORT( 1, 11), LPC24XX_IO_ALTERNATE_0), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 1, 14), LPC24XX_IO_INDEX_BY_PORT( 1, 18), LPC24XX_IO_ALTERNATE_0), + + /* ADC */ + LPC24XX_IO_HEADER( LPC24XX_MODULE_ADC, 0, 0), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 12), LPC24XX_IO_INDEX_BY_PORT( 0, 14), LPC24XX_IO_ALTERNATE_2), + + /* I2C */ + LPC24XX_IO_HEADER( LPC24XX_MODULE_I2C, 0, 0), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 27), LPC24XX_IO_INDEX_BY_PORT( 0, 29), LPC24XX_IO_ALTERNATE_0), + LPC24XX_IO_HEADER( LPC24XX_MODULE_I2C, 1, 0), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 0), LPC24XX_IO_INDEX_BY_PORT( 0, 2), LPC24XX_IO_ALTERNATE_2), + LPC24XX_IO_HEADER( LPC24XX_MODULE_I2C, 1, 1), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 19), LPC24XX_IO_INDEX_BY_PORT( 0, 21), LPC24XX_IO_ALTERNATE_2), + LPC24XX_IO_HEADER( LPC24XX_MODULE_I2C, 1, 2), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 2, 14), LPC24XX_IO_INDEX_BY_PORT( 2, 16), LPC24XX_IO_ALTERNATE_2), + LPC24XX_IO_HEADER( LPC24XX_MODULE_I2C, 2, 0), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 10), LPC24XX_IO_INDEX_BY_PORT( 0, 12), LPC24XX_IO_ALTERNATE_1), + LPC24XX_IO_HEADER( LPC24XX_MODULE_I2C, 2, 1), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 2, 30), LPC24XX_IO_INDEX_BY_PORT( 3, 0), LPC24XX_IO_ALTERNATE_2), + LPC24XX_IO_HEADER( LPC24XX_MODULE_I2C, 2, 2), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 4, 20), LPC24XX_IO_INDEX_BY_PORT( 4, 22), LPC24XX_IO_ALTERNATE_1), + + /* USB */ + LPC24XX_IO_HEADER( LPC24XX_MODULE_USB, 0, 0), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 0, 29), LPC24XX_IO_INDEX_BY_PORT( 0, 31), LPC24XX_IO_ALTERNATE_0), + LPC24XX_IO_ENTRY( LPC24XX_IO_INDEX_BY_PORT( 1, 19), LPC24XX_IO_INDEX_BY_PORT( 1, 20), LPC24XX_IO_ALTERNATE_1), +}; + +static size_t lpc24xx_io_get_entry_index( lpc24xx_module module, unsigned index, unsigned config) +{ + size_t i = 0; + + config |= LPC24XX_IO_HEADER_FLAG; + + for (i = 0; i < sizeof( lpc24xx_io_config_table); ++i) { + const lpc24xx_io_entry *e = lpc24xx_io_config_table + i; + + if (e->function == config && e->begin == module && e->end == index) { + return i + 1; + } + } + + return (size_t) -1; +} + +static void lpc24xx_io_do_config( unsigned index, unsigned function) +{ + rtems_interrupt_level level; + unsigned select = LPC24XX_IO_SELECT( index); + unsigned shift = LPC24XX_IO_SELECT_SHIFT( index); + + rtems_interrupt_disable( level); + + LPC24XX_PINSEL [select] = + (LPC24XX_PINSEL [select] & ~(LPC24XX_IO_SELECT_MASK << shift)) + | ((function & LPC24XX_IO_SELECT_MASK) << shift); + + rtems_interrupt_flash( level); + + LPC24XX_PINMODE [select] &= ~(LPC24XX_IO_SELECT_MASK << shift); + + rtems_interrupt_enable( level); +} + +static void lpc24xx_io_do_release( unsigned index, unsigned function) +{ + rtems_interrupt_level level; + unsigned select = LPC24XX_IO_SELECT( index); + unsigned shift = LPC24XX_IO_SELECT_SHIFT( index); + + rtems_interrupt_disable( level); + LPC24XX_PINSEL [select] = + (LPC24XX_PINSEL [select] & ~(LPC24XX_IO_SELECT_MASK << shift)); + rtems_interrupt_enable( level); +} + +static rtems_status_code lpc24xx_io_iterate( + lpc24xx_module module, + unsigned index, + unsigned config, + lpc24xx_io_iterate_routine routine +) +{ + size_t i = lpc24xx_io_get_entry_index( module, index, config); + + if (i != (size_t) -1) { + const lpc24xx_io_entry * const table_end = lpc24xx_io_config_table + + sizeof( lpc24xx_io_config_table) / sizeof( lpc24xx_io_config_table [0]); + const lpc24xx_io_entry *e = lpc24xx_io_config_table + i; + + while (e != table_end && (e->function & LPC24XX_IO_HEADER_FLAG) == 0) { + unsigned j = e->begin; + unsigned end = e->end; + unsigned function = e->function; + + while (j < end) { + routine( j, function); + + ++j; + } + + ++e; + } + } else { + return RTEMS_INVALID_ID; + } + + return RTEMS_SUCCESSFUL; +} + +rtems_status_code lpc24xx_io_config( + lpc24xx_module module, + unsigned index, + unsigned config +) +{ + return lpc24xx_io_iterate( module, index, config, lpc24xx_io_do_config); +} + +rtems_status_code lpc24xx_io_release( + lpc24xx_module module, + unsigned index, + unsigned config +) +{ + return lpc24xx_io_iterate( module, index, config, lpc24xx_io_do_release); +} + +rtems_status_code lpc24xx_gpio_config( + unsigned index, + lpc24xx_gpio_settings settings +) +{ + if (index <= LPC24XX_IO_INDEX_MAX) { + rtems_interrupt_level level; + unsigned port = LPC24XX_IO_PORT( index); + unsigned bit = LPC24XX_IO_PORT_BIT( index); + unsigned select = LPC24XX_IO_SELECT( index); + unsigned shift = LPC24XX_IO_SELECT_SHIFT( index); + unsigned resistor = settings & LPC24XX_GPIO_RESISTOR_MASK; + unsigned output = (settings & LPC24XX_GPIO_OUTPUT) != 0 ? 1U : 0U; + + /* Get resistor flags */ + switch (resistor) { + case LPC24XX_GPIO_RESISTOR_PULL_UP: + case LPC24XX_GPIO_RESISTOR_DEFAULT: + resistor = 0x0U; + break; + case LPC24XX_GPIO_RESISTOR_NONE: + resistor = 0x2U; + break; + case LPC24XX_GPIO_RESISTOR_PULL_DOWN: + resistor = 0x3U; + break; + default: + return RTEMS_INVALID_NUMBER; + } + + rtems_interrupt_disable( level); + + /* Resistor */ + LPC24XX_PINMODE [select] = + (LPC24XX_PINMODE [select] & ~(LPC24XX_IO_SELECT_MASK << shift)) + | ((resistor & LPC24XX_IO_SELECT_MASK) << shift); + + rtems_interrupt_flash( level); + + /* Input or output */ + LPC24XX_FIO [port].dir = + (LPC24XX_FIO [port].dir & ~(1U << bit)) | (output << bit); + + rtems_interrupt_enable( level); + } else { + return RTEMS_INVALID_ID; + } + + return RTEMS_SUCCESSFUL; +} + +static rtems_status_code lpc24xx_module_do_enable( + lpc24xx_module module, + unsigned index, + lpc24xx_module_clock clock, + bool enable +) +{ + const unsigned NO_POWER = 32U; + const unsigned INVALID = 33U; + unsigned power_bit = INVALID; + unsigned clock_shift = INVALID; + + /* Check clock value */ + if ((clock & ~LPC24XX_MODULE_CLOCK_MASK) != 0U) { + return RTEMS_INVALID_NUMBER; + } + + /* Get power bit */ + switch (module) { + case LPC24XX_MODULE_ACF: + if (index == 0) { + power_bit = NO_POWER; + clock_shift = 30U; + } + break; + case LPC24XX_MODULE_ADC: + if (index == 0) { + power_bit = 12U; + } + break; + case LPC24XX_MODULE_BAT_RAM: + if (index == 0) { + power_bit = NO_POWER; + clock_shift = 32U; + } + break; + case LPC24XX_MODULE_CAN: + if (index < 2) { + power_bit = 13U + index; + } + break; + case LPC24XX_MODULE_DAC: + if (index == 0) { + power_bit = NO_POWER; + clock_shift = 22U; + } + break; + case LPC24XX_MODULE_EMC: + if (index == 0) { + power_bit = 11U; + } + break; + case LPC24XX_MODULE_ETHERNET: + if (index == 0) { + power_bit = 30U; + } + break; + case LPC24XX_MODULE_GPDMA: + if (index == 0) { + power_bit = 29U; + } + break; + case LPC24XX_MODULE_GPIO: + if (index == 0) { + power_bit = NO_POWER; + clock_shift = 34U; + } + break; + case LPC24XX_MODULE_I2C: + switch (index) { + case 0U: + power_bit = 7U; + break; + case 1U: + power_bit = 19U; + break; + case 2U: + power_bit = 26U; + break; + } + break; + case LPC24XX_MODULE_I2S: + if (index == 0) { + power_bit = 27U; + } + break; + case LPC24XX_MODULE_LCD: + if (index == 0) { + power_bit = 20U; + } + break; + case LPC24XX_MODULE_MCI: + if (index == 0) { + power_bit = 28U; + } + break; + case LPC24XX_MODULE_PCB: + if (index == 0) { + power_bit = NO_POWER; + clock_shift = 36U; + } + break; + case LPC24XX_MODULE_PWM: + if (index < 2) { + power_bit = 5U + index; + } + break; + case LPC24XX_MODULE_RTC: + if (index == 0) { + power_bit = 9U; + } + break; + case LPC24XX_MODULE_SPI: + if (index == 0) { + power_bit = 8U; + } + break; + case LPC24XX_MODULE_SSP: + switch (index) { + case 0U: + power_bit = 21U; + break; + case 1U: + power_bit = 10U; + break; + } + break; + case LPC24XX_MODULE_SYSCON: + if (index == 0) { + power_bit = NO_POWER; + clock_shift = 60U; + } + break; + case LPC24XX_MODULE_TIMER: + if (index < 2) { + power_bit = 1U + index; + } else if (index < 4) { + power_bit = 20U + index; + } + break; + case LPC24XX_MODULE_UART: + if (index < 2) { + power_bit = 3U + index; + } else if (index < 4) { + power_bit = 22U + index; + } + break; + case LPC24XX_MODULE_USB: + if (index == 0) { + power_bit = 31U; + } + break; + case LPC24XX_MODULE_WDT: + if (index == 0) { + power_bit = NO_POWER; + clock_shift = 0U; + } + break; + default: + return RTEMS_INVALID_ID; + } + + /* Check power bit */ + if (power_bit == INVALID) { + return RTEMS_INVALID_ID; + } + + /* Get clock shift */ + if (clock_shift == INVALID) { + clock_shift = power_bit << 1U; + } + + /* Enable or disable module */ + if (enable) { + rtems_interrupt_level level; + + rtems_interrupt_disable( level); + PCONP |= 1U << power_bit; + rtems_interrupt_enable( level); + + if (module != LPC24XX_MODULE_USB) { + rtems_interrupt_disable( level); + if (clock_shift < 32U) { + PCLKSEL0 = (PCLKSEL0 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift)) + | (clock << clock_shift); + } else { + clock_shift -= 32U; + PCLKSEL1 = (PCLKSEL1 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift)) + | (clock << clock_shift); + } + rtems_interrupt_enable( level); + } else { + unsigned pllclk = lpc24xx_pllclk(); + unsigned usbsel = pllclk / 48000000U - 1U; + + if (usbsel > 15U || (usbsel % 2U != 1U) || (pllclk % 48000000U) != 0U) { + return RTEMS_INCORRECT_STATE; + } + + USBCLKCFG = usbsel; + } + } else { + rtems_interrupt_level level; + + rtems_interrupt_disable( level); + PCONP &= ~(1U << power_bit); + rtems_interrupt_enable( level); + } + + return RTEMS_SUCCESSFUL; +} + +rtems_status_code lpc24xx_module_enable( + lpc24xx_module module, + unsigned index, + lpc24xx_module_clock clock +) +{ + return lpc24xx_module_do_enable( module, index, clock, true); +} + +rtems_status_code lpc24xx_module_disable( + lpc24xx_module module, + unsigned index +) +{ + return lpc24xx_module_do_enable( module, index, 0U, false); +} diff --git a/c/src/lib/libbsp/shared/include/stackalloc.h b/c/src/lib/libbsp/shared/include/stackalloc.h new file mode 100644 index 0000000000..e95f43591a --- /dev/null +++ b/c/src/lib/libbsp/shared/include/stackalloc.h @@ -0,0 +1,45 @@ +/** + * @file + * + * @ingroup bsp_shared + * + * @brief Stack initialization, allocation and free functions. + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * rtems@embedded-brains.de + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#ifndef LIBBSP_SHARED_STACK_ALLOC_H +#define LIBBSP_SHARED_STACK_ALLOC_H + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void bsp_stack_initialize(void *start, intptr_t size); + +void *bsp_stack_allocate(uint32_t size); + +void bsp_stack_free(void *stack); + +#define CONFIGURE_TASK_STACK_ALLOCATOR bsp_stack_allocate + +#define CONFIGURE_TASK_STACK_DEALLOCATOR bsp_stack_free + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIBBSP_SHARED_STACK_ALLOC_H */ diff --git a/c/src/lib/libbsp/shared/src/stackalloc.c b/c/src/lib/libbsp/shared/src/stackalloc.c new file mode 100644 index 0000000000..31b7c14db3 --- /dev/null +++ b/c/src/lib/libbsp/shared/src/stackalloc.c @@ -0,0 +1,71 @@ +/** + * @file + * + * @ingroup bsp_shared + * + * @brief Stack initialization, allocation and free functions. + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * rtems@embedded-brains.de + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#include <rtems.h> +#include <rtems/score/wkspace.h> + +#include <bsp/stackalloc.h> + +#define BSP_STACK_MAGIC 0xdeadbeef + +static Heap_Control bsp_stack_heap = { + .page_size = BSP_STACK_MAGIC +}; + +void bsp_stack_initialize(void *start, intptr_t size) +{ + bsp_stack_heap.begin = start; + bsp_stack_heap.end = (void *) size; +} + +void *bsp_stack_allocate(uint32_t size) +{ + void *stack = NULL; + + if (bsp_stack_heap.page_size == BSP_STACK_MAGIC) { + uint32_t rv = _Heap_Initialize( + &bsp_stack_heap, + bsp_stack_heap.begin, + (intptr_t) bsp_stack_heap.end, + CPU_STACK_ALIGNMENT + ); + if (rv == 0) { + return NULL; + } + } + + stack = _Heap_Allocate(&bsp_stack_heap, (intptr_t) size); + + if (stack == NULL) { + stack = _Workspace_Allocate(size); + } + + return stack; +} + +void bsp_stack_free(void *stack) +{ + bool ok = _Heap_Free(&bsp_stack_heap, stack); + + if (!ok) { + _Workspace_Free(stack); + } +} diff --git a/cpukit/score/cpu/arm/arm_exc_handler_high.c b/cpukit/score/cpu/arm/arm_exc_handler_high.c new file mode 100644 index 0000000000..0b256ffc7e --- /dev/null +++ b/cpukit/score/cpu/arm/arm_exc_handler_high.c @@ -0,0 +1,115 @@ +/** + * @file + * + * ARM exception support code. + */ + +/* + * COPYRIGHT (c) 2000 Canon Research Centre France SA. + * Emmanuel Raguet, mailto:raguet@crf.canon.fr + * + * Copyright (c) 2002 Advent Networks, Inc + * Jay Monkman <jmonkman@adventnetworks.com> + * + * Copyright (c) 2007 Ray xu <rayx.cn@gmail.com> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * Moved from file 'cpukit/score/cpu/arm/cpu.c'. + * + * $Id$ + */ + +#include <rtems/system.h> +#include <rtems.h> +#include <rtems/bspIo.h> +#include <rtems/score/isr.h> +#include <rtems/score/wkspace.h> +#include <rtems/score/thread.h> +#include <rtems/score/cpu.h> + +static void _defaultExcHandler (CPU_Exception_frame *ctx) +{ + printk("\n\r"); + printk("----------------------------------------------------------\n\r"); +#if 1 + printk("Exception 0x%x caught at PC 0x%x by thread %d\n", + ctx->register_ip, ctx->register_lr - 4, + _Thread_Executing->Object.id); +#endif + printk("----------------------------------------------------------\n\r"); + printk("Processor execution context at time of the fault was :\n\r"); + printk("----------------------------------------------------------\n\r"); +#if 0 + printk(" r0 = %8x r1 = %8x r2 = %8x r3 = %8x\n\r", + ctx->register_r0, ctx->register_r1, + ctx->register_r2, ctx->register_r3); + printk(" r4 = %8x r5 = %8x r6 = %8x r7 = %8x\n\r", + ctx->register_r4, ctx->register_r5, + ctx->register_r6, ctx->register_r7); + printk(" r8 = %8x r9 = %8x r10 = %8x\n\r", + ctx->register_r8, ctx->register_r9, ctx->register_r10); + printk(" fp = %8x ip = %8x sp = %8x pc = %8x\n\r", + ctx->register_fp, ctx->register_ip, + ctx->register_sp, ctx->register_lr - 4); + printk("----------------------------------------------------------\n\r"); +#endif + if (_ISR_Nest_level > 0) { + /* + * In this case we shall not delete the task interrupted as + * it has nothing to do with the fault. We cannot return either + * because the eip points to the faulty instruction so... + */ + printk("Exception while executing ISR!!!. System locked\n\r"); + while(1); + } + else { + printk("*********** FAULTY THREAD WILL BE DELETED **************\n\r"); + rtems_task_delete(_Thread_Executing->Object.id); + } +} + +typedef void (*cpuExcHandlerType) (CPU_Exception_frame*); + +cpuExcHandlerType _currentExcHandler = _defaultExcHandler; + +extern void _Exception_Handler_Undef_Swi(void); +extern void _Exception_Handler_Abort(void); +extern void _exc_data_abort(void); + + + +/* FIXME: put comments here */ +void rtems_exception_init_mngt(void) +{ + ISR_Level level; + + _CPU_ISR_Disable(level); + _CPU_ISR_install_vector(ARM_EXCEPTION_UNDEF, + _Exception_Handler_Undef_Swi, + NULL); + + _CPU_ISR_install_vector(ARM_EXCEPTION_SWI, + _Exception_Handler_Undef_Swi, + NULL); + + _CPU_ISR_install_vector(ARM_EXCEPTION_PREF_ABORT, + _Exception_Handler_Abort, + NULL); + + _CPU_ISR_install_vector(ARM_EXCEPTION_DATA_ABORT, + _exc_data_abort, + NULL); + + _CPU_ISR_install_vector(ARM_EXCEPTION_FIQ, + _Exception_Handler_Abort, + NULL); + + _CPU_ISR_install_vector(ARM_EXCEPTION_IRQ, + _Exception_Handler_Abort, + NULL); + + _CPU_ISR_Enable(level); +} diff --git a/cpukit/score/cpu/arm/arm_exc_handler_low.S b/cpukit/score/cpu/arm/arm_exc_handler_low.S new file mode 100644 index 0000000000..b333ef5d6a --- /dev/null +++ b/cpukit/score/cpu/arm/arm_exc_handler_low.S @@ -0,0 +1,176 @@ +/** + * @file + * + * ARM exception support code. + */ + +/* + * $Id$ + * + * Copyright (c) 2007 by Ray Xu, <Rayx.cn@gmail.com> + * Thumb support added. + * + * Copyright (c) 2002 by Advent Networks, Inc. + * Jay Monkman <jmonkman@adventnetworks.com> + * + * COPYRIGHT (c) 2000 Canon Research Centre France SA. + * Emmanuel Raguet, mailto:raguet@crf.canon.fr + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * Moved from file 'cpukit/score/cpu/arm/cpu_asm.S'. + * + */ + +#include <rtems/asm.h> +#include <rtems/score/cpu_asm.h> + +/* + * function declaration macro (start body in ARM mode) + */ +#ifdef __thumb__ + #define FUNC_START_ARM(_name_) \ + .code 16 ;\ + .thumb_func ;\ + .globl _name_ ;\ +_name_: ;\ + bx pc ;\ + .code 32 ;\ +_name_ ## _ARM: +#else + #define FUNC_START_ARM(_name_) \ + .globl _name_; \ +_name_: +#endif + + .text + +/* FIXME: _Exception_Handler_Undef_Swi is untested */ +FUNC_START_ARM(_Exception_Handler_Undef_Swi) +/* FIXME: This should use load and store multiple instructions */ + sub r13,r13,#SIZE_REGS + str r4, [r13, #REG_R4] + str r5, [r13, #REG_R5] + str r6, [r13, #REG_R6] + str r7, [r13, #REG_R7] + str r8, [r13, #REG_R8] + str r9, [r13, #REG_R9] + str r10, [r13, #REG_R10] + str r11, [r13, #REG_R11] + str sp, [r13, #REG_SP] + str lr, [r13, #REG_LR] + mrs r0, cpsr /* read the status */ + and r0, r0,#0x1f /* we keep the mode as exception number */ + str r0, [r13, #REG_PC] /* we store it in a free place */ + mov r0, r13 /* put frame address in r0 (C arg 1) */ + + ldr r1, =SWI_Handler + ldr lr, =_go_back_1 + ldr pc,[r1] /* call handler */ +_go_back_1: + ldr r4, [r13, #REG_R4] + ldr r5, [r13, #REG_R5] + ldr r6, [r13, #REG_R6] + ldr r7, [r13, #REG_R7] + ldr r8, [r13, #REG_R8] + ldr r9, [r13, #REG_R9] + ldr r10, [r13, #REG_R10] + ldr r11, [r13, #REG_R11] + ldr sp, [r13, #REG_SP] + ldr lr, [r13, #REG_LR] + add r13,r13,#SIZE_REGS + movs pc,r14 /* return */ + +/* FIXME: _Exception_Handler_Abort is untested */ +FUNC_START_ARM(_Exception_Handler_Abort) +/* FIXME: This should use load and store multiple instructions */ + sub r13,r13,#SIZE_REGS + str r4, [r13, #REG_R4] + str r5, [r13, #REG_R5] + str r6, [r13, #REG_R6] + str r7, [r13, #REG_R7] + str r8, [r13, #REG_R8] + str r9, [r13, #REG_R9] + str sp, [r13, #REG_R11] + str lr, [r13, #REG_SP] + str lr, [r13, #REG_LR] + mrs r0, cpsr /* read the status */ + and r0, r0,#0x1f /* we keep the mode as exception number */ + str r0, [r13, #REG_PC] /* we store it in a free place */ + mov r0, r13 /* put frame address in ro (C arg 1) */ + + ldr r1, =_currentExcHandler + ldr lr, =_go_back_2 + ldr pc,[r1] /* call handler */ +_go_back_2: + ldr r4, [r13, #REG_R4] + ldr r5, [r13, #REG_R5] + ldr r6, [r13, #REG_R6] + ldr r7, [r13, #REG_R7] + ldr r8, [r13, #REG_R8] + ldr r9, [r13, #REG_R9] + ldr r10, [r13, #REG_R10] + ldr sp, [r13, #REG_R11] + ldr lr, [r13, #REG_SP] + ldr lr, [r13, #REG_LR] + add r13,r13,#SIZE_REGS +#ifdef __thumb__ + subs r11, r14,#4 + bx r11 + nop +#else + subs pc,r14,#4 /* return */ +#endif + +#define ABORT_REGS_OFFS 32-REG_R4 +#define ABORT_SIZE_REGS SIZE_REGS+ABORT_REGS_OFFS + +FUNC_START_ARM(_exc_data_abort) + sub sp, sp, #ABORT_SIZE_REGS /* reserve register frame */ + stmia sp, {r0-r11} + add sp, sp, #ABORT_REGS_OFFS /* the Context_Control structure starts by CPSR, R4, ... */ + + str ip, [sp, #REG_PC] /* store R12 (ip) somewhere, oh hackery, hackery, hack */ + str lr, [sp, #REG_LR] + + mov r1, lr + ldr r0, [r1, #-8] /* r0 = bad instruction */ + mrs r1, spsr /* r1 = spsr */ + mov r2, r13 /* r2 = exception frame of Context_Control type */ +#if defined(__thumb__) + .code 32 + /*arm to thumb*/ + adr r5, to_thumb + 1 + bx r5 + .code 16 +to_thumb: +#endif + bl do_data_abort +#if defined(__thumb__) +/*back to arm*/ + .code 16 +thumb_to_arm: + .align 2 + adr r5, arm_code + bx r5 + nop + .code 32 +arm_code: +#endif + + ldr lr, [sp, #REG_LR] + ldr ip, [sp, #REG_PC] /* restore R12 (ip) */ + + sub sp, sp, #ABORT_REGS_OFFS + ldmia sp, {r0-r11} + add sp, sp, #ABORT_SIZE_REGS +#ifdef __thumb__ + subs r11, r14, #4 /* return to the instruction */ + bx r11 + nop +#else + subs pc, r14, #4 +#endif + /* _AFTER_ the aborted one */ diff --git a/cpukit/score/cpu/arm/arm_exc_interrupt.S b/cpukit/score/cpu/arm/arm_exc_interrupt.S new file mode 100644 index 0000000000..7cfd56ff00 --- /dev/null +++ b/cpukit/score/cpu/arm/arm_exc_interrupt.S @@ -0,0 +1,229 @@ +/** + * @file + * + * @brief ARM interrupt exception prologue and epilogue. + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +/* + * These two non-volatile registers contain the program status for INT and SVC + * mode. It is important that they are directly accessible in THUMB + * instruction mode. + */ +#define MODE_INT r4 +#define MODE_SVC r5 + +/* + * These three non-volatile registers are used to exchange information between + * INT and SVC mode. + */ +#define SCRATCH_0 r6 +#define SCRATCH_1 r7 +#define SCRATCH_2 r8 + +/* List of scratch registers. They will be saved and restored in INT mode. */ +#define SCRATCH_LIST {SCRATCH_0, SCRATCH_1, SCRATCH_2} + +/* + * List of all volatile registers (r0, r1, r2, r3, r12 and lr), registers + * containing the interrupt context (return address in SCRATCH_0 and saved + * program status in SCRATCH_1) and non-volatile registers used for modes + * (MODE_INT and MODE_SVC). They will be saved and restored in SVC mode. + */ +#define TASK_CONTEXT_LIST \ + {r0, r1, r2, r3, MODE_INT, MODE_SVC, SCRATCH_0, SCRATCH_1, r12, lr} + +/* + * List of all volatile registers (r0, r1, r2, r3, r12 and lr) and the saved + * program status (SCRATCH_0 register). They will be saved and restored in INT + * mode. + */ +#define INTERRUPT_CONTEXT_LIST \ + {r0, r1, r2, r3, SCRATCH_0, r12, lr} + +.extern _ISR_Thread_dispatch +.extern _ISR_Nest_level +.extern _Thread_Dispatch_disable_level +.extern bsp_interrupt_dispatch + +.arm +.globl arm_exc_interrupt +arm_exc_interrupt: + + /* Save scratch registers on INT stack */ + stmdb sp!, SCRATCH_LIST + + /* Increment interrupt nest level */ + ldr SCRATCH_0, =_ISR_Nest_level + ldr SCRATCH_1, [SCRATCH_0] + add SCRATCH_2, SCRATCH_1, #1 + str SCRATCH_2, [SCRATCH_0] + + /* Branch for nested interrupts */ + cmp SCRATCH_1, #0 + bne nested_interrupt_context_save + + /* Move interrupt context and CPSR to scratch registers */ + mov SCRATCH_0, lr + mrs SCRATCH_1, spsr + mrs SCRATCH_2, cpsr + + /* Switch to SVC mode */ + orr SCRATCH_2, SCRATCH_2, #0x1 + msr cpsr_c, SCRATCH_2 + + /* Save context on SVC stack */ + stmdb sp!, TASK_CONTEXT_LIST + + /* Save SVC mode program status to non-volatile register */ + mov MODE_SVC, SCRATCH_2 + + /* Save INT mode program status to non-volatile register */ + bic MODE_INT, MODE_SVC, #0x1 + + /* Switch to INT mode */ + msr cpsr_c, MODE_INT + + /* Restore scratch registers from INT stack */ + ldmia sp!, SCRATCH_LIST + + /* + * At this point the INT stack is in the exception entry state and + * contains no data for us. The context is saved on the SVC stack. We + * can easily switch modes via the registers MODE_INT and MODE_SVC + * which are valid through subroutine calls. We can use all volatile + * registers in both modes. Note that this comment describes the non + * nested interrupt entry. For a nested interrupt things are + * different, since we can save everything on the INT stack and there + * is no need to switch modes. + */ + +task_context_save_done: + + /* Switch to THUMB instructions if necessary */ +#ifdef __thumb__ + add r0, pc, #1 + bx r0 +.thumb +#endif /* __thumb__ */ + + /* Increment thread dispatch disable level */ + ldr r1, =_Thread_Dispatch_disable_level + ldr r3, [r1] + add r3, r3, #1 + str r3, [r1] + + /* Call BSP dependent interrrupt dispatcher */ + bl bsp_interrupt_dispatch + + /* Decrement interrupt nest and thread dispatch disable level */ + ldr r0, =_ISR_Nest_level + ldr r1, =_Thread_Dispatch_disable_level + ldr r2, [r0] + ldr r3, [r1] + sub r2, r2, #1 + sub r3, r3, #1 + str r2, [r0] + str r3, [r1] + + /* Switch to ARM instructions if necessary */ +#ifdef __thumb__ +.align 2 + bx pc +.arm +#endif /* __thumb__ */ + + /* Branch if we have a nested interrupt */ + cmp r2, #0 + bne nested_interrupt_return + + /* Branch if thread dispatching is disabled */ + cmp r3, #0 + bne thread_dispatch_done + + /* + * Switch to SVC mode. It is important to call the thread dispatcher + * in SVC mode since overwise the INT stack may need to store an + * arbitrary number of contexts and it may lead to an invalid order of + * stack operations. + */ + msr cpsr_c, MODE_SVC + + /* Call thread dispatcher */ +#ifdef __thumb__ + ldr r0, =_ISR_Thread_dispatch + mov lr, pc + bx r0 +.thumb + bx pc + nop +.arm +#else + bl _ISR_Thread_dispatch +#endif + + /* Switch to INT mode */ + msr cpsr_c, MODE_INT + +thread_dispatch_done: + + /* Save scratch registers on INT stack */ + stmdb sp!, SCRATCH_LIST + + /* Switch to SVC mode */ + msr cpsr_c, MODE_SVC + + /* Move INT mode program status to scratch register */ + mov SCRATCH_2, MODE_INT + + /* Restore context from SVC stack */ + ldmia sp!, TASK_CONTEXT_LIST + + /* Switch to INT mode */ + msr cpsr_c, SCRATCH_2 + + /* Restore interrupt context */ + mov lr, SCRATCH_0 + msr spsr, SCRATCH_1 + + /* Restore scratch registers from INT stack */ + ldmia sp!, SCRATCH_LIST + + /* Return from interrupt */ + subs pc, lr, #4 + +nested_interrupt_context_save: + + /* Move saved program status register to scratch register */ + mrs SCRATCH_0, spsr + + /* Save context on INT stack */ + stmdb sp!, INTERRUPT_CONTEXT_LIST + + b task_context_save_done + +nested_interrupt_return: + + /* Restore context from INT stack */ + ldmia sp!, INTERRUPT_CONTEXT_LIST + + /* Restore saved program status register */ + msr spsr, SCRATCH_0 + + /* Restore scratch registers from INT stack */ + ldmia sp!, SCRATCH_LIST + + /* Return from interrupt */ + subs pc, lr, #4 |