www.pudn.com > MPC8241BSP.rar > sysLib.c


/* sysLib.c - Motorola PrPMC600 board series system-dependent library */ 
 
/* Copyright 1984-2000 Wind River Systems, Inc. */ 
/* Copyright 1996-2000 Motorola, Inc. All Rights Reserved */ 
 
/* 
modification history 
-------------------- 
01a,28feb00,rhk  created from version 01s, MV2100 BSP. 
*/ 
 
/* 
DESCRIPTION 
This library provides board-specific routines.  The chip drivers included are: 
 
    i8250Sio.c 		- Intel 8250 UART driver  
    ppcDecTimer.c 	- PowerPC decrementer timer library (system clock) 
    byteNvRam.c 	- byte-oriented generic non-volatile RAM library 
    pciConfigLib.c 	- PCI configuration library 
    dec2155xCpci.c      - Dec/Intel non-transparent PCI-to-PCI bridge library 
    mpc8240Epic.c 	- Mpc8240 Interrupt Controller 
    sysMotI2c.c 	- Mpc8240 I2C interface driver 
 
INCLUDE FILES: sysLib.h 
 
SEE ALSO: 
.pG "Configuration" 
*/ 
/* includes */ 
 
 
#include "vxWorks.h" 
#include "pci.h" 
#include "memLib.h" 
#include "cacheLib.h" 
#include "sysLib.h" 
#include "config.h" 
#include "string.h" 
#include "intLib.h" 
#include "esf.h" 
#include "excLib.h" 
#include "logLib.h" 
#include "taskLib.h" 
#include "vxLib.h" 
#include "tyLib.h" 
#include "arch/ppc/archPpc.h" 
#include "arch/ppc/mmu603Lib.h" 
#include "arch/ppc/vxPpcLib.h" 
#include "arch/ppc/excPpcLib.h" 
#include "private/vmLibP.h" 
#include "drv/pci/pciConfigLib.h" 
 
#if 0 
#   include "pci/pciAutoConfigLib.h" 
#else 
#   include "./pci/pciAutoConfigLib.h" 
#endif 
 
void sysMicroDelay(int iDelayUnit); 
 
   
extern void useI2O(void); 
/* defines */ 
extern int sysStartType; 
#define ZERO	0 
 
#define DEFAULT_TAS_CHECKS      10              /* rechecks for soft tas */ 
#define TAS_CONST               0x80 
int pci1200=0; 
char mac[6]={0x00,0x11,0x22,0x33,0x44,0x55}; 
IMPORT void * cookieArray[32]; 
/* structures */ 
 
typedef struct mailboxInfo 
    { 
    BOOL    connected; 
    FUNCPTR routine; 
    int     arg; 
    } MAILBOX_INFO; 
 
typedef struct mpc8240WinStruct 
    { 
    UINT32 winType;   /* mem or i/o */ 
    UINT32 winBase;   /* start of window */ 
    UINT32 winLimit;  /* end of window */ 
    } MPC8240_WIN_STRUCT; 
 
/* The following structure is used in the support of distributed shared 
 * memory interrupt sources. The structure is used to create a linked list 
 * which contains an entry for each PCI device capable of generating shared 
 * memory interrupts. When sysIntDisable is called with the shared memory 
 * interrupt vector, the list of shared memory devices is traversed and 
 * each device's intDisable routine is called to disable shared memory 
 * interrupts from that device. Interrupt enable requests are handled in a 
 * similar manner. The pInfo field is used to save a device-specific 
 * pointer which could be used to specify the hardware's base address or 
 * other similar information. 
 */ 
 
typedef struct sysSmIntDevListEntry 
    { 
    struct sysSmIntDevListEntry * next; 
    void * pInfo; 
    void (* intEnable) ( 
                       void * pInfo, 
                       UINT32 level 
                       ); 
    void (* intDisable) ( 
                        void * pInfo, 
                        UINT32 level 
                        ); 
    } SYS_SM_INT_DEV_LIST_ENTRY; 
 
/* globals */ 
 
/* 
 * sysBatDesc[] is used to initialize the block address translation (BAT) 
 * registers within the PowerPC 603/604 MMU.  BAT hits take precedence 
 * over Page Table Entry (PTE) hits and are faster.  Overlap of memory 
 * coverage by BATs and PTEs is permitted in cases where either the IBATs 
 * or the DBATs do not provide the necessary mapping (PTEs apply to both 
 * instruction AND data space, without distinction). 
 * 
 * The primary means of memory control for VxWorks is the MMU PTE support 
 * provided by vmLib and cacheLib.  Use of BAT registers will conflict 
 * with vmLib support.  User's may use BAT registers for i/o mapping and 
 * other purposes but are cautioned that conflicts with cacheing and mapping 
 * through vmLib may arise.  Be aware that memory spaces mapped through a BAT 
 * are not mapped by a PTE and any vmLib() or cacheLib() operations on such 
 * areas will not be effective, nor will they report any error conditions. 
 * 
 * Note: BAT registers CANNOT be disabled - they are always active. 
 * For example, setting them all to zero will yield four identical data 
 * and instruction memory spaces starting at local address zero, each 128KB 
 * in size, and each set as write-back and cache-enabled.  Hence, the BAT regs 
 * MUST be configured carefully. 
 * 
 * With this in mind, it is recommended that the BAT registers be used 
 * to map LARGE memory areas external to the processor if possible. 
 * If not possible, map sections of high RAM and/or PROM space where 
 * fine grained control of memory access is not needed.  This has the 
 * beneficial effects of reducing PTE table size (8 bytes per 4k page) 
 * and increasing the speed of access to the largest possible memory space. 
 * Use the PTE table only for memory which needs fine grained (4KB pages) 
 * control or which is too small to be mapped by the BAT regs. 
 * 
 * The BAT configuration for 4xx/6xx-based PPC boards is as follows: 
 * All BATs point to PROM/FLASH memory so that end customer may configure 
 * them as required. 
 * 
 * [Ref: chapter 7, PowerPC Microprocessor Family: The Programming Environments] 
 */ 
 
UINT32 sysBatDesc [2 * (_MMU_NUM_IBAT + _MMU_NUM_DBAT)] = 
    { 
    /* I BAT 0 */ 
 
    ((ROM_BASE_ADRS & _MMU_UBAT_BEPI_MASK) | (_MMU_UBAT_BL_1M & 
    ~(_MMU_UBAT_VS & _MMU_UBAT_VP))), 
    ((ROM_BASE_ADRS & _MMU_LBAT_BRPN_MASK) | _MMU_LBAT_PP_RW | 
    _MMU_LBAT_CACHE_INHIBIT), 
 
    /* I BAT 1 */ 
 
    0, 0, 
 
    /* I BAT 2 */ 
 
    0, 0, 
 
    /* I BAT 3 */ 
 
    0, 0, 
 
    /* D BAT 0 */ 
 
    0, 0, 
 
    /* D BAT 1 */ 
 
    0, 0, 
 
    /* D BAT 2 */ 
 
    0, 0, 
 
    /* D BAT 3 */ 
 
    0, 0 
    }; 
 
/* 
 * sysPhysMemDesc[] is used to initialize the Page Table Entry (PTE) array 
 * used by the MMU to translate addresses with single page (4k) granularity. 
 * PTE memory space should not, in general, overlap BAT memory space but 
 * may be allowed if only Data or Instruction access is mapped via BAT. 
 * 
 * Address translations for local RAM, memory mapped PCI bus 
 * and local PROM/FLASH are set here. 
 * 
 * PTEs are held, strangely enough, in a Page Table.  Page Table sizes are 
 * integer powers of two based on amount of memory to be mapped and a 
 * minimum size of 64 kbytes.  The MINIMUM recommended Page Table sizes 
 * for 32-bit PowerPCs are: 
 * 
 * Total mapped memory		Page Table size 
 * -------------------		--------------- 
 *        8 Meg			     64 K 
 *       16 Meg			    128 K 
 *       32 Meg			    256 K 
 *       64 Meg			    512 K 
 *      128 Meg			      1 Meg 
 * 	.				. 
 * 	.				. 
 * 	.				. 
 * 
 * [Ref: chapter 7, PowerPC Microprocessor Family: The Programming Environments] 
 * 
 */ 
 
PHYS_MEM_DESC sysPhysMemDesc [] = 
    { 
    { 
    /* Vector Table and Interrupt Stack */ 
 
    (void *) LOCAL_MEM_LOCAL_ADRS, 
    (void *) LOCAL_MEM_LOCAL_ADRS, 
    RAM_LOW_ADRS, 
    VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE | 
    VM_STATE_MASK_MEM_COHERENCY, 
    VM_STATE_VALID      | VM_STATE_WRITABLE      | VM_STATE_CACHEABLE | 
    VM_STATE_MEM_COHERENCY 
    }, 
 
    { 
    /* Local DRAM */ 
 
    (void *) RAM_LOW_ADRS, 
    (void *) RAM_LOW_ADRS, 
    LOCAL_MEM_SIZE -  RAM_LOW_ADRS, 
    VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE | 
    VM_STATE_MASK_MEM_COHERENCY, 
    VM_STATE_VALID      | VM_STATE_WRITABLE      | VM_STATE_CACHEABLE | 
    VM_STATE_MEM_COHERENCY 
    }, 
 
    /* Access to PCI ISA I/O space */ 
 
    { 
    (void *) ISA_MSTR_IO_LOCAL, 
    (void *) ISA_MSTR_IO_LOCAL, 
    ISA_MSTR_IO_SIZE, 
    VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE, 
    VM_STATE_VALID      | VM_STATE_WRITABLE      | VM_STATE_CACHEABLE_NOT 
    }, 
 
    /* Access to PCI I/O space */ 
 
    { 
    (void *) PCI_MSTR_IO_LOCAL, 
    (void *) PCI_MSTR_IO_LOCAL, 
    PCI_MSTR_IO_SIZE, 
    VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE, 
    VM_STATE_VALID      | VM_STATE_WRITABLE      | VM_STATE_CACHEABLE_NOT 
    }, 
 
#ifdef ISA_MEM_SPACE 
 
    /* Access to PCI ISA memory space */ 
 
    { 
    (void *) ISA_MSTR_MEM_LOCAL, 
    (void *) ISA_MSTR_MEM_LOCAL, 
    ISA_MSTR_MEM_SIZE, 
    VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE, 
    VM_STATE_VALID      | VM_STATE_WRITABLE      | VM_STATE_CACHEABLE_NOT 
    }, 
 
#endif 
 
    /* Access to PCI non-prefetchable memory space */ 
 
    { 
    (void *) PCI_MSTR_MEMIO_LOCAL, 
    (void *) PCI_MSTR_MEMIO_LOCAL, 
    PCI_MSTR_MEMIO_SIZE, 
    VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE, 
    VM_STATE_VALID      | VM_STATE_WRITABLE      | VM_STATE_CACHEABLE_NOT 
    }, 
 
    /* Access to PCI memory space */ 
 
    { 
    (void *) PCI_MSTR_MEM_LOCAL, 
    (void *) PCI_MSTR_MEM_LOCAL, 
    PCI_MSTR_MEM_SIZE, 
    VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE, 
    VM_STATE_VALID      | VM_STATE_WRITABLE      | VM_STATE_CACHEABLE_NOT 
    }, 
    /*{ 
    (void *) 0x88000000, 
    (void *) 0x88000000, 
    (0x8000000), 
    VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE, 
    VM_STATE_VALID      | VM_STATE_WRITABLE      | VM_STATE_CACHEABLE_NOT 
    },*/ 
  /* Access to GALNET space */ 
#ifdef INCLUDE_DEVGALNET 
    { 
    (void *) GALNETPCIMEM, 
    (void *) GALNETPCIMEM, 
    GALNETMEMSIZE, 
    VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE, 
    VM_STATE_VALID      | VM_STATE_WRITABLE      | VM_STATE_CACHEABLE_NOT 
    }, 
#endif 
#ifdef INCLUDE_PCI9030 
	{ 
	(void *) PCI9030EXTFLASHMEM, 
	(void *) PCI9030EXTFLASHMEM, 
	PCI9030EXTFLASHSIZE, 
    VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE, 
    VM_STATE_VALID      | VM_STATE_WRITABLE      | VM_STATE_CACHEABLE_NOT 
    }, 
#endif	 
    { 
    /* Mpc8240 registers */ 
    (void *) MPC8240_EUMB_BASE, 
    (void *) MPC8240_EUMB_BASE, 
    MPC8240_EUMB_SIZE, 
    VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE, 
    VM_STATE_VALID      | VM_STATE_WRITABLE      | VM_STATE_CACHEABLE_NOT 
    }, 
 /*	{*/ 
    /* Mpc8240 registers */ 
/*    (void *) MPC8240_PCSR_BASE, 
    (void *) MPC8240_PCSR_BASE, 
    4*1024, 
    VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE, 
    VM_STATE_VALID      | VM_STATE_WRITABLE      | VM_STATE_CACHEABLE_NOT 
    },*/ 
    { 
    /* PCI interrupt acknowledge */ 
 
    (void *) PCI_MSTR_IACK_WNDW_ADRS, 
    (void *) PCI_MSTR_IACK_WNDW_ADRS, 
    PCI_MSTR_IACK_SIZE, 
    VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE, 
    VM_STATE_VALID      | VM_STATE_WRITABLE      | VM_STATE_CACHEABLE_NOT 
    }, 
 
#ifdef CHRP_ADRS_MAP 
    { 
 
    /* PCI Configuration Address Register */ 
 
    (void *) PCI_MSTR_PRIMARY_CAR, 
    (void *) PCI_MSTR_PRIMARY_CAR, 
    PCI_MSTR_PRIMARY_CAR_SIZE, 
    VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE, 
    VM_STATE_VALID      | VM_STATE_WRITABLE      | VM_STATE_CACHEABLE_NOT 
    }, 
 
    { 
 
    /* PCI Configuration Data Register */ 
 
    (void *) PCI_MSTR_PRIMARY_CDR, 
    (void *) PCI_MSTR_PRIMARY_CDR, 
    PCI_MSTR_PRIMARY_CDR_SIZE, 
    VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE, 
    VM_STATE_VALID      | VM_STATE_WRITABLE      | VM_STATE_CACHEABLE_NOT 
    }, 
#endif 
 
#ifndef CHRP_ADRS_MAP /* if PReP address map */ 
    { 
 
    /* map in direct access of PCI configuration space */ 
 
    (void *) PCI_MSTR_DIRECT_MAP_ADRS, 
    (void *) PCI_MSTR_DIRECT_MAP_ADRS, 
    PCI_MSTR_DIRECT_SIZE, 
    VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE, 
    VM_STATE_VALID      | VM_STATE_WRITABLE      | VM_STATE_CACHEABLE_NOT 
    }, 
#endif 
 
    { 
    (void *) FLASH_BASE_ADRS, 
    (void *) FLASH_BASE_ADRS, 
    FLASH_MEM_SIZE, 
    VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE, 
    VM_STATE_VALID      | VM_STATE_WRITABLE      | VM_STATE_CACHEABLE_NOT 
    }, 
    { 
    (void *) ROM_BASE_ADRS, 
    (void *) ROM_BASE_ADRS, 
    ROM_SIZE, 
    VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE, 
    VM_STATE_VALID      | VM_STATE_WRITABLE      | VM_STATE_CACHEABLE_NOT 
    }, 
    { 
    (void *) 0xff000000, 
    (void *) 0xff000000, 
    0x1000, 
    VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE | VM_STATE_MASK_CACHEABLE, 
    VM_STATE_VALID      | VM_STATE_WRITABLE      | VM_STATE_CACHEABLE_NOT 
    } 
 
    }; 
 
