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

4.115
Last change on this file since ab907e8e was ab907e8e, checked in by Daniel Hellstrom <daniel@…>, on 05/21/13 at 08:10:21

NGMP PCI: added support for NGMP prototype boards

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