diff options
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/pci/grpci.c')
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/pci/grpci.c | 722 |
1 files changed, 0 insertions, 722 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/pci/grpci.c b/c/src/lib/libbsp/sparc/shared/pci/grpci.c deleted file mode 100644 index 047f1c199d..0000000000 --- a/c/src/lib/libbsp/sparc/shared/pci/grpci.c +++ /dev/null @@ -1,722 +0,0 @@ -/* GRLIB GRPCI PCI HOST driver. - * - * COPYRIGHT (c) 2008. - * Cobham Gaisler AB. - * - * Configures the GRPCI 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 <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <rtems/bspIo.h> -#include <libcpu/byteorder.h> -#include <libcpu/access.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/grpci.h> - -#define DMAPCI_ADDR 0x80000500 - -/* Configuration options */ -#define SYSTEM_MAINMEM_START 0x40000000 - -/* If defined to 1 - byte twisting is enabled by default */ -#define DEFAULT_BT_ENABLED 0 - -/* Interrupt assignment. Set to other value than 0xff in order to - * override defaults and plug&play information - */ -#ifndef GRPCI_INTA_SYSIRQ - #define GRPCI_INTA_SYSIRQ 0xff -#endif -#ifndef GRPCI_INTB_SYSIRQ - #define GRPCI_INTB_SYSIRQ 0xff -#endif -#ifndef GRPCI_INTC_SYSIRQ - #define GRPCI_INTC_SYSIRQ 0xff -#endif -#ifndef GRPCI_INTD_SYSIRQ - #define GRPCI_INTD_SYSIRQ 0xff -#endif - -#define PAGE0_BTEN_BIT 0 -#define PAGE0_BTEN (1<<PAGE0_BTEN_BIT) - -#define CFGSTAT_HOST_BIT 13 -#define CFGSTAT_HOST (1<<CFGSTAT_HOST_BIT) - -/*#define DEBUG 1*/ - -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -/* - * Bit encode for PCI_CONFIG_HEADER_TYPE register - */ -struct grpci_regs { - volatile unsigned int cfg_stat; - volatile unsigned int bar0; - volatile unsigned int page0; - volatile unsigned int bar1; - volatile unsigned int page1; - volatile unsigned int iomap; - volatile unsigned int stat_cmd; - volatile unsigned int irq; -}; - -#define HOST_TGT PCI_DEV(0xff, 0, 0) - -struct grpci_priv *grpcipriv = NULL; -static int grpci_minor = 0; -static unsigned int *pcidma = (unsigned int *)DMAPCI_ADDR; - -/* PCI Interrupt assignment. Connects an PCI interrupt pin (INTA#..INTD#) - * to a system interrupt number. - */ -unsigned char grpci_pci_irq_table[4] = -{ - /* INTA# */ GRPCI_INTA_SYSIRQ, - /* INTB# */ GRPCI_INTB_SYSIRQ, - /* INTC# */ GRPCI_INTC_SYSIRQ, - /* INTD# */ GRPCI_INTD_SYSIRQ -}; - -/* Driver private data struture */ -struct grpci_priv { - struct drvmgr_dev *dev; - struct grpci_regs *regs; - int irq; - int minor; - - uint32_t bar1_pci_adr; - uint32_t bar1_size; - - int bt_enabled; - 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 */ - - struct drvmgr_map_entry maps_up[2]; - struct drvmgr_map_entry maps_down[2]; - struct pcibus_config config; -}; - -int grpci_init1(struct drvmgr_dev *dev); - -/* GRPCI DRIVER */ - -struct drvmgr_drv_ops grpci_ops = -{ - .init = {grpci_init1, NULL, NULL, NULL}, - .remove = NULL, - .info = NULL -}; - -struct amba_dev_id grpci_ids[] = -{ - {VENDOR_GAISLER, GAISLER_PCIFBRG}, - {0, 0} /* Mark end of table */ -}; - -struct amba_drv_info grpci_info = -{ - { - DRVMGR_OBJ_DRV, /* Driver */ - NULL, /* Next driver */ - NULL, /* Device list */ - DRIVER_AMBAPP_GAISLER_GRPCI_ID, /* Driver ID */ - "GRPCI_DRV", /* Driver Name */ - DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */ - &grpci_ops, - NULL, /* Funcs */ - 0, /* No devices yet */ - sizeof(struct grpci_priv), /* Make drvmgr alloc private */ - }, - &grpci_ids[0] -}; - -void grpci_register_drv(void) -{ - DBG("Registering GRPCI driver\n"); - drvmgr_drv_register(&grpci_info.general); -} - -static int grpci_cfg_r32(pci_dev_t dev, int ofs, uint32_t *val) -{ - struct grpci_priv *priv = grpcipriv; - 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; - } - - /* GRPCI 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->cfg_stat = (priv->regs->cfg_stat & ~(0xf<<23)) | (bus<<23); - - pci_conf = (volatile uint32_t *)(priv->pci_conf | (devfn << 8) | ofs); - - if (priv->bt_enabled) { - *val = CPU_swap_u32(*pci_conf); - } else { - *val = *pci_conf; - } - - if (priv->regs->cfg_stat & 0x100) { - *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 grpci_cfg_r16(pci_dev_t dev, int ofs, uint16_t *val) -{ - uint32_t v; - int retval; - - if (ofs & 1) - return PCISTS_EINVAL; - - retval = grpci_cfg_r32(dev, ofs & ~0x3, &v); - *val = 0xffff & (v >> (8*(ofs & 0x3))); - - return retval; -} - -static int grpci_cfg_r8(pci_dev_t dev, int ofs, uint8_t *val) -{ - uint32_t v; - int retval; - - retval = grpci_cfg_r32(dev, ofs & ~0x3, &v); - - *val = 0xff & (v >> (8*(ofs & 3))); - - return retval; -} - -static int grpci_cfg_w32(pci_dev_t dev, int ofs, uint32_t val) -{ - struct grpci_priv *priv = grpcipriv; - volatile uint32_t *pci_conf; - uint32_t value, devfn = PCI_DEV_DEVFUNC(dev); - int bus = PCI_DEV_BUS(dev); - - if (ofs & 0x3) - return PCISTS_EINVAL; - - if (PCI_DEV_SLOT(dev) > 15) - return PCISTS_MSTABRT; - - /* GRPCI 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->cfg_stat = (priv->regs->cfg_stat & ~(0xf<<23)) | (bus<<23); - - pci_conf = (volatile uint32_t *)(priv->pci_conf | (devfn << 8) | ofs); - - if ( priv->bt_enabled ) { - value = CPU_swap_u32(val); - } else { - value = val; - } - - *pci_conf = value; - - 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 grpci_cfg_w16(pci_dev_t dev, int ofs, uint16_t val) -{ - uint32_t v; - int retval; - - if (ofs & 1) - return PCISTS_EINVAL; - - retval = grpci_cfg_r32(dev, ofs & ~0x3, &v); - if (retval != PCISTS_OK) - return retval; - - v = (v & ~(0xffff << (8*(ofs&3)))) | ((0xffff&val) << (8*(ofs&3))); - - return grpci_cfg_w32(dev, ofs & ~0x3, v); -} - -static int grpci_cfg_w8(pci_dev_t dev, int ofs, uint8_t val) -{ - uint32_t v; - int retval; - - retval = grpci_cfg_r32(dev, ofs & ~0x3, &v); - if (retval != PCISTS_OK) - return retval; - - v = (v & ~(0xff << (8*(ofs&3)))) | ((0xff&val) << (8*(ofs&3))); - - return grpci_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 grpci_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 grpci_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 = grpci_pci_irq_table[irq_pin]; - } - return sysIrqNr; -} - -static int grpci_translate(uint32_t *address, int type, int dir) -{ - uint32_t adr; - struct grpci_priv *priv = grpcipriv; - - if (type == 1) { - /* I/O */ - if (dir != 0) { - /* The PCI bus can not access the CPU bus from I/O - * because GRPCI core does not support I/O BARs - */ - return -1; - } - - /* We have got a PCI BAR address that the CPU want to access... - * Check that it is within the PCI I/O window, I/O adresses - * are mapped 1:1 with GRPCI driver... no translation needed. - */ - adr = *(uint32_t *)address; - if (adr < priv->pci_io || adr >= priv->pci_conf) - return -1; - } else { - /* MEMIO and MEM. - * Memory space is mapped 1:1 so no translation is needed. - * Check that address is within accessible windows. - */ - adr = *(uint32_t *)address; - if (dir == 0) { - /* PCI BAR to AMBA-CPU address.. check that it is - * located within GRPCI PCI Memory Window - * adr = PCI address. - */ - if (adr < priv->pci_area || adr >= priv->pci_area_end) - return -1; - } else { - /* We have a CPU address and want to get access to it - * from PCI space, typically when doing DMA into CPU - * RAM. The GRPCI core has two target BARs that PCI - * masters can access, we check here that the address - * is accessible from PCI. - * adr = AMBA address. - */ - if (adr < priv->bar1_pci_adr || - adr >= (priv->bar1_pci_adr + priv->bar1_size)) - return -1; - } - } - - return 0; -} - -extern struct pci_memreg_ops pci_memreg_sparc_le_ops; -extern struct pci_memreg_ops pci_memreg_sparc_be_ops; - -/* GRPCI PCI access routines, default to Little-endian PCI Bus */ -struct pci_access_drv grpci_access_drv = { - .cfg = - { - grpci_cfg_r8, - grpci_cfg_r16, - grpci_cfg_r32, - grpci_cfg_w8, - grpci_cfg_w16, - grpci_cfg_w32, - }, - .io = - { - _ld8, - _ld_le16, - _ld_le32, - _st8, - _st_le16, - _st_le32, - }, - .memreg = &pci_memreg_sparc_le_ops, - .translate = grpci_translate, -}; - -struct pci_io_ops grpci_io_ops_be = -{ - _ld8, - _ld_be16, - _ld_be32, - _st8, - _st_be16, - _st_be32, -}; - -static int grpci_hw_init(struct grpci_priv *priv) -{ - volatile unsigned int *mbar0, *page0; - uint32_t data, addr, mbar0size; - pci_dev_t host = HOST_TGT; - - mbar0 = (volatile unsigned int *)priv->pci_area; - - if ( !priv->bt_enabled && ((priv->regs->page0 & PAGE0_BTEN) == PAGE0_BTEN) ) { - /* Byte twisting is on, turn it off */ - grpci_cfg_w32(host, PCIR_BAR(0), 0xffffffff); - grpci_cfg_r32(host, PCIR_BAR(0), &addr); - /* Setup bar0 to nonzero value */ - grpci_cfg_w32(host, PCIR_BAR(0), - CPU_swap_u32(0x80000000)); - /* page0 is accessed through upper half of bar0 */ - addr = (~CPU_swap_u32(addr)+1)>>1; - mbar0size = addr*2; - DBG("GRPCI: Size of MBAR0: 0x%x, MBAR0: 0x%x(lower) 0x%x(upper)\n",mbar0size,((unsigned int)mbar0),((unsigned int)mbar0)+mbar0size/2); - page0 = &mbar0[mbar0size/8]; - DBG("GRPCI: PAGE0 reg address: 0x%x (0x%x)\n",((unsigned int)mbar0)+mbar0size/2,page0); - priv->regs->cfg_stat = (priv->regs->cfg_stat & (~0xf0000000)) | 0x80000000; /* Setup mmap reg so we can reach bar0 */ - *page0 = 0<<PAGE0_BTEN_BIT; /* Disable bytetwisting ... */ - } - - /* Get the GRPCI Host PCI ID */ - grpci_cfg_r32(host, PCIR_VENDOR, &priv->devVend); - - /* set 1:1 mapping between AHB -> PCI memory */ - priv->regs->cfg_stat = (priv->regs->cfg_stat & 0x0fffffff) | priv->pci_area; - - /* determine size of target BAR1 */ - grpci_cfg_w32(host, PCIR_BAR(1), 0xffffffff); - grpci_cfg_r32(host, PCIR_BAR(1), &addr); - priv->bar1_size = (~(addr & ~0xf)) + 1; - - /* and map system RAM at pci address 0x40000000 */ - priv->bar1_pci_adr &= ~(priv->bar1_size - 1); /* Fix alignment of BAR1 */ - grpci_cfg_w32(host, PCIR_BAR(1), priv->bar1_pci_adr); - priv->regs->page1 = priv->bar1_pci_adr; - - /* Translate I/O accesses 1:1 */ - priv->regs->iomap = priv->pci_io & 0xffff0000; - - /* Setup Latency Timer and cache line size. Default cache line - * size will result in poor performance (256 word fetches), 0xff - * will set it according to the max size of the PCI FIFO. - */ - grpci_cfg_w8(host, PCIR_CACHELNSZ, 0xff); - grpci_cfg_w8(host, PCIR_LATTIMER, 0x40); - - /* set as bus master and enable pci memory responses */ - grpci_cfg_r32(host, PCIR_COMMAND, &data); - data |= (PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); - grpci_cfg_w32(host, PCIR_COMMAND, data); - - /* unmask all PCI interrupts at PCI Core, not all GRPCI cores support - * this - */ - priv->regs->irq = 0xf0000; - - /* Successful */ - return 0; -} - -/* Initializes the GRPCI 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 GRPCI hardware initialization - * -4 Error registering driver to PCI layer - */ -static int grpci_init(struct grpci_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 grpci_regs *)apb->start; - priv->bt_enabled = DEFAULT_BT_ENABLED; - - /* 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 GRPCI core. - */ - strcpy(keyname, "INTX#"); - for (pin=1; pin<5; pin++) { - if ( grpci_pci_irq_table[pin-1] == 0xff ) { - grpci_pci_irq_table[pin-1] = priv->irq; - - /* User may override Both hardcoded IRQ setup and Plug & Play IRQ */ - keyname[3] = 'A' + (pin-1); - value = drvmgr_dev_key_get(priv->dev, keyname, DRVMGR_KT_INT); - if ( value ) - grpci_pci_irq_table[pin-1] = value->i; - } - } - - /* User may override DEFAULT_BT_ENABLED to enable/disable byte twisting */ - value = drvmgr_dev_key_get(priv->dev, "byteTwisting", DRVMGR_KT_INT); - if ( value ) - priv->bt_enabled = value->i; - - /* Use GRPCI target BAR1 to map CPU RAM to PCI, this is to make it - * possible for PCI peripherals to do DMA directly to CPU memory. - */ - value = drvmgr_dev_key_get(priv->dev, "tgtbar1", DRVMGR_KT_INT); - if (value) - priv->bar1_pci_adr = value->i; - else - priv->bar1_pci_adr = SYSTEM_MAINMEM_START; /* default */ - - /* This driver only support HOST systems, we check for HOST */ - if ( !(priv->regs->cfg_stat & CFGSTAT_HOST) ) { - /* Target not supported */ - return -2; - } - - /* Init the PCI Core */ - if ( grpci_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 *)priv->bar1_pci_adr; - priv->maps_up[0].to_adr = (void *)priv->bar1_pci_adr; - /* 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 grpci_ids[]. IRQ, Console does not work here - */ -int grpci_init1(struct drvmgr_dev *dev) -{ - int status; - struct grpci_priv *priv; - struct pci_auto_setup grpci_auto_cfg; - - DBG("GRPCI[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name); - - if ( grpci_minor != 0 ) { - DBG("Driver only supports one PCI core\n"); - return DRVMGR_FAIL; - } - - if ( (strcmp(dev->parent->dev->drv->name, "AMBAPP_GRLIB_DRV") != 0) && - (strcmp(dev->parent->dev->drv->name, "AMBAPP_LEON2_DRV") != 0) ) { - /* We only support GRPCI driver on local bus */ - return DRVMGR_FAIL; - } - - priv = dev->priv; - if ( !priv ) - return DRVMGR_NOMEM; - - priv->dev = dev; - priv->minor = grpci_minor++; - - grpcipriv = priv; - status = grpci_init(priv); - if (status) { - printf("Failed to initialize grpci driver %d\n", status); - return DRVMGR_FAIL; - } - - - /* Register the PCI core at the PCI layers */ - - if (priv->bt_enabled == 0) { - /* Host is Big-Endian */ - pci_endian = PCI_BIG_ENDIAN; - - memcpy(&grpci_access_drv.io, &grpci_io_ops_be, - sizeof(grpci_io_ops_be)); - grpci_access_drv.memreg = &pci_memreg_sparc_be_ops; - } - - if (pci_access_drv_register(&grpci_access_drv)) { - /* Access routines registration failed */ - return DRVMGR_FAIL; - } - - /* Prepare memory MAP */ - grpci_auto_cfg.options = 0; - grpci_auto_cfg.mem_start = 0; - grpci_auto_cfg.mem_size = 0; - grpci_auto_cfg.memio_start = priv->pci_area; - grpci_auto_cfg.memio_size = priv->pci_area_end - priv->pci_area; - grpci_auto_cfg.io_start = priv->pci_io; - grpci_auto_cfg.io_size = priv->pci_conf - priv->pci_io; - grpci_auto_cfg.irq_map = grpci_bus0_irq_map; - grpci_auto_cfg.irq_route = NULL; /* use standard routing */ - pci_config_register(&grpci_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); -} - -/* DMA functions which uses GRPCIs optional DMA controller (len in words) */ -int grpci_dma_to_pci( - unsigned int ahb_addr, - unsigned int pci_addr, - unsigned int len) -{ - int ret = 0; - - pcidma[0] = 0x82; - pcidma[1] = ahb_addr; - pcidma[2] = pci_addr; - pcidma[3] = len; - pcidma[0] = 0x83; - - while ( (pcidma[0] & 0x4) == 0) - ; - - if (pcidma[0] & 0x8) { /* error */ - ret = -1; - } - - pcidma[0] |= 0xC; - return ret; - -} - -int grpci_dma_from_pci( - unsigned int ahb_addr, - unsigned int pci_addr, - unsigned int len) -{ - int ret = 0; - - pcidma[0] = 0x80; - pcidma[1] = ahb_addr; - pcidma[2] = pci_addr; - pcidma[3] = len; - pcidma[0] = 0x81; - - while ( (pcidma[0] & 0x4) == 0) - ; - - if (pcidma[0] & 0x8) { /* error */ - ret = -1; - } - - pcidma[0] |= 0xC; - return ret; - -} |