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 BM 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 <drvmgr/drvmgr.h>
0033 #include <grlib/ambapp_bus.h>
0034 
0035 #include <grlib/gr1553b.h>
0036 #include <grlib/gr1553bm.h>
0037 
0038 #include <grlib/grlib_impl.h>
0039 
0040 #define GR1553BM_WRITE_MEM(adr, val) *(volatile uint32_t *)(adr) = (uint32_t)(val)
0041 #define GR1553BM_READ_MEM(adr) (*(volatile uint32_t *)(adr))
0042 
0043 #define GR1553BM_WRITE_REG(adr, val) *(volatile uint32_t *)(adr) = (uint32_t)(val)
0044 #define GR1553BM_READ_REG(adr) (*(volatile uint32_t *)(adr))
0045 
0046 struct gr1553bm_priv {
0047     struct drvmgr_dev **pdev;
0048     struct gr1553b_regs *regs;
0049     SPIN_DECLARE(devlock);
0050 
0051     void *buffer;
0052     unsigned int buffer_base_hw;
0053     unsigned int buffer_base;
0054     unsigned int buffer_end;
0055     unsigned int buffer_size;
0056     unsigned int read_pos;
0057     int started;
0058     struct gr1553bm_config cfg;
0059 
0060     /* Time updated by IRQ when 24-bit Time counter overflows */
0061     volatile uint64_t time;
0062 };
0063 
0064 void gr1553bm_isr(void *data);
0065 
0066 /* Default Driver configuration */
0067 struct gr1553bm_config gr1553bm_default_config =
0068 {
0069     /* Highest resolution, use Time overflow IRQ to track */
0070     .time_resolution = 0,
0071     .time_ovf_irq = 1,
0072 
0073     /* No filtering, log all */
0074     .filt_error_options = GR1553BM_ERROPTS_ALL,
0075     .filt_rtadr = 0xffffffff,
0076     .filt_subadr = 0xffffffff,
0077     .filt_mc = 0x0007ffff,
0078 
0079     /* 128Kbyte dynamically allocated buffer. */
0080     .buffer_size = 128*1024,
0081     .buffer_custom = NULL,
0082 };
0083 
0084 void gr1553bm_register(void)
0085 {
0086     /* The BM driver rely on the GR1553B Driver */
0087     gr1553_register();
0088 }
0089 
0090 static void gr1553bm_hw_start(struct gr1553bm_priv *priv)
0091 {
0092     SPIN_IRQFLAGS(irqflags);
0093 
0094     /* Enable IRQ source and mark running state */
0095     SPIN_LOCK_IRQ(&priv->devlock, irqflags);
0096 
0097     priv->started = 1;
0098 
0099     /* Clear old IRQ flags */
0100     priv->regs->irq = GR1553B_IRQ_BMD | GR1553B_IRQ_BMTOF;
0101 
0102     /* Unmask IRQ sources */
0103     if ( priv->cfg.time_ovf_irq ) {
0104         priv->regs->imask |= GR1553B_IRQEN_BMDE | GR1553B_IRQEN_BMTOE;
0105     } else {
0106         priv->regs->imask |= GR1553B_IRQEN_BMDE;
0107     }
0108 
0109     /* Start logging */
0110     priv->regs->bm_ctrl =
0111         (priv->cfg.filt_error_options &
0112         (GR1553B_BM_CTRL_MANL|GR1553B_BM_CTRL_UDWL|GR1553B_BM_CTRL_IMCL))
0113         | GR1553B_BM_CTRL_BMEN;
0114 
0115     SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
0116 }
0117 
0118 static void gr1553bm_hw_stop(struct gr1553bm_priv *priv)
0119 {
0120     SPIN_IRQFLAGS(irqflags);
0121 
0122     SPIN_LOCK_IRQ(&priv->devlock, irqflags);
0123 
0124     /* Stop Logging */
0125     priv->regs->bm_ctrl = 0;
0126 
0127     /* Stop IRQ source */
0128     priv->regs->imask &= ~(GR1553B_IRQEN_BMDE|GR1553B_IRQEN_BMTOE);
0129 
0130     /* Clear IRQ flags */
0131     priv->regs->irq = GR1553B_IRQ_BMD | GR1553B_IRQ_BMTOF;
0132 
0133     priv->started = 0;
0134 
0135     SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
0136 }
0137 
0138 /* Open device by number */
0139 void *gr1553bm_open(int minor)
0140 {
0141     struct drvmgr_dev **pdev = NULL;
0142     struct gr1553bm_priv *priv = NULL;
0143     struct amba_dev_info *ambadev;
0144     struct ambapp_core *pnpinfo;
0145 
0146     /* Allocate requested device */
0147     pdev = gr1553_bm_open(minor);
0148     if ( pdev == NULL )
0149         goto fail;
0150 
0151     priv = grlib_calloc(1, sizeof(*priv));
0152     if ( priv == NULL )
0153         goto fail;
0154 
0155     /* Init BC device */
0156     priv->pdev = pdev;
0157     (*pdev)->priv = priv;
0158 
0159     /* Get device information from AMBA PnP information */
0160     ambadev = (struct amba_dev_info *)(*pdev)->businfo;
0161     pnpinfo = &ambadev->info;
0162     priv->regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
0163     SPIN_INIT(&priv->devlock, "gr1553bm");
0164 
0165     /* Start with default configuration */
0166     priv->cfg = gr1553bm_default_config;
0167 
0168     /* Unmask IRQs */
0169     gr1553bm_hw_stop(priv);
0170 
0171     return priv;
0172 
0173 fail:
0174     if ( pdev )
0175         gr1553_bm_close(pdev);
0176     return NULL;
0177 }
0178 
0179 /* Close previously */
0180 void gr1553bm_close(void *bm)
0181 {
0182     struct gr1553bm_priv *priv = bm;
0183 
0184     if ( priv->started ) {
0185         gr1553bm_stop(bm);
0186     }
0187 
0188     if ( (priv->cfg.buffer_custom == NULL) && priv->buffer )
0189         free(priv->buffer);
0190 
0191     gr1553_bm_close(priv->pdev);
0192     free(priv);
0193 }
0194 
0195 /* Configure the BM driver */
0196 int gr1553bm_config(void *bm, struct gr1553bm_config *cfg)
0197 {
0198     int retval = 0;
0199     struct gr1553bm_priv *priv = bm;
0200 
0201     if ( priv->started )
0202         return -1;
0203 
0204     /* Check Config validity? */
0205 /*#warning IMPLEMENT.*/
0206 
0207     /* Free old buffer if dynamically allocated */
0208     if ( (priv->cfg.buffer_custom == NULL) && priv->buffer ) {
0209         free(priv->buffer);
0210         priv->buffer = NULL;
0211     }
0212     priv->buffer_size = cfg->buffer_size & ~0x7; /* on 8 byte bounadry */
0213     if ((unsigned int)cfg->buffer_custom & 1) {
0214         /* Custom address given in remote address. We need
0215          * to convert it into a hardware accessible address
0216          */
0217         priv->buffer = (void*)((unsigned int)cfg->buffer_custom & ~1);
0218         priv->buffer_base_hw = (unsigned int)priv->buffer;
0219         drvmgr_translate_check(
0220             *priv->pdev,
0221             DMAMEM_TO_CPU,
0222             (void *)priv->buffer_base_hw,
0223             (void **)&priv->buffer_base,
0224             priv->buffer_size);
0225     } else {
0226         if (cfg->buffer_custom == NULL) {
0227             /* Allocate new buffer dynamically */
0228             priv->buffer = grlib_malloc(priv->buffer_size + 8);
0229             if (priv->buffer == NULL) {
0230                 retval = -1;
0231                 goto err;
0232             }
0233             /* Align to 8 bytes */
0234             priv->buffer_base = ((unsigned int)priv->buffer + (8-1)) & ~(8-1);
0235         } else {
0236             /* Address given in CPU accessible address, no
0237              * translation required.
0238              */
0239             priv->buffer = cfg->buffer_custom;
0240             priv->buffer_base = (unsigned int)priv->buffer;
0241         }
0242         /* Translate address of buffer base into address that Hardware must
0243          * use to access the buffer.
0244          */
0245         drvmgr_translate_check(
0246             *priv->pdev,
0247             CPUMEM_TO_DMA,
0248             (void *)priv->buffer_base,
0249             (void **)&priv->buffer_base_hw,
0250             priv->buffer_size);
0251 
0252     }
0253 
0254     /* Verify alignment */
0255     if (priv->buffer_base_hw & (8-1)) {
0256         retval = -2;
0257         goto err;
0258     }
0259 
0260     /* Copy valid config */
0261     priv->cfg = *cfg;
0262 
0263 err:
0264     if (retval) {
0265         if (cfg->buffer_custom == NULL && priv->buffer) {
0266             free(priv->buffer);
0267         }
0268         priv->buffer_base_hw = (unsigned int)NULL;
0269         priv->buffer_base = (unsigned int)NULL;
0270         priv->buffer = NULL;
0271     }
0272     return retval;
0273 }
0274 
0275 /* Start logging */
0276 int gr1553bm_start(void *bm)
0277 {
0278     struct gr1553bm_priv *priv = bm;
0279 
0280     if ( priv->started )
0281         return -1;
0282     if ( priv->buffer == NULL )
0283         return -2;
0284 
0285     /* Start at Time = 0 */
0286     priv->regs->bm_ttag =
0287         priv->cfg.time_resolution << GR1553B_BM_TTAG_RES_BIT;
0288 
0289     /* Configure Filters */
0290     priv->regs->bm_adr = priv->cfg.filt_rtadr;
0291     priv->regs->bm_subadr = priv->cfg.filt_subadr;
0292     priv->regs->bm_mc = priv->cfg.filt_mc;
0293 
0294     /* Set up buffer */
0295     priv->regs->bm_start = priv->buffer_base_hw;
0296     priv->regs->bm_end = priv->buffer_base_hw + priv->cfg.buffer_size - 4;
0297     priv->regs->bm_pos = priv->buffer_base_hw;
0298     priv->read_pos = priv->buffer_base;
0299     priv->buffer_end = priv->buffer_base + priv->cfg.buffer_size;
0300 
0301     /* Register ISR handler and unmask IRQ source at IRQ controller */
0302     if (drvmgr_interrupt_register(*priv->pdev, 0, "gr1553bm", gr1553bm_isr, priv))
0303         return -3;
0304 
0305     /* Start hardware and set priv->started */
0306     gr1553bm_hw_start(priv);
0307 
0308     return 0;
0309 }
0310 
0311 /* Stop logging */
0312 void gr1553bm_stop(void *bm)
0313 {
0314     struct gr1553bm_priv *priv = bm;
0315 
0316     /* Stop Hardware */
0317     gr1553bm_hw_stop(priv);
0318 
0319     /* At this point the hardware must be stopped and IRQ
0320      * sources unmasked.
0321      */
0322 
0323     /* Unregister ISR handler and unmask 1553 IRQ source at IRQ ctrl */
0324     drvmgr_interrupt_unregister(*priv->pdev, 0, gr1553bm_isr, priv);
0325 }
0326 
0327 int gr1553bm_started(void *bm)
0328 {
0329     return ((struct gr1553bm_priv *)bm)->started;
0330 }
0331 
0332 /* Get 64-bit 1553 Time.
0333  *
0334  * Update software time counters and return the current time.
0335  */
0336 void gr1553bm_time(void *bm, uint64_t *time)
0337 {
0338     struct gr1553bm_priv *priv = bm;
0339     unsigned int hwtime, hwtime2;
0340 
0341 resample:
0342     if ( priv->started && (priv->cfg.time_ovf_irq == 0) ) {
0343         /* Update Time overflow counter. The carry bit from Time counter
0344          * is located in IRQ Flag.
0345          *
0346          * When IRQ is not used this function must be called often
0347          * enough to avoid that the Time overflows and the carry
0348          * bit is already set. The frequency depends on the Time
0349          * resolution.
0350          */
0351         if ( priv->regs->irq & GR1553B_IRQ_BMTOF ) {
0352             /* Clear carry bit */
0353             priv->regs->irq = GR1553B_IRQ_BMTOF;
0354             priv->time += (GR1553B_BM_TTAG_VAL + 1);
0355         }
0356     }
0357 
0358     /* Report current Time, even if stopped */
0359     hwtime = priv->regs->bm_ttag & GR1553B_BM_TTAG_VAL;
0360     if ( time )
0361         *time = priv->time | hwtime;
0362 
0363     if ( priv->cfg.time_ovf_irq ) {
0364         /* Detect wrap around */
0365         hwtime2 = priv->regs->bm_ttag & GR1553B_BM_TTAG_VAL;
0366         if ( hwtime > hwtime2 ) {
0367             /* priv->time and hwtime may be out of sync if
0368              * IRQ updated priv->time just after bm_ttag was read
0369              * here, we resample if we detect inconsistancy.
0370              */
0371             goto resample;
0372         }
0373     }
0374 }
0375 
0376 /* Number of entries available in DMA buffer */
0377 int gr1553bm_available(void *bm, int *nentries)
0378 {
0379     struct gr1553bm_priv *priv = bm;
0380     unsigned int top, bot, pos;
0381 
0382     if ( !priv->started )
0383         return -1;
0384 
0385     /* Get BM posistion in log */
0386     pos = priv->regs->bm_pos;
0387 
0388     /* Convert into CPU accessible address */
0389     pos = priv->buffer_base + (pos - priv->buffer_base_hw);
0390 
0391     if ( pos >= priv->read_pos ) {
0392         top = (pos - priv->read_pos)/sizeof(struct gr1553bm_entry);
0393         bot = 0;
0394     } else {
0395         top = (priv->buffer_end - priv->read_pos)/sizeof(struct gr1553bm_entry);
0396         bot = (pos - priv->buffer_base)/sizeof(struct gr1553bm_entry);
0397     }
0398 
0399     if ( nentries )
0400         *nentries = top+bot;
0401 
0402     return 0;
0403 }
0404 
0405 /* Read a maximum number of entries from LOG buffer. */
0406 int gr1553bm_read(void *bm, struct gr1553bm_entry *dst, int *max)
0407 {
0408     struct gr1553bm_priv *priv = bm;
0409     unsigned int dest, pos, left, newPos, len;
0410     unsigned int topAdr, botAdr, topLen, botLen;
0411 
0412     if ( !priv || !priv->started )
0413         return -1;
0414 
0415     left = *max;
0416     pos = priv->regs->bm_pos & ~0x7;
0417 
0418     /* Convert into CPU accessible address */
0419     pos = priv->buffer_base + (pos - priv->buffer_base_hw);
0420 
0421     if ( (pos == priv->read_pos) || (left < 1) ) {
0422         /* No data available */
0423         *max = 0;
0424         return 0;
0425     }
0426     newPos = 0;
0427 
0428     /* Addresses and lengths of BM log buffer */
0429     if ( pos >= priv->read_pos ) {
0430         /* Read Top only */
0431         topAdr = priv->read_pos;
0432         botAdr = 0;
0433         topLen = (pos - priv->read_pos)/sizeof(struct gr1553bm_entry);
0434         botLen = 0;
0435     } else {
0436         /* Read Top and Bottom */
0437         topAdr = priv->read_pos;
0438         botAdr = priv->buffer_base;
0439         topLen = (priv->buffer_end - priv->read_pos)/sizeof(struct gr1553bm_entry);
0440         botLen = (pos - priv->buffer_base)/sizeof(struct gr1553bm_entry);
0441     }
0442 
0443     dest = (unsigned int)dst;
0444     if ( topLen > 0 ) {
0445         /* Copy from top area first */
0446         if ( topLen > left ) {
0447             len = left;
0448             left = 0;
0449         } else {
0450             len = topLen;
0451             left -= topLen;
0452         }
0453         newPos = topAdr + (len * sizeof(struct gr1553bm_entry));
0454         if ( newPos >= priv->buffer_end )
0455             newPos -= priv->buffer_size;
0456         if ( priv->cfg.copy_func ) {
0457             dest += priv->cfg.copy_func(
0458                 dest,           /*Optional Destination*/
0459                 (void *)topAdr,     /* DMA start address */
0460                 len,            /* Number of entries */
0461                 priv->cfg.copy_func_arg /* Custom ARG */
0462                 );
0463         } else {
0464             memcpy( (void *)dest,
0465                 (void *)topAdr,
0466                 len * sizeof(struct gr1553bm_entry));
0467             dest += len * sizeof(struct gr1553bm_entry);
0468         }
0469     }
0470 
0471     if ( (botLen > 0) && (left > 0) ) {
0472         /* Copy bottom area last */
0473         if ( botLen > left ) {
0474             len = left;
0475             left = 0;
0476         } else {
0477             len = botLen;
0478             left -= botLen;
0479         }
0480         newPos = botAdr + (len * sizeof(struct gr1553bm_entry));
0481 
0482         if ( priv->cfg.copy_func ) {
0483             priv->cfg.copy_func(
0484                 dest,           /*Optional Destination*/
0485                 (void *)botAdr,     /* DMA start address */
0486                 len,            /* Number of entries */
0487                 priv->cfg.copy_func_arg /* Custom ARG */
0488                 );
0489         } else {
0490             memcpy( (void *)dest,
0491                 (void *)botAdr,
0492                 len * sizeof(struct gr1553bm_entry));
0493         }
0494     }
0495 
0496     /* Remember last read posistion in buffer */
0497     /*printf("New pos: 0x%08x (0x%08x), %d\n", newPos, priv->read_pos, *max - left);*/
0498     priv->read_pos = newPos;
0499 
0500     /* Return number of entries read */
0501     *max = *max - left;
0502 
0503     return 0;
0504 }
0505 
0506 /* Note: This is a shared interrupt handler, with BC/RT driver
0507  *       we must determine the cause of IRQ before handling it.
0508  */
0509 void gr1553bm_isr(void *data)
0510 {
0511     struct gr1553bm_priv *priv = data;
0512     uint32_t irqflag;
0513 
0514     /* Get Causes */
0515     irqflag = priv->regs->irq & (GR1553B_IRQ_BMD | GR1553B_IRQ_BMTOF);
0516 
0517     /* Check spurious IRQs */
0518     if ( (irqflag == 0) || (priv->started == 0) )
0519         return;
0520 
0521     if ( (irqflag & GR1553B_IRQ_BMTOF) && priv->cfg.time_ovf_irq ) {
0522         /* 1553 Time Over flow. Time is 24-bits */
0523         priv->time += (GR1553B_BM_TTAG_VAL + 1);
0524 
0525         /* Clear cause handled */
0526         priv->regs->irq = GR1553B_IRQ_BMTOF;
0527     }
0528 
0529     if ( irqflag & GR1553B_IRQ_BMD ) {
0530         /* BM DMA ERROR. Fatal error, we stop BM hardware and let
0531          * user take care of it. From now on all calls will result
0532          * in an error because the BM is stopped (priv->started=0).
0533          */
0534 
0535         /* Clear cause handled */
0536         priv->regs->irq = GR1553B_IRQ_BMD;
0537 
0538         if ( priv->cfg.dma_error_isr )
0539             priv->cfg.dma_error_isr(data, priv->cfg.dma_error_arg);
0540 
0541         gr1553bm_hw_stop(priv);
0542     }
0543 }