UINT wbVectorIRQ0=WBPIC_INTERRUPT_BASE; /*added by xdg*/ 
 
int sysPhysMemDescNumEnt = NELEMENTS (sysPhysMemDesc); 
 
int    sysBus      = BUS_TYPE_PCI;	/* system bus type */ 
int    sysCpu      = CPU;		/* system CPU type (MC680x0) */ 
char * sysBootLine = BOOT_LINE_ADRS;	/* address of boot line */ 
char * sysExcMsg   = EXC_MSG_ADRS;	/* catastrophic message area */ 
int    sysProcNum;			/* processor number of this CPU */ 
int    sysFlags;			/* boot flags */ 
char   sysBootHost [BOOT_FIELD_LEN];	/* name of host from which we booted */ 
char   sysBootFile [BOOT_FIELD_LEN];	/* name of file from which we booted */ 
UINT   sysVectorIRQ0  = INT_VEC_IRQ0;	/* vector for IRQ0 */ 
 
int    smIntArg1 = -1;                  /* Shared memory SM_INT_ARG1 */ 
int    smIntArg2 = -1;                  /* Shared memory SM_INT_ARG2 */ 
 
MPC8240_WIN_STRUCT sysMpc8240CpuToPciWin[MPC8240_WIN_CNT-1] = { { 0 } }; 
MPC8240_WIN_STRUCT sysMpc8240PciToCpuWin[MPC8240_WIN_CNT-1] = { { 0 } }; 
 
#ifdef INCLUDE_SM_NET 
    MAILBOX_INFO sysMailbox = {FALSE, NULL, 0}; 
    SYS_SM_INT_DEV_LIST_ENTRY * pSmIntListHead = 0; 
#endif 
 
#if defined(SYS_SM_ANCHOR_POLL_LIST) && defined(INCLUDE_DEC2155X) 
 
LOCAL SYS_SM_ANCHOR_POLLING_LIST sysSmAnchorPollList[] = 
    { 
    SYS_SM_ANCHOR_POLL_LIST 
    { 0xffffffff, 0xffffffff }  /* Required entry: marks end of list */ 
    }; 
#endif 
 
LOCAL int       sysSmUtilTasValue = 0;          /* special soft tas value */ 
 
/* last 5 nibbles are board specific, initialized in sysHwInit */ 
 
unsigned char lnEnetAddr [6] = { 0x08, 0x00, 0x3e, 0x00, 0x00, 0x00 }; 
unsigned char clearWd [1]  = { 0x00 }; 
 
/* locals */ 
 
LOCAL char sysModelStr[80]; 
LOCAL char wrongCpuMsg[] = WRONG_CPU_MSG;  
 
/* forward declarations */ 
 
void	sysSpuriousIntHandler(void); 
void	sysCpuCheck (void); 
char *  sysPhysMemTop (void); 
 
void	sysBusTasClear (volatile char *); 
STATUS  sysBusProbe (char *, int, int, char *); 
IMPORT UINT sysHid1Get(void); 
void sysFpSet(ULONG tmp); 
void	sysDebugMsg(char * str, UINT32  recovery); 
 
UINT 	sysGetBusSpd(void);     	/* system bus speed (in megahertz) */ 
UINT	sysGetBusSpdHertz(void);	/* system bus speed (in hertz) */ 
UINT	sysGetMpuSpd(void);     	/* processor speed (in megahertz) */ 
UINT	sysGetMpuSpdHertz(void);	/* processor speed (in hertz) */ 
UINT	sysGetPciSpd(void);     	/* pci bus speed (in megahertz) */ 
UINT	sysGetPciSpdHertz(void);	/* pci bus speed (in hertz) */ 
 
void    led12(unsigned short ); 
void    led11(unsigned short ); 
void flashled(unsigned short ,unsigned short ); 
void    sysPciInsertLong (UINT32, UINT32, UINT32); 
void    sysPciInsertWord (UINT32, UINT16, UINT16); 
void    sysPciInsertByte (UINT32, UINT8, UINT8); 
void    sysPciOutLongConfirm (UINT32, UINT32); 
void    sysPciOutWordConfirm (UINT32, UINT16); 
void    sysPciOutByteConfirm (UINT32, UINT8); 
 
void	sysDelay (void); 
 
/* add by zoutl for test 2003-3-28 9:42 */ 
void testConfigReg(void); 
void AddMyexcHandler( void ); 
/* add by zoutl for test 2003-3-28 9:42 */ 
 
#ifdef INCLUDE_PCI9030 
void pci9030Init(void); 
#endif 
 
#ifdef INCLUDE_SM_NET 
    LOCAL STATUS sysPciConfig21554InLong (int, int, int, int, UINT32 *); 
    LOCAL int sysPciConfigPack21554 ( int, int, int, int); 
 
    LOCAL void  sysSmParamsCompute (void); 
    int sysSmArg2Compute (void); 
 
 
#   if (SM_OFF_BOARD == TRUE) 
#       ifdef SYS_SM_ANCHOR_POLL_LIST 
            LOCAL UINT   sysSmAnchorCandidate ( UINT, UINT, UINT); 
#       endif 
        LOCAL STATUS sysSmAnchorFind ( int, char **); 
        LOCAL char   *sysSmAnchorPoll (void); 
        char *  sysSmAnchorAdrs ();     /* Anchor address (dynamic) */ 
#   endif 
#endif /* INCLUDE_SM_NET */ 
 
/* externals */ 
 
IMPORT UCHAR  sysInByte (ULONG); 
IMPORT void   sysOutByte (ULONG, UCHAR); 
IMPORT USHORT sysInWord (ULONG); 
IMPORT void   sysOutWord (ULONG, USHORT); 
IMPORT ULONG  sysInLong (ULONG); 
IMPORT void   sysOutLong (ULONG, ULONG); 
IMPORT UINT32 sysPciInLong (UINT32); 
IMPORT void   sysPciOutLong (UINT32, UINT32); 
IMPORT UINT8 sysPciConfigInByte (UINT8 * dataPtr); 
IMPORT UINT32 sysPciConfigInLong (UINT32 *); 
IMPORT void   sysPciConfigOutLong (UINT32 *, UINT32); 
IMPORT UINT16 sysPciConfigInWord (UINT16 *); 
IMPORT void   sysPciConfigOutWord (UINT16 *, UINT16); 
IMPORT void   sysClkIntCIO (void); 
IMPORT STATUS sysMemProbeSup (int length, char * src, char * dest); 
IMPORT int    sysProbeExc(); 
IMPORT VOIDFUNCPTR      smUtilTasClearRtn; 
IMPORT void   sysBusRmwEnable(UINT, UINT, UINT, char *); 
IMPORT void   sysBusRmwDisable(void); 
IMPORT UINT32 sysTimeBaseLGet (void); 
IMPORT UCHAR  sysProductStr[]; 
 
IMPORT UINT32 sysInLongRev ( UINT32); 
IMPORT void sysOutLongRev (UINT32, UINT32); 
IMPORT UINT16 sysInWordRev (UINT32); 
IMPORT void sysOutWordRev (UINT32, UINT16); 
 
 
/* BSP DRIVERS */ 
 
#include "pci/pciConfigLib.c" 
#include "sysSerial.c" 
#include "mem/nullNvRam.c" 
#include "timer/ppcDecTimer.c"		/* PPC603 has on chip timers */ 
 
/* add by zoutl for NVRam & double boot 2003-4-21 19:01 */ 
/* delete by wanggeng 20050729 
#include "../../Modules/DoubleBoot/xpbConI2c.c" 
#include "../../Modules/DoubleBoot/xpbConEeprom.c" 
#include "../../Modules/DoubleBoot/BootRomDrv.c" 
*/ 
 
#ifdef INCLUDE_NETWORK 
#   include "sysNet.c" 
#   ifdef INCLUDE_END 
#   ifdef INCLUDE_RTL_81X9_END 
#        include "sysRtl81x9End.c" 
#        include "rtl81x9.c" 
#   endif /* INCLUDE_RTL_81X9_END */ /*INCLUDE_RTL_81X9_END is added by mashuyu*/ 
 
#	ifdef INCLUDE_RTL_CP_END 
#		 include "rtlcpp.c" 
#		 include "sysRtlcpEnd.c" 
#		 include "rtl8139Config.c" 
#   endif 
#   endif /* INCLUDE_END */ 
#endif /* INCLUDE_NETWORK */ 
 
#ifdef INCLUDE_SHOW_ROUTINES 
#include "pci/pciConfigShow.c"          /* display of PCI config space */ 
#endif 
 
#ifdef INCLUDE_SCSI 
#   include "sysScsi.c"			/* sysScsiInit routine */ 
#endif /* INCLUDE_SCSI */ 
 
#ifdef INCLUDE_TFFS 
#   include "i28f640.c"	 
#	include "p755-sysTffs.c" 
#	include "trueFFS.c"		/* tffs routine */ 
#endif /* INCLUDE_TFFS */ 
 
#include "mpc8240Epic.c" 
 
#ifdef INCLUDE_AUXCLK 
#    include "mpc8240AuxClk.c" 
#endif 
 
