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

5
Last change on this file since a7267241 was a7267241, checked in by Sebastian Huber <sebastian.huber@…>, on 11/26/18 at 14:44:25

bsps/sparc: Add and use <grlib_impl.h>

Reduce copy and paste.

  • 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 <drvmgr/ambapp_bus.h>
15
16#include <bsp/gr1553b.h>
17#include <bsp/gr1553bm.h>
18
19#include <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 = malloc(sizeof(struct gr1553bm_priv));
133        if ( priv == NULL )
134                goto fail;
135        memset(priv, 0, sizeof(struct gr1553bm_priv));
136
137        /* Init BC device */
138        priv->pdev = pdev;
139        (*pdev)->priv = priv;
140
141        /* Get device information from AMBA PnP information */
142        ambadev = (struct amba_dev_info *)(*pdev)->businfo;
143        pnpinfo = &ambadev->info;
144        priv->regs = (struct gr1553b_regs *)pnpinfo->apb_slv->start;
145        SPIN_INIT(&priv->devlock, "gr1553bm");
146
147        /* Start with default configuration */
148        priv->cfg = gr1553bm_default_config;
149
150        /* Unmask IRQs */
151        gr1553bm_hw_stop(priv);
152
153        return priv;
154
155fail:
156        if ( pdev )
157                gr1553_bm_close(pdev);
158        if ( priv )
159                free(priv);
160        return NULL;
161}
162
163/* Close previously */
164void gr1553bm_close(void *bm)
165{
166        struct gr1553bm_priv *priv = bm;
167
168        if ( priv->started ) {
169                gr1553bm_stop(bm);
170        }
171
172        if ( (priv->cfg.buffer_custom == NULL) && priv->buffer )
173                free(priv->buffer);
174
175        gr1553_bm_close(priv->pdev);
176        free(priv);
177}
178
179/* Configure the BM driver */
180int gr1553bm_config(void *bm, struct gr1553bm_config *cfg)
181{
182        struct gr1553bm_priv *priv = bm;
183
184        if ( priv->started )
185                return -1;
186
187        /* Check Config validity? */
188/*#warning IMPLEMENT.*/
189
190        /* Free old buffer if dynamically allocated */
191        if ( (priv->cfg.buffer_custom == NULL) && priv->buffer ) {
192                free(priv->buffer);
193                priv->buffer = NULL;
194        }
195        priv->buffer_size = cfg->buffer_size & ~0x7; /* on 8 byte bounadry */
196        if ((unsigned int)cfg->buffer_custom & 1) {
197                /* Custom Address Given in Remote address. We need
198                 * to convert it intoTranslate into Hardware a
199                 * hardware accessible address
200                 */
201                priv->buffer_base_hw = (unsigned int)cfg->buffer_custom & ~1;
202                priv->buffer = cfg->buffer_custom;
203                drvmgr_translate_check(
204                        *priv->pdev,
205                        DMAMEM_TO_CPU,
206                        (void *)priv->buffer_base_hw,
207                        (void **)&priv->buffer_base,
208                        priv->buffer_size);
209        } else {
210                if (cfg->buffer_custom == NULL) {
211                        /* Allocate new buffer dynamically */
212                        priv->buffer = malloc(priv->buffer_size + 8);
213                        if (priv->buffer == NULL)
214                                return -1;
215                } else {
216                        /* Address given in CPU accessible address, no
217                         * translation required.
218                         */
219                        priv->buffer = cfg->buffer_custom;
220                }
221                /* Align to 16 bytes */
222                priv->buffer_base = ((unsigned int)priv->buffer + (8-1)) &
223                                        ~(8-1);
224                /* Translate address of buffer base into address that Hardware must
225                 * use to access the buffer.
226                 */
227                drvmgr_translate_check(
228                        *priv->pdev,
229                        CPUMEM_TO_DMA,
230                        (void *)priv->buffer_base,
231                        (void **)&priv->buffer_base_hw,
232                        priv->buffer_size);
233               
234        }
235
236        /* Copy valid config */
237        priv->cfg = *cfg;
238
239        return 0;
240}
241
242/* Start logging */
243int gr1553bm_start(void *bm)
244{
245        struct gr1553bm_priv *priv = bm;
246
247        if ( priv->started )
248                return -1;
249        if ( priv->buffer == NULL )
250                return -2;
251
252        /* Start at Time = 0 */
253        priv->regs->bm_ttag =
254                priv->cfg.time_resolution << GR1553B_BM_TTAG_RES_BIT;
255
256        /* Configure Filters */
257        priv->regs->bm_adr = priv->cfg.filt_rtadr;
258        priv->regs->bm_subadr = priv->cfg.filt_subadr;
259        priv->regs->bm_mc = priv->cfg.filt_mc;
260
261        /* Set up buffer */
262        priv->regs->bm_start = priv->buffer_base_hw;
263        priv->regs->bm_end = priv->buffer_base_hw + priv->cfg.buffer_size - 4;
264        priv->regs->bm_pos = priv->buffer_base_hw;
265        priv->read_pos = priv->buffer_base;
266        priv->buffer_end = priv->buffer_base + priv->cfg.buffer_size;
267
268        /* Register ISR handler and unmask IRQ source at IRQ controller */
269        if (drvmgr_interrupt_register(*priv->pdev, 0, "gr1553bm", gr1553bm_isr, priv))
270                return -3;
271
272        /* Start hardware and set priv->started */
273        gr1553bm_hw_start(priv);
274
275        return 0;
276}
277
278/* Stop logging */
279void gr1553bm_stop(void *bm)
280{
281        struct gr1553bm_priv *priv = bm;
282
283        /* Stop Hardware */
284        gr1553bm_hw_stop(priv);
285
286        /* At this point the hardware must be stopped and IRQ
287         * sources unmasked.
288         */
289
290        /* Unregister ISR handler and unmask 1553 IRQ source at IRQ ctrl */
291        drvmgr_interrupt_unregister(*priv->pdev, 0, gr1553bm_isr, priv);
292}
293
294int gr1553bm_started(void *bm)
295{
296        return ((struct gr1553bm_priv *)bm)->started;
297}
298
299/* Get 64-bit 1553 Time.
300 *
301 * Update software time counters and return the current time.
302 */
303void gr1553bm_time(void *bm, uint64_t *time)
304{
305        struct gr1553bm_priv *priv = bm;
306        unsigned int hwtime, hwtime2;
307
308resample:
309        if ( priv->started && (priv->cfg.time_ovf_irq == 0) ) {
310                /* Update Time overflow counter. The carry bit from Time counter
311                 * is located in IRQ Flag.
312                 *
313                 * When IRQ is not used this function must be called often
314                 * enough to avoid that the Time overflows and the carry
315                 * bit is already set. The frequency depends on the Time
316                 * resolution.
317                 */
318                if ( priv->regs->irq & GR1553B_IRQ_BMTOF ) {
319                        /* Clear carry bit */
320                        priv->regs->irq = GR1553B_IRQ_BMTOF;
321                        priv->time += (GR1553B_BM_TTAG_VAL + 1);
322                }
323        }
324
325        /* Report current Time, even if stopped */
326        hwtime = priv->regs->bm_ttag & GR1553B_BM_TTAG_VAL;
327        if ( time )
328                *time = priv->time | hwtime;
329
330        if ( priv->cfg.time_ovf_irq ) {
331                /* Detect wrap around */
332                hwtime2 = priv->regs->bm_ttag & GR1553B_BM_TTAG_VAL;
333                if ( hwtime > hwtime2 ) {
334                        /* priv->time and hwtime may be out of sync if
335                         * IRQ updated priv->time just after bm_ttag was read
336                         * here, we resample if we detect inconsistancy.
337                         */
338                        goto resample;
339                }
340        }
341}
342
343/* Number of entries available in DMA buffer */
344int gr1553bm_available(void *bm, int *nentries)
345{
346        struct gr1553bm_priv *priv = bm;
347        unsigned int top, bot, pos;
348
349        if ( !priv->started )
350                return -1;
351
352        /* Get BM posistion in log */
353        pos = priv->regs->bm_pos;
354
355        /* Convert into CPU accessible address */
356        pos = priv->buffer_base + (pos - priv->buffer_base_hw);
357
358        if ( pos >= priv->read_pos ) {
359                top = (pos - priv->read_pos)/sizeof(struct gr1553bm_entry);
360                bot = 0;
361        } else {
362                top = (priv->buffer_end - priv->read_pos)/sizeof(struct gr1553bm_entry);
363                bot = (pos - priv->buffer_base)/sizeof(struct gr1553bm_entry);
364        }
365
366        if ( nentries )
367                *nentries = top+bot;
368
369        return 0;
370}
371
372/* Read a maximum number of entries from LOG buffer. */
373int gr1553bm_read(void *bm, struct gr1553bm_entry *dst, int *max)
374{
375        struct gr1553bm_priv *priv = bm;
376        unsigned int dest, pos, left, newPos, len;
377        unsigned int topAdr, botAdr, topLen, botLen;
378
379        if ( !priv || !priv->started )
380                return -1;
381
382        left = *max;
383        pos = priv->regs->bm_pos & ~0x7;
384
385        /* Convert into CPU accessible address */
386        pos = priv->buffer_base + (pos - priv->buffer_base_hw);
387
388        if ( (pos == priv->read_pos) || (left < 1) ) {
389                /* No data available */
390                *max = 0;
391                return 0;
392        }
393        newPos = 0;
394
395        /* Addresses and lengths of BM log buffer */
396        if ( pos >= priv->read_pos ) {
397                /* Read Top only */
398                topAdr = priv->read_pos;
399                botAdr = 0;
400                topLen = (pos - priv->read_pos)/sizeof(struct gr1553bm_entry);
401                botLen = 0;
402        } else {
403                /* Read Top and Bottom */
404                topAdr = priv->read_pos;
405                botAdr = priv->buffer_base;
406                topLen = (priv->buffer_end - priv->read_pos)/sizeof(struct gr1553bm_entry);
407                botLen = (pos - priv->buffer_base)/sizeof(struct gr1553bm_entry);
408        }
409
410        dest = (unsigned int)dst;
411        if ( topLen > 0 ) {
412                /* Copy from top area first */
413                if ( topLen > left ) {
414                        len = left;
415                        left = 0;
416                } else {
417                        len = topLen;
418                        left -= topLen;
419                }
420                newPos = topAdr + (len * sizeof(struct gr1553bm_entry));
421                if ( newPos >= priv->buffer_end )
422                        newPos -= priv->buffer_size;
423                if ( priv->cfg.copy_func ) {
424                        dest += priv->cfg.copy_func(
425                                dest,                   /*Optional Destination*/
426                                (void *)topAdr,         /* DMA start address */
427                                len,                    /* Number of entries */
428                                priv->cfg.copy_func_arg /* Custom ARG */
429                                );
430                } else {
431                        memcpy( (void *)dest,
432                                (void *)topAdr,
433                                len * sizeof(struct gr1553bm_entry));
434                        dest += len * sizeof(struct gr1553bm_entry);
435                }
436        }
437
438        if ( (botLen > 0) && (left > 0) ) {
439                /* Copy bottom area last */
440                if ( botLen > left ) {
441                        len = left;
442                        left = 0;
443                } else {
444                        len = botLen;
445                        left -= botLen;
446                }
447                newPos = botAdr + (len * sizeof(struct gr1553bm_entry));
448
449                if ( priv->cfg.copy_func ) {
450                        priv->cfg.copy_func(
451                                dest,                   /*Optional Destination*/
452                                (void *)botAdr,         /* DMA start address */
453                                len,                    /* Number of entries */
454                                priv->cfg.copy_func_arg /* Custom ARG */
455                                );
456                } else {
457                        memcpy( (void *)dest,
458                                (void *)botAdr,
459                                len * sizeof(struct gr1553bm_entry));
460                }
461        }
462
463        /* Remember last read posistion in buffer */
464        /*printf("New pos: 0x%08x (0x%08x), %d\n", newPos, priv->read_pos, *max - left);*/
465        priv->read_pos = newPos;
466
467        /* Return number of entries read */
468        *max = *max - left;
469
470        return 0;
471}
472
473/* Note: This is a shared interrupt handler, with BC/RT driver
474 *       we must determine the cause of IRQ before handling it.
475 */
476void gr1553bm_isr(void *data)
477{
478        struct gr1553bm_priv *priv = data;
479        uint32_t irqflag;
480
481        /* Get Causes */
482        irqflag = priv->regs->irq & (GR1553B_IRQ_BMD | GR1553B_IRQ_BMTOF);
483
484        /* Check spurious IRQs */
485        if ( (irqflag == 0) || (priv->started == 0) )
486                return;
487
488        if ( (irqflag & GR1553B_IRQ_BMTOF) && priv->cfg.time_ovf_irq ) {
489                /* 1553 Time Over flow. Time is 24-bits */
490                priv->time += (GR1553B_BM_TTAG_VAL + 1);
491
492                /* Clear cause handled */
493                priv->regs->irq = GR1553B_IRQ_BMTOF;
494        }
495
496        if ( irqflag & GR1553B_IRQ_BMD ) {
497                /* BM DMA ERROR. Fatal error, we stop BM hardware and let
498                 * user take care of it. From now on all calls will result
499                 * in an error because the BM is stopped (priv->started=0).
500                 */
501
502                /* Clear cause handled */
503                priv->regs->irq = GR1553B_IRQ_BMD;
504
505                if ( priv->cfg.dma_error_isr )
506                        priv->cfg.dma_error_isr(data, priv->cfg.dma_error_arg);
507
508                gr1553bm_hw_stop(priv);
509        }
510}
Note: See TracBrowser for help on using the repository browser.