summaryrefslogtreecommitdiffstats
path: root/bsps
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-03 16:41:16 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-09 07:09:46 +0200
commit814eccb4cf0e5433bd884a48dfa8e219bb2d0dd0 (patch)
tree2e079ca82187e519b3be56eb25057330b8344648 /bsps
parentbsp: Move umon support to bsps (diff)
downloadrtems-814eccb4cf0e5433bd884a48dfa8e219bb2d0dd0.tar.bz2
bsps: Move VME support to bsps
The VME support is only used by powerpc BSPs. This patch is a part of the BSP source reorganization. Update #3285.
Diffstat (limited to 'bsps')
-rw-r--r--bsps/headers.am5
-rw-r--r--bsps/powerpc/headers.am5
-rw-r--r--bsps/powerpc/include/bsp/vmeTsi148.h (renamed from bsps/include/bsp/vmeTsi148.h)0
-rw-r--r--bsps/powerpc/include/bsp/vmeTsi148DMA.h (renamed from bsps/include/bsp/vmeTsi148DMA.h)0
-rw-r--r--bsps/powerpc/include/bsp/vmeUniverse.h (renamed from bsps/include/bsp/vmeUniverse.h)0
-rw-r--r--bsps/powerpc/include/bsp/vmeUniverseDMA.h (renamed from bsps/include/bsp/vmeUniverseDMA.h)0
-rw-r--r--bsps/powerpc/include/bsp/vme_am_defs.h (renamed from bsps/include/bsp/vme_am_defs.h)0
-rw-r--r--bsps/powerpc/shared/vme-sources.am5
-rw-r--r--bsps/powerpc/shared/vme/README10
-rw-r--r--bsps/powerpc/shared/vme/README.porting96
-rw-r--r--bsps/powerpc/shared/vme/README.universe65
-rw-r--r--bsps/powerpc/shared/vme/bspVmeDmaList.c334
-rw-r--r--bsps/powerpc/shared/vme/bspVmeDmaListP.h107
-rw-r--r--bsps/powerpc/shared/vme/doxygen.h7
-rw-r--r--bsps/powerpc/shared/vme/vmeTsi148.c2695
-rw-r--r--bsps/powerpc/shared/vme/vmeUniverse.c2504
-rw-r--r--bsps/powerpc/shared/vme/vme_universe.c436
-rw-r--r--bsps/powerpc/shared/vme/vmeconfig.c142
18 files changed, 6406 insertions, 5 deletions
diff --git a/bsps/headers.am b/bsps/headers.am
index ab7fa34c58..294d7869a9 100644
--- a/bsps/headers.am
+++ b/bsps/headers.am
@@ -23,11 +23,6 @@ include_bsp_HEADERS += ../../bsps/include/bsp/stackalloc.h
include_bsp_HEADERS += ../../bsps/include/bsp/u-boot.h
include_bsp_HEADERS += ../../bsps/include/bsp/uart-output-char.h
include_bsp_HEADERS += ../../bsps/include/bsp/utility.h
-include_bsp_HEADERS += ../../bsps/include/bsp/vmeTsi148.h
-include_bsp_HEADERS += ../../bsps/include/bsp/vmeTsi148DMA.h
-include_bsp_HEADERS += ../../bsps/include/bsp/vmeUniverse.h
-include_bsp_HEADERS += ../../bsps/include/bsp/vmeUniverseDMA.h
-include_bsp_HEADERS += ../../bsps/include/bsp/vme_am_defs.h
include_libchipdir = $(includedir)/libchip
include_libchip_HEADERS =
diff --git a/bsps/powerpc/headers.am b/bsps/powerpc/headers.am
index 17122404e3..ac73dce08c 100644
--- a/bsps/powerpc/headers.am
+++ b/bsps/powerpc/headers.am
@@ -25,6 +25,11 @@ include_bsp_HEADERS += ../../../../../bsps/powerpc/include/bsp/tsec.h
include_bsp_HEADERS += ../../../../../bsps/powerpc/include/bsp/u-boot-board-info.h
include_bsp_HEADERS += ../../../../../bsps/powerpc/include/bsp/uart.h
include_bsp_HEADERS += ../../../../../bsps/powerpc/include/bsp/vectors.h
+include_bsp_HEADERS += ../../../../../bsps/powerpc/include/bsp/vmeTsi148.h
+include_bsp_HEADERS += ../../../../../bsps/powerpc/include/bsp/vmeTsi148DMA.h
+include_bsp_HEADERS += ../../../../../bsps/powerpc/include/bsp/vmeUniverse.h
+include_bsp_HEADERS += ../../../../../bsps/powerpc/include/bsp/vmeUniverseDMA.h
+include_bsp_HEADERS += ../../../../../bsps/powerpc/include/bsp/vme_am_defs.h
include_bsp_HEADERS += ../../../../../bsps/powerpc/include/bsp/vpd.h
include_libcpudir = $(includedir)/libcpu
diff --git a/bsps/include/bsp/vmeTsi148.h b/bsps/powerpc/include/bsp/vmeTsi148.h
index 6183940a2d..6183940a2d 100644
--- a/bsps/include/bsp/vmeTsi148.h
+++ b/bsps/powerpc/include/bsp/vmeTsi148.h
diff --git a/bsps/include/bsp/vmeTsi148DMA.h b/bsps/powerpc/include/bsp/vmeTsi148DMA.h
index da7c99302b..da7c99302b 100644
--- a/bsps/include/bsp/vmeTsi148DMA.h
+++ b/bsps/powerpc/include/bsp/vmeTsi148DMA.h
diff --git a/bsps/include/bsp/vmeUniverse.h b/bsps/powerpc/include/bsp/vmeUniverse.h
index 7cb9f8d2de..7cb9f8d2de 100644
--- a/bsps/include/bsp/vmeUniverse.h
+++ b/bsps/powerpc/include/bsp/vmeUniverse.h
diff --git a/bsps/include/bsp/vmeUniverseDMA.h b/bsps/powerpc/include/bsp/vmeUniverseDMA.h
index d0a3d6f0e7..d0a3d6f0e7 100644
--- a/bsps/include/bsp/vmeUniverseDMA.h
+++ b/bsps/powerpc/include/bsp/vmeUniverseDMA.h
diff --git a/bsps/include/bsp/vme_am_defs.h b/bsps/powerpc/include/bsp/vme_am_defs.h
index efa28b3aa0..efa28b3aa0 100644
--- a/bsps/include/bsp/vme_am_defs.h
+++ b/bsps/powerpc/include/bsp/vme_am_defs.h
diff --git a/bsps/powerpc/shared/vme-sources.am b/bsps/powerpc/shared/vme-sources.am
new file mode 100644
index 0000000000..62ce3fbcf6
--- /dev/null
+++ b/bsps/powerpc/shared/vme-sources.am
@@ -0,0 +1,5 @@
+libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/vme/bspVmeDmaList.c
+libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/vme/vmeconfig.c
+libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/vme/vmeTsi148.c
+libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/vme/vme_universe.c
+libbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/vme/vmeUniverse.c
diff --git a/bsps/powerpc/shared/vme/README b/bsps/powerpc/shared/vme/README
new file mode 100644
index 0000000000..e2e0020026
--- /dev/null
+++ b/bsps/powerpc/shared/vme/README
@@ -0,0 +1,10 @@
+libbsp/shared/vmeUniverse/VME.h: VME API; BSP and bridge-chip independent
+VMEConfig.h: defines BSP specific constants for VME configuration
+vmeconfig.c configures the VME bridge using the VME.h API calls
+ and BSP specific constants from VMEConfig.h.
+ Independent of the bridge chip, however.
+vme_universe.c: implements VME.h for the vmeUniverse driver.
+vme_universe_dma.c: implements VMEDMA.h for the vmeUniverse driver.
+
+o other universe BSP --> use its own VMEConfig.h; may reuse vmeconfig.c, vme_universe.c
+o other non-universe BSP --> use its own VMEConfig.h and vme_xxx.c; may reuse vmeconfig.c
diff --git a/bsps/powerpc/shared/vme/README.porting b/bsps/powerpc/shared/vme/README.porting
new file mode 100644
index 0000000000..6873f5b1d6
--- /dev/null
+++ b/bsps/powerpc/shared/vme/README.porting
@@ -0,0 +1,96 @@
+#
+
+NOTE: (T.S, 2007/1) The information in this file is outdated
+ (but some portions may still be useful). Some more information
+ about how to use the Universe and Tsi148 drivers in new BSPs
+ can be found in
+
+ README.universe,
+ libbsp/powerpc/shared/vme/VMEConfig.h,
+
+ source files in this directory and libbsp/powerpc/shared/vme
+
+The vmeUniverse driver needs some support from the BSP for
+
+a) PCI configuration space access
+b) PCI interrupt acknowledgement
+c) PCI interrupt handler installation
+
+The driver was developed using the powerpc/shared/ BSP
+(it also supports vxWorks) and by default uses that BSP's
+a) PCI access API
+b,c) irq handling API (AKA 'new' style BSP_install_rtems_irq_handler()
+ API).
+
+Some hooks exist in the driver to ease porting to other BSPs.
+The following information has been assembled when answering a
+question regarding a ppcn_60x BSP port:
+
+I looked through the ppcn_60x BSP. Here's what I found:
+
+ - this BSP does NOT adhere to neither the 'old' nor the 'new' API
+ but provides its own (startup/setvec.c: set_vector()).
+ - the BSP has a 'driver' for vmeUniverse although mine is far more
+ complete (including support for VME interrupts, DMA etc.).
+ - Porting my driver to your BSP should not be too hard:
+
+ 1) vmeUniverse needs PCI configuration space support from the
+ BSP:
+ a) a routine 'pciFindDevice' (need to be macro-aliased
+ to the proper routine/wrapper of your BSP) who scans
+ PCI config space for the universe bridge.
+ You could add 'libbsp/powerpc/shared/pci/pcifinddevice.c'
+ to your BSP substituting the pci_read_config_xxx calls
+ by the ones present on your BSP (see step 2))
+ b) routines to read PCI config registers (byte and longword)
+ [on your BSP these are PCIConfigRead32/PCIConfigRead8;
+ hence you could replace the macros on top with
+ #define pciConfigInLong PCIConfigRead32
+ 2) vmeUniverse needs to know how to acknowledge a PCI interrupt
+ In your case, nothing needs to be done
+ #define BSP_PIC_DO_EOI do {} while (0)
+ 3) Install the VME ISR dispatcher: replace the 'new' style
+ interrupt installer (BSP_install_rtems_irq_handler()) by
+ a proper call to 'set_vector()'
+ 4) I might have missed something...
+
+I attach the latest version of the vmeUniverse driver in case you want
+to try to do the port (should be easy).
+
+For the sake of ease of maintenance, I just added a few hooks making it
+possible to override some things without having to modify the driver code.
+
+ 1,2) PCI config space access macros may be overriden via CFLAGS
+ when compiling vmeUniverse.c, hence:
+ CFLAGS += -DBSP_PIC_DO_EOI=do{}while(0)
+ CFLAGS += -DBSP_PCI_CONFIG_IN_LONG=PCIConfigRead32
+ CFLAGS += -DBSP_PCI_CONFIG_IN_BYTE=PCIConfigRead8
+ (you still need to supply pci_find_device)
+ 3) create your own version of vmeUniverseInstallIrqMgr():
+ copy to a separate file and replace
+ BSP_rtems_install_irq_handler() by a proper call to set_vector.
+
+ 4) Send me email :-)
+
+USAGE NOTE: To fully initialize the driver, the following steps can/must
+be performed:
+
+ vmeUniverseInit(); /* MANDATORY: Driver Initialization */
+ vmeUniverseReset(); /* OPTIONAL: Reset most registers to a known state;
+ * if this step is omitted, firmware setup is
+ * preserved
+ */
+ vmeUniverseMasterPortCfg(...); /* OPTIONAL: setup the master windows
+ * (current setup preserved if omitted)
+ */
+ vmeUniverseSlavePortCfg(...); /* OPTIONAL: setup the slave windows
+ * (current setup preserved if omitted)
+ */
+ vmeUniverseInstallIrqMgr(); /* NEEDED FOR VME INTERRUPT SUPPRORT
+ * initialize the interrupt manager.
+ * NOTE: you need to call your own
+ * version of this routine here
+ */
+
+For an example of init/setup, consult libbsp/powerpc/shared/vme/vmeconfig.c
+
diff --git a/bsps/powerpc/shared/vme/README.universe b/bsps/powerpc/shared/vme/README.universe
new file mode 100644
index 0000000000..1059d8c806
--- /dev/null
+++ b/bsps/powerpc/shared/vme/README.universe
@@ -0,0 +1,65 @@
+The tundra drivers are in a separate subdir
+because they are maintained at SSRL outside of the
+rtems CVS tree. The directory is called 'vmeUniverse'
+for historic reasons. 'tundra' would be better
+since we now support the tundra tsi148 as well...
+
+Till Straumann <strauman@slac.stanford.edu> 1/2002, 2005, 2007
+
+A BSP that wants to use these drivers
+must implement the following headers / functionality:
+ - <bsp/pci.h> offering an API like 'libbsp/powerpc/shared/pci'
+ - <bsp/irq.h> offering the 'new style' RTEMS irq API
+ (like 'libbsp/powerpc/shared/irq').
+ - <libcpu/io.h> for the I/O operations (out_le32,in_le32, ..., out_be32,...)
+ - <libcpu/byteorder.h> for byte-swapping (st_le32, ld_le32, ..., st_be32,...)
+ - glue code that implements the 'VME.h' and 'VMEDMA.h' APIs
+ using the vmeUniverse and/or vmeTsi148 driver code.
+ The 'glue' code initializes appropriate VME/PCI windows when booting
+ and installs the VME interrupt manager.
+
+ The 'glue' may also use the 'bspVmeDmaList' code to implement generic
+ parts of linked-list DMA.
+
+ Boards with a 'universe' chip may use a pretty generic version of
+ the glue code that is defined in libbsp/powerpc/shared/vmeconfig.c,
+ libbsp/powerpc/shared/vme_universe.c, and
+ libbsp/powerpc/shared/vme_universe_dma.c. The board-specific parameters
+ are defined in a single BSP-specific file 'VMEConfig.h'. That's where
+ the actual addresses of VME/PCI windows are configured and where
+ interrupt wires can be assigned etc.
+
+ Read libbsp/powerpc/shared/VMEConfig.h for more information and use
+ it as a template. Note that BSP implementors should try *not* to
+ clone 'vmeconfig.c' but use the constants in VMEConfig.h
+
+ - The BSP should export 'VME.h' and 'VMEDMA.h' to applications
+ and encourage them to only use the API defined there in order
+ to make application code driver-independent. This will ensure
+ seamless portability of applications between the universe and Tsi148
+ drivers.
+
+
+TESTING: A valuable tool for testing are the (substitute XXX for
+ 'Universe' or 'Tsi148') routines:
+ vmeXXXMapCRG()
+ maps the controller registers to VME space so you
+ can test if you successfully can read/write from VME.
+ You can read or DMA the PCI configuration registers
+ and compare to what you expect (beware of endianness).
+
+ vmeXXXIntLoopbackTest()
+ this installs an ISR and then asserts an IRQ on the VME
+ backplane so you can verify that your interrupt routing
+ and handling really works.
+
+NOTES: The universe may always issue MBLTs if a data width of 64-bit
+ is enabled (default for non-BLT addressing modes -- the
+ VME_AM_STD_xx_BLT / VME_AM_EXT_xx_BLT enforce 32-bit transfers).
+
+ Therefore, if you want to setup a outbound window that always
+ uses single cycles then you must explicitely request a data
+ width < 64, e.g.,
+
+ vmeUniverseMasterPortCfg(port, VME_AM_EXT_SUP_DATA | VME_MODE_DBW32, vme_addr, pci_addr, size);
+
diff --git a/bsps/powerpc/shared/vme/bspVmeDmaList.c b/bsps/powerpc/shared/vme/bspVmeDmaList.c
new file mode 100644
index 0000000000..73b398dda1
--- /dev/null
+++ b/bsps/powerpc/shared/vme/bspVmeDmaList.c
@@ -0,0 +1,334 @@
+/* bspVmeDmaList.c:
+ * implementation of generic parts of the 'linked-list VME DMA' API.
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software was created by
+ * Till Straumann <strauman@slac.stanford.edu>, 2006, 2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * This software was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define DEBUG
+#include <bsp/VMEDMA.h>
+#include <bsp/bspVmeDmaList.h>
+#include "bspVmeDmaListP.h"
+
+
+typedef struct VMEDmaListNodeRec_ {
+ VMEDmaListNode p, n; /* linkage */
+ DmaDescriptor d; /* real descriptor */
+ void *usrData;
+ VMEDmaListClass class; /* pointer to 'class' record */
+} VMEDmaListNodeRec;
+
+#define LCHUNK 10
+
+#ifdef DEBUG
+static void
+lprint(VMEDmaListNode d)
+{
+ printf("n 0x%08lx, p: 0x%08lx, n: 0x%08lx d: 0x%08lx\n",
+ (uint32_t)d, (uint32_t)d->p, (uint32_t)d->n, (uint32_t)d->d);
+}
+#endif
+
+static VMEDmaListNode
+lalloc(VMEDmaListClass pc)
+{
+VMEDmaListNode rval;
+int i;
+
+ if ( !pc->freeList ) {
+ /* alloc block of 10 descriptors */
+ pc->freeList = calloc( (LCHUNK), sizeof(*pc->freeList));
+
+ if ( ! (pc->freeList) ) {
+ return 0;
+ }
+
+ /* link together and set 'class' pointer */
+ for (i=0; i<(LCHUNK)-1; i++) {
+ pc->freeList[i].n = &pc->freeList[i+1];
+ pc->freeList[i].class = pc;
+ }
+ pc->freeList[i].n = 0;
+ pc->freeList[i].class = pc;
+
+ /* Allocate 'real' descriptor memory */
+ if ( pc->desc_alloc ) {
+ for (i=0; i<(LCHUNK); i++) {
+ if ( ! (pc->freeList[i].d = pc->desc_alloc()) ) {
+ int j;
+ if ( pc->desc_free ) {
+ for (j=0; j<i; j++)
+ pc->desc_free(pc->freeList[i].d);
+ }
+ free(pc->freeList);
+ pc->freeList = 0;
+ return 0;
+ }
+ }
+ } else {
+ int blksize;
+ uint32_t algnmsk = pc->desc_align - 1;
+ char *memptr;
+
+ /* ignore their 'free' method */
+ pc->desc_free = 0;
+
+ blksize = (pc->desc_size + algnmsk) & ~algnmsk;
+
+ if ( ! (memptr = malloc(blksize*(LCHUNK) + pc->desc_align - 1)) ) {
+ free(pc->freeList);
+ pc->freeList = 0;
+ return 0;
+ }
+
+ /* align memory ptr; must not be freed() anymore */
+ memptr = (char*)( ((uint32_t)memptr + algnmsk) & ~ algnmsk );
+
+ for ( i = 0; i<(LCHUNK); i++, memptr+=blksize ) {
+ memset(memptr, 0, blksize);
+ pc->freeList[i].d = (DmaDescriptor)memptr;
+ }
+ }
+ }
+ rval = pc->freeList;
+ pc->freeList = pc->freeList->n;
+ rval->n = rval->p = 0;
+ return rval;
+}
+
+static int
+lfree(VMEDmaListNode d)
+{
+ if ( d->p || d->n )
+ return -1;
+ d->n = d->class->freeList;
+ d->class->freeList = d;
+ return 0;
+}
+
+static int
+lenq(VMEDmaListNode a, VMEDmaListNode d)
+{
+ if ( a ) {
+ /* enqueue */
+ if ( d->n || d->p )
+ return -1;
+ if ( (d->n = a->n) )
+ a->n->p = d;
+ d->p = a;
+ a->n = d;
+ } else {
+ /* dequeue */
+ if ( d->n )
+ d->n->p = d->p;
+ if ( d->p )
+ d->p->n = d->n;
+ d->n = d->p = 0;
+ }
+ return 0;
+}
+
+
+int
+BSP_VMEDmaListDescriptorStartTool(volatile void *controller, int channel, VMEDmaListNode n)
+{
+ if ( !n )
+ return -1;
+ return n->class->desc_start(controller, channel, n->d);
+}
+
+VMEDmaListNode
+BSP_VMEDmaListDescriptorSetupTool(
+ VMEDmaListNode n,
+ uint32_t attr_mask,
+ uint32_t xfer_mode,
+ uint32_t pci_addr,
+ uint32_t vme_addr,
+ uint32_t n_bytes)
+{
+ if ( !n )
+ return 0;
+
+ if ( n->class->desc_setup(n->d, attr_mask, xfer_mode, pci_addr, vme_addr, n_bytes) ) {
+ return 0;
+ }
+
+ return n;
+}
+
+VMEDmaListNode
+BSP_VMEDmaListDescriptorNewTool(
+ VMEDmaListClass pc,
+ uint32_t attr_mask,
+ uint32_t xfer_mode,
+ uint32_t pci_addr,
+ uint32_t vme_addr,
+ uint32_t n_bytes)
+{
+VMEDmaListNode n;
+
+ if ( !(n=lalloc(pc)) )
+ return 0; /* no memory */
+
+ if ( n->class->desc_init )
+ n->class->desc_init(n->d);
+
+ if ( n->class->desc_setup(n->d, attr_mask, xfer_mode, pci_addr, vme_addr, n_bytes) ) {
+ BSP_VMEDmaListDescriptorDestroy(n);
+ return 0;
+ }
+ return n;
+}
+
+int
+BSP_VMEDmaListDescriptorDestroy(BSP_VMEDmaListDescriptor p)
+{
+VMEDmaListNode d = p;
+ return lfree(d);
+}
+
+int
+BSP_VMEDmaListDestroy(BSP_VMEDmaListDescriptor p)
+{
+VMEDmaListNode d = p;
+VMEDmaListNode n;
+ while (d) {
+ n = d->n;
+ if ( BSP_VMEDmaListDescriptorEnq(0, d) ||
+ BSP_VMEDmaListDescriptorDestroy(d) )
+ return -1;
+ d = n;
+ }
+ return 0;
+}
+
+int
+BSP_VMEDmaListDescriptorEnq(BSP_VMEDmaListDescriptor p, BSP_VMEDmaListDescriptor q)
+{
+VMEDmaListNode anchor = p;
+VMEDmaListNode d = q;
+DmaDescriptorSetNxt setnxt = d->class->desc_setnxt;
+
+ if ( !anchor ) {
+ /* dequeue can't fail - we can update dnlal first (need d->p) */
+ if ( d->p )
+ setnxt(d->p->d, d->n ? d->n->d : 0);
+ /* paranoia */
+ setnxt(d->d, 0);
+ } else {
+ if ( d->class != anchor->class )
+ return -1;
+ }
+ if ( lenq(anchor, d) )
+ return -1;
+ /* update descriptor pointers */
+ if ( anchor ) {
+ setnxt(d->d, d->n ? d->n->d : 0);
+ setnxt(anchor->d, d->d);
+ }
+ return 0;
+}
+
+BSP_VMEDmaListDescriptor
+BSP_VMEDmaListDescriptorNext(BSP_VMEDmaListDescriptor p)
+{
+VMEDmaListNode d = p;
+ return d->n;
+}
+
+BSP_VMEDmaListDescriptor
+BSP_VMEDmaListDescriptorPrev(BSP_VMEDmaListDescriptor p)
+{
+VMEDmaListNode d = p;
+ return d->p;
+}
+
+void
+BSP_VMEDmaListDescriptorSetUsr(BSP_VMEDmaListDescriptor p, void *usrData)
+{
+VMEDmaListNode d = p;
+ d->usrData = usrData;
+}
+
+void *
+BSP_VMEDmaListDescriptorGetUsr(BSP_VMEDmaListDescriptor p)
+{
+VMEDmaListNode d = p;
+ return d->usrData;
+}
+
+int
+BSP_VMEDmaListRefresh(BSP_VMEDmaListDescriptor p)
+{
+VMEDmaListNode anchor = p;
+DmaDescriptorRefr desc_refr;
+VMEDmaListNode n;
+ if ( (desc_refr = anchor->class->desc_refr) ) {
+ for ( n = anchor; n; n = n->n ) {
+ desc_refr(n->d);
+ }
+ }
+ return 0;
+}
+
+#ifdef DEBUG
+void
+BSP_VMEDmaListDump(BSP_VMEDmaListDescriptor p)
+{
+VMEDmaListNode d = p;
+ while (d) {
+ printf("----------\n");
+ lprint(d);
+ if (d->class->desc_dump)
+ d->class->desc_dump(d->d);
+ d = d->n;
+ }
+}
+#endif
diff --git a/bsps/powerpc/shared/vme/bspVmeDmaListP.h b/bsps/powerpc/shared/vme/bspVmeDmaListP.h
new file mode 100644
index 0000000000..1a1f97b9ad
--- /dev/null
+++ b/bsps/powerpc/shared/vme/bspVmeDmaListP.h
@@ -0,0 +1,107 @@
+/**
+ * @file
+ *
+ * @ingroup shared_bspvmedmalistp
+ *
+ * @brief Private Interface to the bspVmeDmaList facility
+ */
+
+#ifndef BSP_VME_DMA_LIST_P_H
+#define BSP_VME_DMA_LIST_P_H
+
+#include <bsp/bspVmeDmaList.h>
+
+/*
+ * This is used by chip drivers to implement the
+ * 'class' members so that 'bspVmeDmaList' can access
+ * the device in an abstract manner.
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software was created by
+ * Till Straumann <strauman@slac.stanford.edu>, 2006, 2007
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * This software was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *DmaDescriptor;
+
+/**
+ * @defgroup shared_bspvmedmalistp member functions
+ *
+ * @ingroup shared_vmeuniverse
+ *
+ * @brief Member functions to be implemented by chip drivers
+ */
+
+typedef DmaDescriptor (*DmaDescriptorAlloc)(void);
+typedef void (*DmaDescriptorFree) (DmaDescriptor d);
+typedef void (*DmaDescriptorInit) (DmaDescriptor d);
+/* Setup takes the parameters declared in VMEDMA.h */
+typedef int (*DmaDescriptorSetup)(DmaDescriptor d, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
+typedef void (*DmaDescriptorSetNxt)(DmaDescriptor d, DmaDescriptor next);
+typedef int (*DmaDescriptorStart)(volatile void *controller_addr, int channel, DmaDescriptor);
+typedef int (*DmaDescriptorRefr) (DmaDescriptor);
+typedef void (*DmaDescriptorDump) (DmaDescriptor);
+
+
+typedef struct VMEDmaListClassRec_ {
+ int desc_size; /* size of a descritor */
+ int desc_align; /* alignment of a descriptor */
+ VMEDmaListNode freeList; /* list of free descriptors of this class, MUST be initialized to NULL */
+ DmaDescriptorAlloc desc_alloc; /* [optional, may be NULL] allocator for one descriptor */
+ DmaDescriptorFree desc_free; /* [optional, may be NULL] destructor for one descriptor */
+ DmaDescriptorInit desc_init; /* [optional, may be NULL] set stuff that don't change during lifetime */
+ DmaDescriptorSetNxt desc_setnxt;/* set 'NEXT' pointer in descriptor; mark as LAST if next == 0 */
+ DmaDescriptorSetup desc_setup; /* setup a descriptor */
+ DmaDescriptorStart desc_start; /* start list at a descriptor */
+ DmaDescriptorRefr desc_refr; /* refresh a descriptor */
+ DmaDescriptorDump desc_dump; /* dump a descriptor (for debugging) */
+} VMEDmaListClassRec;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bsps/powerpc/shared/vme/doxygen.h b/bsps/powerpc/shared/vme/doxygen.h
new file mode 100644
index 0000000000..88ded941ac
--- /dev/null
+++ b/bsps/powerpc/shared/vme/doxygen.h
@@ -0,0 +1,7 @@
+/**
+ * @defgroup shared_vmeuniverse SHARED VMEUNIVERSE Modules
+ *
+ * @ingroup bsp_shared
+ *
+ * @brief SHARED VMEUNIVERSE Modules
+ */ \ No newline at end of file
diff --git a/bsps/powerpc/shared/vme/vmeTsi148.c b/bsps/powerpc/shared/vme/vmeTsi148.c
new file mode 100644
index 0000000000..4e1893b593
--- /dev/null
+++ b/bsps/powerpc/shared/vme/vmeTsi148.c
@@ -0,0 +1,2695 @@
+/* Driver for the Tundra Tsi148 pci-vme bridge */
+
+/*
+ * Authorship
+ * ----------
+ * This software was created by
+ * Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * This software was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+
+#include <rtems.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <bsp/irq.h>
+#include <stdlib.h>
+#include <rtems/bspIo.h> /* printk */
+#include <rtems/error.h> /* printk */
+#include <rtems/pci.h>
+#include <bsp.h>
+#include <libcpu/byteorder.h>
+
+#define __INSIDE_RTEMS_BSP__
+#define _VME_TSI148_DECLARE_SHOW_ROUTINES
+
+#include <bsp/vmeTsi148.h>
+#include <bsp/VMEDMA.h>
+#include <bsp/vmeTsi148DMA.h>
+#include "bspVmeDmaListP.h"
+
+
+#define DEBUG
+
+#ifdef DEBUG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+/* The tsi has 4 'local' wires that can be hooked to a PIC */
+
+#define TSI_NUM_WIRES 4
+
+#define TSI148_NUM_OPORTS 8 /* number of outbound ports */
+#define TSI148_NUM_IPORTS 8 /* number of inbound ports */
+
+#define NUM_TSI_DEVS 2 /* number of instances supported */
+
+#define PCI_VENDOR_TUNDRA 0x10e3
+#define PCI_DEVICE_TSI148 0x0148
+
+#define TSI_OTSAU_SPACING 0x020
+
+#define TSI_OTSAU0_REG 0x100
+#define TSI_OTSAL0_REG 0x104
+#define TSI_OTEAU0_REG 0x108
+#define TSI_OTEAL0_REG 0x10c
+#define TSI_OTOFU0_REG 0x110
+#define TSI_OTOFL0_REG 0x114
+#define TSI_OTBS0_REG 0x118 /* 2eSST broadcast select */
+#define TSI_OTAT0_REG 0x11c
+#define TSI_OTSAU_REG(port) (TSI_OTSAU0_REG + ((port)<<5))
+#define TSI_OTSAL_REG(port) (TSI_OTSAL0_REG + ((port)<<5))
+#define TSI_OTEAU_REG(port) (TSI_OTEAU0_REG + ((port)<<5))
+#define TSI_OTEAL_REG(port) (TSI_OTEAL0_REG + ((port)<<5))
+#define TSI_OTOFU_REG(port) (TSI_OTOFU0_REG + ((port)<<5))
+#define TSI_OTOFL_REG(port) (TSI_OTOFL0_REG + ((port)<<5))
+#define TSI_OTBS_REG(port) (TSI_OTBS0_REG + ((port)<<5))
+#define TSI_OTAT_REG(port) (TSI_OTAT0_REG + ((port)<<5))
+# define TSI_OTAT_EN (1<<31)
+# define TSI_OTAT_MRPFD (1<<18)
+# define TSI_OTAT_PFS(x) (((x)&3)<<16)
+# define TSI_OTAT_2eSSTM(x) (((x)&7)<<11)
+# define TSI_OTAT_2eSSTM_160 TSI_OTAT_2eSSTM(0)
+# define TSI_OTAT_2eSSTM_267 TSI_OTAT_2eSSTM(1)
+# define TSI_OTAT_2eSSTM_320 TSI_OTAT_2eSSTM(2)
+# define TSI_OTAT_TM(x) (((x)&7)<<8)
+# define TSI_TM_SCT_IDX 0
+# define TSI_TM_BLT_IDX 1
+# define TSI_TM_MBLT_IDX 2
+# define TSI_TM_2eVME_IDX 3
+# define TSI_TM_2eSST_IDX 4
+# define TSI_TM_2eSSTB_IDX 5
+# define TSI_OTAT_DBW(x) (((x)&3)<<6)
+# define TSI_OTAT_SUP (1<<5)
+# define TSI_OTAT_PGM (1<<4)
+# define TSI_OTAT_ADMODE(x) (((x)&0xf))
+# define TSI_OTAT_ADMODE_A16 0
+# define TSI_OTAT_ADMODE_A24 1
+# define TSI_OTAT_ADMODE_A32 2
+# define TSI_OTAT_ADMODE_A64 4
+# define TSI_OTAT_ADMODE_CSR 5
+# define TSI_OTAT_ADMODE_USR1 8
+# define TSI_OTAT_ADMODE_USR2 9
+# define TSI_OTAT_ADMODE_USR3 0xa
+# define TSI_OTAT_ADMODE_USR4 0xb
+
+#define TSI_VIACK_1_REG 0x204
+
+#define TSI_VMCTRL_REG 0x234
+# define TSI_VMCTRL_VSA (1<<27)
+# define TSI_VMCTRL_VS (1<<26)
+# define TSI_VMCTRL_DHB (1<<25)
+# define TSI_VMCTRL_DWB (1<<24)
+# define TSI_VMCTRL_RMWEN (1<<20)
+# define TSI_VMCTRL_A64DS (1<<16)
+# define TSI_VMCTRL_VTOFF_MSK (7<<12)
+# define TSI_VMCTRL_VTOFF_0us (0<<12)
+# define TSI_VMCTRL_VTOFF_1us (1<<12)
+# define TSI_VMCTRL_VTOFF_2us (2<<12)
+# define TSI_VMCTRL_VTOFF_4us (3<<12)
+# define TSI_VMCTRL_VTOFF_8us (4<<12)
+# define TSI_VMCTRL_VTOFF_16us (5<<12)
+# define TSI_VMCTRL_VTOFF_32us (6<<12)
+# define TSI_VMCTRL_VTOFF_64us (7<<12)
+# define TSI_VMCTRL_VTON_MSK (7<< 8)
+# define TSI_VMCTRL_VTON_4us (0<< 8)
+# define TSI_VMCTRL_VTON_8us (1<< 8)
+# define TSI_VMCTRL_VTON_16us (2<< 8)
+# define TSI_VMCTRL_VTON_32us (3<< 8)
+# define TSI_VMCTRL_VTON_64us (4<< 8)
+# define TSI_VMCTRL_VTON_128us (5<< 8)
+# define TSI_VMCTRL_VTON_256us (6<< 8)
+# define TSI_VMCTRL_VTON_512us (7<< 8)
+# define TSI_VMCTRL_VREL_MSK (3<< 3)
+# define TSI_VMCTRL_VREL_TON_or_DONE (0<< 3)
+# define TSI_VMCTRL_VREL_TONandREQ_or_DONE (1<< 3)
+# define TSI_VMCTRL_VREL_TONandBCLR_or_DONE (2<< 3)
+# define TSI_VMCTRL_VREL_TONorDONE_and_REQ (3<< 3)
+# define TSI_VMCTRL_VFAIR (1<< 2)
+# define TSI_VMCTRL_VREQL_MSK (3<< 0)
+# define TSI_VMCTRL_VREQL(x) ((x)&3)
+
+#define TSI_VCTRL_REG 0x238
+#define TSI_VCTRL_DLT_MSK (0xf<<24)
+#define TSI_VCTRL_NELBB (1<<20)
+#define TSI_VCTRL_SRESET (1<<17)
+#define TSI_VCTRL_LRESET (1<<16)
+#define TSI_VCTRL_SFAILAI (1<<15)
+#define TSI_VCTRL_BID_MSK (0x1f<<8)
+#define TSI_VCTRL_ATOEN (1<< 7)
+#define TSI_VCTRL_ROBIN (1<< 6)
+#define TSI_VCTRL_GTO_MSK (7<< 0)
+
+
+#define TSI_VSTAT_REG 0x23c
+# define TSI_VSTAT_CPURST (1<<15) /* clear power-up reset bit */
+# define TSI_VSTAT_BDFAIL (1<<14)
+# define TSI_VSTAT_PURSTS (1<<12)
+# define TSI_VSTAT_BDFAILS (1<<11)
+# define TSI_VSTAT_SYSFLS (1<<10)
+# define TSI_VSTAT_ACFAILS (1<< 9)
+# define TSI_VSTAT_SCONS (1<< 8)
+# define TSI_VSTAT_GAP (1<< 5)
+# define TSI_VSTAT_GA_MSK (0x1f)
+
+#define TSI_VEAU_REG 0x260
+#define TSI_VEAL_REG 0x264
+#define TSI_VEAT_REG 0x268
+
+#define TSI_ITSAU_SPACING 0x020
+
+#define TSI_ITSAU0_REG 0x300
+#define TSI_ITSAL0_REG 0x304
+#define TSI_ITEAU0_REG 0x308
+#define TSI_ITEAL0_REG 0x30c
+#define TSI_ITOFU0_REG 0x310
+#define TSI_ITOFL0_REG 0x314
+#define TSI_ITAT0_REG 0x318
+#define TSI_ITSAU_REG(port) (TSI_ITSAU0_REG + ((port)<<5))
+#define TSI_ITSAL_REG(port) (TSI_ITSAL0_REG + ((port)<<5))
+#define TSI_ITEAU_REG(port) (TSI_ITEAU0_REG + ((port)<<5))
+#define TSI_ITEAL_REG(port) (TSI_ITEAL0_REG + ((port)<<5))
+#define TSI_ITOFU_REG(port) (TSI_ITOFU0_REG + ((port)<<5))
+#define TSI_ITOFL_REG(port) (TSI_ITOFL0_REG + ((port)<<5))
+#define TSI_ITAT_REG(port) (TSI_ITAT0_REG + ((port)<<5))
+
+# define TSI_ITAT_EN (1<<31)
+# define TSI_ITAT_TH (1<<18)
+# define TSI_ITAT_VFS(x) (((x)&3)<<16)
+# define TSI_ITAT_2eSSTM(x) (((x)&7)<<12)
+# define TSI_ITAT_2eSSTM_160 TSI_ITAT_2eSSTM(0)
+# define TSI_ITAT_2eSSTM_267 TSI_ITAT_2eSSTM(1)
+# define TSI_ITAT_2eSSTM_320 TSI_ITAT_2eSSTM(2)
+# define TSI_ITAT_2eSSTB (1<<11)
+# define TSI_ITAT_2eSST (1<<10)
+# define TSI_ITAT_2eVME (1<<9)
+# define TSI_ITAT_MBLT (1<<8)
+# define TSI_ITAT_BLT (1<<7)
+# define TSI_ITAT_AS(x) (((x)&7)<<4)
+# define TSI_ITAT_ADMODE_A16 (0<<4)
+# define TSI_ITAT_ADMODE_A24 (1<<4)
+# define TSI_ITAT_ADMODE_A32 (2<<4)
+# define TSI_ITAT_ADMODE_A64 (4<<4)
+# define TSI_ITAT_SUP (1<<3)
+# define TSI_ITAT_USR (1<<2)
+# define TSI_ITAT_PGM (1<<1)
+# define TSI_ITAT_DATA (1<<0)
+
+#define TSI_CBAU_REG 0x40c
+#define TSI_CBAL_REG 0x410
+#define TSI_CRGAT_REG 0x414
+# define TSI_CRGAT_EN (1<<7)
+# define TSI_CRGAT_AS_MSK (7<<4)
+# define TSI_CRGAT_A16 (0<<4)
+# define TSI_CRGAT_A24 (1<<4)
+# define TSI_CRGAT_A32 (2<<4)
+# define TSI_CRGAT_A64 (4<<4)
+# define TSI_CRGAT_SUP (1<<3)
+# define TSI_CRGAT_USR (1<<2)
+# define TSI_CRGAT_PGM (1<<1)
+# define TSI_CRGAT_DATA (1<<0)
+
+#define TSI_VICR_REG 0x440
+# define TSI_VICR_CNTS(v) (((v)&3)<<30)
+# define TSI_VICR_CNTS_DIS (0<<30)
+# define TSI_VICR_CNTS_IRQ1 (1<<30)
+# define TSI_VICR_CNTS_IRQ2 (2<<30)
+# define TSI_VICR_EDGIS(v) (((v)&3)<<28)
+# define TSI_VICR_EDGIS_DIS (0<<28)
+# define TSI_VICR_EDGIS_IRQ1 (1<<28)
+# define TSI_VICR_EDGIS_IRQ2 (2<<28)
+# define TSI_VICR_IRQ1F(v) (((v)&3)<<26)
+# define TSI_VICR_IRQ1F_NORML (0<<26)
+# define TSI_VICR_IRQ1F_PULSE (1<<26)
+# define TSI_VICR_IRQ1F_CLOCK (2<<26)
+# define TSI_VICR_IRQ1F_1MHZ (3<<26)
+# define TSI_VICR_IRQ2F(v) (((v)&3)<<24)
+# define TSI_VICR_IRQ2F_NORML (0<<24)
+# define TSI_VICR_IRQ2F_PULSE (1<<24)
+# define TSI_VICR_IRQ2F_CLOCK (2<<24)
+# define TSI_VICR_IRQ2F_1MHZ (3<<24)
+# define TSI_VICR_BIP (1<<23)
+# define TSI_VICR_BIPS (1<<22)
+# define TSI_VICR_IRQC (1<<15)
+# define TSI_VICR_IRQLS(v) (((v)&7)<<12)
+# define TSI_VICR_IRQS (1<<11)
+# define TSI_VICR_IRQL(v) (((v)&7)<<8)
+# define TSI_VICR_STID(v) ((v)&0xff)
+#define TSI_INTEN_REG 0x448
+#define TSI_INTEO_REG 0x44c
+#define TSI_INTS_REG 0x450
+# define TSI_INTS_IRQ1S (1<<1)
+# define TSI_INTS_IRQ2S (1<<2)
+# define TSI_INTS_IRQ3S (1<<3)
+# define TSI_INTS_IRQ4S (1<<4)
+# define TSI_INTS_IRQ5S (1<<5)
+# define TSI_INTS_IRQ6S (1<<6)
+# define TSI_INTS_IRQ7S (1<<7)
+# define TSI_INTS_ACFLS (1<<8)
+# define TSI_INTS_SYSFLS (1<<9)
+# define TSI_INTS_IACKS (1<<10)
+# define TSI_INTS_VIES (1<<11)
+# define TSI_INTS_VERRS (1<<12)
+# define TSI_INTS_PERRS (1<<13)
+# define TSI_INTS_MB0S (1<<16)
+# define TSI_INTS_MB1S (1<<17)
+# define TSI_INTS_MB2S (1<<18)
+# define TSI_INTS_MB3S (1<<19)
+# define TSI_INTS_LM0S (1<<20)
+# define TSI_INTS_LM1S (1<<21)
+# define TSI_INTS_LM2S (1<<22)
+# define TSI_INTS_LM3S (1<<23)
+# define TSI_INTS_DMA0S (1<<24)
+# define TSI_INTS_DMA1S (1<<25)
+#define TSI_INTC_REG 0x454
+# define TSI_INTC_ACFLC (1<<8)
+# define TSI_INTC_SYSFLC (1<<9)
+# define TSI_INTC_IACKC (1<<10)
+# define TSI_INTC_VIEC (1<<11)
+# define TSI_INTC_VERRC (1<<12)
+# define TSI_INTC_PERRC (1<<13)
+# define TSI_INTC_MB0C (1<<16)
+# define TSI_INTC_MB1C (1<<17)
+# define TSI_INTC_MB2C (1<<18)
+# define TSI_INTC_MB3C (1<<19)
+# define TSI_INTC_LM0C (1<<20)
+# define TSI_INTC_LM1C (1<<21)
+# define TSI_INTC_LM2C (1<<22)
+# define TSI_INTC_LM3C (1<<23)
+# define TSI_INTC_DMA0C (1<<24)
+# define TSI_INTC_DMA1C (1<<25)
+#define TSI_INTM1_REG 0x458
+#define TSI_INTM2_REG 0x45c
+
+#define TSI_CBAR_REG 0xffc
+
+#define TSI_CSR_OFFSET 0x7f000
+
+#define TSI_CRG_SIZE (1<<12) /* 4k */
+
+
+#define TSI_RD(base, reg) in_be32((volatile uint32_t *)((base) + (reg)/sizeof(*base)))
+#define TSI_RD16(base, reg) in_be16((volatile uint16_t *)(base) + (reg)/sizeof(uint16_t))
+#define TSI_LE_RD16(base, reg) in_le16((volatile uint16_t *)(base) + (reg)/sizeof(uint16_t))
+#define TSI_LE_RD32(base, reg) in_le32((volatile uint32_t *)(base) + (reg)/sizeof(*base))
+#define TSI_RD8(base, reg) in_8((volatile uint8_t *)(base) + (reg))
+#define TSI_WR(base, reg, val) out_be32((volatile uint32_t *)((base) + (reg)/sizeof(*base)), val)
+
+#define UNIV_SCTL_AM_MASK (UNIV_CTL_VAS | UNIV_SCTL_PGM | UNIV_SCTL_DAT | UNIV_SCTL_USER | UNIV_SCTL_SUPER)
+
+
+/* allow the BSP to override the default routines */
+#ifndef BSP_PCI_FIND_DEVICE
+#define BSP_PCI_FIND_DEVICE pci_find_device
+#endif
+#ifndef BSP_PCI_CONFIG_IN_LONG
+#define BSP_PCI_CONFIG_IN_LONG pci_read_config_dword
+#endif
+#ifndef BSP_PCI_CONFIG_IN_SHORT
+#define BSP_PCI_CONFIG_IN_SHORT pci_read_config_word
+#endif
+#ifndef BSP_PCI_CONFIG_OUT_SHORT
+#define BSP_PCI_CONFIG_OUT_SHORT pci_write_config_word
+#endif
+#ifndef BSP_PCI_CONFIG_IN_BYTE
+#define BSP_PCI_CONFIG_IN_BYTE pci_read_config_byte
+#endif
+
+typedef uint32_t pci_ulong;
+
+#ifdef __BIG_ENDIAN__
+ static inline void st_be32( uint32_t *a, uint32_t v)
+ {
+ *a = v;
+ }
+ static inline uint32_t ld_be32( uint32_t *a )
+ {
+ return *a;
+ }
+#elif defined(__LITTLE_ENDIAN__)
+#error "You need to implement st_be32/ld_be32"
+#else
+#error "Undefined endianness??"
+#endif
+
+#ifndef BSP_LOCAL2PCI_ADDR
+/* try legacy PCI_DRAM_OFFSET */
+#ifndef PCI_DRAM_OFFSET
+#define PCI_DRAM_OFFSET 0
+#endif
+#define BSP_LOCAL2PCI_ADDR(l) (((uint32_t)l)+PCI_DRAM_OFFSET)
+#endif
+
+/* PCI_MEM_BASE is a possible offset between CPU- and PCI addresses.
+ * Should be defined by the BSP.
+ */
+#ifndef BSP_PCI2LOCAL_ADDR
+#ifndef PCI_MEM_BASE
+#define PCI_MEM_BASE 0
+#endif
+#define BSP_PCI2LOCAL_ADDR(memaddr) ((unsigned long)(memaddr) + PCI_MEM_BASE)
+#endif
+
+typedef uint32_t BEValue;
+
+typedef struct {
+ BERegister *base;
+ int irqLine;
+ int pic_pin[TSI_NUM_WIRES];
+} Tsi148Dev;
+
+static Tsi148Dev devs[NUM_TSI_DEVS] = {{0}};
+
+#define THEBASE (devs[0].base)
+
+/* forward decl */
+extern int vmeTsi148RegPort;
+extern int vmeTsi148RegCSR;
+
+/* 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.
+ */
+
+/* private printing wrapper */
+static void
+uprintf(FILE *f, char *fmt, ...)
+{
+va_list ap;
+ va_start(ap, fmt);
+ if (!f || !_impure_ptr->__sdidinit) {
+ /* Might be called at an early stage when
+ * to a buffer.
+ */
+ vprintk(fmt,ap);
+ } else
+ {
+ vfprintf(f,fmt,ap);
+ }
+ va_end(ap);
+}
+
+#define CHECK_BASE(base,quiet,rval) \
+ do { \
+ if ( !base ) { \
+ if ( !quiet ) { \
+ uprintf(stderr,"Tsi148: Driver not initialized\n"); \
+ } \
+ return rval; \
+ } \
+ } while (0)
+
+int
+vmeTsi148FindPciBase(
+ int instance,
+ BERegister **pbase
+ )
+{
+int bus,dev,fun;
+pci_ulong busaddr;
+unsigned char irqline;
+unsigned short wrd;
+
+ if (BSP_PCI_FIND_DEVICE(
+ PCI_VENDOR_TUNDRA,
+ PCI_DEVICE_TSI148,
+ instance,
+ &bus,
+ &dev,
+ &fun))
+ return -1;
+ if (BSP_PCI_CONFIG_IN_LONG(bus,dev,fun,PCI_BASE_ADDRESS_0,&busaddr))
+ return -1;
+ /* Assume upper BAR is zero */
+
+ *pbase=(BERegister*)(((pci_ulong)BSP_PCI2LOCAL_ADDR(busaddr)) & ~0xff);
+
+ if (BSP_PCI_CONFIG_IN_BYTE(bus,dev,fun,PCI_INTERRUPT_LINE,&irqline))
+ return -1;
+
+ /* Enable PCI master and memory access */
+ BSP_PCI_CONFIG_IN_SHORT(bus, dev, fun, PCI_COMMAND, &wrd);
+ BSP_PCI_CONFIG_OUT_SHORT(bus, dev, fun, PCI_COMMAND, wrd | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+ return irqline;
+}
+
+int
+vmeTsi148InitInstance(unsigned instance)
+{
+int irq;
+BERegister *base;
+
+ if ( instance >= NUM_TSI_DEVS )
+ return -1;
+ if ( devs[instance].base )
+ return -1;
+
+ if ((irq=vmeTsi148FindPciBase(instance,&base)) < 0) {
+ uprintf(stderr,"unable to find a Tsi148 in pci config space\n");
+ } else {
+ uprintf(stderr,"Tundra Tsi148 PCI-VME bridge detected at 0x%08x, IRQ %d\n",
+ (unsigned int)base, irq);
+ }
+ devs[0].base = base;
+ devs[0].irqLine = irq;
+
+ return irq < 0 ? -1 : 0;
+}
+
+int
+vmeTsi148Init(void)
+{
+ return vmeTsi148InitInstance(0);
+}
+
+
+void
+vmeTsi148ResetXX(BERegister *base)
+{
+int port;
+uint32_t v;
+
+ CHECK_BASE(base,0, );
+
+ vmeTsi148DisableAllOutboundPortsXX(base);
+ for ( port=0; port < TSI148_NUM_OPORTS; port++ )
+ TSI_WR(base, TSI_OTBS_REG(port), 0);
+ TSI_WR(base, TSI_INTEO_REG, 0);
+ TSI_WR(base, TSI_INTEN_REG, 0);
+ TSI_WR(base, TSI_INTC_REG, 0xffffffff);
+ TSI_WR(base, TSI_INTM1_REG, 0);
+ TSI_WR(base, TSI_INTM2_REG, 0);
+ TSI_WR(base, TSI_VICR_REG, 0);
+ TSI_WR(base, TSI_VEAT_REG, TSI_VEAT_VESCL);
+ /* Clear BDFAIL / (--> SYSFAIL) */
+# define TSI_VSTAT_BDFAIL (1<<14)
+ TSI_WR(base, TSI_VSTAT_REG, TSI_RD(base, TSI_VSTAT_REG) & ~TSI_VSTAT_BDFAIL);
+ /* Set (long) bus master timeout; the timeout actually overrides
+ * the DMA block size so that the DMA settings would effectively
+ * not be used.
+ * Also, we enable 'release on request' mode so that we normally
+ * don't have to rearbitrate the bus for every transfer.
+ */
+ v = TSI_RD(base, TSI_VMCTRL_REG);
+ v &= ~( TSI_VMCTRL_VTON_MSK | TSI_VMCTRL_VREL_MSK );
+ v |= (TSI_VMCTRL_VTON_512us | TSI_VMCTRL_VREL_TONorDONE_and_REQ );
+ TSI_WR(base, TSI_VMCTRL_REG, v);
+}
+
+void
+vmeTsi148Reset(void)
+{
+ vmeTsi148ResetXX(THEBASE);
+}
+
+void
+vmeTsi148ResetBusXX(BERegister *base)
+{
+unsigned long flags;
+uint32_t v;
+
+ rtems_interrupt_disable(flags);
+ v = TSI_RD(base, TSI_VCTRL_REG);
+ TSI_WR(base, TSI_VCTRL_REG, v | TSI_VCTRL_SRESET);
+ rtems_interrupt_enable(flags);
+}
+
+void
+vmeTsi148ResetBus(void)
+{
+ vmeTsi148ResetBusXX(THEBASE);
+}
+
+
+/* convert an address space selector to a corresponding
+ * Tsi148 control mode word
+ */
+
+static unsigned long ck2esst(unsigned long am)
+{
+ if ( VME_AM_IS_2eSST(am) ) {
+ /* make sure 2eVME is selected */
+ am &= ~VME_AM_MASK;
+ am |= VME_AM_2eVME_6U;
+ }
+ return am;
+}
+
+static int
+am2omode(unsigned long address_space, unsigned long *pmode)
+{
+unsigned long mode = 0;
+unsigned long tm = TSI_TM_SCT_IDX;
+
+ switch ( VME_MODE_DBW_MSK & address_space ) {
+ case VME_MODE_DBW8:
+ return -1; /* unsupported */
+
+ case VME_MODE_DBW16:
+ break;
+
+ default:
+ case VME_MODE_DBW32:
+ mode |= TSI_OTAT_DBW(1);
+ break;
+ }
+
+ if ( ! (VME_MODE_PREFETCH_ENABLE & address_space) )
+ mode |= TSI_OTAT_MRPFD;
+ else {
+ mode |= TSI_OTAT_PFS(address_space>>_LD_VME_MODE_PREFETCHSZ);
+ }
+
+ address_space = ck2esst(address_space);
+
+ switch (address_space & VME_AM_MASK) {
+ case VME_AM_STD_SUP_PGM:
+ case VME_AM_STD_USR_PGM:
+
+ mode |= TSI_OTAT_PGM;
+
+ /* fall thru */
+ case VME_AM_STD_SUP_BLT:
+ case VME_AM_STD_SUP_MBLT:
+
+ case VME_AM_STD_USR_BLT:
+ case VME_AM_STD_USR_MBLT:
+ switch ( address_space & 3 ) {
+ case 0: tm = TSI_TM_MBLT_IDX; break;
+ case 3: tm = TSI_TM_BLT_IDX; break;
+ default: break;
+ }
+
+ case VME_AM_STD_SUP_DATA:
+ case VME_AM_STD_USR_DATA:
+
+ mode |= TSI_OTAT_ADMODE_A24;
+ break;
+
+ case VME_AM_EXT_SUP_PGM:
+ case VME_AM_EXT_USR_PGM:
+ mode |= TSI_OTAT_PGM;
+
+ /* fall thru */
+ case VME_AM_EXT_SUP_BLT:
+ case VME_AM_EXT_SUP_MBLT:
+
+ case VME_AM_EXT_USR_BLT:
+ case VME_AM_EXT_USR_MBLT:
+ switch ( address_space & 3 ) {
+ case 0: tm = TSI_TM_MBLT_IDX; break;
+ case 3: tm = TSI_TM_BLT_IDX; break;
+ default: break;
+ }
+
+ case VME_AM_EXT_SUP_DATA:
+ case VME_AM_EXT_USR_DATA:
+
+ mode |= TSI_OTAT_ADMODE_A32;
+ break;
+
+ case VME_AM_SUP_SHORT_IO:
+ case VME_AM_USR_SHORT_IO:
+ mode |= TSI_OTAT_ADMODE_A16;
+ break;
+
+ case VME_AM_CSR:
+ mode |= TSI_OTAT_ADMODE_CSR;
+ break;
+
+ case VME_AM_2eVME_6U:
+ case VME_AM_2eVME_3U:
+ mode |= TSI_OTAT_ADMODE_A32;
+ if ( VME_AM_IS_2eSST(address_space) ) {
+ tm = ( VME_AM_2eSST_BCST & address_space ) ?
+ TSI_TM_2eSSTB_IDX : TSI_TM_2eSST_IDX;
+ switch ( VME_AM_IS_2eSST(address_space) ) {
+ default:
+ case VME_AM_2eSST_LO: mode |= TSI_OTAT_2eSSTM_160; break;
+ case VME_AM_2eSST_MID: mode |= TSI_OTAT_2eSSTM_267; break;
+ case VME_AM_2eSST_HI: mode |= TSI_OTAT_2eSSTM_320; break;
+ }
+ } else {
+ tm = TSI_TM_2eVME_IDX;
+ }
+ break;
+
+ case 0: /* disable the port alltogether */
+ break;
+
+ default:
+ return -1;
+ }
+
+ mode |= TSI_OTAT_TM(tm);
+
+ if ( VME_AM_IS_SUP(address_space) )
+ mode |= TSI_OTAT_SUP;
+ *pmode = mode;
+ return 0;
+}
+
+static int
+am2imode(unsigned long address_space, unsigned long *pmode)
+{
+unsigned long mode=0;
+unsigned long pgm = 0;
+
+ mode |= TSI_ITAT_VFS(address_space>>_LD_VME_MODE_PREFETCHSZ);
+
+ if ( VME_AM_IS_2eSST(address_space) ) {
+ mode |= TSI_ITAT_2eSST;
+ if ( VME_AM_2eSST_BCST & address_space )
+ mode |= TSI_ITAT_2eSSTB;
+ switch ( VME_AM_IS_2eSST(address_space) ) {
+ default:
+ case VME_AM_2eSST_LO: mode |= TSI_ITAT_2eSSTM_160; break;
+ case VME_AM_2eSST_MID: mode |= TSI_ITAT_2eSSTM_267; break;
+ case VME_AM_2eSST_HI: mode |= TSI_ITAT_2eSSTM_320; break;
+ }
+ address_space = ck2esst(address_space);
+ }
+
+ mode |= TSI_ITAT_BLT;
+ mode |= TSI_ITAT_MBLT;
+
+ mode |= TSI_ITAT_PGM; /* always allow PGM access */
+ mode |= TSI_ITAT_USR; /* always allow USR access */
+
+ switch (address_space & VME_AM_MASK) {
+ case VME_AM_STD_SUP_PGM:
+ case VME_AM_STD_USR_PGM:
+
+ pgm = 1;
+
+ /* fall thru */
+ case VME_AM_STD_SUP_BLT:
+ case VME_AM_STD_SUP_MBLT:
+ case VME_AM_STD_USR_BLT:
+ case VME_AM_STD_USR_MBLT:
+ case VME_AM_STD_SUP_DATA:
+ case VME_AM_STD_USR_DATA:
+
+ mode |= TSI_ITAT_ADMODE_A24;
+ break;
+
+ case VME_AM_EXT_SUP_PGM:
+ case VME_AM_EXT_USR_PGM:
+ pgm = 1;
+
+ /* fall thru */
+ case VME_AM_2eVME_6U:
+ case VME_AM_2eVME_3U:
+ case VME_AM_EXT_SUP_BLT:
+ case VME_AM_EXT_SUP_MBLT:
+ case VME_AM_EXT_USR_BLT:
+ case VME_AM_EXT_USR_MBLT:
+ case VME_AM_EXT_SUP_DATA:
+ case VME_AM_EXT_USR_DATA:
+ mode |= TSI_ITAT_ADMODE_A32;
+ break;
+
+ case VME_AM_SUP_SHORT_IO:
+ case VME_AM_USR_SHORT_IO:
+ mode |= TSI_ITAT_ADMODE_A16;
+ break;
+
+ case 0: /* disable the port alltogether */
+ *pmode = 0;
+ return 0;
+
+ default:
+ return -1;
+ }
+
+ if ( VME_AM_IS_SUP(address_space) )
+ mode |= TSI_ITAT_SUP;
+
+ if ( !pgm )
+ mode |= TSI_ITAT_DATA;
+
+ *pmode = mode;
+ return 0;
+}
+
+static void
+readTriple(
+ BERegister *base,
+ unsigned reg,
+ unsigned long long *ps,
+ unsigned long long *pl,
+ unsigned long long *po)
+{
+ *ps = TSI_RD(base, reg);
+ *ps = (*ps<<32) | (TSI_RD(base, (reg+4)) & 0xffff0000);
+ *pl = TSI_RD(base, (reg+8));
+ *pl = (*pl<<32) | (TSI_RD(base, (reg+0xc)) & 0xffff0000);
+ *po = TSI_RD(base, (reg+0x10));
+ *po = (*po<<32) | (TSI_RD(base, (reg+0x14)) & 0xffff0000);
+}
+
+
+static unsigned long
+inboundGranularity(unsigned long itat)
+{
+ switch ( itat & TSI_ITAT_AS(-1) ) {
+ case TSI_ITAT_ADMODE_A16: return 0xf;
+ case TSI_ITAT_ADMODE_A24: return 0xfff;
+ default:
+ break;
+ }
+ return 0xffff;
+}
+
+static int
+configTsiPort(
+ BERegister *base,
+ int isout,
+ unsigned long port,
+ unsigned long address_space,
+ unsigned long vme_address,
+ unsigned long pci_address,
+ unsigned long length)
+{
+unsigned long long start, limit, offst;
+unsigned long mode, mask, tat_reg, tsau_reg;
+char *name = (isout ? "Outbound" : "Inbound");
+int i,s,l;
+
+ CHECK_BASE(base,0,-1);
+
+ mode = 0; /* silence warning */
+
+ if ( port >= (isout ? TSI148_NUM_OPORTS : TSI148_NUM_IPORTS) ) {
+ uprintf(stderr,"Tsi148 %s Port Cfg: invalid port\n", name);
+ return -1;
+ }
+
+ if ( base == THEBASE && isout && vmeTsi148RegPort == port ) {
+ uprintf(stderr,"Tsi148 %s Port Cfg: invalid port; reserved by the interrupt manager for CRG\n", name);
+ return -1;
+ }
+
+ if ( length && (isout ? am2omode(address_space, &mode) : am2imode(address_space, &mode)) ) {
+ uprintf(stderr,"Tsi148 %s Port Cfg: invalid address space / mode flags\n",name);
+ return -1;
+ }
+
+
+ if ( isout ) {
+ start = pci_address;
+ offst = (unsigned long long)vme_address - start;
+ mask = 0xffff;
+ tat_reg = TSI_OTAT_REG(port);
+ tsau_reg = TSI_OTSAU_REG(port);
+ mode |= TSI_OTAT_EN;
+
+ /* check for overlap */
+ for ( i = 0; i < TSI148_NUM_OPORTS; i++ ) {
+ /* ignore 'this' port */
+ if ( i == port || ! (TSI_OTAT_EN & TSI_RD(base, TSI_OTAT_REG(i))) )
+ continue;
+
+ /* check requested PCI range against current port 'i' config */
+ s = TSI_RD(base, TSI_OTSAU_REG(i) + 0x04); /* start */
+ l = TSI_RD(base, TSI_OTSAU_REG(i) + 0x0c); /* limit */
+ if ( ! ( start + length <= s || start > s + l ) ) {
+ uprintf(stderr,"Tsi148 Outbound Port Cfg: PCI address range overlaps with port %i (0x%08x..0x%08x)\n", i, s, l);
+ return -1;
+ }
+ }
+ } else {
+ start = vme_address;
+ offst = (unsigned long long)pci_address - start;
+ mask = inboundGranularity(mode);
+ tat_reg = TSI_ITAT_REG(port);
+ tsau_reg = TSI_ITSAU_REG(port);
+ mode |= TSI_ITAT_EN;
+
+ /* check for overlap */
+ for ( i = 0; i < TSI148_NUM_IPORTS; i++ ) {
+ /* ignore 'this' port */
+ if ( i == port || ! (TSI_ITAT_EN & (s=TSI_RD(base, TSI_ITAT_REG(i)))) )
+ continue;
+
+ if ( (TSI_ITAT_AS(-1) & s) != (TSI_ITAT_AS(-1) & mode) ) {
+ /* different address space */
+ continue;
+ }
+
+ if ( ! (mode & s & (TSI_ITAT_SUP | TSI_ITAT_USR | TSI_ITAT_PGM | TSI_ITAT_DATA)) ) {
+ /* orthogonal privileges */
+ continue;
+ }
+
+ /* check requested VME range against current port 'i' config */
+ s = TSI_RD(base, TSI_ITSAU_REG(i) + 0x04); /* start */
+ l = TSI_RD(base, TSI_ITSAU_REG(i) + 0x0c); /* limit */
+ if ( ! ( start + length <= s || start > s + l ) ) {
+ uprintf(stderr,"Tsi148 Inbound Port Cfg: VME address range overlaps with port %i (0x%08x..0x%08x)\n", i, s, l);
+ return -1;
+ }
+ }
+ }
+
+ /* If they pass 'length==0' just disable */
+ if ( 0 == length ) {
+ TSI_WR(base, tat_reg, TSI_RD(base, tat_reg) & ~(isout ? TSI_OTAT_EN : TSI_ITAT_EN));
+ return 0;
+ }
+
+
+ if ( (vme_address & mask)
+ || (pci_address & mask)
+ || (length & mask) ) {
+ uprintf(stderr,"Tsi148 %s Port Cfg: invalid address/length; must be multiple of 0x%x\n",
+ name,
+ mask+1);
+ return -1;
+ }
+
+ limit = start + length - 1;
+
+ if ( limit >= (unsigned long long)1<<32 ) {
+ uprintf(stderr,"Tsi148 %s Port Cfg: invalid address/length; must be < 1<<32\n", name);
+ return -1;
+ }
+
+ /* Disable port */
+ TSI_WR(base, tat_reg, 0);
+
+ /* Force to 32-bits */
+ TSI_WR(base, tsau_reg , 0);
+ TSI_WR(base, tsau_reg + 0x04, (uint32_t)start);
+ TSI_WR(base, tsau_reg + 0x08, 0);
+ TSI_WR(base, tsau_reg + 0x0c, (uint32_t)limit);
+ TSI_WR(base, tsau_reg + 0x10, (uint32_t)(offst>>32));
+ TSI_WR(base, tsau_reg + 0x14, (uint32_t)offst);
+
+ /* (outbound only:) leave 2eSST broadcast register alone for user to program */
+
+ /* Set mode and enable */
+ TSI_WR(base, tat_reg, mode);
+ return 0;
+}
+
+static int
+disableTsiPort(
+ BERegister *base,
+ int isout,
+ unsigned long port)
+{
+ return configTsiPort(base, isout, port, 0, 0, 0, 0);
+}
+
+int
+vmeTsi148InboundPortCfgXX(
+ BERegister *base,
+ unsigned long port,
+ unsigned long address_space,
+ unsigned long vme_address,
+ unsigned long pci_address,
+ unsigned long length)
+{
+ return configTsiPort(base, 0, port, address_space, vme_address, pci_address, length);
+}
+
+int
+vmeTsi148InboundPortCfg(
+ unsigned long port,
+ unsigned long address_space,
+ unsigned long vme_address,
+ unsigned long pci_address,
+ unsigned long length)
+{
+ return configTsiPort(THEBASE, 0, port, address_space, vme_address, pci_address, length);
+}
+
+
+int
+vmeTsi148OutboundPortCfgXX(
+ BERegister *base,
+ unsigned long port,
+ unsigned long address_space,
+ unsigned long vme_address,
+ unsigned long pci_address,
+ unsigned long length)
+{
+ return configTsiPort(base, 1, port, address_space, vme_address, pci_address, length);
+}
+
+int
+vmeTsi148OutboundPortCfg(
+ unsigned long port,
+ unsigned long address_space,
+ unsigned long vme_address,
+ unsigned long pci_address,
+ unsigned long length)
+{
+ return configTsiPort(THEBASE, 1, port, address_space, vme_address, pci_address, length);
+}
+
+
+static int
+xlateFindPort(
+ BERegister *base, /* TSI 148 base address */
+ int outbound, /* look in the outbound windows */
+ int reverse, /* reverse mapping; for outbound ports: map local to VME */
+ unsigned long as, /* address space */
+ unsigned long aIn, /* address to look up */
+ unsigned long *paOut/* where to put result */
+ )
+{
+unsigned long mode, mode_msk;
+int port;
+unsigned long long start, limit, offst, a;
+unsigned long tsau_reg, tat_reg, gran, skip;
+
+ CHECK_BASE(base,0,-1);
+
+ mode = 0; /* silence warning */
+
+ switch ( as & VME_MODE_MATCH_MASK ) {
+ case VME_MODE_EXACT_MATCH:
+ mode_msk = ~0;
+ break;
+
+ case VME_MODE_AS_MATCH:
+ if ( outbound )
+ mode_msk = TSI_OTAT_ADMODE(-1) | TSI_OTAT_EN;
+ else
+ mode_msk = TSI_ITAT_AS(-1) | TSI_ITAT_EN;
+ break;
+
+ default:
+ if ( outbound )
+ mode_msk = TSI_OTAT_PGM | TSI_OTAT_SUP | TSI_OTAT_ADMODE(-1) | TSI_OTAT_EN;
+ else
+ mode_msk = TSI_ITAT_PGM | TSI_ITAT_DATA | TSI_ITAT_SUP | TSI_ITAT_USR | TSI_ITAT_AS(-1) | TSI_ITAT_EN;
+ break;
+ }
+
+ as &= ~VME_MODE_MATCH_MASK;
+
+ if ( outbound ? am2omode(as,&mode) : am2imode(as,&mode) ) {
+ uprintf(stderr, "vmeTsi148XlateAddr: invalid address space/mode argument");
+ return -2;
+ }
+
+ if (outbound ) {
+ tsau_reg = TSI_OTSAU_REG(0);
+ tat_reg = TSI_OTAT_REG(0);
+ skip = TSI_OTSAU_SPACING;
+ mode |= TSI_OTAT_EN;
+ gran = 0x10000;
+ } else {
+ tsau_reg = TSI_ITSAU_REG(0);
+ tat_reg = TSI_ITAT_REG(0);
+ skip = TSI_ITSAU_SPACING;
+ mode |= TSI_ITAT_EN;
+ gran = inboundGranularity(mode) + 1;
+ }
+
+ for ( port = 0; port < TSI148_NUM_OPORTS; port++, tsau_reg += skip, tat_reg += skip ) {
+
+ if ( (mode & mode_msk) == (TSI_RD(base, tat_reg) & mode_msk) ) {
+
+ /* found a window with of the right mode; now check the range */
+ readTriple(base, tsau_reg, &start, &limit, &offst);
+ limit += gran;
+
+ if ( !reverse ) {
+ start += offst;
+ limit += offst;
+ offst = -offst;
+ }
+ a = aIn;
+ if ( aIn >= start && aIn <= limit ) {
+ /* found it */
+ *paOut = (unsigned long)(a + offst);
+ return port;
+ }
+ }
+ }
+
+ uprintf(stderr, "vmeTsi148XlateAddr: no matching mapping found\n");
+ return -1;
+}
+
+int
+vmeTsi148XlateAddrXX(
+ BERegister *base, /* TSI 148 base address */
+ int outbound, /* look in the outbound windows */
+ int reverse, /* reverse mapping; for outbound ports: map local to VME */
+ unsigned long as, /* address space */
+ unsigned long aIn, /* address to look up */
+ unsigned long *paOut/* where to put result */
+ )
+{
+int port = xlateFindPort( base, outbound, reverse, as, aIn, paOut );
+ return port < 0 ? -1 : 0;
+}
+
+int
+vmeTsi148XlateAddr(
+ int outbound, /* look in the outbound windows */
+ int reverse, /* reverse mapping; for outbound ports: map local to VME */
+ unsigned long as, /* address space */
+ unsigned long aIn, /* address to look up */
+ unsigned long *paOut/* where to put result */
+ )
+{
+ return vmeTsi148XlateAddrXX(THEBASE, outbound, reverse, as, aIn, paOut);
+}
+
+
+/* printk cannot format %llx */
+static void uprintfllx(FILE *f, unsigned long long v)
+{
+ if ( v >= ((unsigned long long)1)<<32 )
+ uprintf(f,"0x%lx%08lx ", (unsigned long)(v>>32), (unsigned long)(v & 0xffffffff));
+ else
+ uprintf(f,"0x%08lx ", (unsigned long)(v & 0xffffffff));
+}
+
+void
+vmeTsi148OutboundPortsShowXX(BERegister *base, FILE *f)
+{
+int port;
+unsigned long mode;
+char tit = 0;
+
+unsigned long long start, limit, offst;
+
+ CHECK_BASE(base,0, );
+
+ if (!f) f=stdout;
+ uprintf(f,"Tsi148 Outbound Ports:\n");
+
+ for ( port = 0; port < TSI148_NUM_OPORTS; port++ ) {
+ mode = TSI_RD(base, TSI_OTAT_REG(port));
+ if ( ! (TSI_OTAT_EN & mode) )
+ continue; /* skip disabled ports */
+
+ readTriple(base, TSI_OTSAU_REG(port), &start, &limit, &offst);
+
+ /* convert limit to size */
+ limit = limit-start+0x10000;
+ if ( !tit ) {
+ uprintf(f,"Port VME-Addr Size PCI-Adrs Mode:\n");
+ tit = 1;
+ }
+ uprintf(f,"%d: ", port);
+ uprintfllx(f,start+offst);
+ uprintfllx(f,limit);
+ uprintfllx(f,start);
+ switch( mode & TSI_OTAT_ADMODE(-1) ) {
+ case TSI_OTAT_ADMODE_A16: uprintf(f,"A16"); break;
+ case TSI_OTAT_ADMODE_A24: uprintf(f,"A24"); break;
+ case TSI_OTAT_ADMODE_A32: uprintf(f,"A32"); break;
+ case TSI_OTAT_ADMODE_A64: uprintf(f,"A64"); break;
+ case TSI_OTAT_ADMODE_CSR: uprintf(f,"CSR"); break;
+ default: uprintf(f,"A??"); break;
+ }
+
+ if ( mode & TSI_OTAT_PGM ) uprintf(f,", PGM");
+ if ( mode & TSI_OTAT_SUP ) uprintf(f,", SUP");
+ if ( ! (TSI_OTAT_MRPFD & mode) ) uprintf(f,", PREFETCH");
+
+ switch ( mode & TSI_OTAT_DBW(-1) ) {
+ case TSI_OTAT_DBW(0): uprintf(f,", D16"); break;
+ case TSI_OTAT_DBW(1): uprintf(f,", D32"); break;
+ default: uprintf(f,", D??"); break;
+ }
+
+ switch( mode & TSI_OTAT_TM(-1) ) {
+ case TSI_OTAT_TM(0): uprintf(f,", SCT"); break;
+ case TSI_OTAT_TM(1): uprintf(f,", BLT"); break;
+ case TSI_OTAT_TM(2): uprintf(f,", MBLT"); break;
+ case TSI_OTAT_TM(3): uprintf(f,", 2eVME"); break;
+ case TSI_OTAT_TM(4): uprintf(f,", 2eSST"); break;
+ case TSI_OTAT_TM(5): uprintf(f,", 2eSST_BCST"); break;
+ default: uprintf(f," TM??"); break;
+ }
+
+ uprintf(f,"\n");
+ }
+}
+
+void
+vmeTsi148OutboundPortsShow(FILE *f)
+{
+ vmeTsi148OutboundPortsShowXX(THEBASE, f);
+}
+
+void
+vmeTsi148InboundPortsShowXX(BERegister *base, FILE *f)
+{
+int port;
+unsigned long mode;
+char tit = 0;
+
+unsigned long long start, limit, offst;
+
+ CHECK_BASE(base,0, );
+
+ if (!f) f=stdout;
+ uprintf(f,"Tsi148 Inbound Ports:\n");
+
+ for ( port = 0; port < TSI148_NUM_IPORTS; port++ ) {
+ mode = TSI_RD(base, TSI_ITAT_REG(port));
+ if ( ! (TSI_ITAT_EN & mode) )
+ continue; /* skip disabled ports */
+
+ readTriple(base, TSI_ITSAU_REG(port), &start, &limit, &offst);
+
+ /* convert limit to size */
+ limit = limit - start + inboundGranularity(mode) + 1;
+ if ( !tit ) {
+ uprintf(f,"Port VME-Addr Size PCI-Adrs Mode:\n");
+ tit = 1;
+ }
+ uprintf(f,"%d: ", port);
+ uprintfllx(f,start);
+ uprintfllx(f,limit);
+ uprintfllx(f,start+offst);
+ switch( mode & TSI_ITAT_AS(-1) ) {
+ case TSI_ITAT_ADMODE_A16: uprintf(f,"A16"); break;
+ case TSI_ITAT_ADMODE_A24: uprintf(f,"A24"); break;
+ case TSI_ITAT_ADMODE_A32: uprintf(f,"A32"); break;
+ case TSI_ITAT_ADMODE_A64: uprintf(f,"A64"); break;
+ default: uprintf(f,"A??"); break;
+ }
+
+ if ( mode & TSI_ITAT_PGM ) uprintf(f,", PGM");
+ if ( mode & TSI_ITAT_DATA ) uprintf(f,", DAT");
+ if ( mode & TSI_ITAT_SUP ) uprintf(f,", SUP");
+ if ( mode & TSI_ITAT_USR ) uprintf(f,", USR");
+
+ if ( mode & TSI_ITAT_2eSSTB ) uprintf(f,", 2eSSTB");
+ if ( mode & TSI_ITAT_2eSST ) uprintf(f,", 2eSST");
+ if ( mode & TSI_ITAT_2eVME ) uprintf(f,", 2eVME");
+ if ( mode & TSI_ITAT_MBLT ) uprintf(f,", MBLT");
+ if ( mode & TSI_ITAT_BLT ) uprintf(f,", BLT");
+
+ uprintf(f,"\n");
+ }
+}
+
+void
+vmeTsi148InboundPortsShow(FILE *f)
+{
+ vmeTsi148InboundPortsShowXX(THEBASE, f);
+}
+
+
+void
+vmeTsi148DisableAllInboundPortsXX(BERegister *base)
+{
+int port;
+
+ for ( port = 0; port < TSI148_NUM_IPORTS; port++ )
+ if ( disableTsiPort(base, 0, port) )
+ break;
+}
+
+void
+vmeTsi148DisableAllInboundPorts(void)
+{
+ vmeTsi148DisableAllInboundPortsXX(THEBASE);
+}
+
+void
+vmeTsi148DisableAllOutboundPortsXX(BERegister *base)
+{
+int port;
+
+ for ( port = 0; port < TSI148_NUM_IPORTS; port++ )
+ if ( disableTsiPort(base, 1, port) )
+ break;
+}
+
+void
+vmeTsi148DisableAllOutboundPorts(void)
+{
+ vmeTsi148DisableAllOutboundPortsXX(THEBASE);
+}
+
+
+/* Map internal register block to VME */
+
+int
+vmeTsi148MapCRGXX(BERegister *b, uint32_t vme_base, uint32_t as )
+{
+uint32_t mode;
+
+ CHECK_BASE( b, 0, -1 );
+
+ if ( vmeTsi148RegPort > -1 && ! vmeTsi148RegCSR ) {
+ uprintf(stderr,"vmeTsi148: CRG already mapped and in use by interrupt manager\n");
+ return -1;
+ }
+
+ /* enable all, SUP/USR/PGM/DATA accesses */
+ mode = TSI_CRGAT_EN | TSI_CRGAT_SUP | TSI_CRGAT_USR | TSI_CRGAT_PGM | TSI_CRGAT_DATA;
+
+ if ( VME_AM_IS_SHORT(as) ) {
+ mode |= TSI_CRGAT_A16;
+ } else
+ if ( VME_AM_IS_STD(as) ) {
+ mode |= TSI_CRGAT_A24;
+ } else
+ if ( VME_AM_IS_EXT(as) ) {
+ mode |= TSI_CRGAT_A32;
+ } else {
+ return -2;
+ }
+
+ /* map CRG to VME bus */
+ TSI_WR( b, TSI_CBAL_REG, (vme_base & ~(TSI_CRG_SIZE-1)));
+ TSI_WR( b, TSI_CRGAT_REG, mode );
+
+ return 0;
+}
+
+int
+vmeTsi148MapCRG(uint32_t vme_base, uint32_t as )
+{
+ return vmeTsi148MapCRGXX( THEBASE, vme_base, as );
+}
+
+/* Interrupt Subsystem */
+
+typedef struct
+IRQEntryRec_ {
+ VmeTsi148ISR isr;
+ void *usrData;
+} IRQEntryRec, *IRQEntry;
+
+static IRQEntry irqHdlTbl[TSI_NUM_INT_VECS]={0};
+
+int vmeTsi148IrqMgrInstalled = 0;
+int vmeTsi148RegPort = -1;
+int vmeTsi148RegCSR = 0;
+BERegister *vmeTsi148RegBase = 0;
+
+static volatile unsigned long wire_mask[TSI_NUM_WIRES] = {0};
+/* wires are offset by 1 so we can initialize the wire table to all zeros */
+static int tsi_wire[TSI_NUM_WIRES] = {0};
+
+/* how should we iack a given level, 1,2,4 bytes? */
+static unsigned char tsi_iack_width[7] = {
+ 1,1,1,1,1,1,1
+};
+
+/* map universe compatible vector # to Tsi slot (which maps to bit layout in stat/enable/... regs) */
+static int uni2tsi_vec_map[TSI_NUM_INT_VECS-256] = {
+ /* 256 no VOWN interrupt */ -1,
+ /* TSI_DMA_INT_VEC 257 */ 256 + 24 - 8,
+ /* TSI_LERR_INT_VEC 258 */ 256 + 13 - 8,
+ /* TSI_VERR_INT_VEC 259 */ 256 + 12 - 8,
+ /* 260 is reserved */ -1,
+ /* TSI_VME_SW_IACK_INT_VEC 261 */ 256 + 10 - 8,
+ /* 262 no PCI SW IRQ */ -1,
+ /* TSI_SYSFAIL_INT_VEC 263 */ 256 + 9 - 8,
+ /* TSI_ACFAIL_INT_VEC 264 */ 256 + 8 - 8,
+ /* TSI_MBOX0_INT_VEC 265 */ 256 + 16 - 8,
+ /* TSI_MBOX1_INT_VEC 266 */ 256 + 17 - 8,
+ /* TSI_MBOX2_INT_VEC 267 */ 256 + 18 - 8,
+ /* TSI_MBOX3_INT_VEC 268 */ 256 + 19 - 8,
+ /* TSI_LM0_INT_VEC 269 */ 256 + 20 - 8,
+ /* TSI_LM1_INT_VEC 270 */ 256 + 21 - 8,
+ /* TSI_LM2_INT_VEC 271 */ 256 + 22 - 8,
+ /* TSI_LM3_INT_VEC 272 */ 256 + 23 - 8,
+/* New vectors; only on TSI148 */
+ /* TSI_VIES_INT_VEC 273 */ 256 + 11 - 8,
+ /* TSI_DMA1_INT_VEC 274 */ 256 + 25 - 8,
+};
+
+/* and the reverse; map tsi bit number to universe compatible 'special' vector number */
+static int tsi2uni_vec_map[TSI_NUM_INT_VECS - 256] = {
+ TSI_ACFAIL_INT_VEC,
+ TSI_SYSFAIL_INT_VEC,
+ TSI_VME_SW_IACK_INT_VEC,
+ TSI_VIES_INT_VEC,
+ TSI_VERR_INT_VEC,
+ TSI_LERR_INT_VEC,
+ -1,
+ -1,
+ TSI_MBOX0_INT_VEC,
+ TSI_MBOX1_INT_VEC,
+ TSI_MBOX2_INT_VEC,
+ TSI_MBOX3_INT_VEC,
+ TSI_LM0_INT_VEC,
+ TSI_LM1_INT_VEC,
+ TSI_LM2_INT_VEC,
+ TSI_LM3_INT_VEC,
+ TSI_DMA_INT_VEC,
+ TSI_DMA1_INT_VEC,
+ -1,
+};
+
+static inline int
+uni2tsivec(int v)
+{
+ if ( v < 0 || v >= TSI_NUM_INT_VECS )
+ return -1;
+ return v < 256 ? v : uni2tsi_vec_map[v-256];
+}
+
+static int
+lvl2bitno(unsigned int level)
+{
+ if ( level >= 256 )
+ return uni2tsivec(level) + 8 - 256;
+ else if ( level < 8 && level > 0 )
+ return level;
+ return -1;
+}
+
+int
+vmeTsi148IntRoute(unsigned int level, unsigned int pin)
+{
+int i;
+unsigned long mask, shift, mapreg, flags, wire;
+
+ if ( pin >= TSI_NUM_WIRES || ! tsi_wire[pin] || !vmeTsi148IrqMgrInstalled )
+ return -1;
+
+ if ( level >= 256 ) {
+ if ( (i = uni2tsivec(level)) < 0 )
+ return -1;
+ shift = 8 + (i-256);
+ } else if ( 1 <= level && level <=7 ) {
+ shift = level;
+ } else {
+ return -1; /* invalid level */
+ }
+
+ mask = 1<<shift;
+
+ /* calculate the mapping register and contents */
+ if ( shift < 16 ) {
+ mapreg = TSI_INTM2_REG;
+ } else if ( shift < 32 ) {
+ shift -= 16;
+ mapreg = TSI_INTM1_REG;
+ } else {
+ return -1;
+ }
+
+ shift <<=1;
+
+ /* wires are offset by 1 so we can initialize the wire table to all zeros */
+ wire = (tsi_wire[pin]-1) << shift;
+
+rtems_interrupt_disable(flags);
+
+ for ( i = 0; i<TSI_NUM_WIRES; i++ ) {
+ wire_mask[i] &= ~mask;
+ }
+ wire_mask[pin] |= mask;
+
+ mask = TSI_RD(THEBASE, mapreg) & ~ (0x3<<shift);
+ mask |= wire;
+ TSI_WR( THEBASE, mapreg, mask );
+
+rtems_interrupt_enable(flags);
+ return 0;
+}
+
+VmeTsi148ISR
+vmeTsi148ISRGet(unsigned long vector, void **parg)
+{
+VmeTsi148ISR rval = 0;
+unsigned long flags;
+volatile IRQEntry *p;
+int v = uni2tsivec(vector);
+
+
+ if ( v < 0 )
+ return rval;
+
+ p = irqHdlTbl + v;
+
+ rtems_interrupt_disable(flags);
+ if ( *p ) {
+ if ( parg )
+ *parg = (*p)->usrData;
+ rval = (*p)->isr;
+ }
+ rtems_interrupt_enable(flags);
+
+ return rval;
+}
+
+static void
+tsiVMEISR(rtems_irq_hdl_param arg)
+{
+int pin = (int)arg;
+BERegister *b = THEBASE;
+IRQEntry ip;
+unsigned long msk,lintstat,vector, vecarg;
+int lvl;
+
+ /* only handle interrupts routed to this pin */
+
+ /* NOTE: we read the status register over VME, thus flushing the FIFO
+ * where the user ISR possibly left write commands to clear
+ * the interrupt condition at the device.
+ * This is very important - otherwise, the IRQ level may still be
+ * asserted and we would detect an interrupt here but the subsequent
+ * IACK would fail since the write operation was flushed to the
+ * device in the mean time.
+ */
+ while ( (lintstat = (TSI_RD(vmeTsi148RegBase, TSI_INTS_REG) & wire_mask[pin])) ) {
+
+ /* bit 0 is never set since it is never set in wire_mask */
+
+ do {
+ /* simplicity is king; just handle them in MSB to LSB order; reserved bits read as 0 */
+#ifdef __PPC__
+ asm volatile("cntlzw %0, %1":"=r"(lvl):"r"(lintstat));
+ lvl = 31-lvl;
+ msk = 1<<lvl;
+#else
+ { static unsigned long m[] = {
+ 0xffff0000, 0xff00ff00, 0xf0f0f0f0, 0xcccccccc, 0xaaaaaaaa
+ };
+ int i;
+ unsigned tmp;
+
+ /* lintstat has already been checked...
+ if ( !lintstat ) {
+ lvl = -1; msk = 0;
+ } else
+ */
+ for ( i=0, lvl=0, msk = lintstat; i<5; i++ ) {
+ lvl <<= 1;
+ if ( (tmp = msk & m[i]) ) {
+ lvl++;
+ msk = tmp;
+ } else
+ msk = msk & ~m[i];
+ }
+ }
+#endif
+
+ if ( lvl > 7 ) {
+ /* clear this interrupt level */
+ TSI_WR(b, TSI_INTC_REG, msk);
+ vector = 256 + lvl - 8;
+ vecarg = tsi2uni_vec_map[lvl-8];
+ } else {
+ /* need to do get the vector for this level */
+ switch ( tsi_iack_width[lvl-1] ) {
+ default:
+ case 1:
+ vector = TSI_RD8(b, TSI_VIACK_1_REG - 4 + (lvl<<2) + 3);
+ break;
+
+ case 2:
+ vector = TSI_RD16(b, TSI_VIACK_1_REG - 4 + (lvl<<2) + 2);
+ break;
+
+ case 4:
+ vector = TSI_RD(b, TSI_VIACK_1_REG - 4 + (lvl<<2));
+ break;
+ }
+ vecarg = vector;
+ }
+
+ if ( !(ip=irqHdlTbl[vector])) {
+ /* TODO: log error message - RTEMS has no logger :-( */
+ vmeTsi148IntDisable(lvl);
+ printk("vmeTsi148 ISR: ERROR: no handler registered (level %i) IACK 0x%08lx -- DISABLING level %i\n",
+ lvl, vector, lvl);
+ } else {
+ /* dispatch handler, it must clear the IRQ at the device */
+ ip->isr(ip->usrData, vecarg);
+ /* convenience for disobedient users who don't use in_xxx/out_xxx; make
+ * sure we order the subsequent read from the status register after
+ * their business.
+ */
+ iobarrier_rw();
+ }
+ } while ( (lintstat &= ~msk) );
+ /* check if a new irq is pending already */
+ }
+}
+
+
+static void
+my_no_op(const rtems_irq_connect_data * arg)
+{}
+
+static int
+my_isOn(const rtems_irq_connect_data *arg)
+{
+ return (int)(TSI_RD(THEBASE, TSI_INTEO_REG) & TSI_RD(THEBASE, TSI_INTEN_REG));
+}
+
+static void
+connectIsr(int shared, rtems_irq_hdl isr, int pic_line, int slot)
+{
+rtems_irq_connect_data xx;
+ xx.on = my_no_op; /* at _least_ they could check for a 0 pointer */
+ xx.off = my_no_op;
+ xx.isOn = my_isOn;
+ xx.hdl = isr;
+ xx.handle = (rtems_irq_hdl_param)slot;
+ xx.name = pic_line;
+
+ if ( shared ) {
+#if BSP_SHARED_HANDLER_SUPPORT > 0
+ if (!BSP_install_rtems_shared_irq_handler(&xx))
+ rtems_panic("unable to install vmeTsi148 shared irq handler");
+#else
+ uprintf(stderr,"vmeTsi148: WARNING: your BSP doesn't support sharing interrupts\n");
+ if (!BSP_install_rtems_irq_handler(&xx))
+ rtems_panic("unable to install vmeTsi148 irq handler");
+#endif
+ } else {
+ if (!BSP_install_rtems_irq_handler(&xx))
+ rtems_panic("unable to install vmeTsi148 irq handler");
+ }
+}
+
+int
+vmeTsi148InstallIrqMgrAlt(int shared, int tsi_pin0, int pic_pin0, ...)
+{
+int rval;
+va_list ap;
+ va_start(ap, pic_pin0);
+ rval = vmeTsi148InstallIrqMgrVa(shared, tsi_pin0, pic_pin0, ap);
+ va_end(ap);
+ return rval;
+}
+
+#ifndef BSP_EARLY_PROBE_VME
+#define BSP_EARLY_PROBE_VME(addr) \
+ ( \
+ vmeTsi148ClearVMEBusErrorsXX( THEBASE, 0 ), \
+ ( ((PCI_DEVICE_TSI148 << 16) | PCI_VENDOR_TUNDRA ) == TSI_LE_RD32( ((BERegister*)(addr)), 0 ) \
+ && 0 == vmeTsi148ClearVMEBusErrorsXX( THEBASE, 0 ) ) \
+ )
+#endif
+
+/* Check if there is a vme address/as is mapped in any of the outbound windows
+ * and look for the PCI vendordevice ID there.
+ * RETURNS: -1 on error (no mapping or probe failure), outbound window # (0..7)
+ * on success. Address translated into CPU address is returned in *pcpu_addr.
+ */
+static int
+mappedAndProbed(unsigned long vme_addr, unsigned as, unsigned long *pcpu_addr)
+{
+int j;
+char *regtype = (as & VME_AM_MASK) == VME_AM_CSR ? "CSR" : "CRG";
+
+ /* try to find mapping */
+ if ( 0 > (j = xlateFindPort(
+ THEBASE,
+ 1, 0,
+ as | VME_MODE_AS_MATCH,
+ vme_addr,
+ pcpu_addr ) ) ) {
+ uprintf(stderr,"vmeTsi148 - Unable to find mapping for %s VME base (0x%08x)\n", regtype, vme_addr);
+ uprintf(stderr," in outbound windows.\n");
+ }
+ else {
+ /* found a slot number; probe it */
+ *pcpu_addr = BSP_PCI2LOCAL_ADDR( *pcpu_addr );
+ if ( BSP_EARLY_PROBE_VME(*pcpu_addr) ) {
+ uprintf(stderr,"vmeTsi148 - IRQ manager using VME %s to flush FIFO\n", regtype);
+ return j;
+ } else {
+ uprintf(stderr,"vmeTsi148 - Found slot info but detection of tsi148 in VME %s space failed\n", regtype);
+ }
+ }
+ return -1;
+}
+
+int
+vmeTsi148InstallIrqMgrVa(int shared, int tsi_pin0, int pic_pin0, va_list ap)
+{
+int i,j, specialPin, tsi_pin[TSI_NUM_WIRES+1], pic_pin[TSI_NUM_WIRES];
+unsigned long cpu_base, vme_reg_base;
+
+ if (vmeTsi148IrqMgrInstalled) return -4;
+
+ /* check parameters */
+
+ if ( tsi_pin0 < 0 || tsi_pin0 > 3 ) return -1;
+
+ tsi_pin[0] = tsi_pin0;
+ pic_pin[0] = pic_pin0 < 0 ? devs[0].irqLine : pic_pin0;
+ i = 1;
+ while ( (tsi_pin[i] = va_arg(ap, int)) >= 0 ) {
+
+ if ( i >= TSI_NUM_WIRES ) {
+ return -5;
+ }
+
+ pic_pin[i] = va_arg(ap,int);
+
+ if ( tsi_pin[i] > 3 ) return -2;
+ if ( pic_pin[i] < 0 ) return -3;
+ i++;
+ }
+
+ /* all routings must be different */
+ for ( i=0; tsi_pin[i] >= 0; i++ ) {
+ for ( j=i+1; tsi_pin[j] >= 0; j++ ) {
+ if ( tsi_pin[j] == tsi_pin[i] ) return -6;
+ if ( pic_pin[j] == pic_pin[i] ) return -7;
+ }
+ }
+
+ i = -1;
+
+ /* first try VME CSR space; do we have a base address set ? */
+
+ uprintf(stderr,"vmeTsi148 IRQ manager: looking for registers on VME...\n");
+
+ if ( ( i = ((TSI_RD( THEBASE, TSI_CBAR_REG ) & 0xff) >> 3) ) > 0 ) {
+ uprintf(stderr,"Trying to find CSR on VME...\n");
+ vme_reg_base = i*0x80000 + TSI_CSR_OFFSET;
+ i = mappedAndProbed( vme_reg_base, VME_AM_CSR , &cpu_base);
+ if ( i >= 0 )
+ vmeTsi148RegCSR = 1;
+ } else {
+ i = -1;
+ }
+
+ if ( -1 == i ) {
+
+ uprintf(stderr,"Trying to find CRG on VME...\n");
+
+ /* Next we see if the CRG block is mapped to VME */
+
+ if ( (TSI_CRGAT_EN & (j = TSI_RD( THEBASE, TSI_CRGAT_REG ))) ) {
+ switch ( j & TSI_CRGAT_AS_MSK ) {
+ case TSI_CRGAT_A16 : i = VME_AM_SUP_SHORT_IO; break;
+ case TSI_CRGAT_A24 : i = VME_AM_STD_SUP_DATA; break;
+ case TSI_CRGAT_A32 : i = VME_AM_EXT_SUP_DATA; break;
+ default:
+ break;
+ }
+ vme_reg_base = TSI_RD( THEBASE, TSI_CBAL_REG ) & ~ (TSI_CRG_SIZE - 1);
+ }
+
+ if ( -1 == i ) {
+ } else {
+ i = mappedAndProbed( vme_reg_base, (i & VME_AM_MASK), &cpu_base );
+ }
+ }
+
+ if ( i < 0 ) {
+ uprintf(stderr,"vmeTsi148 IRQ manager - BSP configuration error: registers not found on VME\n");
+ uprintf(stderr,"(should open outbound window to CSR space or map CRG [vmeTsi148MapCRG()])\n");
+ uprintf(stderr,"Falling back to PCI but you might experience spurious VME interrupts; read a register\n");
+ uprintf(stderr,"back from user ISR to flush posted-write FIFO as a work-around\n");
+ cpu_base = (unsigned long)THEBASE;
+ i = -1;
+ }
+
+ vmeTsi148RegBase = (BERegister*)cpu_base;
+ vmeTsi148RegPort = i;
+
+ /* give them a chance to override buggy PCI info */
+ if ( pic_pin[0] >= 0 && devs[0].irqLine != pic_pin[0] ) {
+ uprintf(stderr,"Overriding main IRQ line PCI info with %d\n",
+ pic_pin[0]);
+ devs[0].irqLine = pic_pin[0];
+ }
+
+ for ( i = 0; tsi_pin[i] >= 0; i++ ) {
+ /* offset wire # by one so we can initialize to 0 == invalid */
+ tsi_wire[i] = tsi_pin[i] + 1;
+ connectIsr(shared, tsiVMEISR, pic_pin[i], i);
+ }
+
+ specialPin = tsi_pin[1] >= 0 ? 1 : 0;
+
+ /* setup routing */
+
+ /* IntRoute checks for mgr being installed */
+ vmeTsi148IrqMgrInstalled=1;
+
+ /* route 7 VME irqs to first / 'normal' pin */
+ for ( i=1; i<8; i++ )
+ vmeTsi148IntRoute( i, 0 );
+ for ( i=TSI_DMA_INT_VEC; i<TSI_NUM_INT_VECS; i++ )
+ vmeTsi148IntRoute( i, specialPin );
+
+ for ( i = 0; i<TSI_NUM_WIRES; i++ ) {
+ /* remember (for unloading the driver) */
+ devs[0].pic_pin[i] = ( ( tsi_pin[i] >=0 ) ? pic_pin[i] : -1 );
+ }
+
+ return 0;
+}
+
+int
+vmeTsi148InstallISR(unsigned long vector, VmeTsi148ISR hdl, void *arg)
+{
+IRQEntry ip;
+int v;
+unsigned long flags;
+volatile IRQEntry *p;
+
+ if ( !vmeTsi148IrqMgrInstalled || (v = uni2tsivec(vector)) < 0 )
+ return -1;
+
+ p = irqHdlTbl + v;
+
+ if (*p || !(ip=(IRQEntry)malloc(sizeof(IRQEntryRec))))
+ return -1;
+
+ ip->isr=hdl;
+ ip->usrData=arg;
+
+ rtems_interrupt_disable(flags);
+ if (*p) {
+ rtems_interrupt_enable(flags);
+ free(ip);
+ return -1;
+ }
+ *p = ip;
+ rtems_interrupt_enable(flags);
+ return 0;
+}
+
+int
+vmeTsi148RemoveISR(unsigned long vector, VmeTsi148ISR hdl, void *arg)
+{
+int v;
+IRQEntry ip;
+unsigned long flags;
+volatile IRQEntry *p;
+
+ if ( !vmeTsi148IrqMgrInstalled || (v = uni2tsivec(vector)) < 0 )
+ return -1;
+
+ p = irqHdlTbl + v;
+
+ rtems_interrupt_disable(flags);
+ ip = *p;
+ if ( !ip || ip->isr!=hdl || ip->usrData!=arg ) {
+ rtems_interrupt_enable(flags);
+ return -1;
+ }
+ *p = 0;
+ rtems_interrupt_enable(flags);
+
+ free(ip);
+ return 0;
+}
+
+static int
+intDoEnDis(unsigned int level, int dis)
+{
+BERegister *b = THEBASE;
+unsigned long flags, v;
+int shift;
+
+ if ( ! vmeTsi148IrqMgrInstalled || (shift = lvl2bitno(level)) < 0 )
+ return -1;
+
+ v = 1<<shift;
+
+ if ( !dis )
+ return (int)(v & TSI_RD(b, TSI_INTEO_REG) & TSI_RD(b, TSI_INTEN_REG)) ? 1 : 0;
+
+ rtems_interrupt_disable(flags);
+ if ( dis<0 ) {
+ TSI_WR(b, TSI_INTEN_REG, TSI_RD(b, TSI_INTEN_REG) & ~v);
+ TSI_WR(b, TSI_INTEO_REG, TSI_RD(b, TSI_INTEO_REG) & ~v);
+ } else {
+ TSI_WR(b, TSI_INTEN_REG, TSI_RD(b, TSI_INTEN_REG) | v);
+ TSI_WR(b, TSI_INTEO_REG, TSI_RD(b, TSI_INTEO_REG) | v);
+ }
+ rtems_interrupt_enable(flags);
+ return 0;
+}
+
+int
+vmeTsi148IntEnable(unsigned int level)
+{
+ return intDoEnDis(level, 1);
+}
+
+int
+vmeTsi148IntDisable(unsigned int level)
+{
+ return intDoEnDis(level, -1);
+}
+
+int
+vmeTsi148IntIsEnabled(unsigned int level)
+{
+ return intDoEnDis(level, 0);
+}
+
+/* Set IACK width (1,2, or 4 bytes) for a given interrupt level.
+ *
+ * 'width' arg may be 0,1,2 or 4. If zero, the currently active
+ * value is returned but not modified.
+ *
+ * RETURNS: old width or -1 if invalid argument.
+ */
+
+int
+vmeTsi148SetIackWidth(int level, int width)
+{
+int rval;
+ if ( level < 1 || level > 7 || !vmeTsi148IrqMgrInstalled )
+ return -1;
+
+ switch ( width ) {
+ default: return -1;
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ break;
+ }
+
+ rval = tsi_iack_width[level-1];
+ if ( width )
+ tsi_iack_width[level-1] = width;
+ return rval;
+}
+
+int
+vmeTsi148IntRaiseXX(BERegister *base, int level, unsigned vector)
+{
+unsigned long v;
+
+ CHECK_BASE(base,0,-1);
+
+ if ( level < 1 || level > 7 || vector > 255 )
+ return -1; /* invalid argument */
+
+ /* Check if already asserted */
+ if ( (v = TSI_RD(base, TSI_VICR_REG)) & TSI_VICR_IRQS ) {
+ return -2; /* already asserted */
+ }
+
+ v &= ~255;
+
+ v |= TSI_VICR_IRQL(level) | TSI_VICR_STID(vector);
+
+ /* Write Vector */
+ TSI_WR(base, TSI_VICR_REG, v);
+
+ return 0;
+
+}
+
+int
+vmeTsi148IntRaise(int level, unsigned vector)
+{
+ return vmeTsi148IntRaiseXX(THEBASE, level, vector);
+}
+
+/* Loopback test of VME/Tsi148 internal interrupts */
+
+typedef struct {
+ rtems_id q;
+ int l;
+} LoopbackTstArgs;
+
+static void
+loopbackTstIsr(void *arg, unsigned long vector)
+{
+LoopbackTstArgs *pa = arg;
+ if ( RTEMS_SUCCESSFUL != rtems_message_queue_send(pa->q, (void*)&vector, sizeof(vector)) ) {
+ /* Overrun ? */
+ printk("vmeTsi148IntLoopbackTst: (ISR) message queue full / overrun ? disabling IRQ level %i\n", pa->l);
+ vmeTsi148IntDisable(pa->l);
+ }
+}
+
+int
+vmeTsi148IntLoopbackTst(int level, unsigned vector)
+{
+BERegister *b = THEBASE;
+rtems_status_code sc;
+rtems_id q = 0;
+int installed = 0;
+int i, err = 0;
+int doDisable = 0;
+size_t size;
+unsigned long msg;
+char * irqfmt = "VME IRQ @vector %3i %s";
+char * iackfmt = "VME IACK %s";
+LoopbackTstArgs a;
+
+ CHECK_BASE(b,0,-1);
+
+ /* arg check */
+ if ( level < 1 || level > 7 || vector > 255 )
+ return -1;
+
+ /* Create message queue */
+ if ( RTEMS_SUCCESSFUL != (sc=rtems_message_queue_create(
+ rtems_build_name('t' ,'U','I','I'),
+ 4,
+ sizeof(unsigned long),
+ 0, /* default attributes: fifo, local */
+ &q)) ) {
+ rtems_error(sc, "vmeTsi148IntLoopbackTst: Unable to create message queue");
+ goto bail;
+ }
+
+ a.q = q;
+ a.l = level;
+
+ /* Install handlers */
+ if ( vmeTsi148InstallISR(vector, loopbackTstIsr, (void*)&a) ) {
+ uprintf(stderr,"Unable to install VME ISR to vector %i\n",vector);
+ goto bail;
+ }
+ installed++;
+ if ( vmeTsi148InstallISR(TSI_VME_SW_IACK_INT_VEC, loopbackTstIsr, (void*)&a) ) {
+ uprintf(stderr,"Unable to install VME ISR to IACK special vector %i\n",TSI_VME_SW_IACK_INT_VEC);
+ goto bail;
+ }
+ installed++;
+
+ if ( !vmeTsi148IntIsEnabled(level) && 0==vmeTsi148IntEnable(level) )
+ doDisable = 1;
+
+ /* make sure there are no pending interrupts */
+ TSI_WR(b, TSI_INTC_REG, TSI_INTC_IACKC);
+
+ if ( vmeTsi148IntEnable( TSI_VME_SW_IACK_INT_VEC ) ) {
+ uprintf(stderr,"Unable to enable IACK interrupt\n");
+ goto bail;
+ }
+
+ printf("vmeTsi148 VME interrupt loopback test; STARTING...\n");
+ printf(" --> asserting VME IRQ level %i\n", level);
+ vmeTsi148IntRaise(level, vector);
+
+ for ( i = 0; i< 3; i++ ) {
+ sc = rtems_message_queue_receive(
+ q,
+ &msg,
+ &size,
+ RTEMS_WAIT,
+ 20);
+ if ( sc ) {
+ if ( RTEMS_TIMEOUT == sc && i>1 ) {
+ /* OK; we dont' expect more to happen */
+ sc = 0;
+ } else {
+ rtems_error(sc,"Error waiting for interrupts");
+ }
+ break;
+ }
+ if ( msg == vector ) {
+ if ( !irqfmt ) {
+ printf("Excess VME IRQ received ?? -- BAD\n");
+ err = 1;
+ } else {
+ printf(irqfmt, vector, "received -- PASSED\n");
+ irqfmt = 0;
+ }
+ } else if ( msg == TSI_VME_SW_IACK_INT_VEC ) {
+ if ( !iackfmt ) {
+ printf("Excess VME IACK received ?? -- BAD\n");
+ err = 1;
+ } else {
+ printf(iackfmt, "received -- PASSED\n");
+ iackfmt = 0;
+ }
+ } else {
+ printf("Unknown IRQ (vector %lu) received -- BAD\n", msg);
+ err = 1;
+ }
+ }
+
+
+ /* Missing anything ? */
+ if ( irqfmt ) {
+ printf(irqfmt,vector, "MISSED -- BAD\n");
+ err = 1;
+ }
+ if ( iackfmt ) {
+ printf(iackfmt, "MISSED -- BAD\n");
+ err = 1;
+ }
+
+ printf("FINISHED.\n");
+
+bail:
+ if ( doDisable )
+ vmeTsi148IntDisable(level);
+ vmeTsi148IntDisable( TSI_VME_SW_IACK_INT_VEC );
+ if ( installed > 0 )
+ vmeTsi148RemoveISR(vector, loopbackTstIsr, (void*)&a);
+ if ( installed > 1 )
+ vmeTsi148RemoveISR(TSI_VME_SW_IACK_INT_VEC, loopbackTstIsr, (void*)&a);
+ if ( q )
+ rtems_message_queue_delete(q);
+
+ return sc ? sc : err;
+}
+
+unsigned long
+vmeTsi148ClearVMEBusErrorsXX(BERegister *base, uint32_t *paddr)
+{
+unsigned long rval;
+
+ CHECK_BASE(base,1,-1);
+
+ rval = TSI_RD(base, TSI_VEAT_REG);
+ if ( rval & TSI_VEAT_VES ) {
+ if ( paddr ) {
+#if 0 /* no 64-bit support yet */
+ *paddr = ((unsigned long long)TSI_RD(base, TSI_VEAU_REG))<<32;
+ *paddr |= TSI_RD(base, TSI_VEAL_REG);
+#else
+ *paddr = TSI_RD(base, TSI_VEAL_REG);
+#endif
+ }
+ /* clear errors */
+ TSI_WR(base, TSI_VEAT_REG, TSI_VEAT_VESCL);
+ } else {
+ rval = 0;
+ }
+ return rval;
+}
+
+unsigned long
+vmeTsi148ClearVMEBusErrors(uint32_t *paddr)
+{
+ return vmeTsi148ClearVMEBusErrorsXX(THEBASE, paddr);
+}
+
+/** DMA Support **/
+
+/* descriptor must be 8-byte aligned */
+typedef struct VmeTsi148DmaListDescriptorRec_ {
+ BEValue dsau, dsal;
+ BEValue ddau, ddal;
+ BEValue dsat, ddat;
+ BEValue dnlau, dnlal;
+ BEValue dcnt, ddbs;
+} VmeTsi148DmaListDescriptorRec;
+
+static void tsi_desc_init (DmaDescriptor);
+static int tsi_desc_setup (DmaDescriptor, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
+static void tsi_desc_setnxt(DmaDescriptor, DmaDescriptor);
+static void tsi_desc_dump (DmaDescriptor);
+static int tsi_desc_start (volatile void *controller_addr, int channel, DmaDescriptor p);
+
+VMEDmaListClassRec vmeTsi148DmaListClass = {
+ desc_size: sizeof(VmeTsi148DmaListDescriptorRec),
+ desc_align: 8,
+ freeList: 0,
+ desc_alloc: 0,
+ desc_free: 0,
+ desc_init: tsi_desc_init,
+ desc_setnxt:tsi_desc_setnxt,
+ desc_setup: tsi_desc_setup,
+ desc_start: tsi_desc_start,
+ desc_refr: 0,
+ desc_dump: tsi_desc_dump,
+};
+
+/* DMA Control */
+#define TSI_DMA_REG(off,i) ((off)+(((i)&1)<<7))
+
+#define TSI_DCTL_REG(i) TSI_DMA_REG(0x500,i)
+#define TSI_DCTL0_REG 0x500
+#define TSI_DCTL1_REG 0x580
+# define TSI_DCTL_ABT (1<<27) /* abort */
+# define TSI_DCTL_PAU (1<<26) /* pause */
+# define TSI_DCTL_DGO (1<<25) /* GO */
+# define TSI_DCTL_MOD (1<<23) /* linked list: 0, direct: 1 */
+# define TSI_DCTL_VFAR (1<<17) /* flush FIFO on VME error: 1 (discard: 0) */
+# define TSI_DCTL_PFAR (1<<16) /* flush FIFO on PCI error: 1 (discard: 0) */
+
+# define TSI_DCTL_VBKS(i) (((i)&7)<<12) /* VME block size */
+# define TSI_DCTL_VBKS_32 TSI_DCTL_VBKS(0)
+# define TSI_DCTL_VBKS_64 TSI_DCTL_VBKS(1)
+# define TSI_DCTL_VBKS_128 TSI_DCTL_VBKS(2)
+# define TSI_DCTL_VBKS_256 TSI_DCTL_VBKS(3)
+# define TSI_DCTL_VBKS_512 TSI_DCTL_VBKS(4)
+# define TSI_DCTL_VBKS_1024 TSI_DCTL_VBKS(5)
+# define TSI_DCTL_VBKS_2048 TSI_DCTL_VBKS(6)
+# define TSI_DCTL_VBKS_4096 TSI_DCTL_VBKS(7)
+
+# define TSI_DCTL_VBOT(i) (((i)&7)<< 8) /* VME back-off time */
+# define TSI_DCTL_VBOT_0us TSI_DCTL_VBOT(0)
+# define TSI_DCTL_VBOT_1us TSI_DCTL_VBOT(1)
+# define TSI_DCTL_VBOT_2us TSI_DCTL_VBOT(2)
+# define TSI_DCTL_VBOT_4us TSI_DCTL_VBOT(3)
+# define TSI_DCTL_VBOT_8us TSI_DCTL_VBOT(4)
+# define TSI_DCTL_VBOT_16us TSI_DCTL_VBOT(5)
+# define TSI_DCTL_VBOT_32us TSI_DCTL_VBOT(6)
+# define TSI_DCTL_VBOT_64us TSI_DCTL_VBOT(7)
+
+# define TSI_DCTL_PBKS(i) (((i)&7)<< 4) /* PCI block size */
+# define TSI_DCTL_PBKS_32 TSI_DCTL_PBKS(0)
+# define TSI_DCTL_PBKS_64 TSI_DCTL_PBKS(1)
+# define TSI_DCTL_PBKS_128 TSI_DCTL_PBKS(2)
+# define TSI_DCTL_PBKS_256 TSI_DCTL_PBKS(3)
+# define TSI_DCTL_PBKS_512 TSI_DCTL_PBKS(4)
+# define TSI_DCTL_PBKS_1024 TSI_DCTL_PBKS(5)
+# define TSI_DCTL_PBKS_2048 TSI_DCTL_PBKS(6)
+# define TSI_DCTL_PBKS_4096 TSI_DCTL_PBKS(7)
+
+# define TSI_DCTL_PBOT(i) (((i)&7)<< 0) /* PCI back-off time */
+# define TSI_DCTL_PBOT_0us TSI_DCTL_PBOT(0)
+# define TSI_DCTL_PBOT_1us TSI_DCTL_PBOT(1)
+# define TSI_DCTL_PBOT_2us TSI_DCTL_PBOT(2)
+# define TSI_DCTL_PBOT_4us TSI_DCTL_PBOT(3)
+# define TSI_DCTL_PBOT_8us TSI_DCTL_PBOT(4)
+# define TSI_DCTL_PBOT_16us TSI_DCTL_PBOT(5)
+# define TSI_DCTL_PBOT_32us TSI_DCTL_PBOT(6)
+# define TSI_DCTL_PBOT_64us TSI_DCTL_PBOT(7)
+
+/* DMA Status */
+#define TSI_DSTA_REG(i) TSI_DMA_REG(0x504,i)
+#define TSI_DSTA0_REG 0x504
+#define TSI_DSTA1_REG 0x584
+# define TSI_DSTA_ERR (1<<28)
+# define TSI_DSTA_ABT (1<<27)
+# define TSI_DSTA_PAU (1<<26)
+# define TSI_DSTA_DON (1<<25)
+# define TSI_DSTA_BSY (1<<24)
+# define TSI_DSTA_ERRS (1<<20) /* Error source; PCI:1, VME:0 */
+# define TSI_DSTA_ERT_MSK (3<<16) /* Error type */
+# define TSI_DSTA_ERT_BERR_E (0<<16) /* 2eVME even or other bus error */
+# define TSI_DSTA_ERT_BERR_O (1<<16) /* 2eVME odd bus error */
+# define TSI_DSTA_ERT_SLVE_E (2<<16) /* 2eVME even or other slave termination */
+# define TSI_DSTA_ERT_SLVE_O (3<<16) /* 2eVME odd slave termination; 2eSST read last word invalid */
+
+/* DMA Current source address upper */
+#define TSI_DCSAU_REG(i) TSI_DMA_REG(0x508,i)
+#define TSI_DCSAU0_REG 0x508
+#define TSI_DCSAU1_REG 0x588
+
+/* DMA Current source address lower */
+#define TSI_DCSAL_REG(i) TSI_DMA_REG(0x50c,i)
+#define TSI_DCSAL0_REG 0x50c
+#define TSI_DCSAL1_REG 0x58c
+
+/* DMA Current destination address upper */
+#define TSI_DCDAU_REG(i) TSI_DMA_REG(0x510,i)
+#define TSI_DCDAU0_REG 0x510
+#define TSI_DCDAU1_REG 0x590
+
+/* DMA Current destination address lower */
+#define TSI_DCDAL_REG(i) TSI_DMA_REG(0x514,i)
+#define TSI_DCDAL0_REG 0x514
+#define TSI_DCDAL1_REG 0x594
+
+/* DMA Current link address upper */
+#define TSI_DCLAU_REG(i) TSI_DMA_REG(0x518,i)
+#define TSI_DCLAU0_REG 0x518
+#define TSI_DCLAU1_REG 0x598
+
+/* DMA Current link address lower */
+#define TSI_DCLAL_REG(i) TSI_DMA_REG(0x51c,i)
+#define TSI_DCLAL0_REG 0x51c
+#define TSI_DCLAL1_REG 0x59c
+
+/* DMA Source address upper */
+#define TSI_DSAU_REG(i) TSI_DMA_REG(0x520,i)
+#define TSI_DSAU0_REG 0x520
+#define TSI_DSAU1_REG 0x5a0
+
+/* DMA Source address lower */
+#define TSI_DSAL_REG(i) TSI_DMA_REG(0x524,i)
+#define TSI_DSAL0_REG 0x524
+#define TSI_DSAL1_REG 0x5a4
+
+/* DMA Destination address upper */
+#define TSI_DDAU_REG(i) TSI_DMA_REG(0x528,i)
+#define TSI_DDAU0_REG 0x528
+#define TSI_DDAU1_REG 0x5a8
+
+/* DMA Destination address lower */
+#define TSI_DDAL_REG(i) TSI_DMA_REG(0x52c,i)
+#define TSI_DDAL0_REG 0x52c
+#define TSI_DDAL1_REG 0x5ac
+
+/* DMA Source Attribute */
+#define TSI_DSAT_REG(i) TSI_DMA_REG(0x530,i)
+#define TSI_DSAT0_REG 0x530
+#define TSI_DSAT1_REG 0x5b0
+
+/* DMA Destination Attribute */
+#define TSI_DDAT_REG(i) TSI_DMA_REG(0x534,i)
+#define TSI_DDAT0_REG 0x534
+#define TSI_DDAT1_REG 0x5b4
+
+# define TSI_DXAT_TYP(i) (((i)&3)<<28) /* Xfer type */
+# define TSI_DXAT_TYP_PCI TSI_DXAT_TYP(0)
+# define TSI_DXAT_TYP_VME TSI_DXAT_TYP(1)
+# define TSI_DSAT_TYP_PAT TSI_DXAT_TYP(2) /* pattern */
+
+# define TSI_DSAT_PSZ (1<<25) /* pattern size 32-bit: 0, 8-bit: 1 */
+# define TSI_DSAT_NIN (1<<24) /* no-increment */
+
+# define TSI_DXAT_OTAT_MSK ((1<<13)-1) /* get bits compatible with OTAT */
+
+# define TSI_DXAT_SSTM(i) (((i)&3)<<11) /* 2eSST Xfer rate (MB/s) */
+# define TSI_DXAT_SSTM_116 TSI_DXAT_SSTM(0)
+# define TSI_DXAT_SSTM_267 TSI_DXAT_SSTM(1)
+# define TSI_DXAT_SSTM_320 TSI_DXAT_SSTM(2)
+
+# define TSI_DXAT_TM(i) (((i)&7)<< 8) /* VME Xfer mode */
+# define TSI_DXAT_TM_SCT TSI_DXAT_TM(0)
+# define TSI_DXAT_TM_BLT TSI_DXAT_TM(1)
+# define TSI_DXAT_TM_MBLT TSI_DXAT_TM(2)
+# define TSI_DXAT_TM_2eVME TSI_DXAT_TM(3)
+# define TSI_DXAT_TM_2eSST TSI_DXAT_TM(4)
+# define TSI_DSAT_TM_2eSST_B TSI_DXAT_TM(5) /* 2eSST broadcast */
+
+# define TSI_DXAT_DBW(i) (((i)&3)<< 6) /* VME Data width */
+# define TSI_DXAT_DBW_16 TSI_DXAT_DBW(0)
+# define TSI_DXAT_DBW_32 TSI_DXAT_DBW(1)
+
+# define TSI_DXAT_SUP (1<<5) /* supervisor access */
+# define TSI_DXAT_PGM (1<<4) /* program access */
+
+# define TSI_DXAT_AM(i) (((i)&15)<<0) /* VME Address mode */
+# define TSI_DXAT_AM_A16 TSI_DXAT_AM(0)
+# define TSI_DXAT_AM_A24 TSI_DXAT_AM(1)
+# define TSI_DXAT_AM_A32 TSI_DXAT_AM(2)
+# define TSI_DXAT_AM_A64 TSI_DXAT_AM(4)
+# define TSI_DXAT_AM_CSR TSI_DXAT_AM(5)
+
+/* DMA Next link address upper */
+#define TSI_DNLAU_REG(i) TSI_DMA_REG(0x538,i)
+#define TSI_DNLAU0_REG 0x538
+#define TSI_DNLAU1_REG 0x5b8
+
+/* DMA Next link address lower */
+#define TSI_DNLAL_REG(i) TSI_DMA_REG(0x53c,i)
+#define TSI_DNLAL0_REG 0x53c
+#define TSI_DNLAL1_REG 0x5bc
+
+# define TSI_DNLAL_LLA 1 /* last element in chain */
+
+/* DMA Byte Count */
+#define TSI_DCNT_REG(i) TSI_DMA_REG(0x540,i)
+#define TSI_DCNT0_REG 0x540
+#define TSI_DCNT1_REG 0x54c
+
+/* DMA 2eSST destination broadcast select */
+#define TSI_DDBS_REG(i) TSI_DMA_REG(0x544,i)
+#define TSI_DDBS0_REG 0x544
+#define TSI_DDBS1_REG 0x5c4
+
+/* Convert canonical xfer_mode into Tsi148 bits; return -1 if invalid */
+static uint32_t
+vme_attr(uint32_t xfer_mode)
+{
+uint32_t vme_mode;
+ if ( am2omode(xfer_mode, &vme_mode) )
+ return BSP_VMEDMA_STATUS_UNSUP;
+
+ /* am2omode may set prefetch and other bits */
+ vme_mode &= TSI_DXAT_OTAT_MSK;
+ vme_mode |= TSI_DXAT_TYP_VME;
+
+ if ( BSP_VMEDMA_MODE_NOINC_VME & xfer_mode ) {
+ /* no-incr. only supported on source address */
+ if ( (BSP_VMEDMA_MODE_PCI2VME & xfer_mode) )
+ return BSP_VMEDMA_STATUS_UNSUP;
+ vme_mode |= TSI_DSAT_NIN;
+ }
+
+ return vme_mode;
+}
+
+static uint32_t
+pci_attr(uint32_t xfer_mode)
+{
+uint32_t pci_mode = 0;
+ if ( BSP_VMEDMA_MODE_NOINC_PCI & xfer_mode ) {
+ /* no-incr. only supported on source address */
+ if ( ! (BSP_VMEDMA_MODE_PCI2VME & xfer_mode) )
+ return BSP_VMEDMA_STATUS_UNSUP;
+ pci_mode |= TSI_DSAT_NIN;
+ }
+ return pci_mode;
+}
+
+static void tsi_desc_init(DmaDescriptor p)
+{
+VmeTsi148DmaListDescriptor d = p;
+ st_be32( &d->dnlau, 0 );
+ st_be32( &d->dnlal, TSI_DNLAL_LLA );
+ st_be32( &d->ddbs, (1<<22)-1 ); /* SSTB broadcast not yet fully supported */
+}
+
+static void
+tsi_desc_setnxt(DmaDescriptor p, DmaDescriptor n)
+{
+VmeTsi148DmaListDescriptor d = p;
+ if ( 0 == n ) {
+ st_be32( &d->dnlal, TSI_DNLAL_LLA );
+ } else {
+ st_be32( &d->dnlal, BSP_LOCAL2PCI_ADDR((uint32_t)n) );
+ }
+}
+
+static void
+tsi_desc_dump(DmaDescriptor p)
+{
+VmeTsi148DmaListDescriptor d = p;
+ printf(" DSA: 0x%08lx%08lx\n", ld_be32(&d->dsau), ld_be32(&d->dsal));
+ printf(" DDA: 0x%08lx%08lx\n", ld_be32(&d->ddau), ld_be32(&d->ddal));
+ printf(" NLA: 0x%08lx%08lx\n", ld_be32(&d->dnlau), ld_be32(&d->dnlal));
+ printf(" SAT: 0x%08lx DAT: 0x%08lx\n", ld_be32(&d->dsat), ld_be32(&d->ddat));
+ printf(" CNT: 0x%08lx\n", ld_be32(&d->dcnt));
+}
+
+
+int
+vmeTsi148DmaSetupXX(BERegister *base, int channel, uint32_t mode, uint32_t xfer_mode, void *custom)
+{
+uint32_t ctl = 0;
+uint32_t vmeatt, pciatt, sat, dat;
+
+ if ( channel < 0 || channel > 1 )
+ return BSP_VMEDMA_STATUS_UNSUP;
+
+ /* Check bus mode */
+ if ( (uint32_t)BSP_VMEDMA_STATUS_UNSUP == (vmeatt = vme_attr(xfer_mode)) )
+ return -2;
+
+ /* Check PCI bus mode */
+ if ( (uint32_t)BSP_VMEDMA_STATUS_UNSUP == (pciatt = pci_attr(xfer_mode)) )
+ return -3;
+
+ /* Compute control word; bottleneck is VME; */
+ ctl |= TSI_DCTL_PBKS_32;
+ ctl |= (BSP_VMEDMA_OPT_THROUGHPUT == mode ? TSI_DCTL_PBOT_0us : TSI_DCTL_PBOT_1us);
+
+ switch ( mode ) {
+ case BSP_VMEDMA_OPT_THROUGHPUT:
+ ctl |= TSI_DCTL_VBKS_1024;
+ ctl |= TSI_DCTL_VBOT_0us;
+ break;
+
+ case BSP_VMEDMA_OPT_LOWLATENCY:
+ ctl |= TSI_DCTL_VBKS_32;
+ ctl |= TSI_DCTL_VBOT_0us;
+ break;
+
+ case BSP_VMEDMA_OPT_SHAREDBUS:
+ ctl |= TSI_DCTL_VBKS_128;
+ ctl |= TSI_DCTL_VBOT_64us;
+ break;
+
+ case BSP_VMEDMA_OPT_CUSTOM:
+ ctl = *(uint32_t*)custom;
+ break;
+
+ default:
+ case BSP_VMEDMA_OPT_DEFAULT:
+ ctl = 0;
+ break;
+ }
+ TSI_WR(base, TSI_DCTL_REG(channel), ctl);
+ if ( BSP_VMEDMA_MODE_PCI2VME & xfer_mode ) {
+ dat = vmeatt; sat = pciatt;
+ } else {
+ sat = vmeatt; dat = pciatt;
+ }
+ TSI_WR(base, TSI_DSAT_REG(channel), sat);
+ TSI_WR(base, TSI_DDAT_REG(channel), dat);
+ return 0;
+}
+
+int
+vmeTsi148DmaSetup(int channel, uint32_t mode, uint32_t xfer_mode, void *custom)
+{
+BERegister *base = THEBASE;
+ return vmeTsi148DmaSetupXX(base, channel, mode, xfer_mode, custom);
+}
+
+
+int
+vmeTsi148DmaListStartXX(BERegister *base, int channel, VmeTsi148DmaListDescriptor d)
+{
+uint32_t ctl;
+
+ if ( d ) {
+ /* Set list pointer and start */
+ if ( channel < 0 || channel > 1 )
+ return BSP_VMEDMA_STATUS_UNSUP;
+
+ if ( TSI_DSTA_BSY & TSI_RD(base, TSI_DSTA_REG(channel)) )
+ return BSP_VMEDMA_STATUS_BUSY; /* channel busy */
+
+ TSI_WR(base, TSI_DNLAL_REG(channel), (uint32_t)BSP_LOCAL2PCI_ADDR(d));
+
+ asm volatile("":::"memory");
+
+ /* Start transfer */
+ ctl = TSI_RD(base, TSI_DCTL_REG(channel)) | TSI_DCTL_DGO;
+ ctl &= ~TSI_DCTL_MOD;
+ TSI_WR(base, TSI_DCTL_REG(channel), ctl);
+ }
+ /* else: list vs. direct mode is set by the respective start commands */
+ return 0;
+}
+
+int
+vmeTsi148DmaListStart(int channel, VmeTsi148DmaListDescriptor d)
+{
+BERegister *base = THEBASE;
+ return vmeTsi148DmaListStartXX(base, channel, d);
+}
+
+int
+vmeTsi148DmaStartXX(BERegister *base, int channel, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes)
+{
+uint32_t src, dst, ctl;
+
+ if ( channel < 0 || channel > 1 )
+ return BSP_VMEDMA_STATUS_UNSUP;
+
+ if ( TSI_DSTA_BSY & TSI_RD(base, TSI_DSTA_REG(channel)) )
+ return BSP_VMEDMA_STATUS_BUSY; /* channel busy */
+
+ /* retrieve direction from dst attribute */
+ if ( TSI_DXAT_TYP_VME & TSI_RD(base, TSI_DDAT_REG(channel)) ) {
+ dst = vme_addr;
+ src = pci_addr;
+ } else {
+ src = vme_addr;
+ dst = pci_addr;
+ }
+ /* FIXME: we leave the 'upper' registers (topmost 32bits) alone.
+ * Probably, we should reset them at init...
+ */
+ TSI_WR(base, TSI_DSAL_REG(channel), src);
+ TSI_WR(base, TSI_DDAL_REG(channel), dst);
+ TSI_WR(base, TSI_DCNT_REG(channel), n_bytes);
+
+ asm volatile("":::"memory");
+
+ /* Start transfer */
+ ctl = TSI_RD(base, TSI_DCTL_REG(channel)) | TSI_DCTL_DGO | TSI_DCTL_MOD;
+ TSI_WR(base, TSI_DCTL_REG(channel), ctl);
+
+ return 0;
+}
+
+int
+vmeTsi148DmaStart(int channel, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes)
+{
+BERegister *base = THEBASE;
+ return vmeTsi148DmaStartXX(base, channel, pci_addr, vme_addr, n_bytes);
+}
+
+uint32_t
+vmeTsi148DmaStatusXX(BERegister *base, int channel)
+{
+uint32_t st = TSI_RD(base, TSI_DSTA_REG(channel));
+
+ if ( channel < 0 || channel > 1 )
+ return BSP_VMEDMA_STATUS_UNSUP;
+
+ st = TSI_RD(base, TSI_DSTA_REG(channel));
+
+ /* Status can be zero if an empty list (all counts == 0) is executed */
+ if ( (TSI_DSTA_DON & st) || 0 == st )
+ return BSP_VMEDMA_STATUS_OK;
+
+ if ( TSI_DSTA_BSY & st )
+ return BSP_VMEDMA_STATUS_BUSY; /* channel busy */
+
+ if ( TSI_DSTA_ERR & st ) {
+ if ( TSI_DSTA_ERRS & st )
+ return BSP_VMEDMA_STATUS_BERR_PCI;
+ if ( ! (TSI_DSTA_ERT_SLVE_E & st) )
+ return BSP_VMEDMA_STATUS_BERR_VME;
+ }
+
+ return BSP_VMEDMA_STATUS_OERR;
+}
+
+uint32_t
+vmeTsi148DmaStatus(int channel)
+{
+BERegister *base = THEBASE;
+ return vmeTsi148DmaStatusXX(base, channel);
+}
+
+#define ALL_BITS_NEEDED (BSP_VMEDMA_MSK_ATTR | BSP_VMEDMA_MSK_PCIA | BSP_VMEDMA_MSK_VMEA)
+
+static int
+tsi_desc_setup (
+ DmaDescriptor p,
+ uint32_t attr_mask,
+ uint32_t xfer_mode,
+ uint32_t pci_addr,
+ uint32_t vme_addr,
+ uint32_t n_bytes)
+{
+VmeTsi148DmaListDescriptor d = p;
+uint32_t vmeatt = 0, pciatt = 0, tmp, src, dst, dat, sat;
+
+ /* argument check */
+
+ /* since we must vme/pci into src/dst we need the direction
+ * bit. Reject requests that have only part of the mask
+ * bits set. It would be possible to be more sophisticated
+ * by caching more information but we try to be simple here...
+ */
+ tmp = attr_mask & ALL_BITS_NEEDED;
+ if ( tmp != 0 && tmp != ALL_BITS_NEEDED )
+ return -1;
+
+ if ( BSP_VMEDMA_MSK_ATTR & attr_mask ) {
+ /* Check VME bus mode */
+ vmeatt = vme_attr(xfer_mode);
+ if ( (uint32_t)BSP_VMEDMA_STATUS_UNSUP == vmeatt )
+ return -1;
+
+ /* Check PCI bus mode */
+ pciatt = pci_attr(xfer_mode);
+ if ( (uint32_t)BSP_VMEDMA_STATUS_UNSUP == pciatt )
+ return -1;
+ }
+
+ if ( BSP_VMEDMA_MSK_ATTR & attr_mask ) {
+ if ( BSP_VMEDMA_MODE_PCI2VME & xfer_mode ) {
+ dat = vmeatt; sat = pciatt;
+ dst = vme_addr; src = pci_addr;
+ } else {
+ sat = vmeatt; dat = pciatt;
+ src = vme_addr; dst = pci_addr;
+ }
+ st_be32( &d->dsau, 0 ); st_be32( &d->dsal, src );
+ st_be32( &d->ddau, 0 ); st_be32( &d->ddal, dst );
+ st_be32( &d->dsat, sat ); st_be32( &d->ddat, dat );
+ }
+
+ if ( BSP_VMEDMA_MSK_BCNT & attr_mask )
+ st_be32( &d->dcnt, n_bytes);
+
+ return 0;
+}
+
+static int
+tsi_desc_start (volatile void *controller_addr, int channel, DmaDescriptor p)
+{
+VmeTsi148DmaListDescriptor d = p;
+ if ( !controller_addr )
+ controller_addr = THEBASE;
+ return vmeTsi148DmaListStartXX((BERegister*)controller_addr, channel, d);
+}
+
+#ifdef DEBUG_MODULAR
+void
+_cexpModuleInitialize(void* unused)
+{
+ vmeTsi148Init();
+ vmeTsi148Reset();
+}
+
+int
+_cexpModuleFinalize(void *unused)
+{
+int i;
+int rval = 1;
+void (*isrs[TSI_NUM_WIRES])() = {
+ isr_pin0,
+ isr_pin1,
+ isr_pin2,
+ isr_pin3,
+};
+
+rtems_irq_connect_data xx;
+ xx.on = my_no_op; /* at _least_ they could check for a 0 pointer */
+ xx.off = my_no_op;
+ xx.isOn = my_isOn;
+
+ TSI_WR(THEBASE, TSI_INTEO_REG, 0);
+
+ for ( i=0; i<TSI_NUM_INT_VECS; i++) {
+ /* Dont even bother to uninstall handlers */
+ }
+ if ( vmeTsi148IrqMgrInstalled ) {
+ for ( i=0; i<TSI_NUM_WIRES; i++ ) {
+ if ( (int)(xx.name = devs[0].pic_pin[i]) >=0 ) {
+ xx.hdl = isrs[i];
+ rval = rval && BSP_remove_rtems_irq_handler(&xx);
+ }
+ }
+ }
+ return !rval;
+}
+#endif
diff --git a/bsps/powerpc/shared/vme/vmeUniverse.c b/bsps/powerpc/shared/vme/vmeUniverse.c
new file mode 100644
index 0000000000..c7373b4e51
--- /dev/null
+++ b/bsps/powerpc/shared/vme/vmeUniverse.c
@@ -0,0 +1,2504 @@
+/* Driver for the Tundra Universe II pci-vme bridge */
+
+/*
+ * Authorship
+ * ----------
+ * This software was created by
+ * Till Straumann <strauman@slac.stanford.edu>, 2000-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * This software was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#if defined(__rtems__)
+#ifndef __INSIDE_RTEMS_BSP__
+#define __INSIDE_RTEMS_BSP__
+#endif
+#endif
+
+#include <bsp/vmeUniverse.h>
+#include <bsp/vmeUniverseDMA.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_MCTL_VASCSR (0x00050000)
+#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_VDW16 (0x00400000)
+#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)
+
+#ifdef __rtems__
+
+#include <stdlib.h>
+#include <rtems/bspIo.h> /* printk */
+#include <rtems/error.h>
+#include <rtems/pci.h>
+#include <bsp.h>
+#include <libcpu/byteorder.h>
+
+/* allow the BSP to override the default routines */
+#ifndef BSP_PCI_FIND_DEVICE
+#define BSP_PCI_FIND_DEVICE pci_find_device
+#endif
+#ifndef BSP_PCI_CONFIG_IN_LONG
+#define BSP_PCI_CONFIG_IN_LONG pci_read_config_dword
+#endif
+#ifndef BSP_PCI_CONFIG_IN_BYTE
+#define BSP_PCI_CONFIG_IN_BYTE pci_read_config_byte
+#endif
+#ifndef BSP_PCI_CONFIG_IN_SHORT
+#define BSP_PCI_CONFIG_IN_SHORT pci_read_config_word
+#endif
+#ifndef BSP_PCI_CONFIG_OUT_SHORT
+#define BSP_PCI_CONFIG_OUT_SHORT pci_write_config_word
+#endif
+
+/* PCI_MEM_BASE is a possible offset between CPU- and PCI addresses.
+ * Should be defined by the BSP.
+ */
+typedef uint32_t pci_ulong;
+
+#ifndef BSP_PCI2LOCAL_ADDR
+#ifndef PCI_MEM_BASE
+#define PCI_MEM_BASE 0
+#endif
+#define BSP_PCI2LOCAL_ADDR(memaddr) ((pci_ulong)(memaddr) + PCI_MEM_BASE)
+#endif
+
+#ifndef BSP_LOCAL2PCI_ADDR
+#ifndef PCI_DRAM_OFFSET
+#define PCI_DRAM_OFFSET 0
+#endif
+#define BSP_LOCAL2PCI_ADDR(pciaddr) ((uint32_t)(pciaddr) + PCI_DRAM_OFFSET)
+#endif
+
+
+#elif defined(__vxworks)
+typedef unsigned long pci_ulong;
+#define BSP_PCI2LOCAL_ADDR(memaddr) (memaddr)
+#define BSP_PCI_FIND_DEVICE pciFindDevice
+#define BSP_PCI_CONFIG_IN_LONG pciConfigInLong
+#define BSP_PCI_CONFIG_IN_BYTE pciConfigInByte
+#else
+#error "vmeUniverse not ported to this architecture yet"
+#endif
+
+#ifndef PCI_INTERRUPT_LINE
+#define PCI_INTERRUPT_LINE 0x3c
+#endif
+
+volatile LERegister *vmeUniverse0BaseAddr=0;
+int vmeUniverse0PciIrqLine=-1;
+
+#ifdef __rtems__
+int vmeUniverseRegPort = -1;
+int vmeUniverseRegCSR = 0;
+#endif
+
+#define DFLT_BASE volatile LERegister *base = vmeUniverse0BaseAddr
+
+#define CHECK_DFLT_BASE(base) \
+ do { \
+ /* get the universe base address */ \
+ if (!base) { \
+ if (vmeUniverseInit()) { \
+ uprintf(stderr,"unable to find the universe in pci config space\n"); \
+ return -1; \
+ } else { \
+ base = vmeUniverse0BaseAddr; \
+ } \
+ } \
+ } while (0)
+
+#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 uint32_t *)(((uint32_t)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 uint32_t*)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)
+
+#if defined(__rtems__) && 0
+static int
+uprintk(char *fmt, va_list ap)
+{
+int rval;
+extern int k_vsprintf(char *, char *, va_list);
+/* 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 = k_vsprintf(buf,fmt,ap);
+ if (rval > sizeof(buf))
+ rtems_panic("vmeUniverse/uprintk: buffer overrun");
+ printk(buf);
+ return rval;
+}
+#endif
+
+
+/* private printing wrapper */
+static void
+uprintf(FILE *f, char *fmt, ...)
+{
+va_list ap;
+ 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.
+ */
+ vprintk(fmt,ap);
+ } else
+#endif
+ {
+ vfprintf(f,fmt,ap);
+ }
+ va_end(ap);
+}
+
+static int
+vmeUniverseFindPciBase(
+ int instance,
+ volatile LERegister **pbase
+ )
+{
+int bus,dev,fun;
+unsigned short wrd;
+pci_ulong busaddr;
+unsigned char irqline;
+
+ if (BSP_PCI_FIND_DEVICE(
+ PCI_VENDOR_TUNDRA,
+ PCI_DEVICE_UNIVERSEII,
+ instance,
+ &bus,
+ &dev,
+ &fun))
+ return -1;
+ if (BSP_PCI_CONFIG_IN_LONG(bus,dev,fun,PCI_UNIVERSE_BASE0,&busaddr))
+ return -1;
+ if ((unsigned long)(busaddr) & 1) {
+ /* it's IO space, try BASE1 */
+ if (BSP_PCI_CONFIG_IN_LONG(bus,dev,fun,PCI_UNIVERSE_BASE1,&busaddr)
+ || ((unsigned long)(busaddr) & 1))
+ return -1;
+ }
+ *pbase=(volatile LERegister*)BSP_PCI2LOCAL_ADDR(busaddr);
+
+ if (BSP_PCI_CONFIG_IN_BYTE(bus,dev,fun,PCI_INTERRUPT_LINE,&irqline))
+ return -1;
+
+ /* Enable PCI master and memory access */
+ BSP_PCI_CONFIG_IN_SHORT(bus, dev, fun, PCI_COMMAND, &wrd);
+ BSP_PCI_CONFIG_OUT_SHORT(bus, dev, fun, PCI_COMMAND, wrd | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+ return irqline;
+}
+
+/* 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;
+unsigned long vdw =0;
+
+ /* 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.
+ * ????????
+ */
+
+ address_space &= ~VME_MODE_MATCH_MASK;
+
+ if (!ismaster) {
+ mode |= UNIV_SCTL_DAT | UNIV_SCTL_PGM;
+ mode |= UNIV_SCTL_USER;
+ if ( VME_AM_IS_MEMORY & address_space )
+ mode |= UNIV_SCTL_PWEN | UNIV_SCTL_PREN;
+ mode |= UNIV_SCTL_EN;
+ } else {
+ switch ( VME_MODE_DBW_MSK & address_space ) {
+ default:
+ vdw = UNIV_MCTL_VDW64;
+ break;
+
+ case VME_MODE_DBW8:
+ break;
+
+ case VME_MODE_DBW16:
+ vdw = UNIV_MCTL_VDW16;
+ break;
+
+ case VME_MODE_DBW32:
+ vdw = UNIV_MCTL_VDW32;
+ break;
+ }
+ if ( VME_AM_IS_MEMORY & address_space )
+ mode |= UNIV_MCTL_PWEN;
+ mode |= UNIV_MCTL_EN;
+ }
+
+ address_space &= ~VME_AM_IS_MEMORY;
+
+ switch (address_space & VME_AM_MASK) {
+ 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:
+ case VME_AM_STD_SUP_BLT:
+ case VME_AM_STD_SUP_MBLT:
+ case VME_AM_STD_USR_BLT:
+ case VME_AM_STD_USR_MBLT:
+
+ if ( ismaster ) {
+ switch ( address_space & 3 ) {
+ case 0: /* mblt */
+ if ( UNIV_MCTL_VDW64 != vdw )
+ return -1;
+ break;
+
+ case 3: /* blt */
+ mode |= UNIV_MCTL_VCT;
+ /* universe may do mblt anyways so go back to
+ * 32-bit width
+ */
+ vdw = UNIV_MCTL_VDW32;
+ }
+ }
+
+ 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:
+ case VME_AM_EXT_SUP_BLT:
+ case VME_AM_EXT_SUP_MBLT:
+ case VME_AM_EXT_USR_BLT:
+ case VME_AM_EXT_USR_MBLT:
+
+ if ( ismaster ) {
+ switch ( address_space & 3 ) {
+ case 0: /* mblt */
+ if ( UNIV_MCTL_VDW64 != vdw )
+ return -1;
+ break;
+
+ case 3: /* blt */
+ mode |= UNIV_MCTL_VCT;
+ /* universe may do mblt anyways so go back to
+ * 32-bit width
+ */
+ vdw = UNIV_MCTL_VDW32;
+ }
+ }
+
+ mode |= UNIV_CTL_VAS32;
+
+ break;
+
+ case VME_AM_SUP_SHORT_IO:
+ case VME_AM_USR_SHORT_IO:
+ mode |= UNIV_CTL_VAS16;
+ break;
+
+ case VME_AM_CSR:
+ if ( !ismaster )
+ return -1;
+ mode |= UNIV_MCTL_VASCSR;
+ break;
+
+ case 0: /* disable the port alltogether */
+ break;
+
+ default:
+ return -1;
+ }
+ if ( VME_AM_IS_SUP(address_space) )
+ mode |= (ismaster ? UNIV_MCTL_SUPER : UNIV_SCTL_SUPER);
+
+ mode |= vdw; /* vdw still 0 in slave mode */
+ *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(
+ volatile LERegister *base,
+ unsigned long ismaster,
+ unsigned long port,
+ unsigned long address_space,
+ unsigned long vme_address,
+ unsigned long local_address,
+ unsigned long length)
+{
+volatile LERegister *preg;
+unsigned long p=port;
+unsigned long mode=0;
+
+ CHECK_DFLT_BASE(base);
+
+ /* 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;
+ }
+
+ preg=base;
+
+ /* 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
+
+#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;
+}
+
+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,"%d: 0x%08lx 0x%08lx 0x%08lx ",
+ portno,offst,bound-start,start);
+ } else {
+ uprintf(f,"%d: 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;
+ case UNIV_MCTL_VASCSR: if ( ismaster ) { uprintf(f,"CSR, "); break; }
+ /* else fallthru */
+ default: uprintf(f,"A??, "); break;
+ }
+
+ if (ismaster) {
+ unsigned vdw;
+ switch ( cntrl & UNIV_MCTL_VDW64 ) {
+ case UNIV_MCTL_VDW64:
+ vdw = 64;
+ break;
+
+ case UNIV_MCTL_VDW32:
+ vdw = 32;
+ break;
+
+ case UNIV_MCTL_VDW16:
+ vdw = 16;
+ break;
+
+ default:
+ vdw = 8;
+ break;
+ }
+
+ if ( 64 == vdw ) {
+ switch ( UNIV_CTL_VAS & cntrl ) {
+ case UNIV_CTL_VAS24:
+ case UNIV_CTL_VAS32:
+ uprintf(f,"D64 [MBLT], ");
+ break;
+
+ default:
+ uprintf(f,"D64, ");
+ break;
+ }
+ } else {
+ uprintf(f, "D%u%s, ", vdw, (cntrl & UNIV_MCTL_VCT) ? " [BLT]" : "");
+ }
+
+ uprintf(f,"%s, %s",
+ cntrl&UNIV_MCTL_PGM ? "Pgm" : "Dat",
+ cntrl&UNIV_MCTL_SUPER ? "Sup" : "Usr");
+ if ( cntrl & UNIV_MCTL_PWEN )
+ uprintf(f,", PWEN");
+ } 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" : "");
+ if ( cntrl & UNIV_SCTL_PWEN )
+ uprintf(f,", PWEN");
+ if ( cntrl & UNIV_SCTL_PREN )
+ uprintf(f,", PREN");
+ }
+ uprintf(f,"\n");
+ return 0;
+}
+
+typedef struct XlatRec_ {
+ unsigned long address;
+ unsigned long aspace;
+ unsigned reverse; /* find reverse mapping of this port */
+} 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)
+ * port+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;
+ }
+
+
+ switch (VME_MODE_MATCH_MASK & l->aspace) {
+ case VME_MODE_EXACT_MATCH:
+ mask = -1 & ~VME_MODE_MATCH_MASK;
+ break;
+
+ case VME_MODE_AS_MATCH:
+ mask = UNIV_CTL_VAS;
+ break;
+
+ default:
+ mask = (ismaster ? UNIV_MCTL_AM_MASK : UNIV_SCTL_AM_MASK);
+ break;
+ }
+
+ cntrl &= mask;
+ offst &= mask;
+
+ if ( cntrl != 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 */
+ if (l->reverse) {
+ /* reverse mapping, i.e. for master ports we map from
+ * VME to PCI, for slave ports we map from VME to PCI
+ */
+ if (l->address >= start && l->address < bound) {
+ l->address+=offst;
+ return 1 + port;
+ }
+ } else {
+ x = l->address - offst;
+
+ if (x >= start && x < bound) {
+ /* valid address found */
+ l->address = x;
+ return 1 + port;
+ }
+ }
+ return 0;
+}
+
+/* check if there is any active window with write posting enabled */
+static int
+hasPWENWindow(
+ int ismaster,
+ int portno,
+ volatile LERegister *preg,
+ void *parm)
+{
+unsigned long cntrl = READ_LE0(preg);
+unsigned long mask = ismaster ? (UNIV_MCTL_EN|UNIV_MCTL_PWEN) : (UNIV_SCTL_EN|UNIV_SCTL_PWEN);
+ return (cntrl & mask) == mask ? -1 : 0;
+}
+
+static int
+mapOverAll(volatile LERegister *base, int ismaster, int (*func)(int,int,volatile LERegister *,void*), void *arg)
+{
+volatile LERegister *rptr;
+unsigned long port;
+int rval;
+
+ CHECK_DFLT_BASE(base);
+
+ 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<UNIV_NUM_MPORTS; port++) {
+ if ((rval=func(ismaster,port,rptr,arg))) return rval;
+ rptr+=5; /* register block spacing */
+ }
+ return 0;
+}
+
+static void
+showUniversePorts(volatile LERegister *base, int ismaster, FILE *f)
+{
+ if (!f) f=stdout;
+ uprintf(f,"Universe %s Ports:\n",ismaster ? "Master" : "Slave");
+ uprintf(f,"Port VME-Addr Size PCI-Adrs Mode:\n");
+ mapOverAll(base,ismaster,showUniversePort,f);
+}
+
+static int
+xlateFindPort(
+ volatile LERegister *base, /* Universe base address */
+ int master, /* look in the master windows */
+ int reverse, /* reverse mapping; for masters: map local to VME */
+ unsigned long as, /* address space */
+ unsigned long aIn, /* address to look up */
+ unsigned long *paOut/* where to put result */
+ )
+{
+int rval;
+XlatRec l;
+ l.aspace = as;
+ l.address = aIn;
+ l.reverse = reverse;
+ /* map result -1/0/1 to -2/-1/0 with 0 on success */
+ rval = mapOverAll(base,master,xlatePort,(void*)&l) - 1;
+ *paOut = l.address;
+ return rval;
+}
+
+int
+vmeUniverseXlateAddrXX(
+ volatile LERegister *base, /* Universe base address */
+ int master, /* look in the master windows */
+ int reverse, /* reverse mapping; for masters: map local to VME */
+ unsigned long as, /* address space */
+ unsigned long aIn, /* address to look up */
+ unsigned long *paOut/* where to put result */
+ )
+{
+ return xlateFindPort(base, master, reverse, as, aIn, paOut) >= 0 ? 0 : -1;
+}
+
+int
+vmeUniverseXlateAddr(
+ int master, /* look in the master windows */
+ int reverse, /* reverse mapping; for masters: map local to VME */
+ unsigned long as, /* address space */
+ unsigned long aIn, /* address to look up */
+ unsigned long *paOut/* where to put result */
+ )
+{
+ DFLT_BASE;
+ return vmeUniverseXlateAddrXX(base, master, reverse, as, aIn, paOut);
+}
+
+
+void
+vmeUniverseReset(void)
+{
+ /* disable/reset special cycles (ADOH, RMW) */
+ vmeUniverseWriteReg(0, UNIV_REGOFF_SCYC_CTL);
+ vmeUniverseWriteReg(0, UNIV_REGOFF_SCYC_ADDR);
+ vmeUniverseWriteReg(0, UNIV_REGOFF_SCYC_EN);
+
+ /* set coupled window timeout to 0 (release VME after each transaction)
+ * CRT (coupled request timeout) is unused by Universe II
+ */
+ vmeUniverseWriteReg(UNIV_LMISC_CRT_128_US, UNIV_REGOFF_LMISC);
+
+ /* disable/reset DMA engine */
+ vmeUniverseWriteReg(0, UNIV_REGOFF_DCTL);
+ vmeUniverseWriteReg(0, UNIV_REGOFF_DTBC);
+ vmeUniverseWriteReg(0, UNIV_REGOFF_DLA);
+ vmeUniverseWriteReg(0, UNIV_REGOFF_DVA);
+ vmeUniverseWriteReg(0, UNIV_REGOFF_DCPP);
+
+ /* disable location monitor */
+ vmeUniverseWriteReg(0, UNIV_REGOFF_LM_CTL);
+
+ /* disable universe register access from VME bus */
+ vmeUniverseWriteReg(0, UNIV_REGOFF_VRAI_CTL);
+
+#if 0 /* leave CSR bus image alone; IRQ manager can use it */
+ /* disable VME bus image of VME CSR */
+ vmeUniverseWriteReg(0, UNIV_REGOFF_VCSR_CTL);
+#endif
+
+
+ /* I had problems with a Joerger vtr10012_8 card who would
+ * only be accessible after tweaking the U2SPEC register
+ * (the t27 parameter helped).
+ * I use the same settings here that are used by the
+ * Synergy VGM-powerpc BSP for vxWorks.
+ */
+ if (2==UNIV_REV(vmeUniverse0BaseAddr))
+ vmeUniverseWriteReg(UNIV_U2SPEC_DTKFLTR |
+ UNIV_U2SPEC_MASt11 |
+ UNIV_U2SPEC_READt27_NODELAY |
+ UNIV_U2SPEC_POSt28_FAST |
+ UNIV_U2SPEC_PREt28_FAST,
+ UNIV_REGOFF_U2SPEC);
+
+ /* disable interrupts, reset routing */
+ vmeUniverseWriteReg(0, UNIV_REGOFF_LINT_EN);
+ vmeUniverseWriteReg(0, UNIV_REGOFF_LINT_MAP0);
+ vmeUniverseWriteReg(0, UNIV_REGOFF_LINT_MAP1);
+
+ vmeUniverseWriteReg(0, UNIV_REGOFF_VINT_EN);
+ vmeUniverseWriteReg(0, UNIV_REGOFF_VINT_MAP0);
+ vmeUniverseWriteReg(0, UNIV_REGOFF_VINT_MAP1);
+
+ vmeUniverseDisableAllSlaves();
+
+ vmeUniverseDisableAllMasters();
+
+ vmeUniverseWriteReg(UNIV_VCSR_CLR_SYSFAIL, UNIV_REGOFF_VCSR_CLR);
+
+ /* clear interrupt status bits */
+ vmeUniverseWriteReg(UNIV_LINT_STAT_CLR, UNIV_REGOFF_LINT_STAT);
+ vmeUniverseWriteReg(UNIV_VINT_STAT_CLR, UNIV_REGOFF_VINT_STAT);
+
+ vmeUniverseWriteReg(UNIV_V_AMERR_V_STAT, UNIV_REGOFF_V_AMERR);
+
+ vmeUniverseWriteReg(
+ vmeUniverseReadReg(UNIV_REGOFF_PCI_CSR) |
+ UNIV_PCI_CSR_D_PE | UNIV_PCI_CSR_S_SERR | UNIV_PCI_CSR_R_MA |
+ UNIV_PCI_CSR_R_TA | UNIV_PCI_CSR_S_TA,
+ UNIV_REGOFF_PCI_CSR);
+
+ vmeUniverseWriteReg(UNIV_L_CMDERR_L_STAT, UNIV_REGOFF_L_CMDERR);
+
+ vmeUniverseWriteReg(
+ UNIV_DGCS_STOP | UNIV_DGCS_HALT | UNIV_DGCS_DONE |
+ UNIV_DGCS_LERR | UNIV_DGCS_VERR | UNIV_DGCS_P_ERR,
+ UNIV_REGOFF_DGCS);
+}
+
+int
+vmeUniverseInit(void)
+{
+int rval;
+ if ( (rval=vmeUniverseFindPciBase(0,&vmeUniverse0BaseAddr)) < 0 ) {
+ uprintf(stderr,"unable to find the universe in pci config space\n");
+ } else {
+ vmeUniverse0PciIrqLine = rval;
+ rval = 0;
+ uprintf(stderr,"Universe II PCI-VME bridge detected at 0x%08x, IRQ %d\n",
+ (unsigned int)vmeUniverse0BaseAddr, vmeUniverse0PciIrqLine);
+ }
+ return rval;
+}
+
+void
+vmeUniverseMasterPortsShowXX(volatile LERegister *base, FILE *f)
+{
+ showUniversePorts(base,1,f);
+}
+
+void
+vmeUniverseMasterPortsShow(FILE *f)
+{
+ DFLT_BASE;
+ showUniversePorts(base,1,f);
+}
+
+void
+vmeUniverseSlavePortsShowXX(volatile LERegister *base, FILE *f)
+{
+ showUniversePorts(base,0,f);
+}
+
+void
+vmeUniverseSlavePortsShow(FILE *f)
+{
+ DFLT_BASE;
+ showUniversePorts(base,0,f);
+}
+
+int
+vmeUniverseMasterPortCfgXX(
+ volatile LERegister *base,
+ unsigned long port,
+ unsigned long address_space,
+ unsigned long vme_address,
+ unsigned long local_address,
+ unsigned long length)
+{
+ return cfgUniversePort(base,1,port,address_space,vme_address,local_address,length);
+}
+
+int
+vmeUniverseMasterPortCfg(
+ unsigned long port,
+ unsigned long address_space,
+ unsigned long vme_address,
+ unsigned long local_address,
+ unsigned long length)
+{
+ DFLT_BASE;
+ return cfgUniversePort(base,1,port,address_space,vme_address,local_address,length);
+}
+
+int
+vmeUniverseSlavePortCfgXX(
+ volatile LERegister *base,
+ unsigned long port,
+ unsigned long address_space,
+ unsigned long vme_address,
+ unsigned long local_address,
+ unsigned long length)
+{
+ return cfgUniversePort(base,0,port,address_space,vme_address,local_address,length);
+}
+
+int
+vmeUniverseSlavePortCfg(
+ unsigned long port,
+ unsigned long address_space,
+ unsigned long vme_address,
+ unsigned long local_address,
+ unsigned long length)
+{
+ DFLT_BASE;
+ return cfgUniversePort(base,0,port,address_space,vme_address,local_address,length);
+}
+
+
+void
+vmeUniverseDisableAllSlavesXX(volatile LERegister *base)
+{
+ mapOverAll(base,0,disableUniversePort,0);
+}
+
+void
+vmeUniverseDisableAllSlaves(void)
+{
+ DFLT_BASE;
+ mapOverAll(base,0,disableUniversePort,0);
+}
+
+void
+vmeUniverseDisableAllMastersXX(volatile LERegister *base)
+{
+ mapOverAll(base,1,disableUniversePort,0);
+}
+
+void
+vmeUniverseDisableAllMasters(void)
+{
+ DFLT_BASE;
+ mapOverAll(base,1,disableUniversePort,0);
+}
+
+unsigned long
+vmeUniverseReadRegXX(volatile LERegister *base, unsigned long offset)
+{
+unsigned long rval;
+ rval = READ_LE(base,offset);
+ return rval;
+}
+
+
+unsigned long
+vmeUniverseReadReg(unsigned long offset)
+{
+unsigned long rval;
+ rval = READ_LE(vmeUniverse0BaseAddr,offset);
+ return rval;
+}
+
+void
+vmeUniverseWriteRegXX(volatile LERegister *base, unsigned long value, unsigned long offset)
+{
+ WRITE_LE(value, base, offset);
+}
+
+void
+vmeUniverseWriteReg(unsigned long value, unsigned long offset)
+{
+ WRITE_LE(value, vmeUniverse0BaseAddr, offset);
+}
+
+void
+vmeUniverseResetBus(void)
+{
+ vmeUniverseWriteReg(
+ vmeUniverseReadReg(UNIV_REGOFF_MISC_CTL) | UNIV_MISC_CTL_SW_SYSRST,
+ UNIV_REGOFF_MISC_CTL);
+}
+
+void
+vmeUniverseCvtToLE(unsigned long *ptr, unsigned long num)
+{
+#if !defined(__LITTLE_ENDIAN__) || (__LITTLE_ENDIAN__ != 1)
+register unsigned long *p=ptr+num;
+ while (p > 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) : "0"(p) : "r0"
+ );
+#elif defined(__rtems__)
+ p--; st_le32(p, *p);
+#else
+#error "vmeUniverse: endian conversion not implemented for this architecture"
+#endif
+ }
+#endif
+}
+
+int
+vmeUniverseIntRaiseXX(volatile LERegister *base, int level, unsigned vector)
+{
+unsigned long v;
+unsigned long b;
+
+ CHECK_DFLT_BASE(base);
+
+ if ( level < 1 || level > 7 || vector > 255 )
+ return -1; /* invalid argument */
+
+ if ( vector & 1 ) /* SW interrupts always ACK an even vector (pp 2-67) */
+ return -1;
+
+
+ /* Check if already asserted */
+ if ( vmeUniverseReadRegXX(base, UNIV_REGOFF_VINT_STAT ) & UNIV_VINT_STAT_SWINT(level) ) {
+ return -2; /* already asserted */
+ }
+
+ /* Write Vector */
+ vmeUniverseWriteRegXX(base, UNIV_VINT_STATID(vector), UNIV_REGOFF_VINT_STATID );
+
+ if ( UNIV_REV(base) >= 2 ) {
+ /* universe II has individual bits for individual levels */
+ b = UNIV_VINT_STAT_SWINT(level);
+ } else {
+ /* version that is compatible with universe I */
+ v = vmeUniverseReadRegXX(base, UNIV_REGOFF_VINT_MAP1);
+ v &= ~UNIV_VINT_MAP1_SWINT(0x7);
+ v |= UNIV_VINT_MAP1_SWINT(level);
+ vmeUniverseWriteRegXX(base, v, UNIV_REGOFF_VINT_MAP1);
+ b = UNIV_VINT_EN_SWINT;
+ }
+ v = vmeUniverseReadRegXX(base, UNIV_REGOFF_VINT_EN);
+ /* make sure it is clear, then assert */
+ vmeUniverseWriteRegXX(base, v & ~b, UNIV_REGOFF_VINT_EN );
+ vmeUniverseWriteRegXX(base, v | b, UNIV_REGOFF_VINT_EN );
+
+ return 0;
+
+}
+
+int
+vmeUniverseIntRaise(int level, unsigned vector)
+{
+ return vmeUniverseIntRaiseXX(vmeUniverse0BaseAddr, level, vector);
+}
+
+
+/* Map internal register block to VME */
+#define UNIV_CRG_SIZE (1<<12)
+
+int
+vmeUniverseMapCRGXX(volatile LERegister *base, unsigned long vme_base, unsigned long as )
+{
+uint32_t mode;
+
+ CHECK_DFLT_BASE(base);
+
+#ifdef __rtems__
+ if ( vmeUniverseRegPort > -1 && ! vmeUniverseRegCSR ) {
+ uprintf(stderr,"vmeUniverse: CRG already mapped and in use by interrupt manager\n");
+ return -1;
+ }
+#endif
+
+ /* enable all, SUP/USR/PGM/DATA accesses */
+ mode = UNIV_VRAI_CTL_EN | UNIV_VRAI_CTL_PGM | UNIV_VRAI_CTL_DATA | UNIV_VRAI_CTL_SUPER | UNIV_VRAI_CTL_USER;
+
+ if ( VME_AM_IS_SHORT(as) ) {
+ mode |= UNIV_VRAI_CTL_VAS_A16;
+ } else
+ if ( VME_AM_IS_STD(as) ) {
+ mode |= UNIV_VRAI_CTL_VAS_A24;
+ } else
+ if ( VME_AM_IS_EXT(as) ) {
+ mode |= UNIV_VRAI_CTL_VAS_A32;
+ } else {
+ return -2;
+ }
+
+ /* map CRG to VME bus */
+ WRITE_LE( (vme_base & ~(UNIV_CRG_SIZE-1)), base, UNIV_REGOFF_VRAI_BS );
+ WRITE_LE( mode, base, UNIV_REGOFF_VRAI_CTL );
+
+ return 0;
+}
+
+int
+vmeUniverseMapCRG(unsigned long vme_base, unsigned long as )
+{
+ return vmeUniverseMapCRGXX( vmeUniverse0BaseAddr, vme_base, as );
+}
+
+#ifdef __rtems__
+/* DMA Support -- including linked-list implementation */
+#include "bspVmeDmaListP.h"
+#include <bsp/vmeUniverseDMA.h>
+
+/* Filter valid bits of DCTL */
+#define DCTL_MODE_MASK \
+ ( UNIV_DCTL_VDW_MSK | UNIV_DCTL_VAS_MSK | UNIV_DCTL_PGM | UNIV_DCTL_SUPER | UNIV_DCTL_VCT )
+
+static uint32_t
+xfer_mode2dctl(uint32_t xfer_mode)
+{
+uint32_t dctl;
+
+ /* Check requested bus mode */
+
+ /* Universe does not support 'non-incrementing' DMA */
+
+ /* NOTE: Universe IIb/d *does* support NOINC_VME but states
+ * that the VME address needs to be reprogrammed
+ * when re-issuing a transfer
+ */
+ if ( xfer_mode & BSP_VMEDMA_MODE_NOINC_PCI )
+ return BSP_VMEDMA_STATUS_UNSUP;
+
+ /* ignore memory hint */
+ xfer_mode &= ~VME_AM_IS_MEMORY;
+
+ if ( VME_AM_IS_2eSST(xfer_mode) )
+ return BSP_VMEDMA_STATUS_UNSUP;
+
+ if ( ! VME_AM_IS_SHORT(xfer_mode) && ! VME_AM_IS_STD(xfer_mode) && ! VME_AM_IS_EXT(xfer_mode) )
+ return BSP_VMEDMA_STATUS_UNSUP;
+
+ /* Luckily DCTL bits match MCTL bits so we can use am2mode */
+ if ( am2mode( 1, xfer_mode, &dctl ) )
+ return BSP_VMEDMA_STATUS_UNSUP;
+
+ /* However, the book says that for DMA VAS==5 [which would
+ * be a CSR access] is reserved. Tests indicate that
+ * CSR access works on the IIb/d but not really (odd 32-bit
+ * addresses read 0) on the II.
+ * Nevertheless, we disallow DMA CSR access at this point
+ * in order to play it safe...
+ */
+ switch ( UNIV_DCTL_VAS_MSK & dctl ) {
+ case UNIV_DCTL_VAS_A24:
+ case UNIV_DCTL_VAS_A32:
+ /* fixup the data width; universe may always use MBLT
+ * if data width is 64-bit so we go back to 32-bit
+ * if they didn't explicitely ask for MBLT cycles
+ */
+ if ( (xfer_mode & 0xb) != 8 /* MBLT */
+ && ( UNIV_DCTL_VDW_64 == (dctl & UNIV_DCTL_VDW_MSK) ) ) {
+ dctl &= ~UNIV_DCTL_VDW_MSK;
+ dctl |= UNIV_DCTL_VDW_32;
+ }
+ break;
+
+ case UNIV_DCTL_VAS_A16:
+ break;
+
+ default:
+ return BSP_VMEDMA_STATUS_UNSUP;
+ }
+
+ /* Make sure other MCTL bits are masked */
+ dctl &= DCTL_MODE_MASK;
+
+ if ( xfer_mode & BSP_VMEDMA_MODE_NOINC_VME ) {
+ /* If they want NOINC_VME then we have to do some
+ * fixup :-( ('errata' [in this case: feature addition] doc. pp. 11+)
+ */
+ dctl &= ~UNIV_DCTL_VCT; /* clear block xfer flag */
+ dctl |= UNIV_DCTL_NO_VINC;
+ /* cannot do 64 bit transfers; go back to 32 */
+ if ( UNIV_DCTL_VDW_64 == (dctl & UNIV_DCTL_VDW_MSK) ) {
+ dctl &= ~UNIV_DCTL_VDW_MSK;
+ dctl |= UNIV_DCTL_VDW_32;
+ }
+ }
+
+ /* Set direction flag */
+
+ if ( BSP_VMEDMA_MODE_PCI2VME & xfer_mode )
+ dctl |= UNIV_DCTL_L2V;
+
+ return dctl;
+}
+
+/* Convert canonical xfer_mode into Universe setup bits; return -1 if request
+ * cannot be satisfied (unsupported features)
+ */
+int
+vmeUniverseDmaSetupXX(volatile LERegister *base, int channel, uint32_t mode, uint32_t xfer_mode, void *custom)
+{
+uint32_t dctl, dgcs;
+
+ if ( channel != 0 )
+ return BSP_VMEDMA_STATUS_UNSUP;
+
+ dctl = xfer_mode2dctl(xfer_mode);
+
+ if ( (uint32_t)BSP_VMEDMA_STATUS_UNSUP == dctl )
+ return BSP_VMEDMA_STATUS_UNSUP;
+
+ /* Enable all interrupts at the controller */
+ dgcs = UNIV_DGCS_INT_MSK;
+
+ switch ( mode ) {
+ case BSP_VMEDMA_OPT_THROUGHPUT:
+ dgcs |= UNIV_DGCS_VON_1024 | UNIV_DGCS_VOFF_0_US;
+ /* VON counts are different in NO_VINC mode :-( */
+ dgcs |= ( xfer_mode & BSP_VMEDMA_MODE_NOINC_VME ) ?
+ UNIV_DGCS_VON_2048 : UNIV_DGCS_VON_1024;
+ break;
+
+ case BSP_VMEDMA_OPT_LOWLATENCY:
+ dgcs |= UNIV_DGCS_VOFF_0_US;
+ /* VON counts are different in NO_VINC mode :-( */
+ dgcs |= ( xfer_mode & BSP_VMEDMA_MODE_NOINC_VME ) ?
+ UNIV_DGCS_VON_512 : UNIV_DGCS_VON_256;
+ break;
+
+ case BSP_VMEDMA_OPT_SHAREDBUS:
+ dgcs |= UNIV_DGCS_VOFF_512_US;
+ /* VON counts are different in NO_VINC mode :-( */
+ dgcs |= ( xfer_mode & BSP_VMEDMA_MODE_NOINC_VME ) ?
+ UNIV_DGCS_VON_512 : UNIV_DGCS_VON_256;
+ break;
+
+ case BSP_VMEDMA_OPT_CUSTOM:
+ dctl = ((uint32_t*)custom)[0];
+ dgcs = ((uint32_t*)custom)[1];
+ break;
+
+ default:
+ case BSP_VMEDMA_OPT_DEFAULT:
+ break;
+ }
+
+ /* clear status bits */
+ dgcs |= UNIV_DGCS_STATUS_CLEAR;
+
+ vmeUniverseWriteRegXX(base, dctl, UNIV_REGOFF_DCTL);
+ vmeUniverseWriteRegXX(base, dgcs, UNIV_REGOFF_DGCS);
+
+ return BSP_VMEDMA_STATUS_OK;
+}
+
+int
+vmeUniverseDmaSetup(int channel, uint32_t mode, uint32_t xfer_mode, void *custom)
+{
+DFLT_BASE;
+ return vmeUniverseDmaSetupXX(base, channel, mode, xfer_mode, custom);
+}
+
+int
+vmeUniverseDmaStartXX(volatile LERegister *base, int channel, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes)
+{
+ if ( channel != 0 )
+ return BSP_VMEDMA_STATUS_UNSUP;
+
+ if ((pci_addr & 7) != (vme_addr & 7)) {
+ uprintf(stderr,"vmeUniverseDmaStartXX: misaligned addresses\n");
+ return -1;
+ }
+
+ {
+ /* help the compiler allocate registers */
+ register volatile LERegister *b=base;
+ register unsigned long dgcsoff=UNIV_REGOFF_DGCS,dgcs;
+
+ dgcs=READ_LE(b, dgcsoff);
+
+ /* clear status and make sure CHAIN is clear */
+ dgcs &= ~UNIV_DGCS_CHAIN;
+ WRITE_LE(dgcs,
+ b, dgcsoff);
+ WRITE_LE(pci_addr,
+ b, UNIV_REGOFF_DLA);
+ WRITE_LE(vme_addr,
+ b, UNIV_REGOFF_DVA);
+ WRITE_LE(n_bytes,
+ b, UNIV_REGOFF_DTBC);
+ dgcs |= UNIV_DGCS_GO;
+ EIEIO_REG; /* make sure GO is written after everything else */
+ WRITE_LE(dgcs,
+ b, dgcsoff);
+ }
+ SYNC; /* enforce command completion */
+ return 0;
+}
+
+/* This entry point is deprecated */
+int
+vmeUniverseStartDMAXX(
+ volatile LERegister *base,
+ unsigned long local_addr,
+ unsigned long vme_addr,
+ unsigned long count)
+{
+ return vmeUniverseDmaStartXX(base, 0, local_addr, vme_addr, count);
+}
+
+int
+vmeUniverseDmaStart(int channel, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes)
+{
+ DFLT_BASE; /* vmeUniverseDmaStartXX doesn't check for a valid base address for efficiency reasons */
+ return vmeUniverseDmaStartXX(base, channel, pci_addr, vme_addr, n_bytes);
+}
+
+/* This entry point is deprecated */
+int
+vmeUniverseStartDMA(
+ unsigned long local_addr,
+ unsigned long vme_addr,
+ unsigned long count)
+{
+ DFLT_BASE; /* vmeUniverseStartDMAXX doesn't check for a valid base address for efficiency reasons */
+ return vmeUniverseDmaStartXX(base, 0, local_addr, vme_addr, count);
+}
+
+uint32_t
+vmeUniverseDmaStatusXX(volatile LERegister *base, int channel)
+{
+uint32_t dgcs;
+ if ( channel != 0 )
+ return BSP_VMEDMA_STATUS_UNSUP;
+
+ dgcs = vmeUniverseReadRegXX(base, UNIV_REGOFF_DGCS);
+
+ dgcs &= UNIV_DGCS_STATUS_CLEAR;
+
+ if ( 0 == dgcs || UNIV_DGCS_DONE == dgcs )
+ return BSP_VMEDMA_STATUS_OK;
+
+ if ( UNIV_DGCS_ACT & dgcs )
+ return BSP_VMEDMA_STATUS_BUSY;
+
+ if ( UNIV_DGCS_LERR & dgcs )
+ return BSP_VMEDMA_STATUS_BERR_PCI;
+
+ if ( UNIV_DGCS_VERR & dgcs )
+ return BSP_VMEDMA_STATUS_BERR_VME;
+
+ return BSP_VMEDMA_STATUS_OERR;
+}
+
+uint32_t
+vmeUniverseDmaStatus(int channel)
+{
+DFLT_BASE;
+ return vmeUniverseDmaStatusXX(base, channel);
+}
+
+/* bspVmeDmaList driver interface implementation */
+
+/* Cannot use VmeUniverseDMAPacketRec because st_le32 expects unsigned *
+ * and we get 'alias' warnings when we submit uint32_t *
+ */
+
+typedef volatile uint32_t LERegister1;
+
+typedef struct VmeUniverseDmaListDescRec_ {
+ LERegister1 dctl;
+ LERegister1 dtbc;
+ LERegister1 dla;
+ LERegister1 dummy1;
+ LERegister1 dva;
+ LERegister1 dummy2;
+ LERegister1 dcpp;
+ LERegister1 dummy3;
+} __attribute__((aligned(32), __may_alias__))
+VmeUniverseDmaListDescRec;
+
+typedef VmeUniverseDmaListDescRec *VmeUniverseDmaListDesc;
+
+static void uni_desc_init (DmaDescriptor);
+static int uni_desc_setup (DmaDescriptor, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
+static void uni_desc_setnxt(DmaDescriptor, DmaDescriptor);
+static void uni_desc_dump (DmaDescriptor);
+static int uni_desc_start (volatile void *controller_addr, int channel, DmaDescriptor p);
+
+VMEDmaListClassRec vmeUniverseDmaListClass = {
+ desc_size: sizeof(VmeUniverseDMAPacketRec),
+ desc_align: 32,
+ freeList: 0,
+ desc_alloc: 0,
+ desc_free: 0,
+ desc_init: uni_desc_init,
+ desc_setnxt:uni_desc_setnxt,
+ desc_setup: uni_desc_setup,
+ desc_start: uni_desc_start,
+ desc_refr: 0,
+ desc_dump: uni_desc_dump,
+};
+
+static void uni_desc_init (DmaDescriptor p)
+{
+VmeUniverseDmaListDesc d = p;
+ st_le32( &d->dcpp, UNIV_DCPP_IMG_NULL );
+}
+
+static void uni_desc_setnxt(DmaDescriptor p, DmaDescriptor n)
+{
+VmeUniverseDmaListDesc d = p;
+ if ( 0 == n ) {
+ st_le32( &d->dcpp, UNIV_DCPP_IMG_NULL );
+ } else {
+ st_le32( &d->dcpp, BSP_LOCAL2PCI_ADDR( (uint32_t)n));
+ }
+}
+
+static int
+uni_desc_setup (
+ DmaDescriptor p,
+ uint32_t attr_mask,
+ uint32_t xfer_mode,
+ uint32_t pci_addr,
+ uint32_t vme_addr,
+ uint32_t n_bytes)
+{
+VmeUniverseDmaListDesc d = p;
+LERegister1 dctl;
+
+ if ( BSP_VMEDMA_MSK_ATTR & attr_mask ) {
+ dctl = xfer_mode2dctl(xfer_mode);
+
+ if ( (uint32_t)BSP_VMEDMA_STATUS_UNSUP == dctl )
+ return -1;
+
+ st_le32( &d->dctl, dctl );
+ }
+
+ /* Last 3 bits of src & destination addresses must be the same.
+ * For sake of simplicity we enforce (stricter) 8-byte alignment
+ */
+
+ if ( BSP_VMEDMA_MSK_PCIA & attr_mask ) {
+ if ( pci_addr & 0x7 )
+ return -1;
+
+ st_le32( &d->dla, pci_addr );
+ }
+
+ if ( BSP_VMEDMA_MSK_VMEA & attr_mask ) {
+ if ( vme_addr & 0x7 )
+ return -1;
+
+ st_le32( &d->dva, vme_addr );
+ }
+
+ if ( BSP_VMEDMA_MSK_BCNT & attr_mask ) {
+ st_le32( &d->dtbc, n_bytes );
+ }
+
+ return 0;
+}
+
+static int uni_desc_start
+(volatile void *controller_addr, int channel, DmaDescriptor p)
+{
+volatile LERegister *base = controller_addr;
+uint32_t dgcs;
+
+ if ( !base )
+ base = vmeUniverse0BaseAddr;
+
+ dgcs = vmeUniverseReadRegXX( base, UNIV_REGOFF_DGCS );
+
+ if ( UNIV_DGCS_ACT & dgcs )
+ return BSP_VMEDMA_STATUS_BUSY;
+
+ if ( !p ) {
+ /* Chain bit is cleared by non-linked-list start command
+ * but do this anyways...
+ */
+ dgcs &= ~UNIV_DGCS_CHAIN;
+ vmeUniverseWriteRegXX( base, UNIV_REGOFF_DGCS, dgcs);
+ return 0;
+ }
+
+ /* clear status and set CHAIN bit */
+ dgcs |= UNIV_DGCS_CHAIN;
+
+ vmeUniverseWriteRegXX( base, UNIV_REGOFF_DGCS, dgcs);
+
+ /* make sure count is 0 for linked list DMA */
+ vmeUniverseWriteRegXX( base, 0x0, UNIV_REGOFF_DTBC);
+
+ /* set the address of the descriptor chain */
+ vmeUniverseWriteRegXX( base, BSP_LOCAL2PCI_ADDR((uint32_t)p), UNIV_REGOFF_DCPP);
+
+ /* and GO */
+ dgcs |= UNIV_DGCS_GO;
+ vmeUniverseWriteReg(dgcs, UNIV_REGOFF_DGCS);
+
+ return 0;
+}
+
+static void
+uni_desc_dump(DmaDescriptor p)
+{
+VmeUniverseDmaListDesc d = p;
+LERegister1 dcpp = ld_le32(&d->dcpp);
+
+ printf(" DLA: 0x%08x\n", ld_le32(&d->dla));
+ printf(" DVA: 0x%08x\n", ld_le32(&d->dva));
+ printf(" DCPP: 0x%08"PRIx32"%s\n", dcpp, (dcpp & UNIV_DCPP_IMG_NULL) ? " (LAST)" : "");
+ printf(" CTL: 0x%08x\n", ld_le32(&d->dctl));
+ printf(" TBC: 0x%08x\n", ld_le32(&d->dtbc));
+}
+
+/* RTEMS interrupt subsystem */
+
+#include <bsp/irq.h>
+
+typedef struct
+UniverseIRQEntryRec_ {
+ VmeUniverseISR isr;
+ void *usrData;
+} UniverseIRQEntryRec, *UniverseIRQEntry;
+
+static UniverseIRQEntry universeHdlTbl[UNIV_NUM_INT_VECS]={0};
+
+int vmeUniverseIrqMgrInstalled = 0;
+
+volatile LERegister *vmeUniverseRegBase = 0;
+
+/* We support 4 wires between universe + PIC */
+
+#define UNIV_NUM_WIRES 4
+
+static volatile unsigned long wire_mask[UNIV_NUM_WIRES] = {0};
+/* wires are offset by 1 so we can initialize the wire table to all zeros */
+static int universe_wire[UNIV_NUM_WIRES] = {0};
+
+static int
+lvl2bit(unsigned int level)
+{
+int shift = -1;
+ if ( level >= UNIV_DMA_INT_VEC && level <= UNIV_LM3_INT_VEC ) {
+ shift = 8 + (level-UNIV_DMA_INT_VEC);
+ } else if ( UNIV_VOWN_INT_VEC == level ) {
+ shift = 0;
+ } else if ( 1 <= level && level <=7 ) {
+ shift = level;
+ } else {
+ /* invalid level */
+ }
+ return shift;
+}
+
+int
+vmeUniverseIntRoute(unsigned int level, unsigned int pin)
+{
+int i, shift;
+unsigned long mask, mapreg, flags, wire;
+
+ if ( pin >= UNIV_NUM_WIRES || ! universe_wire[pin] || !vmeUniverseIrqMgrInstalled )
+ return -1;
+
+ if ( (shift = lvl2bit(level)) < 0 ) {
+ return -1; /* invalid level */
+ }
+
+ mask = 1<<shift;
+
+ /* calculate the mapping register and contents */
+ if ( shift < 8 ) {
+ mapreg = UNIV_REGOFF_LINT_MAP0;
+ } else if ( shift < 16 ) {
+ shift -= 8;
+ mapreg = UNIV_REGOFF_LINT_MAP1;
+ } else if ( shift < 24 ) {
+ shift -= 16;
+ mapreg = UNIV_REGOFF_LINT_MAP2;
+ } else {
+ return -1;
+ }
+
+ shift <<=2;
+
+ /* wires are offset by 1 so we can initialize the wire table to all zeros */
+ wire = (universe_wire[pin]-1) << shift;
+
+rtems_interrupt_disable(flags);
+
+ for ( i = 0; i<UNIV_NUM_WIRES; i++ ) {
+ wire_mask[i] &= ~mask;
+ }
+ wire_mask[pin] |= mask;
+
+ mask = vmeUniverseReadReg(mapreg) & ~ (0xf<<shift);
+ mask |= wire;
+ vmeUniverseWriteReg( mask, mapreg );
+
+rtems_interrupt_enable(flags);
+ return 0;
+}
+
+VmeUniverseISR
+vmeUniverseISRGet(unsigned long vector, void **parg)
+{
+unsigned long flags;
+VmeUniverseISR rval = 0;
+volatile UniverseIRQEntry *pe = universeHdlTbl + vector;
+
+ if ( vector>=UNIV_NUM_INT_VECS || ! *pe )
+ return 0;
+
+ rtems_interrupt_disable(flags);
+ if ( *pe ) {
+ if (parg)
+ *parg=(*pe)->usrData;
+ rval = (*pe)->isr;
+ }
+ rtems_interrupt_enable(flags);
+ return rval;
+}
+
+#define SPECIAL_IRQ_MSK ( ~((UNIV_LINT_STAT_VIRQ7<<1)-UNIV_LINT_STAT_VIRQ1) )
+
+static void
+universeSpecialISR(unsigned long status)
+{
+register UniverseIRQEntry ip;
+register unsigned vec;
+register unsigned long s;
+
+ /* handle all LINT bits except for the 'normal' VME interrupts */
+
+ /* clear all detected special interrupts */
+ vmeUniverseWriteReg( (status & SPECIAL_IRQ_MSK), UNIV_REGOFF_LINT_STAT );
+
+ /* do VOWN first */
+ vec=UNIV_VOWN_INT_VEC;
+ if ( (status & UNIV_LINT_STAT_VOWN) && (ip=universeHdlTbl[vec]))
+ ip->isr(ip->usrData,vec);
+
+ /* now continue with DMA and scan through all bits;
+ * we assume the vectors are in the right order!
+ *
+ * The initial right shift brings the DMA bit into position 0;
+ * the loop is left early if there are no more bits set.
+ */
+ for ( s = status>>8; s; s >>= 1) {
+ vec++;
+ if ( (s&1) && (ip=universeHdlTbl[vec]) )
+ ip->isr(ip->usrData,vec);
+ }
+
+/*
+ * 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(rtems_irq_hdl_param arg)
+{
+int pin = (int)arg;
+UniverseIRQEntry ip;
+unsigned long msk,lintstat,status;
+int lvl;
+#if defined(BSP_PIC_DO_EOI)
+unsigned long linten;
+#endif
+
+ /* determine the highest priority IRQ source */
+ lintstat = vmeUniverseReadReg(UNIV_REGOFF_LINT_STAT);
+
+ /* only handle interrupts routed to this pin */
+ lintstat &= wire_mask[pin];
+
+#ifdef __PPC__
+ asm volatile("cntlzw %0, %1":"=r"(lvl):"r"(lintstat & ~SPECIAL_IRQ_MSK));
+ lvl = 31-lvl;
+ msk = 1<<lvl;
+#else
+ for (msk=UNIV_LINT_STAT_VIRQ7, lvl=7;
+ lvl>0;
+ lvl--, msk>>=1) {
+ if (lintstat & msk) break;
+ }
+#endif
+
+#ifndef BSP_PIC_DO_EOI /* Software priorities not supported */
+
+ if ( (status = (lintstat & SPECIAL_IRQ_MSK)) )
+ universeSpecialISR( status );
+
+ if ( lvl <= 0)
+ return;
+
+#else
+ if ( lvl <= 0 ) {
+ /* try the special handler */
+ universeSpecialISR( lintstat & SPECIAL_IRQ_MSK );
+
+ /*
+ * let the pic end this cycle
+ */
+ if ( 0 == pin )
+ BSP_PIC_DO_EOI;
+
+ return;
+ }
+ linten = vmeUniverseReadReg(UNIV_REGOFF_LINT_EN);
+
+ /* mask this and all lower levels that are routed to the same pin */
+ vmeUniverseWriteReg(
+ linten & ~( ((msk<<1)-UNIV_LINT_STAT_VIRQ1) & wire_mask[pin]),
+ UNIV_REGOFF_LINT_EN
+ );
+
+ /* end this interrupt
+ * cycle on the PCI bus, so higher level interrupts can be
+ * caught from now on...
+ */
+ if ( 0 == pin )
+ BSP_PIC_DO_EOI;
+#endif
+
+ /* 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 :-( */
+#ifdef BSP_PIC_DO_EOI
+ linten &= ~msk;
+#else
+ vmeUniverseIntDisable(lvl);
+#endif
+ printk("vmeUniverse ISR: error read from STATID register; (level: %i) STATID: 0x%08" PRIx32 " -- DISABLING\n", lvl, status);
+ } else if (!(ip=universeHdlTbl[status & UNIV_VIRQ_STATID_MASK])) {
+#ifdef BSP_PIC_DO_EOI
+ linten &= ~msk;
+#else
+ vmeUniverseIntDisable(lvl);
+#endif
+ /* TODO: log error message - RTEMS has no logger :-( */
+ printk("vmeUniverse ISR: no handler installed for this vector; (level: %i) STATID: 0x%08" PRIx32 " -- DISABLING\n", lvl, status);
+ } else {
+ /* dispatch handler, it must clear the IRQ at the device */
+ ip->isr(ip->usrData, status&UNIV_VIRQ_STATID_MASK);
+
+ /* insert a VME read operation to flush fifo, making sure all user write-ops complete */
+#ifdef __PPC__
+ /* courtesy to disobedient users who don't use I/O ops */
+ asm volatile("eieio");
+#endif
+ READ_LE0(vmeUniverseRegBase);
+#ifdef __PPC__
+ /* make sure this is ordered before re-enabling */
+ asm volatile("eieio");
+#endif
+ }
+
+ /* clear this interrupt level; allow the universe to handler further interrupts */
+ 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);
+*/
+
+#ifdef BSP_PIC_DO_EOI
+
+ /* re-enable the previous level */
+ vmeUniverseWriteReg(linten, UNIV_REGOFF_LINT_EN);
+#endif
+}
+
+
+/* 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);
+}
+
+typedef struct {
+ int uni_pin, pic_pin;
+} IntRoute;
+
+static void
+connectIsr(int shared, rtems_irq_hdl isr, int pic_line, int pic_pin)
+{
+rtems_irq_connect_data aarrggh;
+ 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 = isr;
+ aarrggh.handle = (rtems_irq_hdl_param)pic_pin;
+ aarrggh.name = pic_line;
+
+ if ( shared ) {
+#if BSP_SHARED_HANDLER_SUPPORT > 0
+ if (!BSP_install_rtems_shared_irq_handler(&aarrggh))
+ rtems_panic("unable to install vmeUniverse shared irq handler");
+#else
+ uprintf(stderr,"vmeUniverse: WARNING: your BSP doesn't support sharing interrupts\n");
+ if (!BSP_install_rtems_irq_handler(&aarrggh))
+ rtems_panic("unable to install vmeUniverse irq handler");
+#endif
+ } else {
+ if (!BSP_install_rtems_irq_handler(&aarrggh))
+ rtems_panic("unable to install vmeUniverse irq handler");
+ }
+}
+
+#ifndef BSP_EARLY_PROBE_VME
+#define BSP_EARLY_PROBE_VME(addr) \
+ ( \
+ ((PCI_DEVICE_UNIVERSEII << 16) | PCI_VENDOR_TUNDRA ) == READ_LE( ((volatile LERegister*)(addr)), 0 ) \
+ )
+#endif
+
+/* Check if there is a vme address/as is mapped in any of the outbound windows
+ * and look for the PCI vendordevice ID there.
+ * RETURNS: -1 on error (no mapping or probe failure), outbound window # (0..7)
+ * on success. Address translated into CPU address is returned in *pcpu_addr.
+ */
+static int
+mappedAndProbed(unsigned long vme_addr, unsigned as, unsigned long *pcpu_addr)
+{
+int j;
+char *regtype = (as & VME_AM_MASK) == VME_AM_CSR ? "CSR" : "CRG";
+
+ /* try to find mapping */
+ if ( 0 > (j = xlateFindPort(
+ vmeUniverse0BaseAddr,
+ 1, 0,
+ as | VME_MODE_AS_MATCH,
+ vme_addr,
+ pcpu_addr ) ) ) {
+ uprintf(stderr,"vmeUniverse - Unable to find mapping for %s VME base (0x%08x)\n", regtype, vme_addr);
+ uprintf(stderr," in outbound windows.\n");
+ } else {
+ /* found a slot number; probe it */
+ *pcpu_addr = BSP_PCI2LOCAL_ADDR( *pcpu_addr );
+ if ( BSP_EARLY_PROBE_VME(*pcpu_addr) ) {
+ uprintf(stderr,"vmeUniverse - IRQ manager using VME %s to flush FIFO\n", regtype);
+ return j;
+ } else {
+ uprintf(stderr,"vmeUniverse - Found slot info but detection of universe in VME %s space failed\n", regtype);
+ }
+ }
+ return -1;
+}
+
+
+int
+vmeUniverseInstallIrqMgrAlt(int flags, int uni_pin0, int pic_pin0, ...)
+{
+int rval;
+va_list ap;
+ va_start(ap, pic_pin0);
+ rval = vmeUniverseInstallIrqMgrVa(flags, uni_pin0, pic_pin0, ap);
+ va_end(ap);
+ return rval;
+}
+
+int
+vmeUniverseInstallIrqMgrVa(int flags, int uni_pin0, int pic_pin0, va_list ap)
+{
+int i,j, specialPin, uni_pin[UNIV_NUM_WIRES+1], pic_pin[UNIV_NUM_WIRES];
+unsigned long cpu_base, vme_reg_base;
+
+ if (vmeUniverseIrqMgrInstalled) return -4;
+
+ /* check parameters */
+
+ if ( uni_pin0 < 0 || uni_pin0 > 7 ) return -1;
+
+ uni_pin[0] = uni_pin0;
+ pic_pin[0] = pic_pin0 < 0 ? vmeUniverse0PciIrqLine : pic_pin0;
+ i = 1;
+ while ( (uni_pin[i] = va_arg(ap, int)) >= 0 ) {
+
+ if ( i >= UNIV_NUM_WIRES ) {
+ return -5;
+ }
+
+ pic_pin[i] = va_arg(ap,int);
+
+ if ( uni_pin[i] > 7 ) {
+ return -2;
+ }
+ if ( pic_pin[i] < 0 ) {
+ return -3;
+ }
+ i++;
+ }
+
+ /* all routings must be different */
+ for ( i=0; uni_pin[i] >= 0; i++ ) {
+ for ( j=i+1; uni_pin[j] >= 0; j++ ) {
+ if ( uni_pin[j] == uni_pin[i] ) return -6;
+ if ( pic_pin[j] == pic_pin[i] ) return -7;
+ }
+ }
+
+ if ( flags & VMEUNIVERSE_IRQ_MGR_FLAG_PW_WORKAROUND ) {
+
+ /* Find registers on VME so the ISR can issue a read to flush the FIFO */
+ uprintf(stderr,"vmeUniverse IRQ manager: looking for registers on VME...\n");
+
+ /* NOTE: The universe [unlike the Tsi148] doesn't know about geographical
+ * addressing but the MotLoad firmware [mvme5500] is kind enough to
+ * program VCSR_BS based on the board's geographical address for us :-)
+ */
+ if ( ( i = ((READ_LE( vmeUniverse0BaseAddr, UNIV_REGOFF_VCSR_BS ) >> 27) & 0x1f ) ) > 0 ) {
+ uprintf(stderr,"Trying to find CSR on VME...\n");
+ vme_reg_base = i*0x80000 + UNIV_CSR_OFFSET;
+ i = mappedAndProbed( vme_reg_base, VME_AM_CSR , &cpu_base);
+ if ( i >= 0 )
+ vmeUniverseRegCSR = 1;
+ } else {
+ i = -1;
+ }
+
+ if ( -1 == i ) {
+
+ uprintf(stderr,"Trying to find CRG on VME...\n");
+
+ /* Next we see if the CRG block is mapped to VME */
+
+ if ( UNIV_VRAI_CTL_EN & (j = READ_LE( vmeUniverse0BaseAddr, UNIV_REGOFF_VRAI_CTL )) ) {
+ switch ( j & UNIV_VRAI_CTL_VAS_MSK ) {
+ case UNIV_VRAI_CTL_VAS_A16 : i = VME_AM_SUP_SHORT_IO; break;
+ case UNIV_VRAI_CTL_VAS_A24 : i = VME_AM_STD_SUP_DATA; break;
+ case UNIV_VRAI_CTL_VAS_A32 : i = VME_AM_EXT_SUP_DATA; break;
+ default:
+ break;
+ }
+ vme_reg_base = READ_LE( vmeUniverse0BaseAddr, UNIV_REGOFF_VRAI_BS ) & ~(UNIV_CRG_SIZE - 1);
+ }
+
+ if ( -1 == i ) {
+ } else {
+ i = mappedAndProbed( vme_reg_base, (i & VME_AM_MASK), &cpu_base );
+ }
+ }
+
+ if ( i < 0 ) {
+ if ( mapOverAll( vmeUniverse0BaseAddr, 1, hasPWENWindow, 0 ) ) {
+ uprintf(stderr,"vmeUniverse IRQ manager - BSP configuration error: registers not found on VME\n");
+ uprintf(stderr,"(should open outbound window to CSR space or map CRG [vmeUniverseMapCRG()])\n");
+ uprintf(stderr,"Falling back to PCI but you might experience spurious VME interrupts; read a register\n");
+ uprintf(stderr,"back from user ISR to flush universe FIFO as a work-around or\n");
+ uprintf(stderr,"make sure ISR accesses device using a window with posted-writes disabled\n");
+ } else {
+ uprintf(stderr,"vmeUniverse IRQ manager - registers not found on VME; falling back to PCI\n");
+ }
+ vmeUniverseRegBase = vmeUniverse0BaseAddr;
+ vmeUniverseRegPort = -1;
+ } else {
+ vmeUniverseRegBase = (volatile LERegister*)cpu_base;
+ vmeUniverseRegPort = i;
+ }
+ } else {
+ vmeUniverseRegBase = vmeUniverse0BaseAddr;
+ vmeUniverseRegPort = -1;
+ }
+
+ /* give them a chance to override buggy PCI info */
+ if ( pic_pin[0] >= 0 && vmeUniverse0PciIrqLine != pic_pin[0] ) {
+ uprintf(stderr,"Overriding main IRQ line PCI info with %d\n",
+ pic_pin[0]);
+ vmeUniverse0PciIrqLine=pic_pin[0];
+ }
+
+ for ( i = 0; uni_pin[i] >= 0; i++ ) {
+ /* offset wire # by one so we can initialize to 0 == invalid */
+ universe_wire[i] = uni_pin[i] + 1;
+ connectIsr((flags & VMEUNIVERSE_IRQ_MGR_FLAG_SHARED), universeVMEISR, pic_pin[i], i);
+ }
+
+ specialPin = uni_pin[1] >= 0 ? 1 : 0;
+
+ /* setup routing */
+
+ /* IntRoute checks for mgr being installed */
+ vmeUniverseIrqMgrInstalled=1;
+
+ /* route 7 VME irqs to first / 'normal' pin */
+ for ( i=1; i<8; i++ )
+ vmeUniverseIntRoute( i, 0 );
+ for ( i=UNIV_VOWN_INT_VEC; i<=UNIV_LM3_INT_VEC; i++ ) {
+ if ( vmeUniverseIntRoute( i, specialPin ) )
+ printk("Routing lvl %i -> wire # %i failed\n", i, specialPin);
+ }
+
+ return 0;
+}
+
+int
+vmeUniverseInstallIrqMgr(int vmeIrqUnivOut,
+ int vmeIrqPicLine,
+ int specialIrqUnivOut,
+ int specialIrqPicLine)
+{
+ return vmeUniverseInstallIrqMgrAlt(
+ 0, /* bwds compat. */
+ vmeIrqUnivOut, vmeIrqPicLine,
+ specialIrqUnivOut, specialIrqPicLine,
+ -1);
+}
+
+int
+vmeUniverseInstallISR(unsigned long vector, VmeUniverseISR hdl, void *arg)
+{
+UniverseIRQEntry ip;
+unsigned long flags;
+volatile UniverseIRQEntry *pe;
+
+ if (vector>sizeof(universeHdlTbl)/sizeof(universeHdlTbl[0]) || !vmeUniverseIrqMgrInstalled)
+ return -1;
+
+ pe = universeHdlTbl + vector;
+
+ if (*pe || !(ip=(UniverseIRQEntry)malloc(sizeof(UniverseIRQEntryRec))))
+ return -1;
+
+ ip->isr=hdl;
+ ip->usrData=arg;
+
+ rtems_interrupt_disable(flags);
+ if ( *pe ) {
+ /* oops; someone intervened */
+ rtems_interrupt_enable(flags);
+ free(ip);
+ return -1;
+ }
+ *pe = ip;
+ rtems_interrupt_enable(flags);
+ return 0;
+}
+
+int
+vmeUniverseRemoveISR(unsigned long vector, VmeUniverseISR hdl, void *arg)
+{
+UniverseIRQEntry ip;
+unsigned long flags;
+volatile UniverseIRQEntry *pe;
+
+ if (vector>sizeof(universeHdlTbl)/sizeof(universeHdlTbl[0]) || !vmeUniverseIrqMgrInstalled)
+ return -1;
+
+ pe = universeHdlTbl + vector;
+
+ rtems_interrupt_disable(flags);
+ ip = *pe;
+ if (!ip || ip->isr!=hdl || ip->usrData!=arg) {
+ rtems_interrupt_enable(flags);
+ return -1;
+ }
+ *pe = 0;
+ rtems_interrupt_enable(flags);
+ free(ip);
+ return 0;
+}
+
+static int
+intDoEnDis(unsigned int level, int dis)
+{
+unsigned long flags, v;
+int shift;
+
+ if ( ! vmeUniverseIrqMgrInstalled || (shift = lvl2bit(level)) < 0 )
+ return -1;
+
+ v = 1<<shift;
+
+ if ( !dis )
+ return vmeUniverseReadReg(UNIV_REGOFF_LINT_EN) & v ? 1 : 0;
+
+ rtems_interrupt_disable(flags);
+ if ( dis<0 )
+ vmeUniverseWriteReg( vmeUniverseReadReg(UNIV_REGOFF_LINT_EN) & ~v, UNIV_REGOFF_LINT_EN );
+ else {
+ vmeUniverseWriteReg( vmeUniverseReadReg(UNIV_REGOFF_LINT_EN) | v, UNIV_REGOFF_LINT_EN );
+ }
+ rtems_interrupt_enable(flags);
+ return 0;
+}
+
+int
+vmeUniverseIntEnable(unsigned int level)
+{
+ return intDoEnDis(level, 1);
+}
+
+int
+vmeUniverseIntDisable(unsigned int level)
+{
+ return intDoEnDis(level, -1);
+}
+
+int
+vmeUniverseIntIsEnabled(unsigned int level)
+{
+ return intDoEnDis(level, 0);
+}
+
+/* Loopback test of VME/universe interrupts */
+
+typedef struct {
+ rtems_id q;
+ int l;
+} LoopbackTstArgs;
+
+static void
+loopbackTstIsr(void *arg, unsigned long vector)
+{
+LoopbackTstArgs *pa = arg;
+ if ( RTEMS_SUCCESSFUL != rtems_message_queue_send(pa->q, (void*)&vector, sizeof(vector)) ) {
+ /* Overrun ? */
+ printk("vmeUniverseIntLoopbackTst: (ISR) message queue full / overrun ? disabling IRQ level %i\n", pa->l);
+ vmeUniverseIntDisable(pa->l);
+ }
+}
+
+int
+vmeUniverseIntLoopbackTst(int level, unsigned vector)
+{
+DFLT_BASE;
+rtems_status_code sc;
+rtems_id q = 0;
+int installed = 0;
+int i, err = 0;
+int doDisable = 0;
+size_t size;
+unsigned long msg;
+char * irqfmt = "VME IRQ @vector %3i %s";
+char * iackfmt = "VME IACK %s";
+LoopbackTstArgs a;
+
+ CHECK_DFLT_BASE(base);
+
+ /* arg check */
+ if ( level < 1 || level > 7 || vector > 255 ) {
+ fprintf(stderr,"Invalid level or vector argument\n");
+ return -1;
+ }
+
+ if ( (vector & 1) ) {
+ fprintf(stderr,"Software interrupts can only use even-numbered vectors, sorry.\n");
+ return -1;
+ }
+
+ if ( UNIV_REV(base) < 2 && vector != 0 ) {
+ fprintf(stderr,
+ "vmeUniverseIntLoopbackTst(): Universe 1 has a bug. IACK in response to\n");
+ fprintf(stderr,
+ "self-generated VME interrupt yields always a zero vector. As a workaround,\n");
+ fprintf(stderr,
+ "use vector 0, please.\n");
+ return -1;
+ }
+
+ /* Create message queue */
+ if ( RTEMS_SUCCESSFUL != (sc=rtems_message_queue_create(
+ rtems_build_name('t' ,'U','I','I'),
+ 4,
+ sizeof(unsigned long),
+ 0, /* default attributes: fifo, local */
+ &q)) ) {
+ rtems_error(sc, "vmeUniverseIntLoopbackTst: Unable to create message queue");
+ goto bail;
+ }
+
+ a.q = q;
+ a.l = level;
+
+ /* Install handlers */
+ if ( vmeUniverseInstallISR(vector, loopbackTstIsr, (void*)&a) ) {
+ fprintf(stderr,"Unable to install VME ISR to vector %i\n",vector);
+ goto bail;
+ }
+ installed++;
+ if ( vmeUniverseInstallISR(UNIV_VME_SW_IACK_INT_VEC, loopbackTstIsr, (void*)&a) ) {
+ fprintf(stderr,"Unable to install VME ISR to IACK special vector %i\n",UNIV_VME_SW_IACK_INT_VEC);
+ goto bail;
+ }
+ installed++;
+
+ if ( !vmeUniverseIntIsEnabled(level) && 0==vmeUniverseIntEnable(level) )
+ doDisable = 1;
+
+ /* make sure there are no pending interrupts */
+ vmeUniverseWriteReg( UNIV_LINT_STAT_SW_IACK, UNIV_REGOFF_LINT_STAT );
+
+ if ( vmeUniverseIntEnable( UNIV_VME_SW_IACK_INT_VEC ) ) {
+ fprintf(stderr,"Unable to enable IACK interrupt\n");
+ goto bail;
+ }
+
+ printf("vmeUniverse VME interrupt loopback test; STARTING...\n");
+ printf(" --> asserting VME IRQ level %i\n", level);
+ vmeUniverseIntRaise(level, vector);
+
+ for ( i = 0; i< 3; i++ ) {
+ sc = rtems_message_queue_receive(
+ q,
+ &msg,
+ &size,
+ RTEMS_WAIT,
+ 20);
+ if ( sc ) {
+ if ( RTEMS_TIMEOUT == sc && i>1 ) {
+ /* OK; we dont' expect more to happen */
+ sc = 0;
+ } else {
+ rtems_error(sc,"Error waiting for interrupts");
+ }
+ break;
+ }
+ if ( msg == vector ) {
+ if ( !irqfmt ) {
+ printf("Excess VME IRQ received ?? -- BAD\n");
+ err = 1;
+ } else {
+ printf(irqfmt, vector, "received -- PASSED\n");
+ irqfmt = 0;
+ }
+ } else if ( msg == UNIV_VME_SW_IACK_INT_VEC ) {
+ if ( !iackfmt ) {
+ printf("Excess VME IACK received ?? -- BAD\n");
+ err = 1;
+ } else {
+ printf(iackfmt, "received -- PASSED\n");
+ iackfmt = 0;
+ }
+ } else {
+ printf("Unknown IRQ (vector %lu) received -- BAD\n", msg);
+ err = 1;
+ }
+ }
+
+
+ /* Missing anything ? */
+ if ( irqfmt ) {
+ printf(irqfmt,vector, "MISSED -- BAD\n");
+ err = 1;
+ }
+ if ( iackfmt ) {
+ printf(iackfmt, "MISSED -- BAD\n");
+ err = 1;
+ }
+
+ printf("FINISHED.\n");
+
+bail:
+ if ( doDisable )
+ vmeUniverseIntDisable(level);
+ vmeUniverseIntDisable( UNIV_VME_SW_IACK_INT_VEC );
+ if ( installed > 0 )
+ vmeUniverseRemoveISR(vector, loopbackTstIsr, (void*)&a);
+ if ( installed > 1 )
+ vmeUniverseRemoveISR(UNIV_VME_SW_IACK_INT_VEC, loopbackTstIsr, (void*)&a);
+ if ( q )
+ rtems_message_queue_delete(q);
+
+ return sc ? sc : err;
+}
+
+#endif
diff --git a/bsps/powerpc/shared/vme/vme_universe.c b/bsps/powerpc/shared/vme/vme_universe.c
new file mode 100644
index 0000000000..158a899b2a
--- /dev/null
+++ b/bsps/powerpc/shared/vme/vme_universe.c
@@ -0,0 +1,436 @@
+/* Implementation of the VME.h and VMEDMA.h APIs for the BSP using the
+ * vmeUniverse/vmeTsi148 drivers
+ *
+ * This file is named vme_universe.c for historic reasons.
+ */
+
+
+#include <rtems.h>
+#include <bsp.h>
+#include <bsp/VME.h>
+#include <bsp/VMEDMA.h>
+#include <bsp/VMEConfig.h>
+#include <bsp/irq.h>
+#include <stdio.h>
+
+#define __INSIDE_RTEMS_BSP__
+
+#if !defined(_VME_DRIVER_TSI148) && !defined(_VME_DRIVER_UNIVERSE)
+#define _VME_DRIVER_UNIVERSE
+#endif
+
+#if defined(_VME_DRIVER_TSI148)
+#define _VME_TSI148_DECLARE_SHOW_ROUTINES
+#include <bsp/vmeTsi148.h>
+#include <bsp/vmeTsi148DMA.h>
+#endif
+
+#if defined(_VME_DRIVER_UNIVERSE)
+#define _VME_UNIVERSE_DECLARE_SHOW_ROUTINES
+#include <bsp/vmeUniverse.h>
+#include <bsp/vmeUniverseDMA.h>
+#if !defined(BSP_VME_INSTALL_IRQ_MGR) && defined(BSP_VME_UNIVERSE_INSTALL_IRQ_MGR)
+#define BSP_VME_INSTALL_IRQ_MGR BSP_VME_UNIVERSE_INSTALL_IRQ_MGR
+#endif
+#endif
+
+#include <bsp/bspVmeDmaList.h>
+
+/* Wrap BSP VME calls around driver calls - we do this so EPICS doesn't have to
+ * include bridge-specific headers. This file provides the necessary glue
+ * to make VME.h and vmeconfig.c independent of the bridge chip.
+ *
+ * This file is named 'vme_universe.c' for historical reasons.
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software was created by
+ * Till Straumann <strauman@slac.stanford.edu>, 9/2005,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * This software was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+typedef struct {
+ int (*xlate_adrs)(int, int, unsigned long, unsigned long, unsigned long *);
+ int (*install_isr)(unsigned long, BSP_VME_ISR_t, void *);
+ int (*remove_isr)(unsigned long, BSP_VME_ISR_t, void *);
+ BSP_VME_ISR_t (*get_isr)(unsigned long vector, void **);
+ int (*enable_int_lvl)(unsigned int);
+ int (*disable_int_lvl)(unsigned int);
+ int (*outbound_p_cfg)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
+ int (*inbound_p_cfg) (unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
+ void (*outbound_p_show)(FILE*);
+ void (*inbound_p_show) (FILE*);
+ void (*reset_bus)(void);
+ int (*install_irq_mgr)(int, int, int, ...);
+ int irq_mgr_flags;
+} VMEOpsRec, *VMEOps;
+
+/* two separate 'ops' structs for historic reasons */
+typedef struct DmaOpsRec_ {
+ int (*setup)(int, uint32_t, uint32_t, void *);
+ int (*start)(int, uint32_t, uint32_t, uint32_t);
+ uint32_t (*status)(int);
+ VMEDmaListClass listClass;
+ int nChannels;
+ int *vectors;
+} DmaOpsRec, *DmaOps;
+
+#ifdef _VME_DRIVER_UNIVERSE
+static VMEOpsRec uniOpsRec = {
+ xlate_adrs: vmeUniverseXlateAddr,
+ install_isr: vmeUniverseInstallISR,
+ remove_isr: vmeUniverseRemoveISR,
+ get_isr: vmeUniverseISRGet,
+ enable_int_lvl: vmeUniverseIntEnable,
+ disable_int_lvl: vmeUniverseIntDisable,
+ outbound_p_cfg: vmeUniverseMasterPortCfg,
+ inbound_p_cfg: vmeUniverseSlavePortCfg,
+ outbound_p_show: vmeUniverseMasterPortsShow,
+ inbound_p_show: vmeUniverseSlavePortsShow,
+ reset_bus: vmeUniverseResetBus,
+ install_irq_mgr: vmeUniverseInstallIrqMgrAlt,
+ irq_mgr_flags: VMEUNIVERSE_IRQ_MGR_FLAG_SHARED |
+ VMEUNIVERSE_IRQ_MGR_FLAG_PW_WORKAROUND,
+};
+
+static int uniVecs[] = { UNIV_DMA_INT_VEC };
+
+static DmaOpsRec uniDmaOpsRec = {
+ setup: vmeUniverseDmaSetup,
+ start: vmeUniverseDmaStart,
+ status: vmeUniverseDmaStatus,
+ listClass: &vmeUniverseDmaListClass,
+ nChannels: 1,
+ vectors: uniVecs,
+};
+#endif
+
+#ifdef _VME_DRIVER_TSI148
+static VMEOpsRec tsiOpsRec = {
+ xlate_adrs: vmeTsi148XlateAddr,
+ install_isr: vmeTsi148InstallISR,
+ remove_isr: vmeTsi148RemoveISR,
+ get_isr: vmeTsi148ISRGet,
+ enable_int_lvl: vmeTsi148IntEnable,
+ disable_int_lvl: vmeTsi148IntDisable,
+ outbound_p_cfg: vmeTsi148OutboundPortCfg,
+ inbound_p_cfg: vmeTsi148InboundPortCfg,
+ outbound_p_show: vmeTsi148OutboundPortsShow,
+ inbound_p_show: vmeTsi148InboundPortsShow,
+ reset_bus: vmeTsi148ResetBus,
+ install_irq_mgr: vmeTsi148InstallIrqMgrAlt,
+ irq_mgr_flags: VMETSI148_IRQ_MGR_FLAG_SHARED,
+};
+
+static int tsiVecs[] = {
+ TSI_DMA_INT_VEC,
+ TSI_DMA1_INT_VEC,
+};
+
+static DmaOpsRec tsiDmaOpsRec = {
+ setup: vmeTsi148DmaSetup,
+ start: vmeTsi148DmaStart,
+ status: vmeTsi148DmaStatus,
+ listClass: &vmeTsi148DmaListClass,
+ nChannels: 2,
+ vectors: tsiVecs,
+};
+#endif
+
+static VMEOps theOps = 0;
+static DmaOps theDmaOps = 0;
+
+int
+BSP_vme2local_adrs(unsigned long am, unsigned long vmeaddr, unsigned long *plocaladdr)
+{
+int rval=theOps->xlate_adrs(1,0,am,vmeaddr,plocaladdr);
+ *plocaladdr+=PCI_MEM_BASE;
+ return rval;
+}
+
+int
+BSP_local2vme_adrs(unsigned long am, unsigned long localaddr, unsigned long *pvmeaddr)
+{
+ return theOps->xlate_adrs(0, 0, am,localaddr+PCI_DRAM_OFFSET,pvmeaddr);
+}
+
+int
+BSP_installVME_isr(unsigned long vector, BSP_VME_ISR_t handler, void *arg)
+{
+ return theOps->install_isr(vector, handler, arg);
+}
+
+int
+BSP_removeVME_isr(unsigned long vector, BSP_VME_ISR_t handler, void *arg)
+{
+ return theOps->remove_isr(vector, handler, arg);
+}
+
+/* retrieve the currently installed ISR for a given vector */
+BSP_VME_ISR_t
+BSP_getVME_isr(unsigned long vector, void **parg)
+{
+ return theOps->get_isr(vector, parg);
+}
+
+int
+BSP_enableVME_int_lvl(unsigned int level)
+{
+ return theOps->enable_int_lvl(level);
+}
+
+int
+BSP_disableVME_int_lvl(unsigned int level)
+{
+ return theOps->disable_int_lvl(level);
+}
+
+int
+BSP_VMEOutboundPortCfg(
+ unsigned long port,
+ unsigned long address_space,
+ unsigned long vme_address,
+ unsigned long pci_address,
+ unsigned long size)
+{
+ return theOps->outbound_p_cfg(port, address_space, vme_address, pci_address, size);
+}
+
+int
+BSP_VMEInboundPortCfg(
+ unsigned long port,
+ unsigned long address_space,
+ unsigned long vme_address,
+ unsigned long pci_address,
+ unsigned long size)
+{
+ return theOps->inbound_p_cfg(port, address_space, vme_address, pci_address, size);
+}
+
+void
+BSP_VMEOutboundPortsShow(FILE *f)
+{
+ theOps->outbound_p_show(f);
+}
+
+void
+BSP_VMEInboundPortsShow(FILE *f)
+{
+ theOps->inbound_p_show(f);
+}
+
+void
+BSP_VMEResetBus(void)
+{
+ theOps->reset_bus();
+}
+
+int
+BSP_VMEDmaSetup(int channel, uint32_t bus_mode, uint32_t xfer_mode, void *custom_setup)
+{
+ return theDmaOps->setup(channel, bus_mode, xfer_mode, custom_setup);
+}
+
+int
+BSP_VMEDmaStart(int channel, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes)
+{
+ return theDmaOps->start(channel, pci_addr, vme_addr, n_bytes);
+}
+
+uint32_t
+BSP_VMEDmaStatus(int channel)
+{
+ return theDmaOps->status(channel);
+}
+
+BSP_VMEDmaListDescriptor
+BSP_VMEDmaListDescriptorSetup(
+ BSP_VMEDmaListDescriptor d,
+ uint32_t attr_mask,
+ uint32_t xfer_mode,
+ uint32_t pci_addr,
+ uint32_t vme_addr,
+ uint32_t n_bytes)
+{
+VMEDmaListClass pc;
+
+ if ( !d ) {
+
+ pc = theDmaOps->listClass;
+
+ return BSP_VMEDmaListDescriptorNewTool(
+ pc,
+ attr_mask,
+ xfer_mode,
+ pci_addr,
+ vme_addr,
+ n_bytes);
+
+ }
+
+ return BSP_VMEDmaListDescriptorSetupTool(d, attr_mask, xfer_mode, pci_addr, vme_addr, n_bytes);
+}
+
+int
+BSP_VMEDmaListStart(int channel, BSP_VMEDmaListDescriptor list)
+{
+ return BSP_VMEDmaListDescriptorStartTool(0, channel, list);
+}
+
+/* NOT thread safe! */
+int
+BSP_VMEDmaInstallISR(int channel, BSP_VMEDmaIRQCallback cb, void *usr_arg)
+{
+int vec;
+BSP_VME_ISR_t curr;
+void *carg;
+
+ if ( channel < 0 || channel >= theDmaOps->nChannels )
+ return -1;
+
+ vec = theDmaOps->vectors[channel];
+
+ curr = BSP_getVME_isr(vec, &carg);
+
+ if ( cb && curr ) {
+ /* IRQ currently in use */
+ return -1;
+ }
+
+ if ( !cb && !curr ) {
+ /* Allow uninstall if no handler is currently installed;
+ * just make sure IRQ is disabled
+ */
+ BSP_disableVME_int_lvl(vec);
+ return 0;
+ }
+
+ if ( cb ) {
+ if ( BSP_installVME_isr(vec, (BSP_VME_ISR_t)cb, usr_arg) )
+ return -4;
+ BSP_enableVME_int_lvl(vec);
+ } else {
+ BSP_disableVME_int_lvl(vec);
+ if ( BSP_removeVME_isr(vec, curr, carg) )
+ return -4;
+ }
+ return 0;
+}
+
+#if defined(_VME_DRIVER_TSI148) && !defined(VME_CLEAR_BRIDGE_ERRORS)
+static unsigned short
+tsi_clear_errors(int quiet)
+{
+unsigned long v;
+unsigned short rval;
+ v = vmeTsi148ClearVMEBusErrors(0);
+
+ /* return bits 8..23 of VEAT; set bit 15 to make sure rval is nonzero on error */
+ rval = v ? ((v>>8) & 0xffff) | (1<<15) : 0;
+ return rval;
+}
+
+#define VME_CLEAR_BRIDGE_ERRORS tsi_clear_errors
+#endif
+
+extern unsigned short (*_BSP_clear_vmebridge_errors)(int);
+
+int BSP_VMEInit(void)
+{
+#if defined(_VME_DRIVER_UNIVERSE)
+ if ( 0 == vmeUniverseInit() ) {
+ theOps = &uniOpsRec;
+ theDmaOps = &uniDmaOpsRec;
+ vmeUniverseReset();
+ }
+#endif
+#if defined(_VME_DRIVER_UNIVERSE) && defined(_VME_DRIVER_TSI148)
+ else
+#endif
+#if defined(_VME_DRIVER_TSI148)
+ if ( 0 == vmeTsi148Init() ) {
+ theOps = &tsiOpsRec;
+ theDmaOps = &tsiDmaOpsRec;
+ vmeTsi148Reset();
+#ifdef VME_CLEAR_BRIDGE_ERRORS
+ {
+
+ _BSP_clear_vmebridge_errors = VME_CLEAR_BRIDGE_ERRORS;
+
+ }
+#endif
+ }
+#endif
+ else
+ /* maybe no VME at all - or no universe/tsi148 ... */
+ return -1;
+
+ return 0;
+}
+
+int BSP_VMEIrqMgrInstall(void)
+{
+int err;
+#ifndef BSP_VME_INSTALL_IRQ_MGR
+ /* No map; use first line only and obtain PIC wire from PCI config */
+ err = theOps->install_irq_mgr(
+ theOps->irq_mgr_flags, /* use shared IRQs */
+ 0, -1, /* Universe/Tsi148 pin0 -> PIC line from config space */
+ -1 /* terminate list */
+ );
+#else
+ BSP_VME_INSTALL_IRQ_MGR(err);
+#endif
+
+ if ( err )
+ return err;
+
+/* This feature is only supported by the Universe driver (not Tsi148) */
+#if defined(BSP_PCI_VME_DRIVER_DOES_EOI) && defined(BSP_PIC_DO_EOI)
+#ifdef _VME_DRIVER_TSI148
+#error "BSP_PCI_VME_DRIVER_DOES_EOI/BSP_PIC_DO_EOI feature can only be used with vmeUniverse"
+#endif
+ if ( vmeUniverse0PciIrqLine < 0 )
+ rtems_panic("Unable to get universe interrupt line info from PCI config");
+ _BSP_vme_bridge_irq = vmeUniverse0PciIrqLine;
+#endif
+ return 0;
+}
diff --git a/bsps/powerpc/shared/vme/vmeconfig.c b/bsps/powerpc/shared/vme/vmeconfig.c
new file mode 100644
index 0000000000..c128d75f3c
--- /dev/null
+++ b/bsps/powerpc/shared/vme/vmeconfig.c
@@ -0,0 +1,142 @@
+/* Default VME bridge configuration - note that this file
+ * is independent of the bridge driver/chip
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software was created by
+ * Till Straumann <strauman@slac.stanford.edu>, 3/2002,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * This software was produced by
+ * the Stanford Linear Accelerator Center, Stanford University,
+ * under Contract DE-AC03-76SFO0515 with the Department of Energy.
+ *
+ * Government disclaimer of liability
+ * ----------------------------------
+ * Neither the United States nor the United States Department of Energy,
+ * nor any of their employees, makes any warranty, express or implied, or
+ * assumes any legal liability or responsibility for the accuracy,
+ * completeness, or usefulness of any data, apparatus, product, or process
+ * disclosed, or represents that its use would not infringe privately owned
+ * rights.
+ *
+ * Stanford disclaimer of liability
+ * --------------------------------
+ * Stanford University makes no representations or warranties, express or
+ * implied, nor assumes any liability for the use of this software.
+ *
+ * Stanford disclaimer of copyright
+ * --------------------------------
+ * Stanford University, owner of the copyright, hereby disclaims its
+ * copyright and all other rights in this software. Hence, anyone may
+ * freely use it for any purpose without restriction.
+ *
+ * Maintenance of notices
+ * ----------------------
+ * In the interest of clarity regarding the origin and status of this
+ * SLAC software, this and all the preceding Stanford University notices
+ * are to remain affixed to any copy or derivative of this software made
+ * or distributed by the recipient and are to be affixed to any copy of
+ * software made or distributed by the recipient that contains a copy or
+ * derivative of this software.
+ *
+ * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
+ */
+
+#include <bsp.h>
+#include <bsp/VME.h>
+#include <bsp/VMEConfig.h>
+#ifdef BSP_VME_BAT_IDX
+#include <libcpu/bat.h>
+#endif
+#include <rtems/bspIo.h>
+
+extern int BSP_VMEInit(void);
+extern int BSP_VMEIrqMgrInstall(void);
+
+/* Use a weak alias for the VME configuration.
+ * This permits individual applications to override
+ * this routine.
+ * They may even create an 'empty'
+ *
+ * void BSP_vme_config(void) {}
+ *
+ * which will avoid linking in the Universe driver
+ * at all :-).
+ */
+
+void __BSP_default_vme_config(void);
+void BSP_vme_config(void)
+ __attribute__ (( weak, alias("__BSP_default_vme_config") ));
+
+void
+__BSP_default_vme_config(void)
+{
+
+ if ( BSP_VMEInit() ) {
+ printk("Skipping VME initialization...\n");
+ return;
+ }
+
+#ifdef BSP_VME_BAT_IDX
+ /* setup a PCI area to map the VME bus */
+ setdbat(BSP_VME_BAT_IDX,
+ PCI_MEM_BASE + _VME_A32_WIN0_ON_PCI,
+ PCI_MEM_BASE + _VME_A32_WIN0_ON_PCI,
+ 0x10000000,
+ IO_PAGE);
+#endif
+
+ /* map VME address ranges */
+ BSP_VMEOutboundPortCfg(
+ 0,
+ VME_AM_EXT_SUP_DATA,
+ _VME_A32_WIN0_ON_VME,
+ _VME_A32_WIN0_ON_PCI,
+ 0x0e000000);
+ BSP_VMEOutboundPortCfg(
+ 1,
+ VME_AM_STD_SUP_DATA,
+ 0x00000000,
+ _VME_A24_ON_PCI,
+ 0x00ff0000);
+ BSP_VMEOutboundPortCfg(
+ 2,
+ VME_AM_SUP_SHORT_IO,
+ 0x00000000,
+ _VME_A16_ON_PCI,
+ 0x00010000);
+
+#ifdef _VME_CSR_ON_PCI
+ /* Map VME64 CSR */
+ BSP_VMEOutboundPortCfg(
+ 7,
+ VME_AM_CSR,
+ 0,
+ _VME_CSR_ON_PCI,
+ 0x01000000);
+#endif
+
+
+#ifdef _VME_DRAM_OFFSET
+ /* map our memory to VME giving the driver a hint that it's ordinary memory
+ * so they can enable decoupled cycles which should give better performance...
+ */
+ BSP_VMEInboundPortCfg(
+ 0,
+ VME_AM_EXT_SUP_DATA | VME_AM_IS_MEMORY,
+ _VME_DRAM_OFFSET,
+ PCI_DRAM_OFFSET,
+ BSP_mem_size);
+#endif
+
+ /* stdio is not yet initialized; the driver will revert to printk */
+ BSP_VMEOutboundPortsShow(0);
+ BSP_VMEInboundPortsShow(0);
+
+ BSP_VMEIrqMgrInstall();
+}