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 BC 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 <stdlib.h>
0031 #include <string.h>
0032 #include <rtems.h>
0033 #include <drvmgr/drvmgr.h>
0034 #include <grlib/ambapp_bus.h>
0035 
0036 #include <grlib/gr1553b.h>
0037 #include <grlib/gr1553bc.h>
0038 
0039 #include <grlib/grlib_impl.h>
0040 
0041 #define GR1553BC_WRITE_MEM(adr, val) *(volatile uint32_t *)(adr) = (uint32_t)(val)
0042 #define GR1553BC_READ_MEM(adr) (*(volatile uint32_t *)(adr))
0043 
0044 #define GR1553BC_WRITE_REG(adr, val) *(volatile uint32_t *)(adr) = (uint32_t)(val)
0045 #define GR1553BC_READ_REG(adr) (*(volatile uint32_t *)(adr))
0046 
0047 /* Needed by list for data pinter and BD translation */
0048 struct gr1553bc_priv {
0049     struct drvmgr_dev **pdev;
0050     struct gr1553b_regs *regs;
0051     struct gr1553bc_list *list;
0052     struct gr1553bc_list *alist;
0053     int started;
0054     SPIN_DECLARE(devlock);
0055 
0056     /* IRQ log management */
0057     void *irq_log_p;
0058     uint32_t *irq_log_base;
0059     uint32_t *irq_log_curr;
0060     uint32_t *irq_log_end;
0061     uint32_t *irq_log_base_hw;
0062 
0063     /* Standard IRQ handler function */
0064     bcirq_func_t irq_func;
0065     void *irq_data;
0066 };
0067 
0068 
0069 /*************** LIST HANDLING ROUTINES ***************/
0070 
0071 /* This marks that the jump is a jump to next Minor.
0072  * It is important that it sets one of the two LSB
0073  * so that we can separate it from a JUMP-IRQ function,
0074  * function pointers must be aligned to 4bytes.
0075  *
0076  * This marker is used to optimize the INDICATION process,
0077  * from a descriptor pointer we can step to next Jump that
0078  * has this MARKER set, then we know that the MID is stored
0079  * there.
0080  *
0081  * The marker is limited to 1 byte.
0082  */
0083 #define NEXT_MINOR_MARKER 0x01
0084 
0085 /* To separate ASYNC list from SYNC list we mark them differently, but with
0086  * LSB always set. This can be used to get the list the descriptor is a part
0087  * of.
0088  */
0089 #define NEXT_MINOR_MARKER_ASYNC 0x80
0090 
0091 struct gr1553bc_list_cfg gr1553bc_def_cfg =
0092 {
0093     .rt_timeout =
0094         {
0095             20, 20, 20, 20,
0096             20, 20, 20, 20,
0097             20, 20, 20, 20,
0098             20, 20, 20, 20,
0099             20, 20, 20, 20,
0100             20, 20, 20, 20,
0101             20, 20, 20, 20,
0102             20, 20, 20
0103         },
0104     .bc_timeout = 30,
0105     .tropt_irq_on_err = 0,
0106     .tropt_pause_on_err = 0,
0107     .async_list = 0,
0108 };
0109 
0110 int gr1553bc_list_alloc(struct gr1553bc_list **list, int max_major)
0111 {
0112     size_t size;
0113     struct gr1553bc_list *l;
0114 
0115     size = sizeof(*l) + max_major * sizeof(void *);
0116     l = grlib_calloc(1, size);
0117     if ( l == NULL )
0118         return -1;
0119 
0120     l->major_cnt = max_major;
0121     *list = l;
0122 
0123     /* Set default options:
0124      *  - RT timeout tolerance 20us
0125      *  - Global transfer options used when generating transfer descriptors
0126      *  - No BC device, note that this only works when no translation is
0127      *    required
0128      */
0129     if ( gr1553bc_list_config(l, &gr1553bc_def_cfg, NULL) ) {
0130         free(l);
0131         return -1;
0132     }
0133 
0134     return 0;
0135 }
0136 
0137 void gr1553bc_list_free(struct gr1553bc_list *list)
0138 {
0139     gr1553bc_list_table_free(list);
0140     free(list);
0141 }
0142 
0143 int gr1553bc_list_config
0144     (
0145     struct gr1553bc_list *list,
0146     struct gr1553bc_list_cfg *cfg,
0147     void *bc
0148     )
0149 {
0150     int timeout, i, tropts;
0151 
0152     /* RT Time Tolerances */
0153     for (i=0; i<31; i++) {
0154         /* 0=14us, 1=18us ... 0xf=74us
0155          * round upwards: 15us will be 18us
0156          */
0157         timeout = ((cfg->rt_timeout[i] + 1)  - 14) / 4;
0158         if ( (timeout > 0xf) || (timeout < 0) )
0159             return -1;
0160         list->rt_timeout[i] = timeout;
0161     }
0162     timeout = ((cfg->bc_timeout + 1) - 14) / 4;
0163     if ( timeout > 0xf )
0164         return -1;
0165     list->rt_timeout[i] = timeout;
0166 
0167     /* Transfer descriptor generation options */
0168     tropts = 0;
0169     if ( cfg->tropt_irq_on_err )
0170         tropts |= 1<<28;
0171     if ( cfg->tropt_pause_on_err )
0172         tropts |= 1<<26;
0173     list->tropts = tropts;
0174 
0175     list->async_list = cfg->async_list;
0176     list->bc = bc;
0177 
0178     return 0;
0179 }
0180 
0181 void gr1553bc_list_link_major(
0182     struct gr1553bc_major *major,
0183     struct gr1553bc_major *next
0184     )
0185 {
0186     if ( major ) {
0187         major->next = next;
0188         if ( next ) {
0189             major->minors[major->cfg->minor_cnt-1]->next =
0190                 next->minors[0];
0191         } else {
0192             major->minors[major->cfg->minor_cnt-1]->next = NULL;
0193         }
0194     }
0195 }
0196 
0197 int gr1553bc_list_set_major(
0198     struct gr1553bc_list *list,
0199     struct gr1553bc_major *major,
0200     int no)
0201 {
0202     struct gr1553bc_major *prev, *next;
0203 
0204     if ( no >= list->major_cnt )
0205         return -1;
0206 
0207     list->majors[no] = major;
0208 
0209     /* Link previous Major frame with this one */
0210     if ( no > 0 ) {
0211         prev = list->majors[no-1];
0212     } else {
0213         /* First Major is linked with last major */
0214         prev = list->majors[list->major_cnt-1];
0215     }
0216 
0217     /* Link to next Major if not the last one and if there is
0218      * a next major
0219      */
0220     if ( no == list->major_cnt-1 ) {
0221         /* The last major, assume that it is connected with the first */
0222         next = list->majors[0];
0223     } else {
0224         next = list->majors[no+1];
0225     }
0226 
0227     /* Link previous frame to jump into this */
0228     gr1553bc_list_link_major(prev, major);
0229 
0230     /* Link This frame to jump into the next */
0231     gr1553bc_list_link_major(major, next);
0232 
0233     return 0;
0234 }
0235 
0236 /* Translate Descriptor address from CPU-address to Hardware Address */
0237 static inline union gr1553bc_bd *gr1553bc_bd_cpu2hw
0238     (
0239     struct gr1553bc_list *list,
0240     union gr1553bc_bd *bd
0241     )
0242 {
0243     return (union gr1553bc_bd *)(((unsigned int)bd - list->table_cpu) +
0244         list->table_hw);
0245 }
0246 
0247 /* Translate Descriptor address from HW-address to CPU Address */
0248 static inline union gr1553bc_bd *gr1553bc_bd_hw2cpu
0249     (
0250     struct gr1553bc_list *list,
0251     union gr1553bc_bd *bd
0252     )
0253 {
0254     return (union gr1553bc_bd *)(((unsigned int)bd - list->table_hw) +
0255         list->table_cpu);
0256 }
0257 
0258 int gr1553bc_minor_table_size(struct gr1553bc_minor *minor)
0259 {
0260     struct gr1553bc_minor_cfg *mincfg = minor->cfg;
0261     int slot_cnt;
0262 
0263     /* SLOTS + JUMP */
0264     slot_cnt = mincfg->slot_cnt + 1;
0265     if ( mincfg->timeslot ) {
0266         /* time management requires 1 extra slot */
0267         slot_cnt++;
0268     }
0269 
0270     return slot_cnt * GR1553BC_BD_SIZE;
0271 }
0272 
0273 int gr1553bc_list_table_size(struct gr1553bc_list *list)
0274 {
0275     struct gr1553bc_major *major;
0276     int i, j, minor_cnt, size;
0277 
0278     size = 0;
0279     for (i=0; i<list->major_cnt; i++) {
0280         major = list->majors[i];
0281         minor_cnt = major->cfg->minor_cnt;
0282         for (j=0; j<minor_cnt; j++) {
0283             /* 128-bit Alignment required by HW */
0284             size += (GR1553BC_BD_ALIGN -
0285                 (size & (GR1553BC_BD_ALIGN-1))) &
0286                 ~(GR1553BC_BD_ALIGN-1);
0287 
0288             /* Size required by descriptors */
0289             size += gr1553bc_minor_table_size(major->minors[j]);
0290         }
0291     }
0292 
0293     return size;
0294 }
0295 
0296 int gr1553bc_list_table_alloc
0297     (
0298     struct gr1553bc_list *list,
0299     void *bdtab_custom
0300     )
0301 {
0302     struct gr1553bc_major *major;
0303     int i, j, minor_cnt, size;
0304     unsigned int table;
0305     struct gr1553bc_priv *bcpriv = list->bc;
0306     int retval = 0;
0307 
0308     /* Free previous allocated descriptor table */
0309     gr1553bc_list_table_free(list);
0310 
0311     /* Remember user's settings for uninitialization */
0312     list->_table_custom = bdtab_custom;
0313 
0314     /* Get Size required for descriptors */
0315     size = gr1553bc_list_table_size(list);
0316 
0317     if ((unsigned int)bdtab_custom & 0x1) {
0318         /* Address given in Hardware accessible address, we
0319          * convert it into CPU-accessible address.
0320          */
0321         list->_table = (void*)((unsigned int)bdtab_custom & ~0x1);
0322         list->table_hw = (unsigned int)list->_table;
0323         drvmgr_translate_check(
0324             *bcpriv->pdev,
0325             DMAMEM_TO_CPU,
0326             (void *)list->table_hw,
0327             (void **)&list->table_cpu,
0328             size);
0329     } else {
0330         if (bdtab_custom == NULL) {
0331             /* Allocate descriptors */
0332             list->_table = grlib_malloc(size + (GR1553BC_BD_ALIGN-1));
0333             if ( list->_table == NULL ) {
0334                 retval = -1;
0335                 goto err;
0336             }
0337             /* 128-bit Alignment required by HW */
0338             list->table_cpu =
0339                 (((unsigned int)list->_table + (GR1553BC_BD_ALIGN-1)) &
0340                 ~(GR1553BC_BD_ALIGN-1));
0341         } else {
0342             /* Custom address, given in CPU-accessible address */
0343             list->_table = bdtab_custom;
0344             list->table_cpu = (unsigned int)list->_table;
0345         }
0346 
0347         /* We got CPU accessible descriptor table address, now we
0348          * translate that into an address that the Hardware can
0349          * understand
0350          */
0351         if (bcpriv) {
0352             drvmgr_translate_check(
0353                 *bcpriv->pdev,
0354                 CPUMEM_TO_DMA,
0355                 (void *)list->table_cpu,
0356                 (void **)&list->table_hw,
0357                 size
0358                 );
0359         } else {
0360             list->table_hw = list->table_cpu;
0361         }
0362     }
0363 
0364     /* Verify alignment */
0365     if (list->table_hw & (GR1553BC_BD_ALIGN-1)) {
0366         retval = -2;
0367         goto err;
0368     }
0369 
0370     /* Write End-Of-List all over the descriptor table here,
0371      * For debugging/safety?
0372      */
0373 
0374     /* Assign descriptors to all minor frames. The addresses is
0375      * CPU-accessible addresses.
0376      */
0377     table = list->table_cpu;
0378     for (i=0; i<list->major_cnt; i++) {
0379         major = list->majors[i];
0380         minor_cnt = major->cfg->minor_cnt;
0381         for (j=0; j<minor_cnt; j++) {
0382             /* 128-bit Alignment required by HW */
0383             table = (table + (GR1553BC_BD_ALIGN-1)) &
0384                 ~(GR1553BC_BD_ALIGN-1);
0385             major->minors[j]->bds = (union gr1553bc_bd *)table;
0386 
0387             /* Calc size required by descriptors */
0388             table += gr1553bc_minor_table_size(major->minors[j]);
0389         }
0390     }
0391 err:
0392     if (retval) {
0393         if (list->_table_custom == NULL && list->_table) {
0394             free(list->_table);
0395         }
0396         list->table_hw = 0;
0397         list->table_cpu = 0;
0398         list->_table = NULL;
0399     }
0400     return retval;
0401 }
0402 
0403 void gr1553bc_list_table_free(struct gr1553bc_list *list)
0404 {
0405     if ( (list->_table_custom == NULL) && list->_table ) {
0406         free(list->_table);
0407     }
0408     list->_table = NULL;
0409     list->_table_custom = NULL;
0410     list->table_cpu = 0;
0411     list->table_hw = 0;
0412 }
0413 
0414 /* Init descriptor table provided by each minor frame,
0415  * we link them together using unconditional JUMP.
0416  */
0417 int gr1553bc_list_table_build(struct gr1553bc_list *list)
0418 {
0419     struct gr1553bc_major *major;
0420     struct gr1553bc_minor *minor;
0421     struct gr1553bc_minor_cfg *mincfg;
0422     int i, j, k, minor_cnt, marker;
0423     union gr1553bc_bd *bds, *hwbd;
0424 
0425     marker = NEXT_MINOR_MARKER;
0426     if ( list->async_list )
0427         marker |= NEXT_MINOR_MARKER_ASYNC;
0428 
0429     /* Create Major linking */
0430     for (i=0; i<list->major_cnt; i++) {
0431         major = list->majors[i];
0432         minor_cnt = major->cfg->minor_cnt;
0433         for (j=0; j<minor_cnt; j++) {
0434             minor = major->minors[j];
0435             mincfg = minor->cfg;
0436             bds = minor->bds;
0437 
0438             /* BD[0..SLOTCNT-1] = message slots
0439              * BD[SLOTCNT+0] = END
0440              * BD[SLOTCNT+1] = JUMP
0441              *
0442              * or if no optional time slot handling:
0443              *
0444              * BD[0..SLOTCNT-1] = message slots
0445              * BD[SLOTCNT] = JUMP
0446              */
0447 
0448             /* BD[0..SLOTCNT-1] */
0449             for (k=0; k<mincfg->slot_cnt; k++) {
0450                 gr1553bc_bd_tr_init(
0451                     &bds[k].tr,
0452                     GR1553BC_TR_DUMMY_0,
0453                     GR1553BC_TR_DUMMY_1,
0454                     0,
0455                     0);
0456             }
0457 
0458             /* BD[SLOTCNT] (OPTIONAL)
0459              * If a minor frame is configured to be executed in
0460              * certain time (given a time slot), this descriptor
0461              * sums up all unused time. The time slot is
0462              * decremented when messages are inserted into the
0463              * minor frame and increased when messages are removed.
0464              */
0465             if ( mincfg->timeslot > 0 ) {
0466                 gr1553bc_bd_tr_init(
0467                     &bds[k].tr,
0468                     GR1553BC_TR_DUMMY_0 | (mincfg->timeslot >> 2),
0469                     GR1553BC_TR_DUMMY_1,
0470                     0,
0471                     0);
0472                 k++;
0473             }
0474 
0475             /* Last descriptor is a jump to next minor frame, to a
0476              * synchronization point. If chain ends here, the list
0477              * is marked with a "end-of-list" marker.
0478              *
0479              */
0480             if ( minor->next ) {
0481                 /* Translate CPU address of BD into HW address */
0482                 hwbd = gr1553bc_bd_cpu2hw(
0483                     list,
0484                     &minor->next->bds[0]
0485                     );
0486                 gr1553bc_bd_init(
0487                     &bds[k],
0488                     0xf,
0489                     GR1553BC_UNCOND_JMP,
0490                     (uint32_t)hwbd,
0491                     ((GR1553BC_ID(i,j,k) << 8) | marker),
0492                     0
0493                     );
0494             } else {
0495                 gr1553bc_bd_init(
0496                     &bds[k],
0497                     0xf,
0498                     GR1553BC_TR_EOL,
0499                     0,
0500                     ((GR1553BC_ID(i,j,k) << 8) | marker),
0501                     0);
0502             }
0503         }
0504     }
0505 
0506     return 0;
0507 }
0508 
0509 void gr1553bc_bd_init(
0510     union gr1553bc_bd *bd,
0511     unsigned int flags,
0512     uint32_t word0,
0513     uint32_t word1,
0514     uint32_t word2,
0515     uint32_t word3
0516     )
0517 {
0518     struct gr1553bc_bd_raw *raw = &bd->raw;
0519 
0520     if ( flags & 0x1 ) {
0521         if ( (flags & KEEP_TIMESLOT) &&
0522              ((word0 & GR1553BC_BD_TYPE) == 0) ) {
0523             /* Don't touch timeslot previously allocated */
0524             word0 &= ~GR1553BC_TR_TIME;
0525             word0 |= GR1553BC_READ_MEM(&raw->words[0]) &
0526                     GR1553BC_TR_TIME;
0527         }
0528         GR1553BC_WRITE_MEM(&raw->words[0], word0);
0529     }
0530     if ( flags & 0x2 )
0531         GR1553BC_WRITE_MEM(&raw->words[1], word1);
0532     if ( flags & 0x4 )
0533         GR1553BC_WRITE_MEM(&raw->words[2], word2);
0534     if ( flags & 0x8 )
0535         GR1553BC_WRITE_MEM(&raw->words[3], word3);
0536 }
0537 
0538 /* Alloc a Major frame according to the configuration structure */
0539 int gr1553bc_major_alloc_skel
0540     (
0541     struct gr1553bc_major **major,
0542     struct gr1553bc_major_cfg *cfg
0543     )
0544 {
0545     struct gr1553bc_major *maj;
0546     struct gr1553bc_minor *minor;
0547     size_t size;
0548     int i;
0549 
0550     if ( (cfg == NULL) || (major == NULL) || (cfg->minor_cnt <= 0) )
0551         return -1;
0552 
0553     /* Allocate Major Frame description, but no descriptors */
0554     size = sizeof(*maj) + cfg->minor_cnt *
0555         (sizeof(*minor) + sizeof(void *));
0556     maj = grlib_malloc(size);
0557     if ( maj == NULL )
0558         return -1;
0559 
0560     maj->cfg = cfg;
0561     maj->next = NULL;
0562 
0563     /* Create links between minor frames, and from minor frames
0564      * to configuration structure.
0565      */
0566     minor = (struct gr1553bc_minor *)&maj->minors[cfg->minor_cnt];
0567     for (i=0; i<cfg->minor_cnt; i++, minor++) {
0568         maj->minors[i] = minor;
0569         minor->next = minor + 1;
0570         minor->cfg = &cfg->minor_cfgs[i];
0571         minor->alloc = 0;
0572         minor->bds = NULL;
0573     }
0574     /* last Minor should point to next Major frame's first minor,
0575      * we do that somewhere else.
0576      */
0577     (minor - 1)->next = NULL;
0578 
0579     *major = maj;
0580 
0581     return 0;
0582 }
0583 
0584 struct gr1553bc_major *gr1553bc_major_from_id
0585     (
0586     struct gr1553bc_list *list,
0587     int mid
0588     )
0589 {
0590     int major_no;
0591 
0592     /* Find Minor Frame from MID */
0593     major_no = GR1553BC_MAJID_FROM_ID(mid);
0594 
0595     if ( major_no >= list->major_cnt )
0596         return NULL;
0597     return list->majors[major_no];
0598 }
0599 
0600 struct gr1553bc_minor *gr1553bc_minor_from_id
0601     (
0602     struct gr1553bc_list *list,
0603     int mid
0604     )
0605 {
0606     int minor_no;
0607     struct gr1553bc_major *major;
0608 
0609     /* Get Major from ID */
0610     major = gr1553bc_major_from_id(list, mid);
0611     if ( major == NULL )
0612         return NULL;
0613 
0614     /* Find Minor Frame from MID */
0615     minor_no = GR1553BC_MINID_FROM_ID(mid);
0616 
0617     if ( minor_no >= major->cfg->minor_cnt )
0618         return NULL;
0619     return major->minors[minor_no];
0620 }
0621 
0622 union gr1553bc_bd *gr1553bc_slot_bd
0623     (
0624     struct gr1553bc_list *list,
0625     int mid
0626     )
0627 {
0628     struct gr1553bc_minor *minor;
0629     int slot_no;
0630 
0631     /*** look up BD ***/
0632 
0633     /* Get minor */
0634     minor = gr1553bc_minor_from_id(list, mid);
0635     if ( minor == NULL )
0636         return NULL;
0637 
0638     /* Get Slot */
0639     slot_no = GR1553BC_SLOTID_FROM_ID(mid);
0640     if ( slot_no >= 0xff )
0641         slot_no = 0;
0642 
0643     /* Get BD address */
0644     return &minor->bds[slot_no];
0645 }
0646 
0647 static int gr1553bc_minor_first_avail(struct gr1553bc_minor *minor)
0648 {
0649     int slot_num;
0650     uint32_t alloc;
0651 
0652     alloc = minor->alloc;
0653     if ( alloc == 0xffffffff ) {
0654         /* No free */
0655         return -1;
0656     }
0657     slot_num = 0;
0658     while ( alloc & 1 ) {
0659         alloc = alloc >> 1;
0660         slot_num++;
0661     }
0662     if ( slot_num >= minor->cfg->slot_cnt ) {
0663         /* no free */
0664         return -1;
0665     }
0666     return slot_num;
0667 }
0668 
0669 int gr1553bc_slot_alloc(
0670     struct gr1553bc_list *list,
0671     int *mid,
0672     int timeslot,
0673     union gr1553bc_bd **bd
0674     )
0675 {
0676     struct gr1553bc_minor *minor = gr1553bc_minor_from_id(list, *mid);
0677 
0678     return gr1553bc_slot_alloc2(minor, mid, timeslot, bd);
0679 }
0680 
0681 /* Same as gr1553bc_slot_alloc but identifies a minor instead of list.
0682  * The major/minor part of MID is ignored.
0683  */
0684 int gr1553bc_slot_alloc2(
0685     struct gr1553bc_minor *minor,
0686     int *mid,
0687     int timeslot,
0688     union gr1553bc_bd **bd
0689     )
0690 {
0691     int slot_no;
0692     uint32_t set0;
0693     int timefree;
0694     struct gr1553bc_bd_tr *trbd;
0695     struct gr1553bc_minor_cfg *mincfg;
0696 
0697     if ( minor == NULL )
0698         return -1;
0699 
0700     mincfg = minor->cfg;
0701 
0702     /* Find first free slot if not a certain slot is requested */
0703     slot_no = GR1553BC_SLOTID_FROM_ID(*mid);
0704     if ( slot_no == 0xff ) {
0705         slot_no = gr1553bc_minor_first_avail(minor);
0706         if ( slot_no < 0 )
0707             return -1;
0708     } else {
0709         /* Allocate a certain slot, check that it is free */
0710         if ( slot_no >= mincfg->slot_cnt )
0711             return -1;
0712         if ( (1<<slot_no) & minor->alloc )
0713             return -1;
0714     }
0715 
0716     /* Ok, we got our slot. Lets allocate time for slot if requested by user
0717      * and time management is enabled for this Minor Frame.
0718      */
0719     if ( timeslot > 0 ) {
0720         /* Make timeslot on a 4us boundary (time resolution of core) */
0721         timeslot = (timeslot + 0x3) >> 2;
0722 
0723         if ( mincfg->timeslot ) {
0724             /* Subtract requested time from free time */
0725             trbd = &minor->bds[mincfg->slot_cnt].tr;
0726             set0 = GR1553BC_READ_MEM(&trbd->settings[0]);
0727             timefree = set0 & GR1553BC_TR_TIME;
0728             if ( timefree < timeslot ) {
0729                 /* Not enough time left to schedule slot in minor */
0730                 return -1;
0731             }
0732             /* Store back the time left */
0733             timefree -= timeslot;
0734             set0 = (set0 & ~GR1553BC_TR_TIME) | timefree;
0735             GR1553BC_WRITE_MEM(&trbd->settings[0], set0);
0736             /* Note: at the moment the minor frame can be executed faster
0737              *       than expected, we hurry up writing requested
0738              *       descriptor.
0739              */
0740         }
0741     }
0742 
0743     /* Make the allocated descriptor be an empty slot with the
0744      * timeslot requested.
0745      */
0746     trbd = &minor->bds[slot_no].tr;
0747     gr1553bc_bd_tr_init(
0748         trbd,
0749         GR1553BC_TR_DUMMY_0 | timeslot,
0750         GR1553BC_TR_DUMMY_1,
0751         0,
0752         0);
0753 
0754     /* Allocate slot */
0755     minor->alloc |= 1<<slot_no;
0756 
0757     if ( bd )
0758         *bd = (union gr1553bc_bd *)trbd;
0759     *mid = GR1553BC_ID_SET_SLOT(*mid, slot_no);
0760 
0761     return 0;
0762 }
0763 
0764 /* Return time slot freed (if time is managed by driver), negative on error */
0765 int gr1553bc_slot_free(struct gr1553bc_list *list, int mid)
0766 {
0767     struct gr1553bc_minor *minor = gr1553bc_minor_from_id(list, mid);
0768 
0769     return gr1553bc_slot_free2(minor, mid);
0770 }
0771 
0772 /* Return time slot freed (if time is managed by driver), negative on error */
0773 int gr1553bc_slot_free2(struct gr1553bc_minor *minor, int mid)
0774 {
0775     union gr1553bc_bd *bd;
0776     struct gr1553bc_bd_tr *endbd;
0777     struct gr1553bc_minor_cfg *mincfg;
0778     int slot_no, timeslot, timefree;
0779     uint32_t word0, set0;
0780 
0781     if ( minor == NULL )
0782         return -1;
0783 
0784     slot_no = GR1553BC_SLOTID_FROM_ID(mid);
0785 
0786     if ( (minor->alloc & (1<<slot_no)) == 0 )
0787         return -1;
0788 
0789     bd = &minor->bds[slot_no];
0790 
0791     /* If the driver handles time for this minor frame, return
0792      * time if previuosly requested.
0793      */
0794     timeslot = 0;
0795     mincfg = minor->cfg;
0796     if ( mincfg->timeslot > 0 ) {
0797         /* Find out if message slot had time allocated */
0798         word0 = GR1553BC_READ_MEM(&bd->raw.words[0]);
0799         if ( word0 & GR1553BC_BD_TYPE ) {
0800             /* Condition ==> no time slot allocated */
0801         } else {
0802             /* Transfer descriptor, may have time slot */
0803             timeslot = word0 & GR1553BC_TR_TIME;
0804             if ( timeslot > 0 ) {
0805                 /* Return previously allocated time to END
0806                  * TIME descriptor.
0807                  */
0808                 endbd = &minor->bds[mincfg->slot_cnt].tr;
0809                 set0 = GR1553BC_READ_MEM(&endbd->settings[0]);
0810                 timefree = set0 & GR1553BC_TR_TIME;
0811                 timefree += timeslot;
0812                 set0 = (set0 & ~GR1553BC_TR_TIME) | timefree;
0813                 GR1553BC_WRITE_MEM(&endbd->settings[0], set0);
0814                 /* Note: at the moment the minor frame can be
0815                  *       executed slower than expected, the
0816                  *       timeslot is at two locations.
0817                  */
0818             }
0819         }
0820     }
0821 
0822     /* Make slot an empty message */
0823     gr1553bc_bd_tr_init(
0824         &bd->tr,
0825         GR1553BC_TR_DUMMY_0,
0826         GR1553BC_TR_DUMMY_1,
0827         0,
0828         0);
0829 
0830     /* unallocate descriptor */
0831     minor->alloc &= ~(1<<slot_no);
0832 
0833     /* Return time freed in microseconds */
0834     return timeslot << 2;
0835 }
0836 
0837 int gr1553bc_list_freetime(struct gr1553bc_list *list, int mid)
0838 {
0839     struct gr1553bc_minor *minor = gr1553bc_minor_from_id(list, mid);
0840 
0841     return gr1553bc_minor_freetime(minor);
0842 }
0843 
0844 int gr1553bc_minor_freetime(struct gr1553bc_minor *minor)
0845 {
0846     struct gr1553bc_bd_tr *endbd;
0847     struct gr1553bc_minor_cfg *mincfg;
0848     int timefree;
0849     uint32_t set0;
0850 
0851     if ( minor == NULL )
0852         return -1;
0853 
0854     /* If the driver handles time for this minor frame, return
0855      * time if previuosly requested.
0856      */
0857     timefree = 0;
0858     mincfg = minor->cfg;
0859     if ( mincfg->timeslot > 0 ) {
0860         /* Return previously allocated time to END
0861          * TIME descriptor.
0862          */
0863         endbd = &minor->bds[mincfg->slot_cnt].tr;
0864         set0 = GR1553BC_READ_MEM(&endbd->settings[0]);
0865         timefree = (set0 & GR1553BC_TR_TIME) << 2;
0866     }
0867 
0868     /* Return time freed */
0869     return timefree;
0870 }
0871 
0872 int gr1553bc_slot_raw
0873     (
0874     struct gr1553bc_list *list,
0875     int mid,
0876     unsigned int flags,
0877     uint32_t word0,
0878     uint32_t word1,
0879     uint32_t word2,
0880     uint32_t word3
0881     )
0882 {
0883     struct gr1553bc_minor *minor;
0884     union gr1553bc_bd *bd;
0885     int slot_no;
0886 
0887     minor = gr1553bc_minor_from_id(list, mid);
0888     if ( minor == NULL )
0889         return -1;
0890 
0891     /* Get Slot */
0892     slot_no = GR1553BC_SLOTID_FROM_ID(mid);
0893     if ( slot_no >= minor->cfg->slot_cnt ) {
0894         return -1;
0895     }
0896 
0897     /* Get descriptor */
0898     bd = &minor->bds[slot_no];
0899 
0900     /* Build empty descriptor. */
0901     gr1553bc_bd_init(
0902         bd,
0903         flags,
0904         word0,
0905         word1,
0906         word2,
0907         word3);
0908 
0909     return 0;
0910 }
0911 
0912 /* Create unconditional IRQ customly defined location
0913  * The IRQ is disabled, enable it with gr1553bc_slot_irq_enable().
0914  */
0915 int gr1553bc_slot_irq_prepare
0916     (
0917     struct gr1553bc_list *list,
0918     int mid,
0919     bcirq_func_t func,
0920     void *data
0921     )
0922 {
0923     union gr1553bc_bd *bd;
0924     int slot_no, to_mid;
0925 
0926     /* Build unconditional IRQ descriptor. The padding is used
0927      * for identifying the MINOR frame and function and custom data.
0928      *
0929      * The IRQ is disabled at first, a unconditional jump to next
0930      * descriptor in table.
0931      */
0932 
0933     /* Get BD address of jump destination */
0934     slot_no = GR1553BC_SLOTID_FROM_ID(mid);
0935     to_mid = GR1553BC_ID_SET_SLOT(mid, slot_no + 1);
0936     bd = gr1553bc_slot_bd(list, to_mid);
0937     if ( bd == NULL )
0938         return -1;
0939     bd = gr1553bc_bd_cpu2hw(list, bd);
0940 
0941     return gr1553bc_slot_raw(
0942         list,
0943         mid,
0944         0xF,
0945         GR1553BC_UNCOND_JMP,
0946         (uint32_t)bd,
0947         (uint32_t)func,
0948         (uint32_t)data
0949         );
0950 }
0951 
0952 /* Enable previously prepared unconditional IRQ */
0953 int gr1553bc_slot_irq_enable(struct gr1553bc_list *list, int mid)
0954 {
0955     /* Leave word1..3 untouched:
0956      *  1. Unconditional Jump address
0957      *  2. Function
0958      *  3. Custom Data
0959      *
0960      * Since only one bit is changed in word0 (Condition word),
0961      * no hardware/software races will exist ==> it is safe
0962      * to enable/disable IRQ at any time independent of where
0963      * hardware is in table.
0964      */
0965     return gr1553bc_slot_raw(
0966         list,
0967         mid,
0968         0x1,    /* change only WORD0 */
0969         GR1553BC_UNCOND_IRQ,
0970         0,
0971         0,
0972         0);
0973 }
0974 
0975 /* Disable unconditional IRQ point, changed to unconditional JUMP
0976  * to descriptor following.
0977  * After disabling it it can be enabled again, or freed.
0978  */
0979 int gr1553bc_slot_irq_disable(struct gr1553bc_list *list, int mid)
0980 {
0981     return gr1553bc_slot_raw(
0982         list,
0983         mid,
0984         0x1,    /* change only WORD0, JUMP address already set */
0985         GR1553BC_UNCOND_JMP,
0986         0,
0987         0,
0988         0);
0989 }
0990 
0991 int gr1553bc_slot_empty(struct gr1553bc_list *list, int mid)
0992 {
0993     return gr1553bc_slot_raw(
0994         list,
0995         mid,
0996         0xF | KEEP_TIMESLOT,
0997         GR1553BC_TR_DUMMY_0,
0998         GR1553BC_TR_DUMMY_1,
0999         0,
1000         0);
1001 }
1002 
1003 int gr1553bc_slot_exttrig(struct gr1553bc_list *list, int mid)
1004 {
1005     return gr1553bc_slot_raw(
1006         list,
1007         mid,
1008         0xF | KEEP_TIMESLOT,
1009         GR1553BC_TR_DUMMY_0 | GR1553BC_TR_EXTTRIG,
1010         GR1553BC_TR_DUMMY_1,
1011         0,
1012         0);
1013 }
1014 
1015 int gr1553bc_slot_jump
1016     (
1017     struct gr1553bc_list *list,
1018     int mid,
1019     uint32_t condition,
1020     int to_mid
1021     )
1022 {
1023     union gr1553bc_bd *bd;
1024 
1025     /* Get BD address */
1026     bd = gr1553bc_slot_bd(list, to_mid);
1027     if ( bd == NULL )
1028         return -1;
1029     /* Convert into an address that the HW understand */
1030     bd = gr1553bc_bd_cpu2hw(list, bd);
1031 
1032     return gr1553bc_slot_raw(
1033         list,
1034         mid,
1035         0xF,
1036         condition,
1037         (uint32_t)bd,
1038         0,
1039         0);
1040 }
1041 
1042 int gr1553bc_slot_transfer(
1043     struct gr1553bc_list *list,
1044     int mid,
1045     int options,
1046     int tt,
1047     uint16_t *dptr)
1048 {
1049     uint32_t set0, set1;
1050     union gr1553bc_bd *bd;
1051     int rx_rtadr, tx_rtadr, timeout;
1052 
1053     /* Get BD address */
1054     bd = gr1553bc_slot_bd(list, mid);
1055     if ( bd == NULL )
1056         return -1;
1057 
1058     /* Translate Data pointer from CPU-local to 1553-core accessible
1059      * address if user wants that. This may be useful for AMBA-over-PCI
1060      * cores.
1061      */
1062     if ( (unsigned int)dptr & 0x1 ) {
1063         struct gr1553bc_priv *bcpriv = list->bc;
1064 
1065         drvmgr_translate(
1066             *bcpriv->pdev,
1067             CPUMEM_TO_DMA,
1068             (void *)((unsigned int)dptr & ~0x1),
1069             (void **)&dptr);
1070     }
1071 
1072     /* It is assumed that the descriptor has already been initialized
1073      * as a empty slot (Dummy bit set), so to avoid races the dummy
1074      * bit is cleared last.
1075      *
1076      * If we knew that the write would do a burst (for example over SpW)
1077      * it would be safe to write in order.
1078      */
1079 
1080     /* Preserve timeslot */
1081     set0 = GR1553BC_READ_MEM(&bd->tr.settings[0]);
1082     set0 &= GR1553BC_TR_TIME;
1083     set0 |= options & 0x61f00000;
1084     set0 |= list->tropts; /* Global options */
1085 
1086     /* Set transfer type, bus and let RT tolerance table descide
1087      * responce tolerance.
1088      *
1089      * If a destination address is specified the longest timeout
1090      * tolerance is taken.
1091      */
1092     rx_rtadr = (tt >> 22) & 0x1f;
1093     tx_rtadr = (tt >> 12) & 0x1f;
1094     if ( (tx_rtadr != 0x1f) &&
1095          (list->rt_timeout[rx_rtadr] < list->rt_timeout[tx_rtadr]) ) {
1096         timeout = list->rt_timeout[tx_rtadr];
1097     } else {
1098         timeout = list->rt_timeout[rx_rtadr];
1099     }
1100     set1 = ((timeout & 0xf) << 27) | (tt & 0x27ffffff) | ((options & 0x3)<<30);
1101 
1102     GR1553BC_WRITE_MEM(&bd->tr.settings[0], set0);
1103     GR1553BC_WRITE_MEM(&bd->tr.dptr, (uint32_t)dptr);
1104     /* Write UNUSED BIT, when cleared it Indicates that BC has written it */
1105     GR1553BC_WRITE_MEM(&bd->tr.status, 0x80000000);
1106     GR1553BC_WRITE_MEM(&bd->tr.settings[1], set1);
1107 
1108     return 0;
1109 }
1110 
1111 int gr1553bc_slot_update
1112     (
1113     struct gr1553bc_list *list,
1114     int mid,
1115     uint16_t *dptr,
1116     unsigned int *stat
1117     )
1118 {
1119     union gr1553bc_bd *bd;
1120     unsigned int status;
1121     unsigned int dataptr = (unsigned int)dptr;
1122 
1123     /* Get BD address */
1124     bd = gr1553bc_slot_bd(list, mid);
1125     if ( bd == NULL )
1126         return -1;
1127 
1128     /* Write new Data Pointer if needed */
1129     if ( dataptr ) {
1130         struct gr1553bc_priv *bcpriv = list->bc;
1131 
1132         /* Translate Data pointer from CPU-local to 1553-core accessible
1133          * address if user wants that. This may be useful for AMBA-over-PCI
1134          * cores.
1135          */
1136         if ( dataptr & 0x1 ) {
1137             drvmgr_translate(
1138                 *bcpriv->pdev,
1139                 CPUMEM_TO_DMA,
1140                 (void *)(dataptr & ~0x1),
1141                 (void **)&dptr
1142                 );
1143         }
1144 
1145         /* Update Data Pointer */
1146         GR1553BC_WRITE_MEM(&bd->tr.dptr, dataptr);
1147     }
1148 
1149     /* Get status of transfer descriptor */
1150     if ( stat ) {
1151         status = *stat;
1152         *stat = GR1553BC_READ_MEM(&bd->tr.status);
1153         if ( status ) {
1154             /* Clear status fields user selects, then
1155              * or bit31 if user wants that. The bit31
1156              * may be used to indicate if the BC has
1157              * performed the access.
1158              */
1159             status = (*stat & (status & 0xffffff)) |
1160                  (status & (1<<31));
1161             GR1553BC_WRITE_MEM(&bd->tr.status, status);
1162         }
1163     }
1164 
1165     return 0;
1166 }
1167 
1168 int gr1553bc_slot_dummy(
1169     struct gr1553bc_list *list,
1170     int mid,
1171     unsigned int *dummy)
1172 {
1173     union gr1553bc_bd *bd;
1174     unsigned int set1, new_set1;
1175 
1176     /* Get BD address */
1177     bd = gr1553bc_slot_bd(list, mid);
1178     if ( bd == NULL )
1179         return -1;
1180     /* Update the Dummy Bit */
1181     set1 = GR1553BC_READ_MEM(&bd->tr.settings[1]);
1182     new_set1 = (set1 & ~GR1553BC_TR_DUMMY_1) | (*dummy & GR1553BC_TR_DUMMY_1);
1183     GR1553BC_WRITE_MEM(&bd->tr.settings[1], new_set1);
1184 
1185     *dummy = set1;
1186 
1187     return 0;
1188 }
1189 
1190 /* Find MID from Descriptor pointer */
1191 int gr1553bc_mid_from_bd(
1192     union gr1553bc_bd *bd,
1193     int *mid,
1194     int *async
1195     )
1196 {
1197     int i, bdmid, slot_no;
1198     uint32_t word0, word2;
1199 
1200     /* Find Jump to next Minor Frame or End-Of-List,
1201      * at those locations we have stored a MID
1202      *
1203      * GR1553BC_SLOT_MAX+2 = Worst case, BD is max distance from jump
1204      *                       descriptor. 2=END and Jump descriptors.
1205      */
1206     for (i=0; i<GR1553BC_SLOT_MAX+2; i++) {
1207         word0 = GR1553BC_READ_MEM(&bd->raw.words[0]);
1208         if ( word0 & GR1553BC_BD_TYPE ) {
1209             if ( word0 == GR1553BC_UNCOND_JMP ) {
1210                 /* May be a unconditional IRQ set by user. In
1211                  * that case the function is stored in WORD3,
1212                  * functions must be aligned to 4 byte boudary.
1213                  */
1214                 word2 = GR1553BC_READ_MEM(&bd->raw.words[2]);
1215                 if ( word2 & NEXT_MINOR_MARKER ) {
1216                     goto found_mid;
1217                 }
1218             } else if ( word0 == GR1553BC_TR_EOL ) {
1219                 /* End-Of-List, does contain a MID */
1220                 word2 = GR1553BC_READ_MEM(&bd->raw.words[2]);
1221                 goto found_mid;
1222             }
1223         }
1224         bd++;
1225     }
1226 
1227     return -1;
1228 
1229 found_mid:
1230     /* Get MID of JUMP descriptor */
1231     bdmid = word2 >> 8;
1232     /* Subtract distance from JUMP descriptor to find MID
1233      * of requested BD.
1234      */
1235     slot_no = GR1553BC_SLOTID_FROM_ID(bdmid);
1236     slot_no -= i;
1237     bdmid = GR1553BC_ID_SET_SLOT(bdmid, slot_no);
1238 
1239     if ( mid )
1240         *mid = bdmid;
1241 
1242     /* Determine which list BD belongs to: async or sync */
1243     if ( async )
1244         *async = word2 & NEXT_MINOR_MARKER_ASYNC;
1245 
1246     return 0;
1247 }
1248 
1249 /*************** END OF LIST HANDLING ROUTINES ***************/
1250 
1251 /*************** DEVICE HANDLING ROUTINES ***************/
1252 
1253 void gr1553bc_device_init(struct gr1553bc_priv *priv);
1254 void gr1553bc_device_uninit(struct gr1553bc_priv *priv);
1255 void gr1553bc_isr(void *data);
1256 
1257 /*** GR1553BC driver ***/
1258 
1259 void gr1553bc_register(void)
1260 {
1261     /* The BC driver rely on the GR1553B Driver */
1262     gr1553_register();
1263 }
1264 
1265 static void gr1553bc_isr_std(union gr1553bc_bd *bd, void *data)
1266 {
1267     /* Do nothing */
1268 }
1269 
1270 /* Take a GR1553BC hardware device identified by minor.
1271  * A pointer is returned that is used internally by the GR1553BC
1272  * driver, it is used as an input paramter 'bc' to all other
1273  * functions that manipulate the hardware.
1274  */
1275 void *gr1553bc_open(int minor)
1276 {
1277     struct drvmgr_dev **pdev = NULL;
1278     struct gr1553bc_priv *priv = NULL;
1279     struct amba_dev_info *ambadev;
1280     struct ambapp_core *pnpinfo;
1281     void *irq_log_p = NULL;
1282 
1283     /* Allocate requested device */
1284     pdev = gr1553_bc_open(minor);
1285     if ( pdev == NULL )
1286         goto fail;
1287 
1288     irq_log_p = grlib_malloc(GR1553BC_IRQLOG_SIZE*2);
1289     if ( irq_log_p == NULL )
1290         goto fail;
1291 
1292     priv = grlib_calloc(1, sizeof(*priv));
1293     if ( priv == NULL )
1294         goto fail;
1295 
1296     /* Init BC device */
1297     priv->pdev = pdev;
1298     (*pdev)->priv = priv;
1299     priv->irq_log_p = irq_log_p;
1300     priv->started = 0;
1301 
1302     /* Get device information from AMBA PnP information */
1303     ambadev = (struct amba_dev_info *)(*pdev)->businfo;
1304     pnpinfo = &ambadev->info;
1305     priv->regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
1306 
1307     SPIN_INIT(&priv->devlock, "gr1553bc");
1308 
1309     gr1553bc_device_init(priv);
1310 
1311     /* Register ISR handler (unmask at IRQ controller) */
1312     if ( drvmgr_interrupt_register(*priv->pdev, 0, "gr1553bc",
1313          gr1553bc_isr, priv) ) {
1314         goto fail;
1315     }
1316 
1317     return priv;
1318 
1319 fail:
1320     if ( pdev )
1321         gr1553_bc_close(pdev);
1322     if ( irq_log_p )
1323         free(irq_log_p);
1324     if ( priv )
1325         free(priv);
1326     return NULL;
1327 }
1328 
1329 void gr1553bc_close(void *bc)
1330 {
1331     struct gr1553bc_priv *priv = bc;
1332 
1333     /* Stop Hardware */
1334     gr1553bc_stop(bc, 0x3);
1335 
1336     gr1553bc_device_uninit(priv);
1337 
1338     /* Remove interrupt handler (mask IRQ at IRQ controller) */
1339     drvmgr_interrupt_unregister(*priv->pdev, 0, gr1553bc_isr, priv);
1340 
1341     /* Free device */
1342     gr1553_bc_close(priv->pdev);
1343     SPIN_FREE(&priv->devlock);
1344     free(priv->irq_log_p);
1345     free(priv);
1346 }
1347 
1348 /* Return Current Minor frame number */
1349 int gr1553bc_indication(void *bc, int async, int *mid)
1350 {
1351     struct gr1553bc_priv *priv = bc;
1352     union gr1553bc_bd *bd;
1353 
1354     /* Get current descriptor pointer */
1355     if ( async ) {
1356         bd = (union gr1553bc_bd *)
1357             GR1553BC_READ_REG(&priv->regs->bc_aslot);
1358         bd = gr1553bc_bd_hw2cpu(priv->alist, bd);
1359     } else {
1360         bd = (union gr1553bc_bd *)
1361             GR1553BC_READ_REG(&priv->regs->bc_slot);
1362         bd = gr1553bc_bd_hw2cpu(priv->list, bd);
1363     }
1364 
1365     return gr1553bc_mid_from_bd(bd, mid, NULL);
1366 }
1367 
1368 /* Start major frame processing, wait for TimerManager tick or start directly */
1369 int gr1553bc_start(void *bc, struct gr1553bc_list *list, struct gr1553bc_list *list_async)
1370 {
1371     struct gr1553bc_priv *priv = bc;
1372     union gr1553bc_bd *bd = NULL, *bd_async = NULL;
1373     uint32_t ctrl, irqmask;
1374     SPIN_IRQFLAGS(irqflags);
1375 
1376     if ( (list == NULL) && (list_async == NULL) )
1377         return 0;
1378 
1379     /* Find first descriptor in list, the descriptor
1380      * first to be executed.
1381      */
1382     ctrl = GR1553BC_KEY;
1383     if ( list ) {
1384         bd = gr1553bc_slot_bd(list, GR1553BC_ID(0,0,0));
1385         if ( bd == NULL )
1386             return -1;
1387         bd = gr1553bc_bd_cpu2hw(list, bd);
1388         ctrl |= GR1553B_BC_ACT_SCSRT;
1389     }
1390     if ( list_async ) {
1391         bd_async = gr1553bc_slot_bd(list_async, GR1553BC_ID(0,0,0));
1392         if ( bd_async == NULL )
1393             return -1;
1394         bd_async = gr1553bc_bd_cpu2hw(list_async, bd_async);
1395         ctrl |= GR1553B_BC_ACT_ASSRT;
1396     }
1397 
1398     /* Do "hot-swapping" of lists */
1399     SPIN_LOCK_IRQ(&priv->devlock, irqflags);
1400 
1401     if ( list ) {
1402         priv->list = list;
1403         GR1553BC_WRITE_REG(&priv->regs->bc_bd, (uint32_t)bd);
1404     }
1405     if ( list_async ) {
1406         priv->alist = list_async;
1407         GR1553BC_WRITE_REG(&priv->regs->bc_abd, (uint32_t)bd_async);
1408     }
1409 
1410     /* If not enabled before, we enable it now. */
1411     GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, ctrl);
1412 
1413     /* Enable IRQ */
1414     if ( priv->started == 0 ) {
1415         priv->started = 1;
1416         irqmask = GR1553BC_READ_REG(&priv->regs->imask);
1417         irqmask |= GR1553B_IRQEN_BCEVE|GR1553B_IRQEN_BCDE|GR1553B_IRQEN_BCWKE;
1418         GR1553BC_WRITE_REG(&priv->regs->imask, irqmask);
1419     }
1420 
1421     SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
1422 
1423     return 0;
1424 }
1425 
1426 /* Pause GR1553 BC transfers */
1427 int gr1553bc_pause(void *bc)
1428 {
1429     struct gr1553bc_priv *priv = bc;
1430     uint32_t ctrl;
1431     SPIN_IRQFLAGS(irqflags);
1432 
1433     /* Do "hot-swapping" of lists */
1434     SPIN_LOCK_IRQ(&priv->devlock, irqflags);
1435     ctrl = GR1553BC_KEY | GR1553B_BC_ACT_SCSUS;
1436     GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, ctrl);
1437     SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
1438 
1439     return 0;
1440 }
1441 
1442 /* Restart GR1553 BC transfers, after being paused */
1443 int gr1553bc_restart(void *bc)
1444 {
1445     struct gr1553bc_priv *priv = bc;
1446     uint32_t ctrl;
1447     SPIN_IRQFLAGS(irqflags);
1448 
1449     SPIN_LOCK_IRQ(&priv->devlock, irqflags);
1450     ctrl = GR1553BC_KEY | GR1553B_BC_ACT_SCSRT;
1451     GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, ctrl);
1452     SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
1453 
1454     return 0;
1455 }
1456 
1457 /* Stop BC transmission */
1458 int gr1553bc_stop(void *bc, int options)
1459 {
1460     struct gr1553bc_priv *priv = bc;
1461     uint32_t ctrl;
1462     SPIN_IRQFLAGS(irqflags);
1463 
1464     ctrl = GR1553BC_KEY;
1465     if ( options & 0x1 )
1466         ctrl |= GR1553B_BC_ACT_SCSTP;
1467     if ( options & 0x2 )
1468         ctrl |= GR1553B_BC_ACT_ASSTP;
1469 
1470     SPIN_LOCK_IRQ(&priv->devlock, irqflags);
1471     GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, ctrl);
1472     priv->started = 0;
1473     SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
1474 
1475     return 0;
1476 }
1477 
1478 /* Reset software and BC hardware into a known "unused/init" state */
1479 void gr1553bc_device_init(struct gr1553bc_priv *priv)
1480 {
1481 /* RESET HARDWARE REGISTERS */
1482     /* Stop BC if not already stopped */
1483     GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
1484 
1485     /* Since RT can not be used at the same time as BC, we stop
1486      * RT rx, it should already be stopped...
1487      */
1488     GR1553BC_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
1489 
1490     /* Clear some registers */
1491     GR1553BC_WRITE_REG(&priv->regs->bc_bd, 0);
1492     GR1553BC_WRITE_REG(&priv->regs->bc_abd, 0);
1493     GR1553BC_WRITE_REG(&priv->regs->bc_timer, 0);
1494     GR1553BC_WRITE_REG(&priv->regs->bc_wake, 0);
1495     GR1553BC_WRITE_REG(&priv->regs->bc_irqptr, 0);
1496     GR1553BC_WRITE_REG(&priv->regs->bc_busmsk, 0);
1497 
1498 /* PUT SOFTWARE INTO INITIAL STATE */
1499     priv->list = NULL;
1500     priv->alist = NULL;
1501 
1502     priv->irq_log_base = (uint32_t *)
1503         (((uint32_t)priv->irq_log_p + (GR1553BC_IRQLOG_SIZE-1)) &
1504         ~(GR1553BC_IRQLOG_SIZE-1));
1505     /* Translate into a hardware accessible address */
1506     drvmgr_translate_check(
1507         *priv->pdev,
1508         CPUMEM_TO_DMA,
1509         (void *)priv->irq_log_base,
1510         (void **)&priv->irq_log_base_hw,
1511         GR1553BC_IRQLOG_SIZE);
1512     priv->irq_log_curr = priv->irq_log_base;
1513     priv->irq_log_end = &priv->irq_log_base[GR1553BC_IRQLOG_CNT-1];
1514     priv->irq_func = gr1553bc_isr_std;
1515     priv->irq_data = NULL;
1516 
1517     GR1553BC_WRITE_REG(&priv->regs->bc_irqptr,(uint32_t)priv->irq_log_base_hw);
1518 }
1519 
1520 void gr1553bc_device_uninit(struct gr1553bc_priv *priv)
1521 {
1522     uint32_t irqmask;
1523 
1524     /* Stop BC if not already stopped */
1525     GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
1526 
1527     /* Since RT can not be used at the same time as BC, we stop
1528      * RT rx, it should already be stopped...
1529      */
1530     GR1553BC_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
1531 
1532     /* Turn off IRQ generation */
1533     irqmask=GR1553BC_READ_REG(&priv->regs->imask);
1534     irqmask&=~(GR1553B_IRQEN_BCEVE|GR1553B_IRQEN_BCDE|GR1553B_IRQEN_BCWKE);
1535     GR1553BC_WRITE_REG(&priv->regs->irq, irqmask);
1536 }
1537 
1538 /* Interrupt handler */
1539 void gr1553bc_isr(void *arg)
1540 {
1541     struct gr1553bc_priv *priv = arg;
1542     uint32_t *curr, *pos, word0, word2;
1543     union gr1553bc_bd *bd;
1544     bcirq_func_t func;
1545     void *data;
1546     int handled, irq;
1547     SPIN_ISR_IRQFLAGS(irqflags);
1548 
1549     /* Did core make IRQ */
1550     irq = GR1553BC_READ_REG(&priv->regs->irq);
1551     irq &= (GR1553B_IRQEN_BCEVE|GR1553B_IRQEN_BCDE|GR1553B_IRQEN_BCWKE);
1552     if ( irq == 0 )
1553         return; /* Shared IRQ: some one else may have caused the IRQ */
1554 
1555     /* Clear handled IRQs */
1556     GR1553BC_WRITE_REG(&priv->regs->irq, irq);
1557 
1558     /* DMA error. This IRQ does not affect the IRQ log.
1559      * We let standard IRQ handle handle it.
1560      */
1561     if ( irq & GR1553B_IRQEN_BCDE ) {
1562         priv->irq_func(NULL, priv->irq_data);
1563     }
1564 
1565     /* Get current posistion in hardware */
1566     pos = (uint32_t *)GR1553BC_READ_REG(&priv->regs->bc_irqptr);
1567     /* Converting into CPU address */
1568     pos = priv->irq_log_base +
1569         ((unsigned int)pos - (unsigned int)priv->irq_log_base_hw)/4;
1570 
1571     /* Step in IRQ log until we reach the end. */
1572     handled = 0;
1573     curr = priv->irq_log_curr;
1574     while ( curr != pos ) {
1575         bd = (union gr1553bc_bd *)(GR1553BC_READ_MEM(curr) & ~1);
1576         GR1553BC_WRITE_MEM(curr, 0x2); /* Mark Handled */
1577 
1578         /* Convert Descriptor in IRQ log into CPU address. In order
1579          * to convert we must know which list the descriptor belongs
1580          * to, we compare the address of the bd to the ASYNC list
1581          * descriptor table area.
1582          */
1583         SPIN_LOCK(&priv->devlock, irqflags);
1584         if ( priv->alist && ((unsigned int)bd>=priv->alist->table_hw) &&
1585              ((unsigned int)bd <
1586              (priv->alist->table_hw + priv->alist->table_size))) {
1587                 /* BD in async list */
1588             bd = gr1553bc_bd_hw2cpu(priv->alist, bd);
1589         } else if (priv->list &&
1590                    ((unsigned int)bd >= priv->list->table_hw) &&
1591                ((unsigned int)bd <
1592                (priv->list->table_hw + priv->list->table_size))) {
1593             /* BD in sync list */
1594             bd = gr1553bc_bd_hw2cpu(priv->list, bd);
1595         } else {
1596             /* error - unknown BD. Should not happen but could
1597              * if user has switched list. Ignore IRQ entry and
1598              * continue to next entry.
1599              */
1600             bd = NULL;
1601         }
1602 
1603         /* Handle Descriptor that cased IRQ
1604          *
1605          * If someone have inserted an IRQ descriptor and tied
1606          * that to a custom function we call that function, otherwise
1607          * we let the standard IRQ handle handle it.
1608          */
1609         if ( bd ) {
1610             word0 = GR1553BC_READ_MEM(&bd->raw.words[0]);
1611             word2 = GR1553BC_READ_MEM(&bd->raw.words[2]);
1612             SPIN_UNLOCK(&priv->devlock, irqflags);
1613             if ( word0 == GR1553BC_UNCOND_IRQ ) {
1614                 if ( (word2 & 0x3) == 0 ) {
1615                     func = (bcirq_func_t)(word2 & ~0x3);
1616                     data = (void *)
1617                       GR1553BC_READ_MEM(&bd->raw.words[3]);
1618                     func(bd, data);
1619                     handled = 1;
1620                 }
1621             }
1622 
1623             if ( handled == 0 ) {
1624                 /* Let standard IRQ handle handle it */
1625                 priv->irq_func(bd, priv->irq_data);
1626             } else {
1627                 handled = 0;
1628             }
1629         } else {
1630             SPIN_UNLOCK(&priv->devlock, irqflags);
1631         }
1632 
1633         /* Increment to next entry in IRQ LOG */
1634         if ( curr == priv->irq_log_end )
1635             curr = priv->irq_log_base;
1636         else
1637             curr++;
1638     }
1639     priv->irq_log_curr = curr;
1640 }
1641 
1642 int gr1553bc_irq_setup
1643     (
1644     void *bc,
1645     bcirq_func_t func,
1646     void *data
1647     )
1648 {
1649     struct gr1553bc_priv *priv = bc;
1650 
1651     if ( func == NULL )
1652         priv->irq_func = gr1553bc_isr_std;
1653     else
1654         priv->irq_func = func;
1655     priv->irq_data = data;
1656 
1657     return 0;
1658 }
1659 
1660 void gr1553bc_ext_trig(void *bc, int trig)
1661 {
1662     struct gr1553bc_priv *priv = bc;
1663     unsigned int trigger;
1664 
1665     if ( trig )
1666         trigger = GR1553B_BC_ACT_SETT;
1667     else
1668         trigger = GR1553B_BC_ACT_CLRT;
1669 
1670     GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | trigger);
1671 }
1672 
1673 void gr1553bc_status(void *bc, struct gr1553bc_status *status)
1674 {
1675     struct gr1553bc_priv *priv = bc;
1676 
1677     status->status = GR1553BC_READ_REG(&priv->regs->bc_stat);
1678     status->time = GR1553BC_READ_REG(&priv->regs->bc_timer);
1679 }
1680 
1681 /*** DEBUGGING HELP FUNCTIONS ***/
1682 
1683 #include <stdio.h>
1684 
1685 void gr1553bc_show_list(struct gr1553bc_list *list, int options)
1686 {
1687     struct gr1553bc_major *major;
1688     struct gr1553bc_minor *minor;
1689     int i, j, minor_cnt, timefree;
1690 
1691     printf("LIST\n");
1692     printf("  major cnt: %d\n", list->major_cnt);
1693     for (i=0; i<32; i++) {
1694         printf("  RT[%d] timeout: %d\n", i, 14+(list->rt_timeout[i]*4));
1695     }
1696 
1697     for (i=0; i<list->major_cnt; i++) {
1698         major = list->majors[i];
1699         minor_cnt = major->cfg->minor_cnt;
1700         printf(" MAJOR[%d]\n", i);
1701         printf("   minor count: %d\n", minor_cnt);
1702 
1703         for (j=0; j<minor_cnt; j++) {
1704             minor = major->minors[j];
1705 
1706             printf("   MINOR[%d]\n", j);
1707             printf("     bd:        0x%08x (HW:0x%08x)\n",
1708                 (unsigned int)&minor->bds[0],
1709                 (unsigned int)gr1553bc_bd_cpu2hw(list,
1710                             &minor->bds[0]));
1711             printf("     slot cnt:  %d\n", minor->cfg->slot_cnt);
1712             if ( minor->cfg->timeslot ) {
1713                 timefree = gr1553bc_minor_freetime(minor);
1714                 printf("     timefree:  %d\n", timefree);
1715                 printf("     timetotal: %d\n",
1716                     minor->cfg->timeslot);
1717             } else {
1718                 printf("     no time mgr\n");
1719             }
1720         }
1721     }
1722 }