Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:04

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup lpc32xx_interrupt
0007  *
0008  * @brief Interrupt support.
0009  */
0010 
0011 /*
0012  * Copyright (C) 2009, 2022 embedded brains GmbH & Co. KG
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #include <rtems/score/armv4.h>
0037 
0038 #include <bsp.h>
0039 #include <bsp/irq.h>
0040 #include <bsp/irq-generic.h>
0041 #include <bsp/lpc32xx.h>
0042 #include <bsp/linker-symbols.h>
0043 #include <bsp/mmu.h>
0044 
0045 /* Mask out SIC 1 and 2 IRQ/FIQ requests */
0046 #define LPC32XX_MIC_STATUS_MASK 0x3ffffffcU
0047 
0048 typedef union {
0049   struct {
0050     uint32_t mic;
0051     uint32_t sic_1;
0052     uint32_t sic_2;
0053   } field;
0054   uint32_t fields_table [LPC32XX_IRQ_MODULE_COUNT];
0055 } lpc32xx_irq_fields;
0056 
0057 static uint8_t lpc32xx_irq_priority_table [LPC32XX_IRQ_COUNT];
0058 
0059 static lpc32xx_irq_fields lpc32xx_irq_priority_masks [LPC32XX_IRQ_PRIORITY_COUNT];
0060 
0061 static lpc32xx_irq_fields lpc32xx_irq_enable;
0062 
0063 static const lpc32xx_irq_fields lpc32xx_irq_is_valid = {
0064   .field = {
0065     .mic = 0x3fffeff8U,
0066     .sic_1 = 0xffde71d6U,
0067     .sic_2 = 0x9fdc9fffU
0068   }
0069 };
0070 
0071 static inline bool lpc32xx_irq_priority_is_valid(unsigned priority)
0072 {
0073   return priority <= LPC32XX_IRQ_PRIORITY_LOWEST;
0074 }
0075 
0076 #define LPC32XX_IRQ_BIT_OPS_DEFINE \
0077   unsigned bit = index & 0x1fU; \
0078   unsigned module = index >> 5
0079 
0080 #define LPC32XX_IRQ_BIT_OPS_FOR_REG_DEFINE \
0081   LPC32XX_IRQ_BIT_OPS_DEFINE; \
0082   unsigned module_offset = module << 14; \
0083   volatile uint32_t *reg = (volatile uint32_t *) \
0084     ((volatile char *) &lpc32xx.mic + module_offset + register_offset)
0085 
0086 #define LPC32XX_IRQ_OFFSET_ER 0U
0087 #define LPC32XX_IRQ_OFFSET_RSR 4U
0088 #define LPC32XX_IRQ_OFFSET_SR 8U
0089 #define LPC32XX_IRQ_OFFSET_APR 12U
0090 #define LPC32XX_IRQ_OFFSET_ATR 16U
0091 #define LPC32XX_IRQ_OFFSET_ITR 20U
0092 
0093 static inline bool lpc32xx_irq_is_bit_set_in_register(unsigned index, unsigned register_offset)
0094 {
0095   LPC32XX_IRQ_BIT_OPS_FOR_REG_DEFINE;
0096 
0097   return *reg & (1U << bit);
0098 }
0099 
0100 static inline void lpc32xx_irq_set_bit_in_register(unsigned index, unsigned register_offset)
0101 {
0102   LPC32XX_IRQ_BIT_OPS_FOR_REG_DEFINE;
0103 
0104   *reg |= 1U << bit;
0105 }
0106 
0107 static inline void lpc32xx_irq_clear_bit_in_register(unsigned index, unsigned register_offset)
0108 {
0109   LPC32XX_IRQ_BIT_OPS_FOR_REG_DEFINE;
0110 
0111   *reg &= ~(1U << bit);
0112 }
0113 
0114 static inline bool lpc32xx_irq_is_bit_set_in_field(
0115   unsigned index,
0116   const lpc32xx_irq_fields *fields
0117 )
0118 {
0119   LPC32XX_IRQ_BIT_OPS_DEFINE;
0120 
0121   return fields->fields_table [module] & (1U << bit);
0122 }
0123 
0124 static inline void lpc32xx_irq_set_bit_in_field(unsigned index, lpc32xx_irq_fields *fields)
0125 {
0126   LPC32XX_IRQ_BIT_OPS_DEFINE;
0127 
0128   fields->fields_table [module] |= 1U << bit;
0129 }
0130 
0131 static inline void lpc32xx_irq_clear_bit_in_field(unsigned index, lpc32xx_irq_fields *fields)
0132 {
0133   LPC32XX_IRQ_BIT_OPS_DEFINE;
0134 
0135   fields->fields_table [module] &= ~(1U << bit);
0136 }
0137 
0138 bool bsp_interrupt_is_valid_vector(rtems_vector_number vector)
0139 {
0140   if (vector >= BSP_INTERRUPT_VECTOR_COUNT) {
0141     return false;
0142   }
0143 
0144   return lpc32xx_irq_is_bit_set_in_field(vector, &lpc32xx_irq_is_valid);
0145 }
0146 
0147 static inline unsigned lpc32xx_irq_get_index(uint32_t val)
0148 {
0149   ARM_SWITCH_REGISTERS;
0150 
0151   __asm__ volatile (
0152     ARM_SWITCH_TO_ARM
0153     "clz %[val], %[val]\n"
0154     "rsb %[val], %[val], #31\n"
0155     ARM_SWITCH_BACK
0156     : [val] "=r" (val) ARM_SWITCH_ADDITIONAL_OUTPUT
0157     : "[val]" (val)
0158   );
0159 
0160   return val;
0161 }
0162 
0163 rtems_status_code bsp_interrupt_set_priority(
0164   rtems_vector_number vector,
0165   uint32_t priority
0166 )
0167 {
0168   rtems_interrupt_level level;
0169   uint32_t i;
0170 
0171   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0172 
0173   if (priority > LPC32XX_IRQ_PRIORITY_VALUE_MAX) {
0174     return RTEMS_INVALID_PRIORITY;
0175   }
0176 
0177   rtems_interrupt_disable(level);
0178   lpc32xx_irq_priority_table [vector] = (uint8_t) priority;
0179 
0180   for (i = LPC32XX_IRQ_PRIORITY_HIGHEST; i <= priority; ++i) {
0181     lpc32xx_irq_clear_bit_in_field(vector, &lpc32xx_irq_priority_masks [i]);
0182   }
0183 
0184   for (i = priority + 1; i <= LPC32XX_IRQ_PRIORITY_LOWEST; ++i) {
0185     lpc32xx_irq_set_bit_in_field(vector, &lpc32xx_irq_priority_masks [i]);
0186   }
0187 
0188   rtems_interrupt_enable(level);
0189   return RTEMS_SUCCESSFUL;
0190 }
0191 
0192 rtems_status_code bsp_interrupt_get_priority(
0193   rtems_vector_number vector,
0194   uint32_t *priority
0195 )
0196 {
0197   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0198   bsp_interrupt_assert(priority != NULL);
0199   *priority = lpc32xx_irq_priority_table [vector];
0200   return RTEMS_SUCCESSFUL;
0201 }
0202 
0203 void lpc32xx_irq_set_activation_polarity(rtems_vector_number vector, lpc32xx_irq_activation_polarity activation_polarity)
0204 {
0205   if (bsp_interrupt_is_valid_vector(vector)) {
0206     rtems_interrupt_level level;
0207 
0208     rtems_interrupt_disable(level);
0209     if (activation_polarity == LPC32XX_IRQ_ACTIVE_HIGH_OR_RISING_EDGE) {
0210       lpc32xx_irq_set_bit_in_register(vector, LPC32XX_IRQ_OFFSET_APR);
0211     } else {
0212       lpc32xx_irq_clear_bit_in_register(vector, LPC32XX_IRQ_OFFSET_APR);
0213     }
0214     rtems_interrupt_enable(level);
0215   }
0216 }
0217 
0218 lpc32xx_irq_activation_polarity lpc32xx_irq_get_activation_polarity(rtems_vector_number vector)
0219 {
0220   if (bsp_interrupt_is_valid_vector(vector)) {
0221     if (lpc32xx_irq_is_bit_set_in_register(vector, LPC32XX_IRQ_OFFSET_APR)) {
0222       return LPC32XX_IRQ_ACTIVE_HIGH_OR_RISING_EDGE;
0223     } else {
0224       return LPC32XX_IRQ_ACTIVE_LOW_OR_FALLING_EDGE;
0225     }
0226   } else {
0227     return LPC32XX_IRQ_ACTIVE_LOW_OR_FALLING_EDGE;
0228   }
0229 }
0230 
0231 void lpc32xx_irq_set_activation_type(rtems_vector_number vector, lpc32xx_irq_activation_type activation_type)
0232 {
0233   if (bsp_interrupt_is_valid_vector(vector)) {
0234     rtems_interrupt_level level;
0235 
0236     rtems_interrupt_disable(level);
0237     if (activation_type == LPC32XX_IRQ_EDGE_SENSITIVE) {
0238       lpc32xx_irq_set_bit_in_register(vector, LPC32XX_IRQ_OFFSET_ATR);
0239     } else {
0240       lpc32xx_irq_clear_bit_in_register(vector, LPC32XX_IRQ_OFFSET_ATR);
0241     }
0242     rtems_interrupt_enable(level);
0243   }
0244 }
0245 
0246 lpc32xx_irq_activation_type lpc32xx_irq_get_activation_type(rtems_vector_number vector)
0247 {
0248   if (bsp_interrupt_is_valid_vector(vector)) {
0249     if (lpc32xx_irq_is_bit_set_in_register(vector, LPC32XX_IRQ_OFFSET_ATR)) {
0250       return LPC32XX_IRQ_EDGE_SENSITIVE;
0251     } else {
0252       return LPC32XX_IRQ_LEVEL_SENSITIVE;
0253     }
0254   } else {
0255     return LPC32XX_IRQ_LEVEL_SENSITIVE;
0256   }
0257 }
0258 
0259 void bsp_interrupt_dispatch(void)
0260 {
0261   /*
0262    * Do not dispatch interrupts configured as FIQ.  Use the corresponding
0263    * interrupt type register to mask these interrupts.  The status register may
0264    * indicate an interrupt configured for FIQ before the FIQ exception is
0265    * serviced by the processor.
0266    */
0267   uint32_t status = (lpc32xx.mic.sr & ~lpc32xx.mic.itr) &
0268     LPC32XX_MIC_STATUS_MASK;
0269   uint32_t er_mic = lpc32xx.mic.er;
0270   uint32_t er_sic_1 = lpc32xx.sic_1.er;
0271   uint32_t er_sic_2 = lpc32xx.sic_2.er;
0272   uint32_t psr = 0;
0273   lpc32xx_irq_fields *masks = NULL;
0274   rtems_vector_number vector = 0;
0275   unsigned priority = 0;
0276 
0277   if (status != 0) {
0278     vector = lpc32xx_irq_get_index(status);
0279   } else {
0280     status = lpc32xx.sic_1.sr & ~lpc32xx.sic_1.itr;
0281     if (status != 0) {
0282       vector = lpc32xx_irq_get_index(status) + LPC32XX_IRQ_MODULE_SIC_1;
0283     } else {
0284       status = lpc32xx.sic_2.sr & ~lpc32xx.sic_2.itr;
0285       if (status != 0) {
0286         vector = lpc32xx_irq_get_index(status) + LPC32XX_IRQ_MODULE_SIC_2;
0287       } else {
0288         return;
0289       }
0290     }
0291   }
0292 
0293   priority = lpc32xx_irq_priority_table [vector];
0294 
0295   masks = &lpc32xx_irq_priority_masks [priority];
0296 
0297   lpc32xx.mic.er = er_mic & masks->field.mic;
0298   lpc32xx.sic_1.er = er_sic_1 & masks->field.sic_1;
0299   lpc32xx.sic_2.er = er_sic_2 & masks->field.sic_2;
0300 
0301   psr = _ARMV4_Status_irq_enable();
0302 
0303   bsp_interrupt_handler_dispatch(vector);
0304 
0305   _ARMV4_Status_restore(psr);
0306 
0307   lpc32xx.mic.er = er_mic & lpc32xx_irq_enable.field.mic;
0308   lpc32xx.sic_1.er = er_sic_1 & lpc32xx_irq_enable.field.sic_1;
0309   lpc32xx.sic_2.er = er_sic_2 & lpc32xx_irq_enable.field.sic_2;
0310 }
0311 
0312 rtems_status_code bsp_interrupt_get_attributes(
0313   rtems_vector_number         vector,
0314   rtems_interrupt_attributes *attributes
0315 )
0316 {
0317   bool is_sw_irq;
0318 
0319   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0320   bsp_interrupt_assert(attributes != NULL);
0321 
0322   attributes->is_maskable =
0323     !lpc32xx_irq_is_bit_set_in_register(vector, LPC32XX_IRQ_OFFSET_ITR);
0324   attributes->can_enable = true;
0325   attributes->maybe_enable = true;
0326   attributes->can_disable = true;
0327   attributes->maybe_disable = true;
0328   is_sw_irq = vector == LPC32XX_IRQ_SW;
0329   attributes->can_raise = is_sw_irq;
0330   attributes->can_raise_on = is_sw_irq;
0331   attributes->can_clear = is_sw_irq;
0332   attributes->can_get_affinity = true;
0333   attributes->can_set_affinity = true;
0334   attributes->maximum_priority = LPC32XX_IRQ_PRIORITY_VALUE_MAX;
0335   attributes->can_get_priority = true;
0336   attributes->can_set_priority = true;
0337 
0338   return RTEMS_SUCCESSFUL;
0339 }
0340 
0341 rtems_status_code bsp_interrupt_is_pending(
0342   rtems_vector_number vector,
0343   bool               *pending
0344 )
0345 {
0346   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0347   bsp_interrupt_assert(pending != NULL);
0348 
0349   *pending = lpc32xx_irq_is_bit_set_in_register(vector, LPC32XX_IRQ_OFFSET_RSR);
0350 
0351   return RTEMS_SUCCESSFUL;
0352 }
0353 
0354 rtems_status_code bsp_interrupt_raise(rtems_vector_number vector)
0355 {
0356   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0357 
0358   if (vector != LPC32XX_IRQ_SW) {
0359     return RTEMS_UNSATISFIED;
0360   }
0361 
0362   LPC32XX_SW_INT = 0x1;
0363 
0364   return RTEMS_SUCCESSFUL;
0365 }
0366 
0367 rtems_status_code bsp_interrupt_clear(rtems_vector_number vector)
0368 {
0369   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0370 
0371   if (vector != LPC32XX_IRQ_SW) {
0372     return RTEMS_UNSATISFIED;
0373   }
0374 
0375   LPC32XX_SW_INT = 0x0;
0376 
0377   return RTEMS_SUCCESSFUL;
0378 }
0379 
0380 rtems_status_code bsp_interrupt_vector_is_enabled(
0381   rtems_vector_number vector,
0382   bool               *enabled
0383 )
0384 {
0385   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0386   bsp_interrupt_assert(enabled != NULL);
0387 
0388   *enabled = lpc32xx_irq_is_bit_set_in_field(vector, &lpc32xx_irq_enable);
0389 
0390   return RTEMS_SUCCESSFUL;
0391 }
0392 
0393 rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector)
0394 {
0395   rtems_interrupt_level level;
0396 
0397   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0398 
0399   rtems_interrupt_disable(level);
0400 
0401   if (!lpc32xx_irq_is_bit_set_in_field(vector, &lpc32xx_irq_enable)) {
0402     lpc32xx_irq_set_bit_in_field(vector, &lpc32xx_irq_enable);
0403     lpc32xx_irq_set_bit_in_register(vector, LPC32XX_IRQ_OFFSET_ER);
0404   }
0405 
0406   rtems_interrupt_enable(level);
0407 
0408   return RTEMS_SUCCESSFUL;
0409 }
0410 
0411 rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector)
0412 {
0413   rtems_interrupt_level level;
0414 
0415   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0416 
0417   rtems_interrupt_disable(level);
0418   lpc32xx_irq_clear_bit_in_field(vector, &lpc32xx_irq_enable);
0419   lpc32xx_irq_clear_bit_in_register(vector, LPC32XX_IRQ_OFFSET_ER);
0420   rtems_interrupt_enable(level);
0421 
0422   return RTEMS_SUCCESSFUL;
0423 }
0424 
0425 void lpc32xx_set_exception_handler(
0426   Arm_symbolic_exception_name exception,
0427   void (*handler)(void)
0428 )
0429 {
0430   if ((unsigned) exception < MAX_EXCEPTIONS) {
0431     uint32_t *table = (uint32_t *) bsp_vector_table_begin + MAX_EXCEPTIONS;
0432 
0433     table [exception] = (uint32_t) handler;
0434 
0435     #ifndef LPC32XX_DISABLE_MMU
0436       rtems_cache_flush_multiple_data_lines(table, 64);
0437       rtems_cache_invalidate_multiple_instruction_lines(NULL, 64);
0438     #endif
0439   }
0440 }
0441 
0442 void bsp_interrupt_facility_initialize(void)
0443 {
0444   size_t i = 0;
0445 
0446   /* Set default priority */
0447   for (i = 0; i < LPC32XX_IRQ_COUNT; ++i) {
0448     lpc32xx_irq_priority_table [i] = LPC32XX_IRQ_PRIORITY_LOWEST;
0449   }
0450 
0451   /* Enable SIC 1 and 2 at all priorities */
0452   for (i = 0; i < LPC32XX_IRQ_PRIORITY_COUNT; ++i) {
0453     lpc32xx_irq_priority_masks [i].field.mic = 0xc0000003;
0454   }
0455 
0456   /* Disable all interrupts except SIC 1 and 2 */
0457   lpc32xx_irq_enable.field.sic_2 = 0x0;
0458   lpc32xx_irq_enable.field.sic_1 = 0x0;
0459   lpc32xx_irq_enable.field.mic = 0xc0000003;
0460   lpc32xx.sic_1.er = 0x0;
0461   lpc32xx.sic_2.er = 0x0;
0462   lpc32xx.mic.er = 0xc0000003;
0463 
0464   /* Set interrupt types to IRQ */
0465   lpc32xx.mic.itr = 0x0;
0466   lpc32xx.sic_1.itr = 0x0;
0467   lpc32xx.sic_2.itr = 0x0;
0468 
0469   /* Set interrupt activation polarities */
0470   lpc32xx.mic.apr = 0x3ff0efe0;
0471   lpc32xx.sic_1.apr = 0xfbd27184;
0472   lpc32xx.sic_2.apr = 0x801810c0;
0473 
0474   /* Set interrupt activation types */
0475   lpc32xx.mic.atr = 0x0;
0476   lpc32xx.sic_1.atr = 0x26000;
0477   lpc32xx.sic_2.atr = 0x0;
0478 
0479   lpc32xx_set_exception_handler(ARM_EXCEPTION_IRQ, _ARMV4_Exception_interrupt);
0480 }