Back to home page

LXR

 
 

    


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

0001 /**
0002  *@file
0003  *
0004  *@brief
0005  * - This file implements interrupt dispatcher. Most of the code is taken from
0006  *  the 533 implementation for blackfin. Since 52X supports 56 line and 2 ISR
0007  *  registers some portion is written twice.
0008  *
0009  * Target:   TLL6527v1-0
0010  * Compiler:
0011  *
0012  * COPYRIGHT (c) 2010 by ECE Northeastern University.
0013  *
0014  * The license and distribution terms for this file may be
0015  * found in the file LICENSE in this distribution or at
0016  * http://www.rtems.org/license
0017  *
0018  * @author Rohan Kangralkar, ECE, Northeastern University
0019  *         (kangralkar.r@husky.neu.edu)
0020  *
0021  * LastChange:
0022  */
0023 
0024 #include <rtems.h>
0025 #include <rtems/libio.h>
0026 
0027 #include <bsp.h>
0028 #include <libcpu/cecRegs.h>
0029 #include <libcpu/sicRegs.h>
0030 #include <string.h>
0031 #include <bsp/interrupt.h>
0032 
0033 #define SIC_IAR_COUNT_SET0        4
0034 #define SIC_IAR_BASE_ADDRESS_0  0xFFC00150
0035 
0036 /**
0037  * There are two implementations for the interrupt handler.
0038  * 1. INTERRUPT_USE_TABLE: uses tables for finding the right ISR.
0039  * 2. Uses link list to find the user ISR.
0040  *
0041  *
0042  * 1. INTERRUPT_USE_TABLE
0043  * Space requirement:
0044  *  - Array to hold CEC masks size: CEC_INTERRUPT_COUNT(9)*(2*int).9*2*4= 72B
0045  *  - Array to hold isr function pointers IRQ_MAX(56)*sizeof(bfin_isr_t)= 896B
0046  *  - Array for bit twidlling 32 bytes.
0047  *  - Global Mask 8 bytes.
0048  *  - Total = 1008 Bytes Aprox
0049  *
0050  * Time requirements
0051  *    The worst case time is about the same for jumping to the user ISR. With a
0052  *    variance of one conditional statement.
0053  *
0054  * 2. Using link list.
0055  * Space requirement:
0056  *  - Array to hold CEC mask CEC_INTERRUPT_COUNT(9)*(sizeof(vectors)).
0057  *                                                                 9*3*4= 108B
0058  *  - Array to hold isr IRQ_MAX(56)*sizeof(bfin_isr_t) The structure has
0059  *    additional pointers                                         56*7*4=1568B
0060  *  - Global Mask 8 bytes.
0061  *    Total = 1684.
0062  * Time requirements
0063  *    In the worst case all the lines can be on one CEC line to 56 entries have
0064  *    to be traversed to find the right user ISR.
0065  *    But this implementation has benefit of being flexible, Providing
0066  *    additional user assigned priority. and may consume less space
0067  *    if all devices are not supported.
0068  */
0069 
0070 /**
0071  * TODO: To place the dispatcher routine code in L1.
0072  */
0073 
0074 #if INTERRUPT_USE_TABLE
0075 
0076 
0077 /******************************************************************************
0078  * Static variables
0079  *****************************************************************************/
0080 /**
0081  * @var sic_isr0_mask
0082  * @brief copy of the mask of SIC ISR. The SIC ISR is cleared by the device
0083  * the relevant SIC_ISRx bit is not cleared unless the interrupt
0084  * service routine clears the mechanism that generated interrupt
0085  */
0086 static uint32_t sic_isr0_mask = 0;
0087 
0088 /**
0089  * @var sic_isr0_mask
0090  * @brief copy of the mask of SIC ISR. The SIC ISR is cleared by the device
0091  * the relevant SIC_ISRx bit is not cleared unless the interrupt
0092  * service routine clears the mechanism that generated interrupt
0093  */
0094 static uint32_t sic_isr1_mask = 0;
0095 
0096 
0097 /**
0098  * @var sic_isr
0099  * @brief An array of sic register mask for each of the 16 core interrupt lines
0100  */
0101 static struct {
0102   uint32_t mask0;
0103   uint32_t mask1;
0104 } vectors[CEC_INTERRUPT_COUNT];
0105 
0106 /**
0107  * @var ivt
0108  * @brief Contains a table of ISR and arguments. The ISR jumps directly to
0109  * these ISR.
0110  */
0111 static bfin_isr_t ivt[IRQ_MAX];
0112 
0113 /**
0114  * http://graphics.stanford.edu/~seander/bithacks.html for more details
0115  */
0116 static const char clz_table[32] =
0117 {
0118     0, 31, 9, 30, 3, 8, 18, 29, 2, 5, 7, 14, 12, 17,
0119     22, 28, 1, 10, 4, 19, 6, 15, 13, 23, 11, 20, 16,
0120     24, 21, 25, 26, 27
0121 };
0122 
0123 /**
0124  * finds the first bit set from the left. look at
0125  * http://graphics.stanford.edu/~seander/bithacks.html for more details
0126  * @param n
0127  * @return
0128  */
0129 static unsigned long clz(unsigned long n)
0130 {
0131   unsigned long c = 0x7dcd629;       /* magic constant... */
0132 
0133   n |= (n >> 1);
0134   n |= (n >> 2);
0135   n |= (n >> 4);
0136   n |= (n >> 8);
0137   n |= (n >> 16);
0138   if (n == 0) return 32;
0139   n = c + (c * n);
0140   return 31 - clz_table[n >> 27];       /* For little endian    */
0141 }
0142 
0143 
0144 
0145 /**
0146  * Centralized Interrupt dispatcher routine. This routine dispatches interrupts
0147  * to the user ISR. The priority is according to the blackfin SIC.
0148  * The first level of priority is handled in the hardware at the core event
0149  * controller. The second level of interrupt is handled according to the line
0150  * number that goes in to the SIC.
0151  * * SIC_0 has higher priority than SIC 1.
0152  * * Inside the SIC the priority is assigned according to the line number.
0153  *   Lower the line number higher the priority.
0154  *
0155  *   In order to change the interrupt priority we may
0156  *   1. change the SIC IAR registers or
0157  *   2. Assign priority and extract it inside this function and call the ISR
0158  *   according tot the priority.
0159  *
0160  * @param vector IVG number.
0161  * @return
0162  */
0163 static rtems_isr interruptHandler(rtems_vector_number vector) {
0164   uint32_t mask = 0;
0165   int id = 0;
0166   /**
0167    * Enable for debugging
0168    *
0169    * static volatile uint32_t spurious_sic0    = 0;
0170    * static volatile uint32_t spurious_source  = 0;
0171    * static volatile uint32_t spurious_sic1    = 0;
0172    */
0173 
0174   /**
0175    * Extract the vector number relative to the SIC start line
0176    */
0177   vector -= CEC_INTERRUPT_BASE_VECTOR;
0178 
0179   /**
0180    * Check for bounds
0181    */
0182   if (vector >= 0 && vector < CEC_INTERRUPT_COUNT) {
0183 
0184     /**
0185      * Extract information and execute ISR from SIC 0
0186      */
0187     mask = *(uint32_t volatile *) SIC_ISR &
0188         *(uint32_t volatile *) SIC_IMASK & vectors[vector].mask0;
0189     id      = clz(mask);
0190     if ( SIC_ISR0_MAX > id ) {
0191       /** Parameter check */
0192       if( NULL != ivt[id].pFunc) {
0193         /** Call the relevant function with argument */
0194         ivt[id].pFunc( ivt[id].pArg );
0195       } else {
0196         /**
0197          * spurious interrupt we should not be getting this
0198          * spurious_sic0++;
0199          * spurious_source = id;
0200          */
0201       }
0202     } else {
0203       /**
0204        * we look at SIC 1
0205        */
0206     }
0207 
0208 
0209     /**
0210      * Extract information and execute ISR from SIC 1
0211      */
0212     mask    = *(uint32_t volatile *) (SIC_ISR + SIC_ISR_PITCH) &
0213         *(uint32_t volatile *) (SIC_IMASK + SIC_IMASK_PITCH) &
0214         vectors[vector].mask1;
0215     id      = clz(mask)+SIC_ISR0_MAX;
0216     if ( IRQ_MAX > id ) {
0217       /** Parameter Check */
0218       if( NULL != ivt[id].pFunc ) {
0219         /** Call the relevant function with argument */
0220         ivt[id].pFunc( ivt[id].pArg );
0221       } else {
0222         /**
0223          * spurious interrupt we should not be getting this
0224          *
0225          * spurious_sic1++;
0226          * spurious_source = id;
0227          */
0228       }
0229     } else {
0230       /**
0231        * we continue
0232        */
0233     }
0234 
0235   }
0236 }
0237 
0238 
0239 
0240 /**
0241  * This routine registers a new ISR. It will write a new entry to the IVT table
0242  * @param isr contains a callback function and source
0243  * @return rtems status code
0244  */
0245 rtems_status_code bfin_interrupt_register(bfin_isr_t *isr) {
0246   rtems_interrupt_level isrLevel;
0247   int               id        = 0;
0248   int               position  = 0;
0249 
0250   /**
0251    * Sanity Check
0252    */
0253   if ( NULL == isr ){
0254     return RTEMS_UNSATISFIED;
0255   }
0256 
0257   /**
0258    * Sanity check. The register function should at least provide callback func
0259    */
0260   if ( NULL == isr->pFunc ) {
0261     return RTEMS_UNSATISFIED;
0262   }
0263 
0264   id = isr->source;
0265 
0266   /**
0267    * Parameter Check. We already have a function registered here. First
0268    * unregister and then a new function can be allocated.
0269    */
0270   if ( NULL != ivt[id].pFunc ) {
0271     return RTEMS_UNSATISFIED;
0272   }
0273 
0274   rtems_interrupt_disable(isrLevel);
0275   /**
0276    * Assign the new function pointer to the ISR Dispatcher
0277    * */
0278   ivt[id].pFunc    = isr->pFunc;
0279   ivt[id].pArg     = isr->pArg;
0280 
0281 
0282   /** find out which isr mask has to be set to enable the interrupt */
0283   if ( SIC_ISR0_MAX > id ) {
0284     sic_isr0_mask |= 0x1<<id;
0285     *(uint32_t volatile *) SIC_IMASK  |= 0x1<<id;
0286   } else {
0287     position = id - SIC_ISR0_MAX;
0288     sic_isr1_mask |= 0x1<<position;
0289     *(uint32_t volatile *) (SIC_IMASK + SIC_IMASK_PITCH)  |= 0x1<<position;
0290   }
0291 
0292   rtems_interrupt_enable(isrLevel);
0293 
0294   return RTEMS_SUCCESSFUL;
0295 }
0296 
0297 
0298 /**
0299  * This function unregisters a registered interrupt handler.
0300  * @param isr
0301  */
0302 rtems_status_code bfin_interrupt_unregister(bfin_isr_t *isr) {
0303   rtems_interrupt_level isrLevel;
0304   int               id        = 0;
0305   int               position  = 0;
0306 
0307   /**
0308    * Sanity Check
0309    */
0310   if ( NULL == isr ){
0311     return RTEMS_UNSATISFIED;
0312   }
0313 
0314   id = isr->source;
0315 
0316   rtems_interrupt_disable(isrLevel);
0317   /**
0318    * Assign the new function pointer to the ISR Dispatcher
0319    * */
0320   ivt[id].pFunc    = NULL;
0321   ivt[id].pArg     = NULL;
0322 
0323 
0324   /** find out which isr mask has to be set to enable the interrupt */
0325   if ( SIC_ISR0_MAX > id ) {
0326     sic_isr0_mask &= ~(0x1<<id);
0327     *(uint32_t volatile *) SIC_IMASK  &= ~(0x1<<id);
0328   } else {
0329     position = id - SIC_ISR0_MAX;
0330     sic_isr1_mask &= ~(0x1<<position);
0331     *(uint32_t volatile *) (SIC_IMASK + SIC_IMASK_PITCH)  &= ~(0x1<<position);
0332   }
0333 
0334   rtems_interrupt_enable(isrLevel);
0335 
0336   return RTEMS_SUCCESSFUL;
0337 }
0338 
0339 
0340 
0341 
0342 /**
0343  * blackfin interrupt initialization routine. It initializes the bfin ISR
0344  * dispatcher. It will also create SIC CEC map which will be used for
0345  * identifying the ISR.
0346  */
0347 void bfin_interrupt_init(void) {
0348   int source;
0349   int vector;
0350   uint32_t r;
0351   int i;
0352   int j;
0353 
0354   *(uint32_t volatile *) SIC_IMASK = 0;
0355   *(uint32_t volatile *) (SIC_IMASK + SIC_IMASK_PITCH) = 0;
0356 
0357   memset(vectors, 0, sizeof(vectors));
0358   /* build mask0 showing what SIC sources drive each CEC vector */
0359   source = 0;
0360 
0361   /**
0362    * The bf52x has 8 IAR registers but they do not have a constant pitch.
0363    *
0364    */
0365   for (i = 0; i < SIC_IAR_COUNT; i++) {
0366     if ( SIC_IAR_COUNT_SET0 > i ) {
0367       r = *(uint32_t volatile *) (SIC_IAR_BASE_ADDRESS + i * SIC_IAR_PITCH);
0368     } else {
0369       r = *(uint32_t volatile *) (SIC_IAR_BASE_ADDRESS_0 +
0370           ((i-SIC_IAR_COUNT_SET0) * SIC_IAR_PITCH));
0371     }
0372 
0373     for (j = 0; j < 8; j++) {
0374       vector = r & 0x0f;
0375       if (vector >= 0 && vector < CEC_INTERRUPT_COUNT) {
0376         /* install our local handler */
0377         if (vectors[vector].mask0 == 0 && vectors[vector].mask1 == 0){
0378           set_vector(interruptHandler, vector + CEC_INTERRUPT_BASE_VECTOR, 1);
0379         }
0380         if ( SIC_ISR0_MAX > source ) {
0381           vectors[vector].mask0 |= (1 << source);
0382         } else {
0383           vectors[vector].mask1 |= (1 << (source - SIC_ISR0_MAX));
0384         }
0385       }
0386       r >>= 4;
0387       source++;
0388     }
0389   }
0390 }
0391 
0392 
0393 
0394 
0395 
0396 #else
0397 
0398 static struct {
0399   uint32_t mask0;
0400   uint32_t mask1;
0401   bfin_isr_t *head;
0402 } vectors[CEC_INTERRUPT_COUNT];
0403 
0404 static uint32_t globalMask0;
0405 static uint32_t globalMask1;
0406 
0407 static rtems_isr interruptHandler(rtems_vector_number vector) {
0408   bfin_isr_t *isr = NULL;
0409   uint32_t sourceMask0 = 0;
0410   uint32_t sourceMask1 = 0;
0411   rtems_interrupt_level isrLevel;
0412 
0413   rtems_interrupt_disable(isrLevel);
0414   vector -= CEC_INTERRUPT_BASE_VECTOR;
0415   if (vector >= 0 && vector < CEC_INTERRUPT_COUNT) {
0416     isr = vectors[vector].head;
0417     sourceMask0 = *(uint32_t volatile *) SIC_ISR &
0418         *(uint32_t volatile *) SIC_IMASK;
0419     sourceMask1 = *(uint32_t volatile *) (SIC_ISR + SIC_ISR_PITCH) &
0420         *(uint32_t volatile *) (SIC_IMASK + SIC_IMASK_PITCH);
0421     while (isr) {
0422       if ((sourceMask0 & isr->mask0) || (sourceMask1 & isr->mask1)) {
0423         isr->isr(isr->_arg);
0424         sourceMask0 = *(uint32_t volatile *) SIC_ISR &
0425             *(uint32_t volatile *) SIC_IMASK;
0426         sourceMask1 = *(uint32_t volatile *) (SIC_ISR + SIC_ISR_PITCH) &
0427             *(uint32_t volatile *) (SIC_IMASK + SIC_IMASK_PITCH);
0428       }
0429       isr = isr->next;
0430     }
0431   }
0432   rtems_interrupt_enable(isrLevel);
0433 }
0434 
0435 /**
0436  * Initializes the interrupt module
0437  */
0438 void bfin_interrupt_init(void) {
0439   int source;
0440   int vector;
0441   uint32_t r;
0442   int i;
0443   int j;
0444 
0445   globalMask0 = ~(uint32_t) 0;
0446   globalMask1 = ~(uint32_t) 0;
0447   *(uint32_t volatile *) SIC_IMASK = 0;
0448   *(uint32_t volatile *) (SIC_IMASK + SIC_IMASK_PITCH) = 0;
0449 
0450   memset(vectors, 0, sizeof(vectors));
0451   /* build mask0 showing what SIC sources drive each CEC vector */
0452   source = 0;
0453 
0454   /**
0455    * The bf52x has 8 IAR registers but they do not have a constant pitch.
0456    *
0457    */
0458   for (i = 0; i < SIC_IAR_COUNT; i++) {
0459     if ( SIC_IAR_COUNT_SET0 > i ) {
0460       r = *(uint32_t volatile *) (SIC_IAR_BASE_ADDRESS + i * SIC_IAR_PITCH);
0461     } else {
0462       r = *(uint32_t volatile *) (SIC_IAR_BASE_ADDRESS_0 +
0463           ((i-SIC_IAR_COUNT_SET0) * SIC_IAR_PITCH));
0464     }
0465     for (j = 0; j < 8; j++) {
0466       vector = r & 0x0f;
0467       if (vector >= 0 && vector < CEC_INTERRUPT_COUNT) {
0468         /* install our local handler */
0469         if (vectors[vector].mask0 == 0 && vectors[vector].mask1 == 0){
0470           set_vector(interruptHandler, vector + CEC_INTERRUPT_BASE_VECTOR, 1);
0471         }
0472         if ( SIC_ISR0_MAX > source ) {
0473           vectors[vector].mask0 |= (1 << source);
0474         } else {
0475           vectors[vector].mask1 |= (1 << (source - SIC_ISR0_MAX));
0476         }
0477       }
0478       r >>= 4;
0479       source++;
0480     }
0481   }
0482 }
0483 
0484 /* modify SIC_IMASK based on ISR list for a particular CEC vector */
0485 static void setMask(uint32_t vector) {
0486   bfin_isr_t *isr = NULL;
0487   uint32_t mask = 0;
0488   uint32_t r    = 0;
0489 
0490   mask = 0;
0491   isr = vectors[vector].head;
0492   while (isr) {
0493     mask |= isr->mask0;
0494     isr = isr->next;
0495   }
0496   r = *(uint32_t volatile *) SIC_IMASK;
0497   r &= ~vectors[vector].mask0;
0498   r |= mask;
0499   r &= globalMask0;
0500   *(uint32_t volatile *) SIC_IMASK = r;
0501 
0502 
0503   mask = 0;
0504   isr = vectors[vector].head;
0505   while (isr) {
0506     mask |= isr->mask1;
0507     isr = isr->next;
0508   }
0509   r = *(uint32_t volatile *) (SIC_IMASK+ SIC_IMASK_PITCH);
0510   r &= ~vectors[vector].mask1;
0511   r |= mask;
0512   r &= globalMask1;
0513   *(uint32_t volatile *) (SIC_IMASK+ SIC_IMASK_PITCH) = r;
0514 }
0515 
0516 /* add an ISR to the list for whichever vector it belongs to */
0517 rtems_status_code bfin_interrupt_register(bfin_isr_t *isr) {
0518   bfin_isr_t *walk;
0519   rtems_interrupt_level isrLevel;
0520 
0521   /* find the appropriate vector */
0522   for (isr->vector = 0; isr->vector < CEC_INTERRUPT_COUNT; isr->vector++)
0523     if ( (vectors[isr->vector].mask0 & (1 << isr->source) ) || \
0524         (vectors[isr->vector].mask1 & (1 << (isr->source - SIC_ISR0_MAX)) ))
0525       break;
0526   if (isr->vector < CEC_INTERRUPT_COUNT) {
0527     isr->next = NULL;
0528     isr->mask0 = 0;
0529     isr->mask1 = 0;
0530     rtems_interrupt_disable(isrLevel);
0531     /* find the current end of the list */
0532     walk = vectors[isr->vector].head;
0533     while (walk && walk->next)
0534       walk = walk->next;
0535     /* append new isr to list */
0536     if (walk)
0537       walk->next = isr;
0538     else
0539       vectors[isr->vector].head = isr;
0540     rtems_interrupt_enable(isrLevel);
0541   } else
0542     /* we failed, but make vector a legal value so other calls into
0543            this module with this isr descriptor won't do anything bad */
0544     isr->vector = 0;
0545   return RTEMS_SUCCESSFUL;
0546 }
0547 
0548 rtems_status_code bfin_interrupt_unregister(bfin_isr_t *isr) {
0549   bfin_isr_t *walk, *prev;
0550   rtems_interrupt_level isrLevel;
0551 
0552   rtems_interrupt_disable(isrLevel);
0553   walk = vectors[isr->vector].head;
0554   prev = NULL;
0555   /* find this isr in our list */
0556   while (walk && walk != isr) {
0557     prev = walk;
0558     walk = walk->next;
0559   }
0560   if (walk) {
0561     /* if found, remove it */
0562     if (prev)
0563       prev->next = walk->next;
0564     else
0565       vectors[isr->vector].head = walk->next;
0566     /* fix up SIC_IMASK if necessary */
0567     setMask(isr->vector);
0568   }
0569   rtems_interrupt_enable(isrLevel);
0570   return RTEMS_SUCCESSFUL;
0571 }
0572 
0573 void bfin_interrupt_enable(bfin_isr_t *isr, bool enable) {
0574   rtems_interrupt_level isrLevel;
0575 
0576   rtems_interrupt_disable(isrLevel);
0577   if ( SIC_ISR0_MAX > isr->source ) {
0578     isr->mask0 = enable ? (1 << isr->source) : 0;
0579     *(uint32_t volatile *) SIC_IMASK |= isr->mask0;
0580   }  else {
0581     isr->mask1 = enable ? (1 << (isr->source - SIC_ISR0_MAX)) : 0;
0582     *(uint32_t volatile *) (SIC_IMASK + SIC_IMASK_PITCH) |= isr->mask1;
0583   }
0584 
0585   //setMask(isr->vector);
0586   rtems_interrupt_enable(isrLevel);
0587 }
0588 
0589 void bfin_interrupt_enable_all(int source, bool enable) {
0590   rtems_interrupt_level isrLevel;
0591   int vector;
0592   bfin_isr_t *walk;
0593 
0594   for (vector = 0; vector < CEC_INTERRUPT_COUNT; vector++)
0595     if ( (vectors[vector].mask0 & (1 << source) ) || \
0596         (vectors[vector].mask1 & (1 << (source - SIC_ISR0_MAX)) ))
0597       break;
0598   if (vector < CEC_INTERRUPT_COUNT) {
0599     rtems_interrupt_disable(isrLevel);
0600     walk = vectors[vector].head;
0601     while (walk) {
0602       walk->mask0 = enable ? (1 << source) : 0;
0603       walk = walk->next;
0604     }
0605 
0606     walk = vectors[vector].head;
0607     while (walk) {
0608       walk->mask1 = enable ? (1 << (source - SIC_ISR0_MAX)) : 0;
0609       walk = walk->next;
0610     }
0611     setMask(vector);
0612     rtems_interrupt_enable(isrLevel);
0613   }
0614 }
0615 
0616 void bfin_interrupt_enable_global(int source, bool enable) {
0617   int vector;
0618   rtems_interrupt_level isrLevel;
0619 
0620   for (vector = 0; vector < CEC_INTERRUPT_COUNT; vector++)
0621     if ( (vectors[vector].mask0 & (1 << source) ) || \
0622         (vectors[vector].mask1 & (1 << (source - SIC_ISR0_MAX)) ))
0623       break;
0624   if (vector < CEC_INTERRUPT_COUNT) {
0625     rtems_interrupt_disable(isrLevel);
0626     if ( SIC_ISR0_MAX > source ) {
0627       if (enable)
0628         globalMask0 |= 1 << source;
0629       else
0630         globalMask0 &= ~(1 << source);
0631     }else {
0632       if (enable)
0633         globalMask1 |= 1 << (source - SIC_ISR0_MAX);
0634       else
0635         globalMask1 &= ~(1 << (source - SIC_ISR0_MAX));
0636     }
0637     setMask(vector);
0638     rtems_interrupt_enable(isrLevel);
0639   }
0640 }
0641 
0642 #endif