source: rtems/bsps/sparc/shared/pci/gr_cpci_gr740.c @ 06331e4

Last change on this file since 06331e4 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: 21.1 KB
Line 
1/*  GR-CPCI-GR740 PCI Target driver.
2 *
3 *  COPYRIGHT (c) 2017.
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-CPCI-GR740 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). Based on the
13 *  GR-RASTA-IO driver.
14 *
15 *
16 *  Driver resource options:
17 *   NAME          DEFAULT VALUE
18 *   ahbmst2pci    _RAM_START            AMBA->PCI translation PCI base address
19 *   ambaFreq      250000000 (250MHz)    AMBA system frequency of GR740
20 *   cgEnMask      0x1f (all)            Clock gating enable mask
21 *   bar0          0x00000000            L2-Cache SDRAM memory
22 *   bar1          0xf0000000            L2-Cache registers
23 *
24 * TODO/UNTESTED
25 *   Interrupt testing
26 */
27
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_cpci_gr740.h>
47
48#include <grlib_impl.h>
49
50/* Determines which PCI address the AHB masters on the GR740 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_gr740_init1(struct drvmgr_dev *dev);
73int gr_cpci_gr740_init2(struct drvmgr_dev *dev);
74void gr_cpci_gr740_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 gr740_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 0x3ff
98
99/* Private data structure for driver */
100struct gr_cpci_gr740_priv {
101        /* Driver management */
102        struct drvmgr_dev       *dev;
103        char                    prefix[16];
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-GR740 */
116        unsigned int            amba_freq_hz;
117        unsigned int            cg_en_mask;             /* Enabled cores */
118        struct irqmp_regs       *irq;
119        struct gr740_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-GR740 */
125        struct ambapp_bus       abus;
126        struct ambapp_mmap      amba_maps[5];
127        struct ambapp_config    config;
128};
129
130int ambapp_gr740_int_register(
131        struct drvmgr_dev *dev,
132        int irq,
133        const char *info,
134        drvmgr_isr handler,
135        void *arg);
136int ambapp_gr740_int_unregister(
137        struct drvmgr_dev *dev,
138        int irq,
139        drvmgr_isr handler,
140        void *arg);
141int ambapp_gr740_int_unmask(
142        struct drvmgr_dev *dev,
143        int irq);
144int ambapp_gr740_int_mask(
145        struct drvmgr_dev *dev,
146        int irq);
147int ambapp_gr740_int_clear(
148        struct drvmgr_dev *dev,
149        int irq);
150int ambapp_gr740_get_params(
151        struct drvmgr_dev *dev,
152        struct drvmgr_bus_params *params);
153
154static struct ambapp_ops ambapp_gr740_ops = {
155        .int_register = ambapp_gr740_int_register,
156        .int_unregister = ambapp_gr740_int_unregister,
157        .int_unmask = ambapp_gr740_int_unmask,
158        .int_mask = ambapp_gr740_int_mask,
159        .int_clear = ambapp_gr740_int_clear,
160        .get_params = ambapp_gr740_get_params
161};
162
163struct drvmgr_drv_ops gr_cpci_gr740_ops = 
164{
165        .init = {gr_cpci_gr740_init1, gr_cpci_gr740_init2, NULL, NULL},
166        .remove = NULL,
167        .info = NULL
168};
169
170struct pci_dev_id_match gr_cpci_gr740_ids[] =
171{
172        PCIID_DEVVEND(PCIID_VENDOR_GAISLER, PCIID_DEVICE_GR_CPCI_GR740),
173        PCIID_END_TABLE /* Mark end of table */
174};
175
176struct pci_drv_info gr_cpci_gr740_info =
177{
178        {
179                DRVMGR_OBJ_DRV,                 /* Driver */
180                NULL,                           /* Next driver */
181                NULL,                           /* Device list */
182                DRIVER_PCI_GAISLER_CPCI_GR740_ID,       /* Driver ID */
183                "GR-CPCI-GR740",                /* Driver Name */
184                DRVMGR_BUS_TYPE_PCI,            /* Bus Type */
185                &gr_cpci_gr740_ops,
186                NULL,                           /* Funcs */
187                0,                              /* No devices yet */
188                sizeof(struct gr_cpci_gr740_priv),
189        },
190        &gr_cpci_gr740_ids[0]
191};
192
193/* Driver resources configuration for the AMBA bus on the GR-CPCI-GR740 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-GR740 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_cpci_gr740_resources[] __attribute__((weak)) =
204{
205        NULL
206};
207
208void gr_cpci_gr740_register_drv(void)
209{
210        DBG("Registering GR-CPCI-GR740 PCI driver\n");
211        drvmgr_drv_register(&gr_cpci_gr740_info.general);
212}
213
214void gr_cpci_gr740_isr(void *arg)
215{
216        struct gr_cpci_gr740_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-GR740: 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-GR740-IRQ: 0x%x\n", tmp);
253}
254
255static int gr_cpci_gr740_hw_init1(struct gr_cpci_gr740_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        /* Set AHB address mappings for target PCI bars
277         *  BAR0 maps to 0x00000000-0x07ffffff 128MB (SDRAM/DDR2 memory)
278         *  BAR1 maps to 0xf0000000-0xf7ffffff 128MB (L2-Cache regs/diagnostics)
279         *  BAR2 maps to 0xff800000-0xffffffff   8MB (PnP, I/O regs)
280         */
281        pci_cfg_w32(pcidev, cap_ptr+GRPCI2_BAR0_TO_AHB_MAP, 0x00000000);
282        pci_cfg_w32(pcidev, cap_ptr+GRPCI2_BAR1_TO_AHB_MAP, 0xf0000000);
283        pci_cfg_w32(pcidev, cap_ptr+GRPCI2_BAR2_TO_AHB_MAP, 0xff800000);
284
285        /* Set PCI bus to be big endian */
286        pci_cfg_r32(pcidev, cap_ptr+GRPCI2_PCI_CONFIG, &data);
287        data = data & 0xFFFFFFFE;
288        pci_cfg_w32(pcidev, cap_ptr+GRPCI2_PCI_CONFIG, data);
289
290#if 0
291        /* set parity error response */
292        pci_cfg_r32(pcidev, PCIR_COMMAND, &data);
293        pci_cfg_w32(pcidev, PCIR_COMMAND, (data|PCIM_CMD_PERRESPEN));
294#endif
295
296        /* Scan AMBA Plug&Play */
297
298        /* AMBA MAP bar0 (in gr740) ==> 0x00000000 (remote amba address) */
299        priv->amba_maps[0].size = devinfo->resources[0].size;
300        priv->amba_maps[0].local_adr = devinfo->resources[0].address;
301        priv->amba_maps[0].remote_adr = 0x00000000;
302
303        priv->amba_maps[1].size = devinfo->resources[1].size;
304        priv->amba_maps[1].local_adr = devinfo->resources[1].address;
305        priv->amba_maps[1].remote_adr = 0xf0000000;
306
307        priv->amba_maps[2].size = devinfo->resources[2].size;
308        priv->amba_maps[2].local_adr = devinfo->resources[2].address;
309        priv->amba_maps[2].remote_adr = 0xff800000;
310
311        /* Addresses not matching with map be untouched */
312        priv->amba_maps[3].size = 0xfffffff0;
313        priv->amba_maps[3].local_adr = 0;
314        priv->amba_maps[3].remote_adr = 0;
315
316        /* Mark end of table */
317        priv->amba_maps[4].size=0;
318
319        /* Start AMBA PnP scan at first AHB bus */
320        ambapp_scan(
321                &priv->abus,
322                devinfo->resources[2].address + 0x00700000,
323                NULL,
324                &priv->amba_maps[0]);
325
326        /* Initialize Frequency of AMBA bus */
327        ambapp_freq_init(&priv->abus, NULL, priv->amba_freq_hz);
328
329        /* Find IRQ controller, Clear all current IRQs */
330        tmp = (struct ambapp_dev *)ambapp_for_each(&priv->abus,
331                                (OPTIONS_ALL|OPTIONS_APB_SLVS),
332                                VENDOR_GAISLER, GAISLER_IRQMP,
333                                ambapp_find_by_idx, NULL);
334        if ( !tmp ) {
335                return -4;
336        }
337        priv->irq = (struct irqmp_regs *)DEV_TO_APB(tmp)->start;
338        /* Set up GR-CPCI-GR740 irq controller
339         * Interrupts are routed from IRQCtrl0, we leave the configuration
340         * for the other CPUs, as the board's CPUs may be running something.
341         * We assume IRQCtrl has been set up properly, or at least the reset
342         * values shuold work with this code..
343         */
344        priv->irq->mask[0] = 0;
345        priv->irq->iforce = 0;
346        priv->irq->force[0] = 0;
347        priv->irq->ilevel = 0;
348        priv->irq->ipend = 0;
349        priv->irq->iclear = 0xffffffff;
350        priv->irq->ilevel = 0;
351        /* Get extended Interrupt controller IRQ number */
352        priv->eirq = (priv->irq->mpstat >> 16) & 0xf;
353
354        /* Find first Clock-Gating unit, enable/disable the requested cores */
355        tmp = (struct ambapp_dev *)ambapp_for_each(&priv->abus,
356                                (OPTIONS_ALL|OPTIONS_APB_SLVS),
357                                VENDOR_GAISLER, GAISLER_CLKGATE,
358                                ambapp_find_by_idx, NULL);
359        if ( !tmp ) {
360                return -5;
361        }
362        priv->cg = (struct gr740_grcg_regs *)DEV_TO_APB(tmp)->start;
363        /* Do reset and enable sequence only if not already enabled */
364        if (priv->cg && ((enabled = priv->cg->enable) != priv->cg_en_mask)) {
365                /* First disable already enabled cores */
366                cgmask = ~priv->cg_en_mask & enabled;
367                if (cgmask) {
368                        priv->cg->unlock = cgmask;
369                        priv->cg->enable = enabled = ~cgmask & enabled;
370                        priv->cg->unlock = 0;
371                }
372                /* Enable disabled cores */
373                cgmask = priv->cg_en_mask & ~enabled;
374                if (cgmask) {
375                        priv->cg->unlock = cgmask;
376                        priv->cg->reset |= cgmask;
377                        priv->cg->enable = cgmask | enabled;
378                        priv->cg->reset &= ~cgmask;
379                        priv->cg->unlock = 0;
380                }
381        }
382
383        priv->bus_maps_down[0].name = "PCI BAR0 -> AMBA";
384        priv->bus_maps_down[0].size = priv->amba_maps[0].size;
385        priv->bus_maps_down[0].from_adr = (void *)priv->amba_maps[0].local_adr;
386        priv->bus_maps_down[0].to_adr = (void *)priv->amba_maps[0].remote_adr;
387        priv->bus_maps_down[1].name = "PCI BAR1 -> AMBA";
388        priv->bus_maps_down[1].size = priv->amba_maps[1].size;
389        priv->bus_maps_down[1].from_adr = (void *)priv->amba_maps[1].local_adr;
390        priv->bus_maps_down[1].to_adr = (void *)priv->amba_maps[1].remote_adr;
391        priv->bus_maps_down[2].name = "PCI BAR2 -> AMBA";
392        priv->bus_maps_down[2].size = priv->amba_maps[2].size;
393        priv->bus_maps_down[2].from_adr = (void *)priv->amba_maps[2].local_adr;
394        priv->bus_maps_down[2].to_adr = (void *)priv->amba_maps[2].remote_adr;
395        priv->bus_maps_down[3].size = 0;
396
397        /* Find GRPCI2 controller AHB Slave interface */
398        tmp = (struct ambapp_dev *)ambapp_for_each(&priv->abus,
399                                        (OPTIONS_ALL|OPTIONS_AHB_SLVS),
400                                        VENDOR_GAISLER, GAISLER_GRPCI2,
401                                        ambapp_find_by_idx, NULL);
402        if ( !tmp ) {
403                return -6;
404        }
405        ahb = (struct ambapp_ahb_info *)tmp->devinfo;
406        priv->bus_maps_up[0].name = "AMBA GRPCI2 Window";
407        priv->bus_maps_up[0].size = ahb->mask[0]; /* AMBA->PCI Window on GR-CPCI-GR740 board */
408        priv->bus_maps_up[0].from_adr = (void *)ahb->start[0];
409        priv->bus_maps_up[0].to_adr = (void *)
410                                (priv->ahbmst2pci_map & ~(ahb->mask[0]-1));
411        priv->bus_maps_up[1].size = 0;
412
413        /* Find GRPCI2 controller APB Slave interface */
414        tmp = (struct ambapp_dev *)ambapp_for_each(&priv->abus,
415                                        (OPTIONS_ALL|OPTIONS_APB_SLVS),
416                                        VENDOR_GAISLER, GAISLER_GRPCI2,
417                                        ambapp_find_by_idx, NULL);
418        if ( !tmp ) {
419                return -7;
420        }
421        priv->grpci2 = (struct grpci2_regs *)
422                ((struct ambapp_apb_info *)tmp->devinfo)->start;
423
424        /* Set AHB to PCI mapping for all AMBA AHB masters */
425        for(i = 0; i < 16; i++) {
426                priv->grpci2->ahbmst_map[i] = priv->ahbmst2pci_map &
427                                                        ~(ahb->mask[0]-1);
428        }
429
430        /* Make sure dirq(0) sampling is enabled */
431        ctrl = priv->grpci2->ctrl;
432        ctrl = (ctrl & 0xFFFFFF0F) | (1 << 4);
433        priv->grpci2->ctrl = ctrl;
434
435        /* Successfully registered the GR740 board */
436        return 0;
437}
438
439static int gr_cpci_gr740_hw_init2(struct gr_cpci_gr740_priv *priv)
440{
441        /* Enable DMA by enabling PCI target as master */
442        pci_master_enable(priv->pcidev);
443
444        return DRVMGR_OK;
445}
446
447/* Called when a PCI target is found with the PCI device and vendor ID
448 * given in gr_cpci_gr740_ids[].
449 */
450int gr_cpci_gr740_init1(struct drvmgr_dev *dev)
451{
452        struct gr_cpci_gr740_priv *priv;
453        struct pci_dev_info *devinfo;
454        int status, i;
455        union drvmgr_key_value *value;
456        int resources_cnt;
457
458        priv = dev->priv;
459        if (!priv)
460                return DRVMGR_NOMEM;
461
462        memset(priv, 0, sizeof(*priv));
463        dev->priv = priv;
464        priv->dev = dev;
465
466        /* Determine number of configurations */
467        resources_cnt = get_resarray_count(gr_cpci_gr740_resources);
468
469        /* Generate Device prefix */
470
471        strcpy(priv->prefix, "/dev/gr740_0");
472        priv->prefix[11] += dev->minor_drv;
473        mkdir(priv->prefix, S_IRWXU | S_IRWXG | S_IRWXO);
474        priv->prefix[12] = '/';
475        priv->prefix[13] = '\0';
476
477        priv->devinfo = devinfo = (struct pci_dev_info *)dev->businfo;
478        priv->pcidev = devinfo->pcidev;
479        printk("\n\n--- GR-CPCI-GR740[%d] ---\n", dev->minor_drv);
480        printk(" PCI BUS: 0x%x, SLOT: 0x%x, FUNCTION: 0x%x\n",
481                PCI_DEV_EXPAND(priv->pcidev));
482        printk(" PCI VENDOR: 0x%04x, DEVICE: 0x%04x\n",
483                devinfo->id.vendor, devinfo->id.device);
484        for (i = 0; i < 3; i++) {
485                printk(" PCI BAR[%d]: 0x%08lx - 0x%08lx\n",
486                        i, devinfo->resources[i].address,
487                        devinfo->resources[i].address +
488                        (devinfo->resources[i].size - 1));
489                /* all neccessary space assigned to GR-CPCI-GR740 target? */
490                if (devinfo->resources[i].size == 0)
491                        return DRVMGR_ENORES;
492        }
493        printk(" IRQ: %d\n\n\n", devinfo->irq);
494
495        /* Initialize spin-lock for this PCI perihperal device. This is to
496         * protect the Interrupt Controller Registers. The genirq layer is
497         * protecting its own internals and ISR dispatching.
498         */
499        SPIN_INIT(&priv->devlock, priv->prefix);
500
501        /* Let user override which PCI address the AHB masters of the
502         * GR740 board access when doing DMA to HOST RAM. The AHB masters
503         * access the PCI Window of the AMBA bus, the MSB 2-bits of that address
504         * is translated according this config option before the address goes
505         * out on the PCI bus.
506         *
507         * Only the 2 MSB bits have an effect.
508         */
509        value = drvmgr_dev_key_get(priv->dev, "ahbmst2pci", DRVMGR_KT_INT);
510        if (value)
511                priv->ahbmst2pci_map = value->i;
512        else
513                priv->ahbmst2pci_map = AHBMST2PCIADR; /* default */
514
515        /* Let user override the default AMBA system frequency of the
516         * CPU-bus of the remote GR-CPCI-GR740. Default is 250MHz.
517         */
518        value = drvmgr_dev_key_get(priv->dev, "ambaFreq", DRVMGR_KT_INT);
519        if (value)
520                priv->amba_freq_hz = value->i;
521        else
522                priv->amba_freq_hz = 250000000; /* default */
523
524        /* Let user determine clock-gating unit configuration. The default
525         * is to turn all cores on (disable gating). PCI is always turned ON.
526         */
527        value = drvmgr_dev_key_get(priv->dev, "cgEnMask", DRVMGR_KT_INT);
528        if (value)
529                priv->cg_en_mask = (value->i & CG_MASK) | 0x08;
530        else
531                priv->cg_en_mask = CG_MASK; /* default all ON */
532
533        priv->genirq = genirq_init(32);
534        if (priv->genirq == NULL)
535                return DRVMGR_FAIL;
536
537        if ((status = gr_cpci_gr740_hw_init1(priv)) != 0) {
538                genirq_destroy(priv->genirq);
539                printk(" Failed to initialize GR-CPCI-GR740 HW: %d\n", status);
540                return DRVMGR_FAIL;
541        }
542
543        /* Init amba bus */
544        priv->config.abus = &priv->abus;
545        priv->config.ops = &ambapp_gr740_ops;
546        priv->config.maps_up = &priv->bus_maps_up[0];
547        priv->config.maps_down = &priv->bus_maps_down[0];
548        if ( priv->dev->minor_drv < resources_cnt ) {
549                priv->config.resources = gr_cpci_gr740_resources[priv->dev->minor_drv];
550        } else {
551                priv->config.resources = NULL;
552        }
553
554        /* Create and register AMBA PnP bus. */
555        return ambapp_bus_register(dev, &priv->config);
556}
557
558int gr_cpci_gr740_init2(struct drvmgr_dev *dev)
559{
560        struct gr_cpci_gr740_priv *priv = dev->priv;
561
562        /* Clear any old interrupt requests */
563        drvmgr_interrupt_clear(dev, 0);
564
565        /* Enable System IRQ so that GR-CPCI-GR740 PCI target interrupt
566         * goes through.
567         *
568         * It is important to enable it in stage init2. If interrupts were
569         * enabled in init1 this might hang the system when more than one
570         * PCI board is connected, this is because PCI interrupts might
571         * be shared and PCI board 2 have not initialized and
572         * might therefore drive interrupt already when entering init1().
573         */
574        drvmgr_interrupt_register(
575                dev,
576                0,
577                "gr_cpci_gr740",
578                gr_cpci_gr740_isr,
579                (void *)priv);
580
581        return gr_cpci_gr740_hw_init2(priv);
582}
583
584int ambapp_gr740_int_register(
585        struct drvmgr_dev *dev,
586        int irq,
587        const char *info,
588        drvmgr_isr handler,
589        void *arg)
590{
591        struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
592        SPIN_IRQFLAGS(irqflags);
593        int status;
594        void *h;
595
596        h = genirq_alloc_handler(handler, arg);
597        if ( h == NULL )
598                return DRVMGR_FAIL;
599
600        SPIN_LOCK_IRQ(&priv->devlock, irqflags);
601
602        status = genirq_register(priv->genirq, irq, h);
603        if (status == 0) {
604                /* Clear IRQ for first registered handler */
605                priv->irq->iclear = (1<<irq);
606        } else if (status == 1)
607                status = 0;
608
609        if (status != 0) {
610                SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
611                genirq_free_handler(h);
612                return DRVMGR_FAIL;
613        }
614
615        status = genirq_enable(priv->genirq, irq, handler, arg);
616        if ( status == 0 ) {
617                /* Enable IRQ for first enabled handler only */
618                priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
619        } else if ( status == 1 )
620                status = 0;
621
622        SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
623
624        return status;
625}
626
627int ambapp_gr740_int_unregister(
628        struct drvmgr_dev *dev,
629        int irq,
630        drvmgr_isr isr,
631        void *arg)
632{
633        struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
634        SPIN_IRQFLAGS(irqflags);
635        int status;
636        void *handler;
637
638        SPIN_LOCK_IRQ(&priv->devlock, irqflags);
639
640        status = genirq_disable(priv->genirq, irq, isr, arg);
641        if ( status == 0 ) {
642                /* Disable IRQ only when no enabled handler exists */
643                priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
644        }
645
646        handler = genirq_unregister(priv->genirq, irq, isr, arg);
647        if ( handler == NULL )
648                status = DRVMGR_FAIL;
649        else
650                status = DRVMGR_OK;
651
652        SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
653
654        if (handler)
655                genirq_free_handler(handler);
656
657        return status;
658}
659
660int ambapp_gr740_int_unmask(
661        struct drvmgr_dev *dev,
662        int irq)
663{
664        struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
665        SPIN_IRQFLAGS(irqflags);
666
667        DBG("GR740 IRQ %d: unmask\n", irq);
668
669        if ( genirq_check(priv->genirq, irq) )
670                return DRVMGR_EINVAL;
671
672        SPIN_LOCK_IRQ(&priv->devlock, irqflags);
673
674        /* Enable IRQ for first enabled handler only */
675        priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
676
677        SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
678
679        return DRVMGR_OK;
680}
681
682int ambapp_gr740_int_mask(
683        struct drvmgr_dev *dev,
684        int irq)
685{
686        struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
687        SPIN_IRQFLAGS(irqflags);
688
689        DBG("GR740 IRQ %d: mask\n", irq);
690
691        if ( genirq_check(priv->genirq, irq) )
692                return DRVMGR_EINVAL;
693
694        SPIN_LOCK_IRQ(&priv->devlock, irqflags);
695
696        /* Disable/mask IRQ */
697        priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
698
699        SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
700
701        return DRVMGR_OK;
702}
703
704int ambapp_gr740_int_clear(
705        struct drvmgr_dev *dev,
706        int irq)
707{
708        struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
709
710        if ( genirq_check(priv->genirq, irq) )
711                return DRVMGR_EINVAL;
712
713        priv->irq->iclear = (1<<irq);
714
715        return DRVMGR_OK;
716}
717
718int ambapp_gr740_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params)
719{
720        struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
721
722        /* Device name prefix pointer, skip /dev */
723        params->dev_prefix = &priv->prefix[5];
724
725        return 0;
726}
727
728void gr_cpci_gr740_print_dev(struct drvmgr_dev *dev, int options)
729{
730        struct gr_cpci_gr740_priv *priv = dev->priv;
731        struct pci_dev_info *devinfo = priv->devinfo;
732        uint32_t bar0, bar0_size;
733
734        /* Print */
735        printf("--- GR-CPCI-GR740 [bus 0x%x, dev 0x%x, fun 0x%x] ---\n",
736                PCI_DEV_EXPAND(priv->pcidev));
737
738        bar0 = devinfo->resources[0].address;
739        bar0_size = devinfo->resources[0].size;
740        printf(" PCI BAR[0]: 0x%lx - 0x%lx\n", bar0, bar0 + bar0_size - 1);
741        printf(" IRQ REGS:        0x%x\n", (unsigned int)priv->irq);
742        printf(" IRQ:             %d\n", devinfo->irq);
743        printf(" PCI REVISION:    %d\n", devinfo->rev);
744        printf(" FREQ:            %d Hz\n", priv->amba_freq_hz);
745        printf(" IMASK:           0x%08x\n", priv->irq->mask[0]);
746        printf(" IPEND:           0x%08x\n", priv->irq->ipend);
747
748        /* Print amba config */
749        if (options & GR_CPCI_GR740_OPTIONS_AMBA)
750                ambapp_print(&priv->abus, 10);
751}
752
753void gr_cpci_gr740_print(int options)
754{
755        struct pci_drv_info *drv = &gr_cpci_gr740_info;
756        struct drvmgr_dev *dev;
757
758        dev = drv->general.dev;
759        while(dev) {
760                gr_cpci_gr740_print_dev(dev, options);
761                dev = dev->next_in_drv;
762        }
763}
Note: See TracBrowser for help on using the repository browser.