/* add by zoutl for test BSP 2003-5-30 14:31 */ 
#ifdef BSP_TEST 
#    include "./test/mpc8240AuxClk1.c"	 
#    include "./test/NetTest.c" 
#endif 
 
#if 0 
#   include "pci/pciAutoConfigLib.c" 
#else 
#  include "./pci/pciAutoConfigLib.c" 
#endif 
 
#  include "./sysBusPci.c" 
 
#include "i2o.c" 
#include "i2c.c" 
#include "flash.c" 
#include "pciAddrAlloc.c" 
/* delete by wanggeng 20050729 
#include "BspCpusApi.c" 
*/ 
/*#include "rtc.c"*/ 
/*#include "dma.c"*/ 
/*#include "testfile.c"*/ 
 
 
/* defines for sysBusTas() and sysBusTasClear() */ 
 
#define CPU_CLOCKS_PER_LOOP	10 
#define LOCK_TIMEOUT		10 
#define UNLOCK_TIMEOUT		10000 
 
 
/****************************************************************************** 
* 
* sysModel - return the model name of the CPU board 
* 
* This routine returns the model name of the CPU board.  The returned string 
* depends on the board model and CPU version being used, for example, 
* "Motorola MVME2600 - MPC 604e". 
* 
* RETURNS: A pointer to the string. 
*/ 
 
char * sysModel (void) 
    { 
    int    cpu; 
    char cpuStr[80]; 
 
    /* Determine CPU type and build display string */ 
 
    cpu = CPU_TYPE; 
    switch (cpu) 
        { 
	case CPU_TYPE_603EK: 
	    sprintf(cpuStr, "8240"); 
	    break; 
        default: 
            sprintf (cpuStr, "60%d", cpu); 
            break; 
        } 
 
    sprintf (sysModelStr, "ZTE CDMA LPB %s", cpuStr); 
 
    return (sysModelStr); 
    } 
 
/******************************************************************************* 
* 
* sysBspRev - return the BSP version and revision number 
* 
* This routine returns a pointer to a BSP version and revision number, for 
* example, 1.1/0. BSP_REV is concatenated to BSP_VERSION and returned. 
* 
* RETURNS: A pointer to the BSP version/revision string. 
*/ 
 
char * sysBspRev (void) 
    { 
    return (BSP_VERSION BSP_REV); 
    } 
 
/******************************************************************************* 
* sysDecDelay - decrementer delay 
* 
* This function's purpose is delay for the specified number 
* micro-seconds. 
* 
* RETURNS: none 
*/ 
void sysDecDelay 
    ( 
    UINT usDelay 
    ) 
    { 
    UINT  oneUsDelta; 
    UINT  valueCurrent, valuePrevious, valueDelta; 
 
 
    /* if no delay count, exit */ 
 
    if (!usDelay)  
        return; 
 
    /* 
     * calculate delta of decrementer ticks for 1ms of elapsed time, 
     * the bus clock (in megahertz) is used for 603/604 versions, the 
     * decrementer counts down once every four bus clocks for the 
     * 603/604 versions, and once every RTC tick for the 601, the RTC 
     * tick for 601 is the period of 1ns 
     */ 
 
    oneUsDelta = ((DEC_CLOCK_FREQ / 4) / 1000000); 
 
    /* 
     * snapshot current decrementer count, this count is used 
     * as the starting point 
     * 
     * check for rollover, the decrementer counts down from 
     * the maximum count (0xffffffff) to zero 
     * 
     * calculate delta of the decrementer counts and divide 
     * down by the one MS divider, exit if count has been 
     * met or exceeded 
     */ 
 
    for (valuePrevious = vxDecGet();;)  
        { 
        valueCurrent = vxDecGet(); 
        valueDelta = 0; 
        if (valueCurrent > valuePrevious)  
            { 
            valueDelta = (0xFFFFFFFF - valueCurrent) + valuePrevious; 
            }  
        else  
            { 
            if (valueCurrent < valuePrevious)  
                { 
                valueDelta = valuePrevious - valueCurrent; 
                } 
            } 
 
        if ((valueDelta / oneUsDelta) >= usDelay)  
            break; 
        } 
    } 
 
/****************************************************************************** 
* 
* sysHwInit - initialize the system hardware 
* 
* This routine initializes various features of the CPU board.  It is called 
* by usrInit() in usrConfig.c.  This routine sets up the control registers 
* and initializes various devices if they are present. 
* 
* NOTE: This routine should not be called directly by the user application.  It 
* cannot be used to initialize interrupt vectors. 
* 
* RETURNS: N/A 
*/ 
void sysHwInit (void) 
    {	 
     
    /*	Validate CPU type */ 
     
    sysCpuCheck(); 
     
   /*12.30 for 64bit opt*/ 
   #if(1) 
      
     sysFpSet(0); 
      
   #endif 
   	/* 写EUMB寄存器 Added by xdg*/ 
	/* 参数中前者是需要写到PCI配置地址寄存器的值,后者是需要写到PCI配置数据寄存器的值*/ 
    
   sysPciConfigOutLong ( (UINT32*)(CNFG_PCI_HOST_BRDG+MPC8240_CFG_EUMBBAR), \ 
						  (UINT32)MPC8240_EUMB_BASE ); 
	sysPciConfigOutLong ( (UINT32*)(CNFG_PCI_HOST_BRDG+0xD0), \ 
						  (UINT32)0x85080000 ); 
	sysPciConfigOutLong ( (UINT32*)(CNFG_PCI_HOST_BRDG+0xD8), \ 
						  (UINT32)0x0000000B ); 
    /* 
     * If mmu tables are used, this is where we would dynamically 
     * update the entry describing main memory, using sysPhysMemTop(). 
     * We must call sysPhysMemTop () at sysHwInit() time to do 
     * the memory autosizing if available. 
     */ 
	 
    sysPhysMemTop (); 
	 
	/* add by zoutl 2003-5-24 10:32 */ 
#ifdef BOOT_DEBUG_MSG 
	sysDebugMsg("sysPhysMemTop succeed!\n\r",0); 
#endif 
    /*  Initialize PCI driver library. */ 
 
    if (pciConfigLibInit (PCI_MECHANISM_1, PCI_MSTR_PRIMARY_CAR,  
	PCI_MSTR_PRIMARY_CDR, 0) != OK) 
        { 
        sysToMonitor (BOOT_NO_AUTOBOOT); 
        } 
 
    /* Auto-Configure the PCI busses/devices. */ 
 
    /* 
     * Test to determine if we need to configure the PCI busses with 
     * sysPciAutoConfig().  If we are coming up from a ROM-based image 
     * then we need to reconfigure.  If we have been booted from a ROM 
     * image then we don't need to reconfigure since the bootrom will 
     * already have reconfigured the PCI busses.  We must avoid 
     * configuring the PCI busses twice on startup. 
     */ 
 
    if ( !PCI_AUTOCONFIG_DONE ) 
    {pci1200=1; 
    	} 
    if(1) 
	{ 
	/* in ROM boot phase, OK to continue and configure PCI busses.*/ 
	 
	sysPciAutoConfig (); 
	PCI_AUTOCONFIG_FLAG++;	/* Remember that PCI is configured */ 
	 
	} 
	 
/* add by zoutl 2003-5-24 10:32 */ 
#ifdef BOOT_DEBUG_MSG 
	sysDebugMsg("sysPciAutoConfig succeed!\n\r",0); 
#endif 
	 
    /* Initialize the EPIC. */ 
	 
    sysEpicInit(); 
     
/* add by zoutl 2003-5-24 10:32 */ 
#ifdef BOOT_DEBUG_MSG 
	sysDebugMsg("sysEpicInit succeed!\n\r",0); 
#endif     
	 
    /* set pointer to bus probing hook */ 
 
    _func_vxMemProbeHook = (FUNCPTR)sysBusProbe; 
 
    /* Initialize COM1 and COM2 serial channels */ 
 
	/*pciConfigOutLong (0, 21, 0,  0x18, 0x88000000); */          
	  
	 sysSerialHwInit();	  
	  
	  
/* add by zoutl 2003-5-24 10:32 */ 
#ifdef BOOT_DEBUG_MSG 
	sysDebugMsg("sysSerialHwInit succeed!\n\r",0); 
#endif 	 	  
 
 
#ifdef INCLUDE_NETWORK 
 
    /* Initialize the network */ 
    sysNetHwInit(); 
     
/* add by zoutl 2003-5-24 10:32 */ 
#ifdef BOOT_DEBUG_MSG 
	sysDebugMsg("sysNetHwInit succeed!\n\r",0); 
#endif      
     
#endif 
 
	 
/*#ifdef INCLUDE_PCI9030 
	pci9030Init(); 
#endif*/     
 
    } 
 
/******************************************************************************* 
* 
* sysPhysMemTop - get the address of the top of physical memory 
* 
* This routine returns the address of the first missing byte of memory, 
* which indicates the top of memory. 
* 
* Normally, the user specifies the amount of physical memory with the 
* macro LOCAL_MEM_SIZE in config.h.  BSPs that support run-time 
* memory sizing do so only if the macro LOCAL_MEM_AUTOSIZE is defined. 
* If not defined, then LOCAL_MEM_SIZE is assumed to be, and must be, the 
* true size of physical memory. 
* 
* NOTE: Do no adjust LOCAL_MEM_SIZE to reserve memory for application 
* use.  See sysMemTop() for more information on reserving memory. 
* 
* RETURNS: The address of the top of physical memory. 
* 
* SEE ALSO: sysMemTop() 
*/ 
 
char * sysPhysMemTop (void) 
    { 
 
    static char * sysPhysMemSize = NULL;	/* ptr to top of mem + 1 */ 
 
    if (sysPhysMemSize == NULL) 
	{ 
	/* Don't do auto-sizing, use defined constants. */ 
	sysPhysMemSize = (char *)(LOCAL_MEM_LOCAL_ADRS + LOCAL_MEM_SIZE); 
	} 
 
    return sysPhysMemSize; 
    } 
 
 
/******************************************************************************* 
* 
* sysMemTop - get the address of the top of VxWorks memory 
* 
* This routine returns a pointer to the first byte of memory not 
* controlled or used by VxWorks. 
* 
* The user can reserve memory space by defining the macro USER_RESERVED_MEM 
* in config.h.  This routine returns the address of the reserved memory 
* area.  The value of USER_RESERVED_MEM is in bytes. 
* 
* RETURNS: The address of the top of VxWorks memory. 
*/ 
 
char * sysMemTop (void) 
    { 
    static char * memTop = NULL; 
 
    if (memTop == NULL) 
	{ 
	memTop = sysPhysMemTop () - USER_RESERVED_MEM; 
	} 
 
    return memTop; 
    } 
 
 
/****************************************************************************** 
* 
* sysToMonitor - transfer control to the ROM monitor 
* 
* This routine transfers control to the ROM monitor.  Normally, it is called 
* only by reboot()--which services ^X--and by bus errors at interrupt level. 
* However, in some circumstances, the user may wish to introduce a 
*  to enable special boot ROM facilities. 
* 
* RETURNS: Does not return. 
*/ 
 
STATUS sysToMonitor 
    ( 
    int startType	/* parameter passed to ROM to tell it how to boot */ 
    ) 
    { 
    FUNCPTR pRom = (FUNCPTR) (ROM_TEXT_ADRS + 4); /* Warm reboot */ 
 
    cacheDisable (0);   	/* Disable the Instruction Cache */ 
    cacheDisable (1);   	/* Disable the Data Cache */ 
 
#if     (CPU == PPC604) 
    vxHid0Set (vxHid0Get () & ~_PPC_HID0_SIED);	/* Enable Serial Instr Exec */ 
#endif  /* (CPU == PPC604) */ 
 
    sysSerialReset ();		/* reset serial devices */ 
 
    /* Clear the MSR */ 
 
    vxMsrSet (0); 
 
    /* Reset the EPIC */ 
 
    sysPciOutLong((UINT32)EPIC_GLOBAL_CONFIG_REG, EPIC_GC_RESET); 
 
/*7.28*/ 
#if(0) 
    /* set the Board Fail LED */ 
 
    *(UINT8 *)PRPMC600_SYS_STAT_REG2 |= PRPMC600_BD_FAIL; 
#endif 
    (*pRom) (startType); 
 
    return (OK);	/* in case we ever continue from ROM monitor */ 
    } 
 
 
