Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsARMTMS570
0007  *
0008  * @brief This source file contains the interrupt controller support
0009  *   implementation.
0010  */
0011 
0012 /*
0013  * Copyright (C) 2014 Premysl Houdek <kom541000@gmail.com>
0014  *
0015  * Google Summer of Code 2014 at
0016  * Czech Technical University in Prague
0017  * Zikova 1903/4
0018  * 166 36 Praha 6
0019  * Czech Republic
0020  *
0021  * Redistribution and use in source and binary forms, with or without
0022  * modification, are permitted provided that the following conditions
0023  * are met:
0024  * 1. Redistributions of source code must retain the above copyright
0025  *    notice, this list of conditions and the following disclaimer.
0026  * 2. Redistributions in binary form must reproduce the above copyright
0027  *    notice, this list of conditions and the following disclaimer in the
0028  *    documentation and/or other materials provided with the distribution.
0029  *
0030  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0031  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0032  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0033  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0034  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0035  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0036  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0037  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0038  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0039  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0040  * POSSIBILITY OF SUCH DAMAGE.
0041  */
0042 
0043 #include <bsp.h>
0044 #include <bsp/irq-generic.h>
0045 #include <bsp/tms570.h>
0046 #include <bsp/irq.h>
0047 #include <rtems/score/armv4.h>
0048 
0049 #define VIM_CHANCTRL_COUNT 24
0050 #define VIM_CHANMAP_MASK UINT32_C(0x7f)
0051 #define VIM_CHANMAP_SHIFT(i) (24 - (8 * (i)))
0052 #define VIM_REQ_REG(vector) ((vector) >> 5)
0053 #define VIM_REQ_BIT(vector) (UINT32_C(1) << ((vector) & 0x1f))
0054 
0055 static void vim_set_channel_request(uint32_t channel, uint32_t request)
0056 {
0057   uint32_t chanctrl;
0058   int shift;
0059 
0060   chanctrl = TMS570_VIM.CHANCTRL[channel / 4];
0061   shift = VIM_CHANMAP_SHIFT(channel % 4);
0062   chanctrl &= ~(VIM_CHANMAP_MASK << shift);
0063   chanctrl |= request << shift;
0064   TMS570_VIM.CHANCTRL[channel / 4] = chanctrl;
0065 }
0066 
0067 rtems_status_code tms570_irq_set_priority(
0068   rtems_vector_number vector,
0069   uint32_t            priority
0070 )
0071 {
0072   rtems_interrupt_level level;
0073   uint32_t current_channel;
0074   uint32_t chanctrl;
0075   size_t i;
0076   size_t j;
0077 
0078   if (!bsp_interrupt_is_valid_vector(vector)) {
0079    return RTEMS_INVALID_ID;
0080   }
0081 
0082   if (priority < 2) {
0083     return RTEMS_INVALID_PRIORITY;
0084   }
0085 
0086   if (priority >= BSP_INTERRUPT_VECTOR_COUNT) {
0087     return RTEMS_INVALID_PRIORITY;
0088   }
0089 
0090   rtems_interrupt_disable(level);
0091   current_channel = TMS570_VIM.CHANCTRL[priority / 4];
0092   current_channel >>= VIM_CHANMAP_SHIFT(priority % 4);
0093   current_channel &= VIM_CHANMAP_MASK;
0094 
0095   for (i = 0; i < VIM_CHANCTRL_COUNT; ++i) {
0096     chanctrl = TMS570_VIM.CHANCTRL[i];
0097 
0098     for (j = 0; j < 4; ++j) {
0099       uint32_t channel_vector;
0100 
0101       channel_vector = (chanctrl >> VIM_CHANMAP_SHIFT(j)) & VIM_CHANMAP_MASK;
0102 
0103       if (channel_vector == vector) {
0104         vim_set_channel_request(i * 4 + j, current_channel);
0105         goto set_my_request;
0106       }
0107     }
0108   }
0109 
0110 set_my_request:
0111 
0112   vim_set_channel_request(priority, vector);
0113   rtems_interrupt_enable(level);
0114   return RTEMS_SUCCESSFUL;
0115 }
0116 
0117 rtems_status_code tms570_irq_get_priority(
0118   rtems_vector_number  vector,
0119   unsigned            *priority
0120 )
0121 {
0122   rtems_interrupt_level level;
0123   size_t i;
0124   size_t j;
0125 
0126   if (priority == NULL) {
0127     return RTEMS_INVALID_ADDRESS;
0128   }
0129 
0130   if (!bsp_interrupt_is_valid_vector(vector)) {
0131    return RTEMS_INVALID_ID;
0132   }
0133 
0134   rtems_interrupt_disable(level);
0135 
0136   for (i = 0; i < VIM_CHANCTRL_COUNT; ++i) {
0137     uint32_t chanctrl;
0138 
0139     chanctrl = TMS570_VIM.CHANCTRL[i];
0140 
0141     for (j = 0; j < 4; ++j) {
0142       uint32_t channel_vector;
0143 
0144       channel_vector = (chanctrl >> VIM_CHANMAP_SHIFT(j)) & VIM_CHANMAP_MASK;
0145 
0146       if (channel_vector == vector) {
0147         rtems_interrupt_enable(level);
0148         *priority = i * 4 + j;
0149         return RTEMS_SUCCESSFUL;
0150       }
0151     }
0152   }
0153 
0154   rtems_interrupt_enable(level);
0155   *priority = UINT32_MAX;
0156   return RTEMS_NOT_DEFINED;
0157 }
0158 
0159 /**
0160  * @brief Interrupt dispatch
0161  *
0162  * Called by OS to determine which interrupt occured.
0163  * Function passes control to interrupt handler.
0164  *
0165  * @return Void
0166  */
0167 void bsp_interrupt_dispatch(void)
0168 {
0169   while (true) {
0170     uint32_t irqindex;
0171 
0172     irqindex = TMS570_VIM.IRQINDEX;
0173 
0174     if (irqindex == 0) {
0175       return;
0176     }
0177 
0178     bsp_interrupt_handler_dispatch(irqindex - 1);
0179   }
0180 }
0181 
0182 static bool can_disable(rtems_vector_number vector)
0183 {
0184   /* INT_REQ0 and INT_REQ1 are always enabled as FIQ/NMI */
0185   return vector >= 2;
0186 }
0187 
0188 /**
0189  * @brief enables interrupt vector in the HW
0190  *
0191  * Enables HW interrupt for specified vector
0192  *
0193  * @param[in] vector vector of the isr which needs to be enabled.
0194  * @retval RTEMS_INVALID_ID vector is invalid.
0195  * @retval RTEMS_SUCCESSFUL interrupt source enabled.
0196  */
0197 rtems_status_code bsp_interrupt_get_attributes(
0198   rtems_vector_number         vector,
0199   rtems_interrupt_attributes *attributes
0200 )
0201 {
0202   bool can_disable_vector;
0203 
0204   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0205   bsp_interrupt_assert(attributes != NULL);
0206 
0207   can_disable_vector = can_disable(vector);
0208   attributes->is_maskable = can_disable_vector;
0209   attributes->can_enable = true;
0210   attributes->maybe_enable = true;
0211   attributes->can_disable = can_disable_vector;
0212   attributes->maybe_disable = can_disable_vector;
0213   attributes->can_get_affinity = true;
0214   attributes->can_set_affinity = true;
0215 
0216   return RTEMS_SUCCESSFUL;
0217 }
0218 
0219 rtems_status_code bsp_interrupt_is_pending(
0220   rtems_vector_number vector,
0221   bool               *pending
0222 )
0223 {
0224   uint32_t intreq;
0225 
0226   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0227   bsp_interrupt_assert(pending != NULL);
0228 
0229   intreq = TMS570_VIM.INTREQ[VIM_REQ_REG(vector)];
0230   *pending = (intreq & VIM_REQ_BIT(vector)) != 0;
0231   return RTEMS_SUCCESSFUL;
0232 }
0233 
0234 rtems_status_code bsp_interrupt_raise(rtems_vector_number vector)
0235 {
0236   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0237   return RTEMS_UNSATISFIED;
0238 }
0239 
0240 rtems_status_code bsp_interrupt_clear(rtems_vector_number vector)
0241 {
0242   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0243   return RTEMS_UNSATISFIED;
0244 }
0245 
0246 rtems_status_code bsp_interrupt_vector_is_enabled(
0247   rtems_vector_number vector,
0248   bool               *enabled
0249 )
0250 {
0251   uint32_t reqen;
0252 
0253   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0254   bsp_interrupt_assert(enabled != NULL);
0255 
0256   reqen = TMS570_VIM.REQENASET[VIM_REQ_REG(vector)];
0257   *enabled = (reqen & VIM_REQ_BIT(vector)) != 0;
0258   return RTEMS_SUCCESSFUL;
0259 }
0260 
0261 rtems_status_code bsp_interrupt_vector_enable(
0262   rtems_vector_number vector
0263 )
0264 {
0265   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0266   TMS570_VIM.REQENASET[VIM_REQ_REG(vector)] = VIM_REQ_BIT(vector);
0267   return RTEMS_SUCCESSFUL;
0268 }
0269 
0270 /**
0271  * @brief disables interrupt vector in the HW
0272  *
0273  * Disables HW interrupt for specified vector
0274  *
0275  * @param[in] vector vector of the isr which needs to be disabled.
0276  * @retval RTEMS_INVALID_ID vector is invalid.
0277  * @retval RTEMS_SUCCESSFUL interrupt source disabled.
0278  */
0279 rtems_status_code bsp_interrupt_vector_disable(
0280   rtems_vector_number vector
0281 )
0282 {
0283   if (!can_disable(vector)) {
0284     return RTEMS_UNSATISFIED;
0285   }
0286 
0287   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0288   TMS570_VIM.REQENACLR[VIM_REQ_REG(vector)] = VIM_REQ_BIT(vector);
0289   return RTEMS_SUCCESSFUL;
0290 }
0291 
0292 rtems_status_code bsp_interrupt_set_priority(
0293   rtems_vector_number vector,
0294   uint32_t priority
0295 )
0296 {
0297   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0298   return RTEMS_UNSATISFIED;
0299 }
0300 
0301 rtems_status_code bsp_interrupt_get_priority(
0302   rtems_vector_number vector,
0303   uint32_t *priority
0304 )
0305 {
0306   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0307   bsp_interrupt_assert(priority != NULL);
0308   return RTEMS_UNSATISFIED;
0309 }
0310 
0311 /**
0312  * @brief Init function of interrupt module
0313  *
0314  * Resets vectored interrupt interface to default state.
0315  * Disables all interrupts.
0316  * Set all sources as IRQ (not FIR).
0317  *
0318  * @retval RTEMS_SUCCESSFUL All is set
0319  */
0320 void bsp_interrupt_facility_initialize(void)
0321 {
0322   void (**vim_vec)(void) = (void (**)(void)) 0xFFF82000;
0323   unsigned int value = 0x00010203;
0324   unsigned int i = 0;
0325   uint32_t sctlr;
0326 
0327   /* Disable interrupts */
0328   for ( i = 0; i < 3; i++ ) {
0329     TMS570_VIM.REQENACLR[i] = 0xffffffff;
0330   }
0331   /* Map default events on interrupt vectors */
0332   for ( i = 0; i < VIM_CHANCTRL_COUNT; i += 1, value += 0x04040404) {
0333     TMS570_VIM.CHANCTRL[i] = value;
0334   }
0335   /* Set all vectors as IRQ (not FIR) */
0336   TMS570_VIM.FIRQPR[0] = 3;
0337   TMS570_VIM.FIRQPR[1] = 0;
0338   TMS570_VIM.FIRQPR[2] = 0;
0339 
0340   /*
0341     _CPU_ISR_install_vector(
0342         ARM_EXCEPTION_IRQ,
0343         _ARMV4_Exception_interrupt,
0344         NULL
0345     );
0346 
0347     Call to setup of interrupt entry in CPU level exception vectors table
0348     is not used (necessary/possible) because the table is provided
0349     by c/src/lib/libbsp/arm/shared/start/start.S and POM overlay
0350     solution remaps that to address zero.
0351   */
0352 
0353   for ( i = 0; i <= 94; ++i ) {
0354     vim_vec[i] = _ARMV4_Exception_interrupt;
0355   }
0356   /* Clear bit VE in SCTLR register to not use VIM IRQ exception bypass*/
0357   asm volatile ("mrc p15, 0, %0, c1, c0, 0\n": "=r" (sctlr));
0358   /*
0359    * Disable bypass of CPU level exception table for interrupt entry which
0360    * can be provided by VIM hardware
0361    */
0362   sctlr &= ~(1 << 24);
0363   #if 0
0364     /*
0365      * Option to enable exception table bypass for interrupts
0366      *
0367      * Because RTEMS requires all interrupts to be serviced through
0368      * common _ARMV4_Exception_interrupt handler to allow task switching
0369      * on exit from interrupt working correctly, vim_vec cannot point
0370      * directly to individual vector handlers and need to point
0371      * to single entry path. But if TMS570_VIM.IRQINDEX is then used
0372      * to target execution to corresponding service then for some
0373      * peripherals (i.e. EMAC) interrupt is already acknowledged
0374      * by VIM and IRQINDEX is read as zero which leads to spurious
0375      * interrupt and peripheral not serviced/blocked.
0376      *
0377      * To analyze this behavior we used trampolines which setup
0378      * bsp_interrupt_vector_inject and pass execution to
0379      * _ARMV4_Exception_interrupt. It works but is more ugly than
0380      * use of POM remap for these cases where application does not
0381      * start at address 0x00000000. If RTEMS image is placed at
0382      * memory space beginning then no of these constructs is necessary.
0383      */
0384     sctlr |= 1 << 24;
0385   #endif
0386   asm volatile ("mcr p15, 0, %0, c1, c0, 0\n": : "r" (sctlr));
0387 }