source: rtems/c/src/lib/libbsp/sparc/shared/1553/gr1553bm.c @ 4a7d1026

4.11
Last change on this file since 4a7d1026 was 4a7d1026, checked in by Daniel Hellstrom <daniel@…>, on Apr 13, 2015 at 8:25:52 AM

sparc bsps: updated license to rtems.org

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