/****************************************************************************** 
* 
* sysHwInit2 - initialize additional system hardware 
* 
* This routine connects system interrupt vectors and configures any  
* required features not configured by sysHwInit(). 
* 
* RETURNS: N/A 
*/ 
 
void sysHwInit2 (void) 
    { 
    static BOOL configured = FALSE; 
 
    /* Int connects for various devices */ 
 
    if (!configured) 
	{ 
#ifdef INCLUDE_AUXCLK 
        sysAuxClkInit (); 
        intConnect (INUM_TO_IVEC(TIMER0_INT_VEC), sysAuxClkInt, 0); 
        intEnable (TIMER0_INT_LVL); 
#endif /* INCLUDE_AUXCLK */ 
 
/* add by zoutl for BSP test 2003-5-30 14:31 */ 
#ifdef BSP_TEST 
		sysAuxClk1Init(); 
		/* add by zoutl for really enable interrupt */ 
    	intConnect (INUM_TO_IVEC((int)TIMER1_INT_LVL),sysAuxClk1Int, (int) 0);     
    	intEnable (TIMER1_INT_LVL);    
#endif 
 
	/* initialize serial interrupts */ 
 
	sysSerialHwInit2(); 
    /*in sysnet.c*/ 
 
 
#ifdef INCLUDE_NETWORK 
 
	/* configure the interrupts for the network hardware. */ 
 
	sysNetHwInit2 (); 
#endif 
 
#ifdef INCLUDE_SM_NET 
        sysSmParamsCompute (); 
#endif 
 
	configured = TRUE; 
	} 
    } 
 
 
/****************************************************************************** 
* 
* sysProcNumGet - get the processor number 
* 
* This routine returns the processor number for the CPU board, which is 
* set with sysProcNumSet(). 
* 
* RETURNS: The processor number for the CPU board. 
* 
* SEE ALSO: sysProcNumSet() 
*/ 
 
int sysProcNumGet (void) 
    { 
    return (sysProcNum); 
    } 
 
 
/****************************************************************************** 
* 
* sysProcNumSet - set the processor number 
* 
* This routine sets the processor number for the CPU board.  Processor numbers 
* should be unique on a single backplane.  It also maps local resources onto 
* the VMEbus. 
* 
* RETURNS: N/A 
* 
* SEE ALSO: sysProcNumGet() 
* 
*/ 
 
void sysProcNumSet 
    ( 
    int 	procNum			/* processor number */ 
    ) 
    { 
 
    /*  Init the global variable */ 
 
    sysProcNum = procNum; 
 
    } 
 
 
/* miscellaneous support routines */ 
 
/****************************************************************************** 
* 
* sysMpc8240TransAdrs - translate an address that passes through the mpc8240. 
* 
* This routine converts an address from a cpu to pci address or vice versa. It 
* uses a pair of window arrays built during hardware init2 to guide the 
* translation. The adrs parameter is the address to convert. 
* 
* RETURNS: OK, or ERROR if the address space is unknown or the mapping is not 
* possible. 
* 
* SEE ALSO: sysMpc8240Capt() 
* 
*/ 
 
LOCAL STATUS sysMpc8240TransAdrs 
    ( 
    UINT32            adrsSpace,    /* address space (memory or i/o ) */ 
    UINT32            adrs,         /* known address */ 
    UINT32 *          pTransAdrs,   /* pointer to the translated address */ 
    UINT32            winCnt,       /* number of open windows */ 
    MPC8240_WIN_STRUCT * pSrc,         /* pointer to the source windows */ 
    MPC8240_WIN_STRUCT * pDest         /* pointer to the destination windows */ 
    ) 
    { 
 
    while (winCnt--) 
        { 
 
        /* check for a match on window type and in bounds */ 
 
        if ( (pSrc->winType == adrsSpace) && 
             (adrs >= pSrc->winBase) && 
             (adrs <= pSrc->winLimit) ) 
            { 
            *pTransAdrs = ( adrs - pSrc->winBase + pDest->winBase ); 
 
            return (OK); 
            }; 
 
        /* advance to next window */ 
 
        pSrc++; 
        pDest++; 
        } 
 
    /* 
     * no window was found to contain adrs. indicate that translation was 
     * not possible. 
     */ 
 
    return (ERROR); 
 
    } 
 
 
/****************************************************************************** 
* 
* sysCpuToPciAdrs - translate a cpu address to a pci bus address 
* 
* This routine converts an address as seen from the cpu to the equivalent pci 
* address, if it exists. The input address is the address as seen by the cpu. 
* 
* RETURNS: OK, or ERROR if the address space is unknown or the mapping is not 
* possible. 
* 
* SEE ALSO: sysPciToCpuAdrs() 
*/ 
 
LOCAL STATUS sysCpuToPciAdrs 
    ( 
    int     adrsSpace,  /* bus address space where busAdrs resides */ 
    char *  localAdrs,  /* local address to convert */ 
    char ** pBusAdrs    /* where to return bus address */ 
    ) 
    { 
    return (sysMpc8240TransAdrs (adrsSpace, (UINT32)localAdrs,  
				(UINT32 *)pBusAdrs, MPC8240_WIN_CNT, 
                                &sysMpc8240CpuToPciWin[0], 
                                &sysMpc8240PciToCpuWin[0]) ); 
    } 
 
 
/****************************************************************************** 
* 
* sysPciToCpuAdrs - translate a pci bus address to a cpu address 
* 
* This routine converts an address as seen from the pci bus to the equivalent 
* cpu address, if it exists. The input address is the address as seen by the 
* pci bus. 
* 
* RETURNS: OK, or ERROR if the address space is unknown or the mapping is not 
* possible. 
* 
* SEE ALSO: sysCpuToPciAdrs() 
*/ 
 
LOCAL STATUS sysPciToCpuAdrs 
    ( 
    int     adrsSpace,  /* bus address space where busAdrs resides */ 
    char *  localAdrs,  /* local address to convert */ 
    char ** pBusAdrs    /* where to return bus address */ 
    ) 
    { 
    return (sysMpc8240TransAdrs (adrsSpace, (UINT32)localAdrs,  
				(UINT32 *)pBusAdrs, MPC8240_WIN_CNT, 
                                &sysMpc8240PciToCpuWin[0], 
                                &sysMpc8240CpuToPciWin[0]) ); 
    } 
 
 
/****************************************************************************** 
* 
* sysLocalToBusAdrs - convert a local CPU address to a PCI bus address 
* 
* Given a CPU address, this routine returns a corresponding local PCI bus 
* or Compact (backpanel) PCI bus address provided that such an address exists. 
* The target PCI bus (local or backpanel) is selected by the adrsSpace 
* parameter. Legal values for this parameter are found in "pci.h". If a 
* transparent bridge is used to access the Compact PCI bus, the local PCI bus 
* and the backpanel PCI bus share the same address space. In this case, the 
* local and backpanel address space designators are synonomous. 
* 
* RETURNS: OK, or ERROR if the address space is unknown or the mapping is not 
* possible. 
* 
* SEE ALSO: sysBusToLocalAdrs() 
*/ 
 
STATUS sysLocalToBusAdrs 
    ( 
    int     adrsSpace,  /* bus address space where busAdrs resides */ 
    char *  localAdrs,  /* local address to convert */ 
    char ** pBusAdrs    /* where to return bus address */ 
    ) 
    { 
 
    switch (adrsSpace) 
        { 
 
        case PCI_SPACE_IO_PRI: 
        case PCI_SPACE_IO_SEC: 
 
            /* convert from cpu address space to local pci space */ 
 
            if ( sysCpuToPciAdrs (PCI_BAR_SPACE_IO, localAdrs, pBusAdrs) != OK ) 
                return (ERROR); 
 
 
#ifdef INCLUDE_DEC2155X 
 
            /* 
             * if continuing on to the backpanel using the dec2155x, translate 
             * from local pci space to compact pci space. 
             */ 
 
            if ( PCI_SPACE_IS_CPCI(adrsSpace) ) 
                return ( sysPciToCpciAdrs (PCI_BAR_SPACE_IO, *pBusAdrs, 
                                           pBusAdrs) ); 
 
#endif /* INCLUDE_DEC2155X */ 
            break; 
 
        case PCI_SPACE_MEMIO_PRI: 
        case PCI_SPACE_MEM_PRI: 
        case PCI_SPACE_MEMIO_SEC: 
        case PCI_SPACE_MEM_SEC: 
 
            /* convert from cpu address space to local pci address space */ 
 
            if (sysCpuToPciAdrs (PCI_BAR_SPACE_MEM, localAdrs, pBusAdrs) != OK ) 
                return (ERROR); 
 
#ifdef INCLUDE_DEC2155X 
 
            /* 
             * if continuing on to the backpanel using the dec2155x, translate 
             * from local pci space to compact pci space. 
             */ 
 
            if ( PCI_SPACE_IS_CPCI(adrsSpace) ) 
                return ( sysPciToCpciAdrs(PCI_BAR_SPACE_MEM, *pBusAdrs, 
                                          pBusAdrs) ); 
 
#endif /* INCLUDE_DEC2155X */ 
            break; 
 
        default: 
            return (ERROR); 
            break; 
        } 
    return (OK); 
 
    } 
 
 
/****************************************************************************** 
* 
* sysBusToLocalAdrs - convert a PCI bus address to a local CPU address 
* 
* Given a local or Compact (backpanel) PCI address, this routine returns a 
* corresponding local CPU bus address provided such an address exists. The 
* originating PCI bus (local or backpanel) is selected by the adrsSpace 
* parameter. Legal values for this parameter are found in "pci.h". If a 
* transparent bridge is used to access the Compact PCI bus, the local PCI bus 
* and the Compact PCI bus share the same address space. In this case, the 
* local and backpanel address space designators are synonomous. 
* 
* RETURNS: OK, or ERROR if the address space is unknown or the mapping is not 
* possible. 
* 
* SEE ALSO: sysLocalToBusAdrs() 
*/ 
 
STATUS sysBusToLocalAdrs 
    ( 
    int     adrsSpace,  /* bus address space where busAdrs resides */ 
    char *  busAdrs,    /* bus address to convert */ 
    char ** pLocalAdrs  /* where to return local address */ 
    ) 
    { 
 
    switch (adrsSpace) 
        { 
 
        case PCI_SPACE_IO_SEC: 
 
#ifdef INCLUDE_DEC2155X 
 
            /* 
             * translate from compact PCI address space to local PCI address 
             * space. 
             */ 
 
            if ( sysCpciToPciAdrs (PCI_BAR_SPACE_IO, busAdrs, &busAdrs) != OK ) 
                return (ERROR); 
 
            /* fall through */ 
 
#endif /* INCLUDE_DEC2155X */ 
 
        case PCI_SPACE_IO_PRI: 
 
            /* 
             * translate from local PCI address space to CPU address 
             * space. 
             */ 
 
            return ( sysPciToCpuAdrs (PCI_BAR_SPACE_IO, busAdrs, pLocalAdrs) ); 
            break; 
 
        case PCI_SPACE_MEMIO_SEC: 
        case PCI_SPACE_MEM_SEC: 
 
#ifdef INCLUDE_DEC2155X 
 
            /* 
             * translate from compact PCI address space to local PCI address 
             * space. 
             */ 
 
            if ( sysCpciToPciAdrs (PCI_BAR_SPACE_MEM, busAdrs, &busAdrs) != OK) 
                return (ERROR); 
 
            /* fall through */ 
 
#endif /* INCLUDE_DEC2155X */ 
 
        case PCI_SPACE_MEMIO_PRI: 
        case PCI_SPACE_MEM_PRI: 
 
            /* 
             * translate from local PCI address space to CPU address 
             * space. 
             */ 
 
            return (sysPciToCpuAdrs (PCI_BAR_SPACE_MEM, busAdrs, pLocalAdrs) ); 
            break; 
 
        default: 
            return (ERROR); 
            break; 
        } 
 
    } 
 
 
