diff options
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/pci/grpci2.c')
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/pci/grpci2.c | 1000 |
1 files changed, 0 insertions, 1000 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/pci/grpci2.c b/c/src/lib/libbsp/sparc/shared/pci/grpci2.c deleted file mode 100644 index 2d8e1521f7..0000000000 --- a/c/src/lib/libbsp/sparc/shared/pci/grpci2.c +++ /dev/null @@ -1,1000 +0,0 @@ -/* GRLIB GRPCI2 PCI HOST driver. - * - * COPYRIGHT (c) 2011 - * Cobham Gaisler AB. - * - * 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. - */ - -/* Configures the GRPCI2 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#. GRPCI2 handles differently depending - * on the design (4 different ways). - * - * GRPCI2 IRQ implementation notes - * ------------------------------- - * Since the Driver Manager pci_bus layer implements IRQ by calling - * pci_interrupt_* which translates into BSP_shared_interrupt_*, and the - * root-bus also relies on BSP_shared_interrupt_*, it is safe for the GRPCI2 - * driver to use the drvmgr_interrupt_* routines since they will be - * accessing the same routines in the end. Otherwise the GRPCI2 driver must - * have used the pci_interrupt_* routines. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <rtems.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/grpci2.h> - -/* Use interrupt lock privmitives compatible with SMP defined in - * RTEMS 4.11.99 and higher. - */ -#if (((__RTEMS_MAJOR__ << 16) | (__RTEMS_MINOR__ << 8) | __RTEMS_REVISION__) >= 0x040b63) - -/* map via rtems_interrupt_lock_* API: */ -#define SPIN_DECLARE(lock) RTEMS_INTERRUPT_LOCK_MEMBER(lock) -#define SPIN_INIT(lock, name) rtems_interrupt_lock_initialize(lock, name) -#define SPIN_LOCK(lock, level) rtems_interrupt_lock_acquire_isr(lock, &level) -#define SPIN_LOCK_IRQ(lock, level) rtems_interrupt_lock_acquire(lock, &level) -#define SPIN_UNLOCK(lock, level) rtems_interrupt_lock_release_isr(lock, &level) -#define SPIN_UNLOCK_IRQ(lock, level) rtems_interrupt_lock_release(lock, &level) -#define SPIN_IRQFLAGS(k) rtems_interrupt_lock_context k -#define SPIN_ISR_IRQFLAGS(k) SPIN_IRQFLAGS(k) - -#else - -/* maintain single-core compatibility with older versions of RTEMS: */ -#define SPIN_DECLARE(name) -#define SPIN_INIT(lock, name) -#define SPIN_LOCK(lock, level) -#define SPIN_LOCK_IRQ(lock, level) rtems_interrupt_disable(level) -#define SPIN_UNLOCK(lock, level) -#define SPIN_UNLOCK_IRQ(lock, level) rtems_interrupt_enable(level) -#define SPIN_IRQFLAGS(k) rtems_interrupt_level k -#define SPIN_ISR_IRQFLAGS(k) - -#ifdef RTEMS_SMP -#error SMP mode not compatible with these interrupt lock primitives -#endif -#endif - -/* If defined to 1 - byte twisting is enabled by default */ -#define DEFAULT_BT_ENABLED 0 - -/* If defined to 64 - Latency timer is 64 by default */ -#define DEFAULT_LATENCY_TIMER 64 - -/* Interrupt assignment. Set to other value than 0xff in order to - * override defaults and plug&play information - */ -#ifndef GRPCI2_INTA_SYSIRQ - #define GRPCI2_INTA_SYSIRQ 0xff -#endif -#ifndef GRPCI2_INTB_SYSIRQ - #define GRPCI2_INTB_SYSIRQ 0xff -#endif -#ifndef GRPCI2_INTC_SYSIRQ - #define GRPCI2_INTC_SYSIRQ 0xff -#endif -#ifndef GRPCI2_INTD_SYSIRQ - #define GRPCI2_INTD_SYSIRQ 0xff -#endif - -/*#define DEBUG 1*/ - -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -/* - * GRPCI2 APB Register MAP - */ -struct grpci2_regs { - volatile unsigned int ctrl; /* 0x00 */ - volatile unsigned int sts_cap; /* 0x04 */ - volatile unsigned int ppref; /* 0x08 */ - volatile unsigned int io_map; /* 0x0C */ - volatile unsigned int dma_ctrl; /* 0x10 */ - volatile unsigned int dma_bdbase; /* 0x14 */ - volatile unsigned int dma_chact; /* 0x18 */ - int res1; /* 0x1C */ - volatile unsigned int bars[6]; /* 0x20 */ - int res2[2]; /* 0x38 */ - volatile unsigned int ahbmst_map[16]; /* 0x40 */ -}; - -#define CTRL_BUS_BIT 16 - -#define CTRL_SI (1<<27) -#define CTRL_PE (1<<26) -#define CTRL_ER (1<<25) -#define CTRL_EI (1<<24) -#define CTRL_BUS (0xff<<CTRL_BUS_BIT) -#define CTRL_HOSTINT 0xf - -#define STS_HOST_BIT 31 -#define STS_MST_BIT 30 -#define STS_TAR_BIT 29 -#define STS_DMA_BIT 28 -#define STS_DI_BIT 27 -#define STS_HI_BIT 26 -#define STS_IRQMODE_BIT 24 -#define STS_TRACE_BIT 23 -#define STS_CFGERRVALID_BIT 20 -#define STS_CFGERR_BIT 19 -#define STS_INTTYPE_BIT 12 -#define STS_INTSTS_BIT 8 -#define STS_FDEPTH_BIT 2 -#define STS_FNUM_BIT 0 - -#define STS_HOST (1<<STS_HOST_BIT) -#define STS_MST (1<<STS_MST_BIT) -#define STS_TAR (1<<STS_TAR_BIT) -#define STS_DMA (1<<STS_DMA_BIT) -#define STS_DI (1<<STS_DI_BIT) -#define STS_HI (1<<STS_HI_BIT) -#define STS_IRQMODE (0x3<<STS_IRQMODE_BIT) -#define STS_TRACE (1<<STS_TRACE_BIT) -#define STS_CFGERRVALID (1<<STS_CFGERRVALID_BIT) -#define STS_CFGERR (1<<STS_CFGERR_BIT) -#define STS_INTTYPE (0x7f<<STS_INTTYPE_BIT) -#define STS_INTSTS (0xf<<STS_INTSTS_BIT) -#define STS_FDEPTH (0x7<<STS_FDEPTH_BIT) -#define STS_FNUM (0x3<<STS_FNUM_BIT) - -#define STS_ITIMEOUT (1<<18) -#define STS_ISYSERR (1<<17) -#define STS_IDMA (1<<16) -#define STS_IDMAERR (1<<15) -#define STS_IMSTABRT (1<<14) -#define STS_ITGTABRT (1<<13) -#define STS_IPARERR (1<<12) - -/* GRPCI2 Capability */ -struct grpci2_cap_first { - unsigned int ctrl; - unsigned int pci2ahb_map[6]; - unsigned int ext2ahb_map; - unsigned int io_map; - unsigned int pcibar_size[6]; - unsigned int ahb_pref; -}; -#define CAP9_CTRL_OFS 0 -#define CAP9_BAR_OFS 0x4 -#define CAP9_IOMAP_OFS 0x20 -#define CAP9_BARSIZE_OFS 0x24 -#define CAP9_AHBPREF_OFS 0x3C - -/* Used internally for accessing the PCI bridge's configuration space itself */ -#define HOST_TGT PCI_DEV(0xff, 0, 0) - -struct grpci2_priv *grpci2priv = NULL; - -/* PCI Interrupt assignment. Connects an PCI interrupt pin (INTA#..INTD#) - * to a system interrupt number. - */ -unsigned char grpci2_pci_irq_table[4] = -{ - /* INTA# */ GRPCI2_INTA_SYSIRQ, - /* INTB# */ GRPCI2_INTB_SYSIRQ, - /* INTC# */ GRPCI2_INTC_SYSIRQ, - /* INTD# */ GRPCI2_INTD_SYSIRQ -}; - -/* Start of workspace/dynamical area */ -extern unsigned int _end; -#define DMA_START ((unsigned int) &_end) - -/* Default BAR mapping, set BAR0 256MB 1:1 mapped base of CPU RAM */ -struct grpci2_pcibar_cfg grpci2_default_bar_mapping[6] = { - /* BAR0 */ {DMA_START, DMA_START, 0x10000000}, - /* BAR1 */ {0, 0, 0}, - /* BAR2 */ {0, 0, 0}, - /* BAR3 */ {0, 0, 0}, - /* BAR4 */ {0, 0, 0}, - /* BAR5 */ {0, 0, 0}, -}; - -/* Driver private data struture */ -struct grpci2_priv { - struct drvmgr_dev *dev; - struct grpci2_regs *regs; - unsigned char ver; - char irq; - char irq_mode; /* IRQ Mode from CAPSTS REG */ - char irq_dma; /* IRQ Index for DMA */ - char bt_enabled; - unsigned int irq_mask; - unsigned int latency_timer; - - struct grpci2_pcibar_cfg *barcfg; - - 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 Device/Vendor ID */ - - struct drvmgr_map_entry maps_up[7]; - struct drvmgr_map_entry maps_down[2]; - struct pcibus_config config; - - /* DMA interrupts */ - void (*dma_isr)(void *data); - void *dma_isr_arg; - - SPIN_DECLARE(devlock) -}; - -int grpci2_init1(struct drvmgr_dev *dev); -int grpci2_init3(struct drvmgr_dev *dev); -void grpci2_err_isr(void *arg); -void grpci2_dma_isr(void *arg); - -/* GRPCI2 DRIVER */ - -struct drvmgr_drv_ops grpci2_ops = -{ - .init = {grpci2_init1, NULL, grpci2_init3, NULL}, - .remove = NULL, - .info = NULL -}; - -struct amba_dev_id grpci2_ids[] = -{ - {VENDOR_GAISLER, GAISLER_GRPCI2}, - {0, 0} /* Mark end of table */ -}; - -struct amba_drv_info grpci2_info = -{ - { - DRVMGR_OBJ_DRV, /* Driver */ - NULL, /* Next driver */ - NULL, /* Device list */ - DRIVER_AMBAPP_GAISLER_GRPCI2_ID,/* Driver ID */ - "GRPCI2_DRV", /* Driver Name */ - DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */ - &grpci2_ops, - NULL, /* Funcs */ - 0, /* No devices yet */ - sizeof(struct grpci2_priv), /* Make drvmgr alloc private */ - }, - &grpci2_ids[0] -}; - -/* Defaults to do nothing - user can override this function - * by including the DMA DRIVER. - */ -int __attribute__((weak)) grpci2dma_init(void * regs, void isr_register( void (*isr)(void *), void * arg)); - -int grpci2dma_init(void * regs, void isr_register( void (*isr)(void *), void * arg)) -{ - return 0; -} - -/* Prototype of grpci2_dma_isr_register function */ -static void grpci2_dma_isr_register( void (*isr)(void *), void * arg); - -void grpci2_register_drv(void) -{ - DBG("Registering GRPCI2 driver\n"); - drvmgr_drv_register(&grpci2_info.general); -} - -static int grpci2_cfg_r32(pci_dev_t dev, int ofs, uint32_t *val) -{ - struct grpci2_priv *priv = grpci2priv; - volatile uint32_t *pci_conf; - unsigned int tmp, devfn; - int retval, bus = PCI_DEV_BUS(dev); - SPIN_IRQFLAGS(irqflags); - - if ((unsigned int)ofs & 0xffffff03) { - retval = PCISTS_EINVAL; - goto out2; - } - - if (PCI_DEV_SLOT(dev) > 15) { - retval = PCISTS_MSTABRT; - goto out; - } - - /* GRPCI2 can access "non-standard" devices on bus0 (on AD11.AD16), - * 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); - - pci_conf = (volatile uint32_t *) (priv->pci_conf | (devfn << 8) | ofs); - - SPIN_LOCK_IRQ(&priv->devlock, irqflags); - - /* Select bus */ - priv->regs->ctrl = (priv->regs->ctrl & ~(0xff<<16)) | (bus<<16); - /* clear old status */ - priv->regs->sts_cap = (STS_CFGERR | STS_CFGERRVALID); - - tmp = *pci_conf; - - /* Wait until GRPCI2 signals that CFG access is done, it should be - * done instantaneously unless a DMA operation is ongoing... - */ - while ((priv->regs->sts_cap & STS_CFGERRVALID) == 0) - ; - - if (priv->regs->sts_cap & STS_CFGERR) { - retval = PCISTS_MSTABRT; - } else { - /* Bus always little endian (unaffected by byte-swapping) */ - *val = CPU_swap_u32(tmp); - retval = PCISTS_OK; - } - - SPIN_UNLOCK_IRQ(&priv->devlock, irqflags); - -out: - if (retval != PCISTS_OK) - *val = 0xffffffff; - - DBG("pci_read: [%x:%x:%x] reg: 0x%x => addr: 0x%x, val: 0x%x (%d)\n", - PCI_DEV_EXPAND(dev), ofs, pci_conf, *val, retval); - -out2: - return retval; -} - -static int grpci2_cfg_r16(pci_dev_t dev, int ofs, uint16_t *val) -{ - uint32_t v; - int retval; - - if (ofs & 1) - return PCISTS_EINVAL; - - retval = grpci2_cfg_r32(dev, ofs & ~0x3, &v); - *val = 0xffff & (v >> (8*(ofs & 0x3))); - - return retval; -} - -static int grpci2_cfg_r8(pci_dev_t dev, int ofs, uint8_t *val) -{ - uint32_t v; - int retval; - - retval = grpci2_cfg_r32(dev, ofs & ~0x3, &v); - - *val = 0xff & (v >> (8*(ofs & 3))); - - return retval; -} - -static int grpci2_cfg_w32(pci_dev_t dev, int ofs, uint32_t val) -{ - struct grpci2_priv *priv = grpci2priv; - volatile uint32_t *pci_conf; - uint32_t value, devfn; - int retval, bus = PCI_DEV_BUS(dev); - SPIN_IRQFLAGS(irqflags); - - if ((unsigned int)ofs & 0xffffff03) - return PCISTS_EINVAL; - - if (PCI_DEV_SLOT(dev) > 15) - return PCISTS_MSTABRT; - - value = CPU_swap_u32(val); - - /* GRPCI2 can access "non-standard" devices on bus0 (on AD11.AD16), - * 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); - - pci_conf = (volatile uint32_t *) (priv->pci_conf | (devfn << 8) | ofs); - - SPIN_LOCK_IRQ(&priv->devlock, irqflags); - - /* Select bus */ - priv->regs->ctrl = (priv->regs->ctrl & ~(0xff<<16)) | (bus<<16); - /* clear old status */ - priv->regs->sts_cap = (STS_CFGERR | STS_CFGERRVALID); - - *pci_conf = value; - - /* Wait until GRPCI2 signals that CFG access is done, it should be - * done instantaneously unless a DMA operation is ongoing... - */ - while ((priv->regs->sts_cap & STS_CFGERRVALID) == 0) - ; - - if (priv->regs->sts_cap & STS_CFGERR) - retval = PCISTS_MSTABRT; - else - retval = PCISTS_OK; - - SPIN_UNLOCK_IRQ(&priv->devlock, irqflags); - - DBG("pci_write - [%x:%x:%x] reg: 0x%x => addr: 0x%x, val: 0x%x (%d)\n", - PCI_DEV_EXPAND(dev), ofs, pci_conf, value, retval); - - return retval; -} - -static int grpci2_cfg_w16(pci_dev_t dev, int ofs, uint16_t val) -{ - uint32_t v; - int retval; - - if (ofs & 1) - return PCISTS_EINVAL; - - retval = grpci2_cfg_r32(dev, ofs & ~0x3, &v); - if (retval != PCISTS_OK) - return retval; - - v = (v & ~(0xffff << (8*(ofs&3)))) | ((0xffff&val) << (8*(ofs&3))); - - return grpci2_cfg_w32(dev, ofs & ~0x3, v); -} - -static int grpci2_cfg_w8(pci_dev_t dev, int ofs, uint8_t val) -{ - uint32_t v; - int retval; - - retval = grpci2_cfg_r32(dev, ofs & ~0x3, &v); - if (retval != PCISTS_OK) - return retval; - - v = (v & ~(0xff << (8*(ofs&3)))) | ((0xff&val) << (8*(ofs&3))); - - return grpci2_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 grpci2_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 grpci2_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 = grpci2_pci_irq_table[irq_pin]; - } - return sysIrqNr; -} - -static int grpci2_translate(uint32_t *address, int type, int dir) -{ - uint32_t adr, start, end; - struct grpci2_priv *priv = grpci2priv; - int i; - - if (type == 1) { - /* I/O */ - if (dir != 0) { - /* The PCI bus can not access the CPU bus from I/O - * because GRPCI2 core does not support I/O BARs - */ - return -1; - } - - /* We have got a PCI IO BAR address that the CPU want to access. - * Check that it is within the PCI I/O window, I/O adresses - * are NOT mapped 1:1 with GRPCI2 driver... translation needed. - */ - adr = *(uint32_t *)address; - if (adr < 0x100 || adr > 0x10000) - return -1; - *address = adr + priv->pci_io; - } 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 GRPCI2 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 GRPCI2 core may have multiple target BARs - * that PCI masters can access, the BARs are user - * configurable in the following ways: - * BAR_SIZE, PCI_BAR Address and MAPPING (AMBA ADR) - * - * The below code tries to find a BAR for which the - * AMBA bar may have been mapped onto, and translate - * the AMBA-CPU address into a PCI address using the - * given mapping. - * - * adr = AMBA address. - */ - for(i=0; i<6; i++) { - start = priv->barcfg[i].ahbadr; - end = priv->barcfg[i].ahbadr + - priv->barcfg[i].barsize; - if (adr >= start && adr < end) { - /* BAR match: Translate address */ - *address = (adr - start) + - priv->barcfg[i].pciadr; - return 0; - } - } - return -1; - } - } - - return 0; -} - -extern struct pci_memreg_ops pci_memreg_sparc_le_ops; -extern struct pci_memreg_ops pci_memreg_sparc_be_ops; - -/* GRPCI2 PCI access routines, default to Little-endian PCI Bus */ -struct pci_access_drv grpci2_access_drv = { - .cfg = - { - grpci2_cfg_r8, - grpci2_cfg_r16, - grpci2_cfg_r32, - grpci2_cfg_w8, - grpci2_cfg_w16, - grpci2_cfg_w32, - }, - .io = - { - _ld8, - _ld_le16, - _ld_le32, - _st8, - _st_le16, - _st_le32, - }, - .memreg = &pci_memreg_sparc_le_ops, - .translate = grpci2_translate, -}; - -struct pci_io_ops grpci2_io_ops_be = -{ - _ld8, - _ld_be16, - _ld_be32, - _st8, - _st_be16, - _st_be32, -}; - -/* PCI Error Interrupt handler, called when there may be a PCI Target/Master - * Abort. - */ -void grpci2_err_isr(void *arg) -{ - struct grpci2_priv *priv = arg; - unsigned int sts = priv->regs->sts_cap; - - if (sts & (STS_IMSTABRT | STS_ITGTABRT | STS_IPARERR | STS_ISYSERR | STS_ITIMEOUT)) { - /* A PCI error IRQ ... Error handler unimplemented - * add your code here... - */ - if (sts & STS_IMSTABRT) { - printk("GRPCI2: unhandled Master Abort IRQ\n"); - } - if (sts & STS_ITGTABRT) { - printk("GRPCI2: unhandled Target Abort IRQ\n"); - } - if (sts & STS_IPARERR) { - printk("GRPCI2: unhandled Parity Error IRQ\n"); - } - if (sts & STS_ISYSERR) { - printk("GRPCI2: unhandled System Error IRQ\n"); - } - if (sts & STS_ITIMEOUT) { - printk("GRPCI2: unhandled PCI target access timeout IRQ\n"); - } - } -} - -/* PCI DMA Interrupt handler, called when there may be a PCI DMA interrupt. - */ -void grpci2_dma_isr(void *arg) -{ - struct grpci2_priv *priv = arg; - unsigned int sts = (priv->regs->sts_cap & (STS_IDMAERR | STS_IDMA)); - - /* Clear Interrupt if taken*/ - if (sts != 0){ - /* Clear IDMAERR and IDMA bits */ - priv->regs->sts_cap = (STS_IDMAERR | STS_IDMA); - /* Clear DRVMGR interrupt */ - drvmgr_interrupt_clear(priv->dev, priv->irq_dma); - /* Call DMA driver ISR */ - (priv->dma_isr)(priv->dma_isr_arg); - } -} - -static int grpci2_hw_init(struct grpci2_priv *priv) -{ - struct grpci2_regs *regs = priv->regs; - int i; - uint8_t capptr; - uint32_t data, io_map, ahbadr, pciadr, size; - pci_dev_t host = HOST_TGT; - struct grpci2_pcibar_cfg *barcfg = priv->barcfg; - - /* Reset any earlier setup */ - regs->ctrl = 0; - regs->sts_cap = ~0; /* Clear Status */ - regs->dma_ctrl = 0; - regs->dma_bdbase = 0; - - /* Translate I/O accesses 1:1, (will not work for PCI 2.3) */ - regs->io_map = priv->pci_io & 0xffff0000; - - /* set 1:1 mapping between AHB -> PCI memory space, for all Masters - * Each AHB master has it's own mapping registers. Max 16 AHB masters. - */ - for (i=0; i<16; i++) - regs->ahbmst_map[i] = priv->pci_area; - - /* Get the GRPCI2 Host PCI ID */ - grpci2_cfg_r32(host, PCIR_VENDOR, &priv->devVend); - - /* Get address to first (always defined) capability structure */ - grpci2_cfg_r8(host, PCIR_CAP_PTR, &capptr); - if (capptr == 0) - return -1; - - /* Limit the prefetch for GRPCI2 version 0. */ - if (priv->ver == 0) - grpci2_cfg_w32(host, capptr+CAP9_AHBPREF_OFS, 0); - - /* Enable/Disable Byte twisting */ - grpci2_cfg_r32(host, capptr+CAP9_IOMAP_OFS, &io_map); - io_map = (io_map & ~0x1) | (priv->bt_enabled ? 1 : 0); - grpci2_cfg_w32(host, capptr+CAP9_IOMAP_OFS, io_map); - - /* Setup the Host's PCI Target BARs for others to access (DMA) */ - for (i=0; i<6; i++) { - /* Make sure address is properly aligned */ - size = ~(barcfg[i].barsize-1); - barcfg[i].pciadr &= size; - barcfg[i].ahbadr &= size; - - pciadr = barcfg[i].pciadr; - ahbadr = barcfg[i].ahbadr; - size |= PCIM_BAR_MEM_PREFETCH; - - grpci2_cfg_w32(host, capptr+CAP9_BARSIZE_OFS+i*4, size); - grpci2_cfg_w32(host, capptr+CAP9_BAR_OFS+i*4, ahbadr); - grpci2_cfg_w32(host, PCIR_BAR(0)+i*4, pciadr); - } - - /* set as bus master and enable pci memory responses */ - grpci2_cfg_r32(host, PCIR_COMMAND, &data); - data |= (PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); - grpci2_cfg_w32(host, PCIR_COMMAND, data); - - /* set latency timer */ - grpci2_cfg_r32(host, PCIR_CACHELNSZ, &data); - data &= ~0xff00; - data |= ((priv->latency_timer & 0xff) << 8); - grpci2_cfg_w32(host, PCIR_CACHELNSZ, data); - - /* Enable Error respone (CPU-TRAP) on illegal memory access */ - regs->ctrl = CTRL_ER | CTRL_PE; - - /* Successful */ - return 0; -} - -/* Initializes the GRPCI2 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 GRPCI2 hardware initialization - */ -static int grpci2_init(struct grpci2_priv *priv) -{ - struct ambapp_apb_info *apb; - struct ambapp_ahb_info *ahb; - int pin, i, j; - union drvmgr_key_value *value; - char keyname[6]; - struct amba_dev_info *ainfo = priv->dev->businfo; - struct grpci2_pcibar_cfg *barcfg; - unsigned int size; - - /* 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->ver = apb->ver; - priv->regs = (struct grpci2_regs *)apb->start; - priv->bt_enabled = DEFAULT_BT_ENABLED; - priv->irq_mode = (priv->regs->sts_cap & STS_IRQMODE) >> STS_IRQMODE_BIT; - priv->latency_timer = DEFAULT_LATENCY_TIMER; - - /* Initialize Spin-lock for GRPCI2 Device. */ - SPIN_INIT(&priv->devlock, "grpci2"); - - /* 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] + 0x10000; - priv->pci_conf_end = priv->pci_conf + 0x10000; - - /* 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 GRPCI2 core. - */ - strcpy(keyname, "INTX#"); - for (pin=1; pin<5; pin++) { - if (grpci2_pci_irq_table[pin-1] == 0xff) { - if (priv->irq_mode < 2) { - /* PCI Interrupts are shared */ - grpci2_pci_irq_table[pin-1] = priv->irq; - } else { - /* Unique IRQ per PCI INT Pin */ - grpci2_pci_irq_table[pin-1] = priv->irq + pin-1; - } - - /* 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) - grpci2_pci_irq_table[pin-1] = value->i; - } - - /* Remember which IRQs are enabled */ - if (grpci2_pci_irq_table[pin-1] != 0) - priv->irq_mask |= 1 << (pin-1); - } - - /* 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; - - /* Let user Configure the 6 target BARs */ - value = drvmgr_dev_key_get(priv->dev, "tgtBarCfg", DRVMGR_KT_POINTER); - if (value) - priv->barcfg = value->ptr; - else - priv->barcfg = grpci2_default_bar_mapping; - - /* User may override DEFAULT_LATENCY_TIMER */ - value = drvmgr_dev_key_get(priv->dev, "latencyTimer", DRVMGR_KT_INT); - if (value) - priv->latency_timer = value->i; - - /* This driver only support HOST systems, we check that it can act as a - * PCI Master and that it is in the Host slot. */ - if ((priv->regs->sts_cap&STS_HOST) || !(priv->regs->sts_cap&STS_MST)) - return -2; /* Target not supported */ - - /* Init the PCI Core */ - if (grpci2_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 */ - /* Setup the Host's PCI Target BARs for others to access (DMA) */ - barcfg = priv->barcfg; - for (i=0,j=0; i<6; i++) { - size = barcfg[i].barsize; - if (size == 0) - continue; - - /* Make sure address is properly aligned */ - priv->maps_up[j].name = "Target BAR[I] -> AMBA"; - priv->maps_up[j].size = size; - priv->maps_up[j].from_adr = (void *) - (barcfg[i].pciadr & ~(size - 1)); - priv->maps_up[j].to_adr = (void *) - (barcfg[i].ahbadr & ~(size - 1)); - j++; - } - - /* End table */ - priv->maps_up[j].size = 0; - - return 0; -} - -/* Called when a core is found with the AMBA device and vendor ID - * given in grpci2_ids[]. IRQ, Console does not work here - */ -int grpci2_init1(struct drvmgr_dev *dev) -{ - int status; - struct grpci2_priv *priv; - struct pci_auto_setup grpci2_auto_cfg; - - DBG("GRPCI2[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name); - - if (grpci2priv) { - 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 GRPCI2 driver on local bus */ - return DRVMGR_FAIL; - } - - priv = dev->priv; - if (!priv) - return DRVMGR_NOMEM; - - priv->dev = dev; - grpci2priv = priv; - - /* Initialize GRPCI2 Hardware */ - status = grpci2_init(priv); - if (status) { - printf("Failed to initialize grpci2 driver %d\n", status); - return -1; - } - - /* Register the PCI core at the PCI layers */ - - if (priv->bt_enabled == 0) { - /* Host is Big-Endian */ - pci_endian = PCI_BIG_ENDIAN; - - memcpy(&grpci2_access_drv.io, &grpci2_io_ops_be, - sizeof(grpci2_io_ops_be)); - grpci2_access_drv.memreg = &pci_memreg_sparc_be_ops; - } - - if (pci_access_drv_register(&grpci2_access_drv)) { - /* Access routines registration failed */ - return DRVMGR_FAIL; - } - - /* Prepare memory MAP */ - grpci2_auto_cfg.options = 0; - grpci2_auto_cfg.mem_start = 0; - grpci2_auto_cfg.mem_size = 0; - grpci2_auto_cfg.memio_start = priv->pci_area; - grpci2_auto_cfg.memio_size = priv->pci_area_end - priv->pci_area; - grpci2_auto_cfg.io_start = 0x100; /* avoid PCI address 0 */ - grpci2_auto_cfg.io_size = 0x10000 - 0x100; /* lower 64kB I/O 16 */ - grpci2_auto_cfg.irq_map = grpci2_bus0_irq_map; - grpci2_auto_cfg.irq_route = NULL; /* use standard routing */ - pci_config_register(&grpci2_auto_cfg); - - if (pci_config_init()) { - /* PCI configuration failed */ - return DRVMGR_FAIL; - } - - /* Initialize/Register Driver Manager PCI Bus */ - priv->config.maps_down = &priv->maps_down[0]; - priv->config.maps_up = &priv->maps_up[0]; - return pcibus_register(dev, &priv->config); -} - -int grpci2_init3(struct drvmgr_dev *dev) -{ - struct grpci2_priv *priv = dev->priv; - - /* Install and Enable PCI Error interrupt handler */ - drvmgr_interrupt_register(dev, 0, "grpci2", grpci2_err_isr, priv); - - /* Initialize DMA driver (if supported) */ - if (priv->regs->sts_cap & STS_DMA){ - grpci2dma_init((void *) &(priv->regs->dma_ctrl), grpci2_dma_isr_register); - } - - /* Unmask Error IRQ and all PCI interrupts at PCI Core. For this to be - * safe every PCI board have to be resetted (no IRQ generation) before - * Global IRQs are enabled (Init is reached or similar) - */ - priv->regs->ctrl |= (CTRL_EI | priv->irq_mask); - - return DRVMGR_OK; -} - -static void grpci2_dma_isr_register( void (*isr)(void *), void * arg) -{ - struct grpci2_priv *priv = grpci2priv; - - /* Handle unregistration */ - if (priv->dma_isr != NULL) { - drvmgr_interrupt_unregister(priv->dev, priv->irq_dma, grpci2_dma_isr, priv); - /* Uninstall user ISR */ - priv->dma_isr = NULL; - priv->dma_isr_arg = NULL; - } - - if (isr == NULL) - return; - - /* Install user ISR */ - priv->dma_isr_arg = arg; - priv->dma_isr = isr; - - /* Install and Enable PCI DMA interrupt handler */ - if (priv->irq_mode == 1) { - priv->irq_dma = 1; - } else if (priv->irq_mode == 3) { - priv->irq_dma = 4; - } else { - priv->irq_dma = 0; - } - drvmgr_interrupt_register(priv->dev, priv->irq_dma, "grpci2dma", grpci2_dma_isr, priv); -} |