source: rtems/c/src/lib/libbsp/sparc/shared/pci/gr_leon4_n2x.c @ 4d3e70f4

4.115
Last change on this file since 4d3e70f4 was 4d3e70f4, checked in by Daniel Hellstrom <daniel@…>, on Apr 13, 2015 at 9:26:52 AM

DRVMGR: KEY_TYPE now a enum drvmgr_kt

  • Property mode set to 100644
File size: 21.4 KB
Line 
1/*  GR-CPCI-LEON4-N2X (NGFP) PCI Peripheral driver
2 *
3 *  COPYRIGHT (c) 2013.
4 *  Cobham Gaisler AB.
5 *
6 *  The license and distribution terms for this file may be
7 *  found in found in the file LICENSE in this distribution or at
8 *  http://www.rtems.org/license/LICENSE.
9 *
10 *  Configures the GR-CPIC-LEON4-N2X interface PCI board in peripheral
11 *  mode. This driver provides a AMBA PnP bus by using the general part
12 *  of the AMBA PnP bus driver (ambapp_bus.c).
13 *
14 *
15 *  Driver resource options:
16 *   NAME          DEFAULT VALUE
17 *   ahbmst2pci    _RAM_START            AMBA->PCI translation PCI base address
18 *   ambaFreq      200000000 (200MHz)    AMBA system frequency of LEON4-N2X
19 *   cgEnMask      0x1f (all)            Clock gating enable mask
20 *
21 * TODO/UNTESTED
22 *   Interrupt testing
23 *   bar0 RESOURCE 0x00000000            L2-Cache SDRAM memory
24 *   bar1 RESOURCE 0xf0000000            L2-Cache registers
25 */
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <sys/types.h>
31#include <sys/stat.h>
32
33#include <bsp.h>
34#include <rtems/bspIo.h>
35#include <pci.h>
36
37#include <ambapp.h>
38#include <grlib.h>
39#include <drvmgr/drvmgr.h>
40#include <drvmgr/ambapp_bus.h>
41#include <drvmgr/pci_bus.h>
42#include <drvmgr/bspcommon.h>
43#include <bsp/genirq.h>
44
45#include <bsp/gr_leon4_n2x.h>
46
47/* Determines which PCI address the AHB masters on the LEON-N2X board will
48 * access when accessing the AHB to PCI window, it should be set so that the
49 * masters can access the HOST RAM.
50 * Default is base of HOST RAM, HOST RAM is mapped 1:1 to PCI memory space.
51 */
52extern unsigned int _RAM_START;
53#define AHBMST2PCIADR (((unsigned int)&_RAM_START) & 0xc0000000)
54
55#define GRPCI2_BAR0_TO_AHB_MAP 0x04
56#define GRPCI2_BAR1_TO_AHB_MAP 0x08
57#define GRPCI2_BAR2_TO_AHB_MAP 0x0c
58#define GRPCI2_PCI_CONFIG      0x20
59#define CAP9_AHBPREF_OFS 0x3c
60
61/* #define DEBUG 1 */
62
63#ifdef DEBUG
64#define DBG(x...) printk(x)
65#else
66#define DBG(x...)
67#endif
68
69int gr_cpci_leon4_n2x_init1(struct drvmgr_dev *dev);
70int gr_cpci_leon4_n2x_init2(struct drvmgr_dev *dev);
71void gr_cpci_leon4_n2x_isr(void *arg);
72
73struct grpci2_regs {
74        volatile unsigned int ctrl;             /* 0x00 */
75        volatile unsigned int sts_cap;          /* 0x04 */
76        volatile unsigned int ppref;            /* 0x08 */
77        volatile unsigned int io_map;           /* 0x0C */
78        volatile unsigned int dma_ctrl;         /* 0x10 */
79        volatile unsigned int dma_bdbase;       /* 0x14 */
80        volatile unsigned int dma_chact;        /* 0x18 */
81        int res1;                               /* 0x1C */
82        volatile unsigned int bars[6];          /* 0x20 */
83        int res2[2];                            /* 0x38 */
84        volatile unsigned int ahbmst_map[16];   /* 0x40 */
85};
86
87/* Clock gating unit register layout */
88struct l4n2x_grcg_regs {
89        volatile unsigned int unlock;
90        volatile unsigned int enable;
91        volatile unsigned int reset;
92        volatile unsigned int cpu_fpu;
93};
94#define CG_MASK 0x1f
95
96/* Private data structure for driver */
97struct gr_cpci_leon4_n2x_priv {
98        /* Driver management */
99        struct drvmgr_dev       *dev;
100        char                    prefix[20];
101
102        /* PCI */
103        pci_dev_t               pcidev;
104        struct pci_dev_info     *devinfo;
105        uint32_t                ahbmst2pci_map;
106
107        /* IRQ */
108        int                     eirq;
109        genirq_t                genirq;
110
111        /* GR-CPCI-LEON4-N2X */
112        unsigned int            amba_freq_hz;
113        unsigned int            cg_en_mask;             /* Enabled cores */
114        struct irqmp_regs       *irq;
115        struct l4n2x_grcg_regs  *cg;                    /* Clock-gating unit */
116        struct grpci2_regs      *grpci2;
117        struct drvmgr_map_entry bus_maps_up[2];
118        struct drvmgr_map_entry bus_maps_down[4];
119
120        /* AMBA Plug&Play information on GR-CPCI-LEON4-N2X */
121        struct ambapp_bus       abus;
122        struct ambapp_mmap      amba_maps[5];
123        struct ambapp_config    config;
124};
125
126int ambapp_leon4_n2x_int_register(
127        struct drvmgr_dev *dev,
128        int irq,
129        const char *info,
130        drvmgr_isr handler,
131        void *arg);
132int ambapp_leon4_n2x_int_unregister(
133        struct drvmgr_dev *dev,
134        int irq,
135        drvmgr_isr handler,
136        void *arg);
137int ambapp_leon4_n2x_int_unmask(
138        struct drvmgr_dev *dev,
139        int irq);
140int ambapp_leon4_n2x_int_mask(
141        struct drvmgr_dev *dev,
142        int irq);
143int ambapp_leon4_n2x_int_clear(
144        struct drvmgr_dev *dev,
145        int irq);
146int ambapp_leon4_n2x_get_params(
147        struct drvmgr_dev *dev,
148        struct drvmgr_bus_params *params);
149
150static struct ambapp_ops ambapp_leon4_n2x_ops = {
151        .int_register = ambapp_leon4_n2x_int_register,
152        .int_unregister = ambapp_leon4_n2x_int_unregister,
153        .int_unmask = ambapp_leon4_n2x_int_unmask,
154        .int_mask = ambapp_leon4_n2x_int_mask,
155        .int_clear = ambapp_leon4_n2x_int_clear,
156        .get_params = ambapp_leon4_n2x_get_params
157};
158
159struct drvmgr_drv_ops gr_cpci_leon4_n2x_ops = 
160{
161        .init = {gr_cpci_leon4_n2x_init1, gr_cpci_leon4_n2x_init2, NULL, NULL},
162        .remove = NULL,
163        .info = NULL
164};
165
166struct pci_dev_id_match gr_cpci_leon4_n2x_ids[] =
167{
168        PCIID_DEVVEND(PCIID_VENDOR_GAISLER, PCIID_DEVICE_GR_LEON4_N2X),
169        PCIID_DEVVEND(PCIID_VENDOR_GAISLER, PCIID_DEVICE_GR_NGMP_PROTO),
170        PCIID_END_TABLE /* Mark end of table */
171};
172
173struct pci_drv_info gr_cpci_leon4_n2x_info =
174{
175        {
176                DRVMGR_OBJ_DRV,                 /* Driver */
177                NULL,                           /* Next driver */
178                NULL,                           /* Device list */
179                DRIVER_PCI_GAISLER_LEON4_N2X_ID,/* Driver ID */
180                "GR-CPCI-LEON4-N2X",            /* Driver Name */
181                DRVMGR_BUS_TYPE_PCI,            /* Bus Type */
182                &gr_cpci_leon4_n2x_ops,
183                NULL,                           /* Funcs */
184                0,                              /* No devices yet */
185                sizeof(struct gr_cpci_leon4_n2x_priv),
186        },
187        &gr_cpci_leon4_n2x_ids[0]
188};
189
190/* Driver resources configuration for the AMBA bus on the GR-CPCI-LEON4-N2X board.
191 * It is declared weak so that the user may override it from the project file,
192 * if the default settings are not enough.
193 *
194 * The configuration consists of an array of configuration pointers, each
195 * pointer determine the configuration of one GR-CPCI-LEON4-N2X board. Pointer
196 * zero is for board0, pointer 1 for board1 and so on.
197 *
198 * The array must end with a NULL pointer.
199 */
200struct drvmgr_bus_res *gr_leon4_n2x_resources[] __attribute__((weak)) =
201{
202        NULL
203};
204
205void gr_cpci_leon4_n2x_register_drv(void)
206{
207        DBG("Registering GR-CPCI-LEON4-N2X PCI driver\n");
208        drvmgr_drv_register(&gr_cpci_leon4_n2x_info.general);
209}
210
211void gr_cpci_leon4_n2x_isr(void *arg)
212{
213        struct gr_cpci_leon4_n2x_priv *priv = arg;
214        unsigned int status, tmp;
215        int irq, eirq;
216        tmp = status = priv->irq->ipend;
217
218        /* DBG("GR-CPCI-LEON4-N2X: IRQ 0x%x\n",status); */
219
220        for(irq = 0; irq < 32; irq++) {
221                if (status & (1 << irq)) {
222                        if (irq == priv->eirq) {
223                                while ((eirq = priv->irq->intid[0] & 0x1f)) {
224                                        if ((eirq & 0x10) == 0)
225                                                continue;
226                                        genirq_doirq(priv->genirq, eirq);
227                                        priv->irq->iclear = (1 << eirq);
228                                }
229                        } else {
230                                genirq_doirq(priv->genirq, irq);
231                        }
232                        priv->irq->iclear = (1 << irq);
233                        status &= ~(1 << irq);
234                        if ( status == 0 )
235                                break;
236                }
237        }
238
239        /* ACK interrupt, this is because PCI is Level, so the IRQ Controller
240         * still drives the IRQ
241         */
242        if ( tmp ) 
243                drvmgr_interrupt_clear(priv->dev, 0);
244
245        DBG("RASTA-SPW_ROUTER-IRQ: 0x%x\n", tmp);
246}
247
248static int gr_cpci_leon4_n2x_hw_init1(struct gr_cpci_leon4_n2x_priv *priv)
249{
250        int i;
251        uint32_t data;
252        unsigned int ctrl;
253        uint8_t tmp2;
254        struct ambapp_dev *tmp;
255        struct ambapp_ahb_info *ahb;
256        uint8_t cap_ptr;
257        pci_dev_t pcidev = priv->pcidev;
258        struct pci_dev_info *devinfo = priv->devinfo;
259        unsigned int cgmask, enabled;
260
261        /* Check capabilities list bit and read its pointer */
262        pci_cfg_r8(pcidev, PCIR_STATUS, &tmp2);
263        if (!((tmp2 >> 4) & 1)) {
264                /* Capabilities list not available which it should be in the GRPCI2 */
265                return -2;
266        }
267        pci_cfg_r8(pcidev, PCIR_CAP_PTR, &cap_ptr);
268
269        /* Workarounds depends on PCI revision of GR-CPCI-LEON4-N2X board */
270        switch (devinfo->rev) {
271        case 0:
272                /* Limit the AMBA prefetch for GRPCI2 version 0. */
273                pci_cfg_w32(pcidev, cap_ptr+CAP9_AHBPREF_OFS, 0);
274        default:
275                break;
276        }
277
278        /* Set AHB address mappings for target PCI bars
279         *  BAR0 maps to 0x00000000-0x07ffffff 128MB (SDRAM/DDR2 memory)
280         *  BAR1 maps to 0xf0000000-0xf7ffffff 128MB (L2-Cache regs/diagnostics)
281         *  BAR2 maps to 0xff800000-0xffffffff   8MB (PnP, I/O regs)
282         */
283        pci_cfg_w32(pcidev, cap_ptr+GRPCI2_BAR0_TO_AHB_MAP, 0x00000000);
284        pci_cfg_w32(pcidev, cap_ptr+GRPCI2_BAR1_TO_AHB_MAP, 0xf0000000);
285        pci_cfg_w32(pcidev, cap_ptr+GRPCI2_BAR2_TO_AHB_MAP, 0xff800000);
286
287        /* Set PCI bus to be big endian */
288        pci_cfg_r32(pcidev, cap_ptr+GRPCI2_PCI_CONFIG, &data);
289        data = data & 0xFFFFFFFE;
290        pci_cfg_w32(pcidev, cap_ptr+GRPCI2_PCI_CONFIG, data);
291
292#if 0
293        /* set parity error response */
294        pci_cfg_r32(pcidev, PCIR_COMMAND, &data);
295        pci_cfg_w32(pcidev, PCIR_COMMAND, (data|PCIM_CMD_PERRESPEN));
296#endif
297
298        /* Scan AMBA Plug&Play */
299
300        /* AMBA MAP bar0 (in leon4-n2x) ==> 0x00000000 (remote amba address) */
301        priv->amba_maps[0].size = devinfo->resources[0].size;
302        priv->amba_maps[0].local_adr = devinfo->resources[0].address;
303        priv->amba_maps[0].remote_adr = 0x00000000;
304
305        priv->amba_maps[1].size = devinfo->resources[1].size;
306        priv->amba_maps[1].local_adr = devinfo->resources[1].address;
307        priv->amba_maps[1].remote_adr = 0xf0000000;
308
309        priv->amba_maps[2].size = devinfo->resources[2].size;
310        priv->amba_maps[2].local_adr = devinfo->resources[2].address;
311        priv->amba_maps[2].remote_adr = 0xff800000;
312
313        /* Addresses not matching with map be untouched */
314        priv->amba_maps[3].size = 0xfffffff0;
315        priv->amba_maps[3].local_adr = 0;
316        priv->amba_maps[3].remote_adr = 0;
317
318        /* Mark end of table */
319        priv->amba_maps[4].size=0;
320
321        /* Start AMBA PnP scan at first AHB bus */
322        ambapp_scan(
323                &priv->abus,
324                devinfo->resources[2].address + 0x00700000,
325                NULL,
326                &priv->amba_maps[0]);
327
328        /* Initialize Frequency of AMBA bus */
329        ambapp_freq_init(&priv->abus, NULL, priv->amba_freq_hz);
330
331        /* Find IRQ controller, Clear all current IRQs */
332        tmp = (struct ambapp_dev *)ambapp_for_each(&priv->abus,
333                                (OPTIONS_ALL|OPTIONS_APB_SLVS),
334                                VENDOR_GAISLER, GAISLER_IRQMP,
335                                ambapp_find_by_idx, NULL);
336        if ( !tmp ) {
337                return -4;
338        }
339        priv->irq = (struct irqmp_regs *)DEV_TO_APB(tmp)->start;
340        /* Set up GR-CPCI-LEON4-N2X irq controller
341         * Interrupts are routed from IRQCtrl0, we leave the configuration
342         * for the other CPUs, as the board's CPUs may be running something.
343         * We assume IRQCtrl has been set up properly, or at least the reset
344         * values shuold work with this code..
345         */
346        priv->irq->mask[0] = 0;
347        priv->irq->iforce = 0;
348        priv->irq->force[0] = 0;
349        priv->irq->ilevel = 0;
350        priv->irq->ipend = 0;
351        priv->irq->iclear = 0xffffffff;
352        priv->irq->ilevel = 0;
353        /* Get extended Interrupt controller IRQ number */
354        priv->eirq = (priv->irq->mpstat >> 16) & 0xf;
355
356        /* Find first Clock-Gating unit, enable/disable the requested cores.
357         * It is optional in order to support FPGA prototypes.
358         */
359        priv->cg = NULL;
360        tmp = (struct ambapp_dev *)ambapp_for_each(&priv->abus,
361                                (OPTIONS_ALL|OPTIONS_APB_SLVS),
362                                VENDOR_GAISLER, GAISLER_CLKGATE,
363                                ambapp_find_by_idx, NULL);
364        if (tmp)
365                priv->cg = (struct l4n2x_grcg_regs *)DEV_TO_APB(tmp)->start;
366
367        /* Do reset and enable sequence only if not already enabled */
368        if (priv->cg && ((enabled = priv->cg->enable) != priv->cg_en_mask)) {
369                /* First disable already enabled cores */
370                cgmask = ~priv->cg_en_mask & enabled;
371                if (cgmask) {
372                        priv->cg->unlock = cgmask;
373                        priv->cg->enable = enabled = ~cgmask & enabled;
374                        priv->cg->unlock = 0;
375                }
376                /* Enable disabled cores */
377                cgmask = priv->cg_en_mask & ~enabled;
378                if (cgmask) {
379                        priv->cg->unlock = cgmask;
380                        priv->cg->reset |= cgmask;
381                        priv->cg->enable = cgmask | enabled;
382                        priv->cg->reset &= ~cgmask;
383                        priv->cg->unlock = 0;
384                }
385        }
386
387        priv->bus_maps_down[0].name = "PCI BAR0 -> AMBA";
388        priv->bus_maps_down[0].size = priv->amba_maps[0].size;
389        priv->bus_maps_down[0].from_adr = (void *)priv->amba_maps[0].local_adr;
390        priv->bus_maps_down[0].to_adr = (void *)priv->amba_maps[0].remote_adr;
391        priv->bus_maps_down[1].name = "PCI BAR1 -> AMBA";
392        priv->bus_maps_down[1].size = priv->amba_maps[1].size;
393        priv->bus_maps_down[1].from_adr = (void *)priv->amba_maps[1].local_adr;
394        priv->bus_maps_down[1].to_adr = (void *)priv->amba_maps[1].remote_adr;
395        priv->bus_maps_down[2].name = "PCI BAR2 -> AMBA";
396        priv->bus_maps_down[2].size = priv->amba_maps[2].size;
397        priv->bus_maps_down[2].from_adr = (void *)priv->amba_maps[2].local_adr;
398        priv->bus_maps_down[2].to_adr = (void *)priv->amba_maps[2].remote_adr;
399        priv->bus_maps_down[3].size = 0;
400
401        /* Find GRPCI2 controller AHB Slave interface */
402        tmp = (struct ambapp_dev *)ambapp_for_each(&priv->abus,
403                                        (OPTIONS_ALL|OPTIONS_AHB_SLVS),
404                                        VENDOR_GAISLER, GAISLER_GRPCI2,
405                                        ambapp_find_by_idx, NULL);
406        if ( !tmp ) {
407                return -6;
408        }
409        ahb = (struct ambapp_ahb_info *)tmp->devinfo;
410        priv->bus_maps_up[0].name = "AMBA GRPCI2 Window";
411        priv->bus_maps_up[0].size = ahb->mask[0]; /* AMBA->PCI Window on GR-CPCI-LEON4-N2X board */
412        priv->bus_maps_up[0].from_adr = (void *)ahb->start[0];
413        priv->bus_maps_up[0].to_adr = (void *)
414                                (priv->ahbmst2pci_map & ~(ahb->mask[0]-1));
415        priv->bus_maps_up[1].size = 0;
416
417        /* Find GRPCI2 controller APB Slave interface */
418        tmp = (struct ambapp_dev *)ambapp_for_each(&priv->abus,
419                                        (OPTIONS_ALL|OPTIONS_APB_SLVS),
420                                        VENDOR_GAISLER, GAISLER_GRPCI2,
421                                        ambapp_find_by_idx, NULL);
422        if ( !tmp ) {
423                return -7;
424        }
425        priv->grpci2 = (struct grpci2_regs *)
426                ((struct ambapp_apb_info *)tmp->devinfo)->start;
427
428        /* Workarounds depends on PCI revision of GR-CPCI-LEON4-N2X board */
429        switch (devinfo->rev) {
430        case 0:
431                /* Limit the PCI master prefetch for GRPCI2 version 0.
432                 * This fix is required only when PCI Host bridge is
433                 * GRPCI2 rev 0.
434                 */
435                priv->grpci2->ppref = 0xffff0000;
436        default:
437                break;
438        }
439
440        /* Set AHB to PCI mapping for all AMBA AHB masters */
441        for(i = 0; i < 16; i++) {
442                priv->grpci2->ahbmst_map[i] = priv->ahbmst2pci_map &
443                                                        ~(ahb->mask[0]-1);
444        }
445
446        /* Make sure dirq(0) sampling is enabled */
447        ctrl = priv->grpci2->ctrl;
448        ctrl = (ctrl & 0xFFFFFF0F) | (1 << 4);
449        priv->grpci2->ctrl = ctrl;
450
451        /* Successfully registered the LEON4-N2X board */
452        return 0;
453}
454
455static int gr_cpci_leon4_n2x_hw_init2(struct gr_cpci_leon4_n2x_priv *priv)
456{
457        /* Enable DMA by enabling PCI target as master */
458        pci_master_enable(priv->pcidev);
459
460        return DRVMGR_OK;
461}
462
463/* Called when a PCI target is found with the PCI device and vendor ID
464 * given in gr_cpci_leon4_n2x_ids[].
465 */
466int gr_cpci_leon4_n2x_init1(struct drvmgr_dev *dev)
467{
468        struct gr_cpci_leon4_n2x_priv *priv;
469        struct pci_dev_info *devinfo;
470        int status, i;
471        union drvmgr_key_value *value;
472        int resources_cnt;
473
474        priv = dev->priv;
475        if (!priv)
476                return DRVMGR_NOMEM;
477
478        memset(priv, 0, sizeof(*priv));
479        dev->priv = priv;
480        priv->dev = dev;
481
482        /* Determine number of configurations */
483        resources_cnt = get_resarray_count(gr_leon4_n2x_resources);
484
485        /* Generate Device prefix */
486
487        strcpy(priv->prefix, "/dev/leon4n2x0");
488        priv->prefix[13] += dev->minor_drv;
489        mkdir(priv->prefix, S_IRWXU | S_IRWXG | S_IRWXO);
490        priv->prefix[14] = '/';
491        priv->prefix[15] = '\0';
492
493        priv->devinfo = devinfo = (struct pci_dev_info *)dev->businfo;
494        priv->pcidev = devinfo->pcidev;
495        printf("\n\n--- GR-CPCI-LEON4-N2X[%d] ---\n", dev->minor_drv);
496        printf(" PCI BUS: 0x%x, SLOT: 0x%x, FUNCTION: 0x%x\n",
497                PCI_DEV_EXPAND(priv->pcidev));
498        printf(" PCI VENDOR: 0x%04x, DEVICE: 0x%04x\n",
499                devinfo->id.vendor, devinfo->id.device);
500        for (i = 0; i < 3; i++) {
501                printf(" PCI BAR[%d]: 0x%08lx - 0x%08lx\n",
502                        i, devinfo->resources[i].address,
503                        devinfo->resources[i].address +
504                        (devinfo->resources[i].size - 1));
505                /* all neccessary space assigned to GR-CPCI-LEON4-N2X target? */
506                if (devinfo->resources[i].size == 0)
507                        return DRVMGR_ENORES;
508        }
509        printf(" IRQ: %d\n\n\n", devinfo->irq);
510
511        /* Let user override which PCI address the AHB masters of the
512         * LEON4-N2X board access when doing DMA to HOST RAM. The AHB masters
513         * access the PCI Window of the AMBA bus, the MSB 2-bits of that address
514         * is translated according this config option before the address goes
515         * out on the PCI bus.
516         *
517         * Only the 2 MSB bits have an effect.
518         */
519        value = drvmgr_dev_key_get(priv->dev, "ahbmst2pci", DRVMGR_KT_INT);
520        if (value)
521                priv->ahbmst2pci_map = value->i;
522        else
523                priv->ahbmst2pci_map = AHBMST2PCIADR; /* default */
524
525        /* Let user override the default AMBA system frequency of the
526         * CPU-bus of the remote GR-CPCI-LEON4-N2X. Default is 200MHz.
527         */
528        value = drvmgr_dev_key_get(priv->dev, "ambaFreq", DRVMGR_KT_INT);
529        if (value)
530                priv->amba_freq_hz = value->i;
531        else
532                priv->amba_freq_hz = 200000000; /* default */
533
534        /* Let user determine clock-gating unit configuration. The default
535         * is to turn all cores on (disable gating). PCI is always turned ON.
536         */
537        value = drvmgr_dev_key_get(priv->dev, "cgEnMask", DRVMGR_KT_INT);
538        if (value)
539                priv->cg_en_mask = (value->i & CG_MASK) | 0x08;
540        else
541                priv->cg_en_mask = CG_MASK; /* default all ON */
542
543        priv->genirq = genirq_init(32);
544        if (priv->genirq == NULL)
545                return DRVMGR_FAIL;
546
547        if ((status = gr_cpci_leon4_n2x_hw_init1(priv)) != 0) {
548                genirq_destroy(priv->genirq);
549                printf(" Failed to initialize GR-CPCI-LEON4-N2X HW: %d\n", status);
550                return DRVMGR_FAIL;
551        }
552
553        /* Init amba bus */
554        priv->config.abus = &priv->abus;
555        priv->config.ops = &ambapp_leon4_n2x_ops;
556        priv->config.maps_up = &priv->bus_maps_up[0];
557        priv->config.maps_down = &priv->bus_maps_down[0];
558        if ( priv->dev->minor_drv < resources_cnt ) {
559                priv->config.resources = gr_leon4_n2x_resources[priv->dev->minor_drv];
560        } else {
561                priv->config.resources = NULL;
562        }
563
564        /* Create and register AMBA PnP bus. */
565        return ambapp_bus_register(dev, &priv->config);
566}
567
568int gr_cpci_leon4_n2x_init2(struct drvmgr_dev *dev)
569{
570        struct gr_cpci_leon4_n2x_priv *priv = dev->priv;
571
572        /* Clear any old interrupt requests */
573        drvmgr_interrupt_clear(dev, 0);
574
575        /* Enable System IRQ so that GR-CPCI-LEON4-N2X PCI target interrupt
576         * goes through.
577         *
578         * It is important to enable it in stage init2. If interrupts were
579         * enabled in init1 this might hang the system when more than one
580         * PCI board is connected, this is because PCI interrupts might
581         * be shared and PCI board 2 have not initialized and
582         * might therefore drive interrupt already when entering init1().
583         */
584        drvmgr_interrupt_register(
585                dev,
586                0,
587                "gr_cpci_leon4_n2x",
588                gr_cpci_leon4_n2x_isr,
589                (void *)priv);
590
591        return gr_cpci_leon4_n2x_hw_init2(priv);
592}
593
594int ambapp_leon4_n2x_int_register(
595        struct drvmgr_dev *dev,
596        int irq,
597        const char *info,
598        drvmgr_isr handler,
599        void *arg)
600{
601        struct gr_cpci_leon4_n2x_priv *priv = dev->parent->dev->priv;
602        rtems_interrupt_level level;
603        int status;
604
605        rtems_interrupt_disable(level);
606
607        status = genirq_register(priv->genirq, irq, handler, arg);
608        if (status == 0) {
609                /* Clear IRQ for first registered handler */
610                priv->irq->iclear = (1<<irq);
611        } else if (status == 1)
612                status = 0;
613
614        if (status != 0) {
615                rtems_interrupt_enable(level);
616                return DRVMGR_FAIL;
617        }
618
619        status = genirq_enable(priv->genirq, irq, handler, arg);
620        if ( status == 0 ) {
621                /* Enable IRQ for first enabled handler only */
622                priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
623        } else if ( status == 1 )
624                status = 0;
625
626        rtems_interrupt_enable(level);
627
628        return status;
629}
630
631int ambapp_leon4_n2x_int_unregister(
632        struct drvmgr_dev *dev,
633        int irq,
634        drvmgr_isr isr,
635        void *arg)
636{
637        struct gr_cpci_leon4_n2x_priv *priv = dev->parent->dev->priv;
638        rtems_interrupt_level level;
639        int status;
640
641        rtems_interrupt_disable(level);
642
643        status = genirq_disable(priv->genirq, irq, isr, arg);
644        if ( status == 0 ) {
645                /* Disable IRQ only when no enabled handler exists */
646                priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
647        }
648
649        status = genirq_unregister(priv->genirq, irq, isr, arg);
650        if ( status != 0 )
651                status = DRVMGR_FAIL;
652
653        rtems_interrupt_enable(level);
654
655        return status;
656}
657
658int ambapp_leon4_n2x_int_unmask(
659        struct drvmgr_dev *dev,
660        int irq)
661{
662        struct gr_cpci_leon4_n2x_priv *priv = dev->parent->dev->priv;
663        rtems_interrupt_level level;
664
665        DBG("LEON4-N2X IRQ %d: unmask\n", irq);
666
667        if ( genirq_check(priv->genirq, irq) )
668                return DRVMGR_EINVAL;
669
670        rtems_interrupt_disable(level);
671
672        /* Enable IRQ for first enabled handler only */
673        priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
674
675        rtems_interrupt_enable(level);
676
677        return DRVMGR_OK;
678}
679
680int ambapp_leon4_n2x_int_mask(
681        struct drvmgr_dev *dev,
682        int irq)
683{
684        struct gr_cpci_leon4_n2x_priv *priv = dev->parent->dev->priv;
685        rtems_interrupt_level level;
686
687        DBG("LEON4-N2X IRQ %d: mask\n", irq);
688
689        if ( genirq_check(priv->genirq, irq) )
690                return DRVMGR_EINVAL;
691
692        rtems_interrupt_disable(level);
693
694        /* Disable/mask IRQ */
695        priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
696
697        rtems_interrupt_enable(level);
698
699        return DRVMGR_OK;
700}
701
702int ambapp_leon4_n2x_int_clear(
703        struct drvmgr_dev *dev,
704        int irq)
705{
706        struct gr_cpci_leon4_n2x_priv *priv = dev->parent->dev->priv;
707
708        if ( genirq_check(priv->genirq, irq) )
709                return DRVMGR_EINVAL;
710
711        priv->irq->iclear = (1<<irq);
712
713        return DRVMGR_OK;
714}
715
716int ambapp_leon4_n2x_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params)
717{
718        struct gr_cpci_leon4_n2x_priv *priv = dev->parent->dev->priv;
719
720        /* Device name prefix pointer, skip /dev */
721        params->dev_prefix = &priv->prefix[5];
722
723        return 0;
724}
725
726void gr_cpci_leon4_n2x_print_dev(struct drvmgr_dev *dev, int options)
727{
728        struct gr_cpci_leon4_n2x_priv *priv = dev->priv;
729        struct pci_dev_info *devinfo = priv->devinfo;
730        uint32_t bar0, bar0_size;
731
732        /* Print */
733        printf("--- GR-CPCI-LEON4-N2X [bus 0x%x, dev 0x%x, fun 0x%x] ---\n",
734                PCI_DEV_EXPAND(priv->pcidev));
735
736        bar0 = devinfo->resources[0].address;
737        bar0_size = devinfo->resources[0].size;
738        printf(" PCI BAR[0]: 0x%lx - 0x%lx\n", bar0, bar0 + bar0_size - 1);
739        printf(" IRQ REGS:        0x%x\n", (unsigned int)priv->irq);
740        printf(" IRQ:             %d\n", devinfo->irq);
741        printf(" PCI REVISION:    %d\n", devinfo->rev);
742        printf(" FREQ:            %d Hz\n", priv->amba_freq_hz);
743        printf(" IMASK:           0x%08x\n", priv->irq->mask[0]);
744        printf(" IPEND:           0x%08x\n", priv->irq->ipend);
745
746        /* Print amba config */
747        if (options & GR_LEON4_N2X_OPTIONS_AMBA)
748                ambapp_print(&priv->abus, 10);
749}
750
751void gr_leon4_n2x_print(int options)
752{
753        struct pci_drv_info *drv = &gr_cpci_leon4_n2x_info;
754        struct drvmgr_dev *dev;
755
756        dev = drv->general.dev;
757        while(dev) {
758                gr_cpci_leon4_n2x_print_dev(dev, options);
759                dev = dev->next_in_drv;
760        }
761}
Note: See TracBrowser for help on using the repository browser.