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

Last change on this file since c05d7a9d was c05d7a9d, checked in by Sebastian Huber <sebastian.huber@…>, on Dec 21, 2018 at 8:43:27 PM

bsps/sparc: Fix warnings

  • Property mode set to 100644
File size: 21.2 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 <inttypes.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <sys/types.h>
33#include <sys/stat.h>
34
35#include <bsp.h>
36#include <rtems/bspIo.h>
37#include <pci.h>
38
39#include <ambapp.h>
40#include <grlib.h>
41#include <drvmgr/drvmgr.h>
42#include <drvmgr/ambapp_bus.h>
43#include <drvmgr/pci_bus.h>
44#include <drvmgr/bspcommon.h>
45#include <bsp/genirq.h>
46
47#include <bsp/gr_cpci_gr740.h>
48
49#include <grlib_impl.h>
50
51/* Determines which PCI address the AHB masters on the GR740 board will
52 * access when accessing the AHB to PCI window, it should be set so that the
53 * masters can access the HOST RAM.
54 * Default is base of HOST RAM, HOST RAM is mapped 1:1 to PCI memory space.
55 */
56extern unsigned int _RAM_START;
57#define AHBMST2PCIADR (((unsigned int)&_RAM_START) & 0xc0000000)
58
59#define GRPCI2_BAR0_TO_AHB_MAP 0x04
60#define GRPCI2_BAR1_TO_AHB_MAP 0x08
61#define GRPCI2_BAR2_TO_AHB_MAP 0x0c
62#define GRPCI2_PCI_CONFIG      0x20
63#define CAP9_AHBPREF_OFS 0x3c
64
65/* #define DEBUG 1 */
66
67#ifdef DEBUG
68#define DBG(x...) printk(x)
69#else
70#define DBG(x...)
71#endif
72
73int gr_cpci_gr740_init1(struct drvmgr_dev *dev);
74int gr_cpci_gr740_init2(struct drvmgr_dev *dev);
75void gr_cpci_gr740_isr(void *arg);
76
77struct grpci2_regs {
78        volatile unsigned int ctrl;             /* 0x00 */
79        volatile unsigned int sts_cap;          /* 0x04 */
80        volatile unsigned int ppref;            /* 0x08 */
81        volatile unsigned int io_map;           /* 0x0C */
82        volatile unsigned int dma_ctrl;         /* 0x10 */
83        volatile unsigned int dma_bdbase;       /* 0x14 */
84        volatile unsigned int dma_chact;        /* 0x18 */
85        int res1;                               /* 0x1C */
86        volatile unsigned int bars[6];          /* 0x20 */
87        int res2[2];                            /* 0x38 */
88        volatile unsigned int ahbmst_map[16];   /* 0x40 */
89};
90
91/* Clock gating unit register layout */
92struct gr740_grcg_regs {
93        volatile unsigned int unlock;
94        volatile unsigned int enable;
95        volatile unsigned int reset;
96        volatile unsigned int cpu_fpu;
97};
98#define CG_MASK 0x3ff
99
100/* Private data structure for driver */
101struct gr_cpci_gr740_priv {
102        /* Driver management */
103        struct drvmgr_dev       *dev;
104        char                    prefix[16];
105        SPIN_DECLARE(devlock);
106
107        /* PCI */
108        pci_dev_t               pcidev;
109        struct pci_dev_info     *devinfo;
110        uint32_t                ahbmst2pci_map;
111
112        /* IRQ */
113        int                     eirq;
114        genirq_t                genirq;
115
116        /* GR-CPCI-GR740 */
117        unsigned int            amba_freq_hz;
118        unsigned int            cg_en_mask;             /* Enabled cores */
119        struct irqmp_regs       *irq;
120        struct gr740_grcg_regs  *cg;                    /* Clock-gating unit */
121        struct grpci2_regs      *grpci2;
122        struct drvmgr_map_entry bus_maps_up[2];
123        struct drvmgr_map_entry bus_maps_down[4];
124
125        /* AMBA Plug&Play information on GR-CPCI-GR740 */
126        struct ambapp_bus       abus;
127        struct ambapp_mmap      amba_maps[5];
128        struct ambapp_config    config;
129};
130
131int ambapp_gr740_int_register(
132        struct drvmgr_dev *dev,
133        int irq,
134        const char *info,
135        drvmgr_isr handler,
136        void *arg);
137int ambapp_gr740_int_unregister(
138        struct drvmgr_dev *dev,
139        int irq,
140        drvmgr_isr handler,
141        void *arg);
142int ambapp_gr740_int_unmask(
143        struct drvmgr_dev *dev,
144        int irq);
145int ambapp_gr740_int_mask(
146        struct drvmgr_dev *dev,
147        int irq);
148int ambapp_gr740_int_clear(
149        struct drvmgr_dev *dev,
150        int irq);
151int ambapp_gr740_get_params(
152        struct drvmgr_dev *dev,
153        struct drvmgr_bus_params *params);
154
155static struct ambapp_ops ambapp_gr740_ops = {
156        .int_register = ambapp_gr740_int_register,
157        .int_unregister = ambapp_gr740_int_unregister,
158        .int_unmask = ambapp_gr740_int_unmask,
159        .int_mask = ambapp_gr740_int_mask,
160        .int_clear = ambapp_gr740_int_clear,
161        .get_params = ambapp_gr740_get_params
162};
163
164struct drvmgr_drv_ops gr_cpci_gr740_ops = 
165{
166        .init = {gr_cpci_gr740_init1, gr_cpci_gr740_init2, NULL, NULL},
167        .remove = NULL,
168        .info = NULL
169};
170
171struct pci_dev_id_match gr_cpci_gr740_ids[] =
172{
173        PCIID_DEVVEND(PCIID_VENDOR_GAISLER, PCIID_DEVICE_GR_CPCI_GR740),
174        PCIID_END_TABLE /* Mark end of table */
175};
176
177struct pci_drv_info gr_cpci_gr740_info =
178{
179        {
180                DRVMGR_OBJ_DRV,                 /* Driver */
181                NULL,                           /* Next driver */
182                NULL,                           /* Device list */
183                DRIVER_PCI_GAISLER_CPCI_GR740_ID,       /* Driver ID */
184                "GR-CPCI-GR740",                /* Driver Name */
185                DRVMGR_BUS_TYPE_PCI,            /* Bus Type */
186                &gr_cpci_gr740_ops,
187                NULL,                           /* Funcs */
188                0,                              /* No devices yet */
189                sizeof(struct gr_cpci_gr740_priv),
190        },
191        &gr_cpci_gr740_ids[0]
192};
193
194/* Driver resources configuration for the AMBA bus on the GR-CPCI-GR740 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-GR740 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_cpci_gr740_resources[] __attribute__((weak)) =
205{
206        NULL
207};
208
209void gr_cpci_gr740_register_drv(void)
210{
211        DBG("Registering GR-CPCI-GR740 PCI driver\n");
212        drvmgr_drv_register(&gr_cpci_gr740_info.general);
213}
214
215void gr_cpci_gr740_isr(void *arg)
216{
217        struct gr_cpci_gr740_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-GR740: 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-GR740-IRQ: 0x%x\n", tmp);
254}
255
256static int gr_cpci_gr740_hw_init1(struct gr_cpci_gr740_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        /* 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, PCIR_COMMAND, &data);
294        pci_cfg_w32(pcidev, PCIR_COMMAND, (data|PCIM_CMD_PERRESPEN));
295#endif
296
297        /* Scan AMBA Plug&Play */
298
299        /* AMBA MAP bar0 (in gr740) ==> 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-GR740 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        tmp = (struct ambapp_dev *)ambapp_for_each(&priv->abus,
357                                (OPTIONS_ALL|OPTIONS_APB_SLVS),
358                                VENDOR_GAISLER, GAISLER_CLKGATE,
359                                ambapp_find_by_idx, NULL);
360        if ( !tmp ) {
361                return -5;
362        }
363        priv->cg = (struct gr740_grcg_regs *)DEV_TO_APB(tmp)->start;
364        /* Do reset and enable sequence only if not already enabled */
365        if (priv->cg && ((enabled = priv->cg->enable) != priv->cg_en_mask)) {
366                /* First disable already enabled cores */
367                cgmask = ~priv->cg_en_mask & enabled;
368                if (cgmask) {
369                        priv->cg->unlock = cgmask;
370                        priv->cg->enable = enabled = ~cgmask & enabled;
371                        priv->cg->unlock = 0;
372                }
373                /* Enable disabled cores */
374                cgmask = priv->cg_en_mask & ~enabled;
375                if (cgmask) {
376                        priv->cg->unlock = cgmask;
377                        priv->cg->reset |= cgmask;
378                        priv->cg->enable = cgmask | enabled;
379                        priv->cg->reset &= ~cgmask;
380                        priv->cg->unlock = 0;
381                }
382        }
383
384        priv->bus_maps_down[0].name = "PCI BAR0 -> AMBA";
385        priv->bus_maps_down[0].size = priv->amba_maps[0].size;
386        priv->bus_maps_down[0].from_adr = (void *)priv->amba_maps[0].local_adr;
387        priv->bus_maps_down[0].to_adr = (void *)priv->amba_maps[0].remote_adr;
388        priv->bus_maps_down[1].name = "PCI BAR1 -> AMBA";
389        priv->bus_maps_down[1].size = priv->amba_maps[1].size;
390        priv->bus_maps_down[1].from_adr = (void *)priv->amba_maps[1].local_adr;
391        priv->bus_maps_down[1].to_adr = (void *)priv->amba_maps[1].remote_adr;
392        priv->bus_maps_down[2].name = "PCI BAR2 -> AMBA";
393        priv->bus_maps_down[2].size = priv->amba_maps[2].size;
394        priv->bus_maps_down[2].from_adr = (void *)priv->amba_maps[2].local_adr;
395        priv->bus_maps_down[2].to_adr = (void *)priv->amba_maps[2].remote_adr;
396        priv->bus_maps_down[3].size = 0;
397
398        /* Find GRPCI2 controller AHB Slave interface */
399        tmp = (struct ambapp_dev *)ambapp_for_each(&priv->abus,
400                                        (OPTIONS_ALL|OPTIONS_AHB_SLVS),
401                                        VENDOR_GAISLER, GAISLER_GRPCI2,
402                                        ambapp_find_by_idx, NULL);
403        if ( !tmp ) {
404                return -6;
405        }
406        ahb = (struct ambapp_ahb_info *)tmp->devinfo;
407        priv->bus_maps_up[0].name = "AMBA GRPCI2 Window";
408        priv->bus_maps_up[0].size = ahb->mask[0]; /* AMBA->PCI Window on GR-CPCI-GR740 board */
409        priv->bus_maps_up[0].from_adr = (void *)ahb->start[0];
410        priv->bus_maps_up[0].to_adr = (void *)
411                                (priv->ahbmst2pci_map & ~(ahb->mask[0]-1));
412        priv->bus_maps_up[1].size = 0;
413
414        /* Find GRPCI2 controller APB Slave interface */
415        tmp = (struct ambapp_dev *)ambapp_for_each(&priv->abus,
416                                        (OPTIONS_ALL|OPTIONS_APB_SLVS),
417                                        VENDOR_GAISLER, GAISLER_GRPCI2,
418                                        ambapp_find_by_idx, NULL);
419        if ( !tmp ) {
420                return -7;
421        }
422        priv->grpci2 = (struct grpci2_regs *)
423                ((struct ambapp_apb_info *)tmp->devinfo)->start;
424
425        /* Set AHB to PCI mapping for all AMBA AHB masters */
426        for(i = 0; i < 16; i++) {
427                priv->grpci2->ahbmst_map[i] = priv->ahbmst2pci_map &
428                                                        ~(ahb->mask[0]-1);
429        }
430
431        /* Make sure dirq(0) sampling is enabled */
432        ctrl = priv->grpci2->ctrl;
433        ctrl = (ctrl & 0xFFFFFF0F) | (1 << 4);
434        priv->grpci2->ctrl = ctrl;
435
436        /* Successfully registered the GR740 board */
437        return 0;
438}
439
440static int gr_cpci_gr740_hw_init2(struct gr_cpci_gr740_priv *priv)
441{
442        /* Enable DMA by enabling PCI target as master */
443        pci_master_enable(priv->pcidev);
444
445        return DRVMGR_OK;
446}
447
448/* Called when a PCI target is found with the PCI device and vendor ID
449 * given in gr_cpci_gr740_ids[].
450 */
451int gr_cpci_gr740_init1(struct drvmgr_dev *dev)
452{
453        struct gr_cpci_gr740_priv *priv;
454        struct pci_dev_info *devinfo;
455        int status, i;
456        union drvmgr_key_value *value;
457        int resources_cnt;
458
459        priv = dev->priv;
460        if (!priv)
461                return DRVMGR_NOMEM;
462
463        memset(priv, 0, sizeof(*priv));
464        dev->priv = priv;
465        priv->dev = dev;
466
467        /* Determine number of configurations */
468        resources_cnt = get_resarray_count(gr_cpci_gr740_resources);
469
470        /* Generate Device prefix */
471
472        strcpy(priv->prefix, "/dev/gr740_0");
473        priv->prefix[11] += dev->minor_drv;
474        mkdir(priv->prefix, S_IRWXU | S_IRWXG | S_IRWXO);
475        priv->prefix[12] = '/';
476        priv->prefix[13] = '\0';
477
478        priv->devinfo = devinfo = (struct pci_dev_info *)dev->businfo;
479        priv->pcidev = devinfo->pcidev;
480        printk("\n\n--- GR-CPCI-GR740[%d] ---\n", dev->minor_drv);
481        printk(" PCI BUS: 0x%x, SLOT: 0x%x, FUNCTION: 0x%x\n",
482                PCI_DEV_EXPAND(priv->pcidev));
483        printk(" PCI VENDOR: 0x%04x, DEVICE: 0x%04x\n",
484                devinfo->id.vendor, devinfo->id.device);
485        for (i = 0; i < 3; i++) {
486                printk(" PCI BAR[%d]: 0x%08" PRIx32 " - 0x%08" PRIx32 "\n",
487                        i, devinfo->resources[i].address,
488                        devinfo->resources[i].address +
489                        (devinfo->resources[i].size - 1));
490                /* all neccessary space assigned to GR-CPCI-GR740 target? */
491                if (devinfo->resources[i].size == 0)
492                        return DRVMGR_ENORES;
493        }
494        printk(" IRQ: %d\n\n\n", devinfo->irq);
495
496        /* Initialize spin-lock for this PCI perihperal device. This is to
497         * protect the Interrupt Controller Registers. The genirq layer is
498         * protecting its own internals and ISR dispatching.
499         */
500        SPIN_INIT(&priv->devlock, priv->prefix);
501
502        /* Let user override which PCI address the AHB masters of the
503         * GR740 board access when doing DMA to HOST RAM. The AHB masters
504         * access the PCI Window of the AMBA bus, the MSB 2-bits of that address
505         * is translated according this config option before the address goes
506         * out on the PCI bus.
507         *
508         * Only the 2 MSB bits have an effect.
509         */
510        value = drvmgr_dev_key_get(priv->dev, "ahbmst2pci", DRVMGR_KT_INT);
511        if (value)
512                priv->ahbmst2pci_map = value->i;
513        else
514                priv->ahbmst2pci_map = AHBMST2PCIADR; /* default */
515
516        /* Let user override the default AMBA system frequency of the
517         * CPU-bus of the remote GR-CPCI-GR740. Default is 250MHz.
518         */
519        value = drvmgr_dev_key_get(priv->dev, "ambaFreq", DRVMGR_KT_INT);
520        if (value)
521                priv->amba_freq_hz = value->i;
522        else
523                priv->amba_freq_hz = 250000000; /* default */
524
525        /* Let user determine clock-gating unit configuration. The default
526         * is to turn all cores on (disable gating). PCI is always turned ON.
527         */
528        value = drvmgr_dev_key_get(priv->dev, "cgEnMask", DRVMGR_KT_INT);
529        if (value)
530                priv->cg_en_mask = (value->i & CG_MASK) | 0x08;
531        else
532                priv->cg_en_mask = CG_MASK; /* default all ON */
533
534        priv->genirq = genirq_init(32);
535        if (priv->genirq == NULL)
536                return DRVMGR_FAIL;
537
538        if ((status = gr_cpci_gr740_hw_init1(priv)) != 0) {
539                genirq_destroy(priv->genirq);
540                printk(" Failed to initialize GR-CPCI-GR740 HW: %d\n", status);
541                return DRVMGR_FAIL;
542        }
543
544        /* Init amba bus */
545        priv->config.abus = &priv->abus;
546        priv->config.ops = &ambapp_gr740_ops;
547        priv->config.maps_up = &priv->bus_maps_up[0];
548        priv->config.maps_down = &priv->bus_maps_down[0];
549        if ( priv->dev->minor_drv < resources_cnt ) {
550                priv->config.resources = gr_cpci_gr740_resources[priv->dev->minor_drv];
551        } else {
552                priv->config.resources = NULL;
553        }
554
555        /* Create and register AMBA PnP bus. */
556        return ambapp_bus_register(dev, &priv->config);
557}
558
559int gr_cpci_gr740_init2(struct drvmgr_dev *dev)
560{
561        struct gr_cpci_gr740_priv *priv = dev->priv;
562
563        /* Clear any old interrupt requests */
564        drvmgr_interrupt_clear(dev, 0);
565
566        /* Enable System IRQ so that GR-CPCI-GR740 PCI target interrupt
567         * goes through.
568         *
569         * It is important to enable it in stage init2. If interrupts were
570         * enabled in init1 this might hang the system when more than one
571         * PCI board is connected, this is because PCI interrupts might
572         * be shared and PCI board 2 have not initialized and
573         * might therefore drive interrupt already when entering init1().
574         */
575        drvmgr_interrupt_register(
576                dev,
577                0,
578                "gr_cpci_gr740",
579                gr_cpci_gr740_isr,
580                (void *)priv);
581
582        return gr_cpci_gr740_hw_init2(priv);
583}
584
585int ambapp_gr740_int_register(
586        struct drvmgr_dev *dev,
587        int irq,
588        const char *info,
589        drvmgr_isr handler,
590        void *arg)
591{
592        struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
593        SPIN_IRQFLAGS(irqflags);
594        int status;
595        void *h;
596
597        h = genirq_alloc_handler(handler, arg);
598        if ( h == NULL )
599                return DRVMGR_FAIL;
600
601        SPIN_LOCK_IRQ(&priv->devlock, irqflags);
602
603        status = genirq_register(priv->genirq, irq, h);
604        if (status == 0) {
605                /* Clear IRQ for first registered handler */
606                priv->irq->iclear = (1<<irq);
607        } else if (status == 1)
608                status = 0;
609
610        if (status != 0) {
611                SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
612                genirq_free_handler(h);
613                return DRVMGR_FAIL;
614        }
615
616        status = genirq_enable(priv->genirq, irq, handler, arg);
617        if ( status == 0 ) {
618                /* Enable IRQ for first enabled handler only */
619                priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
620        } else if ( status == 1 )
621                status = 0;
622
623        SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
624
625        return status;
626}
627
628int ambapp_gr740_int_unregister(
629        struct drvmgr_dev *dev,
630        int irq,
631        drvmgr_isr isr,
632        void *arg)
633{
634        struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
635        SPIN_IRQFLAGS(irqflags);
636        int status;
637        void *handler;
638
639        SPIN_LOCK_IRQ(&priv->devlock, irqflags);
640
641        status = genirq_disable(priv->genirq, irq, isr, arg);
642        if ( status == 0 ) {
643                /* Disable IRQ only when no enabled handler exists */
644                priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
645        }
646
647        handler = genirq_unregister(priv->genirq, irq, isr, arg);
648        if ( handler == NULL )
649                status = DRVMGR_FAIL;
650        else
651                status = DRVMGR_OK;
652
653        SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
654
655        if (handler)
656                genirq_free_handler(handler);
657
658        return status;
659}
660
661int ambapp_gr740_int_unmask(
662        struct drvmgr_dev *dev,
663        int irq)
664{
665        struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
666        SPIN_IRQFLAGS(irqflags);
667
668        DBG("GR740 IRQ %d: unmask\n", irq);
669
670        if ( genirq_check(priv->genirq, irq) )
671                return DRVMGR_EINVAL;
672
673        SPIN_LOCK_IRQ(&priv->devlock, irqflags);
674
675        /* Enable IRQ for first enabled handler only */
676        priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
677
678        SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
679
680        return DRVMGR_OK;
681}
682
683int ambapp_gr740_int_mask(
684        struct drvmgr_dev *dev,
685        int irq)
686{
687        struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
688        SPIN_IRQFLAGS(irqflags);
689
690        DBG("GR740 IRQ %d: mask\n", irq);
691
692        if ( genirq_check(priv->genirq, irq) )
693                return DRVMGR_EINVAL;
694
695        SPIN_LOCK_IRQ(&priv->devlock, irqflags);
696
697        /* Disable/mask IRQ */
698        priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
699
700        SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
701
702        return DRVMGR_OK;
703}
704
705int ambapp_gr740_int_clear(
706        struct drvmgr_dev *dev,
707        int irq)
708{
709        struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
710
711        if ( genirq_check(priv->genirq, irq) )
712                return DRVMGR_EINVAL;
713
714        priv->irq->iclear = (1<<irq);
715
716        return DRVMGR_OK;
717}
718
719int ambapp_gr740_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params)
720{
721        struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
722
723        /* Device name prefix pointer, skip /dev */
724        params->dev_prefix = &priv->prefix[5];
725
726        return 0;
727}
728
729void gr_cpci_gr740_print_dev(struct drvmgr_dev *dev, int options)
730{
731        struct gr_cpci_gr740_priv *priv = dev->priv;
732        struct pci_dev_info *devinfo = priv->devinfo;
733        uint32_t bar0, bar0_size;
734
735        /* Print */
736        printf("--- GR-CPCI-GR740 [bus 0x%x, dev 0x%x, fun 0x%x] ---\n",
737                PCI_DEV_EXPAND(priv->pcidev));
738
739        bar0 = devinfo->resources[0].address;
740        bar0_size = devinfo->resources[0].size;
741        printf(" PCI BAR[0]: 0x%" PRIx32 " - 0x%" PRIx32 "\n",
742                bar0, bar0 + bar0_size - 1);
743        printf(" IRQ REGS:        0x%" PRIxPTR "\n", (uintptr_t)priv->irq);
744        printf(" IRQ:             %d\n", devinfo->irq);
745        printf(" PCI REVISION:    %d\n", devinfo->rev);
746        printf(" FREQ:            %d Hz\n", priv->amba_freq_hz);
747        printf(" IMASK:           0x%08x\n", priv->irq->mask[0]);
748        printf(" IPEND:           0x%08x\n", priv->irq->ipend);
749
750        /* Print amba config */
751        if (options & GR_CPCI_GR740_OPTIONS_AMBA)
752                ambapp_print(&priv->abus, 10);
753}
754
755void gr_cpci_gr740_print(int options)
756{
757        struct pci_drv_info *drv = &gr_cpci_gr740_info;
758        struct drvmgr_dev *dev;
759
760        dev = drv->general.dev;
761        while(dev) {
762                gr_cpci_gr740_print_dev(dev, options);
763                dev = dev->next_in_drv;
764        }
765}
Note: See TracBrowser for help on using the repository browser.