Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:05

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*  GR1553B RT driver
0004  *
0005  *  COPYRIGHT (c) 2010.
0006  *  Cobham Gaisler AB.
0007  *
0008  * Redistribution and use in source and binary forms, with or without
0009  * modification, are permitted provided that the following conditions
0010  * are met:
0011  * 1. Redistributions of source code must retain the above copyright
0012  *    notice, this list of conditions and the following disclaimer.
0013  * 2. Redistributions in binary form must reproduce the above copyright
0014  *    notice, this list of conditions and the following disclaimer in the
0015  *    documentation and/or other materials provided with the distribution.
0016  *
0017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0027  * POSSIBILITY OF SUCH DAMAGE.
0028  */
0029 
0030 #include <rtems.h>
0031 #include <stdlib.h>
0032 #include <stdio.h>
0033 #include <string.h>
0034 
0035 #include <grlib/gr1553b.h>
0036 #include <grlib/gr1553rt.h>
0037 
0038 #include <drvmgr/drvmgr.h>
0039 #include <grlib/ambapp_bus.h>
0040 
0041 #include <grlib/grlib_impl.h>
0042 
0043 #define GR1553RT_WRITE_MEM(adr, val) *(volatile uint32_t *)(adr) = (uint32_t)(val)
0044 #define GR1553RT_READ_MEM(adr) (*(volatile uint32_t *)(adr))
0045 
0046 #define GR1553RT_WRITE_REG(adr, val) *(volatile uint32_t *)(adr) = (uint32_t)(val)
0047 #define GR1553RT_READ_REG(adr) (*(volatile uint32_t *)(adr))
0048 
0049 /* Software representation of one hardware descriptor */
0050 struct gr1553rt_sw_bd {
0051     unsigned short this_next;/* Next entry or this entry. 0xffff: no next */
0052     unsigned char listid;   /* ListID of List the descriptor is attached */
0053     char unused;
0054 } __attribute__((packed));
0055 
0056 /* Software description of a subaddress */
0057 struct gr1553rt_subadr {
0058     /* RX LIST */
0059     unsigned char rxlistid;
0060     /* TX LIST */
0061     unsigned char txlistid;
0062 };
0063 
0064 struct gr1553rt_irqerr {
0065     gr1553rt_irqerr_t func;
0066     void *data;
0067 };
0068 
0069 struct gr1553rt_irqmc {
0070     gr1553rt_irqmc_t func;
0071     void *data;
0072 };
0073 
0074 struct gr1553rt_irq {
0075     gr1553rt_irq_t func;
0076     void *data;
0077 };
0078 
0079 struct gr1553rt_priv {
0080     /* Pointer to Hardware registers */
0081     struct gr1553b_regs *regs;
0082 
0083     /* Software State */
0084     int started;
0085     struct gr1553rt_cfg cfg;
0086     SPIN_DECLARE(devlock);
0087 
0088     /* Handle to GR1553B RT device layer */
0089     struct drvmgr_dev **pdev;
0090 
0091     /* Each Index represents one RT Subaddress. 31 = Broadcast */
0092     struct gr1553rt_subadr subadrs[32];
0093 
0094     /* Pointer to array of Software's description of a hardware
0095      * descriptor.
0096      */
0097 #if (RTBD_MAX == 0)
0098     struct gr1553rt_sw_bd *swbds;
0099 #else
0100     struct gr1553rt_sw_bd swbds[RTBD_MAX];
0101 #endif
0102 
0103     /* List of Free descriptors */
0104     unsigned short swbd_free;
0105     int swbd_free_cnt;
0106 
0107     /* Hardware SubAddress descriptors given for CPU and Hardware */
0108     void *satab_buffer;
0109     struct gr1553rt_sa *sas_cpu;    /* Translated for CPU */
0110     struct gr1553rt_sa *sas_hw; /* Translated for Hardware */
0111 
0112     /* Hardware descriptors address given for CPU and hardware */
0113     void *bd_buffer;
0114     int bds_cnt;            /* Number of descriptors */
0115     struct gr1553rt_bd *bds_cpu;    /* Translated for CPU */
0116     struct gr1553rt_bd *bds_hw; /* Translated for Hardware */
0117 
0118 
0119     /* Event Log buffer in */
0120     void *evlog_buffer;
0121     unsigned int *evlog_cpu_next;   /* Next LOG entry to be handled */
0122     unsigned int *evlog_cpu_base;   /* First Entry in LOG */
0123     unsigned int *evlog_cpu_end;    /* Last+1 Entry in LOG */
0124     unsigned int *evlog_hw_base;    /* Translated for Hardware */
0125 
0126     /* Each Index represents a LIST ID */
0127     struct gr1553rt_list *lists[RTLISTID_MAX];
0128 
0129     /* IRQ handlers, one per SUBADDRESS */
0130     struct gr1553rt_irq irq_rx[32];
0131     struct gr1553rt_irq irq_tx[32];
0132 
0133     /* ISR called when an ERROR IRQ is received */
0134     struct gr1553rt_irqerr irq_err;
0135 
0136     /* ISR called when an Mode Code is received */
0137     struct gr1553rt_irqmc irq_mc;
0138 };
0139 
0140 void gr1553rt_sw_init(struct gr1553rt_priv *priv);
0141 void gr1553rt_sw_free(struct gr1553rt_priv *priv);
0142 void gr1553rt_isr(void *data);
0143 
0144 /* Assign and ID to the list. An LIST ID is needed before scheduling list
0145  * on an RT subaddress.
0146  *
0147  * Only 64 lists can be registered at a time on the same device.
0148  */
0149 static int gr1553rt_list_reg(struct gr1553rt_list *list)
0150 {
0151     struct gr1553rt_priv *priv = list->rt;
0152     int i;
0153 
0154     /* Find first free list ID */
0155     for ( i=0; i<RTLISTID_MAX; i++) {
0156         if ( priv->lists[i] == NULL ) {
0157             priv->lists[i] = list;
0158             list->listid = i;
0159             return i;
0160         }
0161     }
0162 
0163     /* No available LIST IDs */
0164     list->listid = -1;
0165 
0166     return -1;
0167 }
0168 
0169 /* Unregister List from device */
0170 static void gr1553rt_list_unreg(struct gr1553rt_list *list)
0171 {
0172     struct gr1553rt_priv *priv = list->rt;
0173 
0174     priv->lists[list->listid] = NULL;
0175     list->listid = -1;
0176 }
0177 
0178 static int gr1553rt_bdid(void *rt, struct gr1553rt_sw_bd *bd)
0179 {
0180     struct gr1553rt_priv *priv = rt;
0181 
0182     unsigned short index;
0183 
0184     /* Get Index of Software BD */
0185     index = ((unsigned int)bd - (unsigned int)&priv->swbds[0]) /
0186         sizeof(struct gr1553rt_sw_bd);
0187 
0188     return index;
0189 }
0190 
0191 static void gr1553rt_bd_alloc_init(void *rt, int count)
0192 {
0193     struct gr1553rt_priv *priv = rt;
0194     int i;
0195 
0196     for (i=0; i<count-1; i++) {
0197         priv->swbds[i].this_next = i+1;
0198     }
0199     priv->swbds[count-1].this_next = 0xffff;
0200     priv->swbd_free = 0;
0201     priv->swbd_free_cnt = count;
0202 }
0203 
0204 /* Allocate a Chain of descriptors */
0205 static int gr1553rt_bd_alloc(void *rt, struct gr1553rt_sw_bd **bd, int cnt)
0206 {
0207     struct gr1553rt_priv *priv = rt;
0208     struct gr1553rt_sw_bd *curr;
0209     int i;
0210 
0211     if ((priv->swbd_free_cnt < cnt) || (cnt <= 0)) {
0212         *bd = NULL;
0213         return -1;
0214     }
0215 
0216     *bd = &priv->swbds[priv->swbd_free];
0217     curr = &priv->swbds[priv->swbd_free];
0218     for (i=0; i<cnt; i++) {
0219         if ( i != 0) {
0220             curr = &priv->swbds[curr->this_next];
0221         }
0222         if ( curr->this_next == 0xffff ) {
0223             *bd = NULL;
0224             return -1;
0225         }
0226     }
0227     priv->swbd_free = curr->this_next;
0228     priv->swbd_free_cnt -= cnt;
0229     curr->this_next = 0xffff; /* Mark end of chain on last entry */
0230 
0231     return 0;
0232 }
0233 
0234 #if 0 /* unused for now */
0235 static void gr1553rt_bd_free(void *rt, struct gr1553rt_sw_bd *bd)
0236 {
0237     struct gr1553rt_priv *priv = rt;
0238     unsigned short index;
0239 
0240     /* Get Index of Software BD */
0241     index = gr1553rt_bdid(priv, bd);
0242 
0243     /* Insert first in list */
0244     bd->this_next = priv->swbd_free;
0245     priv->swbd_free = index;
0246     priv->swbd_free_cnt++;
0247 }
0248 #endif
0249 
0250 int gr1553rt_list_init
0251     (
0252     void *rt,
0253     struct gr1553rt_list **plist,
0254     struct gr1553rt_list_cfg *cfg
0255     )
0256 {
0257     struct gr1553rt_priv *priv = rt;
0258     size_t size;
0259     int i, malloc_used;
0260     struct gr1553rt_sw_bd *swbd;
0261     unsigned short index;
0262     struct gr1553rt_list *list;
0263 
0264     /* The user may provide a pre allocated LIST, or
0265      * let the driver handle allocation by using malloc()
0266      *
0267      * If the IN/OUT plist argument points to NULL a list
0268      * dynamically allocated here.
0269      */
0270     malloc_used = 0;
0271     list = *plist;
0272     if ( list == NULL ) {
0273         /* Dynamically allocate LIST */
0274         size = sizeof(*list) +
0275             (cfg->bd_cnt * sizeof(list->bds[0]));
0276         list = grlib_malloc(size);
0277         if ( list == NULL )
0278             return -1; /* Out of Memory */
0279         *plist = list;
0280         malloc_used = 1;
0281     }
0282 
0283     list->rt = rt;
0284     list->subadr = -1;
0285     list->listid = gr1553rt_list_reg(list);
0286     if ( list->listid == -1 ) {
0287         if (malloc_used)
0288             free(list);
0289         return -2; /* Too many lists */
0290     }
0291     list->cfg = cfg;
0292     list->bd_cnt = cfg->bd_cnt;
0293 
0294     /* Allocate all BDs needed by list */
0295     if ( gr1553rt_bd_alloc(rt, &swbd, list->bd_cnt) ) {
0296         gr1553rt_list_unreg(list);
0297         if (malloc_used)
0298             free(list);
0299         return -3; /* Too few descriptors */
0300     }
0301 
0302     /* Get ID/INDEX of Software BDs */
0303     index = gr1553rt_bdid(rt, swbd);
0304     list->bds[0] = index;
0305     for (i=1; i<list->bd_cnt; i++) {
0306         list->bds[i] = priv->swbds[list->bds[i-1]].this_next;
0307     }
0308 
0309     /* Now that the next pointer has fullfilled it's job and not
0310      * needed anymore, we use it as list entry pointer instead.
0311      * The this_next pointer is a list entry number.
0312      */
0313     for (i=0; i<list->bd_cnt; i++) {
0314         priv->swbds[list->bds[i]].this_next = i;
0315     }
0316 
0317     return 0;
0318 }
0319 
0320 int gr1553rt_bd_init(
0321     struct gr1553rt_list *list,
0322     unsigned short entry_no,
0323     unsigned int flags,
0324     uint16_t *dptr,
0325     unsigned short next
0326     )
0327 {
0328     struct gr1553rt_priv *priv;
0329     unsigned short bdid;
0330     struct gr1553rt_bd *bd;
0331     unsigned int nextbd, dataptr;
0332     SPIN_IRQFLAGS(irqflags);
0333 
0334     if ( entry_no >= list->bd_cnt )
0335         return -1;
0336 
0337     /* Find Descriptor */
0338     bdid = list->bds[entry_no];
0339     priv = list->rt;
0340     bd = &priv->bds_cpu[bdid];
0341 
0342     if ( next == 0xfffe ) {
0343         next = entry_no + 1;
0344         if ( next >= list->bd_cnt )
0345             next = 0;
0346     }
0347 
0348     /* Find next descriptor in address space that the
0349      * Hardware understand.
0350      */
0351     if ( next >= 0xffff ) {
0352         nextbd = 0x3; /* End of list */
0353     } else if ( next >= list->bd_cnt ) {
0354         return -1;
0355     } else {
0356         bdid = list->bds[next];
0357         nextbd = (unsigned int)&priv->bds_hw[bdid];
0358     }
0359 
0360     dataptr = (unsigned int)dptr;
0361     if ( dataptr & 1 ) {
0362         /* Translate address from CPU-local into remote */
0363         dataptr &= ~1;
0364         drvmgr_translate(
0365             *priv->pdev,
0366             CPUMEM_TO_DMA,
0367             (void *)dataptr,
0368             (void **)&dataptr
0369             );
0370     }
0371 
0372     /* Init BD */
0373     SPIN_LOCK_IRQ(&priv->devlock, irqflags);
0374     bd->ctrl = flags & GR1553RT_BD_FLAGS_IRQEN;
0375     bd->dptr = (unsigned int)dptr;
0376     bd->next = nextbd;
0377     SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
0378 
0379     return 0;
0380 }
0381 
0382 int gr1553rt_bd_update(
0383     struct gr1553rt_list *list,
0384     int entry_no,
0385     unsigned int *status,
0386     uint16_t **dptr
0387     )
0388 {
0389     struct gr1553rt_priv *priv;
0390     unsigned short bdid;
0391     struct gr1553rt_bd *bd;
0392     unsigned int tmp, dataptr;
0393     SPIN_IRQFLAGS(irqflags);
0394 
0395     if ( entry_no >= list->bd_cnt )
0396         return -1;
0397 
0398     /* Find Descriptor */
0399     bdid = list->bds[entry_no];
0400     priv = list->rt;
0401     bd = &priv->bds_cpu[bdid];
0402 
0403     /* Prepare translation if needed */
0404     if ( dptr && (dataptr=(unsigned int)*dptr) ) {
0405         if ( dataptr & 1 ) {
0406             /* Translate address from CPU-local into remote. May
0407              * be used when RT core is accessed over the PCI bus.
0408              */
0409             dataptr &= ~1;
0410             drvmgr_translate(
0411                 *priv->pdev,
0412                 CPUMEM_TO_DMA,
0413                 (void *)dataptr,
0414                 (void **)&dataptr
0415                 );
0416         }
0417     }
0418 
0419     /* Get current values and then set new values in BD */
0420     SPIN_LOCK_IRQ(&priv->devlock, irqflags);
0421     /* READ/WRITE Status/Control word */
0422     if ( status ) {
0423         tmp = bd->ctrl;
0424         if ( *status ) {
0425             bd->ctrl = *status;
0426         }
0427         *status = tmp;
0428     }
0429     /* READ/WRITE Data-Pointer word */
0430     if ( dptr ) {
0431         tmp = bd->dptr;
0432         if ( dataptr ) {
0433             bd->dptr = dataptr;
0434         }
0435         *dptr = (uint16_t *)tmp;
0436     }
0437     SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
0438 
0439     return 0;
0440 }
0441 
0442 int gr1553rt_irq_err
0443     (
0444     void *rt,
0445     gr1553rt_irqerr_t func,
0446     void *data
0447     )
0448 {
0449     struct gr1553rt_priv *priv = rt;
0450     SPIN_IRQFLAGS(irqflags);
0451 
0452     SPIN_LOCK_IRQ(&priv->devlock, irqflags);
0453     priv->irq_err.func = func;
0454     priv->irq_err.data = data;
0455     SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
0456 
0457     return 0;
0458 }
0459 
0460 int gr1553rt_irq_mc
0461     (
0462     void *rt,
0463     gr1553rt_irqmc_t func,
0464     void *data
0465     )
0466 {
0467     struct gr1553rt_priv *priv = rt;
0468     SPIN_IRQFLAGS(irqflags);
0469 
0470     SPIN_LOCK_IRQ(&priv->devlock, irqflags);
0471     priv->irq_mc.func = func;
0472     priv->irq_mc.data = data;
0473     SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
0474 
0475     return 0;
0476 }
0477 
0478 int gr1553rt_irq_sa
0479     (
0480     void *rt,
0481     int subadr,
0482     int tx,
0483     gr1553rt_irq_t func,
0484     void *data
0485     )
0486 {
0487     struct gr1553rt_priv *priv = rt;
0488     SPIN_IRQFLAGS(irqflags);
0489 
0490     SPIN_LOCK_IRQ(&priv->devlock, irqflags);
0491     if ( tx ) {
0492         priv->irq_tx[subadr].func = func;
0493         priv->irq_tx[subadr].data = data;
0494     } else {
0495         priv->irq_rx[subadr].func = func;
0496         priv->irq_rx[subadr].data = data;
0497     }
0498     SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
0499 
0500     return 0;
0501 }
0502 
0503 /* GR1553-RT Interrupt Service Routine */
0504 void gr1553rt_isr(void *data)
0505 {
0506     struct gr1553rt_priv *priv = data;
0507     unsigned int firstirq, lastpos;
0508     int index;
0509     unsigned int *last, *curr, entry, hwbd;
0510     int type, samc, mcode, subadr;
0511     int listid;
0512     struct gr1553rt_irq *pisr, isr;
0513     struct gr1553rt_irqerr isrerr;
0514     struct gr1553rt_irqmc isrmc;
0515     unsigned int irq;
0516     SPIN_ISR_IRQFLAGS(irqflags);
0517 
0518     /* Ack IRQ before reading current write pointer, but after
0519      * reading current IRQ pointer. This is because RT_EVIRQ
0520      * may be updated after we ACK the IRQ source.
0521      */
0522     irq = priv->regs->irq &
0523         (GR1553B_IRQ_RTTE|GR1553B_IRQ_RTD|GR1553B_IRQ_RTEV);
0524     if ( irq == 0 )
0525         return;
0526 
0527     firstirq = priv->regs->rt_evirq;
0528     priv->regs->irq = irq;
0529     lastpos = priv->regs->rt_evlog;
0530 
0531     /* Quit if nothing has been added to the log */
0532     if ( lastpos == firstirq )
0533         return;
0534 
0535     if ( irq & (GR1553B_IRQ_RTTE|GR1553B_IRQ_RTD) ) {
0536         /* copy func and arg while owning lock */
0537         SPIN_LOCK(&priv->devlock, irqflags);
0538         isrerr = priv->irq_err;
0539         SPIN_UNLOCK(&priv->devlock, irqflags);
0540         if ( isrerr.func ) {
0541             isrerr.func(irq, isrerr.data);
0542         }
0543 
0544         /* Stop Hardware and enter non-started mode. This will
0545          * make all future calls to driver result in an error.
0546          */
0547         gr1553rt_stop(priv);
0548     }
0549 
0550     /* Step between first log entry causing an IRQ to last
0551      * entry. Each entry that has caused an IRQ will be handled
0552      * by calling user-defined function.
0553      *
0554      * We convert hardware addresses into CPU accessable addresses
0555      * first.
0556      */
0557     index = (firstirq - (unsigned int)priv->evlog_hw_base) /
0558         sizeof(unsigned int);
0559     curr = priv->evlog_cpu_base + index;
0560     index = (lastpos - (unsigned int)priv->evlog_hw_base) /
0561         sizeof(unsigned int);
0562     last = priv->evlog_cpu_base + index;
0563 
0564     do {
0565         /* Process one entry */
0566         entry = *curr;
0567 
0568         if ( entry & 0x80000000 ) {
0569             /* Entry caused IRQ */
0570             type = (entry >> 29) & 0x3;
0571             samc = (entry >> 24) & 0x1f;
0572             if ( (type & 0x2) == 0 ) {
0573                 /* Transmit/Receive Data */
0574                 subadr = samc;
0575                 if ( type ) {
0576                     /* Receive */
0577                     listid = priv->subadrs[subadr].rxlistid;
0578                     hwbd = priv->sas_cpu[subadr].rxptr;
0579                     pisr = &priv->irq_rx[subadr];
0580                 } else {
0581                     /* Transmit */
0582                     listid = priv->subadrs[subadr].txlistid;
0583                     hwbd = priv->sas_cpu[subadr].txptr;
0584                     pisr = &priv->irq_tx[subadr];
0585                 }
0586 
0587                 index = ((unsigned int)hwbd - (unsigned int)
0588                     priv->bds_hw)/sizeof(struct gr1553rt_bd);
0589 
0590                 /* copy func and arg while owning lock */
0591                 SPIN_LOCK(&priv->devlock, irqflags);
0592                 isr = *pisr;
0593                 SPIN_UNLOCK(&priv->devlock, irqflags);
0594 
0595                 /* Call user ISR of RX/TX transfer */
0596                 if ( isr.func ) {
0597                     isr.func(
0598                         priv->lists[listid],
0599                         entry,
0600                         priv->swbds[index].this_next,
0601                         isr.data
0602                         );
0603                 }
0604             } else if ( type == 0x2) {
0605                 /* Modecode */
0606                 mcode = samc;
0607 
0608                 /* copy func and arg while owning lock */
0609                 SPIN_LOCK(&priv->devlock, irqflags);
0610                 isrmc = priv->irq_mc;
0611                 SPIN_UNLOCK(&priv->devlock, irqflags);
0612 
0613                 /* Call user ISR of ModeCodes RX/TX */
0614                 if ( isrmc.func ) {
0615                     isrmc.func(
0616                         mcode,
0617                         entry,
0618                         isrmc.data
0619                         );
0620                 }
0621             } else {
0622                 /* ERROR OF SOME KIND, EVLOG OVERWRITTEN? */
0623                 rtems_fatal_error_occurred(RTEMS_IO_ERROR);
0624             }
0625         }
0626 
0627         /* Calc next entry posistion */
0628         curr++;
0629         if ( curr == priv->evlog_cpu_end )
0630             curr = priv->evlog_cpu_base;
0631 
0632     } while ( curr != last );
0633 }
0634 
0635 int gr1553rt_indication(void *rt, int subadr, int *txeno, int *rxeno)
0636 {
0637     struct gr1553rt_priv *priv = rt;
0638     struct gr1553rt_sa *sa;
0639     unsigned int bd, index;
0640 
0641     /*  Sub address valid */
0642     if ( (subadr < 0) || (subadr > 31) )
0643         return -1;
0644 
0645     /* Get SubAddress Descriptor address as accessed from CPU */
0646     sa = &priv->sas_cpu[subadr];
0647 
0648     /* Indication of TX descriptor? */
0649     if ( txeno ) {
0650         bd = sa->txptr;
0651         /* Get Index of Hardware BD */
0652         index = ((unsigned int)bd - (unsigned int)&priv->bds_hw[0]) /
0653             sizeof(struct gr1553rt_bd);
0654         *txeno = priv->swbds[index].this_next;
0655     }
0656 
0657     /* Indication of RX descriptor? */
0658     if ( rxeno ) {
0659         bd = sa->rxptr;
0660         /* Get Index of Hardware BD */
0661         index = ((unsigned int)bd - (unsigned int)&priv->bds_hw[0]) /
0662             sizeof(struct gr1553rt_bd);
0663         *rxeno = priv->swbds[index].this_next;
0664     }
0665 
0666     return 0;
0667 }
0668 
0669 void gr1553rt_hw_stop(struct gr1553rt_priv *priv);
0670 
0671 void gr1553rt_register(void)
0672 {
0673     /* The RT driver rely on the GR1553B Driver */
0674     gr1553_register();
0675 }
0676 
0677 void *gr1553rt_open(int minor)
0678 {
0679     struct drvmgr_dev **pdev = NULL;
0680     struct gr1553rt_priv *priv = NULL;
0681     struct amba_dev_info *ambadev;
0682     struct ambapp_core *pnpinfo;
0683 
0684     /* Allocate requested device */
0685     pdev = gr1553_rt_open(minor);
0686     if ( pdev == NULL )
0687         goto fail;
0688 
0689     priv = grlib_calloc(1, sizeof(*priv));
0690     if ( priv == NULL )
0691         goto fail;
0692 
0693     /* Assign a device private to RT device */
0694     priv->pdev = pdev;
0695     (*pdev)->priv = priv;
0696 
0697     /* Get device information from AMBA PnP information */
0698     ambadev = (struct amba_dev_info *)(*pdev)->businfo;
0699     pnpinfo = &ambadev->info;
0700     priv->regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
0701 
0702     SPIN_INIT(&priv->devlock, "gr1553rt");
0703 
0704     /* Start with default configuration */
0705     /*priv->cfg = gr1553rt_default_config;*/
0706 
0707     /* Unmask IRQs and so */
0708     gr1553rt_hw_stop(priv);
0709 
0710     /* Register ISR handler. hardware mask IRQ, so it is safe to unmask
0711      * at IRQ controller.
0712      */
0713     if (drvmgr_interrupt_register(*priv->pdev, 0, "gr1553rt", gr1553rt_isr, priv))
0714         goto fail;
0715 
0716     return priv;
0717 
0718 fail:
0719     if ( pdev )
0720         gr1553_rt_close(pdev);
0721     if ( priv )
0722         free(priv);
0723     return NULL;
0724 }
0725 
0726 void gr1553rt_close(void *rt)
0727 {
0728     struct gr1553rt_priv *priv = rt;
0729 
0730     if ( priv->started ) {
0731         gr1553rt_stop(priv);
0732     }
0733 
0734     /* Remove ISR handler */
0735     drvmgr_interrupt_unregister(*priv->pdev, 0, gr1553rt_isr, priv);
0736 
0737     /* Free dynamically allocated buffers if any */
0738     gr1553rt_sw_free(priv);
0739     SPIN_FREE(&priv->devlock);
0740 
0741     /* Return RT/BC device */
0742     gr1553_rt_close(priv->pdev);
0743 }
0744 
0745 /* Stop Hardware and disable IRQ */
0746 void gr1553rt_hw_stop(struct gr1553rt_priv *priv)
0747 {
0748     uint32_t irqmask;
0749 
0750     /* Disable RT */
0751     GR1553RT_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
0752 
0753     /* Stop BC if not already stopped: BC can not be used simultaneously
0754      * as the RT anyway
0755      */
0756     GR1553RT_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
0757 
0758     /* Turn off RT IRQ generation */
0759     irqmask=GR1553RT_READ_REG(&priv->regs->imask);
0760     irqmask&=~(GR1553B_IRQEN_RTEVE|GR1553B_IRQEN_RTDE);
0761     GR1553RT_WRITE_REG(&priv->regs->irq, irqmask);
0762 }
0763 
0764 /* Free dynamically allocated buffers, if any */
0765 void gr1553rt_sw_free(struct gr1553rt_priv *priv)
0766 {
0767     /* Event log */
0768     if ( (priv->cfg.evlog_buffer == NULL) && priv->evlog_buffer ) {
0769         free(priv->evlog_buffer);
0770         priv->evlog_buffer = NULL;
0771     }
0772 
0773     /* RX/TX Descriptors */
0774     if ( (priv->cfg.bd_buffer == NULL) && priv->bd_buffer ) {
0775         free(priv->bd_buffer);
0776         priv->bd_buffer = NULL;
0777     }
0778 
0779 #if (RTBD_MAX == 0)
0780     if ( priv->swbds ) {
0781         free(priv->swbds);
0782         priv->swbds = NULL;
0783     }
0784 #endif
0785 
0786     /* Sub address table */
0787     if ( (priv->cfg.satab_buffer == NULL) && priv->satab_buffer ) {
0788         free(priv->satab_buffer);
0789         priv->satab_buffer = NULL;
0790     }
0791 }
0792 
0793 static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
0794 {
0795     int size;
0796     int retval = 0;
0797 
0798     /* Allocate Event log */
0799     if ((unsigned int)priv->cfg.evlog_buffer & 1) {
0800         /* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
0801         priv->evlog_buffer = (void *)
0802             ((unsigned int)priv->cfg.evlog_buffer & ~0x1);
0803         priv->evlog_hw_base = (unsigned int*)priv->evlog_buffer;
0804         drvmgr_translate_check(
0805             *priv->pdev,
0806             DMAMEM_TO_CPU,
0807             (void *)priv->evlog_hw_base,
0808             (void **)&priv->evlog_cpu_base,
0809             priv->cfg.evlog_size
0810             );
0811     } else {
0812         if (priv->cfg.evlog_buffer == NULL) {
0813             priv->evlog_buffer = grlib_malloc(
0814                 priv->cfg.evlog_size * 2);
0815             if (priv->evlog_buffer == NULL) {
0816                 retval = -1;
0817                 goto err;
0818             }
0819             /* Align to SIZE bytes boundary */
0820             priv->evlog_cpu_base = (unsigned int *)
0821                 (((unsigned int)priv->evlog_buffer +
0822                 (priv->cfg.evlog_size-1)) & ~(priv->cfg.evlog_size-1));
0823         } else {
0824             /* Addess already CPU-LOCAL */
0825             priv->evlog_buffer = priv->cfg.evlog_buffer;
0826             priv->evlog_cpu_base  = (unsigned int *)priv->evlog_buffer;
0827         }
0828 
0829         drvmgr_translate_check(
0830             *priv->pdev,
0831             CPUMEM_TO_DMA,
0832             (void *)priv->evlog_cpu_base,
0833             (void **)&priv->evlog_hw_base,
0834             priv->cfg.evlog_size
0835             );
0836     }
0837     /* Verify alignment */
0838     if ((unsigned int)priv->evlog_hw_base & (priv->cfg.evlog_size-1)) {
0839         retval = -2;
0840         goto err;
0841     }
0842     priv->evlog_cpu_end = priv->evlog_cpu_base +
0843                 priv->cfg.evlog_size/sizeof(unsigned int *);
0844 
0845     /* Allocate Transfer Descriptors */
0846     priv->bds_cnt = priv->cfg.bd_count;
0847     size = priv->bds_cnt * sizeof(struct gr1553rt_bd);
0848     if ((unsigned int)priv->cfg.bd_buffer & 1) {
0849         /* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
0850         priv->bd_buffer = (void *)
0851             ((unsigned int)priv->cfg.bd_buffer & ~0x1);
0852         priv->bds_hw = (struct gr1553rt_bd *)priv->bd_buffer;
0853         drvmgr_translate_check(
0854             *priv->pdev,
0855             DMAMEM_TO_CPU,
0856             (void *)priv->bds_hw,
0857             (void **)&priv->bds_cpu,
0858             size
0859             );
0860     } else {
0861         if ( priv->cfg.bd_buffer == NULL ) {
0862             priv->bd_buffer = grlib_malloc(size + 0xf);
0863             if (priv->bd_buffer == NULL) {
0864                 retval = -1;
0865                 goto err;
0866             }
0867             /* Align to 16 bytes boundary */
0868             priv->bds_cpu = (struct gr1553rt_bd *)
0869                 (((unsigned int)priv->bd_buffer + 0xf) & ~0xf);
0870         } else {
0871             /* Addess already CPU-LOCAL */
0872             priv->bd_buffer = priv->cfg.bd_buffer;
0873             priv->bds_cpu = (struct gr1553rt_bd *)priv->bd_buffer;
0874         }
0875 
0876         /* Translate from CPU address to hardware address */
0877         drvmgr_translate_check(
0878             *priv->pdev,
0879             CPUMEM_TO_DMA,
0880             (void *)priv->bds_cpu,
0881             (void **)&priv->bds_hw,
0882             size
0883             );
0884     }
0885     /* Verify alignment */
0886     if ((unsigned int)priv->bds_hw & (0xf)) {
0887         retval = -2;
0888         goto err;
0889     }
0890 
0891 #if (RTBD_MAX == 0)
0892     /* Allocate software description of */
0893     priv->swbds = grlib_malloc(priv->cfg.bd_count * sizeof(*priv->swbds));
0894     if ( priv->swbds == NULL ) {
0895         retval = -1;
0896         goto err;
0897     }
0898 #endif
0899 
0900     /* Allocate Sub address table */
0901     if ((unsigned int)priv->cfg.satab_buffer & 1) {
0902         /* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
0903         priv->satab_buffer = (void *)
0904             ((unsigned int)priv->cfg.satab_buffer & ~0x1);
0905         priv->sas_hw = (struct gr1553rt_sa *)priv->satab_buffer;
0906 
0907         drvmgr_translate_check(
0908             *priv->pdev,
0909             DMAMEM_TO_CPU,
0910             (void *)priv->sas_hw,
0911             (void **)&priv->sas_cpu,
0912             16 * 32);
0913     } else {
0914         if (priv->cfg.satab_buffer == NULL) {
0915             priv->satab_buffer = grlib_malloc((16 * 32) * 2);
0916             if (priv->satab_buffer == NULL) {
0917                 retval = -1;
0918                 goto err;
0919             }
0920             /* Align to 512 bytes boundary */
0921             priv->sas_cpu = (struct gr1553rt_sa *)
0922                 (((unsigned int)priv->satab_buffer + 0x1ff) & ~0x1ff);
0923         } else {
0924             /* Addess already CPU-LOCAL */
0925             priv->satab_buffer = priv->cfg.satab_buffer;
0926             priv->sas_cpu = (struct gr1553rt_sa *)priv->satab_buffer;
0927         }
0928 
0929         /* Translate Address from CPU-LOCAL to HARDWARE (REMOTE) */
0930         drvmgr_translate_check(
0931             *priv->pdev,
0932             CPUMEM_TO_DMA,
0933             (void *)priv->sas_cpu,
0934             (void **)&priv->sas_hw,
0935             16 * 32);
0936     }
0937     /* Verify alignment */
0938     if ((unsigned int)priv->sas_hw & (0x1ff)) {
0939         retval = -2;
0940         goto err;
0941     }
0942 
0943 err:
0944     if (retval) {
0945         gr1553rt_sw_free(priv);
0946     }
0947     return retval;
0948 }
0949 
0950 void gr1553rt_sw_init(struct gr1553rt_priv *priv)
0951 {
0952     int i;
0953 
0954     /* Clear Sub Address table */
0955     memset(priv->sas_cpu, 0, 512);
0956 
0957     /* Clear Transfer descriptors */
0958     memset(priv->bds_cpu, 0, priv->bds_cnt * 16);
0959 
0960     /* Clear the Event log */
0961     memset(priv->evlog_cpu_base, 0, priv->cfg.evlog_size);
0962 
0963     /* Init descriptor allocation algorithm */
0964     gr1553rt_bd_alloc_init(priv, priv->bds_cnt);
0965 
0966     /* Init table used to convert from sub address to list.
0967      * Currently non assigned.
0968      */
0969     for (i=0; i<32; i++) {
0970         priv->subadrs[i].rxlistid = 0xff;
0971         priv->subadrs[i].txlistid = 0xff;
0972     }
0973 
0974     /* Clear all previous IRQ handlers */
0975     for (i=0; i<32; i++) {
0976         priv->irq_rx[i].func = NULL;
0977         priv->irq_tx[i].data = NULL;
0978     }
0979     priv->irq_err.func = NULL;
0980     priv->irq_err.data = NULL;
0981     priv->irq_mc.func = NULL;
0982     priv->irq_mc.data = NULL;
0983 
0984     /* Clear LIST to LISTID table */
0985     for (i=0; i<RTLISTID_MAX; i++) {
0986         priv->lists[i] = NULL;
0987     }
0988 }
0989 
0990 int gr1553rt_config(void *rt, struct gr1553rt_cfg *cfg)
0991 {
0992     struct gr1553rt_priv *priv = rt;
0993     int retval = 0;
0994     if ( priv->started )
0995         return -1;
0996 
0997     /*** Free dynamically allocated buffers ***/
0998 
0999     gr1553rt_sw_free(priv);
1000 
1001     /*** Check new config ***/
1002     if ( cfg->rtaddress > 30 )
1003         return -1;
1004     if ( (cfg->evlog_size & (cfg->evlog_size-1)) != 0)
1005         return -2; /* SIZE: Not aligned to a power of 2 */
1006     if ( ((unsigned int)priv->cfg.evlog_buffer & (cfg->evlog_size-1)) != 0 )
1007         return -2; /* Buffer: Not aligned to size */
1008 #if (RTBD_MAX > 0)
1009     if ( cfg->bd_count > RTBD_MAX )
1010         return -1;
1011 #endif
1012 
1013     /*** Make new config current ***/
1014     priv->cfg = *cfg;
1015 
1016     /*** Adapt to new config ***/
1017 
1018     if ( (retval=gr1553rt_sw_alloc(priv)) != 0 ) {
1019         return retval;
1020     }
1021 
1022     gr1553rt_sw_init(priv);
1023 
1024     return 0;
1025 }
1026 
1027 int gr1553rt_start(void *rt)
1028 {
1029     struct gr1553rt_priv *priv = rt;
1030     SPIN_IRQFLAGS(irqflags);
1031 
1032     if ( priv->started )
1033         return -1;
1034 
1035     /*** Initialize software Pointers and stuff ***/
1036 
1037     if ( !priv->satab_buffer || !priv->bd_buffer || !priv->evlog_buffer )
1038         return -2;
1039 
1040     priv->evlog_cpu_next = priv->evlog_cpu_base;
1041 
1042     /*** Initialize Registers ***/
1043 
1044     /* Subaddress table base */
1045     priv->regs->rt_tab = (unsigned int)priv->sas_hw;
1046 
1047     /* Mode code configuration */
1048     priv->regs->rt_mcctrl = priv->cfg.modecode;
1049 
1050     /* RT Time Tag resolution */
1051     priv->regs->rt_ttag = priv->cfg.time_res << 16;
1052 
1053     /* Event LOG base and size */
1054     priv->regs->rt_evsz = ~(priv->cfg.evlog_size - 1);
1055     priv->regs->rt_evlog = (unsigned int)priv->evlog_hw_base;
1056     priv->regs->rt_evirq = 0;
1057 
1058     /* Clear and old IRQ flag and Enable IRQ */
1059     SPIN_LOCK_IRQ(&priv->devlock, irqflags);
1060     priv->regs->irq = GR1553B_IRQ_RTEV|GR1553B_IRQ_RTD|GR1553B_IRQ_RTTE;
1061     priv->regs->imask |= GR1553B_IRQEN_RTEVE | GR1553B_IRQEN_RTDE |
1062             GR1553B_IRQEN_RTTEE;
1063 
1064     /* Enable and Set RT address */
1065     priv->regs->rt_cfg = GR1553RT_KEY |
1066             (priv->cfg.rtaddress << GR1553B_RT_CFG_RTADDR_BIT) |
1067             GR1553B_RT_CFG_RTEN;
1068 
1069     /* Tell software RT is started */
1070     priv->started = 1;
1071     SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
1072 
1073     return 0;
1074 }
1075 
1076 void gr1553rt_stop(void *rt)
1077 {
1078     struct gr1553rt_priv *priv = rt;
1079     SPIN_IRQFLAGS(irqflags);
1080 
1081     SPIN_LOCK_IRQ(&priv->devlock, irqflags);
1082 
1083     /* Stop Hardware */
1084     gr1553rt_hw_stop(priv);
1085 
1086     /* Software state */
1087     priv->started = 0;
1088 
1089     SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
1090 }
1091 
1092 void gr1553rt_sa_schedule(
1093     void *rt,
1094     int subadr,
1095     int tx,
1096     struct gr1553rt_list *list
1097     )
1098 {
1099     struct gr1553rt_priv *priv = rt;
1100     unsigned short bdid;
1101     struct gr1553rt_bd *bd;
1102 
1103     if ( !list || (list->listid == -1) )
1104         return;
1105 
1106     /* Get Hardware address of first descriptor in list */
1107     bdid = list->bds[0];
1108     if ( bdid == 0xffff )
1109         return;
1110     bd = &priv->bds_hw[bdid];
1111 
1112     list->subadr = subadr;
1113 
1114     /* Update Sub address table */
1115     if ( tx ) {
1116         list->subadr |= 0x100;
1117         priv->subadrs[subadr].txlistid = list->listid;
1118         priv->sas_cpu[subadr].txptr = (unsigned int)bd;
1119     } else {
1120         priv->subadrs[subadr].rxlistid = list->listid;
1121         priv->sas_cpu[subadr].rxptr = (unsigned int)bd;
1122     }
1123 }
1124 
1125 void gr1553rt_sa_setopts(
1126     void *rt,
1127     int subadr,
1128     unsigned int mask,
1129     unsigned int options
1130     )
1131 {
1132     struct gr1553rt_priv *priv = rt;
1133     unsigned int ctrl;
1134 
1135     if ( (subadr > 31) || (priv->sas_cpu == NULL) )
1136         return;
1137 
1138     ctrl = priv->sas_cpu[subadr].ctrl;
1139     priv->sas_cpu[subadr].ctrl = (ctrl & ~mask) | options;
1140 }
1141 
1142 void gr1553rt_set_vecword(void *rt, unsigned int mask, unsigned int words)
1143 {
1144     struct gr1553rt_priv *priv = rt;
1145     unsigned int vword;
1146 
1147     if ( mask == 0 )
1148         return;
1149 
1150     vword = priv->regs->rt_statw;
1151 
1152     priv->regs->rt_statw = (vword & ~mask) | (words & mask);
1153 }
1154 
1155 void gr1553rt_set_bussts(void *rt, unsigned int mask, unsigned int sts)
1156 {
1157     struct gr1553rt_priv *priv = rt;
1158     unsigned int stat;
1159 
1160     stat = priv->regs->rt_stat2;
1161     priv->regs->rt_stat2 = (stat & ~mask) | (mask & sts);
1162 }
1163 
1164 void gr1553rt_status(void *rt, struct gr1553rt_status *status)
1165 {
1166     struct gr1553rt_priv *priv = rt;
1167     struct gr1553b_regs *regs = priv->regs;
1168     unsigned int tmp;
1169     SPIN_IRQFLAGS(irqflags);
1170 
1171     SPIN_LOCK_IRQ(&priv->devlock, irqflags);
1172     status->status = regs->rt_stat;
1173     status->bus_status = regs->rt_stat2;
1174 
1175     tmp = regs->rt_sync;
1176     status->synctime = tmp >> 16;
1177     status->syncword = tmp & 0xffff;
1178 
1179     tmp = regs->rt_ttag;
1180     status->time_res = tmp >> 16;
1181     status->time = tmp & 0xffff;
1182 
1183     SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
1184 }
1185 
1186 void gr1553rt_list_sa(struct gr1553rt_list *list, int *subadr, int *tx)
1187 {
1188     int sa, trt;
1189 
1190     if ( list->subadr == -1 ) {
1191         sa = -1;
1192         trt = -1;
1193     } else {
1194         sa = list->subadr & 0xff;
1195         trt = (list->subadr & 0x100) >> 8;
1196     }
1197 
1198     if ( subadr )
1199         *subadr = sa;
1200     if ( tx )
1201         *tx = trt;
1202 }
1203 
1204 int gr1553rt_evlog_read(void *rt, unsigned int *dst, int max)
1205 {
1206     struct gr1553rt_priv *priv = rt;
1207     int cnt, top, bot, left;
1208     unsigned int *hwpos;
1209 
1210     /* Get address of hardware's current working entry */
1211     hwpos = (unsigned int *)priv->regs->rt_evlog;
1212 
1213     /* Convert into CPU address */
1214     hwpos = (unsigned int *)
1215         ((unsigned int)hwpos - (unsigned int)priv->evlog_hw_base +
1216         (unsigned int)priv->evlog_cpu_base);
1217 
1218     if ( priv->evlog_cpu_next == hwpos )
1219         return 0;
1220 
1221     if ( priv->evlog_cpu_next > hwpos ) {
1222         top = (unsigned int)priv->evlog_cpu_end -
1223             (unsigned int)priv->evlog_cpu_next;
1224         bot = (unsigned int)hwpos - (unsigned int)priv->evlog_cpu_base;
1225     } else {
1226         top = (unsigned int)hwpos - (unsigned int)priv->evlog_cpu_next;
1227         bot = 0;
1228     }
1229     top = top / 4;
1230     bot = bot / 4;
1231 
1232     left = max;
1233     if ( top > 0 ) {
1234         if ( top > left ) {
1235             cnt = left;
1236         } else {
1237             cnt = top;
1238         }
1239         memcpy(dst, priv->evlog_cpu_next, cnt*4);
1240         dst += cnt;
1241         left -= cnt;
1242     }
1243 
1244     if ( (bot > 0) && (left > 0) ) {
1245         if ( bot > left ) {
1246             cnt = left;
1247         } else {
1248             cnt = bot;
1249         }
1250         memcpy(dst, priv->evlog_cpu_base, cnt*4);
1251         left -= cnt;
1252     }
1253 
1254     cnt = max - left;
1255     priv->evlog_cpu_next += cnt;
1256     if ( priv->evlog_cpu_next >= priv->evlog_cpu_end ) {
1257         priv->evlog_cpu_next = (unsigned int *)
1258             ((unsigned int)priv->evlog_cpu_base +
1259             ((unsigned int)priv->evlog_cpu_next -
1260              (unsigned int)priv->evlog_cpu_end ));
1261     }
1262 
1263     return max - left;
1264 }