diff options
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/pci/pcif.c')
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/pci/pcif.c | 586 |
1 files changed, 0 insertions, 586 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/pci/pcif.c b/c/src/lib/libbsp/sparc/shared/pci/pcif.c deleted file mode 100644 index c0b8fc9629..0000000000 --- a/c/src/lib/libbsp/sparc/shared/pci/pcif.c +++ /dev/null @@ -1,586 +0,0 @@ -/* GRLIB PCIF PCI HOST driver. - * - * COPYRIGHT (c) 2008. - * Cobham Gaisler AB. - * - * Configures the PCIF core and initialize, - * - the PCI Library (pci.c) - * - the general part of the PCI Bus driver (pci_bus.c) - * - * System interrupt assigned to PCI interrupt (INTA#..INTD#) is by - * default taken from Plug and Play, but may be overridden by the - * driver resources INTA#..INTD#. - * - * The license and distribution terms for this file may be - * found in found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <libcpu/byteorder.h> -#include <libcpu/access.h> -#include <rtems/bspIo.h> -#include <pci.h> -#include <pci/cfg.h> - -#include <drvmgr/drvmgr.h> -#include <drvmgr/ambapp_bus.h> -#include <ambapp.h> -#include <drvmgr/pci_bus.h> -#include <bsp/pcif.h> - - -/* Configuration options */ -#define SYSTEM_MAINMEM_START 0x40000000 - -/* Interrupt assignment. Set to other value than 0xff in order to - * override defaults and plug&play information - */ -#ifndef PCIF_INTA_SYSIRQ - #define PCIF_INTA_SYSIRQ 0xff -#endif -#ifndef PCIF_INTB_SYSIRQ - #define PCIF_INTB_SYSIRQ 0xff -#endif -#ifndef PCIF_INTC_SYSIRQ - #define PCIF_INTC_SYSIRQ 0xff -#endif -#ifndef PCIF_INTD_SYSIRQ - #define PCIF_INTD_SYSIRQ 0xff -#endif - -/*#define DEBUG 1 */ - -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -/* - * Bit encode for PCI_CONFIG_HEADER_TYPE register - */ -struct pcif_regs { - volatile unsigned int bars[4]; /* 0x00-0x10 */ - volatile unsigned int bus; /* 0x10 */ - volatile unsigned int map_io; /* 0x14 */ - volatile unsigned int status; /* 0x18 */ - volatile unsigned int intr; /* 0x1c */ - int unused[(0x40-0x20)/4]; /* 0x20-0x40 */ - volatile unsigned int maps[(0x80-0x40)/4]; /* 0x40-0x80*/ -}; - -/* Used internally for accessing the PCI bridge's configuration space itself */ -#define HOST_TGT PCI_DEV(0xff, 0, 0) - -struct pcif_priv *pcifpriv = NULL; -static int pcif_minor = 0; - -/* PCI Interrupt assignment. Connects an PCI interrupt pin (INTA#..INTD#) - * to a system interrupt number. - */ -unsigned char pcif_pci_irq_table[4] = -{ - /* INTA# */ PCIF_INTA_SYSIRQ, - /* INTB# */ PCIF_INTB_SYSIRQ, - /* INTC# */ PCIF_INTC_SYSIRQ, - /* INTD# */ PCIF_INTD_SYSIRQ -}; - -/* Driver private data struture */ -struct pcif_priv { - struct drvmgr_dev *dev; - struct pcif_regs *regs; - int irq; - int minor; - int irq_mask; - - unsigned int pci_area; - unsigned int pci_area_end; - unsigned int pci_io; - unsigned int pci_conf; - unsigned int pci_conf_end; - - uint32_t devVend; /* Host PCI Vendor/Device ID */ - uint32_t bar1_size; - - struct drvmgr_map_entry maps_up[2]; - struct drvmgr_map_entry maps_down[2]; - struct pcibus_config config; -}; - -int pcif_init1(struct drvmgr_dev *dev); -int pcif_init3(struct drvmgr_dev *dev); - -/* PCIF DRIVER */ - -struct drvmgr_drv_ops pcif_ops = -{ - .init = {pcif_init1, NULL, pcif_init3, NULL}, - .remove = NULL, - .info = NULL -}; - -struct amba_dev_id pcif_ids[] = -{ - {VENDOR_GAISLER, GAISLER_PCIF}, - {0, 0} /* Mark end of table */ -}; - -struct amba_drv_info pcif_info = -{ - { - DRVMGR_OBJ_DRV, /* Driver */ - NULL, /* Next driver */ - NULL, /* Device list */ - DRIVER_AMBAPP_GAISLER_PCIF_ID, /* Driver ID */ - "PCIF_DRV", /* Driver Name */ - DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */ - &pcif_ops, - NULL, /* Funcs */ - 0, /* No devices yet */ - sizeof(struct pcif_priv), /* Let drvmgr alloc private */ - }, - &pcif_ids[0] -}; - -void pcif_register_drv(void) -{ - DBG("Registering PCIF driver\n"); - drvmgr_drv_register(&pcif_info.general); -} - -static int pcif_cfg_r32(pci_dev_t dev, int ofs, uint32_t *val) -{ - struct pcif_priv *priv = pcifpriv; - volatile uint32_t *pci_conf; - uint32_t devfn; - int retval; - int bus = PCI_DEV_BUS(dev); - - if (ofs & 3) - return PCISTS_EINVAL; - - if (PCI_DEV_SLOT(dev) > 15) { - *val = 0xffffffff; - return PCISTS_OK; - } - - /* PCIF can access "non-standard" devices on bus0 (on AD11.AD16), - * but we skip them. - */ - if (dev == HOST_TGT) - bus = devfn = 0; - else if (bus == 0) - devfn = PCI_DEV_DEVFUNC(dev) + PCI_DEV(0, 6, 0); - else - devfn = PCI_DEV_DEVFUNC(dev); - - /* Select bus */ - priv->regs->bus = bus << 16; - - pci_conf = (volatile uint32_t *)(priv->pci_conf | (devfn << 8) | ofs); - - *val = *pci_conf; - - if (priv->regs->status & 0x30000000) { - *val = 0xffffffff; - retval = PCISTS_MSTABRT; - } else - retval = PCISTS_OK; - - DBG("pci_read: [%x:%x:%x] reg: 0x%x => addr: 0x%x, val: 0x%x\n", - PCI_DEV_EXPAND(dev), ofs, pci_conf, *val); - - return retval; -} - -static int pcif_cfg_r16(pci_dev_t dev, int ofs, uint16_t *val) -{ - uint32_t v; - int retval; - - if (ofs & 1) - return PCISTS_EINVAL; - - retval = pcif_cfg_r32(dev, ofs & ~0x3, &v); - *val = 0xffff & (v >> (8*(ofs & 0x3))); - - return retval; -} - -static int pcif_cfg_r8(pci_dev_t dev, int ofs, uint8_t *val) -{ - uint32_t v; - int retval; - - retval = pcif_cfg_r32(dev, ofs & ~0x3, &v); - - *val = 0xff & (v >> (8*(ofs & 3))); - - return retval; -} - -static int pcif_cfg_w32(pci_dev_t dev, int ofs, uint32_t val) -{ - struct pcif_priv *priv = pcifpriv; - volatile uint32_t *pci_conf; - uint32_t devfn; - int bus = PCI_DEV_BUS(dev); - - if (ofs & ~0xfc) - return PCISTS_EINVAL; - - if (PCI_DEV_SLOT(dev) > 15) - return PCISTS_MSTABRT; - - /* PCIF can access "non-standard" devices on bus0 (on AD11.AD16), - * but we skip them. - */ - if (dev == HOST_TGT) - bus = devfn = 0; - else if (bus == 0) - devfn = PCI_DEV_DEVFUNC(dev) + PCI_DEV(0, 6, 0); - else - devfn = PCI_DEV_DEVFUNC(dev); - - /* Select bus */ - priv->regs->bus = bus << 16; - - pci_conf = (volatile uint32_t *)(priv->pci_conf | (devfn << 8) | ofs); - - *pci_conf = val; - - DBG("pci_write - [%x:%x:%x] reg: 0x%x => addr: 0x%x, val: 0x%x\n", - PCI_DEV_EXPAND(dev), ofs, pci_conf, value); - - return PCISTS_OK; -} - -static int pcif_cfg_w16(pci_dev_t dev, int ofs, uint16_t val) -{ - uint32_t v; - int retval; - - if (ofs & 1) - return PCISTS_EINVAL; - - retval = pcif_cfg_r32(dev, ofs & ~0x3, &v); - if (retval != PCISTS_OK) - return retval; - - v = (v & ~(0xffff << (8*(ofs&3)))) | ((0xffff&val) << (8*(ofs&3))); - - return pcif_cfg_w32(dev, ofs & ~0x3, v); -} - -static int pcif_cfg_w8(pci_dev_t dev, int ofs, uint8_t val) -{ - uint32_t v; - int retval; - - retval = pcif_cfg_r32(dev, ofs & ~0x3, &v); - if (retval != PCISTS_OK) - return retval; - - v = (v & ~(0xff << (8*(ofs&3)))) | ((0xff&val) << (8*(ofs&3))); - - return pcif_cfg_w32(dev, ofs & ~0x3, v); -} - - -/* Return the assigned system IRQ number that corresponds to the PCI - * "Interrupt Pin" information from configuration space. - * - * The IRQ information is stored in the pcif_pci_irq_table configurable - * by the user. - * - * Returns the "system IRQ" for the PCI INTA#..INTD# pin in irq_pin. Returns - * 0xff if not assigned. - */ -static uint8_t pcif_bus0_irq_map(pci_dev_t dev, int irq_pin) -{ - uint8_t sysIrqNr = 0; /* not assigned */ - int irq_group; - - if ( (irq_pin >= 1) && (irq_pin <= 4) ) { - /* Use default IRQ decoding on PCI BUS0 according slot numbering */ - irq_group = PCI_DEV_SLOT(dev) & 0x3; - irq_pin = ((irq_pin - 1) + irq_group) & 0x3; - /* Valid PCI "Interrupt Pin" number */ - sysIrqNr = pcif_pci_irq_table[irq_pin]; - } - return sysIrqNr; -} - -static int pcif_translate(uint32_t *address, int type, int dir) -{ - /* No address translation implmented at this point */ - return 0; -} - -extern struct pci_memreg_ops pci_memreg_sparc_be_ops; - -/* PCIF Big-Endian PCI access routines */ -struct pci_access_drv pcif_access_drv = { - .cfg = - { - pcif_cfg_r8, - pcif_cfg_r16, - pcif_cfg_r32, - pcif_cfg_w8, - pcif_cfg_w16, - pcif_cfg_w32, - }, - .io = /* PCIF only supports Big-endian */ - { - _ld8, - _ld_be16, - _ld_be32, - _st8, - _st_be16, - _st_be32, - }, - .memreg = &pci_memreg_sparc_be_ops, - .translate = pcif_translate, -}; - -/* Initializes the PCIF core hardware - * - */ -static int pcif_hw_init(struct pcif_priv *priv) -{ - struct pcif_regs *regs; - uint32_t data, size; - int mst; - pci_dev_t host = HOST_TGT; - - regs = priv->regs; - - /* Mask PCI interrupts */ - regs->intr = 0; - - /* Get the PCIF Host PCI ID */ - pcif_cfg_r32(host, PCIR_VENDOR, &priv->devVend); - - /* set 1:1 mapping between AHB -> PCI memory space, for all Master cores */ - for ( mst=0; mst<16; mst++) { - regs->maps[mst] = priv->pci_area; - - /* Check if this register is implemented */ - if ( regs->maps[mst] != priv->pci_area ) - break; - } - - /* and map system RAM at pci address SYSTEM_MAINMEM_START. This way - * PCI targets can do DMA directly into CPU main memory. - */ - regs->bars[0] = SYSTEM_MAINMEM_START; - regs->bars[1] = 0; - regs->bars[2] = 0; - regs->bars[3] = 0; - - /* determine size of target BAR1 */ - pcif_cfg_w32(host, PCIR_BAR(1), 0xffffffff); - pcif_cfg_r32(host, PCIR_BAR(1), &size); - priv->bar1_size = (~(size & ~0xf)) + 1; - - pcif_cfg_w32(host, PCIR_BAR(0), 0); - pcif_cfg_w32(host, PCIR_BAR(1), SYSTEM_MAINMEM_START); - pcif_cfg_w32(host, PCIR_BAR(2), 0); - pcif_cfg_w32(host, PCIR_BAR(3), 0); - pcif_cfg_w32(host, PCIR_BAR(4), 0); - pcif_cfg_w32(host, PCIR_BAR(5), 0); - - /* set as bus master and enable pci memory responses */ - pcif_cfg_r32(host, PCIR_COMMAND, &data); - data |= (PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); - pcif_cfg_w32(host, PCIR_COMMAND, data); - - /* Successful */ - return 0; -} - -/* Initializes the PCIF core and driver, must be called before calling init_pci() - * - * Return values - * 0 Successful initalization - * -1 Error during initialization, for example "PCI core not found". - * -2 Error PCI controller not HOST (targets not supported) - * -3 Error due to PCIF hardware initialization - * -4 Error registering driver to PCI layer - */ -static int pcif_init(struct pcif_priv *priv) -{ - struct ambapp_apb_info *apb; - struct ambapp_ahb_info *ahb; - int pin; - union drvmgr_key_value *value; - char keyname[6]; - struct amba_dev_info *ainfo = priv->dev->businfo; - - /* Find PCI core from Plug&Play information */ - apb = ainfo->info.apb_slv; - ahb = ainfo->info.ahb_slv; - - /* Found PCI core, init private structure */ - priv->irq = apb->irq; - priv->regs = (struct pcif_regs *)apb->start; - - /* Calculate the PCI windows - * AMBA->PCI Window: AHB SLAVE AREA0 - * AMBA->PCI I/O cycles Window: AHB SLAVE AREA1 Lower half - * AMBA->PCI Configuration cycles Window: AHB SLAVE AREA1 Upper half - */ - priv->pci_area = ahb->start[0]; - priv->pci_area_end = ahb->start[0] + ahb->mask[0]; - priv->pci_io = ahb->start[1]; - priv->pci_conf = ahb->start[1] + (ahb->mask[1] >> 1); - priv->pci_conf_end = ahb->start[1] + ahb->mask[1]; - - /* On systems where PCI I/O area and configuration area is apart of the "PCI Window" - * the PCI Window stops at the start of the PCI I/O area - */ - if ( (priv->pci_io > priv->pci_area) && (priv->pci_io < (priv->pci_area_end-1)) ) { - priv->pci_area_end = priv->pci_io; - } - - /* Init PCI interrupt assignment table to all use the interrupt routed through - * the PCIF core. - */ - strcpy(keyname, "INTX#"); - for (pin=1; pin<5; pin++) { - if ( pcif_pci_irq_table[pin-1] == 0xff ) { - pcif_pci_irq_table[pin-1] = priv->irq; - - /* User may override Plug & Play IRQ */ - keyname[3] = 'A' + (pin-1); - value = drvmgr_dev_key_get(priv->dev, keyname, DRVMGR_KT_INT); - if ( value ) - pcif_pci_irq_table[pin-1] = value->i; - } - } - - priv->irq_mask = 0xf; - value = drvmgr_dev_key_get(priv->dev, "", DRVMGR_KT_INT); - if ( value ) - priv->irq_mask = value->i & 0xf; - - /* This driver only support HOST systems, we check for HOST */ - if ( priv->regs->status & 0x00000001 ) { - /* Target not supported */ - return -2; - } - - /* Init the PCI Core */ - if ( pcif_hw_init(priv) ) { - return -3; - } - - /* Down streams translation table */ - priv->maps_down[0].name = "AMBA -> PCI MEM Window"; - priv->maps_down[0].size = priv->pci_area_end - priv->pci_area; - priv->maps_down[0].from_adr = (void *)priv->pci_area; - priv->maps_down[0].to_adr = (void *)priv->pci_area; - /* End table */ - priv->maps_down[1].size = 0; - - /* Up streams translation table */ - priv->maps_up[0].name = "Target BAR1 -> AMBA"; - priv->maps_up[0].size = priv->bar1_size; - priv->maps_up[0].from_adr = (void *)SYSTEM_MAINMEM_START; - priv->maps_up[0].to_adr = (void *)SYSTEM_MAINMEM_START; - /* End table */ - priv->maps_up[1].size = 0; - - return 0; -} - -/* Called when a core is found with the AMBA device and vendor ID - * given in pcif_ids[]. - */ -int pcif_init1(struct drvmgr_dev *dev) -{ - struct pcif_priv *priv; - struct pci_auto_setup pcif_auto_cfg; - - DBG("PCIF[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name); - - if ( pcif_minor != 0 ) { - printf("Driver only supports one PCI core\n"); - return DRVMGR_FAIL; - } - - priv = dev->priv; - if ( !priv ) - return DRVMGR_NOMEM; - - dev->priv = priv; - priv->dev = dev; - priv->minor = pcif_minor++; - - pcifpriv = priv; - if ( pcif_init(priv) ) { - printf("Failed to initialize PCIF driver\n"); - free(priv); - dev->priv = NULL; - return DRVMGR_FAIL; - } - - /* Host is always Big-Endian */ - pci_endian = PCI_BIG_ENDIAN; - - /* Register the PCI core at the PCI layer */ - - if (pci_access_drv_register(&pcif_access_drv)) { - /* Access routines registration failed */ - return DRVMGR_FAIL; - } - - /* Prepare memory MAP */ - pcif_auto_cfg.options = 0; - pcif_auto_cfg.mem_start = 0; - pcif_auto_cfg.mem_size = 0; - pcif_auto_cfg.memio_start = priv->pci_area; - pcif_auto_cfg.memio_size = priv->pci_area_end - priv->pci_area; - pcif_auto_cfg.io_start = priv->pci_io; - pcif_auto_cfg.io_size = priv->pci_conf - priv->pci_io; - pcif_auto_cfg.irq_map = pcif_bus0_irq_map; - pcif_auto_cfg.irq_route = NULL; /* use standard routing */ - pci_config_register(&pcif_auto_cfg); - - if (pci_config_init()) { - /* PCI configuration failed */ - return DRVMGR_FAIL; - } - - priv->config.maps_down = &priv->maps_down[0]; - priv->config.maps_up = &priv->maps_up[0]; - return pcibus_register(dev, &priv->config); -} - -int pcif_init3(struct drvmgr_dev *dev) -{ - struct pcif_priv *priv = dev->priv; - - /* Unmask all interrupts, on some sytems this - * might be problematic because all PCI IRQs are - * not connected on the PCB or used for something - * else. The irqMask driver resource can be used to - * control which PCI IRQs are used to generate the - * PCI system IRQ, example: - * - * 0xf - enable all (DEFAULT) - * 0x8 - enable one PCI irq - * - * Before unmasking PCI IRQ, all PCI boards must - * have been initialized and IRQ turned off to avoid - * system hang. - */ - - priv->regs->intr = priv->irq_mask; - - return DRVMGR_OK; -} |