From 6fae45804d1a552e19c735cd75ee2d462a00f254 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Tue, 14 May 2002 17:04:40 +0000 Subject: 2001-05-14 Till Straumann * vmeUniverse/README.universe, vmeUniverse/vmeUniverse.c, vmeUniverse/vmeUniverse.h: New files. * Makefile.am: Modified to reflect addition of files. * Per PR214, contributes a driver for the TUNDRA UNIVERSE VME-PCI bridge to libbsp/shared. NOTE: This driver is maintained _outside_ RTEMS by Till. Please forward future modifications to him. --- c/src/lib/libbsp/shared/ChangeLog | 10 + c/src/lib/libbsp/shared/Makefile.am | 3 +- .../lib/libbsp/shared/vmeUniverse/README.universe | 19 + c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.c | 1212 ++++++++++++++++++++ c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.h | 662 +++++++++++ 5 files changed, 1905 insertions(+), 1 deletion(-) create mode 100644 c/src/lib/libbsp/shared/vmeUniverse/README.universe create mode 100644 c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.c create mode 100644 c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.h (limited to 'c') diff --git a/c/src/lib/libbsp/shared/ChangeLog b/c/src/lib/libbsp/shared/ChangeLog index 50b168b063..82cb3bd225 100644 --- a/c/src/lib/libbsp/shared/ChangeLog +++ b/c/src/lib/libbsp/shared/ChangeLog @@ -1,3 +1,13 @@ +2001-05-14 Till Straumann + + * vmeUniverse/README.universe, vmeUniverse/vmeUniverse.c, + vmeUniverse/vmeUniverse.h: New files. + * Makefile.am: Modified to reflect addition of files. + * Per PR214, contributes a driver for the TUNDRA UNIVERSE + VME-PCI bridge to libbsp/shared. + NOTE: This driver is maintained _outside_ RTEMS by Till. Please + forward future modifications to him. + 2002-03-27 Ralf Corsepius * include/Makefile.am: Remove AUTOMAKE_OPTIONS. diff --git a/c/src/lib/libbsp/shared/Makefile.am b/c/src/lib/libbsp/shared/Makefile.am index 179398c9b3..6542966122 100644 --- a/c/src/lib/libbsp/shared/Makefile.am +++ b/c/src/lib/libbsp/shared/Makefile.am @@ -6,7 +6,8 @@ SUBDIRS = include EXTRA_DIST = bootcard.c bspclean.c bsplibc.c bsppost.c console-polled.c \ - console.c gnatinstallhandler.c main.c sbrk.c tod.c tod.h + console.c gnatinstallhandler.c main.c sbrk.c tod.c tod.h \ + vmeUniverse/vmeUniverse.c vmeUniverse/vmeUniverse.h include $(top_srcdir)/../../../../automake/subdirs.am include $(top_srcdir)/../../../../automake/local.am diff --git a/c/src/lib/libbsp/shared/vmeUniverse/README.universe b/c/src/lib/libbsp/shared/vmeUniverse/README.universe new file mode 100644 index 0000000000..a5f02c8bbc --- /dev/null +++ b/c/src/lib/libbsp/shared/vmeUniverse/README.universe @@ -0,0 +1,19 @@ +The universe II driver is in a separate subdir +because it is maintained at SSRL outside of the +rtems CVS tree (it supports other OSes as well) + +Till Straumann 1/2002 + +NOTES: +This driver is maintained _outside_ rtems. +Please forward future modifications to me. + +A BSP that wants to use the vmeUniverse driver +must implement the following headers / functionality: + - offering an API like 'libbsp/powerpc/shared/pci' + - offering the 'new style' RTEMS irq API + (like 'libbsp/powerpc/shared/irq'). + +The BSP should then use "VPATH magic" (to use Joel's +words :-) to reach the vmeUniverse.* files in the +universe subdir. diff --git a/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.c b/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.c new file mode 100644 index 0000000000..0fbd2840e8 --- /dev/null +++ b/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.c @@ -0,0 +1,1212 @@ +/* $Id$ */ + +/* Routines to configure the VME interface + * Author: Till Straumann + * Nov 2000, Oct 2001, Jan 2002 + */ + +#if 0 + * $Log$ + * Revision 1.21 2002/04/11 06:54:48 till + * - silenced message about 'successfully configured a port' + * + * Revision 1.20 2002/03/27 21:14:50 till + * - fix: handler table holds pointers, so hdlrTbl[vector]->usrData etc. + * not hdlrTbl[vector].usrData... + * + * Revision 1.19 2002/03/09 00:14:36 till + * - added vmeUniverseISRGet() to retrieve the currently installed + * ISR for a given vector + * - swapped the argument order for ISRs to (usrarg, vector) + * + * Revision 1.18 2002/02/07 19:53:48 till + * - reverted back to publish base_addr/irq_line as variables rather than + * through functions: the irq_line is read by the interrupt dispatcher... + * + * Revision 1.17 2002/01/24 08:28:10 till + * - initialize driver when reading base address or irq line. + * however, this requires the pci driver to be working already. + * + * Revision 1.16 2002/01/24 08:21:48 till + * - replaced public global vars for base address/irq line by routines. + * + * Revision 1.15 2002/01/23 06:15:30 till + * - changed master port data width to 64 bit. + * /* NOTE: reading the CY961 (Echotek ECDR814) with VDW32 + * * generated bus errors when reading 32-bit words + * * - very weird, because the registers are 16-bit + * * AFAIK. + * * - 32-bit accesses worked fine on vxWorks which + * * has the port set to 64-bit. + * * ???????? + * */ + * + * Revision 1.14 2002/01/11 19:30:54 till + * - added more register defines to header + * - completed vmeUniverseReset + * + * Revision 1.13 2002/01/11 05:06:18 till + * - fixed VMEISR failing to check (lint_stat & msk) when determining + * the highes level... + * - tested interrupt handling & nesting. Seems to work. + * + * Revision 1.12 2002/01/11 02:25:55 till + * - added interrupt manager + * + * Revision 1.11 2002/01/08 03:59:52 till + * - vxworks always defines _LITTLE_ENDIAN, fixed the conditionals + * so it should work on __vxworks and on __rtems now. + * - rtems uprintf wrapper reverts to printk if stdio is not yet + * initialized (uses _impure_ptr->__sdidinit) + * - tested bus address translation utility routines + * + * Revision 1.9 2002/01/05 02:36:32 till + * - added vmeUniverseBusToLocalAdrs / vmeUniverseLocalToBusAdrs for address + * space translations. + * - include bsp.h under rtems to hack around the libcpu/powerpc/shared/io.h + * #define _IO_BASE & friends problem. + * + * Revision 1.8 2002/01/04 04:12:51 till + * - changed some rtems/pci related names + * + * Revision 1.7 2002/01/04 03:06:30 till + * - added further register definitions + * + * Revision 1.6 2001/12/20 04:42:44 till + * - fixed endianness stuff; theoretically, PPC could be LITTLE_ENDIAN... + * + * Revision 1.4 2001/12/19 01:59:02 till + * - started adding interrupt stuff + * - private implementation of PCI scanning if necessary + * + * Revision 1.3 2001/07/27 22:22:51 till + * - added more DMA support routines and defines to include file + * - xxxPortsShow can now print to a given file descriptor argument + * + * Revision 1.2 2001/07/26 18:06:13 till + * - ported to RTEMS + * - fixed a couple of wrong pointer calculations. + * + * Revision 1.1.1.1 2001/07/12 23:15:19 till + * - cvs import + * +#endif + +#include +#include +#include "vmeUniverse.h" + +#define UNIV_NUM_MPORTS 8 /* number of master ports */ +#define UNIV_NUM_SPORTS 8 /* number of slave ports */ + +#define PCI_VENDOR_TUNDRA 0x10e3 +#define PCI_DEVICE_UNIVERSEII 0 +#define PCI_UNIVERSE_BASE0 0x10 +#define PCI_UNIVERSE_BASE1 0x14 + +#define UNIV_REGOFF_PCITGT0_CTRL 0x100 +#define UNIV_REGOFF_PCITGT4_CTRL 0x1a0 +#define UNIV_REGOFF_VMESLV0_CTRL 0xf00 +#define UNIV_REGOFF_VMESLV4_CTRL 0xf90 + +#define UNIV_CTL_VAS16 (0x00000000) +#define UNIV_CTL_VAS24 (0x00010000) +#define UNIV_CTL_VAS32 (0x00020000) +#define UNIV_CTL_VAS (0x00070000) + +#define UNIV_MCTL_EN (0x80000000) +#define UNIV_MCTL_PWEN (0x40000000) +#define UNIV_MCTL_PGM (0x00004000) +#define UNIV_MCTL_VCT (0x00000100) +#define UNIV_MCTL_SUPER (0x00001000) +#define UNIV_MCTL_VDW32 (0x00800000) +#define UNIV_MCTL_VDW64 (0x00c00000) + +#define UNIV_MCTL_AM_MASK (UNIV_CTL_VAS | UNIV_MCTL_PGM | UNIV_MCTL_SUPER) + +#define UNIV_SCTL_EN (0x80000000) +#define UNIV_SCTL_PWEN (0x40000000) +#define UNIV_SCTL_PREN (0x20000000) +#define UNIV_SCTL_PGM (0x00800000) +#define UNIV_SCTL_DAT (0x00400000) +#define UNIV_SCTL_SUPER (0x00200000) +#define UNIV_SCTL_USER (0x00100000) + +#define UNIV_SCTL_AM_MASK (UNIV_CTL_VAS | UNIV_SCTL_PGM | UNIV_SCTL_DAT | UNIV_SCTL_USER | UNIV_SCTL_SUPER) + +/* we rely on a vxWorks definition here */ +#define VX_AM_SUP 4 + +#ifdef __rtems + +#include +#include /* printk */ +#include +#include + +#define pciFindDevice BSP_pciFindDevice +#define pciConfigInLong pci_read_config_dword +#define pciConfigInByte pci_read_config_byte + +typedef unsigned int pci_ulong; +#define PCI_TO_LOCAL_ADDR(memaddr) ((pci_ulong)(memaddr) + PCI_MEM_BASE) + + +#elif defined(__vxworks) +typedef unsigned long pci_ulong; +#define PCI_TO_LOCAL_ADDR(memaddr) (memaddr) +#define PCI_INTERRUPT_LINE 0x3c +#else +#error "vmeUniverse not ported to this architecture yet" +#endif + + +volatile LERegister *vmeUniverse0BaseAddr=0; +int vmeUniverse0PciIrqLine=-1; + +#if 0 +/* public access functions */ +volatile LERegister * +vmeUniverseBaseAddr(void) +{ + if (!vmeUniverse0BaseAddr) vmeUniverseInit(); + return vmeUniverse0BaseAddr; +} + +int +vmeUniversePciIrqLine(void) +{ + if (vmeUniverse0PciIrqLine<0) vmeUniverseInit(); + return vmeUniverse0PciIrqLine; +} +#endif + +static inline void +WRITE_LE( + unsigned long val, + volatile LERegister *adrs, + unsigned long off) +{ +#if (__LITTLE_ENDIAN__ == 1) + *(volatile unsigned long*)(((unsigned long)adrs)+off)=val; +#elif (defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)) && (__BIG_ENDIAN__ == 1) + /* offset is in bytes and MUST not end up in r0 */ + __asm__ __volatile__("stwbrx %1, %0, %2" :: "b"(off),"r"(val),"r"(adrs)); +#elif defined(__rtems) + st_le32((volatile unsigned long*)(((unsigned long)adrs)+off), val); +#else +#error "little endian register writing not implemented" +#endif +} + +#if defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC) +#define SYNC __asm__ __volatile__("sync") +#else +#define SYNC +#warning "SYNC instruction unknown for this architecture" +#endif + +/* registers should be mapped to guarded, non-cached memory; hence + * subsequent stores are ordered. eieio is only needed to enforce + * ordering of loads with respect to stores. + */ +#define EIEIO_REG + +static inline unsigned long +READ_LE0(volatile LERegister *adrs) +{ +#if (__LITTLE_ENDIAN__ == 1) + return *(volatile unsigned long *)adrs; +#elif (defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)) && (__BIG_ENDIAN__ == 1) +register unsigned long rval; +__asm__ __volatile__("lwbrx %0, 0, %1":"=r"(rval):"r"(adrs)); + return rval; +#elif defined(__rtems) + return ld_le32((volatile unsigned long*)adrs); +#else +#error "little endian register reading not implemented" +#endif +} + +static inline unsigned long +READ_LE(volatile LERegister *adrs, unsigned long off) +{ +#if (__LITTLE_ENDIAN__ == 1) + return *((volatile LERegister *)(((unsigned long)adrs)+off)); +#elif (defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)) && (__BIG_ENDIAN__ == 1) +register unsigned long rval; + /* offset is in bytes and MUST not end up in r0 */ +__asm__ __volatile__("lwbrx %0, %2, %1" + : "=r"(rval) + : "r"(adrs), "b"(off)); +#if 0 +__asm__ __volatile__("eieio"); +#endif +return rval; +#else +return READ_LE0((volatile LERegister *)(((unsigned long)adrs)+off)); +#endif +} + +#define PORT_UNALIGNED(addr,port) \ + ( (port)%4 ? ((addr) & 0xffff) : ((addr) & 4095) ) + + +#define UNIV_REV(base) (READ_LE(base,2*sizeof(LERegister)) & 0xff) + +#ifdef __rtems +static int +uprintk(char *fmt, va_list ap) +{ +int rval; +/* during bsp init, there is no malloc and no stdio, + * hence we assemble the message on the stack and revert + * to printk + */ +char buf[200]; + rval = vsprintf(buf,fmt,ap); + if (rval > sizeof(buf)) + BSP_panic("vmeUniverse/uprintk: buffer overrun"); + printk(buf); + return rval; +} +#endif + + +/* private printing wrapper */ +static int +uprintf(FILE *f, char *fmt, ...) +{ +va_list ap; +int rval; + va_start(ap, fmt); +#ifdef __rtems + if (!f || !_impure_ptr->__sdidinit) { + /* Might be called at an early stage when + * stdio is not yet initialized. + * There is no vprintk, hence we must assemble + * to a buffer. + */ + rval=uprintk(fmt,ap); + } else +#endif + { + rval=vfprintf(f,fmt,ap); + } + va_end(ap); + return rval; +} + +int +vmeUniverseFindPciBase( + int instance, + volatile LERegister **pbase + ) +{ +int bus,dev,fun; +pci_ulong busaddr; +unsigned char irqline; + + if (pciFindDevice( + PCI_VENDOR_TUNDRA, + PCI_DEVICE_UNIVERSEII, + instance, + &bus, + &dev, + &fun)) + return -1; + if (pciConfigInLong(bus,dev,fun,PCI_UNIVERSE_BASE0,&busaddr)) + return -1; + if ((unsigned long)(busaddr) & 1) { + /* it's IO space, try BASE1 */ + if (pciConfigInLong(bus,dev,fun,PCI_UNIVERSE_BASE1,&busaddr) + || ((unsigned long)(busaddr) & 1)) + return -1; + } + *pbase=(volatile LERegister*)PCI_TO_LOCAL_ADDR(busaddr); + + if (pciConfigInByte(bus,dev,fun,PCI_INTERRUPT_LINE,&irqline)) + return -1; + else + vmeUniverse0PciIrqLine = irqline; + + return 0; +} + +/* convert an address space selector to a corresponding + * universe control mode word + */ + +static int +am2mode(int ismaster, unsigned long address_space, unsigned long *pmode) +{ +unsigned long mode=0; + if (!ismaster) { + mode |= UNIV_SCTL_DAT | UNIV_SCTL_PGM; + mode |= UNIV_SCTL_USER; + } + switch (address_space) { + case VME_AM_STD_SUP_PGM: + case VME_AM_STD_USR_PGM: + if (ismaster) + mode |= UNIV_MCTL_PGM ; + else { + mode &= ~UNIV_SCTL_DAT; + } + /* fall thru */ + case VME_AM_STD_SUP_DATA: + case VME_AM_STD_USR_DATA: + mode |= UNIV_CTL_VAS24; + break; + + case VME_AM_EXT_SUP_PGM: + case VME_AM_EXT_USR_PGM: + if (ismaster) + mode |= UNIV_MCTL_PGM ; + else { + mode &= ~UNIV_SCTL_DAT; + } + /* fall thru */ + case VME_AM_EXT_SUP_DATA: + case VME_AM_EXT_USR_DATA: + mode |= UNIV_CTL_VAS32; + break; + + case VME_AM_SUP_SHORT_IO: + case VME_AM_USR_SHORT_IO: + mode |= UNIV_CTL_VAS16; + break; + + case 0: /* disable the port alltogether */ + break; + + default: + return -1; + } + if (address_space & VX_AM_SUP) + mode |= (ismaster ? UNIV_MCTL_SUPER : UNIV_SCTL_SUPER); + *pmode = mode; + return 0; +} + +static int +disableUniversePort(int ismaster, int portno, volatile unsigned long *preg, void *param) +{ +unsigned long cntrl; + cntrl=READ_LE0(preg); + cntrl &= ~(ismaster ? UNIV_MCTL_EN : UNIV_SCTL_EN); + WRITE_LE(cntrl,preg,0); + SYNC; /* make sure this command completed */ + return 0; +} + +static int +cfgUniversePort( + unsigned long ismaster, + unsigned long port, + unsigned long address_space, + unsigned long vme_address, + unsigned long local_address, + unsigned long length) +{ +#define base vmeUniverse0BaseAddr +volatile LERegister *preg=base; +unsigned long p=port; +unsigned long mode=0; + + /* check parameters */ + if (port >= (ismaster ? UNIV_NUM_MPORTS : UNIV_NUM_SPORTS)) { + uprintf(stderr,"invalid port\n"); + return -1; + } + /* port start, bound addresses and offset must lie on 64k boundary + * (4k for port 0 and 4) + */ + if ( PORT_UNALIGNED(local_address,port) ) { + uprintf(stderr,"local address misaligned\n"); + return -1; + } + if ( PORT_UNALIGNED(vme_address,port) ) { + uprintf(stderr,"vme address misaligned\n"); + return -1; + } + if ( PORT_UNALIGNED(length,port) ) { + uprintf(stderr,"length misaligned\n"); + return -1; + } + + /* check address space validity */ + if (am2mode(ismaster,address_space,&mode)) { + uprintf(stderr,"invalid address space\n"); + return -1; + } + + /* get the universe base address */ + if (!base && vmeUniverseInit()) { + return -1; + } + + /* find out if we have a rev. II chip */ + if ( UNIV_REV(base) < 2 ) { + if (port>3) { + uprintf(stderr,"Universe rev. < 2 has only 4 ports\n"); + return -1; + } + } + + /* finally, configure the port */ + + /* find the register set for our port */ + if (port<4) { + preg += (ismaster ? UNIV_REGOFF_PCITGT0_CTRL : UNIV_REGOFF_VMESLV0_CTRL)/sizeof(LERegister); + } else { + preg += (ismaster ? UNIV_REGOFF_PCITGT4_CTRL : UNIV_REGOFF_VMESLV4_CTRL)/sizeof(LERegister); + p-=4; + } + preg += 5 * p; + + /* temporarily disable the port */ + disableUniversePort(ismaster,port,preg,0); + + /* address_space == 0 means disable */ + if (address_space != 0) { + unsigned long start,offst; + /* set the port starting address; + * this is the local address for the master + * and the VME address for the slave + */ + if (ismaster) { + start=local_address; + /* let it overflow / wrap around 0 */ + offst=vme_address-local_address; + } else { + start=vme_address; + /* let it overflow / wrap around 0 */ + offst=local_address-vme_address; + } +#undef TSILL +#ifdef TSILL + uprintf(stderr,"writing 0x%08x to 0x%08x + 4\n",start,preg); +#else + WRITE_LE(start,preg,4); +#endif + /* set bound address */ + length+=start; +#ifdef TSILL + uprintf(stderr,"writing 0x%08x to 0x%08x + 8\n",length,preg); +#else + WRITE_LE(length,preg,8); +#endif + /* set offset */ +#ifdef TSILL + uprintf(stderr,"writing 0x%08x to 0x%08x + 12\n",offst,preg); +#else + WRITE_LE(offst,preg,12); +#endif + /* calculate configuration word and enable the port */ + /* NOTE: reading the CY961 (Echotek ECDR814) with VDW32 + * generated bus errors when reading 32-bit words + * - very weird, because the registers are 16-bit + * AFAIK. + * - 32-bit accesses worked fine on vxWorks which + * has the port set to 64-bit. + * ???????? + */ + if (ismaster) + mode |= UNIV_MCTL_EN | UNIV_MCTL_PWEN | UNIV_MCTL_VDW64 | UNIV_MCTL_VCT; + else + mode |= UNIV_SCTL_EN | UNIV_SCTL_PWEN | UNIV_SCTL_PREN; + +#ifdef TSILL + uprintf(stderr,"writing 0x%08x to 0x%08x + 0\n",mode,preg); +#else + EIEIO_REG; /* make sure mode is written last */ + WRITE_LE(mode,preg,0); + SYNC; /* enforce completion */ +#endif + +#ifdef TSILL + uprintf(stderr, + "universe %s port %lu successfully configured\n", + ismaster ? "master" : "slave", + port); +#endif + +#ifdef __vxworks + if (ismaster) + uprintf(stderr, + "WARNING: on the synergy, sysMasterPortsShow() may show incorrect settings (it uses cached values)\n"); +#endif + } + return 0; +#undef base +} + + +static int +showUniversePort( + int ismaster, + int portno, + volatile LERegister *preg, + void *parm) +{ + FILE *f=parm ? (FILE *)parm : stdout; + unsigned long cntrl, start, bound, offst, mask; + + cntrl = READ_LE0(preg++); +#undef TSILL +#ifdef TSILL + uprintf(stderr,"showUniversePort: *(0x%08x): 0x%08x\n",preg-1,cntrl); +#endif +#undef TSILL + + /* skip this port if disabled */ + if (!(cntrl & (ismaster ? UNIV_MCTL_EN : UNIV_SCTL_EN))) + return 0; + + /* for the master `start' is the PCI address, + * for the slave `start' is the VME address + */ + mask = ~PORT_UNALIGNED(0xffffffff,portno); + + start = READ_LE0(preg++)&mask; + bound = READ_LE0(preg++)&mask; + offst = READ_LE0(preg++)&mask; + + offst+=start; /* calc start on the other bus */ + + if (ismaster) { + uprintf(f,"%i: 0x%08lx 0x%08lx 0x%08lx ", + portno,offst,bound-start,start); + } else { + uprintf(f,"%i: 0x%08lx 0x%08lx 0x%08lx ", + portno,start,bound-start,offst); + } + + switch (cntrl & UNIV_CTL_VAS) { + case UNIV_CTL_VAS16: uprintf(f,"A16, "); break; + case UNIV_CTL_VAS24: uprintf(f,"A24, "); break; + case UNIV_CTL_VAS32: uprintf(f,"A32, "); break; + default: uprintf(f,"A??, "); break; + } + + if (ismaster) { + uprintf(f,"%s, %s", + cntrl&UNIV_MCTL_PGM ? "Pgm" : "Dat", + cntrl&UNIV_MCTL_SUPER ? "Sup" : "Usr"); + } else { + uprintf(f,"%s %s %s %s", + cntrl&UNIV_SCTL_PGM ? "Pgm," : " ", + cntrl&UNIV_SCTL_DAT ? "Dat," : " ", + cntrl&UNIV_SCTL_SUPER ? "Sup," : " ", + cntrl&UNIV_SCTL_USER ? "Usr" : ""); + } + uprintf(f,"\n"); + return 0; +} + +typedef struct XlatRec_ { + unsigned long address; + unsigned long aspace; +} XlatRec, *Xlat; + +/* try to translate an address through the bridge + * + * IN: l->address, l->aspace + * OUT: l->address (translated address) + * + * RETURNS: -1: invalid space + * 0: invalid address (not found in range) + * 1: success + */ + +static int +xlatePort(int ismaster, int port, volatile LERegister *preg, void *parm) +{ +Xlat l=(Xlat)parm; +unsigned long cntrl, start, bound, offst, mask, x; + + cntrl = READ_LE0(preg++); + + /* skip this port if disabled */ + if (!(cntrl & (ismaster ? UNIV_MCTL_EN : UNIV_SCTL_EN))) + return 0; + + /* check for correct address space */ + if ( am2mode(ismaster,l->aspace,&offst) ) { + uprintf(stderr,"vmeUniverse WARNING: invalid adressing mode 0x%x\n", + l->aspace); + return -1; + } + if ( (cntrl & (ismaster ? UNIV_MCTL_AM_MASK : UNIV_SCTL_AM_MASK)) + != offst ) + return 0; /* mode doesn't match requested AM */ + + /* OK, we found a matching mode, now we must check the address range */ + mask = ~PORT_UNALIGNED(0xffffffff,port); + + /* for the master `start' is the PCI address, + * for the slave `start' is the VME address + */ + start = READ_LE0(preg++) & mask; + bound = READ_LE0(preg++) & mask; + offst = READ_LE0(preg++) & mask; + + /* translate address to the other bus */ + x = l->address - offst; + + if (x >= start && x < bound) { + /* valid address found */ + l->address = x; + return 1; + } + return 0; +} + + +static int +mapOverAll(int ismaster, int (*func)(int,int,volatile LERegister *,void*), void *arg) +{ +#define base vmeUniverse0BaseAddr +volatile LERegister *rptr; +unsigned long port; +int rval; + + /* get the universe base address */ + if (!base && vmeUniverseInit()) { + uprintf(stderr,"unable to find the universe in pci config space\n"); + return -1; + } + rptr = (base + + (ismaster ? UNIV_REGOFF_PCITGT0_CTRL : UNIV_REGOFF_VMESLV0_CTRL)/sizeof(LERegister)); +#undef TSILL +#ifdef TSILL + uprintf(stderr,"mapoverall: base is 0x%08x, rptr 0x%08x\n",base,rptr); +#endif +#undef TSILL + for (port=0; port<4; port++) { + if ((rval=func(ismaster,port,rptr,arg))) return rval; + rptr+=5; /* register block spacing */ + } + + /* only rev. 2 has 8 ports */ + if (UNIV_REV(base)<2) return -1; + + rptr = (base + + (ismaster ? UNIV_REGOFF_PCITGT4_CTRL : UNIV_REGOFF_VMESLV4_CTRL)/sizeof(LERegister)); + for (port=4; port ptr) { +#if (defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC)) && (__BIG_ENDIAN__ == 1) + __asm__ __volatile__( + "lwzu 0, -4(%0)\n" + "stwbrx 0, 0, %0\n" + : "=r"(p) : "r"(p) : "r0" + ); +#elif defined(__rtems) + p--; st_le32(p, *p); +#else +#error "vmeUniverse: endian conversion not implemented for this architecture" +#endif + } +#endif +} + +/* RTEMS interrupt subsystem */ + +#ifdef __rtems +#include + +typedef struct +UniverseIRQEntryRec_ { + VmeUniverseISR isr; + void *usrData; +} UniverseIRQEntryRec, *UniverseIRQEntry; + +static UniverseIRQEntry universeHdlTbl[257]={0}; + +static int mgrInstalled=0; +static int vmeIrqUnivOut=-1; +static int specialIrqUnivOut=-1; + +VmeUniverseISR +vmeUniverseISRGet(unsigned long vector, void **parg) +{ + if (vector>255) return 0; + if (parg) + *parg=universeHdlTbl[vector]->usrData; + return universeHdlTbl[vector]->isr; +} + +static void +universeSpecialISR(void) +{ +UniverseIRQEntry ip; + /* try the special handler */ + if ((ip=universeHdlTbl[UNIV_SPECIAL_IRQ_VECTOR])) { + ip->isr(ip->usrData, UNIV_SPECIAL_IRQ_VECTOR); + } + /* clear all special interrupts */ + vmeUniverseWriteReg( + ~((UNIV_LINT_STAT_VIRQ7<<1)-UNIV_LINT_STAT_VIRQ1), + UNIV_REGOFF_LINT_STAT + ); + +/* + * clear our line in the VINT_STAT register + * seems to be not neccessary... + vmeUniverseWriteReg( + UNIV_VINT_STAT_LINT(specialIrqUnivOut), + UNIV_REGOFF_VINT_STAT); + */ +} + +/* + * interrupts from VME to PCI seem to be processed more or less + * like this: + * + * + * VME IRQ ------ + * & ----- LINT_STAT ---- + * | & ---------- PCI LINE + * | | + * | | + * LINT_EN --------------------------- + * + * I.e. + * - if LINT_EN is disabled, a VME IRQ will not set LINT_STAT. + * - while LINT_STAT is set, it will pull the PCI line unless + * masked by LINT_EN. + * - VINT_STAT(lint_bit) seems to have no effect beyond giving + * status info. + * + * Hence, it is possible to + * - arm (set LINT_EN, routing etc.) + * - receive an irq (sets. LINT_STAT) + * - the ISR then: + * * clears LINT_EN, results in masking LINT_STAT (which + * is still set to prevent another VME irq at the same + * level to be ACKEd by the universe. + * * do PCI_EOI to allow nesting of higher VME irqs. + * (previous step also cleared LINT_EN of lower levels) + * * when the handler returns, clear LINT_STAT + * * re-enable setting LINT_EN. + */ + +static void +universeVMEISR(void) +{ +UniverseIRQEntry ip; +unsigned long lvl,msk,lintstat,linten,status; + + /* determine the highest priority IRQ source */ + lintstat=vmeUniverseReadReg(UNIV_REGOFF_LINT_STAT); + for (msk=UNIV_LINT_STAT_VIRQ7, lvl=7; + lvl>0; + lvl--, msk>>=1) { + if (lintstat & msk) break; + } + if (!lvl) { + /* try the special handler */ + universeSpecialISR(); + + /* + * let the pic end this cycle + */ + BSP_PIC_DO_EOI; + + return; + } + linten = vmeUniverseReadReg(UNIV_REGOFF_LINT_EN); + + /* mask this and all lower levels */ + vmeUniverseWriteReg( + linten & ~((msk<<1)-UNIV_LINT_STAT_VIRQ1), + UNIV_REGOFF_LINT_EN + ); + + /* end this interrupt + * cycle on the PCI bus, so higher level interrupts can be + * caught from now on... + */ + BSP_PIC_DO_EOI; + + /* get vector and dispatch handler */ + status = vmeUniverseReadReg(UNIV_REGOFF_VIRQ1_STATID - 4 + (lvl<<2)); + /* determine the highest priority IRQ source */ + + if (status & UNIV_VIRQ_ERR) { + /* TODO: log error message - RTEMS has no logger :-( */ + } else if (!(ip=universeHdlTbl[status & UNIV_VIRQ_STATID_MASK])) { + /* TODO: log error message - RTEMS has no logger :-( */ + } else { + /* dispatch handler, it must clear the IRQ at the device */ + ip->isr(ip->usrData, status&UNIV_VIRQ_STATID_MASK); + } + + /* clear this interrupt level */ + vmeUniverseWriteReg(msk, UNIV_REGOFF_LINT_STAT); +/* + * this seems not to be necessary; we just leave the + * bit set to save a couple of instructions... + vmeUniverseWriteReg( + UNIV_VINT_STAT_LINT(vmeIrqUnivOut), + UNIV_REGOFF_VINT_STAT); +*/ + + + /* re-enable the previous level */ + vmeUniverseWriteReg(linten, UNIV_REGOFF_LINT_EN); +} + +/* STUPID API */ +static void +my_no_op(const rtems_irq_connect_data * arg) +{} + +static int +my_isOn(const rtems_irq_connect_data *arg) +{ + return (int)vmeUniverseReadReg(UNIV_REGOFF_LINT_EN); +} + +int +vmeUniverseInstallIrqMgr(int vmeOut, int specialOut, int specialIrqPicLine) +{ +rtems_irq_connect_data aarrggh; + + /* check parameters */ + if ((vmeIrqUnivOut=vmeOut) < 0 || vmeIrqUnivOut > 7) return -1; + if ((specialIrqUnivOut=specialOut) > 7) return -2; + if (specialIrqPicLine < 0) return -3; + + if (mgrInstalled) return -4; + + aarrggh.on=my_no_op; /* at _least_ they could check for a 0 pointer */ + aarrggh.off=my_no_op; + aarrggh.isOn=my_isOn; + aarrggh.hdl=universeVMEISR; + aarrggh.name=vmeUniverse0PciIrqLine + BSP_PCI_IRQ0; + if (!BSP_install_rtems_irq_handler(&aarrggh)) + BSP_panic("unable to install vmeUniverse irq handler"); + if (specialIrqUnivOut > 0) { + /* install the special handler to a separate irq */ + aarrggh.hdl=universeSpecialISR; + aarrggh.name=specialIrqPicLine + BSP_PCI_IRQ0; + if (!BSP_install_rtems_irq_handler(&aarrggh)) + BSP_panic("unable to install vmeUniverse secondary irq handler"); + } else { + specialIrqUnivOut = vmeIrqUnivOut; + } + /* setup routing */ + + vmeUniverseWriteReg( + (UNIV_LINT_MAP0_VIRQ7(vmeIrqUnivOut) | + UNIV_LINT_MAP0_VIRQ6(vmeIrqUnivOut) | + UNIV_LINT_MAP0_VIRQ5(vmeIrqUnivOut) | + UNIV_LINT_MAP0_VIRQ4(vmeIrqUnivOut) | + UNIV_LINT_MAP0_VIRQ3(vmeIrqUnivOut) | + UNIV_LINT_MAP0_VIRQ2(vmeIrqUnivOut) | + UNIV_LINT_MAP0_VIRQ1(vmeIrqUnivOut) | + UNIV_LINT_MAP0_VOWN(specialIrqUnivOut) + ), + UNIV_REGOFF_LINT_MAP0); + vmeUniverseWriteReg( + (UNIV_LINT_MAP1_ACFAIL(specialIrqUnivOut) | + UNIV_LINT_MAP1_SYSFAIL(specialIrqUnivOut) | + UNIV_LINT_MAP1_SW_INT(specialIrqUnivOut) | + UNIV_LINT_MAP1_SW_IACK(specialIrqUnivOut) | + UNIV_LINT_MAP1_VERR(specialIrqUnivOut) | + UNIV_LINT_MAP1_LERR(specialIrqUnivOut) | + UNIV_LINT_MAP1_DMA(specialIrqUnivOut) + ), + UNIV_REGOFF_LINT_MAP1); + mgrInstalled=1; + return 0; +} + + +int +vmeUniverseInstallISR(unsigned long vector, VmeUniverseISR hdl, void *arg) +{ +UniverseIRQEntry ip; + + if (vector>sizeof(universeHdlTbl)/sizeof(universeHdlTbl[0]) || !mgrInstalled) + return -1; + + ip=universeHdlTbl[vector]; + + if (ip || !(ip=(UniverseIRQEntry)malloc(sizeof(UniverseIRQEntryRec)))) + return -1; + ip->isr=hdl; + ip->usrData=arg; + universeHdlTbl[vector]=ip; + return 0; +} + +int +vmeUniverseRemoveISR(unsigned long vector, VmeUniverseISR hdl, void *arg) +{ +UniverseIRQEntry ip; + + if (vector>sizeof(universeHdlTbl)/sizeof(universeHdlTbl[0]) || !mgrInstalled) + return -1; + + ip=universeHdlTbl[vector]; + + if (!ip || ip->isr!=hdl || ip->usrData!=arg) + return -1; + universeHdlTbl[vector]=0; + free(ip); + return 0; +} + +int +vmeUniverseIntEnable(unsigned int level) +{ + if (!mgrInstalled || level<1 || level>7) + return -1; + vmeUniverseWriteReg( + (vmeUniverseReadReg(UNIV_REGOFF_LINT_EN) | + (UNIV_LINT_EN_VIRQ1 << (level-1)) + ), + UNIV_REGOFF_LINT_EN); + return 0; +} + +int +vmeUniverseIntDisable(unsigned int level) +{ + if (!mgrInstalled || level<1 || level>7) + return -1; + vmeUniverseWriteReg( + (vmeUniverseReadReg(UNIV_REGOFF_LINT_EN) & + ~ (UNIV_LINT_EN_VIRQ1 << (level-1)) + ), + UNIV_REGOFF_LINT_EN); + return 0; +} + + +#endif diff --git a/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.h b/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.h new file mode 100644 index 0000000000..03f9032154 --- /dev/null +++ b/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.h @@ -0,0 +1,662 @@ +/* $Id$ */ +#ifndef VME_UNIVERSE_UTIL_H +#define VME_UNIVERSE_UTIL_H + +/* Routines to configure and use the Tundra Universe VME bridge + * Author: Till Straumann + * Nov 2000, July 2001 + */ + +/* Register definitions */ +/* NOTE: all registers contents in PCI space are LITTLE ENDIAN */ + +#ifdef __vxworks +#include +#else +/* vxworks compatible addressing modes */ +#define VME_AM_STD_SUP_PGM 0x3e +#define VME_AM_STD_USR_PGM 0x3a +#define VME_AM_STD_SUP_DATA 0x3d +#define VME_AM_STD_USR_DATA 0x39 +#define VME_AM_EXT_SUP_PGM 0x0e +#define VME_AM_EXT_USR_PGM 0x0a +#define VME_AM_EXT_SUP_DATA 0x0d +#define VME_AM_EXT_USR_DATA 0x09 +#define VME_AM_SUP_SHORT_IO 0x2d +#define VME_AM_USR_SHORT_IO 0x29 +#endif + +typedef unsigned long LERegister; /* emphasize contents are little endian */ + +/* NOTE: DMA packet descriptors MUST be 32 byte aligned */ +typedef struct VmeUniverseDMAPacketRec_ { + LERegister dctl __attribute__((aligned(32))); + LERegister dtbc; + LERegister dla; + LERegister dummy1; + LERegister dva; + LERegister dummy2; + LERegister dccp; + LERegister dummy3; +} VmeUniverseDMAPacketRec, *VmeUniverseDMAPacket; + +/* PCI CSR register */ +#define UNIV_REGOFF_PCI_CSR 0x4 +# define UNIV_PCI_CSR_D_PE (1<<31) /* detected parity error; write 1 to clear */ +# define UNIV_PCI_CSR_S_SERR (1<<30) /* SERR (signalled error) asserted; write 1 to clear */ +# define UNIV_PCI_CSR_R_MA (1<<29) /* received master abort; write 1 to clear */ +# define UNIV_PCI_CSR_R_TA (1<<28) /* received target abort; write 1 to clear */ +# define UNIV_PCI_CSR_S_TA (1<<27) /* signalled target abort; write 1 to clear */ +# define UNIV_PCI_CSR_DEVSEL_MASK (3<<25) /* device select timing (RO) */ +# define UNIV_PCI_CSR_DP_D (1<<24) /* data parity error detected; write 1 to clear */ +# define UNIV_PCI_CSR_TFBBC (1<<23) /* target fast back to back capable (RO) */ +# define UNIV_PCI_CSR_MFBBC (1<<9) /* master fast back to back capable (RO) */ +# define UNIV_PCI_CSR_SERR_EN (1<<8) /* enable SERR driver */ +# define UNIV_PCI_CSR_WAIT (1<<7) /* wait cycle control (RO) */ +# define UNIV_PCI_CSR_PERESP (1<<6) /* parity error response enable */ +# define UNIV_PCI_CSR_VGAPS (1<<5) /* VGA palette snoop (RO) */ +# define UNIV_PCI_CSR_MWI_EN (1<<4) /* Memory write and invalidate enable (RO) */ +# define UNIV_PCI_CSR_SC (1<<3) /* special cycles (RO) */ +# define UNIV_PCI_CSR_BM (1<<2) /* master enable (MUST SET TO ENABLE VME SLAVES) */ +# define UNIV_PCI_CSR_MS (1<<1) /* target memory enable */ +# define UNIV_PCI_CSR_IOS (1<<0) /* target IO enable */ + +/* Special cycle (ADOH, RMW) control register */ +#define UNIV_REGOFF_SCYC_CTL 0x170 /* write 0 to disable */ +# define UNIV_SCYC_CTL_LAS_IO (1<<2) /* PCI address space (1: IO, 0: mem) */ +# define UNIV_SCYC_CTL_SCYC_RMW (1<<0) /* do a RMW cycle when reading PCI address */ +# define UNIV_SCYC_CTL_SCYC_ADOH (2<<0) /* do a ADOH cycle when reading/writing PCI address */ + +/* Special cycle address register */ +#define UNIV_REGOFF_SCYC_ADDR 0x174 /* PCI address (must be long word aligned) */ + +/* Special cycle Swap/Compare/Enable */ +#define UNIV_REGOFF_SCYC_EN 0x178 /* mask determining the bits involved in the compare and swap operations for VME RMW cycles */ + +/* Special cycle compare data register */ +#define UNIV_REGOFF_SCYC_CMP 0x17c /* data to compare with word returned from VME RMW read */ + +/* Special cycle swap data register */ +#define UNIV_REGOFF_SCYC_SWP 0x180 /* If enabled bits of CMP match, corresponding SWP bits are written back to VME (under control of EN) */ + +/* PCI miscellaneous register */ +#define UNIV_REGOFF_LMISC 0x184 +# define UNIV_LMISC_CRT_MASK (7<<28) /* Univ. I only, not used on II */ +# define UNIV_LMISC_CRT_INF (0<<28) /* Coupled Request Timeout */ +# define UNIV_LMISC_CRT_128_US (1<<28) /* Coupled Request Timeout */ +# define UNIV_LMISC_CRT_256_US (2<<28) /* Coupled Request Timeout */ +# define UNIV_LMISC_CRT_512_US (3<<28) /* Coupled Request Timeout */ +# define UNIV_LMISC_CRT_1024_US (4<<28) /* Coupled Request Timeout */ +# define UNIV_LMISC_CRT_2048_US (5<<28) /* Coupled Request Timeout */ +# define UNIV_LMISC_CRT_4096_US (6<<28) /* Coupled Request Timeout */ + +# define UNIV_LMISC_CWT_MASK (7<<24) /* coupled window timer */ +# define UNIV_LMISC_CWT_DISABLE 0 /* disabled (release VME after 1 coupled xaction) */ +# define UNIV_LMISC_CWT_16 (1<<24) /* 16 PCI clock cycles */ +# define UNIV_LMISC_CWT_32 (2<<24) /* 32 PCI clock cycles */ +# define UNIV_LMISC_CWT_64 (3<<24) /* 64 PCI clock cycles */ +# define UNIV_LMISC_CWT_128 (4<<24) /* 128 PCI clock cycles */ +# define UNIV_LMISC_CWT_256 (5<<24) /* 256 PCI clock cycles */ +# define UNIV_LMISC_CWT_512 (6<<24) /* 512 PCI clock cycles */ + +/* PCI Command Error Log Register */ +#define UNIV_REGOFF_L_CMDERR 0x18c +# define UNIV_L_CMDERR_CMDERR(reg) (((reg)>>28)&0xf) /* extract PCI cmd error log */ +# define UNIV_L_CMDERR_M_ERR (1<<27) /* multiple errors have occurred */ +# define UNIV_L_CMDERR_L_STAT (1<<23) /* PCI error log status valid (write 1 to clear and enable logging) */ + +/* PCI Address Error Log */ +#define UNIV_REGOFF_LAERR 0x190 /* PCI fault address (if L_CMDERR_L_STAT valid) */ +/* DMA Xfer Control Register */ +#define UNIV_REGOFF_DCTL 0x200 +# define UNIV_DCTL_L2V (1<<31) /* PCI->VME if set */ +# define UNIV_DCTL_VDW_MSK (3<<22) /* VME max. width mask 0x00c00000 */ +# define UNIV_DCTL_VDW_8 (0<<22) /* VME max. width 8 */ +# define UNIV_DCTL_VDW_16 (1<<22) /* VME max. width 16 */ +# define UNIV_DCTL_VDW_32 (2<<22) /* VME max. width 32 */ +# define UNIV_DCTL_VDW_64 (3<<22) /* VME max. width 64 */ +# define UNIV_DCTL_VAS_MSK (7<<16) /* VME AS mask 0x00070000 */ +# define UNIV_DCTL_VAS_A16 (0<<16) /* VME A16 */ +# define UNIV_DCTL_VAS_A24 (1<<16) /* VME A24 */ +# define UNIV_DCTL_VAS_A32 (2<<16) /* VME A32 */ +# define UNIV_DCTL_PGM_MSK (3<<14) /* VME PGM/DATA mask 0x0000c000 */ +# define UNIV_DCTL_PGM (1<<14) /* VME PGM(1)/DATA(0) */ +# define UNIV_DCTL_SUPER_MSK (3<<12) /* VME SUPER/USR mask 0x00003000 */ +# define UNIV_DCTL_SUPER (1<<12) /* VME SUPER(1)/USR(0) */ +# define UNIV_DCTL_VCT (1<<8) /* VME enable BLT */ +# define UNIV_DCTL_LD64EN (1<<7) /* PCI 64 enable */ + +/* DMA Xfer byte count register (is updated by DMA) */ +#define UNIV_REGOFF_DTBC 0x204 +/* DMA Xfer local (PCI) address (direction is set in DCTL) */ +#define UNIV_REGOFF_DLA 0x208 +/* DMA Xfer VME address (direction is set in DCTL) + * NOTE: (*UNIV_DVA) & ~7 == (*UNIV_DLA) & ~7 MUST HOLD + */ +#define UNIV_REGOFF_DVA 0x210 + +/* DMA Xfer VME command packet pointer + * NOTE: The address stored here MUST be 32-byte aligned + */ +#define UNIV_REGOFF_DCPP 0x218 +/* these bits are only used in linked lists */ +# define UNIV_DCCP_IMG_NULL (1<<0) /* last packet in list */ +# define UNIV_DCCP_IMG_PROCESSED (1<<1) /* packet processed */ + +/* DMA Xfer General Control/Status register */ +#define UNIV_REGOFF_DGCS 0x220 +# define UNIV_DGCS_GO (1<<31) /* start xfer */ +# define UNIV_DGCS_STOP_REQ (1<<30) /* stop xfer (immediate abort) */ +# define UNIV_DGCS_HALT_REQ (1<<29) /* halt xfer (abort after current packet) */ +# define UNIV_DGCS_CHAIN (1<<27) /* enable linked list mode */ +# define UNIV_DGCS_VON_MSK (7<<20) /* VON mask */ +# define UNIV_DGCS_VON_DONE (0<<20) /* VON counter disabled (do until done) */ +# define UNIV_DGCS_VON_256 (1<<20) /* VON yield bus after 256 bytes */ +# define UNIV_DGCS_VON_512 (2<<20) /* VON yield bus after 512 bytes */ +# define UNIV_DGCS_VON_1024 (3<<20) /* VON yield bus after 512 bytes */ +# define UNIV_DGCS_VON_2048 (4<<20) /* VON yield bus after 1024 bytes */ +# define UNIV_DGCS_VON_4096 (5<<20) /* VON yield bus after 4096 bytes */ +# define UNIV_DGCS_VON_8192 (6<<20) /* VON yield bus after 8192 bytes */ +# define UNIV_DGCS_VOFF_MSK (15<<16) /* VOFF mask */ +# define UNIV_DGCS_VOFF_0_US (0<<16) /* re-request VME master after 0 us */ +# define UNIV_DGCS_VOFF_2_US (8<<16) /* re-request VME master after 2 us */ +# define UNIV_DGCS_VOFF_4_US (9<<16) /* re-request VME master after 4 us */ +# define UNIV_DGCS_VOFF_8_US (10<<16)/* re-request VME master after 8 us */ +# define UNIV_DGCS_VOFF_16_US (1<<16) /* re-request VME master after 16 us */ +# define UNIV_DGCS_VOFF_32_US (2<<16) /* re-request VME master after 32 us */ +# define UNIV_DGCS_VOFF_64_US (3<<16) /* re-request VME master after 64 us */ +# define UNIV_DGCS_VOFF_128_US (4<<16) /* re-request VME master after 128 us */ +# define UNIV_DGCS_VOFF_256_US (5<<16) /* re-request VME master after 256 us */ +# define UNIV_DGCS_VOFF_512_US (6<<16) /* re-request VME master after 512 us */ +# define UNIV_DGCS_VOFF_1024_US (7<<16) /* re-request VME master after 1024 us */ +/* Status Bits (write 1 to clear) */ +# define UNIV_DGCS_ACT (1<<15) /* DMA active */ +# define UNIV_DGCS_STOP (1<<14) /* DMA stopped */ +# define UNIV_DGCS_HALT (1<<13) /* DMA halted */ +# define UNIV_DGCS_DONE (1<<11) /* DMA done (OK) */ +# define UNIV_DGCS_LERR (1<<10) /* PCI bus error */ +# define UNIV_DGCS_VERR (1<<9) /* VME bus error */ +# define UNIV_DGCS_P_ERR (1<<8) /* programming protocol error (e.g. PCI master disabled) */ +# define UNIV_DGCS_STATUS_CLEAR\ + (UNIV_DGCS_ACT|UNIV_DGCS_STOP|UNIV_DGCS_HALT|\ + UNIV_DGCS_DONE|UNIV_DGCS_LERR|UNIV_DGCS_VERR|UNIV_DGCS_P_ERR) +# define UNIV_DGCS_P_ERR (1<<8) /* programming protocol error (e.g. PCI master disabled) */ +/* Interrupt Mask Bits */ +# define UNIV_DGCS_INT_STOP (1<<6) /* interrupt when stopped */ +# define UNIV_DGCS_INT_HALT (1<<5) /* interrupt when halted */ +# define UNIV_DGCS_INT_DONE (1<<3) /* interrupt when done */ +# define UNIV_DGCS_INT_LERR (1<<2) /* interrupt on LERR */ +# define UNIV_DGCS_INT_VERR (1<<1) /* interrupt on VERR */ +# define UNIV_DGCS_INT_P_ERR (1<<0) /* interrupt on P_ERR */ +# define UNIV_DGCS_INT_MSK (0x0000006f) /* interrupt mask */ + +/* DMA Linked List Update Enable Register */ +#define UNIV_REGOFF_D_LLUE 0x224 +# define UNIV_D_LLUE_UPDATE (1<<31) + + +/* PCI (local) interrupt enable register */ +#define UNIV_REGOFF_LINT_EN 0x300 +# define UNIV_LINT_EN_LM3 (1<<23) /* location monitor 3 mask */ +# define UNIV_LINT_EN_LM2 (1<<22) /* location monitor 2 mask */ +# define UNIV_LINT_EN_LM1 (1<<21) /* location monitor 1 mask */ +# define UNIV_LINT_EN_LM0 (1<<20) /* location monitor 0 mask */ +# define UNIV_LINT_EN_MBOX3 (1<<19) /* mailbox 3 mask */ +# define UNIV_LINT_EN_MBOX2 (1<<18) /* mailbox 2 mask */ +# define UNIV_LINT_EN_MBOX1 (1<<17) /* mailbox 1 mask */ +# define UNIV_LINT_EN_MBOX0 (1<<16) /* mailbox 0 mask */ +# define UNIV_LINT_EN_ACFAIL (1<<15) /* ACFAIL irq mask */ +# define UNIV_LINT_EN_SYSFAIL (1<<14) /* SYSFAIL irq mask */ +# define UNIV_LINT_EN_SW_INT (1<<13) /* PCI (local) software irq */ +# define UNIV_LINT_EN_SW_IACK (1<<12) /* VME software IACK mask */ +# define UNIV_LINT_EN_VERR (1<<10) /* PCI VERR irq mask */ +# define UNIV_LINT_EN_LERR (1<<9) /* PCI LERR irq mask */ +# define UNIV_LINT_EN_DMA (1<<8) /* PCI DMA irq mask */ +# define UNIV_LINT_EN_VIRQ7 (1<<7) /* VIRQ7 mask (universe does IACK automatically) */ +# define UNIV_LINT_EN_VIRQ6 (1<<6) /* VIRQ6 mask */ +# define UNIV_LINT_EN_VIRQ5 (1<<5) /* VIRQ5 mask */ +# define UNIV_LINT_EN_VIRQ4 (1<<4) /* VIRQ4 mask */ +# define UNIV_LINT_EN_VIRQ3 (1<<3) /* VIRQ3 mask */ +# define UNIV_LINT_EN_VIRQ2 (1<<2) /* VIRQ2 mask */ +# define UNIV_LINT_EN_VIRQ1 (1<<1) /* VIRQ1 mask */ +# define UNIV_LINT_EN_VOWN (1<<0) /* VOWN mask */ + +/* PCI (local) interrupt status register */ +#define UNIV_REGOFF_LINT_STAT 0x304 +# define UNIV_LINT_STAT_LM3 (1<<23) /* location monitor 3 status */ +# define UNIV_LINT_STAT_LM2 (1<<22) /* location monitor 2 status */ +# define UNIV_LINT_STAT_LM1 (1<<21) /* location monitor 1 status */ +# define UNIV_LINT_STAT_LM0 (1<<20) /* location monitor 0 status */ +# define UNIV_LINT_STAT_MBOX3 (1<<19) /* mailbox 3 status */ +# define UNIV_LINT_STAT_MBOX2 (1<<18) /* mailbox 2 status */ +# define UNIV_LINT_STAT_MBOX1 (1<<17) /* mailbox 1 status */ +# define UNIV_LINT_STAT_MBOX0 (1<<16) /* mailbox 0 status */ +# define UNIV_LINT_STAT_ACFAIL (1<<15) /* ACFAIL irq status */ +# define UNIV_LINT_STAT_SYSFAIL (1<<14) /* SYSFAIL irq status */ +# define UNIV_LINT_STAT_SW_INT (1<<13) /* PCI (local) software irq */ +# define UNIV_LINT_STAT_SW_IACK (1<<12) /* VME software IACK status */ +# define UNIV_LINT_STAT_VERR (1<<10) /* PCI VERR irq status */ +# define UNIV_LINT_STAT_LERR (1<<9) /* PCI LERR irq status */ +# define UNIV_LINT_STAT_DMA (1<<8) /* PCI DMA irq status */ +# define UNIV_LINT_STAT_VIRQ7 (1<<7) /* VIRQ7 status */ +# define UNIV_LINT_STAT_VIRQ6 (1<<6) /* VIRQ6 status */ +# define UNIV_LINT_STAT_VIRQ5 (1<<5) /* VIRQ5 status */ +# define UNIV_LINT_STAT_VIRQ4 (1<<4) /* VIRQ4 status */ +# define UNIV_LINT_STAT_VIRQ3 (1<<3) /* VIRQ3 status */ +# define UNIV_LINT_STAT_VIRQ2 (1<<2) /* VIRQ2 status */ +# define UNIV_LINT_STAT_VIRQ1 (1<<1) /* VIRQ1 status */ +# define UNIV_LINT_STAT_VOWN (1<<0) /* VOWN status */ +# define UNIV_LINT_STAT_CLR (0xfff7ff)/* Clear all status bits */ + +/* PCI (local) interrupt map 0 register */ +#define UNIV_REGOFF_LINT_MAP0 0x308 /* mapping of VME IRQ sources to PCI irqs */ +# define UNIV_LINT_MAP0_VIRQ7(lint) (((lint)&0x7)<<(7*4)) +# define UNIV_LINT_MAP0_VIRQ6(lint) (((lint)&0x7)<<(6*4)) +# define UNIV_LINT_MAP0_VIRQ5(lint) (((lint)&0x7)<<(5*4)) +# define UNIV_LINT_MAP0_VIRQ4(lint) (((lint)&0x7)<<(4*4)) +# define UNIV_LINT_MAP0_VIRQ3(lint) (((lint)&0x7)<<(3*4)) +# define UNIV_LINT_MAP0_VIRQ2(lint) (((lint)&0x7)<<(2*4)) +# define UNIV_LINT_MAP0_VIRQ1(lint) (((lint)&0x7)<<(1*4)) +# define UNIV_LINT_MAP0_VOWN(lint) (((lint)&0x7)<<(0*4)) + +#define UNIV_REGOFF_LINT_MAP1 0x30c /* mapping of internal / VME IRQ sources to PCI irqs */ +# define UNIV_LINT_MAP1_ACFAIL(lint) (((lint)&0x7)<<(7*4)) +# define UNIV_LINT_MAP1_SYSFAIL(lint) (((lint)&0x7)<<(6*4)) +# define UNIV_LINT_MAP1_SW_INT(lint) (((lint)&0x7)<<(5*4)) +# define UNIV_LINT_MAP1_SW_IACK(lint) (((lint)&0x7)<<(4*4)) +# define UNIV_LINT_MAP1_VERR(lint) (((lint)&0x7)<<(2*4)) +# define UNIV_LINT_MAP1_LERR(lint) (((lint)&0x7)<<(1*4)) +# define UNIV_LINT_MAP1_DMA(lint) (((lint)&0x7)<<(0*4)) + +/* enabling of generation of VME bus IRQs, TODO */ +#define UNIV_REGOFF_VINT_EN 0x310 +# define UNIV_VINT_EN_DISABLE_ALL 0 + +/* status of generation of VME bus IRQs, TODO */ +#define UNIV_REGOFF_VINT_STAT 0x314 +# define UNIV_VINT_STAT_LINT(lint) (1<<((lint)&7)) +# define UNIV_VINT_STAT_LINT_MASK (0xff) +# define UNIV_VINT_STAT_CLR (0xfe0f17ff) +#define UNIV_REGOFF_VINT_MAP0 0x318 /* VME destination of PCI IRQ source, TODO */ +#define UNIV_REGOFF_VINT_MAP1 0x31c /* VME destination of PCI IRQ source, TODO */ +#define UNIV_REGOFF_VINT_STATID 0x320 /* our status/id response to IACK, TODO */ + +#define UNIV_REGOFF_VIRQ1_STATID 0x324 /* status/id of VME IRQ level 1 */ +#define UNIV_REGOFF_VIRQ2_STATID 0x328 /* status/id of VME IRQ level 2 */ +#define UNIV_REGOFF_VIRQ3_STATID 0x32c /* status/id of VME IRQ level 3 */ +#define UNIV_REGOFF_VIRQ4_STATID 0x330 /* status/id of VME IRQ level 4 */ +#define UNIV_REGOFF_VIRQ5_STATID 0x334 /* status/id of VME IRQ level 5 */ +#define UNIV_REGOFF_VIRQ6_STATID 0x338 /* status/id of VME IRQ level 6 */ +#define UNIV_REGOFF_VIRQ7_STATID 0x33c /* status/id of VME IRQ level 7 */ +# define UNIV_VIRQ_ERR (1<<8) /* set if universe encountered a bus error when doing IACK */ +# define UNIV_VIRQ_STATID_MASK (0xff) + +#define UNIV_REGOFF_LINT_MAP2 0x340 /* mapping of internal sources to PCI irqs */ +# define UNIV_LINT_MAP2_LM3(lint) (((lint)&0x7)<<7*4) /* location monitor 3 */ +# define UNIV_LINT_MAP2_LM2(lint) (((lint)&0x7)<<6*4) /* location monitor 2 */ +# define UNIV_LINT_MAP2_LM1(lint) (((lint)&0x7)<<5*4) /* location monitor 1 */ +# define UNIV_LINT_MAP2_LM0(lint) (((lint)&0x7)<<4*4) /* location monitor 0 */ +# define UNIV_LINT_MAP2_MBOX3(lint) (((lint)&0x7)<<3*4) /* mailbox 3 */ +# define UNIV_LINT_MAP2_MBOX2(lint) (((lint)&0x7)<<2*4) /* mailbox 2 */ +# define UNIV_LINT_MAP2_MBOX1(lint) (((lint)&0x7)<<1*4) /* mailbox 1 */ +# define UNIV_LINT_MAP2_MBOX0(lint) (((lint)&0x7)<<0*4) /* mailbox 0 */ + +#define UNIV_REGOFF_VINT_MAP2 0x344 /* mapping of internal sources to VME irqs */ +# define UNIV_VINT_MAP2_MBOX3(vint) (((vint)&0x7)<<3*4) /* mailbox 3 */ +# define UNIV_VINT_MAP2_MBOX2(vint) (((vint)&0x7)<<2*4) /* mailbox 2 */ +# define UNIV_VINT_MAP2_MBOX1(vint) (((vint)&0x7)<<1*4) /* mailbox 1 */ +# define UNIV_VINT_MAP2_MBOX0(vint) (((vint)&0x7)<<0*4) /* mailbox 0 */ + +#define UNIV_REGOFF_MBOX0 0x348 /* mailbox 0 */ +#define UNIV_REGOFF_MBOX1 0x34c /* mailbox 1 */ +#define UNIV_REGOFF_MBOX2 0x350 /* mailbox 2 */ +#define UNIV_REGOFF_MBOX3 0x354 /* mailbox 3 */ + +#define UNIV_REGOFF_SEMA0 0x358 /* semaphore 0 */ +#define UNIV_REGOFF_SEMA1 0x35c /* semaphore 0 */ +/* TODO define semaphore register bits */ + +#define UNIV_REGOFF_MAST_CTL 0x400 /* master control register */ +# define UNIV_MAST_CTL_MAXRTRY(val) (((val)&0xf)<<7*4) /* max # of pci master retries */ +# define UNIV_MAST_CTL_PWON(val) (((val)&0xf)<<6*4) /* posted write xfer count */ +# define UNIV_MAST_CTL_VRL(val) (((val)&0x3)<<22) /* VME bus request level */ +# define UNIV_MAST_CTL_VRM (1<<21) /* bus request mode (demand = 0, fair = 1) */ +# define UNIV_MAST_CTL_VREL (1<<20) /* bus release mode (when done = 0, on request = 1) */ +# define UNIV_MAST_CTL_VOWN (1<<19) /* bus ownership (release = 0, acquire/hold = 1) */ +# define UNIV_MAST_CTL_VOWN_ACK (1<<18) /* bus ownership (not owned = 0, acquired/held = 1) */ +# define UNIV_MAST_CTL_PABS(val) (((val)&0x3)<<3*4) /* PCI aligned burst size (32,64,128 byte / 0x3 is reserved) */ +# define UNIV_MAST_CTL_BUS_NO(val) (((val)&0xff)<<0*4) /* PCI bus number */ + +#define UNIV_REGOFF_MISC_CTL 0x404 /* misc control register */ +# define UNIV_MISC_CTL_VBTO(val) (((val)&0x7)<<7*4) /* VME bus timeout (0=disable, 16*2^(val-1) us) */ +# define UNIV_MISC_CTL_VARB (1<<26) /* VME bus arbitration mode (0=round robin, 1= priority) */ +# define UNIV_MISC_CTL_VARBTO(val) (((val)&0x3)<<6*4) /* arbitration time out: disable, 16us, 256us, reserved */ +# define UNIV_MISC_CTL_SW_LRST (1<<23) /* software PCI reset */ +# define UNIV_MISC_CTL_SW_SYSRST (1<<22) /* software VME reset */ +# define UNIV_MISC_CTL_BI (1<<20) /* BI mode */ +# define UNIV_MISC_CTL_ENGBI (1<<19) /* enable global BI mode initiator */ +# define UNIV_MISC_CTL_SYSCON (1<<17) /* (R/W) 1:universe is system controller */ +# define UNIV_MISC_CTL_V64AUTO (1<<16) /* (R/W) 1:initiate VME64 auto id slave participation */ + +/* Location Monitor control register */ +#define UNIV_REGOFF_LM_CTL 0xf64 +# define UNIV_LM_CTL_EN (1<<31) /* image enable */ +# define UNIV_LM_CTL_PGM (1<<23) /* program AM */ +# define UNIV_LM_CTL_DATA (1<<22) /* data AM */ +# define UNIV_LM_CTL_SUPER (1<<21) /* supervisor AM */ +# define UNIV_LM_CTL_USER (1<<20) /* user AM */ +# define UNIV_LM_CTL_VAS_A16 (0<<16) /* A16 */ +# define UNIV_LM_CTL_VAS_A24 (1<<16) /* A16 */ +# define UNIV_LM_CTL_VAS_A32 (2<<16) /* A16 */ + +/* Location Monitor base address */ +#define UNIV_REGOFF_LM_BS 0xf68 + +/* VMEbus register access image control register */ +#define UNIV_REGOFF_VRAI_CTL 0xf70 +# define UNIV_VRAI_CTL_EN (1<<31) /* image enable */ +# define UNIV_VRAI_CTL_PGM (1<<23) /* program AM */ +# define UNIV_VRAI_CTL_DATA (1<<22) /* data AM */ +# define UNIV_VRAI_CTL_SUPER (1<<21) /* supervisor AM */ +# define UNIV_VRAI_CTL_USER (1<<20) /* user AM */ +# define UNIV_VRAI_CTL_VAS_A16 (0<<16) /* A16 */ +# define UNIV_VRAI_CTL_VAS_A24 (1<<16) /* A16 */ +# define UNIV_VRAI_CTL_VAS_A32 (2<<16) /* A16 */ + +/* VMEbus register acces image base address register */ +#define UNIV_REGOFF_VRAI_BS 0xf74 + +/* VMEbus CSR control register */ +#define UNIV_REGOFF_VCSR_CTL 0xf80 +# define UNIV_VCSR_CTL_EN (1<<31) /* image enable */ +# define UNIV_VCSR_CTL_LAS_PCI_MEM (0<<0) /* pci mem space */ +# define UNIV_VCSR_CTL_LAS_PCI_IO (1<<0) /* pci IO space */ +# define UNIV_VCSR_CTL_LAS_PCI_CFG (2<<0) /* pci config space */ + +/* VMEbus CSR translation offset */ +#define UNIV_REGOFF_VCSR_TO 0xf84 + +/* VMEbus AM code error log */ +#define UNIV_REGOFF_V_AMERR 0xf88 +# define UNIV_V_AMERR_AMERR(reg) (((reg)>>26)&0x3f) /* extract error log code */ +# define UNIV_V_AMERR_IACK (1<<25) /* VMEbus IACK signal */ +# define UNIV_V_AMERR_M_ERR (1<<24) /* multiple errors occurred */ +# define UNIV_V_AMERR_V_STAT (1<<23) /* log status valid (write 1 to clear) */ + +/* VMEbus address error log */ +#define UNIV_REGOFF_VAERR 0xf8c /* address of fault address (if MERR_V_STAT valid) */ + +/* VMEbus CSR bit clear register */ +#define UNIV_REGOFF_VCSR_CLR 0xff4 +# define UNIV_VCSR_CLR_RESET (1<<31) /* read/negate LRST (can only be written from VME bus */ +# define UNIV_VCSR_CLR_SYSFAIL (1<<30) /* read/negate SYSFAIL */ +# define UNIV_VCSR_CLR_FAIL (1<<29) /* read: board has failed */ + +/* VMEbus CSR bit set register */ +#define UNIV_REGOFF_VCSR_SET (0xff8) +# define UNIV_VCSR_SET_RESET (1<<31) /* read/assert LRST (can only be written from VME bus */ +# define UNIV_VCSR_SET_SYSFAIL (1<<30) /* read/assert SYSFAIL */ +# define UNIV_VCSR_SET_FAIL (1<<29) /* read: board has failed */ + +/* VMEbus CSR base address register */ +#define UNIV_REGOFF_VCSR_BS 0xffc +#define UNIV_VCSR_BS_MASK (0xfff80000) + +#ifdef __cplusplus +extern "C" { +#endif + +/* base address and IRQ line of 1st universe bridge + * NOTE: vmeUniverseInit() must be called before + * these may be used. + */ +extern volatile LERegister *vmeUniverse0BaseAddr; +extern int vmeUniverse0PciIrqLine; + + +/* Initialize the driver */ +int +vmeUniverseInit(void); + +/* setup the universe chip, i.e. disable most of its + * mappings, reset interrupts etc. + */ +void +vmeUniverseReset(void); + +/* avoid pulling stdio.h into this header. + * Applications that want a declaration of the + * following routines should + * #include + * #define _VME_UNIVERSE_DECLARE_SHOW_ROUTINES + * #include + */ +#ifdef _VME_UNIVERSE_DECLARE_SHOW_ROUTINES +/* print the current configuration of all master ports to + * f (stderr if NULL) + */ +void +vmeUniverseMasterPortsShow(FILE *f); + +/* print the current configuration of all slave ports to + * f (stderr if NULL) + */ +void +vmeUniverseSlavePortsShow(FILE *f); +#else +void +vmeUniverseMasterPortsShow(); +void +vmeUniverseSlavePortsShow(); +#endif + +/* disable all master or slave ports, respectively */ +void +vmeUniverseDisableAllMasters(void); + +void +vmeUniverseDisableAllSlaves(void); + +/* configure a master port + * + * port: port number 0..3 (0..7 for a UniverseII) + * + * address_space: vxWorks compliant addressing mode identifier + * (see vme.h). The most important are: + * 0x0d - A32, Sup, Data + * 0x3d - A24, Sup, Data + * 0x2d - A16, Sup, Data + * additionally, the value 0 is accepted; it will + * disable this port. + * vme_address: address on the vme_bus of this port. + * local_address: address on the pci_bus of this port. + * length: size of this port. + * + * NOTE: the addresses and length parameters must be aligned on a + * 2^16 byte (0x10000) boundary, except for port 4 (only available + * on a UniverseII), where the alignment can be 4k (4096). + * + * RETURNS: 0 on success, -1 on failure. Error messages printed to stderr. + */ + +int +vmeUniverseMasterPortCfg( + unsigned long port, + unsigned long address_space, + unsigned long vme_address, + unsigned long local_address, + unsigned long length); + +/* translate an address through the bridge + * + * vmeUniverseLocalToBusAdrs() yields a VME a address that reflects + * a local memory location as seen from the VME bus through the universe + * VME slave. + * + * likewise does vmeUniverseBusToLocalAdrs() translate a VME bus addr + * (through the VME master) to the PCI side of the bridge. + * + * a valid address space modifier must be specified. + * + * RETURNS: translated address in *pbusAdrs / *plocalAdrs + * + * 0: success + * -1: address/modifier not found in any bridge port + * -2: invalid modifier + */ +int +vmeUniverseLocalToBusAdrs(unsigned long am, unsigned long localAdrs, unsigned long *pbusAdrs); + +int +vmeUniverseBusToLocalAdrs(unsigned long am, unsigned long busAdrs, unsigned long *plocalAdrs); + + +/* configure a VME slave (PCI master) port */ +int +vmeUniverseSlavePortCfg( + unsigned long port, + unsigned long address_space, + unsigned long vme_address, + unsigned long local_address, + unsigned long length); + +/* start a (direct, not linked) DMA transfer + * + * NOTE: DCTL and DGCS must be set up + * prior to calling this routine + */ +int +vmeUniverseStartDMA( + unsigned long local_addr, + unsigned long vme_addr, + unsigned long count); + +/* read a register in PCI memory space + * (offset being one of the declared constants) + */ +unsigned long +vmeUniverseReadReg(unsigned long offset); + +/* write a register in PCI memory space */ +void +vmeUniverseWriteReg(unsigned long value, unsigned long offset); + +/* convert an array of unsigned long values to LE (as needed + * when the universe reads e.g. DMA descriptors from PCI) + */ +void +vmeUniverseCvtToLE(unsigned long *ptr, unsigned long num); + +/* reset the VME bus */ +static inline void +vmeUniverseResetBus(void) +{ + vmeUniverseWriteReg( + vmeUniverseReadReg(UNIV_REGOFF_MISC_CTL) | UNIV_MISC_CTL_SW_SYSRST, + UNIV_REGOFF_MISC_CTL); +} + +#ifdef __rtems +/* VME Interrupt Handler functionality */ + +/* we dont use the current RTEMS/BSP interrupt API for the + * following reasons: + * + * - RTEMS/BSP API does not pass an argument to the ISR :-( :-( + * - no separate vector space for VME vectors. Some vectors would + * have to overlap with existing PCI/ISA vectors. + * - RTEMS/BSP API allocates a structure for every possible vector + * - the irq_on(), irq_off() functions add more bloat than helping. + * They are (currently) only used by the framework to disable + * interrupts at the device level before removing a handler + * and to enable interrupts after installing a handler. + * These operations may as well be done by the driver itself. + * + * Hence, we maintain our own (VME) handler table and hook our PCI + * handler into the standard RTEMS/BSP environment. Our handler then + * dispatches VME interrupts. + */ + +typedef void (*VmeUniverseISR) (void *usrArg, unsigned long vector); + +/* install a handler for a VME vector + * RETURNS 0 on success, nonzero on failure. + */ +int +vmeUniverseInstallISR(unsigned long vector, VmeUniverseISR handler, void *usrArg); + +/* remove a handler for a VME vector. The vector and usrArg parameters + * must match the respective parameters used when installing the handler. + * RETURNS 0 on success, nonzero on failure. + */ +int +vmeUniverseRemoveISR(unsigned long vector, VmeUniverseISR handler, void *usrArg); + +/* query for the currently installed ISR and usr parameter at a given vector + * RETURNS: ISR or 0 (vector too big or no ISR installed) + */ +VmeUniverseISR +vmeUniverseISRGet(unsigned long vector, void **parg); + +/* utility routines to enable/disable a VME IRQ level + * + * RETURNS 0 on success, nonzero on failure + */ +int +vmeUniverseIntEnable(unsigned int level); +int +vmeUniverseIntDisable(unsigned int level); + + +/* use this special vector to connect a handler to the + * universe specific interrupts (such as "DMA done", + * VOWN, error irqs etc.) + * NOTE: The wrapper clears all status LINT bits (except + * for regular VME irqs). Also note that it is the user's + * responsibility to enable the necessary interrupts in + * LINT_EN + */ +#define UNIV_SPECIAL_IRQ_VECTOR 256 + +/* the universe interrupt handler is capable of routing all sorts of + * (VME) interrupts to 8 different lines (some of) which may be hooked up + * in a (board specific) way to a PIC. + * + * This driver only supports at most two lines. It routes the 7 VME + * interrupts to the main line and optionally, it routes the 'special' + * interrupts generated by the universe itself (DMA done, VOWN etc.) + * to a second line. If no second line is available, all IRQs are routed + * to the main line. + * + * Because the driver has no way to figure out which lines are actually + * wired to the PIC, this information has to be provided when installing + * the manager. + * + * Hence the manager sets up routing VME interrupts to 1 or 2 universe + * OUTPUTS. However, it must also be told to which PIC INPUTS they + * are wired. The first PIC input line is read from PCI config space + * but the second must be passed to this routine. + * + * PARAMETERS: + * vmeIRQunivOut: to which output pin (of the universe) should the 7 + * VME irq levels be routed. + * specialIRQunivOut: to which output pin (of the universe) should the + * internally irqs be routed. Use 'vmeIRQunivOut' + * if < 0. + * specialIrqPicLine: specifies to which PIC input the 'special' output + * pin is wired. The wiring of the 'vmeIRQunivOut' to + * the PIC is determined by reading PCI config space. + * + * RETURNS: 0 on success, -1 on failure. + * + */ +int +vmeUniverseInstallIrqMgr(int vmeIrqUnivOut, int specialIrqUnivOut, int specialIrqPicLine); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif -- cgit v1.2.3