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

5
Last change on this file since d60d303c was d60d303c, checked in by Sebastian Huber <sebastian.huber@…>, on 04/20/18 at 11:33:24

bsps/sparc: Move shared files to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

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