/******************************************************************************* 
* 
* sysBusTas - test and set a location across the bus 
* 
* The cPCI bridge chips do not support PCI target locking, therefore there is 
* no atomic RMW operation. This routine performs a software-based mutual 
* exclusion algorithm in place of a true test and set. 
* 
* NOTE: This algorithm is performed through a PCI-to-PCI bridge to a shared 
* location that is subject to unprotected access by multiple simultaneous 
* processors. There is the possibility that the bridge will deliver a delayed 
* read completion to a PCI bus master which was not the original initiator of 
* the delayed read. The bridge delivers the delayed read completion to the new 
* requestor because it believes that the new delayed read request is actually 
* the original master performing a delayed read retry as required by the PCI 
* spec. When the original master comes back with the genuine retry, the bridge 
* treats it as a new request. When this "aliasing" occurs, a read performed 
* after a write can appear to complete ahead of the write, which is in violation 
* of PCI transaction ordering rules. Since this algorithm depends on a strict 
* time-ordered sequence of operations, it can deadlock under this condition. 
* To prevent the deadlock, a throw-away read must be performed after the initial 
* write. Since the bridge only remembers once instance of a queued delayed 
* read request, the throw-away read will "consume" the results of a 
* mis-directed read completion and subsequent read requests are guaranteed to 
* be queued and completed after the write. 
* 
* RETURNS: TRUE if lock acquired. 
* FALSE if lock not acquired. 
* 
* SEE ALSO: sysBusTasClear() 
*/ 
 
BOOL sysBusTas 
    ( 
    char * adrs          /* address to be tested and set */ 
    ) 
    { 
    FAST int    value;                  /* value to place in lock variable */ 
    FAST int    nChecks;                /* number of times to re-check lock */ 
    FAST int    count;                  /* running count of re-checks */ 
    int         oldLvl;                 /* previous interrupt level */ 
 
    volatile int * lockAdrs = (int *)adrs; 
 
    if (sysSmUtilTasValue == 0) 
        sysSmUtilTasValue =  (TAS_CONST + sysProcNumGet ())<< 24; 
 
    value   = sysSmUtilTasValue;                /* special value to write */ 
    nChecks = DEFAULT_TAS_CHECKS;               /* number of checks to do */ 
 
    /* Lock out interrupts */ 
 
    oldLvl = intLock (); 
 
    /* Test that lock variable is initially empty */ 
 
    if (*lockAdrs != 0) 
        { 
        intUnlock (oldLvl); 
        return (FALSE);                         /* someone else has lock */ 
        } 
 
    /* Set lock value */ 
 
    *lockAdrs = value; 
 
    /* Perform a preliminary read due to PCI bridge issues */ 
 
    count = *lockAdrs; 
 
    /* Check that no one else is trying to take lock */ 
 
    for (count = 0;  count < nChecks;  count++) 
        { 
        if (*lockAdrs != value) 
            { 
            intUnlock (oldLvl); 
            return (FALSE);                     /* someone else stole lock */ 
            } 
        } 
 
    intUnlock (oldLvl); 
    return (TRUE);                              /* exclusive access obtained */ 
 
    } 
 
 
/****************************************************************************** 
* 
* sysBusTasClear - clear a location set by sysBusTas() 
* 
* This routine clears a bus test and set location.  This routine is only 
* required if the sysBusTas() routine uses special semaphore techniques (such 
* as bus locking). Since the sysBusTas routine doesn't use any special 
* semaphore techniques, this routine is a no-op. 
* 
* If used, the BSP activates this routine by placing its address into the 
* global variable 'smUtilTasClearRtn'. 
* 
* RETURNS: N/A 
* 
* SEE ALSO: sysBusTas() 
*/ 
 
void sysBusTasClear 
    ( 
    volatile char * address     /* address to be tested-and-cleared */ 
    ) 
    { 
    } 
 
 
/****************************************************************************** 
* 
* sysSpuriousIntHandler - spurious interrupt handler 
* 
* This is the entry point for spurious interrupts. 
* 
* NOTE: This routine has no effect. 
* 
* This routine catches all spurious interrupts.  It does nothing at all. 
* 
* RETURNS: N/A. 
* 
* RETURNS: N/A 
* 
* NOMANUAL 
*/ 
 
void sysSpuriousIntHandler (void) 
    { 
    } 
 
 
 
/******************************************************************************* 
* 
* sysCpuCheck - confirm the CPU type 
* 
* This routine validates the cpu type.  If the wrong cpu type is discovered 
* a message is printed using the serial channel in polled mode. 
* 
* RETURNS: N/A. 
*/ 
 
void sysCpuCheck (void) 
    { 
    int msgSize; 
    int msgIx; 
    SIO_CHAN * pSioChan;        /* serial I/O channel */ 
 
    /* Check for a valid CPU type;  If one is found, just return */ 
 
    if	((CPU_TYPE == CPU_TYPE_603) || (CPU_TYPE == CPU_TYPE_603E) ||(CPU_TYPE == CPU_TYPE_8245)|| 
         (CPU_TYPE == CPU_TYPE_603P) || (CPU_TYPE == CPU_TYPE_603EK)||(CPU_TYPE == CPU_TYPE_750)) 
	{ 
	/*flashled(2,2);*/ 
	return; 
	} 
 
    /* Invalid CPU type; print error message and terminate */ 
 
    msgSize = strlen (wrongCpuMsg); 
/*	flashled(2,5);*/ 
    sysSerialHwInit (); 
 
    pSioChan = sysSerialChanGet (0); 
 
    sioIoctl (pSioChan, SIO_MODE_SET, (void *) SIO_MODE_POLL); 
 
    for (msgIx = 0; msgIx < msgSize; msgIx++) 
    	{ 
    	while (sioPollOutput (pSioChan, wrongCpuMsg[msgIx]) == EAGAIN); 
    	} 
 
    sysToMonitor (BOOT_NO_AUTOBOOT); 
    } 
 
 
/****************************************************************************** 
* 
* sysMemProbeTrap - trap handler for vxMemProbe exception 
* 
* This routine is called from the excConnectCode stub if sysMemProbeSup 
* generates an exception. By default, sysMemProbeSup returns OK. 
* This code changes the PC value to "sysProbeExc" (within the sysMemProbeSup 
* routine), and sysProbeExc sets the return value to ERROR. 
*/ 
 
static int sysMemProbeTrap 
    ( 
    ESFPPC *    pEsf		/* pointer to exception stack frame */ 
    ) 
    { 
    REG_SET *pRegSet = &pEsf->regSet; 
 
    pRegSet->pc = (_RType)sysProbeExc;	/* sysProbeExc forces an ERROR return */ 
    return (0); 
    } 
 
 
/****************************************************************************** 
* 
* sysMemProbeBus - probe an address on a bus. 
* 
* This routine probes a specified address to see if it is readable or 
* writable, as specified by .  The address will be read or written as 
* 1, 2, or 4 bytes as specified by  (values other than 1, 2, or 4 
* yield unpredictable results).  If the probe is a VX_READ, the value read will 
* be copied to the location pointed to by .  If the probe is a VX_WRITE, 
* the value written will be taken from the location pointed to by . 
* In either case,  should point to a value of 1, 2, or 4 bytes, as 
* specified by . 
* 
* This routine probes the specified address with interrupts disabled and 
* a special handler for Machine Check, Data Access and Alignment exceptions. 
* 
* RETURNS: OK if probe succeeded or ERROR if an exception occured. 
*/ 
 
static STATUS sysMemProbeBus 
    ( 
    char   * adrs,	/* address to be probed */ 
    int      mode,	/* VX_READ or VX_WRITE */ 
    int      length,	/* 1, 2 or 4 byte probe */ 
    char   * pVal	/* address of value to write OR */ 
			/* address of location to place value read */ 
    ) 
    { 
    int      oldLevel; 
    FUNCPTR  oldVec1; 
    FUNCPTR  oldVec2; 
    STATUS   status; 
    UINT32   ppcHid0;   /* H/W Implementation Dependent reg (PPC60x) */ 
    UINT32   ppcMsr;    /* PPC Machine Status Reg */ 
    UINT16   temp; 
 
    /* Probes performed with interrupts disabled */ 
 
    oldLevel = intLock (); 
 
    /* Handle Machine Check Exceptions locally */ 
 
    oldVec1 = excVecGet ((FUNCPTR *) _EXC_OFF_MACH); 
    excVecSet ((FUNCPTR *) _EXC_OFF_MACH, FUNCREF(sysMemProbeTrap));  
 
    /* 
     *  Handle Data Access Exceptions locally 
     * 
     *  Data Access Exceptions will occur when trying to probe addresses 
     *  that have not been mapped by the MMU. 
     */ 
 
    oldVec2 = excVecGet ((FUNCPTR *) _EXC_OFF_DATA); 
    excVecSet ((FUNCPTR *) _EXC_OFF_DATA, FUNCREF(sysMemProbeTrap)); 
 
    /* Enable Machine Check Pin (EMCP) */ 
 
    ppcHid0 = vxHid0Get(); 
    vxHid0Set(ppcHid0 | _PPC_HID0_EMCP); 
 
    /* Enable Machine Check exception */ 
 
    ppcMsr = vxMsrGet(); 
    vxMsrSet(ppcMsr | _PPC_MSR_ME); 
 
    /* clear the PCI abort bits in the PCI status word */ 
 
    sysPciConfigOutWord((UINT16 *)(CNFG_PCI_HOST_BRDG + MPC8240_CFG_STATUS), 
                        (MPC8240_PCI_RCV_MSTR_ABORT | MPC8240_PCI_RCV_TGT_ABORT)); 
 
    /* do probe */ 
 
    if (mode == VX_READ) 
        { 
        status = sysMemProbeSup (length, adrs, pVal); 
        SYNC; 
        } 
    else 
        { 
        status = sysMemProbeSup (length, pVal, adrs); 
        SYNC; 
        } 
 
    /* check for valid address */ 
 
    temp = sysPciConfigInWord((UINT16 *)(CNFG_PCI_HOST_BRDG +  
			      MPC8240_CFG_STATUS)); 
    if (temp & (MPC8240_PCI_RCV_MSTR_ABORT | MPC8240_PCI_RCV_TGT_ABORT)) 
        status = ERROR; 
 
    /* clear the PCI status reg. bits */ 
 
    sysPciConfigOutWord((UINT16 *)(CNFG_PCI_HOST_BRDG + MPC8240_CFG_STATUS),  
			(MPC8240_PCI_RCV_MSTR_ABORT | MPC8240_PCI_RCV_TGT_ABORT)); 
 
    /* Disable Machine Check Exceptions */ 
 
    vxMsrSet(ppcMsr); 
 
    /* Disable Machine Check Pin (EMCP) */ 
 
    vxHid0Set(ppcHid0); 
 
    /* restore original vectors and unlock */ 
 
    excVecSet ((FUNCPTR *) _EXC_OFF_DATA, oldVec2); 
 
    excVecSet ((FUNCPTR *) _EXC_OFF_MACH, oldVec1); 
 
    intUnlock (oldLevel); 
 
    return (status); 
    } 
 
 
/****************************************************************************** 
* 
* sysProbeErrClr - clear errors associated with probing an address on a bus. 
* 
* This routine clears the error flags and conditions in the DAR, DSISR, SRR0 
* and SRR1 PowerPC registers arising from probing addresses as well as the 
* PCI_CFG_STATUS registers and the Universe PCI_CSR and V_AMERR registers. 
* 
* RETURNS: N/A 
*/ 
 
void sysProbeErrClr (void) 
    { 
 
    /* Clear PowerPC Data Access Exception Registers */ 
 
    vxDarSet   (0); 
    vxDsisrSet (0); 
    vxSrr0Set  (0); 
    vxSrr1Set  (0); 
    } 
 
 
/****************************************************************************** 
* 
* sysPciProbe - probe a PCI bus address 
* 
* This routine probes an address on the PCI bus.  The PCI bridge chip 
* must have a special setup to enable generation of Master Abort cycles on 
* write probes and reception of Target Abort cycles on read probes. 
* The CPU must be configured to enable Machine Check exceptions.  In  
* addition, if the probe is a write, the Universe must be configured to 
* disable Posted Writes.  All probing is done with interrupts disabled. 
* 
* RETURNS: OK or ERROR if address cannot be probed 
*/ 
 
STATUS sysPciProbe 
    ( 
    char   * adrs,	/* address to be probed */ 
    int      mode,	/* VX_READ or VX_WRITE */ 
    int      length,	/* 1, 2 or 4 byte probe */ 
    char   * pVal	/* address of value to write OR */ 
			/* address of location to place value read */ 
    ) 
    { 
    STATUS status = ERROR; 
 
    /* Perform probe */ 
 
    status = sysMemProbeBus (adrs, mode, length, pVal); 
 
    return (status); 
    } 
 
 
