source: rtems/bsps/sparc/shared/1553/gr1553bm.c @ 31720925

Last change on this file since 31720925 was 31720925, checked in by Sebastian Huber <sebastian.huber@…>, on Dec 22, 2018 at 6:13:44 AM

grlib: Move header files

Update #3678.

  • Property mode set to 100644
File size: 12.1 KB
Line 
1/*  GR1553B BM driver
2 *
3 *  COPYRIGHT (c) 2010.
4 *  Cobham Gaisler AB.
5 *
6 *  The license and distribution terms for this file may be
7 *  found in the file LICENSE in this distribution or at
8 *  http://www.rtems.org/license/LICENSE.
9 */
10
11#include <stdlib.h>
12#include <string.h>
13#include <drvmgr/drvmgr.h>
14#include <grlib/ambapp_bus.h>
15
16#include <grlib/gr1553b.h>
17#include <grlib/gr1553bm.h>
18
19#include <grlib/grlib_impl.h>
20
21#define GR1553BM_WRITE_MEM(adr, val) *(volatile uint32_t *)(adr) = (uint32_t)(val)
22#define GR1553BM_READ_MEM(adr) (*(volatile uint32_t *)(adr))
23
24#define GR1553BM_WRITE_REG(adr, val) *(volatile uint32_t *)(adr) = (uint32_t)(val)
25#define GR1553BM_READ_REG(adr) (*(volatile uint32_t *)(adr))
26
27struct gr1553bm_priv {
28        struct drvmgr_dev **pdev;
29        struct gr1553b_regs *regs;
30        SPIN_DECLARE(devlock);
31
32        void *buffer;
33        unsigned int buffer_base_hw;
34        unsigned int buffer_base;
35        unsigned int buffer_end;
36        unsigned int buffer_size;
37        unsigned int read_pos;
38        int started;
39        struct gr1553bm_config cfg;
40
41        /* Time updated by IRQ when 24-bit Time counter overflows */
42        volatile uint64_t time;
43};
44
45void gr1553bm_isr(void *data);
46
47/* Default Driver configuration */
48struct gr1553bm_config gr1553bm_default_config =
49{
50        /* Highest resolution, use Time overflow IRQ to track */
51        .time_resolution = 0,
52        .time_ovf_irq = 1,
53
54        /* No filtering, log all */
55        .filt_error_options = GR1553BM_ERROPTS_ALL,
56        .filt_rtadr = 0xffffffff,
57        .filt_subadr = 0xffffffff,
58        .filt_mc = 0x0007ffff,
59
60        /* 128Kbyte dynamically allocated buffer. */
61        .buffer_size = 128*1024,
62        .buffer_custom = NULL,
63};
64
65void gr1553bm_register(void)
66{
67        /* The BM driver rely on the GR1553B Driver */
68        gr1553_register();
69}
70
71static void gr1553bm_hw_start(struct gr1553bm_priv *priv)
72{
73        SPIN_IRQFLAGS(irqflags);
74
75        /* Enable IRQ source and mark running state */
76        SPIN_LOCK_IRQ(&priv->devlock, irqflags);
77
78        priv->started = 1;
79
80        /* Clear old IRQ flags */
81        priv->regs->irq = GR1553B_IRQ_BMD | GR1553B_IRQ_BMTOF;
82
83        /* Unmask IRQ sources */
84        if ( priv->cfg.time_ovf_irq ) {
85                priv->regs->imask |= GR1553B_IRQEN_BMDE | GR1553B_IRQEN_BMTOE;
86        } else {
87                priv->regs->imask |= GR1553B_IRQEN_BMDE;
88        }
89
90        /* Start logging */
91        priv->regs->bm_ctrl =
92                (priv->cfg.filt_error_options & 
93                (GR1553B_BM_CTRL_MANL|GR1553B_BM_CTRL_UDWL|GR1553B_BM_CTRL_IMCL))
94                | GR1553B_BM_CTRL_BMEN;
95
96        SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
97}
98
99static void gr1553bm_hw_stop(struct gr1553bm_priv *priv)
100{
101        SPIN_IRQFLAGS(irqflags);
102
103        SPIN_LOCK_IRQ(&priv->devlock, irqflags);
104
105        /* Stop Logging */
106        priv->regs->bm_ctrl = 0;
107
108        /* Stop IRQ source */
109        priv->regs->imask &= ~(GR1553B_IRQEN_BMDE|GR1553B_IRQEN_BMTOE);
110
111        /* Clear IRQ flags */
112        priv->regs->irq = GR1553B_IRQ_BMD | GR1553B_IRQ_BMTOF;
113
114        priv->started = 0;
115
116        SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
117}
118
119/* Open device by number */
120void *gr1553bm_open(int minor)
121{
122        struct drvmgr_dev **pdev = NULL;
123        struct gr1553bm_priv *priv = NULL;
124        struct amba_dev_info *ambadev;
125        struct ambapp_core *pnpinfo;
126
127        /* Allocate requested device */
128        pdev = gr1553_bm_open(minor);
129        if ( pdev == NULL )
130                goto fail;
131
132        priv = grlib_calloc(1, sizeof(*priv));
133        if ( priv == NULL )
134                goto fail;
135
136        /* Init BC device */
137        priv->pdev = pdev;
138        (*pdev)->priv = priv;
139
140        /* Get device information from AMBA PnP information */
141        ambadev = (struct amba_dev_info *)(*pdev)->businfo;
142        pnpinfo = &ambadev->info;
143        priv->regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
144        SPIN_INIT(&priv->devlock, "gr1553bm");
145
146        /* Start with default configuration */
147        priv->cfg = gr1553bm_default_config;
148
149        /* Unmask IRQs */
150        gr1553bm_hw_stop(priv);
151
152        return priv;
153
154fail:
155        if ( pdev )
156                gr1553_bm_close(pdev);
157        if ( priv )
158                free(priv);
159        return NULL;
160}
161
162/* Close previously */
163void gr1553bm_close(void *bm)
164{
165        struct gr1553bm_priv *priv = bm;
166
167        if ( priv->started ) {
168                gr1553bm_stop(bm);
169        }
170
171        if ( (priv->cfg.buffer_custom == NULL) && priv->buffer )
172                free(priv->buffer);
173
174        gr1553_bm_close(priv->pdev);
175        free(priv);
176}
177
178/* Configure the BM driver */
179int gr1553bm_config(void *bm, struct gr1553bm_config *cfg)
180{
181        struct gr1553bm_priv *priv = bm;
182
183        if ( priv->started )
184                return -1;
185
186        /* Check Config validity? */
187/*#warning IMPLEMENT.*/
188
189        /* Free old buffer if dynamically allocated */
190        if ( (priv->cfg.buffer_custom == NULL) && priv->buffer ) {
191                free(priv->buffer);
192                priv->buffer = NULL;
193        }
194        priv->buffer_size = cfg->buffer_size & ~0x7; /* on 8 byte bounadry */
195        if ((unsigned int)cfg->buffer_custom & 1) {
196                /* Custom Address Given in Remote address. We need
197                 * to convert it intoTranslate into Hardware a
198                 * hardware accessible address
199                 */
200                priv->buffer_base_hw = (unsigned int)cfg->buffer_custom & ~1;
201                priv->buffer = cfg->buffer_custom;
202                drvmgr_translate_check(
203                        *priv->pdev,
204                        DMAMEM_TO_CPU,
205                        (void *)priv->buffer_base_hw,
206                        (void **)&priv->buffer_base,
207                        priv->buffer_size);
208        } else {
209                if (cfg->buffer_custom == NULL) {
210                        /* Allocate new buffer dynamically */
211                        priv->buffer = grlib_malloc(priv->buffer_size + 8);
212                        if (priv->buffer == NULL)
213                                return -1;
214                } else {
215                        /* Address given in CPU accessible address, no
216                         * translation required.
217                         */
218                        priv->buffer = cfg->buffer_custom;
219                }
220                /* Align to 16 bytes */
221                priv->buffer_base = ((unsigned int)priv->buffer + (8-1)) &
222                                        ~(8-1);
223                /* Translate address of buffer base into address that Hardware must
224                 * use to access the buffer.
225                 */
226                drvmgr_translate_check(
227                        *priv->pdev,
228                        CPUMEM_TO_DMA,
229                        (void *)priv->buffer_base,
230                        (void **)&priv->buffer_base_hw,
231                        priv->buffer_size);
232               
233        }
234
235        /* Copy valid config */
236        priv->cfg = *cfg;
237
238        return 0;
239}
240
241/* Start logging */
242int gr1553bm_start(void *bm)
243{
244        struct gr1553bm_priv *priv = bm;
245
246        if ( priv->started )
247                return -1;
248        if ( priv->buffer == NULL )
249                return -2;
250
251        /* Start at Time = 0 */
252        priv->regs->bm_ttag = 
253                priv->cfg.time_resolution << GR1553B_BM_TTAG_RES_BIT;
254
255        /* Configure Filters */
256        priv->regs->bm_adr = priv->cfg.filt_rtadr;
257        priv->regs->bm_subadr = priv->cfg.filt_subadr;
258        priv->regs->bm_mc = priv->cfg.filt_mc;
259
260        /* Set up buffer */
261        priv->regs->bm_start = priv->buffer_base_hw;
262        priv->regs->bm_end = priv->buffer_base_hw + priv->cfg.buffer_size - 4;
263        priv->regs->bm_pos = priv->buffer_base_hw;
264        priv->read_pos = priv->buffer_base;
265        priv->buffer_end = priv->buffer_base + priv->cfg.buffer_size;
266
267        /* Register ISR handler and unmask IRQ source at IRQ controller */
268        if (drvmgr_interrupt_register(*priv->pdev, 0, "gr1553bm", gr1553bm_isr, priv))
269                return -3;
270
271        /* Start hardware and set priv->started */
272        gr1553bm_hw_start(priv);
273
274        return 0;
275}
276
277/* Stop logging */
278void gr1553bm_stop(void *bm)
279{
280        struct gr1553bm_priv *priv = bm;
281
282        /* Stop Hardware */
283        gr1553bm_hw_stop(priv);
284
285        /* At this point the hardware must be stopped and IRQ
286         * sources unmasked.
287         */
288
289        /* Unregister ISR handler and unmask 1553 IRQ source at IRQ ctrl */
290        drvmgr_interrupt_unregister(*priv->pdev, 0, gr1553bm_isr, priv);
291}
292
293int gr1553bm_started(void *bm)
294{
295        return ((struct gr1553bm_priv *)bm)->started;
296}
297
298/* Get 64-bit 1553 Time.
299 *
300 * Update software time counters and return the current time.
301 */
302void gr1553bm_time(void *bm, uint64_t *time)
303{
304        struct gr1553bm_priv *priv = bm;
305        unsigned int hwtime, hwtime2;
306
307resample:
308        if ( priv->started && (priv->cfg.time_ovf_irq == 0) ) {
309                /* Update Time overflow counter. The carry bit from Time counter
310                 * is located in IRQ Flag.
311                 *
312                 * When IRQ is not used this function must be called often
313                 * enough to avoid that the Time overflows and the carry
314                 * bit is already set. The frequency depends on the Time
315                 * resolution.
316                 */
317                if ( priv->regs->irq & GR1553B_IRQ_BMTOF ) {
318                        /* Clear carry bit */
319                        priv->regs->irq = GR1553B_IRQ_BMTOF;
320                        priv->time += (GR1553B_BM_TTAG_VAL + 1);
321                }
322        }
323
324        /* Report current Time, even if stopped */
325        hwtime = priv->regs->bm_ttag & GR1553B_BM_TTAG_VAL;
326        if ( time )
327                *time = priv->time | hwtime;
328
329        if ( priv->cfg.time_ovf_irq ) {
330                /* Detect wrap around */
331                hwtime2 = priv->regs->bm_ttag & GR1553B_BM_TTAG_VAL;
332                if ( hwtime > hwtime2 ) {
333                        /* priv->time and hwtime may be out of sync if
334                         * IRQ updated priv->time just after bm_ttag was read
335                         * here, we resample if we detect inconsistancy.
336                         */
337                        goto resample;
338                }
339        }
340}
341
342/* Number of entries available in DMA buffer */
343int gr1553bm_available(void *bm, int *nentries)
344{
345        struct gr1553bm_priv *priv = bm;
346        unsigned int top, bot, pos;
347
348        if ( !priv->started )
349                return -1;
350
351        /* Get BM posistion in log */
352        pos = priv->regs->bm_pos;
353
354        /* Convert into CPU accessible address */
355        pos = priv->buffer_base + (pos - priv->buffer_base_hw);
356
357        if ( pos >= priv->read_pos ) {
358                top = (pos - priv->read_pos)/sizeof(struct gr1553bm_entry);
359                bot = 0;
360        } else {
361                top = (priv->buffer_end - priv->read_pos)/sizeof(struct gr1553bm_entry);
362                bot = (pos - priv->buffer_base)/sizeof(struct gr1553bm_entry);
363        }
364
365        if ( nentries )
366                *nentries = top+bot;
367
368        return 0;
369}
370
371/* Read a maximum number of entries from LOG buffer. */
372int gr1553bm_read(void *bm, struct gr1553bm_entry *dst, int *max)
373{
374        struct gr1553bm_priv *priv = bm;
375        unsigned int dest, pos, left, newPos, len;
376        unsigned int topAdr, botAdr, topLen, botLen;
377
378        if ( !priv || !priv->started )
379                return -1;
380
381        left = *max;
382        pos = priv->regs->bm_pos & ~0x7;
383
384        /* Convert into CPU accessible address */
385        pos = priv->buffer_base + (pos - priv->buffer_base_hw);
386
387        if ( (pos == priv->read_pos) || (left < 1) ) {
388                /* No data available */
389                *max = 0;
390                return 0;
391        }
392        newPos = 0;
393
394        /* Addresses and lengths of BM log buffer */
395        if ( pos >= priv->read_pos ) {
396                /* Read Top only */
397                topAdr = priv->read_pos;
398                botAdr = 0;
399                topLen = (pos - priv->read_pos)/sizeof(struct gr1553bm_entry);
400                botLen = 0;
401        } else {
402                /* Read Top and Bottom */
403                topAdr = priv->read_pos;
404                botAdr = priv->buffer_base;
405                topLen = (priv->buffer_end - priv->read_pos)/sizeof(struct gr1553bm_entry);
406                botLen = (pos - priv->buffer_base)/sizeof(struct gr1553bm_entry);
407        }
408
409        dest = (unsigned int)dst;
410        if ( topLen > 0 ) {
411                /* Copy from top area first */
412                if ( topLen > left ) {
413                        len = left;
414                        left = 0;
415                } else {
416                        len = topLen;
417                        left -= topLen;
418                }
419                newPos = topAdr + (len * sizeof(struct gr1553bm_entry));
420                if ( newPos >= priv->buffer_end )
421                        newPos -= priv->buffer_size;
422                if ( priv->cfg.copy_func ) {
423                        dest += priv->cfg.copy_func(
424                                dest,                   /*Optional Destination*/
425                                (void *)topAdr,         /* DMA start address */
426                                len,                    /* Number of entries */
427                                priv->cfg.copy_func_arg /* Custom ARG */
428                                );
429                } else {
430                        memcpy( (void *)dest,
431                                (void *)topAdr,
432                                len * sizeof(struct gr1553bm_entry));
433                        dest += len * sizeof(struct gr1553bm_entry);
434                }
435        }
436
437        if ( (botLen > 0) && (left > 0) ) {
438                /* Copy bottom area last */
439                if ( botLen > left ) {
440                        len = left;
441                        left = 0;
442                } else {
443                        len = botLen;
444                        left -= botLen;
445                }
446                newPos = botAdr + (len * sizeof(struct gr1553bm_entry));
447
448                if ( priv->cfg.copy_func ) {
449                        priv->cfg.copy_func(
450                                dest,                   /*Optional Destination*/
451                                (void *)botAdr,         /* DMA start address */
452                                len,                    /* Number of entries */
453                                priv->cfg.copy_func_arg /* Custom ARG */
454                                );
455                } else {
456                        memcpy( (void *)dest,
457                                (void *)botAdr,
458                                len * sizeof(struct gr1553bm_entry));
459                }
460        }
461
462        /* Remember last read posistion in buffer */
463        /*printf("New pos: 0x%08x (0x%08x), %d\n", newPos, priv->read_pos, *max - left);*/
464        priv->read_pos = newPos;
465
466        /* Return number of entries read */
467        *max = *max - left;
468
469        return 0;
470}
471
472/* Note: This is a shared interrupt handler, with BC/RT driver
473 *       we must determine the cause of IRQ before handling it.
474 */
475void gr1553bm_isr(void *data)
476{
477        struct gr1553bm_priv *priv = data;
478        uint32_t irqflag;
479
480        /* Get Causes */
481        irqflag = priv->regs->irq & (GR1553B_IRQ_BMD | GR1553B_IRQ_BMTOF);
482
483        /* Check spurious IRQs */
484        if ( (irqflag == 0) || (priv->started == 0) )
485                return;
486
487        if ( (irqflag & GR1553B_IRQ_BMTOF) && priv->cfg.time_ovf_irq ) {
488                /* 1553 Time Over flow. Time is 24-bits */
489                priv->time += (GR1553B_BM_TTAG_VAL + 1);
490
491                /* Clear cause handled */
492                priv->regs->irq = GR1553B_IRQ_BMTOF;
493        }
494
495        if ( irqflag & GR1553B_IRQ_BMD ) {
496                /* BM DMA ERROR. Fatal error, we stop BM hardware and let
497                 * user take care of it. From now on all calls will result
498                 * in an error because the BM is stopped (priv->started=0).
499                 */
500
501                /* Clear cause handled */
502                priv->regs->irq = GR1553B_IRQ_BMD;
503
504                if ( priv->cfg.dma_error_isr )
505                        priv->cfg.dma_error_isr(data, priv->cfg.dma_error_arg);
506
507                gr1553bm_hw_stop(priv);
508        }
509}
Note: See TracBrowser for help on using the repository browser.