Back to home page

LXR

 
 

    


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

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