/****************************************************************************** 
* 
* sysBusProbe - probe a bus address based on bus type. 
* 
* This routine is a function hook into vxMemProbe.  It determines which bus, 
* PCI or local is being probed based on the address to be probed. 
* If the PCI bus is being probed, the sysPciProbe() routine is called to do the 
* special PCI probing. If the local bus is being probed, the routine calls an 
* architecture-specific probe routine. 
* 
* RETURNS: ERROR if the probed address does not respond or causes a MMU fault. 
* Returns OK if the probed address responds. 
*/ 
 
STATUS  sysBusProbe 
    ( 
    char   * adrs,	/* address to be probed */ 
    int      mode,	/* VX_READ or VX_WRITE */ 
    int      length,	/* 1, 2 or 4 byte probe */ 
    char   * pVal	/* address of value to write OR */ 
			/* address of location to place value read */ 
    ) 
    { 
    STATUS status; 
 
    /* Clear any existing errors/exceptions */ 
 
    sysProbeErrClr (); 
 
    /* Handle PCI bus in special manner */ 
 
    if (IS_PCI_ADDRESS(adrs)) 
        status = sysPciProbe (adrs, mode, length, pVal); 
 
    /* Handle local bus in architecture-specific manner */ 
 
    else 
        status = vxMemArchProbe (adrs, mode, length, pVal); 
 
    /* Clear any errors/exceptions before exiting */ 
 
    sysProbeErrClr (); 
 
    return (status); 
    } 
 
 
/****************************************************************************** 
* 
* sysUsDelay - delay at least the specified amount of time (in microseconds) 
* 
* This routine will delay for at least the specified amount of time using the 
* lower 32 bit "word" of the Time Base register as the timer.  The accuracy of 
* the delay increases as the requested delay increases due to a certain amount 
* of overhead.  As an example, a requested delay of 10 microseconds is 
* accurate within approximately twenty percent, and a requested delay of 100 
* microseconds is accurate within approximately two percent. 
* 
* NOTE:  This routine will not relinquish the CPU; it is meant to perform a 
* busy loop delay.  The minimum delay that this routine will provide is 
* approximately 10 microseconds.  The maximum delay is approximately the 
* size of UINT32; however, there is no roll-over compensation for the total 
* delay time, so it is necessary to back off two times the system tick rate 
* from the maximum. 
* 
* RETURNS: N/A 
*/ 
 
void sysUsDelay 
    ( 
    UINT32	delay		/* length of time in microsec to delay */ 
    ) 
    { 
    register UINT baselineTickCount; 
    register UINT curTickCount; 
    register UINT terminalTickCount; 
    register int actualRollover = 0; 
    register int calcRollover = 0; 
    UINT ticksToWait; 
    UINT requestedDelay; 
    UINT oneUsDelay; 
 
    /* Exit if no delay count */ 
 
    if ((requestedDelay = delay) == 0) 
	return; 
 
    /* 
     * Get the Time Base Lower register tick count, this will be used 
     * as the baseline. 
     */ 
 
    baselineTickCount = sysTimeBaseLGet(); 
 
    /* 
     * Calculate number of ticks equal to 1 microsecond 
     * 
     * The Time Base register and the Decrementer count at the same rate: 
     * once per 4 System Bus cycles. 
     * 
     * e.g., 66666666 cycles     1 tick      1 second             16 tick 
     *       ---------------  *  ------   *  --------          =  ---------- 
     *       second              4 cycles    1000000 microsec    microsec 
     */ 
 
    oneUsDelay = ((DEC_CLOCK_FREQ / 4) / 1000000); 
 
    /* Convert delay time into ticks */ 
 
    ticksToWait = requestedDelay * oneUsDelay; 
 
    /* Compute when to stop */ 
 
    terminalTickCount = baselineTickCount + ticksToWait; 
 
    /* Check for expected rollover */ 
 
    if (terminalTickCount < baselineTickCount) 
	{ 
	calcRollover = 1; 
	} 
 
    do 
	{ 
	/* 
	 * Get current Time Base Lower register count. 
	 * The Time Base counts UP from 0 to 
	 * all F's. 
	 */ 
 
	curTickCount = sysTimeBaseLGet(); 
 
        /* Check for actual rollover */ 
 
	if (curTickCount < baselineTickCount) 
	    { 
	    actualRollover = 1; 
	    } 
 
	if (((curTickCount >= terminalTickCount) 
	    && (actualRollover == calcRollover)) || 
	    ((curTickCount < terminalTickCount) 
            && (actualRollover > calcRollover))) 
	    { 
	    /* Delay time met */ 
 
	    break; 
	    } 
 
	} 
    while (TRUE); 
    } 
 
/****************************************************************************** 
* 
* sysDebugMsg - print a debug string to the console in polled mode. 
* 
* This routine prints a message to the system console in polled mode and 
* optionally exits to the monitor. 
* 
* RETURNS: N/A 
* 
*/ 
 
void sysDebugMsg 
    ( 
    char * str, 
    UINT32  recovery 
    ) 
    { 
    int msgSize; 
    int msgIx; 
    SIO_CHAN * pSioChan;        /* serial I/O channel */ 
     
    /* add by zoutl delay a while */ 
	for (msgIx = 0; msgIx < 50000; msgIx++) 
	{ 
		msgSize = msgIx; 
	} 
 
    msgSize = strlen (str); 
 
    sysSerialHwInit (); 
 
    pSioChan = sysSerialChanGet (0); 
 
    sioIoctl (pSioChan, SIO_MODE_SET, (void *) SIO_MODE_POLL); 
 
    for (msgIx = 0; msgIx < msgSize; msgIx++) 
        { 
        while (sioPollOutput (pSioChan, str[msgIx]) == EAGAIN); 
        } 
 
    /* follow caller's error recovery policy. */ 
 
#ifdef DEBUGMSG_RECOVERY 
    if (recovery == EXIT_TO_SYSTEM_MONITOR) 
        sysToMonitor (BOOT_NO_AUTOBOOT); 
#endif 
    } 
 
 
/***************************************************************************** 
* 
* sysPciInsertLong - Insert field into PCI data long 
* 
* This function writes a field into a PCI data long without altering any bits 
* not present in the field.  It does this by first doing a PCI long read 
* (into a temporary location) of the PCI data long which contains the field 
* to be altered. It then alters the bits in the temporary location to match 
* the desired value of the field.  It then writes back the temporary location 
* with a PCI long write.  All PCI accesses are byte and the field to alter is 
* specified by the "1" bits in the 'bitMask' parameter. 
* 
* RETURNS: N/A 
*/ 
 
void sysPciInsertLong 
    ( 
    UINT32 adrs,         /* PCI address */ 
    UINT32 bitMask,      /* Mask which defines field to alter */ 
    UINT32 data          /* data written to the offset */ 
    ) 
    { 
    UINT32 temp; 
    int key; 
 
    key = intLock (); 
    temp = sysPciInLong (adrs); 
    temp = (temp & ~bitMask) | (data & bitMask); 
    sysPciOutLong (adrs, temp); 
    intUnlock (key); 
    } 
 
 
/***************************************************************************** 
* 
* sysPciInsertWord - Insert field into PCI data word 
* 
* This function writes a field into a PCI data word without altering any bits 
* not present in the field.  It does this by first doing a PCI word read 
* (into a temporary location) of the PCI data word which contains the field 
* to be altered. It then alters the bits in the temporary location to match 
* the desired value of the field.  It then writes back the temporary location 
* with a PCI word write.  All PCI accesses are word and the field to alter is 
* specified by the "1" bits in the 'bitMask' parameter. 
* 
* RETURNS: N/A 
*/ 
 
void sysPciInsertWord 
    ( 
    UINT32 adrs,       /* PCI address */ 
    UINT16 bitMask,      /* Mask which defines field to alter */ 
    UINT16 data          /* data written to the offset */ 
    ) 
    { 
    UINT16 temp; 
    int key; 
 
    key = intLock (); 
    temp = sysPciInWord (adrs); 
    temp = (temp & ~bitMask) | (data & bitMask); 
    sysPciOutWord (adrs, temp); 
    intUnlock (key); 
    } 
 
 
/***************************************************************************** 
* 
* sysPciInsertByte - Insert field into PCI data byte 
* 
* This function writes a field into a PCI data byte without altering any bits 
* not present in the field.  It does this by first doing a PCI byte read 
* (into a temporary location) of the PCI data byte which contains the field 
* to be altered. It then alters the bits in the temporary location to match 
* the desired value of the field.  It then writes back the temporary location 
* with a PCI byte write.  All PCI accesses are byte and the field to alter is 
* specified by the "1" bits in the 'bitMask' parameter. 
* 
* RETURNS: N/A 
*/ 
 
void sysPciInsertByte 
    ( 
    UINT32 adrs,       /* PCI address */ 
    UINT8  bitMask,    /* Mask which defines field to alter */ 
    UINT8  data        /* data written to the offset */ 
    ) 
    { 
    UINT8 temp; 
    int key; 
 
    key = intLock (); 
    temp = sysPciInByte (adrs); 
    temp = (temp & ~bitMask) | (data & bitMask); 
    sysPciOutByte (adrs, temp); 
    intUnlock (key); 
    } 
 
 
/***************************************************************************** 
* 
* sysPciOutByteConfirm - Byte out to PCI memory space and flush buffers. 
* 
* This function outputs a byte to PCI memory space and then flushes the PCI 
* write posting buffers by reading from the target address. Since the PCI 
* spec requires the completion of posted writes before the completion of delayed 
* reads, when the read completes, the write posting buffers have been flushed. 
* 
* NOTE: If the write is performed through a PCI-to-PCI bridge to a shared 
* location that is subject to unprotected access by multiple simultaneous 
* processors, there is the possibility that the bridge will deliver a delayed 
* read completion to a PCI bus master which was not the original initiator of 
* the delayed read. When this occurs, it appears as if a PCI delayed read had 
* passed a posted write, which would violate PCI transaction ordering rules. 
* If this is a concern, an additional read must be performed outside of this 
* routine to guarantee that the confirming read performed in this routine was 
* not aliased. 
* 
* RETURNS: N/A 
*/ 
 
void sysPciOutByteConfirm 
    ( 
    UINT32 adrs,       /* PCI address */ 
    UINT8  data        /* data to be written */ 
    ) 
    { 
    UINT8 temp; 
 
    sysPciOutByte (adrs, data); 
    temp = sysPciInByte (adrs); 
 
    } 
 
 
/***************************************************************************** 
* 
* sysPciOutWordConfirm - Word out to PCI memory space and flush buffers. 
* 
* This function outputs a word to PCI memory space and then flushes the PCI 
* write posting buffers by reading from the target address. Since the PCI 
* spec requires the completion of posted writes before the completion of delayed 
* reads, when the read completes, the write posting buffers have been flushed. 
* 
* NOTE: If the write is performed through a PCI-to-PCI bridge to a shared 
* location that is subject to unprotected access by multiple simultaneous 
* processors, there is the possibility that the bridge will deliver a delayed 
* read completion to a PCI bus master which was not the original initiator of 
* the delayed read. When this occurs, it appears as if a PCI delayed read had 
* passed a posted write, which would violate PCI transaction ordering rules. 
* If this is a concern, an additional read must be performed outside of this 
* routine to guarantee that the confirming read performed in this routine was 
* not aliased. 
* 
* RETURNS: N/A 
*/ 
 
void sysPciOutWordConfirm 
    ( 
    UINT32 adrs,       /* PCI address */ 
    UINT16 data        /* data to be written */ 
    ) 
    { 
    UINT16 temp; 
 
    sysPciOutWord (adrs, data); 
    temp = sysPciInWord (adrs); 
 
    } 
 
 
/***************************************************************************** 
* 
* sysPciOutLongConfirm - Long word out to PCI memory space and flush buffers. 
* 
* This function outputs a long word to PCI memory space and then flushes the 
* PCI write posting buffers by reading from the target address. Since the PCI 
* spec requires the completion of posted writes before the completion of delayed 
* reads, when the read completes, the write posting buffers have been flushed. 
* 
* NOTE: If the write is performed through a PCI-to-PCI bridge to a shared 
* location that is subject to unprotected access by multiple simultaneous 
* processors, there is the possibility that the bridge will deliver a delayed 
* read completion to a PCI bus master which was not the original initiator of 
* the delayed read. When this occurs, it appears as if a PCI delayed read had 
* passed a posted write, which would violate PCI transaction ordering rules. 
* If this is a concern, an additional read must be performed outside of this 
* routine to guarantee that the confirming read performed in this routine was 
* not aliased. 
* 
* RETURNS: N/A 
*/ 
 
