/*ixdp2400.c - npu, master/slave and flashmode identification routines*/ /* modification history -------------------- 01a,14jan03,scm add enum PciBarId here... rev, 1apr02, vgd - creation */ #include "vxWorks.h" #include "config.h" #include "ixdp2400.h" #include "ixdp2400Misc.h" #define QDR2 /*global variables*/ UINT32 strapOptionsVal = 0; UINT32 sramSize =0; UINT32 ixp2400XtalFreq; UINT32 sramChanSize[4]={0,0,0,0}; static UINT32 _period; struct board_config *pBoardCfgData =(struct board_config *)IXP2400_SCRATCH_BASE; struct SPCfg spCfgCpld; /*externs*/ extern UINT32 boardRev; /****************************************************************************** * int isNPUMaster(void) - identify whether the code is running on Master NPU or * slave NPU *This routine reads the STRAP OPTIONs register and if bit 2 is 1, then the npu *is master. It returns a value representative of whether or not running on the *master NPU * * RETURNS: TRUE if running on master FALSE if running on slave. */ int isNPUMaster (void) { FAST int locKey; /* Lock Interrupts */ locKey = intLock(); /*Read STRAP_OPTIONS register*/ IXP2400_REG_READ(IXP2400_STRAP_OPTIONS,strapOptionsVal); /* UnLock Interrupts */ intUnlock (locKey); return ( (strapOptionsVal & CFG_PCI_BOOT_HOST) ? TRUE : FALSE); } /****************************************************************************** * int isNPUFlashEnabled(void) - identify the flash on the NPU where the code is running has flash or not. *This routine reads the STRAP OPTIONs register and returns a value representative *of whether the nPU's flash is enabled or not. The master NPU flash is always *enabled, while the slave NPU's flash could be either enabled or disabled * * RETURNS: TRUE if Flash enabled FALSE if Flash disabled. */ int isNPUFlashEnabled (void) { FAST int locKey; /* Lock Interrupts */ locKey = intLock(); /*Read STRAP_OPTIONS register*/ IXP2400_REG_READ(IXP2400_STRAP_OPTIONS,strapOptionsVal); /* UnLock Interrupts */ intUnlock (locKey); return ( (strapOptionsVal & CFG_PROM_BOOT) ? TRUE : FALSE); } /******************************************************************************** *int getProductID (void) - return the product id *This function returns the major product type, minor product type, major revision, *and minor revision fields. *[31:21] RES Reserved *[20:16] MAJ_PROD_TYPE 0 = IXP2000 others will be assigned as needed *[15:8] MIN_PROD_TYPE 0 = IXP2800 with Crypto * 1 = IXP2800 * 2 = IXP2400 * *[7:4] MAJ_REV Current Revision. Starts at 0 *[3:0] MIN_REV Current Revision. Starts at 0 * *Return Value: IDData value */ int getProductID (unsigned int mask){ int IDData; FAST int locKey; /* Lock Interrupts */ locKey = intLock(); /*Read the Product ID register */ IDData=((*(volatile unsigned int *)(IXP2400_PROD_ID))&mask); /* UnLock Interrupts */ intUnlock (locKey); return(IDData); } /****************************************************************************** * STATUS sysCFGDATAcopy(void ) - copies config data on I2C EEPROM attached to * master onto to SRAM on the master NPU. * *Return: OK if sucessful else ERROR */ STATUS sysCFGDATAcopy(void) { int i; struct EEPROM_CONTENT temp; FAST int locKey; if(isNPUMaster()) { /* read config data and save it*/ i2c_seq_read(0xa2, 0x0, (unsigned char *)&temp, CONFIG_DATA_SIZE); if(temp.prom_fmt == '0') { locKey = intLock (); for(i = 0; i < CONFIG_DATA_SIZE; i += 4) { *((UINT32 *)((UINT32)&(pBoardCfgData->config_data) + i)) = *((UINT32 *)((UINT32)&temp + i)); } intUnlock (locKey); pBoardCfgData->config_valid = CONFIG_DATA_VALID; } } return OK; } /****************************************************************************** * STATUS ixdp2400SRAMInit(int channel, int skipCsr, int frmPci, int offset ) * Initializes SRAM with max size and the dynamically sizes it. * *Return: OK if sucessful else ERROR */ STATUS ixdp2400SRAMInit(int channel, int skipCsr, int frmPci, int offset) { int i; int j; int qdrChSize = MIN_SRAM_SIZE; int qdrChanCsrBase; int qdrBase; volatile UINT32 *sramCmpLoc; volatile UINT32 *sramTstLoc; int sramDetected =0; UINT32 sramCsrVal, temp, addr; FAST int locKey; #ifndef INCLUDE_PCI qdrChanCsrBase = IXP2400_QDR_CH_CSR_BASE + (channel * 0x400000); qdrBase = IXP2400_SRAM_CH0_BASE + (channel * 0x10000000); #else /*calculate the csr base and qdr base*/ if(frmPci) { qdrChanCsrBase = pSlave->bar[CSR_BAR].address + SLAVE_QDR_CH_BASE + (channel * 0x400); qdrBase = pSlave->bar[SRAM_BAR].address + (channel * 0x10000000); } else { qdrChanCsrBase = IXP2400_QDR_CH_CSR_BASE + (channel * 0x400000); qdrBase = IXP2400_SRAM_CH0_BASE + (channel * 0x10000000); } #endif /* Init CSRs*/ if(!skipCsr) { locKey = intLock (); /*Program Slew rate tables for normal Rcomp operation*/ /* Rcomp registers are only 4 bytes distant. So, when this function * will be called by pci init it won't work properly due to pci bug. * Insert dummy read cycle in between write operations */ for(addr = 0x340; addr { IXP2400_REG_WRITE((qdrChanCsrBase+addr),0xCCCC); #if A0_REV IXP2400_REG_READ((qdrChanCsrBase+addr),temp); #endif } /*Invert rcomp polarity*/ IXP2400_REG_WRITE((qdrChanCsrBase+IXP2400_QDR_RCMP_SETUP_CONTROL_OFF), 0x00010060); #ifdef QDR1 /* Set 50 ohm ref resistor in real board/tester*/ IXP2400_REG_WRITE((qdrChanCsrBase+IXP2400_QDR_RCOMP_OFF), 0xFFFF3); /*wait for 1 ms*/ delayUSec(1000); IXP2400_REG_WRITE((qdrChanCsrBase+IXP2400_QDR_RX_DLL_OFF),0x48); #else /* Set 50 ohm ref resistor in real board/tester*/ IXP2400_REG_WRITE((qdrChanCsrBase+IXP2400_QDR_RCOMP_OFF), 0x518C3); /*wait for 1 ms*/ delayUSec(1000); IXP2400_REG_WRITE((qdrChanCsrBase+IXP2400_QDR_RX_DLL_OFF),0x52); #endif IXP2400_REG_WRITE((qdrChanCsrBase+IXP2400_QDR_RX_DESKEW_OFF),0x12); /*Set SRAM CSR to use max size*/ IXP2400_REG_WRITE((qdrChanCsrBase+IXP2400_QDR_CH_CONTROL_OFF),MAX_SRAM_SIZE_CSR_VAL); /*wait for 3 ms*/ delayUSec(3000); IXP2400_REG_WRITE((qdrChanCsrBase+IXP2400_QDR_RD_PTR_OFF), 0x4); /*read RD_PTR back to ensure write is completed*/ IXP2400_REG_READ((qdrChanCsrBase+IXP2400_QDR_RD_PTR_OFF), temp); intUnlock (locKey); } if(!frmPci) { locKey = intLock (); for(j=1;j { IXP2400_REG_WRITE((qdrChanCsrBase+IXP2400_QDR_CH_CONTROL_OFF),(PIPELINE|(j /*wait for 3 ms*/ delayUSec(3000); /*Now probe for the right size*/ for(i = 0; i < SRAM_SIZE_LOOPS; i++) { sramCmpLoc = (UINT32 *)(qdrBase + qdrChSize); *sramCmpLoc = 0xAA55AA55; if(*sramCmpLoc != 0xAA55AA55) { break; } sramCmpLoc = (UINT32 *)(qdrBase + offset); sramTstLoc = (UINT32 *)(qdrBase + (qdrChSize/2) + offset); *sramCmpLoc = 0xA5A5A5A5; *sramTstLoc = 0x55AAAA55; if(*sramCmpLoc == *sramTstLoc) { break; } sramDetected = 1; qdrChSize *= 2; } } if(!sramDetected) { qdrChSize = 0; } sramChanSize[channel] = qdrChSize; /*save sram size*/ sramSize += qdrChSize; temp = 1024 * 1024; for(i = 0; i < 6; i++) { temp = temp * 2; if(temp == qdrChSize) break; } sramCsrVal = i sramCsrVal = sramCsrVal | PIPELINE; /* init channel 0*/ IXP2400_REG_WRITE((qdrChanCsrBase+IXP2400_QDR_CH_CONTROL_OFF), sramCsrVal); intUnlock (locKey); } if(!frmPci && qdrChSize ) { locKey = intLock (); /*Init whole SRAM with 0x0 so that the parity errors are not generated*/ memset((char *)(qdrBase+offset), 0, (qdrChSize-offset)); if(boardRev >= 3) { /*Parity is working only on board rev3 and above*/ *((UINT32*)(qdrChanCsrBase + IXP2400_QDR_CH_CONTROL_OFF)) |= PARITY_ENABLE; } intUnlock (locKey); } return OK; } void ixp2400Timer1Init(UINT32 period) { FAST int locKey; _period = period; locKey = intLock (); /* load the counter */ *((UINT32 *)IXP2400_TIMER1_LOAD) = period; /* start the timer */ *((UINT32 *)IXP2400_TIMER1_CONTROL) = (1 intUnlock (locKey); } /* Read the current value of the clock, returning the number of hardware * "ticks" that have occurred (i.e. how far away the current value is from * the start) */ void ixp2400Timer1read(UINT32 *pvalue) { FAST int locKey; locKey = intLock (); /* read the current counter value */ *pvalue = *((UINT32 *)IXP2400_TIMER1_STATUS); intUnlock (locKey); } /* Delay for some usecs. */ void delayUSec(UINT32 delay) { UINT32 now, last, diff, ticks, ticks_per_usec; ticks_per_usec = ixp2400XtalFreq / 1000000; ixp2400Timer1read(&last); diff = ticks = 0; while (delay > ticks) { ixp2400Timer1read(&now); if (now > last) diff += ((_period - now) + last); else diff += (last - now); last = now; if (diff >= ticks_per_usec) { ticks += (diff / ticks_per_usec); diff %= ticks_per_usec; } } } void getXtalFreq(void) { UINT32 cpld_rev; UINT32 board_rev; FAST int locKey; locKey = intLock (); cpld_rev = *((volatile UINT32*)(CPLD_REV)); intUnlock (locKey); board_rev = (cpld_rev & 0xF0) >> 4; if(board_rev < 4) { ixp2400XtalFreq = IXP2400_DEFAULT_CLK_RATE / 12; } else { int numerator, denominator; int denom_array[] = {2, 4, 8, 16, 1, 2, 4, 8}; numerator = ((*(volatile UINT32*)(SYS_CLK_M)) & 0xFF)*2; denominator = denom_array[((*(volatile UINT32*)(SYS_CLK_N)) & 0x7)]; ixp2400XtalFreq = (3125000 * numerator) / denominator; ixp2400XtalFreq = ixp2400XtalFreq/2; } } void ixdp2400SPCfgSave(struct SPCfg *slowPortCfg) { FAST int locKey; locKey = intLock (); IXP2400_REG_READ(IXP2400_SP_CCR, slowPortCfg->spCCR); IXP2400_REG_READ(IXP2400_SP_WTC2, slowPortCfg->spWTC2); IXP2400_REG_READ(IXP2400_SP_RTC2, slowPortCfg->spRTC2); IXP2400_REG_READ(IXP2400_SP_PCR, slowPortCfg->spPCR); IXP2400_REG_READ(IXP2400_SP_ADC, slowPortCfg->spADC); intUnlock (locKey); } void ixdp2400SPCfgRestore(struct SPCfg *slowPortCfg) { FAST int locKey; locKey = intLock (); IXP2400_REG_WRITE(IXP2400_SP_CCR, slowPortCfg->spCCR); IXP2400_REG_WRITE(IXP2400_SP_WTC2, slowPortCfg->spWTC2); IXP2400_REG_WRITE(IXP2400_SP_RTC2, slowPortCfg->spRTC2); IXP2400_REG_WRITE(IXP2400_SP_PCR, slowPortCfg->spPCR); IXP2400_REG_WRITE(IXP2400_SP_ADC, slowPortCfg->spADC); intUnlock (locKey); } #ifdef _DIAB_TOOL __asm void sync_dcache () { % lab loop_667; ! "r0", "r1" mov r0, #0x70000000 add r1, r0, #0x8800 loop_667: mcr p15, 0, r0, c7, c2, 5 add r0, r0, #32 teq r1, r0 bne loop_667 mcr p15, 0, r0, c7, c6, 0 mrc p15, 0, r1, c2, c0, 0 mov r1, r1 sub pc, pc, #4 mcr p15, 0, r0, c7, c10, 4 mrc p15, 0, r1, c2, c0, 0 mov r1, r1 sub pc, pc, #4 nop } #endif void dcacheSync(void) { #ifdef _DIAB_TOOL sync_dcache (); #else /* The best way to evict a dirty line is by using the */ /* line allocate operation on non-existent memory. */ __asm ("mov r0, #0x70000000;" /* use upper 256M of SDRAM for cache flush region */ "add r1, r0, #0x8800;" /* 32KB cache + 2KB mini cache */ "667: " "mcr p15,0,r0,c7,c2,5;" /* allocate a line */ "add r0, r0, #32;" /* 32 bytes/line */ "teq r1, r0;" "bne 667b;" "mcr p15,0,r0,c7,c6,0;" /* invalidate data cache */ /* cpuwait */ "mrc p15,0,r1,c2,c0,0;" /* arbitrary read */ "mov r1,r1;" "sub pc,pc,#4;" "mcr p15,0,r0,c7,c10,4;" /* and drain the write buffer */ /* cpuwait */ "mrc p15,0,r1,c2,c0,0;" /* arbitrary read */ "mov r1,r1;" "sub pc,pc,#4;" "nop" : : : "r0","r1" /* Clobber list */ ); #endif } void dcacheOn(void) { /* Enable data cahce and MMU by writing 1 to bits 0 and 2*/ __asm ("mrc p15,0,r1,c7,c10,4;" /* drain write buffer */ "mrc p15,0,r1,c1,c0,0;" "orr r1,r1,#0x0004;" "mcr p15,0,r1,c1,c0,0;" "mrc p15,0,r1,c2,c0,0;" /* arbitrary read*/ "mov r1,r1;" "sub pc,pc,#4;" "mcr p15,0,r1,c7,c6,0;" /* invalidate data cache*/ ); } void dcacheOff(void) { __asm ("mrc p15,0,r1,c1,c0,0;" "bic r1,r1,#0x0004;" "mcr p15,0,r1,c1,c0,0;" "mrc p15,0,r1,c2,c0,0;" /* arbitrary read*/ "mov r1,r1;" "sub pc,pc,#4;" "mcr p15,0,r1,c7,c6,0;" /* invalidate data cache*/ "mrc p15,0,r1,c2,c0,0;" /* arbitrary read*/ "mov r1,r1;" "sub pc,pc,#4;" ); } #ifdef _DIAB_TOOL __asm void flush_dcache(void) { % lab loop_fd1; ! "r0", "r1", "r2" ldr r0, =0x0 add r1, r0, #8192 loop_fd1: ldr r2, [r0], #32 teqs r1, r0 bne loop_fd1 mcr p15, 0, r0, c7, c10, 4 mcr p15, 0, a1, c7, c6, 0 mov pc, lr } #endif void dcacheFlush(void) { #ifdef _DIAB_TOOL flush_dcache(); #else __asm ("ldr r0,=0x0;" "add r1,r0,#8192;" "1:;" "ldr r2,[r0],#32;" "teqs r1,r0;" "bne 01b;" "mcr p15,0,r0,c7,c10,4;" "mcr p15,0,a1,c7,c6,0;" "mov pc,lr;" ); #endif } #ifdef _DIAB_TOOL __asm int cp15_val (void) { ! "r0" mrc p15, 0, r0, c1, c0, 0 } #endif unsigned int getCP15(void) { unsigned int x = 0; #ifdef _DIAB_TOOL x = cp15_val(); #else __asm ("mrc p15, 0, %0, c1, c0, 0;" : "=r"(x) :); #endif return x; }