forked from Imagelibrary/rtems
* vmeUniverse/vme_am_defs.h: Added address modifiers for 2eVME. Added
flags for 2eSST and DBW16. * vmeUniverse/vmeUniverse.h: Removed AM definitions and include vme_am_defs.h instead. Declare new routine vmeUniverseMapCRG(). Export 'irq manager' API only if __INSIDE_RTEMS_BSP__ defined. Renamed 'shared' argument to vmeUniverseInstallIrqMgrAlt() to 'flags' since now more options are available. Added new flag to install 'posted-write' workaround. * vmeUniverse/vmeUniverse.c: Allow BSP to override BSP_PCI2LOCAL_ADDR() macro. Data width of outbound port can now be restricted to 16-bit (if new DBW16 flag set in address modifier). Added vmeUniverseMapCRG() for mapping local registers onto VME. Interrupt manager now implements a workaround (enabled at installation time) which flushes the write-fifo after user ISR returns. This requires the universe's registers to be accessible from VME (either CSR space or CRG mapped to A16/A24/A32), though. * vmeUniverse/vmeTsi148.h: vmeTsi148ClearVMEBusErrors() now returns the fault address as a 32-bit address (not ulonglong anymore). The driver only supports 32-bit addresses. Declare new routine vmeTsi148MapCRG(). Export 'irq manager' API only if __INSIDE_RTEMS_BSP__ defined. Renamed 'shared' argument to vmeTsi148InstallIrqMgrAlt() to 'flags' to allow more options to be supported. Added comments explaining the 'posted-write' workaround implemented by the interrupt manager. * vmeUniverse/vmeTsi148.c: Clear 'SYSFAIL' during initialization. Allow BSP to override BSP_PCI2LOCAL_ADDR() macro. Added support for 2eSST when configuring windows (untested - I have no 2eSST). Added vmeTsi148MapCRG() for mapping local registers onto VME. Implemented 'posted-write' workaround for interrupt manager (consult source for details).
This commit is contained in:
@@ -1,3 +1,37 @@
|
||||
2006-12-13 Till Straumann <strauman@slac.stanford.edu>
|
||||
* vmeUniverse/vme_am_defs.h: Added address modifiers for 2eVME. Added
|
||||
flags for 2eSST and DBW16.
|
||||
|
||||
* vmeUniverse/vmeUniverse.h: Removed AM definitions and include vme_am_defs.h
|
||||
instead. Declare new routine vmeUniverseMapCRG(). Export 'irq manager' API
|
||||
only if __INSIDE_RTEMS_BSP__ defined. Renamed 'shared' argument to
|
||||
vmeUniverseInstallIrqMgrAlt() to 'flags' since now more options are available.
|
||||
Added new flag to install 'posted-write' workaround.
|
||||
|
||||
* vmeUniverse/vmeUniverse.c: Allow BSP to override BSP_PCI2LOCAL_ADDR()
|
||||
macro. Data width of outbound port can now be restricted to 16-bit
|
||||
(if new DBW16 flag set in address modifier). Added vmeUniverseMapCRG()
|
||||
for mapping local registers onto VME. Interrupt manager now implements
|
||||
a workaround (enabled at installation time) which flushes the write-fifo
|
||||
after user ISR returns. This requires the universe's registers to be
|
||||
accessible from VME (either CSR space or CRG mapped to A16/A24/A32),
|
||||
though.
|
||||
|
||||
* vmeUniverse/vmeTsi148.h: vmeTsi148ClearVMEBusErrors() now returns
|
||||
the fault address as a 32-bit address (not ulonglong anymore). The
|
||||
driver only supports 32-bit addresses. Declare new routine vmeTsi148MapCRG().
|
||||
Export 'irq manager' API only if __INSIDE_RTEMS_BSP__ defined.
|
||||
Renamed 'shared' argument to vmeTsi148InstallIrqMgrAlt() to 'flags'
|
||||
to allow more options to be supported. Added comments explaining the
|
||||
'posted-write' workaround implemented by the interrupt manager.
|
||||
|
||||
* vmeUniverse/vmeTsi148.c: Clear 'SYSFAIL' during initialization.
|
||||
Allow BSP to override BSP_PCI2LOCAL_ADDR() macro. Added support for
|
||||
2eSST when configuring windows (untested - I have no 2eSST).
|
||||
Added vmeTsi148MapCRG() for mapping local registers onto VME.
|
||||
Implemented 'posted-write' workaround for interrupt manager
|
||||
(consult source for details).
|
||||
|
||||
2006-11-17 Joel Sherrill <joel@OARcorp.com>
|
||||
|
||||
* clock_driver_stub.c, clockdrv_shell.c: Use common clock driver
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include <bsp.h>
|
||||
#include <libcpu/byteorder.h>
|
||||
|
||||
#define __INSIDE_RTEMS_BSP__
|
||||
|
||||
#include "vmeTsi148.h"
|
||||
|
||||
#define STATIC static
|
||||
@@ -54,7 +56,16 @@
|
||||
# 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)
|
||||
@@ -71,6 +82,17 @@
|
||||
|
||||
#define TSI_VIACK_1_REG 0x204
|
||||
|
||||
#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
|
||||
@@ -96,6 +118,9 @@
|
||||
# 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)
|
||||
@@ -111,6 +136,20 @@
|
||||
# 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)
|
||||
@@ -183,10 +222,18 @@
|
||||
#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 unsigned *)((base) + (reg)/sizeof(*base)))
|
||||
#define TSI_RD16(base, reg) in_be16((volatile unsigned short *)(base) + (reg)/sizeof(short))
|
||||
#define TSI_RD8(base, reg) *((volatile unsigned char *)(base) + (reg))
|
||||
#define TSI_LE_RD16(base, reg) in_le16((volatile unsigned short *)(base) + (reg)/sizeof(short))
|
||||
#define TSI_LE_RD32(base, reg) in_le32((volatile unsigned *)(base) + (reg)/sizeof(*base))
|
||||
#define TSI_RD8(base, reg) in_8((volatile unsigned char *)(base) + (reg))
|
||||
#define TSI_WR(base, reg, val) out_be32((volatile unsigned *)((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)
|
||||
@@ -214,7 +261,12 @@ typedef unsigned int pci_ulong;
|
||||
/* PCI_MEM_BASE is a possible offset between CPU- and PCI addresses.
|
||||
* Should be defined by the BSP.
|
||||
*/
|
||||
#define PCI_TO_LOCAL_ADDR(memaddr) ((pci_ulong)(memaddr) + PCI_MEM_BASE)
|
||||
#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 struct {
|
||||
BERegister *base;
|
||||
@@ -224,6 +276,10 @@ typedef struct {
|
||||
|
||||
static Tsi148Dev devs[NUM_TSI_DEVS] = {{0}};
|
||||
|
||||
/* 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.
|
||||
@@ -280,7 +336,7 @@ unsigned short wrd;
|
||||
return -1;
|
||||
/* Assume upper BAR is zero */
|
||||
|
||||
*pbase=(BERegister*)(PCI_TO_LOCAL_ADDR(busaddr) & ~0xff);
|
||||
*pbase=(BERegister*)(((pci_ulong)BSP_PCI2LOCAL_ADDR(busaddr)) & ~0xff);
|
||||
|
||||
if (BSP_PCI_CONFIG_IN_BYTE(bus,dev,fun,PCI_INTERRUPT_LINE,&irqline))
|
||||
return -1;
|
||||
@@ -339,6 +395,9 @@ int port;
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -351,28 +410,31 @@ vmeTsi148Reset()
|
||||
* 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, mask;
|
||||
unsigned long mode = 0;
|
||||
unsigned long tm = TSI_TM_SCT_IDX;
|
||||
|
||||
if ( ! (VME_MODE_DBW32_DISABLE & address_space ) )
|
||||
if ( ! (VME_MODE_DBW16 & address_space ) )
|
||||
mode |= TSI_OTAT_DBW(1);
|
||||
if ( ! (VME_MODE_PREFETCH_ENABLE & address_space) )
|
||||
mode |= TSI_OTAT_MRPFD;
|
||||
else {
|
||||
mode |= TSI_OTAT_PFS(address_space>>12);
|
||||
mode |= TSI_OTAT_PFS(address_space>>_LD_VME_MODE_PREFETCHSZ);
|
||||
}
|
||||
mode |= TSI_OTAT_2eSSTM(address_space>>16);
|
||||
|
||||
for ( tm = 1, mask = VME_MODE_BLT; ! (mask & address_space); tm++, mask<<=1 ) {
|
||||
if ( VME_MODE_2eSST_BCST == mask ) {
|
||||
tm = 0; /* select default: BLT enabled */
|
||||
break;
|
||||
}
|
||||
}
|
||||
mode |= TSI_OTAT_TM(tm);
|
||||
address_space = ck2esst(address_space);
|
||||
|
||||
switch (address_space & VME_AM_MASK) {
|
||||
case VME_AM_STD_SUP_PGM:
|
||||
@@ -381,6 +443,17 @@ unsigned long tm, mask;
|
||||
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:
|
||||
|
||||
@@ -392,8 +465,20 @@ unsigned long tm, mask;
|
||||
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;
|
||||
|
||||
@@ -406,12 +491,32 @@ unsigned long tm, mask;
|
||||
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;
|
||||
@@ -422,30 +527,40 @@ STATIC int
|
||||
am2imode(unsigned long address_space, unsigned long *pmode)
|
||||
{
|
||||
unsigned long mode=0;
|
||||
unsigned long tm, mask;
|
||||
unsigned long pgm = 0;
|
||||
|
||||
mode |= TSI_ITAT_VFS(address_space>>12);
|
||||
mode |= TSI_ITAT_2eSSTM(address_space>>16);
|
||||
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;
|
||||
|
||||
mask = VME_MODE_BLT;
|
||||
tm = TSI_ITAT_BLT;
|
||||
do {
|
||||
mask<<=1; tm<<=1;
|
||||
if ( address_space & mask )
|
||||
mode |= tm;
|
||||
} while ( TSI_ITAT_2eSSTB != tm );
|
||||
|
||||
tm = 0;
|
||||
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:
|
||||
|
||||
tm = 1;
|
||||
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:
|
||||
|
||||
@@ -454,9 +569,15 @@ unsigned long tm, mask;
|
||||
|
||||
case VME_AM_EXT_SUP_PGM:
|
||||
case VME_AM_EXT_USR_PGM:
|
||||
tm = 1;
|
||||
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;
|
||||
@@ -477,12 +598,8 @@ unsigned long tm, mask;
|
||||
|
||||
if ( VME_AM_IS_SUP(address_space) )
|
||||
mode |= TSI_ITAT_SUP;
|
||||
else
|
||||
mode |= TSI_ITAT_USR;
|
||||
|
||||
if ( tm )
|
||||
mode |= TSI_ITAT_PGM;
|
||||
else
|
||||
if ( !pgm )
|
||||
mode |= TSI_ITAT_DATA;
|
||||
|
||||
*pmode = mode;
|
||||
@@ -531,6 +648,7 @@ configTsiPort(
|
||||
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);
|
||||
|
||||
@@ -541,6 +659,11 @@ char *name = (isout ? "Outbound" : "Inbound");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( base == devs[0].base && 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;
|
||||
@@ -554,6 +677,21 @@ char *name = (isout ? "Outbound" : "Inbound");
|
||||
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;
|
||||
@@ -561,6 +699,31 @@ char *name = (isout ? "Outbound" : "Inbound");
|
||||
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 */
|
||||
@@ -661,8 +824,8 @@ vmeTsi148OutboundPortCfg(
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
vmeTsi148XlateAddrXX(
|
||||
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 */
|
||||
@@ -680,16 +843,27 @@ unsigned long tsau_reg, tat_reg, gran, skip;
|
||||
|
||||
mode = 0; /* silence warning */
|
||||
|
||||
if ( VME_MODE_EXACT_MATCH & as ) {
|
||||
switch ( as & VME_MODE_MATCH_MASK ) {
|
||||
case VME_MODE_EXACT_MATCH:
|
||||
mode_msk = ~0;
|
||||
} else {
|
||||
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_EXACT_MATCH;
|
||||
as &= ~VME_MODE_MATCH_MASK;
|
||||
|
||||
if ( outbound ? am2omode(as,&mode) : am2imode(as,&mode) ) {
|
||||
uprintf(stderr, "vmeTsi148XlateAddr: invalid address space/mode argument");
|
||||
@@ -727,7 +901,7 @@ unsigned long tsau_reg, tat_reg, gran, skip;
|
||||
if ( aIn >= start && aIn <= limit ) {
|
||||
/* found it */
|
||||
*paOut = (unsigned long)(a + offst);
|
||||
return 0;
|
||||
return port;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -736,6 +910,20 @@ unsigned long tsau_reg, tat_reg, gran, skip;
|
||||
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 */
|
||||
@@ -922,6 +1110,48 @@ vmeTsi148DisableAllOutboundPorts(void)
|
||||
}
|
||||
|
||||
|
||||
/* 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( devs[0].base, vme_base, as );
|
||||
}
|
||||
|
||||
/* Interrupt Subsystem */
|
||||
|
||||
typedef struct
|
||||
@@ -932,7 +1162,10 @@ IRQEntryRec_ {
|
||||
|
||||
static IRQEntry irqHdlTbl[TSI_NUM_INT_VECS]={0};
|
||||
|
||||
int vmeTsi148IrqMgrInstalled=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 */
|
||||
@@ -1094,7 +1327,16 @@ unsigned long msk,lintstat,vector, vecarg;
|
||||
int lvl;
|
||||
|
||||
/* only handle interrupts routed to this pin */
|
||||
while ( (lintstat = (TSI_RD(b, TSI_INTS_REG) & wire_mask[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 */
|
||||
|
||||
@@ -1154,11 +1396,16 @@ int lvl;
|
||||
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%08x -- DISABING level %i\n",
|
||||
printk("vmeTsi148 ISR: ERROR: no handler registered (level %i) IACK 0x%08x -- 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 */
|
||||
@@ -1213,10 +1460,54 @@ va_list ap;
|
||||
return rval;
|
||||
}
|
||||
|
||||
#ifndef BSP_EARLY_PROBE_VME
|
||||
#define BSP_EARLY_PROBE_VME(addr) \
|
||||
( \
|
||||
vmeTsi148ClearVMEBusErrorsXX( devs[0].base, 0 ), \
|
||||
( ((PCI_DEVICE_TSI148 << 16) | PCI_VENDOR_TUNDRA ) == TSI_LE_RD32( ((BERegister*)(addr)), 0 ) \
|
||||
&& 0 == vmeTsi148ClearVMEBusErrorsXX( devs[0].base, 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(
|
||||
devs[0].base,
|
||||
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;
|
||||
|
||||
@@ -1248,6 +1539,57 @@ int i,j, specialPin, tsi_pin[TSI_NUM_WIRES+1], pic_pin[TSI_NUM_WIRES];
|
||||
}
|
||||
}
|
||||
|
||||
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( devs[0].base, 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( devs[0].base, 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( devs[0].base, 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)devs[0].base;
|
||||
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",
|
||||
@@ -1591,7 +1933,7 @@ bail:
|
||||
}
|
||||
|
||||
unsigned long
|
||||
vmeTsi148ClearVMEBusErrorsXX(BERegister *base, unsigned long long *paddr)
|
||||
vmeTsi148ClearVMEBusErrorsXX(BERegister *base, uint32_t *paddr)
|
||||
{
|
||||
unsigned long rval;
|
||||
|
||||
@@ -1600,8 +1942,12 @@ unsigned long rval;
|
||||
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);
|
||||
@@ -1612,7 +1958,7 @@ unsigned long rval;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
vmeTsi148ClearVMEBusErrors(unsigned long long *paddr)
|
||||
vmeTsi148ClearVMEBusErrors(uint32_t *paddr)
|
||||
{
|
||||
return vmeTsi148ClearVMEBusErrorsXX(devs[0].base, paddr);
|
||||
}
|
||||
|
||||
@@ -7,33 +7,27 @@
|
||||
* Sept. 2005.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <bsp/vme_am_defs.h>
|
||||
|
||||
|
||||
/* NOTE: A64 currently not implemented */
|
||||
|
||||
/* These can be ored with the AM */
|
||||
|
||||
/* NOTE: unlike the universe, the tsi148 doesn't allow for disabling posted writes ! */
|
||||
|
||||
#define VME_MODE_PREFETCH_ENABLE VME_AM_IS_MEMORY
|
||||
#define VME_MODE_PREFETCH_SIZE(x) (((x)&3)<<12)
|
||||
#define VME_MODE_2eSSTM(x) (((x)&7)<<16)
|
||||
#define _LD_VME_MODE_PREFETCHSZ 24
|
||||
#define VME_MODE_PREFETCH_SIZE(x) (((x)&3)<<_LD_VME_MODE_PREFETCHSZ)
|
||||
|
||||
#define VME_MODE_DBW32_DISABLE (8<<12)
|
||||
|
||||
/* Transfer modes:
|
||||
*
|
||||
* On a outbound window, only the least significant
|
||||
* bit that is set is considered.
|
||||
* On a inbound window, the bitwise OR of modes
|
||||
* is accepted.
|
||||
/* These bits can be or'ed with the address-modifier when calling
|
||||
* the 'XlateAddr' routine below to further qualify the
|
||||
* search criteria.
|
||||
*/
|
||||
#define VME_MODE_BLT (1<<20)
|
||||
#define VME_MODE_MBLT (1<<21)
|
||||
#define VME_MODE_2eVME (1<<22)
|
||||
#define VME_MODE_2eSST (1<<23)
|
||||
#define VME_MODE_2eSST_BCST (1<<24)
|
||||
#define VME_MODE_MASK (31<<20)
|
||||
|
||||
#define VME_MODE_EXACT_MATCH (1<<31)
|
||||
#define VME_MODE_MATCH_MASK (3<<30)
|
||||
#define VME_MODE_EXACT_MATCH (2<<30) /* all bits must match */
|
||||
#define VME_MODE_AS_MATCH (1<<30) /* only A16/24/32 must match */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -191,6 +185,16 @@ vmeTsi148XlateAddr(
|
||||
unsigned long *paOut/* where to put result */
|
||||
);
|
||||
|
||||
|
||||
/* avoid pulling stdio.h into this header.
|
||||
* Applications that want a declaration of the
|
||||
* following routines should
|
||||
* #include <stdio.h>
|
||||
* #define _VME_TSI148_DECLARE_SHOW_ROUTINES
|
||||
* #include <vmeTsi148.h>
|
||||
*/
|
||||
#ifdef _VME_TSI148_DECLARE_SHOW_ROUTINES
|
||||
|
||||
/* Print the current configuration of all outbound ports to
|
||||
* f (stdout if NULL)
|
||||
*/
|
||||
@@ -211,6 +215,8 @@ vmeTsi148InboundPortsShowXX(BERegister *base, FILE *f);
|
||||
void
|
||||
vmeTsi148InboundPortsShow(FILE *f);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Disable all in- or out-bound ports, respectively */
|
||||
void
|
||||
@@ -248,17 +254,43 @@ vmeTsi148DisableAllOutboundPorts(void);
|
||||
* 0 if no error has occurred since this routine was last called.
|
||||
* Contents of the 'VEAT' register (bit definitions as above)
|
||||
* otherwise.
|
||||
* If a non-NULL 'paddr' argument is provided then the 64-bit error
|
||||
* address is stored in *paddr (only if return value is non-zero).
|
||||
* If a non-NULL 'paddr' argument is provided then the lower 32-bit
|
||||
* of the error address is stored in *paddr (only if return value is
|
||||
* non-zero).
|
||||
*
|
||||
* SIDE EFFECTS: this routine clears the error attribute register, allowing
|
||||
* for future errors to be latched.
|
||||
*/
|
||||
unsigned long
|
||||
vmeTsi148ClearVMEBusErrorsXX(BERegister *base, unsigned long long *paddr);
|
||||
vmeTsi148ClearVMEBusErrorsXX(BERegister *base, uint32_t *paddr);
|
||||
|
||||
unsigned long
|
||||
vmeTsi148ClearVMEBusErrors(unsigned long long *paddr);
|
||||
vmeTsi148ClearVMEBusErrors(uint32_t *paddr);
|
||||
|
||||
/* Map internal register block to VME.
|
||||
*
|
||||
* This routine is intended for BSP implementors. The registers must be
|
||||
* accessible from VME so that the interrupt handler can flush the
|
||||
* bridge FIFO (see below).
|
||||
*
|
||||
* vme_base: VME address where the TSI registers (4k) can be mapped.
|
||||
* This VME address must fall into a range covered by
|
||||
* any pre-configured outbound window.
|
||||
* address_space: The desired VME address space.
|
||||
* (all of SUP/USR/PGM/DATA are always accepted).
|
||||
*
|
||||
* See NOTES [vmeTsi148InstallIrqMgrAlt()] below for further information.
|
||||
*
|
||||
* RETURNS: 0 on success, nonzero on error. It is not possible (and results
|
||||
* in a non-zero return code) to change the CRG VME address after
|
||||
* initializing the interrupt manager as it uses the CRG.
|
||||
*/
|
||||
int
|
||||
vmeTsi148MapCRGXX(BERegister *base, uint32_t vme_base, uint32_t address_space);
|
||||
|
||||
int
|
||||
vmeTsi148MapCRG(uint32_t vme_base, uint32_t address_space);
|
||||
|
||||
|
||||
/* VME Interrupt Handler functionality */
|
||||
|
||||
@@ -474,6 +506,10 @@ vmeTsi148IntLoopbackTst(int level, unsigned vector);
|
||||
|
||||
#define TSI_NUM_INT_VECS 275
|
||||
|
||||
#ifdef __INSIDE_RTEMS_BSP__
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/* the tsi148 interrupt handler is capable of routing all sorts of
|
||||
* (VME) interrupts to 4 different lines (some of) which may be hooked up
|
||||
* in a (board specific) way to a PIC.
|
||||
@@ -501,15 +537,18 @@ vmeTsi148IntLoopbackTst(int level, unsigned vector);
|
||||
* from PCI config space is wrong for some boards!
|
||||
*
|
||||
* PARAMETERS:
|
||||
* shared: use the BSP_install_rtems_shared_irq_handler() instead
|
||||
* flags: VMETSI148_IRQ_MGR_FLAG_SHARED:
|
||||
* use the BSP_install_rtems_shared_irq_handler() instead
|
||||
* of BSP_install_rtems_irq_handler(). Use this if the PIC
|
||||
* line is used by other devices, too.
|
||||
* CAVEAT: shared interrupts need RTEMS workspace, i.e., the
|
||||
* VME interrupt manager can only be installed
|
||||
* *after workspace is initialized* if 'shared' is nonzero
|
||||
* (i.e., *not* from bspstart()).
|
||||
*
|
||||
* tsi_pin_0: to which output pin (of the tsi148) should the 7
|
||||
* VME irq levels be routed.
|
||||
*
|
||||
* pic_pin_0: specifies to which PIC input the 'main' output is
|
||||
* wired on your board. If passed a value < 0, the driver
|
||||
* reads this information from PCI config space ("IRQ line").
|
||||
@@ -519,12 +558,39 @@ vmeTsi148IntLoopbackTst(int level, unsigned vector);
|
||||
*
|
||||
* RETURNS: 0 on success, -1 on failure.
|
||||
*
|
||||
* NOTES: The Tsi148 always does 'posted' writes through a FIFO buffer.
|
||||
* This effectively makes VME write operations asynchronous
|
||||
* which can have undesired side-effects.
|
||||
* In particular, consider the case of an ISR clearing the
|
||||
* interrupt condition by writing to a CSR. The write operation
|
||||
* doesn't really do anything but goes into the FIFO and
|
||||
* the user ISR returns. At this point, the interrupt manager
|
||||
* may find the IRQ still pending, trying another IACK
|
||||
* cycle. Because it is probable that at this time the FIFO
|
||||
* has been flushed and the CSR-write operation been effective,
|
||||
* the IACK then times out.
|
||||
* Note that this phenomenon becomes more obvious as CPUs
|
||||
* become faster.
|
||||
*
|
||||
* To avoid this race condition and many VME drivers having
|
||||
* to be re-written, a VME read (having the desired side-effect
|
||||
* of flushing the write FIFO) must be issued between the
|
||||
* user ISR returning and the interrupt manager checking for
|
||||
* more pending interrupts.
|
||||
*
|
||||
* Therefore, the BSP needs to map the Tsi148 register
|
||||
* block to VME so that a read over VME can be effectuated.
|
||||
* (In addition to being mapped to VME, the mapped address
|
||||
* range must be accessible through an outbound window.)
|
||||
*/
|
||||
|
||||
#define VMETSI148_IRQ_MGR_FLAG_SHARED 1
|
||||
int
|
||||
vmeTsi148InstallIrqMgrAlt(int shared, int tsi_pin0, int pic_pin0, ...);
|
||||
|
||||
int
|
||||
vmeTsi148InstallIrqMgrVa(int shared, int tsi_pin0, int pic_pin0, va_list ap);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -6,7 +6,11 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#if defined(__rtems__)
|
||||
#define __INSIDE_RTEMS_BSP__
|
||||
#endif
|
||||
|
||||
#include "vmeUniverse.h"
|
||||
|
||||
#define UNIV_NUM_MPORTS 8 /* number of master ports */
|
||||
@@ -33,6 +37,7 @@
|
||||
#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)
|
||||
|
||||
@@ -77,12 +82,18 @@
|
||||
* Should be defined by the BSP.
|
||||
*/
|
||||
typedef unsigned int pci_ulong;
|
||||
#define PCI_TO_LOCAL_ADDR(memaddr) ((pci_ulong)(memaddr) + PCI_MEM_BASE)
|
||||
|
||||
#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
|
||||
|
||||
|
||||
#elif defined(__vxworks)
|
||||
typedef unsigned long pci_ulong;
|
||||
#define PCI_TO_LOCAL_ADDR(memaddr) (memaddr)
|
||||
#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
|
||||
@@ -97,6 +108,11 @@ typedef unsigned long pci_ulong;
|
||||
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) \
|
||||
@@ -271,7 +287,7 @@ unsigned char irqline;
|
||||
|| ((unsigned long)(busaddr) & 1))
|
||||
return -1;
|
||||
}
|
||||
*pbase=(volatile LERegister*)PCI_TO_LOCAL_ADDR(busaddr);
|
||||
*pbase=(volatile LERegister*)BSP_PCI2LOCAL_ADDR(busaddr);
|
||||
|
||||
if (BSP_PCI_CONFIG_IN_BYTE(bus,dev,fun,PCI_INTERRUPT_LINE,&irqline))
|
||||
return -1;
|
||||
@@ -301,6 +317,8 @@ unsigned long mode=0;
|
||||
* ????????
|
||||
*/
|
||||
|
||||
address_space &= ~VME_MODE_MATCH_MASK;
|
||||
|
||||
if (!ismaster) {
|
||||
mode |= UNIV_SCTL_DAT | UNIV_SCTL_PGM;
|
||||
mode |= UNIV_SCTL_USER;
|
||||
@@ -308,7 +326,11 @@ unsigned long mode=0;
|
||||
mode |= UNIV_SCTL_PWEN | UNIV_SCTL_PREN;
|
||||
mode |= UNIV_SCTL_EN;
|
||||
} else {
|
||||
mode |= UNIV_MCTL_VDW64 | UNIV_MCTL_VCT /* enable block transfers */;
|
||||
if ( VME_MODE_DBW16 & address_space )
|
||||
mode |= UNIV_MCTL_VDW16;
|
||||
else
|
||||
mode |= UNIV_MCTL_VDW64;
|
||||
mode |= UNIV_MCTL_VCT /* enable block transfers */;
|
||||
if ( VME_AM_IS_MEMORY & address_space )
|
||||
mode |= UNIV_MCTL_PWEN;
|
||||
mode |= UNIV_MCTL_EN;
|
||||
@@ -316,7 +338,7 @@ unsigned long mode=0;
|
||||
|
||||
address_space &= ~VME_AM_IS_MEMORY;
|
||||
|
||||
switch (address_space) {
|
||||
switch (address_space & VME_AM_MASK) {
|
||||
case VME_AM_STD_SUP_PGM:
|
||||
case VME_AM_STD_USR_PGM:
|
||||
if (ismaster)
|
||||
@@ -592,7 +614,7 @@ typedef struct XlatRec_ {
|
||||
*
|
||||
* RETURNS: -1: invalid space
|
||||
* 0: invalid address (not found in range)
|
||||
* 1: success
|
||||
* port+1: success
|
||||
*/
|
||||
|
||||
static int
|
||||
@@ -614,11 +636,24 @@ unsigned long cntrl, start, bound, offst, mask, x;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( ! (VME_MODE_EXACT_MATCH & l->aspace) ) {
|
||||
cntrl &= (ismaster ? UNIV_MCTL_AM_MASK : UNIV_SCTL_AM_MASK);
|
||||
offst &= (ismaster ? UNIV_MCTL_AM_MASK : UNIV_SCTL_AM_MASK);
|
||||
|
||||
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 */
|
||||
|
||||
@@ -639,7 +674,7 @@ unsigned long cntrl, start, bound, offst, mask, x;
|
||||
*/
|
||||
if (l->address >= start && l->address < bound) {
|
||||
l->address+=offst;
|
||||
return 1;
|
||||
return 1 + port;
|
||||
}
|
||||
} else {
|
||||
x = l->address - offst;
|
||||
@@ -647,12 +682,24 @@ unsigned long cntrl, start, bound, offst, mask, x;
|
||||
if (x >= start && x < bound) {
|
||||
/* valid address found */
|
||||
l->address = x;
|
||||
return 1;
|
||||
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)
|
||||
@@ -696,8 +743,8 @@ showUniversePorts(volatile LERegister *base, int ismaster, FILE *f)
|
||||
mapOverAll(base,ismaster,showUniversePort,f);
|
||||
}
|
||||
|
||||
int
|
||||
vmeUniverseXlateAddrXX(
|
||||
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 */
|
||||
@@ -717,6 +764,19 @@ XlatRec l;
|
||||
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 */
|
||||
@@ -757,8 +817,10 @@ vmeUniverseReset(void)
|
||||
/* 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
|
||||
@@ -1082,9 +1144,56 @@ vmeUniverseIntRaise(int level, unsigned 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 );
|
||||
}
|
||||
|
||||
|
||||
/* RTEMS interrupt subsystem */
|
||||
|
||||
#ifdef __rtems__
|
||||
|
||||
#include <bsp/irq.h>
|
||||
|
||||
typedef struct
|
||||
@@ -1095,7 +1204,9 @@ UniverseIRQEntryRec_ {
|
||||
|
||||
static UniverseIRQEntry universeHdlTbl[UNIV_NUM_INT_VECS]={0};
|
||||
|
||||
int vmeUniverseIrqMgrInstalled=0;
|
||||
int vmeUniverseIrqMgrInstalled = 0;
|
||||
|
||||
volatile LERegister *vmeUniverseRegBase = 0;
|
||||
|
||||
/* We support 4 wires between universe + PIC */
|
||||
|
||||
@@ -1350,6 +1461,17 @@ unsigned long linten;
|
||||
} 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 */
|
||||
@@ -1412,21 +1534,63 @@ rtems_irq_connect_data aarrggh;
|
||||
}
|
||||
}
|
||||
|
||||
#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 shared, int uni_pin0, int pic_pin0, ...)
|
||||
vmeUniverseInstallIrqMgrAlt(int flags, int uni_pin0, int pic_pin0, ...)
|
||||
{
|
||||
int rval;
|
||||
va_list ap;
|
||||
va_start(ap, pic_pin0);
|
||||
rval = vmeUniverseInstallIrqMgrVa(shared, uni_pin0, pic_pin0, ap);
|
||||
rval = vmeUniverseInstallIrqMgrVa(flags, uni_pin0, pic_pin0, ap);
|
||||
va_end(ap);
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
vmeUniverseInstallIrqMgrVa(int shared, int uni_pin0, int pic_pin0, va_list ap)
|
||||
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;
|
||||
|
||||
@@ -1462,6 +1626,69 @@ int i,j, specialPin, uni_pin[UNIV_NUM_WIRES+1], pic_pin[UNIV_NUM_WIRES];
|
||||
}
|
||||
}
|
||||
|
||||
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",
|
||||
@@ -1472,7 +1699,7 @@ int i,j, specialPin, uni_pin[UNIV_NUM_WIRES+1], pic_pin[UNIV_NUM_WIRES];
|
||||
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(shared, universeVMEISR, pic_pin[i], i);
|
||||
connectIsr((flags & VMEUNIVERSE_IRQ_MGR_FLAG_SHARED), universeVMEISR, pic_pin[i], i);
|
||||
}
|
||||
|
||||
specialPin = uni_pin[1] >= 0 ? 1 : 0;
|
||||
|
||||
@@ -14,83 +14,19 @@
|
||||
#include <vme.h>
|
||||
#else
|
||||
|
||||
/* vxworks compatible addressing modes */
|
||||
|
||||
#ifndef VME_AM_STD_SUP_ASCENDING
|
||||
#define VME_AM_STD_SUP_ASCENDING 0x3f
|
||||
#endif
|
||||
#ifndef VME_AM_STD_SUP_PGM
|
||||
#define VME_AM_STD_SUP_PGM 0x3e
|
||||
#endif
|
||||
#ifndef VME_AM_STD_USR_ASCENDING
|
||||
#define VME_AM_STD_USR_ASCENDING 0x3b
|
||||
#endif
|
||||
#ifndef VME_AM_STD_USR_PGM
|
||||
#define VME_AM_STD_USR_PGM 0x3a
|
||||
#endif
|
||||
#ifndef VME_AM_STD_SUP_DATA
|
||||
#define VME_AM_STD_SUP_DATA 0x3d
|
||||
#endif
|
||||
#ifndef VME_AM_STD_USR_DATA
|
||||
#define VME_AM_STD_USR_DATA 0x39
|
||||
#endif
|
||||
#ifndef VME_AM_EXT_SUP_ASCENDING
|
||||
#define VME_AM_EXT_SUP_ASCENDING 0x0f
|
||||
#endif
|
||||
#ifndef VME_AM_EXT_SUP_PGM
|
||||
#define VME_AM_EXT_SUP_PGM 0x0e
|
||||
#endif
|
||||
#ifndef VME_AM_EXT_USR_ASCENDING
|
||||
#define VME_AM_EXT_USR_ASCENDING 0x0b
|
||||
#endif
|
||||
#ifndef VME_AM_EXT_USR_PGM
|
||||
#define VME_AM_EXT_USR_PGM 0x0a
|
||||
#endif
|
||||
#ifndef VME_AM_EXT_SUP_DATA
|
||||
#define VME_AM_EXT_SUP_DATA 0x0d
|
||||
#endif
|
||||
#ifndef VME_AM_EXT_USR_DATA
|
||||
#define VME_AM_EXT_USR_DATA 0x09
|
||||
#endif
|
||||
#ifndef VME_AM_CSR
|
||||
#define VME_AM_CSR 0x2f
|
||||
#endif
|
||||
#ifndef VME_AM_SUP_SHORT_IO
|
||||
#define VME_AM_SUP_SHORT_IO 0x2d
|
||||
#endif
|
||||
#ifndef VME_AM_USR_SHORT_IO
|
||||
#define VME_AM_USR_SHORT_IO 0x29
|
||||
#endif
|
||||
#ifndef VME_AM_IS_SHORT
|
||||
#define VME_AM_IS_SHORT(a) (((a) & 0xf0) == 0x20)
|
||||
#endif
|
||||
#ifndef VME_AM_IS_STD
|
||||
#define VME_AM_IS_STD(a) (((a) & 0xf0) == 0x30)
|
||||
#endif
|
||||
#ifndef VME_AM_IS_EXT
|
||||
#define VME_AM_IS_EXT(a) (((a) & 0xf0) == 0x00)
|
||||
#endif
|
||||
#ifndef VME_AM_IS_SUP
|
||||
#define VME_AM_IS_SUP(a) ((a) & 4)
|
||||
#endif
|
||||
#ifndef VME_AM_MASK
|
||||
#define VME_AM_MASK 0xff
|
||||
#endif
|
||||
|
||||
/* Enables posted writes (and on a VME slave: prefetched reads, too) */
|
||||
#ifndef VME_AM_IS_MEMORY
|
||||
#define VME_AM_IS_MEMORY (1<<8)
|
||||
#endif
|
||||
#include <bsp/vme_am_defs.h>
|
||||
|
||||
#endif
|
||||
|
||||
/* These bits can be or'ed with the address-modifier when calling
|
||||
* the 'XlateAddr' routine below to further qualify the
|
||||
* search criteria.
|
||||
*/
|
||||
#define VME_MODE_MATCH_MASK (3<<30)
|
||||
#define VME_MODE_EXACT_MATCH (2<<30) /* all bits must match */
|
||||
#define VME_MODE_AS_MATCH (1<<30) /* only A16/24/32 must match */
|
||||
|
||||
|
||||
/* When looking for an address translation, ask for a match of VME_MODE_PWEN etc., too */
|
||||
#define VME_MODE_EXACT_MATCH (1<<31)
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
typedef unsigned long LERegister; /* emphasize contents are little endian */
|
||||
|
||||
/* NOTE: DMA packet descriptors MUST be 32 byte aligned */
|
||||
@@ -450,8 +386,9 @@ typedef struct VmeUniverseDMAPacketRec_ {
|
||||
# define UNIV_VRAI_CTL_SUPER (1<<21) /* supervisor AM */
|
||||
# define UNIV_VRAI_CTL_USER (1<<20) /* user AM */
|
||||
# define UNIV_VRAI_CTL_VAS_A16 (0<<16) /* A16 */
|
||||
# define UNIV_VRAI_CTL_VAS_A24 (1<<16) /* A16 */
|
||||
# define UNIV_VRAI_CTL_VAS_A32 (2<<16) /* A16 */
|
||||
# define UNIV_VRAI_CTL_VAS_A24 (1<<16) /* A14 */
|
||||
# define UNIV_VRAI_CTL_VAS_A32 (2<<16) /* A32 */
|
||||
# define UNIV_VRAI_CTL_VAS_MSK (3<<16)
|
||||
|
||||
/* VMEbus register acces image base address register */
|
||||
#define UNIV_REGOFF_VRAI_BS 0xf74
|
||||
@@ -490,7 +427,10 @@ typedef struct VmeUniverseDMAPacketRec_ {
|
||||
|
||||
/* VMEbus CSR base address register */
|
||||
#define UNIV_REGOFF_VCSR_BS 0xffc
|
||||
#define UNIV_VCSR_BS_MASK (0xfff80000)
|
||||
#define UNIV_VCSR_BS_MASK (0xf8000000)
|
||||
|
||||
/* offset of universe registers in VME-CSR slot */
|
||||
#define UNIV_CSR_OFFSET 0x7f000
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -760,7 +700,36 @@ vmeUniverseIntRaiseXX(volatile LERegister *base, int level, unsigned vector);
|
||||
int
|
||||
vmeUniverseIntRaise(int level, unsigned vector);
|
||||
|
||||
/* Map internal register block to VME.
|
||||
*
|
||||
* This routine is intended for BSP implementors. The registers can be
|
||||
* made accessible from VME so that the interrupt handler can flush the
|
||||
* bridge FIFO (see below). The preferred method is by accessing VME CSR,
|
||||
* though, if these are mapped [and the BSP provides an outbound window].
|
||||
* On the universe we can also disable posted writes in the 'ordinary'
|
||||
* outbound windows.
|
||||
*
|
||||
* vme_base: VME address where the universe registers (4k) can be mapped.
|
||||
* This VME address must fall into a range covered by
|
||||
* any pre-configured outbound window.
|
||||
* address_space: The desired VME address space.
|
||||
* (all of SUP/USR/PGM/DATA are always accepted).
|
||||
*
|
||||
* See NOTES [vmeUniverseInstallIrqMgrAlt()] below for further information.
|
||||
*
|
||||
* RETURNS: 0 on success, nonzero on error. It is not possible (and results
|
||||
* in a non-zero return code) to change the CRG VME address after
|
||||
* initializing the interrupt manager as it uses the CRG.
|
||||
*/
|
||||
int
|
||||
vmeUniverseMapCRGXX(volatile LERegister *base, unsigned long vme_base, unsigned long address_space);
|
||||
|
||||
int
|
||||
vmeUniverseMapCRG(unsigned long vme_base, unsigned long address_space);
|
||||
|
||||
|
||||
#ifdef __rtems__
|
||||
|
||||
/* VME Interrupt Handler functionality */
|
||||
|
||||
/* we dont use the current RTEMS/BSP interrupt API for the
|
||||
@@ -783,6 +752,41 @@ vmeUniverseIntRaise(int level, unsigned vector);
|
||||
|
||||
typedef void (*VmeUniverseISR) (void *usrArg, unsigned long vector);
|
||||
|
||||
/* use these special vectors to connect a handler to the
|
||||
* universe specific interrupts (such as "DMA done",
|
||||
* VOWN, error irqs etc.)
|
||||
* NOTE: The wrapper clears all status LINT bits (except
|
||||
* for regular VME irqs). Also note that it is the user's
|
||||
* responsibility to enable the necessary interrupts in
|
||||
* LINT_EN
|
||||
*
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* DO NOT CHANGE THE ORDER OF THESE VECTORS - THE DRIVER
|
||||
* DEPENDS ON IT
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
*
|
||||
*/
|
||||
#define UNIV_VOWN_INT_VEC 256
|
||||
#define UNIV_DMA_INT_VEC 257
|
||||
#define UNIV_LERR_INT_VEC 258
|
||||
#define UNIV_VERR_INT_VEC 259
|
||||
/* 260 is reserved */
|
||||
#define UNIV_VME_SW_IACK_INT_VEC 261
|
||||
#define UNIV_PCI_SW_INT_VEC 262
|
||||
#define UNIV_SYSFAIL_INT_VEC 263
|
||||
#define UNIV_ACFAIL_INT_VEC 264
|
||||
#define UNIV_MBOX0_INT_VEC 265
|
||||
#define UNIV_MBOX1_INT_VEC 266
|
||||
#define UNIV_MBOX2_INT_VEC 267
|
||||
#define UNIV_MBOX3_INT_VEC 268
|
||||
#define UNIV_LM0_INT_VEC 269
|
||||
#define UNIV_LM1_INT_VEC 270
|
||||
#define UNIV_LM2_INT_VEC 271
|
||||
#define UNIV_LM3_INT_VEC 272
|
||||
|
||||
#define UNIV_NUM_INT_VECS 273
|
||||
|
||||
|
||||
/* install a handler for a VME vector
|
||||
* RETURNS 0 on success, nonzero on failure.
|
||||
*/
|
||||
@@ -864,39 +868,34 @@ vmeUniverseIntIsEnabled(unsigned int level);
|
||||
int
|
||||
vmeUniverseIntRoute(unsigned int level, unsigned int pin);
|
||||
|
||||
/* use these special vectors to connect a handler to the
|
||||
* universe specific interrupts (such as "DMA done",
|
||||
* VOWN, error irqs etc.)
|
||||
* NOTE: The wrapper clears all status LINT bits (except
|
||||
* for regular VME irqs). Also note that it is the user's
|
||||
* responsibility to enable the necessary interrupts in
|
||||
* LINT_EN
|
||||
/* Loopback test of the VME interrupt subsystem.
|
||||
* - installs ISRs on 'vector' and on UNIV_VME_SW_IACK_INT_VEC
|
||||
* - asserts VME interrupt 'level'
|
||||
* - waits for both interrupts: 'ordinary' VME interrupt of 'level' and
|
||||
* IACK completion interrupt ('special' vector UNIV_VME_SW_IACK_INT_VEC).
|
||||
*
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* DO NOT CHANGE THE ORDER OF THESE VECTORS - THE DRIVER
|
||||
* DEPENDS ON IT
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* NOTES:
|
||||
* - make sure no other handler responds to 'level'.
|
||||
* - make sure no ISR is installed on both vectors yet.
|
||||
* - ISRs installed by this routine are removed after completion.
|
||||
* - no concurrent access protection of all involved resources
|
||||
* (levels, vectors and registers [see vmeUniverseIntRaise()])
|
||||
* is implemented.
|
||||
* - this routine is intended for TESTING (when implementing new BSPs etc.).
|
||||
* - one RTEMS message queue is temporarily used (created/deleted).
|
||||
* - the universe 1 always yields a zero vector (VIRQx_STATID) in response
|
||||
* to a self-generated VME interrupt. As a workaround, the routine
|
||||
* only accepts a zero vector when running on a universe 1.
|
||||
*
|
||||
* RETURNS:
|
||||
* 0: Success.
|
||||
* -1: Invalid arguments.
|
||||
* 1: Test failed (outstanding interrupts).
|
||||
* rtems_status_code: Failed RTEMS directive.
|
||||
*/
|
||||
#define UNIV_VOWN_INT_VEC 256
|
||||
#define UNIV_DMA_INT_VEC 257
|
||||
#define UNIV_LERR_INT_VEC 258
|
||||
#define UNIV_VERR_INT_VEC 259
|
||||
/* 260 is reserved */
|
||||
#define UNIV_VME_SW_IACK_INT_VEC 261
|
||||
#define UNIV_PCI_SW_INT_VEC 262
|
||||
#define UNIV_SYSFAIL_INT_VEC 263
|
||||
#define UNIV_ACFAIL_INT_VEC 264
|
||||
#define UNIV_MBOX0_INT_VEC 265
|
||||
#define UNIV_MBOX1_INT_VEC 266
|
||||
#define UNIV_MBOX2_INT_VEC 267
|
||||
#define UNIV_MBOX3_INT_VEC 268
|
||||
#define UNIV_LM0_INT_VEC 269
|
||||
#define UNIV_LM1_INT_VEC 270
|
||||
#define UNIV_LM2_INT_VEC 271
|
||||
#define UNIV_LM3_INT_VEC 272
|
||||
int
|
||||
vmeUniverseIntLoopbackTst(int level, unsigned vector);
|
||||
|
||||
#define UNIV_NUM_INT_VECS 273
|
||||
|
||||
/* the universe interrupt handler is capable of routing all sorts of
|
||||
* (VME) interrupts to 8 different lines (some of) which may be hooked up
|
||||
@@ -939,12 +938,18 @@ vmeUniverseIntRoute(unsigned int level, unsigned int pin);
|
||||
* RETURNS: 0 on success, -1 on failure.
|
||||
*
|
||||
*/
|
||||
|
||||
/* This routine is outside of the __INSIDE_RTEMS_BSP__ test for bwrds compatibility ONLY */
|
||||
int
|
||||
vmeUniverseInstallIrqMgr(int vmeIrqUnivOut,
|
||||
int vmeIrqPicLine,
|
||||
int specialIrqUnivOut,
|
||||
int specialIrqPicLine);
|
||||
|
||||
|
||||
#if defined(__INSIDE_RTEMS_BSP__)
|
||||
#include <stdarg.h>
|
||||
|
||||
/* up to 4 universe outputs are now supported by this alternate
|
||||
* entry point.
|
||||
* Terminate the vararg list (uni_pin/pic_pin pairs) with a
|
||||
@@ -952,46 +957,40 @@ vmeUniverseInstallIrqMgr(int vmeIrqUnivOut,
|
||||
* E.g., the old interface is now just a wrapper to
|
||||
* vmeUniverseInstallIrqMgrAlt(0, vmeUnivOut, vmePicLint, specUnivOut, specPicLine, -1);
|
||||
*
|
||||
* The 'shared' argument uses the BSP_install_rtems_shared_irq_handler()
|
||||
* The 'IRQ_MGR_SHARED' flag uses the BSP_install_rtems_shared_irq_handler()
|
||||
* API. CAVEAT: shared interrupts need RTEMS workspace, i.e., the
|
||||
* VME interrupt manager can only be installed *after workspace is initialized*
|
||||
* if 'shared' is nonzero (i.e., *not* from bspstart()).
|
||||
*/
|
||||
int
|
||||
vmeUniverseInstallIrqMgrAlt(int shared, int uni_pin0, int pic_pin0, ...);
|
||||
|
||||
int
|
||||
vmeUniverseInstallIrqMgrVa(int shared, int uni_pin0, int pic_pin0, va_list ap);
|
||||
|
||||
/* Loopback test of the VME interrupt subsystem.
|
||||
* - installs ISRs on 'vector' and on UNIV_VME_SW_IACK_INT_VEC
|
||||
* - asserts VME interrupt 'level'
|
||||
* - waits for both interrupts: 'ordinary' VME interrupt of 'level' and
|
||||
* IACK completion interrupt ('special' vector UNIV_VME_SW_IACK_INT_VEC).
|
||||
*
|
||||
* NOTES:
|
||||
* - make sure no other handler responds to 'level'.
|
||||
* - make sure no ISR is installed on both vectors yet.
|
||||
* - ISRs installed by this routine are removed after completion.
|
||||
* - no concurrent access protection of all involved resources
|
||||
* (levels, vectors and registers [see vmeUniverseIntRaise()])
|
||||
* is implemented.
|
||||
* - this routine is intended for TESTING (when implementing new BSPs etc.).
|
||||
* - one RTEMS message queue is temporarily used (created/deleted).
|
||||
* - the universe 1 always yields a zero vector (VIRQx_STATID) in response
|
||||
* to a self-generated VME interrupt. As a workaround, the routine
|
||||
* only accepts a zero vector when running on a universe 1.
|
||||
* If 'PW_WORKAROUND' flag is set then the interrupt manager will try to
|
||||
* find a way to access the control registers from VME so that the universe's
|
||||
* posted write FIFO can be flushed after the user ISR returns:
|
||||
*
|
||||
* RETURNS:
|
||||
* 0: Success.
|
||||
* -1: Invalid arguments.
|
||||
* 1: Test failed (outstanding interrupts).
|
||||
* rtems_status_code: Failed RTEMS directive.
|
||||
* The installation routine looks first for CSR registers in CSR space (this
|
||||
* requires:
|
||||
* - a VME64 crate with autoid or geographical addressing
|
||||
* - the firmware or BSP to figure out the slot number and program the CSR base
|
||||
* in the universe.
|
||||
* - the BSP to open an outbound window to CSR space.
|
||||
*
|
||||
* If CSR registers cannot be found then the installation routine looks for CRG registers:
|
||||
* - BSP must map CRG on VME
|
||||
* - CRG must be visible in outbound window
|
||||
* CAVEAT: multiple boards with same BSP on single backplane must not map their CRG
|
||||
* to the same address!
|
||||
*/
|
||||
int
|
||||
vmeUniverseIntLoopbackTst(int level, unsigned vector);
|
||||
|
||||
#endif
|
||||
#define VMEUNIVERSE_IRQ_MGR_FLAG_SHARED 1 /* use shared interrupts */
|
||||
#define VMEUNIVERSE_IRQ_MGR_FLAG_PW_WORKAROUND 2 /* use shared interrupts */
|
||||
|
||||
int
|
||||
vmeUniverseInstallIrqMgrAlt(int flags, int uni_pin0, int pic_pin0, ...);
|
||||
|
||||
int
|
||||
vmeUniverseInstallIrqMgrVa(int flags, int uni_pin0, int pic_pin0, va_list ap);
|
||||
|
||||
#endif /* __INSIDE_RTEMS_BSP__ */
|
||||
#endif /* __rtems__ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
/* vxworks compatible addressing modes */
|
||||
|
||||
/* NOTE: 64-bit *addresses* are not supported [data are]. */
|
||||
|
||||
#ifndef VME_AM_STD_SUP_BLT
|
||||
#define VME_AM_STD_SUP_BLT 0x3f
|
||||
#endif
|
||||
@@ -63,6 +65,12 @@
|
||||
#ifndef VME_AM_EXT_USR_MBLT
|
||||
#define VME_AM_EXT_USR_MBLT 0x08
|
||||
#endif
|
||||
#ifndef VME_AM_2eVME_6U
|
||||
#define VME_AM_2eVME_6U 0x20
|
||||
#endif
|
||||
#ifndef VME_AM_2eVME_3U
|
||||
#define VME_AM_2eVME_3U 0x21
|
||||
#endif
|
||||
#ifndef VME_AM_CSR
|
||||
#define VME_AM_CSR 0x2f
|
||||
#endif
|
||||
@@ -99,8 +107,30 @@
|
||||
#define VME_AM_IS_MEMORY (1<<8)
|
||||
#endif
|
||||
|
||||
/* Flags 1<<11 .. 1<<8 are reserved
|
||||
* Flags 1<<12 .. 1<<31 are for driver specific options
|
||||
/* I don't know AMs for 2eSST so we use some extra bits;
|
||||
* HOWEVER: these are just qualifiers to the VME_AM_2eVME_xx modes
|
||||
* i.e., if you want 2eSST you must also select 2eVME...
|
||||
*/
|
||||
|
||||
/* 2eSST broadcast; you still need to set one of the speed bits */
|
||||
#define VME_AM_2eSST_BCST (1<<9)
|
||||
/* Low speed (driver specific) */
|
||||
#define VME_AM_2eSST_LO (1<<10)
|
||||
/* Mid speed (driver specific) */
|
||||
#define VME_AM_2eSST_MID (2<<10)
|
||||
/* High speed (driver specific) */
|
||||
#define VME_AM_2eSST_HI (3<<10)
|
||||
|
||||
#define VME_AM_IS_2eSST(am) ((am) & (3<<10))
|
||||
|
||||
/* Use 16-bit transfers for coupled- or BLT cycles
|
||||
* (MBLT, 2exxx are probably always 64-bit)
|
||||
*/
|
||||
#define VME_MODE_DBW16 (1<<12)
|
||||
|
||||
/* Unused Flags 1<<12 .. 1<<23 are reserved
|
||||
* Flags 1<<24 .. 1<<31 are for driver specific options
|
||||
*/
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user