void sysPciOutLongConfirm 
    ( 
    UINT32 adrs,       /* PCI address */ 
    UINT32 data        /* data to be written */ 
    ) 
    { 
    UINT32 temp; 
 
    sysPciOutLong (adrs, data); 
    temp = sysPciInLong (adrs); 
 
    } 
 
 
 
/******************************************************************************* 
* 
* sysIntDisable - disable a bus interrupt level (vector) 
* 
* This routine disables reception of a specified local or Compact PCI bus 
* interrupt. If the interrupt level (vector) specified is used for shared 
* memory interrupts, a distributed shared memory interrrupt routine is called 
* to disable shared memory interrupts from all PCI or cPCI shared memory 
* devices. If the level (vector) is not the one used for shared memory, the 
* standard intDisable function is called to disable the interrupt at the MPIC. 
* 
* RETURNS: The results of sysSmIntDisable or intDisable. 
* 
* SEE ALSO: sysSmIntDisable, sysIntEnable() 
*/ 
 
STATUS sysIntDisable 
    ( 
    int intLevel        /* interrupt level (vector) */ 
    ) 
    { 
    return (intDisable (intLevel)); 
    } 
 
 
/******************************************************************************* 
* 
* sysIntEnable - enable a bus interrupt level (vector) 
* 
* This routine enables reception of a specified local or Compact PCI bus 
* interrupt. If the interrupt level (vector) specified is used for shared 
* memory interrupts, a distributed shared memory interrrupt routine is called 
* to enable shared memory interrupts from all PCI or cPCI shared memory 
* devices. If the level (vector) is not the one used for shared memory, the 
* standard intEnable function is called to enable the interrupt at the MPIC. 
* 
* RETURNS: The results of sysSmIntEnable or intEnable. 
* 
* SEE ALSO: sysSmIntEnable, sysIntDisable() 
*/ 
 
STATUS sysIntEnable 
    ( 
    int intLevel        /* interrupt level (vector) */ 
    ) 
    { 
    return (intEnable (intLevel) ); 
    } 
 
 
/******************************************************************************* 
* 
* sysBusIntAck - acknowledge a bus interrupt 
* 
* This routine acknowledges a specified Compact PCI bus interrupt level. 
* 
* NOTE: This routine is included for BSP compliance only.  Since PCI and Compact 
* PCI bus interrupts are routed directly to the interrupt controller, interrupts 
* are re-enabled in the interrupt controller's handler and this routine is a 
* no-op. 
* 
* RETURNS: NULL. 
* 
* SEE ALSO: sysBusIntGen() 
*/ 
 
int sysBusIntAck 
    ( 
    int intLevel        /* interrupt level to acknowledge */ 
    ) 
    { 
    return (NULL); 
    } 
 
 
/******************************************************************************* 
* 
* sysBusIntGen - generate a bus interrupt 
* 
* This routine generates an out-bound PCI or Compact PCI backpanel interrupt. 
* The method used to generate the interrupt is based on the current 
* configuration and operating mode of the BSP. If the BSP was built with 
* DEC2155X support and the BSP is operating as the (local) PCI Host device, the 
* outbound Compact PCI bus interrupt is generated by calling 
* sysDec2155xBusIntGen which sets a bit in the secondary mailbox register of 
* the 2155x. If the BSP does not contain DEC2155X support or is operating as a 
* PCI Slave device, the outbound PCI interrupt is generated by calling 
* sysMpicBusIntGen which sets a bit in the CPU 1 portion of the MPIC's 
* Inter-Process Interrupt mechanism. The PRPMC750 hardware ties the CPU 1 
* interrupt line to one of the PCI bus interrupt pins which allows this 
* mechanism to generate PCI bus interrupts. 
* 
* RETURNS: The results of sysDec2155xBusIntGen or sysMpicBusIntGen. 
* 
* SEE ALSO: sysBusIntAck() 
*/ 
 
STATUS sysBusIntGen 
    ( 
    int level,          /* interrupt level to generate (not used) */ 
    int vector          /* interrupt vector for interrupt */ 
    ) 
    { 
 
#ifdef INCLUDE_DEC2155X 
    return (sysDec2155xBusIntGen (level, vector)); 
#endif 
    return (OK); 
    } 
 
 
#ifdef INCLUDE_SM_NET 
/***************************************************************************** 
* 
* sysSmParamsCompute - Compute dynamic run-time shared memory parameters. 
* 
* This function computes the shared memory the SM_INT_ARG1 parameter 
* (saved in smIntArg1). 
* 
* RETURNS: NA 
*/ 
 
LOCAL void sysSmParamsCompute (void) 
    { 
    smIntArg1 = PCI_SPACE_MEM_SEC; 
    } 
 
 
/***************************************************************************** 
* 
* sysSmArg2Compute - Compute dynamic run-time shared memory parameters. 
* 
* This function computes the shared memory SM_INT_ARG2 parameter. 
* 
* RETURNS: NA 
*/ 
 
int sysSmArg2Compute (void) 
    { 
    UINT32 smAddr; 
    UINT32 pciAddr; 
    UINT32 locAddr; 
 
    pciConfigInLong (0, DEC2155X_PCI_DEV_NUMBER, 0, 
                     DEC2155X_CFG_SEC_CSR_MEM_BAR, &pciAddr); 
    pciAddr += DEC2155X_CSR_SEC_SET_IRQ + (DEC2155X_SM_DOORBELL_BIT >= 8); 
    sysBusToLocalAdrs (PCI_SPACE_MEM_PRI, (char *)pciAddr, 
                       (char **)&locAddr); 
 
    /* Wait for Drawbridge to be configured by host */ 
 
    while (sysLocalToBusAdrs (PCI_SPACE_MEM_SEC, (char *)locAddr, 
                       (char **)&smAddr) != OK ); 
 
    return((int)smAddr); 
    } 
 
 
#if defined(SYS_SM_ANCHOR_POLL_LIST) && defined(INCLUDE_DEC2155X) 
/***************************************************************************** 
* 
* sysSmAnchorCandidate - Dynamically poll for the anchor address. 
* 
* This function will determine whether a given bus, device, and function 
* number correspond to a defined device on the SYS_SM_ANCHOR_POLL_LIST 
* 
* RETURNS: TRUE if device is on the SYS_SM_ANCHOR_POLL_LIST 
* FALSE if device is not on the SYS_SM_ANCHOR_POLL_LIST 
*/ 
 
LOCAL UINT sysSmAnchorCandidate 
    ( 
    UINT busNo,         /* candidate's PCI bus number */ 
    UINT deviceNo,      /* candidate's PCI device number */ 
    UINT funcNo         /* candidate's PCI function number */ 
    ) 
    { 
    UINT i; 
    UINT found = FALSE; 
    UINT devVend; 
    UINT subIdVend; 
 
    for (i = 0 ; (sysSmAnchorPollList[i].devVend != 0xffffffff) ; i++) 
        { 
        sysPciConfig21554InLong (busNo, deviceNo, funcNo, PCI_CFG_VENDOR_ID, 
                             &devVend); 
        if (devVend == sysSmAnchorPollList[i].devVend) 
            { 
 
            sysPciConfig21554InLong (busNo, deviceNo, funcNo, 
                                     PCI_CFG_SUB_VENDER_ID, &subIdVend); 
            if (subIdVend == sysSmAnchorPollList[i].subIdVend) 
                { 
                found = TRUE; 
                break; 
                } 
            } 
        } 
    return (found); 
    } 
#endif /* SYS_SM_ANCHOR_POLL_LIST && INCLUDE_DEC2155X */ 
 
 
/***************************************************************************** 
* 
* sysSmAnchorFind - Dynamically poll for the anchor address. 
* 
* This function makes one pass on a polling list of devices in an attempt 
* to find the shared memory anchor address.  The list of devices polled 
* includes the system memory DRAM if SYS_SM_SYSTEM_MEM_POLL is defined. 
* In addition, if SYS_SM_ANCHOR_POLL_LIST is defined, the devices on this 
* list are also included in the search.  If SYS_SM_ANCHOR_POLL_LIST is not 
* defined, then all devices on the "pciBus" parameter are polled for the 
* existence of the shared memory anchor.  The "window" which is searched 
* corresponds to PCI_CFG_BASE_ADDRESS_0 and the offset queried is 
* SM_ANCHOR_OFFSET.  If a value of SM_READY is found, the shared memory 
* anchor is assumed to be at the corresponding address. 
* 
* RETURNS: OK if SM_READY found, 'anchor' parameter will contain local address. 
* ERROR if SM_READY not find after one scan of the list. 
*/ 
 
LOCAL STATUS sysSmAnchorFind 
    ( 
    int     pciBus,     /* PCI bus number */ 
    char ** anchor      /* return variable */ 
    ) 
    { 
    SM_ANCHOR * tryAddr; 
 
#ifdef INCLUDE_DEC2155X 
    UINT32 devVend; 
    UINT32 memBarVal; 
    int    deviceNo; 
    int    maxDevNo; 
#endif 
 
#ifdef SYS_SM_SYSTEM_MEM_POLL 
    LOCAL   UINT beat1 = 0; 
    LOCAL   UINT beat2 = 0; 
#endif 
 
    if (sysProcNumGet () == 0) 
        { 
#if (SM_OFF_BOARD == FALSE) 
        *anchor = (char *)LOCAL_SM_ANCHOR_ADRS; 
        return (OK); 
#else 
        /* 
         * Anchor in host DRAM: 
         * We will receive an ERROR return initially if the host has not 
         * yet enabled the bus master bit in the primary PCI command register. 
         */ 
 
        if ( sysBusToLocalAdrs (PCI_SPACE_MEM_SEC, 
                                (char *)(CPCI_MSTR_MEM_BUS + SM_ANCHOR_OFFSET), 
                                (char **)&tryAddr) != OK ) 
            return (ERROR); 
 
        *anchor = (char *)tryAddr; 
        return (OK); 
#endif 
        } 
 
#ifdef SYS_SM_SYSTEM_MEM_POLL 
 
    /* 
     * Look in host DRAM for anchor: 
     * We will receive an ERROR return initially if the host has not 
     * yet enabled the bus master bit in the primary PCI command register. 
     */ 
 
    if ( sysBusToLocalAdrs (PCI_SPACE_MEM_SEC, 
                            (char *)(CPCI_MSTR_MEM_BUS + SM_ANCHOR_OFFSET), 
                            (char **)&tryAddr) != OK ) 
        return (ERROR); 
 
    /* 
     * Check for SM_READY to appear and for a heartbeat that changes 
     * from one call into this routine to the next. 
     */ 
 
    if (tryAddr->readyValue == SM_READY) 
        { 
        beat2 = *(UINT *)((UINT)(tryAddr->smPktHeader) + (UINT)tryAddr); 
        if (beat1 == 0) 
 
            /* 
             * First time through we just record the heartbeat value so 
             * we can check in on the next call. 
             */ 
 
            beat1 = beat2; 
        else 
            { 
 
            /* 
             * On second and subsequent calls, we just check for a change 
             * in the heartbeat 
             */ 
 
            if (beat1 != beat2) 
                { 
                *anchor = (char *)tryAddr; 
                return (OK); 
                } 
            } 
        } 
 
#endif /* SYS_SM_SYSTEM_MEM_POLL */ 
 
#ifdef INCLUDE_DEC2155X 
 
#   ifdef SYS_SM_ANCHOR_POLL_LIST 
 
    /* if polling list is defined but empty then we're done */ 
 
    if (sysSmAnchorPollList[0].devVend != 0xffffffff) 
#   endif 
        { 
        if (pciBus == SYS_SM_CPCI_BUS_NUMBER) 
            maxDevNo = 16; 
        else 
            maxDevNo = PCI_MAX_DEV; 
 
        for (deviceNo = 0; deviceNo < maxDevNo; deviceNo++) 
            { 
            if (sysPciConfig21554InLong (pciBus, deviceNo, 0, 0, 
                                         &devVend) != OK) 
                continue; 
 
#   ifdef SYS_SM_ANCHOR_POLL_LIST 
            if (!sysSmAnchorCandidate (pciBus, deviceNo, 0)) 
                continue; 
#   endif 
 
            if (sysPciConfig21554InLong (pciBus, deviceNo, 0, 
                                 PCI_CFG_BASE_ADDRESS_0, &memBarVal) != OK) 
                continue; 
 
            if (sysBusToLocalAdrs (PCI_SPACE_MEM_SEC, 
                                   (char *)(memBarVal + SM_ANCHOR_OFFSET), 
                                   (char **)&tryAddr) != OK) 
                continue; 
 
            if (tryAddr->readyValue == SM_READY) 
                { 
                *anchor = (char *)tryAddr; 
                return (OK); 
                } 
            } 
        } 
#endif /* INCLUDE_DEC2155X */ 
    return (ERROR); 
    } 
 
 
 
