Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:08

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*  GR-CPCI-GR740 PCI Target driver.
0004  * 
0005  *  COPYRIGHT (c) 2017.
0006  *  Cobham Gaisler AB.
0007  *
0008  * Redistribution and use in source and binary forms, with or without
0009  * modification, are permitted provided that the following conditions
0010  * are met:
0011  * 1. Redistributions of source code must retain the above copyright
0012  *    notice, this list of conditions and the following disclaimer.
0013  * 2. Redistributions in binary form must reproduce the above copyright
0014  *    notice, this list of conditions and the following disclaimer in the
0015  *    documentation and/or other materials provided with the distribution.
0016  *
0017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0027  * POSSIBILITY OF SUCH DAMAGE.
0028  *
0029  *  Configures the GR-CPCI-GR740 interface PCI board in peripheral
0030  *  mode. This driver provides a AMBA PnP bus by using the general part
0031  *  of the AMBA PnP bus driver (ambapp_bus.c). Based on the
0032  *  GR-RASTA-IO driver.
0033  *
0034  *
0035  *  Driver resource options:
0036  *   NAME          DEFAULT VALUE
0037  *   ahbmst2pci    _RAM_START            AMBA->PCI translation PCI base address
0038  *   ambaFreq      250000000 (250MHz)    AMBA system frequency of GR740
0039  *   cgEnMask      0x1f (all)            Clock gating enable mask
0040  *   bar0          0x00000000            L2-Cache SDRAM memory
0041  *   bar1          0xf0000000            L2-Cache registers
0042  *
0043  * TODO/UNTESTED
0044  *   Interrupt testing
0045  */
0046 
0047 #include <inttypes.h>
0048 #include <stdio.h>
0049 #include <stdlib.h>
0050 #include <string.h>
0051 #include <sys/types.h>
0052 #include <sys/stat.h>
0053 
0054 #include <bsp.h>
0055 #include <rtems/bspIo.h>
0056 #include <pci.h>
0057 
0058 #include <grlib/ambapp.h>
0059 #include <grlib/grlib.h>
0060 #include <drvmgr/drvmgr.h>
0061 #include <grlib/ambapp_bus.h>
0062 #include <drvmgr/pci_bus.h>
0063 #include <grlib/bspcommon.h>
0064 #include <grlib/genirq.h>
0065 
0066 #include <grlib/gr_cpci_gr740.h>
0067 
0068 #include <grlib/grlib_impl.h>
0069 
0070 /* Determines which PCI address the AHB masters on the GR740 board will
0071  * access when accessing the AHB to PCI window, it should be set so that the
0072  * masters can access the HOST RAM.
0073  * Default is base of HOST RAM, HOST RAM is mapped 1:1 to PCI memory space.
0074  */
0075 extern unsigned int _RAM_START;
0076 #define AHBMST2PCIADR (((unsigned int)&_RAM_START) & 0xc0000000)
0077 
0078 #define GRPCI2_BAR0_TO_AHB_MAP 0x04
0079 #define GRPCI2_BAR1_TO_AHB_MAP 0x08
0080 #define GRPCI2_BAR2_TO_AHB_MAP 0x0c
0081 #define GRPCI2_PCI_CONFIG      0x20
0082 #define CAP9_AHBPREF_OFS 0x3c
0083 
0084 /* #define DEBUG 1 */
0085 
0086 #ifdef DEBUG
0087 #define DBG(x...) printk(x)
0088 #else
0089 #define DBG(x...) 
0090 #endif
0091 
0092 int gr_cpci_gr740_init1(struct drvmgr_dev *dev);
0093 int gr_cpci_gr740_init2(struct drvmgr_dev *dev);
0094 void gr_cpci_gr740_isr(void *arg);
0095 
0096 struct grpci2_regs {
0097     volatile unsigned int ctrl;     /* 0x00 */
0098     volatile unsigned int sts_cap;      /* 0x04 */
0099     volatile unsigned int ppref;        /* 0x08 */
0100     volatile unsigned int io_map;       /* 0x0C */
0101     volatile unsigned int dma_ctrl;     /* 0x10 */
0102     volatile unsigned int dma_bdbase;   /* 0x14 */
0103     volatile unsigned int dma_chact;    /* 0x18 */
0104     int res1;               /* 0x1C */
0105     volatile unsigned int bars[6];      /* 0x20 */
0106     int res2[2];                /* 0x38 */
0107     volatile unsigned int ahbmst_map[16];   /* 0x40 */
0108 };
0109 
0110 /* Clock gating unit register layout */
0111 struct gr740_grcg_regs {
0112     volatile unsigned int unlock;
0113     volatile unsigned int enable;
0114     volatile unsigned int reset;
0115     volatile unsigned int cpu_fpu;
0116 };
0117 #define CG_MASK 0x3ff
0118 
0119 /* Private data structure for driver */
0120 struct gr_cpci_gr740_priv {
0121     /* Driver management */
0122     struct drvmgr_dev   *dev;
0123     char            prefix[16];
0124     SPIN_DECLARE(devlock);
0125 
0126     /* PCI */
0127     pci_dev_t       pcidev;
0128     struct pci_dev_info *devinfo;
0129     uint32_t        ahbmst2pci_map;
0130 
0131     /* IRQ */
0132     int         eirq;
0133     genirq_t        genirq;
0134 
0135     /* GR-CPCI-GR740 */
0136     unsigned int        amba_freq_hz;
0137     unsigned int        cg_en_mask;     /* Enabled cores */
0138     struct irqmp_regs   *irq;
0139     struct gr740_grcg_regs  *cg;            /* Clock-gating unit */
0140     struct grpci2_regs  *grpci2;
0141     struct drvmgr_map_entry bus_maps_up[2];
0142     struct drvmgr_map_entry bus_maps_down[4];
0143 
0144     /* AMBA Plug&Play information on GR-CPCI-GR740 */
0145     struct ambapp_bus   abus;
0146     struct ambapp_mmap  amba_maps[5];
0147     struct ambapp_config    config;
0148 };
0149 
0150 int ambapp_gr740_int_register(
0151     struct drvmgr_dev *dev,
0152     int irq,
0153     const char *info,
0154     drvmgr_isr handler,
0155     void *arg);
0156 int ambapp_gr740_int_unregister(
0157     struct drvmgr_dev *dev,
0158     int irq,
0159     drvmgr_isr handler,
0160     void *arg);
0161 int ambapp_gr740_int_unmask(
0162     struct drvmgr_dev *dev,
0163     int irq);
0164 int ambapp_gr740_int_mask(
0165     struct drvmgr_dev *dev,
0166     int irq);
0167 int ambapp_gr740_int_clear(
0168     struct drvmgr_dev *dev,
0169     int irq);
0170 int ambapp_gr740_get_params(
0171     struct drvmgr_dev *dev,
0172     struct drvmgr_bus_params *params);
0173 
0174 static struct ambapp_ops ambapp_gr740_ops = {
0175     .int_register = ambapp_gr740_int_register,
0176     .int_unregister = ambapp_gr740_int_unregister,
0177     .int_unmask = ambapp_gr740_int_unmask,
0178     .int_mask = ambapp_gr740_int_mask,
0179     .int_clear = ambapp_gr740_int_clear,
0180     .get_params = ambapp_gr740_get_params
0181 };
0182 
0183 struct drvmgr_drv_ops gr_cpci_gr740_ops = 
0184 {
0185     .init = {gr_cpci_gr740_init1, gr_cpci_gr740_init2, NULL, NULL},
0186     .remove = NULL,
0187     .info = NULL
0188 };
0189 
0190 struct pci_dev_id_match gr_cpci_gr740_ids[] =
0191 {
0192     PCIID_DEVVEND(PCIID_VENDOR_GAISLER, PCIID_DEVICE_GR_CPCI_GR740),
0193     PCIID_END_TABLE /* Mark end of table */
0194 };
0195 
0196 struct pci_drv_info gr_cpci_gr740_info =
0197 {
0198     {
0199         DRVMGR_OBJ_DRV,         /* Driver */
0200         NULL,               /* Next driver */
0201         NULL,               /* Device list */
0202         DRIVER_PCI_GAISLER_CPCI_GR740_ID,   /* Driver ID */
0203         "GR-CPCI-GR740",        /* Driver Name */
0204         DRVMGR_BUS_TYPE_PCI,        /* Bus Type */
0205         &gr_cpci_gr740_ops,
0206         NULL,               /* Funcs */
0207         0,              /* No devices yet */
0208         sizeof(struct gr_cpci_gr740_priv),
0209     },
0210     &gr_cpci_gr740_ids[0]
0211 };
0212 
0213 /* Driver resources configuration for the AMBA bus on the GR-CPCI-GR740 board.
0214  * It is declared weak so that the user may override it from the project file,
0215  * if the default settings are not enough.
0216  *
0217  * The configuration consists of an array of configuration pointers, each
0218  * pointer determine the configuration of one GR-CPCI-GR740 board. Pointer
0219  * zero is for board0, pointer 1 for board1 and so on.
0220  *
0221  * The array must end with a NULL pointer.
0222  */
0223 struct drvmgr_bus_res *gr_cpci_gr740_resources[] __attribute__((weak)) =
0224 {
0225     NULL
0226 };
0227 
0228 void gr_cpci_gr740_register_drv(void)
0229 {
0230     DBG("Registering GR-CPCI-GR740 PCI driver\n");
0231     drvmgr_drv_register(&gr_cpci_gr740_info.general);
0232 }
0233 
0234 void gr_cpci_gr740_isr(void *arg)
0235 {
0236     struct gr_cpci_gr740_priv *priv = arg;
0237     unsigned int status, tmp;
0238     int irq, eirq;
0239     SPIN_ISR_IRQFLAGS(irqflags);
0240 
0241     tmp = status = priv->irq->ipend;
0242 
0243     /* DBG("GR-CPCI-GR740: IRQ 0x%x\n",status); */
0244 
0245     SPIN_LOCK(&priv->devlock, irqflags);
0246     for(irq = 0; irq < 32; irq++) {
0247         if (status & (1 << irq)) {
0248             if (irq == priv->eirq) {
0249                 while ((eirq = priv->irq->intid[0] & 0x1f)) {
0250                     if ((eirq & 0x10) == 0)
0251                         continue;
0252                     genirq_doirq(priv->genirq, eirq);
0253                     priv->irq->iclear = (1 << eirq);
0254                 }
0255             } else {
0256                 genirq_doirq(priv->genirq, irq);
0257             }
0258             priv->irq->iclear = (1 << irq);
0259             status &= ~(1 << irq);
0260             if ( status == 0 )
0261                 break;
0262         }
0263     }
0264     SPIN_UNLOCK(&priv->devlock, irqflags);
0265 
0266     /* ACK interrupt, this is because PCI is Level, so the IRQ Controller
0267      * still drives the IRQ
0268      */
0269     if ( tmp ) 
0270         drvmgr_interrupt_clear(priv->dev, 0);
0271 
0272     DBG("GR-CPCI-GR740-IRQ: 0x%x\n", tmp);
0273 }
0274 
0275 static int gr_cpci_gr740_hw_init1(struct gr_cpci_gr740_priv *priv)
0276 {
0277     int i;
0278     uint32_t data;
0279     unsigned int ctrl;
0280     uint8_t tmp2;
0281     struct ambapp_dev *tmp;
0282     struct ambapp_ahb_info *ahb;
0283     uint8_t cap_ptr;
0284     pci_dev_t pcidev = priv->pcidev;
0285     struct pci_dev_info *devinfo = priv->devinfo;
0286     unsigned int cgmask, enabled;
0287 
0288     /* Check capabilities list bit and read its pointer */
0289     pci_cfg_r8(pcidev, PCIR_STATUS, &tmp2);
0290     if (!((tmp2 >> 4) & 1)) {
0291         /* Capabilities list not available which it should be in the GRPCI2 */
0292         return -2;
0293     }
0294     pci_cfg_r8(pcidev, PCIR_CAP_PTR, &cap_ptr);
0295 
0296     /* Set AHB address mappings for target PCI bars
0297      *  BAR0 maps to 0x00000000-0x07ffffff 128MB (SDRAM/DDR2 memory)
0298      *  BAR1 maps to 0xf0000000-0xf7ffffff 128MB (L2-Cache regs/diagnostics)
0299      *  BAR2 maps to 0xff800000-0xffffffff   8MB (PnP, I/O regs)
0300      */
0301     pci_cfg_w32(pcidev, cap_ptr+GRPCI2_BAR0_TO_AHB_MAP, 0x00000000);
0302     pci_cfg_w32(pcidev, cap_ptr+GRPCI2_BAR1_TO_AHB_MAP, 0xf0000000);
0303     pci_cfg_w32(pcidev, cap_ptr+GRPCI2_BAR2_TO_AHB_MAP, 0xff800000);
0304 
0305     /* Set PCI bus to be big endian */
0306     pci_cfg_r32(pcidev, cap_ptr+GRPCI2_PCI_CONFIG, &data);
0307     data = data & 0xFFFFFFFE;
0308     pci_cfg_w32(pcidev, cap_ptr+GRPCI2_PCI_CONFIG, data);
0309 
0310 #if 0
0311     /* set parity error response */
0312     pci_cfg_r32(pcidev, PCIR_COMMAND, &data);
0313     pci_cfg_w32(pcidev, PCIR_COMMAND, (data|PCIM_CMD_PERRESPEN));
0314 #endif
0315 
0316     /* Scan AMBA Plug&Play */
0317 
0318     /* AMBA MAP bar0 (in gr740) ==> 0x00000000 (remote amba address) */
0319     priv->amba_maps[0].size = devinfo->resources[0].size;
0320     priv->amba_maps[0].local_adr = devinfo->resources[0].address;
0321     priv->amba_maps[0].remote_adr = 0x00000000;
0322 
0323     priv->amba_maps[1].size = devinfo->resources[1].size;
0324     priv->amba_maps[1].local_adr = devinfo->resources[1].address;
0325     priv->amba_maps[1].remote_adr = 0xf0000000;
0326 
0327     priv->amba_maps[2].size = devinfo->resources[2].size;
0328     priv->amba_maps[2].local_adr = devinfo->resources[2].address;
0329     priv->amba_maps[2].remote_adr = 0xff800000;
0330 
0331     /* Addresses not matching with map be untouched */
0332     priv->amba_maps[3].size = 0xfffffff0;
0333     priv->amba_maps[3].local_adr = 0;
0334     priv->amba_maps[3].remote_adr = 0;
0335 
0336     /* Mark end of table */
0337     priv->amba_maps[4].size=0;
0338 
0339     /* Start AMBA PnP scan at first AHB bus */
0340     ambapp_scan(
0341         &priv->abus,
0342         devinfo->resources[2].address + 0x00700000,
0343         NULL,
0344         &priv->amba_maps[0]);
0345 
0346     /* Initialize Frequency of AMBA bus */
0347     ambapp_freq_init(&priv->abus, NULL, priv->amba_freq_hz);
0348 
0349     /* Find IRQ controller, Clear all current IRQs */
0350     tmp = (struct ambapp_dev *)ambapp_for_each(&priv->abus,
0351                 (OPTIONS_ALL|OPTIONS_APB_SLVS),
0352                 VENDOR_GAISLER, GAISLER_IRQMP,
0353                 ambapp_find_by_idx, NULL);
0354     if ( !tmp ) {
0355         return -4;
0356     }
0357     priv->irq = (struct irqmp_regs *)DEV_TO_APB(tmp)->start;
0358     /* Set up GR-CPCI-GR740 irq controller
0359      * Interrupts are routed from IRQCtrl0, we leave the configuration
0360      * for the other CPUs, as the board's CPUs may be running something.
0361      * We assume IRQCtrl has been set up properly, or at least the reset
0362      * values shuold work with this code..
0363      */
0364     priv->irq->mask[0] = 0;
0365     priv->irq->iforce = 0;
0366     priv->irq->force[0] = 0;
0367     priv->irq->ilevel = 0;
0368     priv->irq->ipend = 0;
0369     priv->irq->iclear = 0xffffffff;
0370     priv->irq->ilevel = 0;
0371     /* Get extended Interrupt controller IRQ number */
0372     priv->eirq = (priv->irq->mpstat >> 16) & 0xf;
0373 
0374     /* Find first Clock-Gating unit, enable/disable the requested cores */
0375     tmp = (struct ambapp_dev *)ambapp_for_each(&priv->abus,
0376                 (OPTIONS_ALL|OPTIONS_APB_SLVS),
0377                 VENDOR_GAISLER, GAISLER_CLKGATE,
0378                 ambapp_find_by_idx, NULL);
0379     if ( !tmp ) {
0380         return -5;
0381     }
0382     priv->cg = (struct gr740_grcg_regs *)DEV_TO_APB(tmp)->start;
0383     /* Do reset and enable sequence only if not already enabled */
0384     if (priv->cg && ((enabled = priv->cg->enable) != priv->cg_en_mask)) {
0385         /* First disable already enabled cores */
0386         cgmask = ~priv->cg_en_mask & enabled;
0387         if (cgmask) {
0388             priv->cg->unlock = cgmask;
0389             priv->cg->enable = enabled = ~cgmask & enabled;
0390             priv->cg->unlock = 0;
0391         }
0392         /* Enable disabled cores */
0393         cgmask = priv->cg_en_mask & ~enabled;
0394         if (cgmask) {
0395             priv->cg->unlock = cgmask;
0396             priv->cg->reset |= cgmask;
0397             priv->cg->enable = cgmask | enabled;
0398             priv->cg->reset &= ~cgmask;
0399             priv->cg->unlock = 0;
0400         }
0401     }
0402 
0403     priv->bus_maps_down[0].name = "PCI BAR0 -> AMBA";
0404     priv->bus_maps_down[0].size = priv->amba_maps[0].size;
0405     priv->bus_maps_down[0].from_adr = (void *)priv->amba_maps[0].local_adr;
0406     priv->bus_maps_down[0].to_adr = (void *)priv->amba_maps[0].remote_adr;
0407     priv->bus_maps_down[1].name = "PCI BAR1 -> AMBA";
0408     priv->bus_maps_down[1].size = priv->amba_maps[1].size;
0409     priv->bus_maps_down[1].from_adr = (void *)priv->amba_maps[1].local_adr;
0410     priv->bus_maps_down[1].to_adr = (void *)priv->amba_maps[1].remote_adr;
0411     priv->bus_maps_down[2].name = "PCI BAR2 -> AMBA";
0412     priv->bus_maps_down[2].size = priv->amba_maps[2].size;
0413     priv->bus_maps_down[2].from_adr = (void *)priv->amba_maps[2].local_adr;
0414     priv->bus_maps_down[2].to_adr = (void *)priv->amba_maps[2].remote_adr;
0415     priv->bus_maps_down[3].size = 0;
0416 
0417     /* Find GRPCI2 controller AHB Slave interface */
0418     tmp = (struct ambapp_dev *)ambapp_for_each(&priv->abus,
0419                     (OPTIONS_ALL|OPTIONS_AHB_SLVS),
0420                     VENDOR_GAISLER, GAISLER_GRPCI2,
0421                     ambapp_find_by_idx, NULL);
0422     if ( !tmp ) {
0423         return -6;
0424     }
0425     ahb = (struct ambapp_ahb_info *)tmp->devinfo;
0426     priv->bus_maps_up[0].name = "AMBA GRPCI2 Window";
0427     priv->bus_maps_up[0].size = ahb->mask[0]; /* AMBA->PCI Window on GR-CPCI-GR740 board */
0428     priv->bus_maps_up[0].from_adr = (void *)ahb->start[0];
0429     priv->bus_maps_up[0].to_adr = (void *)
0430                 (priv->ahbmst2pci_map & ~(ahb->mask[0]-1));
0431     priv->bus_maps_up[1].size = 0;
0432 
0433     /* Find GRPCI2 controller APB Slave interface */
0434     tmp = (struct ambapp_dev *)ambapp_for_each(&priv->abus,
0435                     (OPTIONS_ALL|OPTIONS_APB_SLVS),
0436                     VENDOR_GAISLER, GAISLER_GRPCI2,
0437                     ambapp_find_by_idx, NULL);
0438     if ( !tmp ) {
0439         return -7;
0440     }
0441     priv->grpci2 = (struct grpci2_regs *)
0442         ((struct ambapp_apb_info *)tmp->devinfo)->start;
0443 
0444     /* Set AHB to PCI mapping for all AMBA AHB masters */
0445     for(i = 0; i < 16; i++) {
0446         priv->grpci2->ahbmst_map[i] = priv->ahbmst2pci_map &
0447                             ~(ahb->mask[0]-1);
0448     }
0449 
0450     /* Make sure dirq(0) sampling is enabled */
0451     ctrl = priv->grpci2->ctrl;
0452     ctrl = (ctrl & 0xFFFFFF0F) | (1 << 4);
0453     priv->grpci2->ctrl = ctrl;
0454 
0455     /* Successfully registered the GR740 board */
0456     return 0;
0457 }
0458 
0459 static int gr_cpci_gr740_hw_init2(struct gr_cpci_gr740_priv *priv)
0460 {
0461     /* Enable DMA by enabling PCI target as master */
0462     pci_master_enable(priv->pcidev);
0463 
0464     return DRVMGR_OK;
0465 }
0466 
0467 /* Called when a PCI target is found with the PCI device and vendor ID 
0468  * given in gr_cpci_gr740_ids[].
0469  */
0470 int gr_cpci_gr740_init1(struct drvmgr_dev *dev)
0471 {
0472     struct gr_cpci_gr740_priv *priv;
0473     struct pci_dev_info *devinfo;
0474     int status, i;
0475     union drvmgr_key_value *value;
0476     int resources_cnt;
0477     int sc;
0478 
0479     priv = dev->priv;
0480     if (!priv)
0481         return DRVMGR_NOMEM;
0482 
0483     memset(priv, 0, sizeof(*priv));
0484     dev->priv = priv;
0485     priv->dev = dev;
0486 
0487     /* Determine number of configurations */
0488     resources_cnt = get_resarray_count(gr_cpci_gr740_resources);
0489 
0490     /* Generate Device prefix */
0491 
0492     strcpy(priv->prefix, "/dev/gr740_0");
0493     priv->prefix[11] += dev->minor_drv;
0494     sc = mkdir(priv->prefix, S_IRWXU | S_IRWXG | S_IRWXO);
0495     _Assert_Unused_variable_equals(sc, 0);
0496     priv->prefix[12] = '/';
0497     priv->prefix[13] = '\0';
0498 
0499     priv->devinfo = devinfo = (struct pci_dev_info *)dev->businfo;
0500     priv->pcidev = devinfo->pcidev;
0501     printk("\n\n--- GR-CPCI-GR740[%d] ---\n", dev->minor_drv);
0502     printk(" PCI BUS: 0x%x, SLOT: 0x%x, FUNCTION: 0x%x\n",
0503         PCI_DEV_EXPAND(priv->pcidev));
0504     printk(" PCI VENDOR: 0x%04x, DEVICE: 0x%04x\n",
0505         devinfo->id.vendor, devinfo->id.device);
0506     for (i = 0; i < 3; i++) {
0507         printk(" PCI BAR[%d]: 0x%08" PRIx32 " - 0x%08" PRIx32 "\n",
0508             i, devinfo->resources[i].address,
0509             devinfo->resources[i].address +
0510             (devinfo->resources[i].size - 1));
0511         /* all neccessary space assigned to GR-CPCI-GR740 target? */
0512         if (devinfo->resources[i].size == 0)
0513             return DRVMGR_ENORES;
0514     }
0515     printk(" IRQ: %d\n\n\n", devinfo->irq);
0516 
0517     /* Initialize spin-lock for this PCI perihperal device. This is to
0518      * protect the Interrupt Controller Registers. The genirq layer is
0519          * protecting its own internals and ISR dispatching.
0520          */
0521     SPIN_INIT(&priv->devlock, priv->prefix);
0522 
0523     /* Let user override which PCI address the AHB masters of the
0524      * GR740 board access when doing DMA to HOST RAM. The AHB masters
0525      * access the PCI Window of the AMBA bus, the MSB 2-bits of that address
0526      * is translated according this config option before the address goes
0527      * out on the PCI bus.
0528      *
0529      * Only the 2 MSB bits have an effect.
0530      */
0531     value = drvmgr_dev_key_get(priv->dev, "ahbmst2pci", DRVMGR_KT_INT);
0532     if (value)
0533         priv->ahbmst2pci_map = value->i;
0534     else
0535         priv->ahbmst2pci_map = AHBMST2PCIADR; /* default */
0536 
0537     /* Let user override the default AMBA system frequency of the 
0538      * CPU-bus of the remote GR-CPCI-GR740. Default is 250MHz.
0539      */
0540     value = drvmgr_dev_key_get(priv->dev, "ambaFreq", DRVMGR_KT_INT);
0541     if (value)
0542         priv->amba_freq_hz = value->i;
0543     else
0544         priv->amba_freq_hz = 250000000; /* default */
0545 
0546     /* Let user determine clock-gating unit configuration. The default
0547      * is to turn all cores on (disable gating). PCI is always turned ON.
0548      */
0549     value = drvmgr_dev_key_get(priv->dev, "cgEnMask", DRVMGR_KT_INT);
0550     if (value)
0551         priv->cg_en_mask = (value->i & CG_MASK) | 0x08;
0552     else
0553         priv->cg_en_mask = CG_MASK; /* default all ON */
0554 
0555     priv->genirq = genirq_init(32);
0556     if (priv->genirq == NULL)
0557         return DRVMGR_FAIL;
0558 
0559     if ((status = gr_cpci_gr740_hw_init1(priv)) != 0) {
0560         genirq_destroy(priv->genirq);
0561         printk(" Failed to initialize GR-CPCI-GR740 HW: %d\n", status);
0562         return DRVMGR_FAIL;
0563     }
0564 
0565     /* Init amba bus */
0566     priv->config.abus = &priv->abus;
0567     priv->config.ops = &ambapp_gr740_ops;
0568     priv->config.maps_up = &priv->bus_maps_up[0];
0569     priv->config.maps_down = &priv->bus_maps_down[0];
0570     if ( priv->dev->minor_drv < resources_cnt ) {
0571         priv->config.resources = gr_cpci_gr740_resources[priv->dev->minor_drv];
0572     } else {
0573         priv->config.resources = NULL;
0574     }
0575 
0576     /* Create and register AMBA PnP bus. */
0577     return ambapp_bus_register(dev, &priv->config);
0578 }
0579 
0580 int gr_cpci_gr740_init2(struct drvmgr_dev *dev)
0581 {
0582     struct gr_cpci_gr740_priv *priv = dev->priv;
0583 
0584     /* Clear any old interrupt requests */
0585     drvmgr_interrupt_clear(dev, 0);
0586 
0587     /* Enable System IRQ so that GR-CPCI-GR740 PCI target interrupt
0588      * goes through.
0589      *
0590      * It is important to enable it in stage init2. If interrupts were
0591      * enabled in init1 this might hang the system when more than one
0592      * PCI board is connected, this is because PCI interrupts might
0593      * be shared and PCI board 2 have not initialized and
0594      * might therefore drive interrupt already when entering init1().
0595      */
0596     drvmgr_interrupt_register(
0597         dev,
0598         0,
0599         "gr_cpci_gr740",
0600         gr_cpci_gr740_isr,
0601         (void *)priv);
0602 
0603     return gr_cpci_gr740_hw_init2(priv);
0604 }
0605 
0606 int ambapp_gr740_int_register(
0607     struct drvmgr_dev *dev,
0608     int irq,
0609     const char *info,
0610     drvmgr_isr handler,
0611     void *arg)
0612 {
0613     struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
0614     SPIN_IRQFLAGS(irqflags);
0615     int status;
0616     void *h;
0617 
0618     h = genirq_alloc_handler(handler, arg);
0619     if ( h == NULL )
0620         return DRVMGR_FAIL;
0621 
0622     SPIN_LOCK_IRQ(&priv->devlock, irqflags);
0623 
0624     status = genirq_register(priv->genirq, irq, h);
0625     if (status == 0) {
0626         /* Clear IRQ for first registered handler */
0627         priv->irq->iclear = (1<<irq);
0628     } else if (status == 1)
0629         status = 0;
0630 
0631     if (status != 0) {
0632         SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
0633         genirq_free_handler(h);
0634         return DRVMGR_FAIL;
0635     }
0636 
0637     status = genirq_enable(priv->genirq, irq, handler, arg);
0638     if ( status == 0 ) {
0639         /* Enable IRQ for first enabled handler only */
0640         priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
0641     } else if ( status == 1 )
0642         status = 0;
0643 
0644     SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
0645 
0646     return status;
0647 }
0648 
0649 int ambapp_gr740_int_unregister(
0650     struct drvmgr_dev *dev,
0651     int irq,
0652     drvmgr_isr isr,
0653     void *arg)
0654 {
0655     struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
0656     SPIN_IRQFLAGS(irqflags);
0657     int status;
0658     void *handler;
0659 
0660     SPIN_LOCK_IRQ(&priv->devlock, irqflags);
0661 
0662     status = genirq_disable(priv->genirq, irq, isr, arg);
0663     if ( status == 0 ) {
0664         /* Disable IRQ only when no enabled handler exists */
0665         priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
0666     }
0667 
0668     handler = genirq_unregister(priv->genirq, irq, isr, arg);
0669     if ( handler == NULL )
0670         status = DRVMGR_FAIL;
0671     else
0672         status = DRVMGR_OK;
0673 
0674     SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
0675 
0676     if (handler)
0677         genirq_free_handler(handler);
0678 
0679     return status;
0680 }
0681 
0682 int ambapp_gr740_int_unmask(
0683     struct drvmgr_dev *dev,
0684     int irq)
0685 {
0686     struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
0687     SPIN_IRQFLAGS(irqflags);
0688 
0689     DBG("GR740 IRQ %d: unmask\n", irq);
0690 
0691     if ( genirq_check(priv->genirq, irq) )
0692         return DRVMGR_EINVAL;
0693 
0694     SPIN_LOCK_IRQ(&priv->devlock, irqflags);
0695 
0696     /* Enable IRQ for first enabled handler only */
0697     priv->irq->mask[0] |= (1<<irq); /* unmask interrupt source */
0698 
0699     SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
0700 
0701     return DRVMGR_OK;
0702 }
0703 
0704 int ambapp_gr740_int_mask(
0705     struct drvmgr_dev *dev,
0706     int irq)
0707 {
0708     struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
0709     SPIN_IRQFLAGS(irqflags);
0710 
0711     DBG("GR740 IRQ %d: mask\n", irq);
0712 
0713     if ( genirq_check(priv->genirq, irq) )
0714         return DRVMGR_EINVAL;
0715 
0716     SPIN_LOCK_IRQ(&priv->devlock, irqflags);
0717 
0718     /* Disable/mask IRQ */
0719     priv->irq->mask[0] &= ~(1<<irq); /* mask interrupt source */
0720 
0721     SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
0722 
0723     return DRVMGR_OK;
0724 }
0725 
0726 int ambapp_gr740_int_clear(
0727     struct drvmgr_dev *dev,
0728     int irq)
0729 {
0730     struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
0731 
0732     if ( genirq_check(priv->genirq, irq) )
0733         return DRVMGR_EINVAL;
0734 
0735     priv->irq->iclear = (1<<irq);
0736 
0737     return DRVMGR_OK;
0738 }
0739 
0740 int ambapp_gr740_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params)
0741 {
0742     struct gr_cpci_gr740_priv *priv = dev->parent->dev->priv;
0743 
0744     /* Device name prefix pointer, skip /dev */
0745     params->dev_prefix = &priv->prefix[5];
0746 
0747     return 0;
0748 }
0749 
0750 void gr_cpci_gr740_print_dev(struct drvmgr_dev *dev, int options)
0751 {
0752     struct gr_cpci_gr740_priv *priv = dev->priv;
0753     struct pci_dev_info *devinfo = priv->devinfo;
0754     uint32_t bar0, bar0_size;
0755 
0756     /* Print */
0757     printf("--- GR-CPCI-GR740 [bus 0x%x, dev 0x%x, fun 0x%x] ---\n",
0758         PCI_DEV_EXPAND(priv->pcidev));
0759 
0760     bar0 = devinfo->resources[0].address;
0761     bar0_size = devinfo->resources[0].size;
0762     printf(" PCI BAR[0]: 0x%" PRIx32 " - 0x%" PRIx32 "\n",
0763         bar0, bar0 + bar0_size - 1);
0764     printf(" IRQ REGS:        0x%" PRIxPTR "\n", (uintptr_t)priv->irq);
0765     printf(" IRQ:             %d\n", devinfo->irq);
0766     printf(" PCI REVISION:    %d\n", devinfo->rev);
0767     printf(" FREQ:            %d Hz\n", priv->amba_freq_hz);
0768     printf(" IMASK:           0x%08x\n", priv->irq->mask[0]);
0769     printf(" IPEND:           0x%08x\n", priv->irq->ipend);
0770 
0771     /* Print amba config */
0772     if (options & GR_CPCI_GR740_OPTIONS_AMBA)
0773         ambapp_print(&priv->abus, 10);
0774 }
0775 
0776 void gr_cpci_gr740_print(int options)
0777 {
0778     struct pci_drv_info *drv = &gr_cpci_gr740_info;
0779     struct drvmgr_dev *dev;
0780 
0781     dev = drv->general.dev;
0782     while(dev) {
0783         gr_cpci_gr740_print_dev(dev, options);
0784         dev = dev->next_in_drv;
0785     }
0786 }