source: rtems/bsps/sparc/shared/pci/gr_leon4_n2x.c @ a7267241

Last change on this file since a7267241 was a7267241, checked in by Sebastian Huber <sebastian.huber@…>, on Nov 26, 2018 at 2:44:25 PM

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

Reduce copy and paste.

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