From c1b34d5a9269ccdd35c581bc158acbe5888fec06 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Wed, 31 Jan 2007 04:02:52 +0000 Subject: 2007-01-30 Till Straumann * vmeUniverse/README.porting, vmeUniverse/README.universe: updated, added more information for BSP implementors. * vmeUniverse/VMEDMA.h (added): VME DMA API definition. * vmeUniverse/bspVmeDmaList.h (added), vmeUniverse/bspVmeDmaListP.h (added), * vmeUniverse/bspVmeDmaList.c (added): Driver-independent code for linked-list DMA (public + private headers, implementation). * vmeUniverse/vmeUniverseDMA.h (added), vmeUniverse/vmeTsi148DMA.h (added): interface to new DMA features of drivers. * vmeUniverse/vme_amd_defs.h: Added definition for data-width hint bits (VME_MODE_DBWxx). * vmeUniverse/vmeTsi148.c: added DMA support. Added support for data-width hint/modifier bits. * vmeUniverse/vmeUniverse.c, vmeUniverse/vmeUniverse.h: Added support for data-width hint/modifier bits. Added support for xxx_BLT, xxx_MBLT address modifiers. Restrict DBW to 32 in non-MBLT modes (except single-beat; a comment is in README.universe). Updated DMA support to implement new VMEDMA.h API. Added support for non-incrementing VME addresses. Restrict data width to 32 for single-beat AMs when the universe would use MBLT for DMA. --- c/src/lib/libbsp/shared/ChangeLog | 31 + c/src/lib/libbsp/shared/vmeUniverse/README.porting | 11 + .../lib/libbsp/shared/vmeUniverse/README.universe | 60 +- c/src/lib/libbsp/shared/vmeUniverse/VMEDMA.h | 292 ++++++++++ .../lib/libbsp/shared/vmeUniverse/bspVmeDmaList.c | 335 +++++++++++ .../lib/libbsp/shared/vmeUniverse/bspVmeDmaList.h | 130 +++++ .../lib/libbsp/shared/vmeUniverse/bspVmeDmaListP.h | 96 ++++ c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148.c | 628 ++++++++++++++++++++- c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148DMA.h | 88 +++ c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.c | 595 ++++++++++++++++--- c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.h | 34 +- .../lib/libbsp/shared/vmeUniverse/vmeUniverseDMA.h | 80 +++ c/src/lib/libbsp/shared/vmeUniverse/vme_am_defs.h | 9 +- 13 files changed, 2272 insertions(+), 117 deletions(-) create mode 100644 c/src/lib/libbsp/shared/vmeUniverse/VMEDMA.h create mode 100644 c/src/lib/libbsp/shared/vmeUniverse/bspVmeDmaList.c create mode 100644 c/src/lib/libbsp/shared/vmeUniverse/bspVmeDmaList.h create mode 100644 c/src/lib/libbsp/shared/vmeUniverse/bspVmeDmaListP.h create mode 100644 c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148DMA.h create mode 100644 c/src/lib/libbsp/shared/vmeUniverse/vmeUniverseDMA.h (limited to 'c') diff --git a/c/src/lib/libbsp/shared/ChangeLog b/c/src/lib/libbsp/shared/ChangeLog index ba75d8b881..fd679a9416 100644 --- a/c/src/lib/libbsp/shared/ChangeLog +++ b/c/src/lib/libbsp/shared/ChangeLog @@ -1,3 +1,34 @@ +2007-01-30 Till Straumann + + * vmeUniverse/README.porting, vmeUniverse/README.universe: + updated, added more information for BSP implementors. + + * vmeUniverse/VMEDMA.h (added): VME DMA API definition. + + * vmeUniverse/bspVmeDmaList.h (added), vmeUniverse/bspVmeDmaListP.h (added), + * vmeUniverse/bspVmeDmaList.c (added): + Driver-independent code for linked-list DMA (public + private headers, + implementation). + + * vmeUniverse/vmeUniverseDMA.h (added), vmeUniverse/vmeTsi148DMA.h (added): + interface to new DMA features of drivers. + + * vmeUniverse/vme_amd_defs.h: Added definition for data-width + hint bits (VME_MODE_DBWxx). + + + * vmeUniverse/vmeTsi148.c: added DMA support. Added support for + data-width hint/modifier bits. + + * vmeUniverse/vmeUniverse.c, vmeUniverse/vmeUniverse.h: + Added support for data-width hint/modifier bits. + Added support for xxx_BLT, xxx_MBLT address modifiers. + Restrict DBW to 32 in non-MBLT modes (except single-beat; + a comment is in README.universe). Updated DMA support to + implement new VMEDMA.h API. Added support for non-incrementing + VME addresses. Restrict data width to 32 for single-beat AMs + when the universe would use MBLT for DMA. + 2007-01-19 Till Straumann * vmeUniverse/VME.h: diff --git a/c/src/lib/libbsp/shared/vmeUniverse/README.porting b/c/src/lib/libbsp/shared/vmeUniverse/README.porting index 8346a4b1b2..e0144806a3 100644 --- a/c/src/lib/libbsp/shared/vmeUniverse/README.porting +++ b/c/src/lib/libbsp/shared/vmeUniverse/README.porting @@ -1,6 +1,17 @@ # # $Id$ # +# + +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 diff --git a/c/src/lib/libbsp/shared/vmeUniverse/README.universe b/c/src/lib/libbsp/shared/vmeUniverse/README.universe index 2983d1911a..1059d8c806 100644 --- a/c/src/lib/libbsp/shared/vmeUniverse/README.universe +++ b/c/src/lib/libbsp/shared/vmeUniverse/README.universe @@ -4,18 +4,62 @@ 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 1/2002, 2005 - -NOTES: -These driver are maintained _outside_ rtems. -Please forward future modifications to me. +Till Straumann 1/2002, 2005, 2007 A BSP that wants to use these drivers must implement the following headers / functionality: - offering an API like 'libbsp/powerpc/shared/pci' - offering the 'new style' RTEMS irq API (like 'libbsp/powerpc/shared/irq'). + - for the I/O operations (out_le32,in_le32, ..., out_be32,...) + - 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). -The BSP should then use "VPATH magic" (to use Joel's -words :-) to reach the vmeUniverse.* / vmeTsi148.* files -in this subdir. + 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/c/src/lib/libbsp/shared/vmeUniverse/VMEDMA.h b/c/src/lib/libbsp/shared/vmeUniverse/VMEDMA.h new file mode 100644 index 0000000000..9c56b13ca5 --- /dev/null +++ b/c/src/lib/libbsp/shared/vmeUniverse/VMEDMA.h @@ -0,0 +1,292 @@ +/* $Id$ */ + +#ifndef BSP_VME_DMA_H +#define BSP_VME_DMA_H + +/* Public interface of DMA routines */ + +/* + * Authorship + * ---------- + * This software was created by + * Till Straumann , 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 + +#ifdef __cplusplus +extern "C" { +#endif + + +/* NOTE: Access to DMA Channels is *not* protected / thread-safe. + * It is the responsability of the user to provide appropriate + * locking/serialization. + */ + +/* Simple abstraction of DMA controller setup / bus utilization: */ + +/* Since VME is the bottleneck, the settings for PCI are always + * chosen aggressively. + */ + + +/* Optimize for throughput; accept longer latencies: + * Choose a large block size (1k) and immediately re-request + * the bus at block boundaries. + */ +#define BSP_VMEDMA_OPT_THROUGHPUT 1 +/* Optimize for latency, accept throughput penalty: + * Choose a small block size (32b) and immediately re-request + * the bus at block boundaries. + */ +#define BSP_VMEDMA_OPT_LOWLATENCY 2 + +/* Optimize for bus sharing with other devices: + * Choose relatively small block size (128) and back off for 64us + * at each block boundary. + */ +#define BSP_VMEDMA_OPT_SHAREDBUS 3 + +/* Choose bridge default/reset configuration: + * (see manual) + */ +#define BSP_VMEDMA_OPT_DEFAULT 4 + +/* Provide custom configuration pass pointer to array + * with as many 32-bit words the particular bridge chip + * expects. + */ +#define BSP_VMEDMA_OPT_CUSTOM 5 + +/* VME Transfer modes */ + +/* Bitwise OR of the VME address-modifier/transfer-type + * with driver specific (no standard AM code for 2eVME and + * 2eSST defined) and optional special flags (see below) + */ + +/* Additional qualifiers: */ + +/* Don't increment VME address */ +#define BSP_VMEDMA_MODE_NOINC_VME (1<<20) +/* Don't increment PCI address */ +#define BSP_VMEDMA_MODE_NOINC_PCI (1<<21) + +/* Direction */ +#define BSP_VMEDMA_MODE_PCI2VME (1<<31) + +typedef void *BSP_VMEDmaListDescriptor; + +/* Program the device for the selected mode; + * + * 'bus_mode': one of the ...VMEDMA_OPT... choices + * listed above. + * 'xfer_mode': VME address-modifier optionally ORed with + * ...VMEDMA_MODE... bits listed above. + * 'custom': (only used if bus_mode is VMEDMA_OPT_CUSTOM) + * pointer to a list of setup parameters (chip-driver + * specific). + * + * RETURNS: 0 on success, nonzero on error (mode or channel + * unsupported). + * + * NOTES: The setup is preserved across multiple DMA transfers. + * It is the responsibility of the driver to reprogram + * the setup if the hardware does not preserve it. + * However - in linked list mode, some fields may be + * read from the list descriptors. + * + * Usually this routine must be used even in linked-list + * mode to program the 'bus_mode'. + * + * Direction of transfer is specified by a bit in the + * 'xfer_mode' (BSP_VMEDMA_MODE_PCI2VME). + */ +int +BSP_VMEDmaSetup(int channel, uint32_t bus_mode, uint32_t xfer_mode, void *custom_setup); + +/* Start direct (not linked-list) transfer. + * + * RETURNS: 0 on success, nonzero on failure + */ +int +BSP_VMEDmaStart(int channel, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes); + +/* Transfer status/result */ +#define BSP_VMEDMA_STATUS_OK 0 +/* Unsupported channel */ +#define BSP_VMEDMA_STATUS_UNSUP (-1) +/* Bus error on VME */ +#define BSP_VMEDMA_STATUS_BERR_VME 1 +/* Bus error on PCI */ +#define BSP_VMEDMA_STATUS_BERR_PCI 2 +/* Channel busy */ +#define BSP_VMEDMA_STATUS_BUSY 3 +/* Setup/programming error */ +#define BSP_VMEDMA_STATUS_PERR 4 +/* Other/unspecified error */ +#define BSP_VMEDMA_STATUS_OERR 5 + +/* Retrieve status of last transfer. + * + * RETURNS: 0 if the transfer was successful, + * nonzero on error (e.g., one of the + * values defined above). + * + * NOTE: Driver is allowed to pass other, + * device specific codes + */ + +uint32_t +BSP_VMEDmaStatus(int channel); + +/* + * Hook a callback (executed from ISR context) to DMA interrupt and + * enable it. + * If called with NULL callback then an existing callback is removed + * and the interrupt disabled. + * + * RETURNS: 0 on success, nonzero on failure (IRQ in use, unsupported + * channel). + */ +typedef void (*BSP_VMEDmaIRQCallback)(void *usr_arg); + +int +BSP_VMEDmaInstallISR(int channel, BSP_VMEDmaIRQCallback cb, void *usr_arg); + +/* + * DMA List operations. + * + * Note that the list is totally unprotected, i.e., the user is + * responsible for maintaining coherency against concurrent + * access by multiple threads or hardware. + * We assume the user builds/updates a list, hands it over to + * the hardware (list start command) and leaves it alone until + * the DMA controller is done with it. + */ + +/* Modify a list entry. If the list element pointer is NULL + * then a new list element is allocated. + * Only the fields with its corresponding bit set in the mask + * argument are touched. + * + * RETURNS: 'd' or newly allocated descriptor or NULL (no memory, + * or invalid setup). + */ +#define BSP_VMEDMA_MSK_ATTR (1<<0) +#define BSP_VMEDMA_MSK_PCIA (1<<1) +#define BSP_VMEDMA_MSK_VMEA (1<<2) +#define BSP_VMEDMA_MSK_BCNT (1<<3) +#define BSP_VMEDMA_MSK_ALL (0xf) +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); + +/* De-allocate a list descriptor previously obtained by + * BSP_VMEDmaListDescriptorSetup(0,...); + * + * RETURNS: 0 on success, nonzero on failure (d currently on a list) + */ +int +BSP_VMEDmaListDescriptorDestroy(BSP_VMEDmaListDescriptor d); + +/* Traverse a list of descriptors and destroy all elements */ +int +BSP_VMEDmaListDestroy(BSP_VMEDmaListDescriptor anchor); + +/* Enqueue a list descriptor 'd' after 'tail' + * + * If 'tail' is NULL then 'd' is removed from + * the list it is currently on. + * + * RETURNS: 0 on success, nonzero if 'd' is already + * on a list (enqueue) or if it is not currently + * on a list (dequeue). + * + * NOTE: it is obviously the user's responsibility to update + * list queue/tail pointers when changing the + * structure of the list. + */ +int +BSP_VMEDmaListDescriptorEnq( + BSP_VMEDmaListDescriptor tail, + BSP_VMEDmaListDescriptor d); + +/* Obtain next and previous descriptors */ +BSP_VMEDmaListDescriptor +BSP_VMEDmaListDescriptorNext(BSP_VMEDmaListDescriptor d); + +BSP_VMEDmaListDescriptor +BSP_VMEDmaListDescriptorPrev(BSP_VMEDmaListDescriptor d); + +/* Set and get a 'usrData' pointer in the descriptor */ +void +BSP_VMEDmaListDescriptorSetUsr(BSP_VMEDmaListDescriptor d, void *usrData); + +void * +BSP_VMEDmaListDescriptorGetUsr(BSP_VMEDmaListDescriptor d); + +/* Refresh an entire list. Some DMA controllers modify certain + * fields (e.g., byte count) and this command restores the original + * setup. + */ + +int +BSP_VMEDmaListRefresh(BSP_VMEDmaListDescriptor anchor); + +/* Start linked-list operation. + * + * RETURNS: 0 on success, nonzero on failure + */ +int +BSP_VMEDmaListStart(int channel, BSP_VMEDmaListDescriptor list); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/c/src/lib/libbsp/shared/vmeUniverse/bspVmeDmaList.c b/c/src/lib/libbsp/shared/vmeUniverse/bspVmeDmaList.c new file mode 100644 index 0000000000..80a464b9bd --- /dev/null +++ b/c/src/lib/libbsp/shared/vmeUniverse/bspVmeDmaList.c @@ -0,0 +1,335 @@ +/* $Id$ */ + +/* bspVmeDmaList.c: + * implementation of generic parts of the 'linked-list VME DMA' API. + */ + +/* + * Authorship + * ---------- + * This software was created by + * Till Straumann , 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 +#include +#include +#include + +#include +#include "bspVmeDmaListP.h" + +#define DEBUG + +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; jdesc_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_VMEDmaDescriptorPrev(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/c/src/lib/libbsp/shared/vmeUniverse/bspVmeDmaList.h b/c/src/lib/libbsp/shared/vmeUniverse/bspVmeDmaList.h new file mode 100644 index 0000000000..c95d866f50 --- /dev/null +++ b/c/src/lib/libbsp/shared/vmeUniverse/bspVmeDmaList.h @@ -0,0 +1,130 @@ +#ifndef BSP_VME_DMA_LIST_H +#define BSP_VME_DMA_LIST_H + +/* $Id$ */ + + +/* The bspVmeDmaList utility implements part of the API defined by + * 'VMEDMA.h' namely all 'VMEDmaListDescriptor' related entry points: + * + * BSP_VMEDmaListDescriptorDestroy(), + * BSP_VMEDmaListDestroy(), + * BSP_VMEDmaListDescriptorEnq(), + * BSP_VMEDmaListDescriptorNext(), + * BSP_VMEDmaListDescriptorPrev(), + * BSP_VMEDmaListDescriptorSetUsr(), + * BSP_VMEDmaListDescriptorGetUsr(), + * BSP_VMEDmaListRefresh() + * + * Also, it provides helper routines to assist BSPs with implementing + * + * BSP_VMEDmaListDescriptorSetup() + * + * and + * + * BSP_VMEDmaListStart() + * + * by providing + * + * BSP_VMEDmaListDescriptorNewTool(), + * BSP_VMEDmaListDescriptorSetupTool(), + * + * and + * + * BSP_VMEDmaListDescriptorStartTool() + * + * This header should only be used inside a BSP + * chosing to use bspVmeDmaList for implementing VMEDMA.h + */ + +/* + * Authorship + * ---------- + * This software was created by + * Till Straumann , 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 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct VMEDmaListNodeRec_ *VMEDmaListNode; + +typedef struct VMEDmaListClassRec_ *VMEDmaListClass; + +/* Create and setup a new descriptor. + * The BSP must supply the appropriate controller class. + */ + +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); + +/* Setup an existing descriptor */ +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); + + +/* Start a list DMA transfer on 'controller'. The 'controller' information + * must be provided by the BSP. + */ +int +BSP_VMEDmaListDescriptorStartTool(volatile void *controller, int channel, VMEDmaListNode n); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/c/src/lib/libbsp/shared/vmeUniverse/bspVmeDmaListP.h b/c/src/lib/libbsp/shared/vmeUniverse/bspVmeDmaListP.h new file mode 100644 index 0000000000..e609cf7698 --- /dev/null +++ b/c/src/lib/libbsp/shared/vmeUniverse/bspVmeDmaListP.h @@ -0,0 +1,96 @@ +/* $Id$ */ + +#ifndef BSP_VME_DMA_LIST_P_H +#define BSP_VME_DMA_LIST_P_H + +#include + +/* Private Interface to the bspVmeDmaList facility + * + * 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 , 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; + +/* 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/c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148.c b/c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148.c index d09206899a..e51cde9bbd 100644 --- a/c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148.c +++ b/c/src/lib/libbsp/shared/vmeUniverse/vmeTsi148.c @@ -61,8 +61,18 @@ #define __INSIDE_RTEMS_BSP__ #include "vmeTsi148.h" +#include +#include "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 */ @@ -300,6 +310,29 @@ typedef unsigned int 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. */ @@ -310,6 +343,8 @@ typedef unsigned int pci_ulong; #define BSP_PCI2LOCAL_ADDR(memaddr) ((unsigned long)(memaddr) + PCI_MEM_BASE) #endif +typedef uint32_t BEValue; + typedef struct { BERegister *base; int irqLine; @@ -318,6 +353,8 @@ typedef struct { static Tsi148Dev devs[NUM_TSI_DEVS] = {{0}}; +#define THEBASE (devs[0].base) + /* forward decl */ extern int vmeTsi148RegPort; extern int vmeTsi148RegCSR; @@ -445,7 +482,7 @@ int port; void vmeTsi148Reset() { - vmeTsi148ResetXX(devs[0].base); + vmeTsi148ResetXX(THEBASE); } /* convert an address space selector to a corresponding @@ -468,8 +505,19 @@ am2omode(unsigned long address_space, unsigned long *pmode) unsigned long mode = 0; unsigned long tm = TSI_TM_SCT_IDX; - if ( ! (VME_MODE_DBW16 & address_space ) ) - mode |= TSI_OTAT_DBW(1); + 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 { @@ -701,7 +749,7 @@ int i,s,l; return -1; } - if ( base == devs[0].base && isout && vmeTsi148RegPort == port ) { + 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; } @@ -838,7 +886,7 @@ vmeTsi148InboundPortCfg( unsigned long pci_address, unsigned long length) { - return configTsiPort(devs[0].base, 0, port, address_space, vme_address, pci_address, length); + return configTsiPort(THEBASE, 0, port, address_space, vme_address, pci_address, length); } @@ -862,7 +910,7 @@ vmeTsi148OutboundPortCfg( unsigned long pci_address, unsigned long length) { - return configTsiPort(devs[0].base, 1, port, address_space, vme_address, pci_address, length); + return configTsiPort(THEBASE, 1, port, address_space, vme_address, pci_address, length); } @@ -975,7 +1023,7 @@ vmeTsi148XlateAddr( unsigned long *paOut/* where to put result */ ) { - return vmeTsi148XlateAddrXX(devs[0].base, outbound, reverse, as, aIn, paOut); + return vmeTsi148XlateAddrXX(THEBASE, outbound, reverse, as, aIn, paOut); } @@ -1055,7 +1103,7 @@ unsigned long long start, limit, offst; void vmeTsi148OutboundPortsShow(FILE *f) { - vmeTsi148OutboundPortsShowXX(devs[0].base, f); + vmeTsi148OutboundPortsShowXX(THEBASE, f); } void @@ -1115,7 +1163,7 @@ unsigned long long start, limit, offst; void vmeTsi148InboundPortsShow(FILE *f) { - vmeTsi148InboundPortsShowXX(devs[0].base, f); + vmeTsi148InboundPortsShowXX(THEBASE, f); } @@ -1132,7 +1180,7 @@ int port; void vmeTsi148DisableAllInboundPorts(void) { - vmeTsi148DisableAllInboundPortsXX(devs[0].base); + vmeTsi148DisableAllInboundPortsXX(THEBASE); } void @@ -1148,7 +1196,7 @@ int port; void vmeTsi148DisableAllOutboundPorts(void) { - vmeTsi148DisableAllOutboundPortsXX(devs[0].base); + vmeTsi148DisableAllOutboundPortsXX(THEBASE); } @@ -1191,7 +1239,7 @@ uint32_t mode; int vmeTsi148MapCRG(uint32_t vme_base, uint32_t as ) { - return vmeTsi148MapCRGXX( devs[0].base, vme_base, as ); + return vmeTsi148MapCRGXX( THEBASE, vme_base, as ); } /* Interrupt Subsystem */ @@ -1326,9 +1374,9 @@ rtems_interrupt_disable(flags); } wire_mask[pin] |= mask; - mask = TSI_RD(devs[0].base, mapreg) & ~ (0x3< (j = xlateFindPort( - devs[0].base, + THEBASE, 1, 0, as | VME_MODE_AS_MATCH, vme_addr, @@ -1587,7 +1635,7 @@ unsigned long cpu_base, vme_reg_base; uprintf(stderr,"vmeTsi148 IRQ manager: looking for registers on VME...\n"); - if ( ( i = ((TSI_RD( devs[0].base, TSI_CBAR_REG ) & 0xff) >> 3) ) > 0 ) { + 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); @@ -1603,7 +1651,7 @@ unsigned long cpu_base, vme_reg_base; /* Next we see if the CRG block is mapped to VME */ - if ( (TSI_CRGAT_EN & (j = TSI_RD( devs[0].base, TSI_CRGAT_REG ))) ) { + 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; @@ -1611,7 +1659,7 @@ unsigned long cpu_base, vme_reg_base; default: break; } - vme_reg_base = TSI_RD( devs[0].base, TSI_CBAL_REG ) & ~ (TSI_CRG_SIZE - 1); + vme_reg_base = TSI_RD( THEBASE, TSI_CBAL_REG ) & ~ (TSI_CRG_SIZE - 1); } if ( -1 == i ) { @@ -1625,7 +1673,7 @@ unsigned long cpu_base, vme_reg_base; 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)devs[0].base; + cpu_base = (unsigned long)THEBASE; i = -1; } @@ -1725,7 +1773,7 @@ volatile IRQEntry *p; static int intDoEnDis(unsigned int level, int dis) { -BERegister *b = devs[0].base; +BERegister *b = THEBASE; unsigned long flags, v; int shift; @@ -1826,7 +1874,7 @@ unsigned long v; int vmeTsi148IntRaise(int level, unsigned vector) { - return vmeTsi148IntRaiseXX(devs[0].base, level, vector); + return vmeTsi148IntRaiseXX(THEBASE, level, vector); } /* Loopback test of VME/Tsi148 internal interrupts */ @@ -1850,7 +1898,7 @@ LoopbackTstArgs *pa = arg; int vmeTsi148IntLoopbackTst(int level, unsigned vector) { -BERegister *b = devs[0].base; +BERegister *b = THEBASE; rtems_status_code sc; rtems_id q = 0; int installed = 0; @@ -2002,7 +2050,531 @@ unsigned long rval; unsigned long vmeTsi148ClearVMEBusErrors(uint32_t *paddr) { - return vmeTsi148ClearVMEBusErrorsXX(devs[0].base, 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 @@ -2030,7 +2602,7 @@ rtems_irq_connect_data xx; xx.off = my_no_op; xx.isOn = my_isOn; - TSI_WR(devs[0].base, TSI_INTEO_REG, 0); + TSI_WR(THEBASE, TSI_INTEO_REG, 0); for ( i=0; i + +/* + * Authorship + * ---------- + * This software was created by + * Till Straumann , 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 + +/* DMA List access functions for use by bspVmeDmaList */ +extern struct VMEDmaListClassRec_ vmeTsi148DmaListClass; + +typedef struct VmeTsi148DmaListDescriptorRec_ *VmeTsi148DmaListDescriptor; + +int +vmeTsi148DmaSetupXX(BERegister *base, int channel, uint32_t mode, uint32_t xfer_mode, void *custom); + +int +vmeTsi148DmaSetup(int channel, uint32_t mode, uint32_t xfer_mode, void *custom); + +int +vmeTsi148DmaListStartXX(BERegister *base, int channel, VmeTsi148DmaListDescriptor d); + +int +vmeTsi148DmaListStart(int channel, VmeTsi148DmaListDescriptor d); + +int +vmeTsi148DmaStartXX(BERegister *base, int channel, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes); + +int +vmeTsi148DmaStart(int channel, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes); + +uint32_t +vmeTsi148DmaStatusXX(BERegister *base, int channel); + +uint32_t +vmeTsi148DmaStatus(int channel); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.c b/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.c index c5c0b6f5e1..4f6947eb79 100644 --- a/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.c +++ b/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.c @@ -54,6 +54,7 @@ #endif #include "vmeUniverse.h" +#include "vmeUniverseDMA.h" #define UNIV_NUM_MPORTS 8 /* number of master ports */ #define UNIV_NUM_SPORTS 8 /* number of slave ports */ @@ -102,6 +103,7 @@ #include #include #include +#include /* allow the BSP to override the default routines */ #ifndef BSP_PCI_FIND_DEVICE @@ -132,6 +134,13 @@ typedef unsigned int pci_ulong; #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; @@ -349,6 +358,7 @@ 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 @@ -368,11 +378,22 @@ unsigned long mode=0; mode |= UNIV_SCTL_PWEN | UNIV_SCTL_PREN; mode |= UNIV_SCTL_EN; } else { - if ( VME_MODE_DBW16 & address_space ) - mode |= UNIV_MCTL_VDW16; - else - mode |= UNIV_MCTL_VDW64; - mode |= UNIV_MCTL_VCT /* enable block transfers */; + 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; @@ -388,11 +409,35 @@ unsigned long mode=0; 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: @@ -402,9 +447,32 @@ unsigned long mode=0; 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: @@ -426,6 +494,8 @@ unsigned long mode=0; } 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; } @@ -623,6 +693,40 @@ showUniversePort( } 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"); @@ -1030,62 +1134,6 @@ vmeUniverseDisableAllMasters(void) mapOverAll(base,1,disableUniversePort,0); } -int -vmeUniverseStartDMAXX( - volatile LERegister *base, - unsigned long local_addr, - unsigned long vme_addr, - unsigned long count) -{ - if ((local_addr & 7) != (vme_addr & 7)) { - uprintf(stderr,"vmeUniverseStartDMA: 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); - - if ( UNIV_DGCS_ACT & dgcs ) -#if 0 - return BSP_VMEDMA_STATUS_BUSY; -#else - return -1; -#warning "BSP_VMEDMA_STATUS_BUSY commented" -#endif - - /* clear status and make sure CHAIN is clear */ - dgcs &= ~UNIV_DGCS_CHAIN; - WRITE_LE(dgcs, - b, dgcsoff); - WRITE_LE(local_addr, - b, UNIV_REGOFF_DLA); - WRITE_LE(vme_addr, - b, UNIV_REGOFF_DVA); - WRITE_LE(count, - 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; -} - -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 vmeUniverseStartDMAXX(base, local_addr, vme_addr, count); -} - unsigned long vmeUniverseReadRegXX(volatile LERegister *base, unsigned long offset) { @@ -1239,10 +1287,427 @@ 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 -/* RTEMS interrupt subsystem */ +/* 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 ) -#ifdef __rtems__ +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 unsigned LERegister1; + +typedef struct VmeUniverseDmaListDescRec_ { + LERegister1 dctl; + LERegister1 dtbc; + LERegister1 dla; + LERegister1 dummy1; + LERegister1 dva; + LERegister1 dummy2; + LERegister1 dcpp; + LERegister1 dummy3; +} VmeUniverseDmaListDescRec +__attribute__((aligned(32), __may_alias__)); +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, +}; + +/* gcc complains even if unsigned and uint32 are the same size :-( */ + +static inline void ST_LE32(volatile uint32_t *a, uint32_t v) +{ + st_le32( (volatile unsigned *)a, v); +} + +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%08x%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 @@ -1429,7 +1894,7 @@ int pin = (int)arg; UniverseIRQEntry ip; unsigned long msk,lintstat,status; int lvl; -#ifdef BSP_PIC_DO_EOI +#if defined(BSP_PIC_DO_EOI) unsigned long linten; #endif @@ -1451,7 +1916,7 @@ unsigned long linten; } #endif -#ifndef BSP_PIC_DO_EOI /* Software priorities not supported */ +#ifndef BSP_PIC_DO_EOI /* Software priorities not supported */ if ( (status = (lintstat & SPECIAL_IRQ_MSK)) ) universeSpecialISR( status ); diff --git a/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.h b/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.h index 83d5cdd44f..b788e2a10a 100644 --- a/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.h +++ b/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverse.h @@ -71,6 +71,9 @@ typedef unsigned long LERegister; /* emphasize contents are little endian */ +/****** NOTE: USE OF VmeUniverseDMAPacket IS DEPRECATED ********* + ****** USE API IN VMEDMA.h INSTEAD *********/ + /* NOTE: DMA packet descriptors MUST be 32 byte aligned */ typedef struct VmeUniverseDMAPacketRec_ { LERegister dctl __attribute__((aligned(32))); @@ -81,7 +84,7 @@ typedef struct VmeUniverseDMAPacketRec_ { LERegister dummy2 __attribute__((packed)); LERegister dcpp __attribute__((packed)); LERegister dummy3 __attribute__((packed)); -} VmeUniverseDMAPacketRec, *VmeUniverseDMAPacket; +} VmeUniverseDMAPacketRec, *VmeUniverseDMAPacket; /* DEPRECATED */ /* PCI CSR register */ #define UNIV_REGOFF_PCI_CSR 0x4 @@ -166,6 +169,7 @@ typedef struct VmeUniverseDMAPacketRec_ { # define UNIV_DCTL_PGM (1<<14) /* VME PGM(1)/DATA(0) */ # define UNIV_DCTL_SUPER_MSK (3<<12) /* VME SUPER/USR mask 0x00003000 */ # define UNIV_DCTL_SUPER (1<<12) /* VME SUPER(1)/USR(0) */ +# define UNIV_DCTL_NO_VINC (1<<9) /* VME no VME address increment [Universe IIa/b ONLY */ # define UNIV_DCTL_VCT (1<<8) /* VME enable BLT */ # define UNIV_DCTL_LD64EN (1<<7) /* PCI 64 enable */ @@ -196,10 +200,11 @@ typedef struct VmeUniverseDMAPacketRec_ { # define UNIV_DGCS_VON_DONE (0<<20) /* VON counter disabled (do until done) */ # define UNIV_DGCS_VON_256 (1<<20) /* VON yield bus after 256 bytes */ # define UNIV_DGCS_VON_512 (2<<20) /* VON yield bus after 512 bytes */ -# define UNIV_DGCS_VON_1024 (3<<20) /* VON yield bus after 512 bytes */ -# define UNIV_DGCS_VON_2048 (4<<20) /* VON yield bus after 1024 bytes */ +# define UNIV_DGCS_VON_1024 (3<<20) /* VON yield bus after 1024 bytes */ +# define UNIV_DGCS_VON_2048 (4<<20) /* VON yield bus after 2048 bytes */ # define UNIV_DGCS_VON_4096 (5<<20) /* VON yield bus after 4096 bytes */ # define UNIV_DGCS_VON_8192 (6<<20) /* VON yield bus after 8192 bytes */ +# define UNIV_DGCS_VON_16384 (7<<20) /* VON yield bus after 16384 bytes */ # define UNIV_DGCS_VOFF_MSK (15<<16) /* VOFF mask */ # define UNIV_DGCS_VOFF_0_US (0<<16) /* re-request VME master after 0 us */ # define UNIV_DGCS_VOFF_2_US (8<<16) /* re-request VME master after 2 us */ @@ -600,6 +605,9 @@ vmeUniverseSlavePortCfg( unsigned long local_address, unsigned long length); +/****** NOTE: USE OF vmeUniverseStartDMA IS DEPRECATED ********* + ****** USE API IN VMEDMA.h/vmeUniverseDMA.h INSTEAD *********/ + /* start a (direct, not linked) DMA transfer * * NOTE: DCTL and DGCS must be set up @@ -609,7 +617,15 @@ int vmeUniverseStartDMA( unsigned long local_addr, unsigned long vme_addr, - unsigned long count); + unsigned long count); /* DEPRECATED */ + +int +vmeUniverseStartDMAXX( + volatile LERegister *ubase, + unsigned long local_addr, + unsigned long vme_addr, + unsigned long count); /* DEPRECATED */ + /* read a register in PCI memory space * (offset being one of the declared constants) @@ -696,13 +712,6 @@ void vmeUniverseSlavePortsShowXX(); #endif -int -vmeUniverseStartDMAXX( - volatile LERegister *ubase, - unsigned long local_addr, - unsigned long vme_addr, - unsigned long count); - /* Raise a VME Interrupt at 'level' and respond with 'vector' to a * handler on the VME bus. (The handler could be a different board * or the universe itself - [only works with universe II]). @@ -879,8 +888,7 @@ vmeUniverseIntIsEnabled(unsigned int level); * line a given 'level' is using. By default, * all 7 VME levels use the first wire (pin==0) and * all internal sources use the (optional) second - * wire (pin==1) [The driver doesn't support more than - * to wires]. + * wire (pin==1). * This feature is useful if you want to make use of * different hardware priorities of the PIC. Let's * say you want to give IRQ level 7 the highest priority. diff --git a/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverseDMA.h b/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverseDMA.h new file mode 100644 index 0000000000..0b1f93b7b3 --- /dev/null +++ b/c/src/lib/libbsp/shared/vmeUniverse/vmeUniverseDMA.h @@ -0,0 +1,80 @@ +/* $Id$ */ +#ifndef VME_UNIVERSE_DMA_H +#define VME_UNIVERSE_DMA_H + +/* + * Authorship + * ---------- + * This software was created by + * Till Straumann , 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 +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern struct VMEDmaListClassRec_ vmeUniverseDmaListClass; + +int +vmeUniverseDmaSetupXX(volatile LERegister *base, int channel, uint32_t mode, uint32_t xfer_mode, void *custom); + +int +vmeUniverseDmaSetup(int channel, uint32_t mode, uint32_t xfer_mode, void *custom); + +int +vmeUniverseDmaStartXX(volatile LERegister *base, int channel, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes); + +int +vmeUniverseDmaStart(int channel, uint32_t pci_addr, uint32_t vme_addr, uint32_t n_bytes); + +uint32_t +vmeUniverseDmaStatusXX(volatile LERegister *base, int channel); + +uint32_t +vmeUniverseDmaStatus(int channel); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/c/src/lib/libbsp/shared/vmeUniverse/vme_am_defs.h b/c/src/lib/libbsp/shared/vmeUniverse/vme_am_defs.h index ebe9142ffe..ed42e37a38 100644 --- a/c/src/lib/libbsp/shared/vmeUniverse/vme_am_defs.h +++ b/c/src/lib/libbsp/shared/vmeUniverse/vme_am_defs.h @@ -167,12 +167,15 @@ #define VME_AM_IS_2eSST(am) ((am) & (3<<10)) -/* Use 16-bit transfers for coupled- or BLT cycles +/* Use 8/16/32-bit transfers for coupled- or BLT cycles * (MBLT, 2exxx are probably always 64-bit) */ -#define VME_MODE_DBW16 (1<<12) +#define VME_MODE_DBW_MSK (3<<12) +#define VME_MODE_DBW8 (1<<12) +#define VME_MODE_DBW16 (2<<12) +#define VME_MODE_DBW32 (3<<12) -/* Unused Flags 1<<12 .. 1<<23 are reserved +/* Unused Flags 1<<14 .. 1<<23 are reserved * * (20-23 used by DMA API). * Flags 1<<24 .. 1<<31 are for driver specific options -- cgit v1.2.3