source: rtems/c/src/lib/libbsp/sparc/shared/pci/gr_tmtc_1553.c @ ce76b9d2

5
Last change on this file since ce76b9d2 was ce76b9d2, checked in by Daniel Hellstrom <daniel@…>, on 05/08/17 at 12:58:41

leon, pci-peripherals: SMP support by spin-locks and updated genirq

  • Property mode set to 100644
File size: 15.7 KB
Line 
1/*  GR-TMTC-1553 PCI Target driver.
2 *
3 *  COPYRIGHT (c) 2008.
4 *  Cobham Gaisler AB.
5 *
6 *  Configures the GR-TMTC-1553 interface PCI board.
7 *  This driver provides a AMBA PnP bus by using the general part
8 *  of the AMBA PnP bus driver (ambapp_bus.c).
9 *
10 *  Driver resources for the AMBA PnP bus provided can be set using
11 *  gr_tmtc_1553_set_resources().
12 *
13 *  The license and distribution terms for this file may be
14 *  found in found in the file LICENSE in this distribution or at
15 *  http://www.rtems.org/license/LICENSE.
16 */
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23
24#include <bsp.h>
25#include <rtems/bspIo.h>
26#include <rtems/score/isrlock.h> /* spin-lock */
27#include <pci.h>
28#include <pci/access.h>
29
30#include <ambapp.h>
31#include <grlib.h>
32#include <drvmgr/drvmgr.h>
33#include <drvmgr/ambapp_bus.h>
34#include <drvmgr/pci_bus.h>
35#include <drvmgr/bspcommon.h>
36#include <bsp/genirq.h>
37
38#include <bsp/gr_tmtc_1553.h>
39
40/* map via rtems_interrupt_lock_* API: */
41#define SPIN_DECLARE(lock) RTEMS_INTERRUPT_LOCK_MEMBER(lock)
42#define SPIN_INIT(lock, name) rtems_interrupt_lock_initialize(lock, name)
43#define SPIN_LOCK(lock, level) rtems_interrupt_lock_acquire_isr(lock, &level)
44#define SPIN_LOCK_IRQ(lock, level) rtems_interrupt_lock_acquire(lock, &level)
45#define SPIN_UNLOCK(lock, level) rtems_interrupt_lock_release_isr(lock, &level)
46#define SPIN_UNLOCK_IRQ(lock, level) rtems_interrupt_lock_release(lock, &level)
47#define SPIN_IRQFLAGS(k) rtems_interrupt_lock_context k
48#define SPIN_ISR_IRQFLAGS(k) SPIN_IRQFLAGS(k)
49
50/*#define DEBUG 1 */
51
52#ifdef DEBUG
53#define DBG(x...) printk(x)
54#else
55#define DBG(x...)
56#endif
57
58/* PCI ID */
59#define PCIID_VENDOR_GAISLER            0x1AC8
60
61int gr_tmtc_1553_init1(struct drvmgr_dev *dev);
62int gr_tmtc_1553_init2(struct drvmgr_dev *dev);
63void gr_tmtc_1553_isr (void *arg);
64
65struct gr_tmtc_1553_ver {
66        const unsigned int      amba_freq_hz;   /* The frequency */
67        const unsigned int      amba_ioarea;    /* The address where the PnP IOAREA starts at */
68};
69
70/* Private data structure for driver */
71struct gr_tmtc_1553_priv {
72        /* Driver management */
73        struct drvmgr_dev               *dev;
74        char                            prefix[32];
75        SPIN_DECLARE(devlock);
76
77        /* PCI */
78        pci_dev_t                       pcidev;
79        struct pci_dev_info             *devinfo;
80
81        /* IRQ */
82        genirq_t                        genirq;
83
84        struct gr_tmtc_1553_ver         *version;
85        struct irqmp_regs               *irq;
86        struct drvmgr_map_entry         bus_maps_down[2];
87
88        struct ambapp_bus               abus;
89        struct ambapp_mmap              amba_maps[4];
90        struct ambapp_config            config;
91};
92
93struct gr_tmtc_1553_ver gr_tmtc_1553_ver0 = {
94        .amba_freq_hz           = 33333333,
95        .amba_ioarea            = 0xfff00000,
96};
97
98
99int ambapp_tmtc_1553_int_register(
100        struct drvmgr_dev *dev,
101        int irq,
102        const char *info,
103        drvmgr_isr handler,
104        void *arg);
105int ambapp_tmtc_1553_int_unregister(
106        struct drvmgr_dev *dev,
107        int irq,
108        drvmgr_isr handler,
109        void *arg);
110int ambapp_tmtc_1553_int_unmask(
111        struct drvmgr_dev *dev,
112        int irq);
113int ambapp_tmtc_1553_int_mask(
114        struct drvmgr_dev *dev,
115        int irq);
116int ambapp_tmtc_1553_int_clear(
117        struct drvmgr_dev *dev,
118        int irq);
119int ambapp_tmtc_1553_get_params(
120        struct drvmgr_dev *dev,
121        struct drvmgr_bus_params *params);
122
123struct ambapp_ops ambapp_tmtc_1553_ops = {
124        .int_register = ambapp_tmtc_1553_int_register,
125        .int_unregister = ambapp_tmtc_1553_int_unregister,
126        .int_unmask = ambapp_tmtc_1553_int_unmask,
127        .int_mask = ambapp_tmtc_1553_int_mask,
128        .int_clear = ambapp_tmtc_1553_int_clear,
129        .get_params = ambapp_tmtc_1553_get_params
130};
131
132struct drvmgr_drv_ops gr_tmtc_1553_ops =
133{
134        {gr_tmtc_1553_init1, gr_tmtc_1553_init2, NULL, NULL},
135        NULL,
136        NULL
137};
138
139struct pci_dev_id_match gr_tmtc_1553_ids[] =
140{
141        PCIID_DEVVEND(PCIID_VENDOR_GAISLER, PCIID_DEVICE_GR_TMTC_1553),
142        PCIID_END_TABLE /* Mark end of table */
143};
144
145struct pci_drv_info gr_tmtc_1553_info =
146{
147        {
148                DRVMGR_OBJ_DRV,                 /* Driver */
149                NULL,                           /* Next driver */
150                NULL,                           /* Device list */
151                DRIVER_PCI_GAISLER_TMTC_1553_ID, /* Driver ID */
152                "GR-TMTC-1553_DRV",             /* Driver Name */
153                DRVMGR_BUS_TYPE_PCI,            /* Bus Type */
154                &gr_tmtc_1553_ops,
155                NULL,                           /* Funcs */
156                0,                              /* No devices yet */
157                0,
158        },
159        &gr_tmtc_1553_ids[0]
160};
161
162/* Driver resources configuration for the AMBA bus on the GR-RASTA-IO board.
163 * It is declared weak so that the user may override it from the project file,
164 * if the default settings are not enough.
165 *
166 * The configuration consists of an array of configuration pointers, each
167 * pointer determine the configuration of one GR-RASTA-IO board. Pointer
168 * zero is for board0, pointer 1 for board1 and so on.
169 *
170 * The array must end with a NULL pointer.
171 */
172struct drvmgr_bus_res *gr_tmtc_1553_resources[] __attribute__((weak)) =
173{
174        NULL
175};
176
177void gr_tmtc_1553_register_drv(void)
178{
179        DBG("Registering GR-TMTC-1553 PCI driver\n");
180        drvmgr_drv_register(&gr_tmtc_1553_info.general);
181}
182
183void gr_tmtc_1553_isr (void *arg)
184{
185        struct gr_tmtc_1553_priv *priv = arg;
186        unsigned int status, tmp;
187        int irq;
188        SPIN_ISR_IRQFLAGS(irqflags);
189
190        tmp = status = priv->irq->ipend;
191
192        /* DBG("GR-RASTA-IO: IRQ 0x%x\n",status); */
193
194        SPIN_LOCK(&priv->devlock, irqflags);
195        for(irq=0; irq<16; irq++) {
196                if ( status & (1<<irq) ) {
197                        genirq_doirq(priv->genirq, irq);
198                        priv->irq->iclear = (1<<irq);
199                        status &= ~(1<<irq);
200                        if ( status == 0 )
201                                break;
202                }
203        }
204        SPIN_UNLOCK(&priv->devlock, irqflags);
205
206        /* ACK interrupt, this is because PCI is Level, so the IRQ Controller still drives the IRQ. */
207        if ( tmp )
208                drvmgr_interrupt_clear(priv->dev, 0);
209
210        DBG("GR-TMTC-1553-IRQ: 0x%x\n", tmp);
211}
212
213static int gr_tmtc_1553_hw_init(struct gr_tmtc_1553_priv *priv)
214{
215        unsigned int *page0 = NULL;
216        struct ambapp_dev *tmp;
217        unsigned int pci_freq_hz;
218        struct pci_dev_info *devinfo = priv->devinfo;
219        uint32_t bar0, bar0_size;
220
221        /* Select version of GR-TMTC-1553 board */
222        switch (devinfo->rev) {
223                case 0:
224                        priv->version = &gr_tmtc_1553_ver0;
225                        break;
226                default:
227                        return -2;
228        }
229
230        bar0 = devinfo->resources[0].address;
231        bar0_size = devinfo->resources[0].size;
232        page0 = (unsigned int *)(bar0 + bar0_size/2);
233
234        /* Point PAGE0 to start of board address map. RAM at 0xff000000, APB at 0xffc00000, IOAREA at 0xfff000000 */
235        /* XXX We assume little endian host with byte twisting enabled here */
236        *page0 = 0x010000ff;    /* Set little endian mode on peripheral. */
237
238        /* Scan AMBA Plug&Play */
239
240        /* AMBA MAP bar0 (in CPU) ==> 0x80000000(remote amba address) */
241        priv->amba_maps[0].size = 0x1000000;
242        priv->amba_maps[0].local_adr = bar0;
243        priv->amba_maps[0].remote_adr = 0xff000000;
244       
245        /* Addresses not matching with map be untouched */
246        priv->amba_maps[2].size = 0xfffffff0;
247        priv->amba_maps[2].local_adr = 0;
248        priv->amba_maps[2].remote_adr = 0;
249
250        /* Mark end of table */
251        priv->amba_maps[3].size=0;
252        priv->amba_maps[3].local_adr = 0;
253        priv->amba_maps[3].remote_adr = 0;
254
255        /* Start AMBA PnP scan at first AHB bus */
256        ambapp_scan(&priv->abus,
257                bar0 + (priv->version->amba_ioarea & ~0xff000000),
258                NULL, &priv->amba_maps[0]);
259
260        /* Frequency is the hsame as the PCI bus frequency */
261        drvmgr_freq_get(priv->dev, 0, &pci_freq_hz);
262
263        ambapp_freq_init(&priv->abus, NULL, pci_freq_hz);
264
265        /* Find IRQ controller */
266        tmp = (struct ambapp_dev *)ambapp_for_each(&priv->abus,
267                                        (OPTIONS_ALL|OPTIONS_APB_SLVS),
268                                        VENDOR_GAISLER, GAISLER_IRQMP,
269                                        ambapp_find_by_idx, NULL);
270        if ( !tmp ) {
271                return -4;
272        }
273        priv->irq = (struct irqmp_regs *)DEV_TO_APB(tmp)->start;
274        /* Set up irq controller */
275        priv->irq->mask[0] = 0;
276        priv->irq->iclear = 0xffff;
277        priv->irq->ilevel = 0;
278
279        /* DOWN streams translation table */
280        priv->bus_maps_down[0].name = "PCI BAR0 -> AMBA";
281        priv->bus_maps_down[0].size = priv->amba_maps[0].size;
282        priv->bus_maps_down[0].from_adr = (void *)priv->amba_maps[0].local_adr;
283        priv->bus_maps_down[0].to_adr = (void *)priv->amba_maps[0].remote_adr;
284        /* Mark end of translation table */
285        priv->bus_maps_down[1].size = 0;
286
287        /* Successfully registered the board */
288        return 0;
289}
290
291
292/* Called when a PCI target is found with the PCI device and vendor ID
293 * given in gr_tmtc_1553_ids[].
294 */
295int gr_tmtc_1553_init1(struct drvmgr_dev *dev)
296{
297        struct gr_tmtc_1553_priv *priv;
298        struct pci_dev_info *devinfo;
299        int status;
300        uint32_t bar0, bar0_size;
301        int resources_cnt;
302
303        /* PCI device does not have the IRQ line register, when PCI autoconf configures it the configuration
304         * is forgotten. We take the IRQ number from the PCI Host device (AMBA device), this works as long
305         * as PCI-IRQs are ored together on the bus.
306         *
307         * Note that this only works on LEON.
308         */
309        ((struct pci_dev_info *)dev->businfo)->irq = ((struct amba_dev_info *)dev->parent->dev->businfo)->info.irq;
310
311        priv = malloc(sizeof(struct gr_tmtc_1553_priv));
312        if ( !priv )
313                return DRVMGR_NOMEM;
314
315        memset(priv, 0, sizeof(*priv));
316        dev->priv = priv;
317        priv->dev = dev;
318
319        /* Determine number of configurations */
320        resources_cnt = get_resarray_count(gr_tmtc_1553_resources);
321
322        /* Generate Device prefix */
323
324        strcpy(priv->prefix, "/dev/tmtc1553_0");
325        priv->prefix[14] += dev->minor_drv;
326        mkdir(priv->prefix, S_IRWXU | S_IRWXG | S_IRWXO);
327        priv->prefix[15] = '/';
328        priv->prefix[16] = '\0';
329
330        priv->devinfo = devinfo = (struct pci_dev_info *)dev->businfo;
331        priv->pcidev = devinfo->pcidev;
332        bar0 = devinfo->resources[0].address;
333        bar0_size = devinfo->resources[0].size;
334        printf("\n\n--- GR-TMTC-1553[%d] ---\n", dev->minor_drv);
335        printf(" PCI BUS: 0x%x, SLOT: 0x%x, FUNCTION: 0x%x\n",
336                PCI_DEV_EXPAND(priv->pcidev));
337        printf(" PCI VENDOR: 0x%04x, DEVICE: 0x%04x\n",
338                devinfo->id.vendor, devinfo->id.device);
339        printf(" PCI BAR[0]: 0x%lx - 0x%lx\n", bar0, bar0 + bar0_size - 1);
340        printf(" IRQ: %d\n\n\n", devinfo->irq);
341
342        /* all neccessary space assigned to GR-TMTC-1553 target? */
343        if (bar0_size == 0)
344                return DRVMGR_ENORES;
345
346        /* Initialize spin-lock for this PCI peripheral device. This is to
347         * protect the Interrupt Controller Registers. The genirq layer is
348         * protecting its own internals and ISR dispatching.
349         */
350        SPIN_INIT(&priv->devlock, priv->prefix);
351
352        priv->genirq = genirq_init(16);
353        if ( priv->genirq == NULL ) {
354                free(priv);
355                dev->priv = NULL;
356                return DRVMGR_FAIL;
357        }
358
359        status = gr_tmtc_1553_hw_init(priv);
360        if ( status != 0 ) {
361                genirq_destroy(priv->genirq);
362                free(priv);
363                dev->priv = NULL;
364                printf(" Failed to initialize GR-TMTC-1553 HW: %d\n", status);
365                return DRVMGR_FAIL;
366        }
367
368        /* Init amba bus */
369        priv->config.abus = &priv->abus;
370        priv->config.ops = &ambapp_tmtc_1553_ops;
371        priv->config.maps_down = &priv->bus_maps_down[0];
372        /* This PCI device has only target interface so DMA is not supported,
373         * which means that translation from AMBA->PCI should fail if attempted.
374         */
375        priv->config.maps_up = DRVMGR_TRANSLATE_NO_BRIDGE;
376        if ( priv->dev->minor_drv < resources_cnt ) {
377                priv->config.resources = gr_tmtc_1553_resources[priv->dev->minor_drv];
378        } else {
379                priv->config.resources = NULL;
380        }
381
382        /* Create And Register AMBA PnP Bus */
383        return ambapp_bus_register(dev, &priv->config);
384}
385
386int gr_tmtc_1553_init2(struct drvmgr_dev *dev)
387{
388        struct gr_tmtc_1553_priv *priv = dev->priv;
389
390        /* Clear any old interrupt requests */
391        drvmgr_interrupt_clear(dev, 0);
392
393        /* Enable System IRQ so that GR-TMTC-1553 PCI target interrupt goes through.
394         *
395         * It is important to enable it in stage init2. If interrupts were enabled in init1
396         * this might hang the system when more than one PCI target is connected, this is
397         * because PCI interrupts might be shared and PCI target 2 have not initialized and
398         * might therefore drive interrupt already when entering init1().
399         */
400        drvmgr_interrupt_register(
401                dev,
402                0,
403                "gr_tmtc_1553",
404                gr_tmtc_1553_isr,
405                (void *)priv);
406
407        return DRVMGR_OK;
408}
409
410int ambapp_tmtc_1553_int_register(
411        struct drvmgr_dev *dev,
412        int irq,
413        const char *info,
414        drvmgr_isr handler,
415        void *arg)
416{
417        struct gr_tmtc_1553_priv *priv = dev->parent->dev->priv;
418        SPIN_IRQFLAGS(irqflags);
419        int status;
420        void *h;
421
422        h = genirq_alloc_handler(handler, arg);
423        if ( h == NULL )
424                return DRVMGR_FAIL;
425
426        SPIN_LOCK_IRQ(&priv->devlock, irqflags);
427
428        status = genirq_register(priv->genirq, irq, h);
429        if ( status == 0 ) {
430                /* Disable and clear IRQ for first registered handler */
431                priv->irq->iclear = (1<<irq);
432                priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
433        } else if ( status == 1 )
434                status = 0;
435
436        if (status != 0) {
437                SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
438                genirq_free_handler(h);
439                return DRVMGR_FAIL;
440        }
441
442        status = genirq_enable(priv->genirq, irq, handler, arg);
443        if ( status == 0 ) {
444                /* Enable IRQ for first enabled handler only */
445                priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
446        } else if ( status == 1 )
447                status = 0;
448
449        SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
450
451        return status;
452}
453
454int ambapp_tmtc_1553_int_unregister(
455        struct drvmgr_dev *dev,
456        int irq,
457        drvmgr_isr isr,
458        void *arg)
459{
460        struct gr_tmtc_1553_priv *priv = dev->parent->dev->priv;
461        SPIN_IRQFLAGS(irqflags);
462        int status;
463        void *handler;
464
465        SPIN_LOCK_IRQ(&priv->devlock, irqflags);
466
467        status = genirq_disable(priv->genirq, irq, isr, arg);
468        if ( status == 0 ) {
469                /* Disable IRQ only when no enabled handler exists */
470                priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
471        } else if ( status == 1 )
472                status = 0;
473
474        handler = genirq_unregister(priv->genirq, irq, isr, arg);
475        if ( handler == NULL )
476                status = DRVMGR_FAIL;
477        else
478                status = DRVMGR_OK;
479
480        SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
481
482        if (handler)
483                genirq_free_handler(handler);
484
485        return status;
486}
487
488int ambapp_tmtc_1553_int_unmask(
489        struct drvmgr_dev *dev,
490        int irq)
491{
492        struct gr_tmtc_1553_priv *priv = dev->parent->dev->priv;
493        SPIN_IRQFLAGS(irqflags);
494
495        DBG("TMTC-1553 IRQ %d: enable\n", irq);
496       
497        if ( genirq_check(priv->genirq, irq) )
498                return DRVMGR_FAIL;
499
500        SPIN_LOCK_IRQ(&priv->devlock, irqflags);
501
502        /* Enable IRQ */
503        priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
504
505        SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
506
507        return DRVMGR_OK;
508}
509
510int ambapp_tmtc_1553_int_mask(
511        struct drvmgr_dev *dev,
512        int irq)
513{
514        struct gr_tmtc_1553_priv *priv = dev->parent->dev->priv;
515        SPIN_IRQFLAGS(irqflags);
516
517        DBG("TMTC-1553 IRQ %d: disable\n", irq);
518
519        if ( genirq_check(priv->genirq, irq) )
520                return DRVMGR_FAIL;
521
522        SPIN_LOCK_IRQ(&priv->devlock, irqflags);
523
524        /* Disable IRQ */
525        priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
526
527        SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
528
529        return DRVMGR_OK;
530}
531
532int ambapp_tmtc_1553_int_clear(
533        struct drvmgr_dev *dev,
534        int irq)
535{
536        struct gr_tmtc_1553_priv *priv = dev->parent->dev->priv;
537
538        if ( genirq_check(priv->genirq, irq) )
539                return DRVMGR_FAIL;
540
541        priv->irq->iclear = (1<<irq);
542
543        return DRVMGR_OK;
544}
545
546int ambapp_tmtc_1553_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params)
547{
548        struct gr_tmtc_1553_priv *priv = dev->parent->dev->priv;
549
550        /* Device name prefix pointer, skip /dev */
551        params->dev_prefix = &priv->prefix[5];
552
553        return 0;
554}
555
556void gr_tmtc_1553_print_dev(struct drvmgr_dev *dev, int options)
557{
558        struct gr_tmtc_1553_priv *priv = dev->priv;
559        struct pci_dev_info *devinfo = priv->devinfo;
560        uint32_t bar0, bar0_size;
561
562        /* Print */
563        printf("--- GR-TMTC-1553 [bus 0x%x, dev 0x%x, fun 0x%x] ---\n",
564                PCI_DEV_EXPAND(priv->pcidev));
565
566        bar0 = devinfo->resources[0].address;
567        bar0_size = devinfo->resources[0].size;
568
569        printf(" PCI BAR[0]: 0x%lx - 0x%lx\n", bar0, bar0 + bar0_size - 1);
570        printf(" IRQ REGS:        0x%x\n", (unsigned int)priv->irq);
571        printf(" IRQ:             %d\n", devinfo->irq);
572        printf(" FREQ:            %d Hz\n", priv->version->amba_freq_hz);
573        printf(" IMASK:           0x%08x\n", priv->irq->mask[0]);
574        printf(" IPEND:           0x%08x\n", priv->irq->ipend);
575
576        /* Print amba config */
577        if ( options & TMTC_1553_OPTIONS_AMBA ) {
578                ambapp_print(&priv->abus, 10);
579        }
580#if 0
581        /* Print IRQ handlers and their arguments */
582        if ( options & TMTC_1553_OPTIONS_IRQ ) {
583                int i;
584                for(i=0; i<16; i++) {
585                        printf(" IRQ[%02d]:         0x%x, arg: 0x%x\n",
586                                i, (unsigned int)priv->isrs[i].handler, (unsigned int)priv->isrs[i].arg);
587                }
588        }
589#endif
590}
591
592void gr_tmtc_1553_print(int options)
593{
594        struct pci_drv_info *drv = &gr_tmtc_1553_info;
595        struct drvmgr_dev *dev;
596
597        dev = drv->general.dev;
598        while(dev) {
599                gr_tmtc_1553_print_dev(dev, options);
600                dev = dev->next_in_drv;
601        }
602}
Note: See TracBrowser for help on using the repository browser.