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

5
Last change on this file since 8f5abea was c05d7a9d, checked in by Sebastian Huber <sebastian.huber@…>, on 12/21/18 at 20:43:27

bsps/sparc: Fix warnings

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