/***************************************************************************** 
* 
* sysSmAnchorPoll - Dynamically poll for the anchor address. 
* 
* This function will loop and repeatedly call a polling routine to search 
* for the shared memrory anchor on the cPCI bus number indicated by 
* SYS_SM_CPCI_BUS_NUMBER.  It returns with an anchor address only when the 
* anchor is actually found. 
* 
* RETURNS: Anchor address 
*/ 
 
LOCAL char *sysSmAnchorPoll (void) 
    { 
 
    char *anchor; 
    int  count = 0; 
 
    while (sysSmAnchorFind (SYS_SM_CPCI_BUS_NUMBER, &anchor) != OK) 
        { 
        if (((++count) % 6) == 0) 
            printf ("sysSmAnchorPoll() searching for shared memory anchor\n"); 
        sysUsDelay (1000000); 
        } 
    return (anchor); 
    } 
 
 
/***************************************************************************** 
* 
* sysSmAnchorAdrs - Dynamically compute anchor address 
* 
* This function is called if SM_OFF_BOARD == TRUE, that is the shared memory 
* anchor is not on this node.  If the anchor has been found by a previous 
* call to this routine, the previously found anchor value is returned. 
* Otherwise if this BSP is running as a PCI Host, a polling routine is called 
* which will dynamically search for the anchor. If this BSP is running in 
* Slave-Mode, the shared memory anchor must be in the local PCI Host's DRAM. 
* This routine is aliased to SM_ANCHOR_ADRS and thus is first called when 
* SM_ANCHOR_ADRS is first referenced. 
* 
* RETURNS: Anchor address 
*/ 
 
char *sysSmAnchorAdrs (void) 
    { 
    static char *anchorAddr; 
    static int anchorFound = FALSE; 
 
    if (anchorFound) 
        return (anchorAddr); 
 
    /* perform the standard search */ 
 
    anchorAddr = sysSmAnchorPoll (); 
 
    anchorFound = TRUE; 
    return (anchorAddr); 
    } 
#endif /* INCLUDE_SM_NET */ 
 
 
/******************************************************************************* 
* 
* sysMailboxInt - mailbox interrupt handler 
* 
* The interrupt dispatcher will clear the in-bound interrupt for us, 
* so all we need to do is call the mailbox routine, if it exists. 
*/ 
 
void sysMailboxInt (void) 
    { 
#ifdef INCLUDE_SM_NET 
    if (sysMailbox.routine != NULL) 
        (sysMailbox.routine) (sysMailbox.arg); 
#endif /* INCLUDE_SM_NET */ 
    } 
 
 
/******************************************************************************* 
* 
* sysMailboxConnect - connect a routine to the in-bound mailbox interrupt 
* 
* This routine connects a local interrupt service routine to a operating mode 
* dependent interrupt vector.  If DEC2155X driver support was included, then 
* the interrupt handler is connected to the 2155X's interrupt vector. 
* 
* NOTE: The mailbox interrupt is DEC2155X_MAILBOX_INT_VEC. 
* 
* RETURNS: OK, or ERROR if the routine cannot be connected to the interrupt. 
* 
* SEE ALSO: intConnect(), sysMailboxEnable() 
*/ 
 
STATUS sysMailboxConnect 
    ( 
    FUNCPTR routine,    /* routine called at each mailbox interrupt */ 
    int arg             /* argument with which to call routine      */ 
    ) 
    { 
#ifdef INCLUDE_SM_NET 
    if (!sysMailbox.connected) 
        { 
 
#ifdef INCLUDE_DEC2155X 
        if (intConnect (INUM_TO_IVEC(DEC2155X_MAILBOX_INT_VEC), 
                        sysMailboxInt, NULL) == ERROR) 
            return (ERROR); 
        (void) sysDec2155xIntClear (DEC2155X_MAILBOX_INT_VEC); 
#endif 
        } 
 
    /* 
     * Save the routine address and argument, then mark the mailbox interrupt 
     * handler connected. 
     */ 
 
    sysMailbox.arg       = arg; 
    sysMailbox.routine   = routine; 
    sysMailbox.connected = TRUE; 
#endif /* INCLUDE_SM_NET */ 
 
    return (OK); 
    } 
 
 
/******************************************************************************* 
* 
* sysMailboxEnable - enable the in-bound mailbox interrupt 
* 
* This routine enables an operating mode dependent in-bound mailbox interrupt. 
* If the BSP was built with DEC2155X support and the BSP is operating as the 
* (local) PCI Host, sysDec2155xIntEnable is called to enable the proper bit in 
* the 2155X's Secondary mailbox register. 
* 
* RETURNS: The results of sysDec2155xIntEnable 
* 
* SEE ALSO: sysMailboxConnect(), sysMailboxDisable() 
*/ 
 
STATUS sysMailboxEnable 
    ( 
    char *mailboxAdrs           /* address of mailbox (ignored) */ 
    ) 
    { 
 
#ifdef INCLUDE_DEC2155X 
    return (sysDec2155xIntEnable (DEC2155X_MAILBOX_INT_VEC)); 
#endif 
    return (OK); 
    } 
 
 
/******************************************************************************* 
* 
* sysMailboxDisable - disable the in-bound mailbox interrupt 
* 
* This routine disables an operating mode dependent in-bound mailbox interrupt. 
* If the BSP was built with DEC2155X support and the BSP is operating as the 
* (local) PCI Host, sysDec2155xIntDisable is called to disable the proper bit in 
* the 2155X's Secondary mailbox register. 
* 
* RETURNS: The results of sysDec2155xIntDisable 
* 
* SEE ALSO: sysMailboxConnect(), sysMailboxEnable() 
*/ 
 
STATUS sysMailboxDisable 
    ( 
    char *mailboxAdrs           /* address of mailbox (ignored) */ 
    ) 
    { 
 
#ifdef INCLUDE_DEC2155X 
    /* calculate the bit in the register */ 
 
    bit = DEC2155X_MAILBOX_INT_VEC - DEC2155X_DOORBELL0_INT_VEC; 
 
    /* 
     * clear any pending interrupt by writing a one to the proper bit in the 
     * the Secondary Clear IRQ Register 
     */ 
 
    sysPciOutWord (DEC2155X_CSR_ADRS(DEC2155X_CSR_SEC_CLR_IRQ), 
                   (UINT16)(1 << bit)); 
 
    /* disable the interrupt */ 
 
    return (sysDec2155xIntDisable (DEC2155X_MAILBOX_INT_VEC)); 
#endif 
    return (OK); 
    } 
 
 
 
void SerialTest(char *TestMsg) 
{ 
    ULONG msgIx,msgSize; 
    /*char TestMsg[]= "This is a test string";*/ 
    SIO_CHAN * pSioChan; 
    msgSize = strlen(TestMsg); 
    sysSerialHwInit (); 
 
    pSioChan = sysSerialChanGet (0); 
 
    sioIoctl (pSioChan, SIO_MODE_SET, (void *) SIO_MODE_POLL); 
 
    for (msgIx = 0; msgIx < msgSize; msgIx++) 
    	{ 
    	while (sioPollOutput (pSioChan, TestMsg[msgIx]) == EAGAIN); 
    	}	 
} 
 
 
 
 
/************************************************************** 
 * Get internal bus speed, megahertz 
 */ 
UINT  sysGetBusSpd(void) 
{ 
	UINT8  ucPCR; 
	UINT   dwBusSpd = 66; 
	 
	/* 读PLL配置寄存器 */ 
	ucPCR = sysPciConfigInByte ((UINT8*)0x800000E2);  
	if((ucPCR & 0xf8) == 0x08 ) 
	{ 
		dwBusSpd = 100; 
	} 
	 
	if((ucPCR & 0xf8) == 0x50 ) 
	{ 
		dwBusSpd = 66; 
	} 
	 
	return (dwBusSpd); 
} 
 
/************************************************************** 
 * Get internal bus speed, Hz 
 */ 
UINT	sysGetBusSpdHertz(void) 
{ 
	UINT8  ucPCR; 
	UINT   dwBusSpd = 66700000; 
	 
	/* 读PLL配置寄存器 */ 
	ucPCR = sysPciConfigInByte ((UINT8*)0x800000E2); 
	if((ucPCR & 0xf8) == 0x08 ) 
	{ 
		dwBusSpd = 100000000; 
	} 
	 
	if((ucPCR & 0xf8) == 0x50 ) 
	{ 
		dwBusSpd = 66700000; 
	} 
	 
	return (dwBusSpd); 
} 
 
/************************************************************** 
 * Get cpu speed, Hz 
 */ 
UINT  sysGetMpuSpd(void) 
{ 
	return(DEFAULT_INTERNAL_CLOCK); 
} 
 
/*************************************************************** 
 * Get PCI bus speed, Hz 
 */ 
UINT  sysGetPciSpd(void) 
{ 
	return(DEFAULT_PCI_CLOCK); 
} 
 
 
/******************************************************************************* 
* 
* sysMsDelay - delay for the specified amount of time (MS) 
* 
* This routine will delay for the specified amount of time by counting 
* decrementer ticks. 
* 
* This routine is not dependent on a particular rollover value for 
* the decrementer, it should work no matter what the rollover 
* value is. 
* 
* A small amount of count may be lost at the rollover point resulting in 
* the sysMsDelay() causing a slightly longer delay than requested. 
* 
* This routine will produce incorrect results if the delay time requested 
* requires a count larger than 0xffffffff to hold the decrementer 
* elapsed tick count.  For a System Bus Speed of 67 MHZ this amounts to 
* about 258 seconds. 
* 
* RETURNS: N/A 
*/ 
 
void sysMsDelay 
    ( 
    UINT        delay                   /* length of time in MS to delay */ 
    ) 
    { 
    register UINT oldval;               /* decrementer value */ 
    register UINT newval;               /* decrementer value */ 
    register UINT totalDelta;           /* Dec. delta for entire delay period */ 
    register UINT decElapsed;           /* cumulative decrementer ticks */ 
 
    /* 
     * Calculate delta of decrementer ticks for desired elapsed time. 
     * The macro DEC_CLOCK_FREQ MUST REFLECT THE PROPER 6xx BUS SPEED. 
     */ 
 
    totalDelta = ((DEC_CLOCK_FREQ / 4) / 1000) * delay; 
 
    /* 
     * Now keep grabbing decrementer value and incrementing "decElapsed" until 
     * we hit the desired delay value.  Compensate for the fact that we may 
     * read the decrementer at 0xffffffff before the interrupt service 
     * routine has a chance to set in the rollover value. 
     */ 
 
    decElapsed = 0; 
 
    oldval = vxDecGet (); 
 
    while (decElapsed < totalDelta) 
        { 
        newval = vxDecGet (); 
 
        if ( DELTA(oldval,newval) < 1000 ) 
            decElapsed += DELTA(oldval,newval);  /* no rollover */ 
        else 
            if (newval > oldval) 
                decElapsed += abs((int)oldval);  /* rollover */ 
 
        oldval = newval; 
        } 
    } 
 
/******************************************************************************* 
* 
* sysDelay - delay for approximately one millisecond 
* 
* Delay for approximately one milli-second. 
* 
* RETURNS: N/A 
*/ 
 
void sysDelay (void) 
    { 
    sysMsDelay (1); 
    } 
 
 
void led11(unsigned short i) 
{ 
	unsigned char * ledbit; 
	ledbit=(unsigned char *)(0xff000000); 
	if(i==0) 
	*ledbit&=~(0x01<<(7-7)); 
	else 
	*ledbit|=0x01<<(7-7);  
	} 
void led12(unsigned short i) 
{ 
	unsigned char * ledbit; 
	ledbit=(unsigned char *)(0xff000000); 
	if(i==0) 
	*ledbit&=~(0x01<<(7-6)); 
	else 
	*ledbit|=0x01<<(7-6);  
} 
void flashled(unsigned short whichled,unsigned short flashnumber) 
{	 
	int i,j ; 
	switch(whichled) 
	{ 
		case 1: 
			for (i=0;i