oempci.c
来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C语言 代码 · 共 1,258 行 · 第 1/4 页
C
1,258 行
/* These functions are used to generate PCI configuration bus cycles. They all */
/* return 0 on success and non-zero on error. An error should be returned on */
/* a master abort for example, so that the presense/absense of a device can be */
/* established. Note that all configuration accesses are DWORD wide on the */
/* bus itself, so that the simulated BYTE and WORD accesses provided by these */
/* functions must be read/modify/writes of DWORDs. */
/* The parameters are: */
/* bBusNo - Target bus number for the configuration cycle. Type 0 or Type 1 */
/* bus cycles will be automatically based on the target specified. */
/* Since bus 0 is assumed to be directly connected to the host */
/* bridge, bus 0 references will generate Type 0 cycles and any */
/* other number will generate a Type 1 cycle. */
/* bDevNo - Device number on the target bus. The PCI specification allows */
/* device numbers from 0 through 20. Device 0 corresponds to */
/* setting bit 11 and clearing bits 12-31 in a Type 0 bus cycle. */
/* Device 19 corresponds to setting bit 30 and clearing bits */
/* 11-29 and 31, */
/* bFuncNo - The function being selected on the target device. This can be in */
/* the range of 0 to 7. */
/* bOffset - The offset into the specified configuration space. Note that */
/* the offset will only be aligned to the size of the data item */
/* being requested. For example, a byte read of bOffset = 7 would */
/* return the high order byte of the second DWORD. */
/* xData - Pointer to the variable where the result should be stored. */
void OEM_ReadConfigByte( DWORD dwBusNo, DWORD dwDevNo, DWORD dwFuncNo, DWORD dwOffset, BYTE *pbData ) {
DWORD dwData;
OEM_ReadConfigDword( dwBusNo, dwDevNo, dwFuncNo, dwOffset & 0xFC, &dwData );
*pbData = (BYTE)(dwData >> (8 * (dwOffset & 0x03)));
} /* OEM_ReadConfigByte() */
void OEM_WriteConfigByte( DWORD dwBusNo, DWORD dwDevNo, DWORD dwFuncNo, DWORD dwOffset, BYTE bData ) {
DWORD dwData;
OEM_ReadConfigDword( dwBusNo, dwDevNo, dwFuncNo, dwOffset & 0xFC, &dwData );
dwData &= ~(0x000000FF << (8 * (dwOffset & 0x03)));
dwData |= ((DWORD)bData) << (8 * (dwOffset & 0x03));
OEM_WriteConfigDword( dwBusNo, dwDevNo, dwFuncNo, dwOffset & 0xFC, dwData );
} /* OEM_WriteConfigByte() */
void OEM_ReadConfigWord( DWORD dwBusNo, DWORD dwDevNo, DWORD dwFuncNo, DWORD dwOffset, WORD *pwData ) {
DWORD dwData;
OEM_ReadConfigDword( dwBusNo, dwDevNo, dwFuncNo, dwOffset & 0xFC, &dwData );
*pwData = (WORD)(dwData >> (8 * (dwOffset & 0x02)));
} /* OEM_ReadConfigWord() */
void OEM_WriteConfigWord( DWORD dwBusNo, DWORD dwDevNo, DWORD dwFuncNo, DWORD dwOffset, WORD wData ) {
DWORD dwData;
OEM_ReadConfigDword( dwBusNo, dwDevNo, dwFuncNo, dwOffset & 0xFC, &dwData );
dwData &= ~(0x0000FFFF << (8 * (dwOffset & 0x02)));
dwData |= ((DWORD)wData) << (8 * (dwOffset & 0x02));
OEM_WriteConfigDword( dwBusNo, dwDevNo, dwFuncNo, dwOffset & 0xFC, dwData );
} /* OEM_WriteConfigWord() */
void OEM_ReadConfigDword( DWORD dwBusNo, DWORD dwDevNo, DWORD dwFuncNo, DWORD dwOffset, DWORD *pdwData ) {
// This routine would check out the entire range of idsels by asserting
// bits 11 - 31, one bit at a time.
// If some of the bits are don't care, it would not make any difference.
// So the configuration addresses generated would be of the form :-
// dwDevNo == 0, idSel = 0x00000800
// dwDevNo == 1, idSel = 0x00001000
// dwDevNo == 21, idSel = 0x8000000
// This way a max. of 21 devices are supported.
#if ( (SH_PLATFORM == PLATFORM_ASPEN) || (SH_PLATFORM == PLATFORM_BIGSUR) )
DWORD dwConfigAddress;
unsigned addr;
unsigned old_val;
DEBUGMSG(DEB_PCI_CONFIG, (TEXT("RCD: dwBusNo = 0x%x, dwDevNo = 0x%x, dwFuncNo = 0x%x, dwOffset = 0x%x\r\n"), dwBusNo, dwDevNo, dwFuncNo, dwOffset));
CONFIG_WAIT;
// Get the address in the PCI configuration space for the requested register
OEM_EncodeConfigAddress( dwBusNo, dwDevNo, dwFuncNo, dwOffset, &dwConfigAddress );
// Save OLD Value of LB_MAP1 so that you can restore it after the access
old_val = V360_LB_MAP1_RES;
DEBUGMSG(DEB_PCI_CONFIG, (TEXT("Encoded Address = 0x%x\r\n"), dwConfigAddress));
// Now is the address bigger than PCI memory size that you mapped ?
if(dwConfigAddress >= PCI_CONFIG_SIZE) {
DEBUGMSG(DEB_PCI_CONFIG, (TEXT("Writing to LB_MAP1_RES1 0x%x\n"), ((dwConfigAddress & 0xFFF00000) | (TYPE_CONFIG << 16)) ));
// Split dwConfigAddress into two parts. The upper part gets written
// to MAP1 register and the lower part is the address that gets accessed.
V360_LB_MAP1_RES = ((dwConfigAddress & 0xFFF00000) | (TYPE_CONFIG << 16));
}
else {
DEBUGMSG(DEB_PCI_CONFIG, (TEXT("Writing to LB_MAP1_RES2 0x%x\r\n"), (TYPE_CONFIG) << 16) );
V360_LB_MAP1_RES = (TYPE_CONFIG) << 16 ;
}
addr = PciConfigBase + (dwConfigAddress & (PCI_CONFIG_SIZE - 1));
DEBUGMSG(DEB_PCI_CONFIG, (TEXT("addr = 0x%x\r\n"), addr));
// If type is 1, that is address bits 0,1 are 01, Then you need to
// program AD_LOW_ENABLE in LB_MAP1_RES and AD_LOW=01 in PCI_CFG
if(addr & 3) {
volatile unsigned long *tmp_addr = (unsigned *) (addr & 0xFFFFFFFC);
CONFIG_WAIT;
// Set bits 8,9 of PCI_CFG register to the override value of address.
V360_PCI_CFG = ( V360_PCI_CFG & ~(0x300) ) | ( (addr & 3) << 8);
V360_LB_MAP1_RES = (V360_LB_MAP1_RES | 0x10000);
DEBUGMSG(DEB_PCI_CONFIG, (TEXT("RCD: addr = 0x%x, V360_PCI_CFG = 0x%x, V360_LB_MAP1_RES = 0x%x\n"), tmp_addr, V360_PCI_CFG, V360_LB_MAP1_RES));
*pdwData = *tmp_addr;
}
else {
CONFIG_WAIT;
DEBUGMSG(DEB_PCI_CONFIG, (TEXT("About to read location 0x%x, pdwData = 0x%x\r\n"), addr, pdwData));
*pdwData = *(volatile unsigned long *)(addr);
DEBUGMSG(DEB_PCI_CONFIG, (TEXT("read data %x\r\n"), *pdwData));
}
DEBUGMSG(DEB_PCI_CONFIG, (TEXT("RCD(BDFO)=(%d:%d:%d:0x%x),A=%x,*D=%x,M1=%x,CA=%x\r\n"), dwBusNo, dwDevNo, dwFuncNo, dwOffset, addr, *pdwData, V360_LB_MAP1_RES, dwConfigAddress));
// Switch back the area to old mode
V360_LB_MAP1_RES = old_val;
// No need to reset PCI_CFG AD_LOW bits since they would not be used.
#else (SH_PLATFORM == PLATFORM_ASPEN)
unsigned short idSel;
switch(dwDevNo) {
case 0: idSel = 0x9000; break;
case 1: idSel = 0xA000; break;
case 2: idSel = 0xC000; break;
default:
// DbgPrintf("Error: dwDevNo = %d unsupported. supported range 0-2\r\n", dwDevNo);
return;
}
// By default the 0xA4000000 range is PCI memory.
// Change that to PCI config, read dword, and change back.
FPGA_PCI_CNT = (0xFF | idSel);
V360_LB_MAP0_RES = 0x000A0000;
// Read the dword
*pdwData = *(unsigned long *)(PciConfigBase + dwOffset);
// Change it back
V360_LB_MAP0_RES = 0x00060000;
// DbgPrintf("ReadConfigDword: dwDevNo = %d, dwOffset=0x%x, *Data=0x%x\r\n", dwDevNo, dwOffset, *pdwData);
#endif (SH_PLATFORM == PLATFORM_ASPEN)
return;
#if 0
volatile DWORD *pdwConfigAddressReg = (volatile DWORD *)CONFIG_ADDRESS_REG_ADDR;
volatile DWORD *pdwConfigDataReg = (volatile DWORD *)CONFIG_DATA_REG_ADDR;
DWORD dwConfigAddress;
/* Encode Type 0 or Type 1 configuration address */
OEM_EncodeConfigAddress( dwBusNo, dwDevNo, dwFuncNo, dwOffset, &dwConfigAddress );
*pdwConfigAddressReg = dwConfigAddress;
/* Actually perform the configuration Read */
*pdwData = *pdwConfigDataReg;
#endif
} /* OEM_ReadConfigDword() */
void OEM_WriteConfigDword( DWORD dwBusNo, DWORD dwDevNo, DWORD dwFuncNo, DWORD dwOffset, DWORD dwData ) {
// Please see comments of OEM_ReadConfigDword for idsel technique.
#if ( (SH_PLATFORM == PLATFORM_ASPEN) || (SH_PLATFORM == PLATFORM_BIGSUR) )
DWORD dwConfigAddress;
unsigned addr;
unsigned old_val;
CONFIG_WAIT;
// Get the address in the PCI configuration space for the requested register
OEM_EncodeConfigAddress( dwBusNo, dwDevNo, dwFuncNo, dwOffset, &dwConfigAddress );
// Save OLD Value of LB_MAP1 so that you can restore it after the access
old_val = V360_LB_MAP1_RES;
// Now is the address is bigger than PCI memory size that you mapped,
if(dwConfigAddress >= PCI_CONFIG_SIZE) {
// Split dwConfigAddress into two parts. The upper part gets written
// to MAP1 register and the lower part is the address that gets accessed.
V360_LB_MAP1_RES = ((dwConfigAddress & 0xFFF00000) | (TYPE_CONFIG << 16));
}
else {
V360_LB_MAP1_RES = (TYPE_CONFIG) << 16 ;
}
addr = PciConfigBase + (dwConfigAddress & (PCI_CONFIG_SIZE - 1));
DEBUGMSG(DEB_PCI_CONFIG, (TEXT("WCD: (B:D:F:O) = (%d:%d:%d:0x%x), *Data=%x, addr=%x, MAP1=%x\r\n"), dwBusNo, dwDevNo, dwFuncNo, dwOffset, dwData, addr, V360_LB_MAP1_RES));
// If type is 1, that is address bits 0,1 are 01, Then you need to
// program AD_LOW_ENABLE in LB_MAP1_RES and AD_LOW=01 in PCI_CFG
if(addr & 3) {
volatile unsigned long *tmp_addr = (unsigned long *)(addr & 0xFFFFFFFC);
// Set bits 8,9 of PCI_CFG register to the override value of address.
V360_PCI_CFG = ( V360_PCI_CFG & ~(0x300) ) | ( (addr & 3) << 8);
V360_LB_MAP1_RES = (V360_LB_MAP1_RES | 0x10000);
DEBUGMSG(DEB_PCI_CONFIG, (TEXT("WCD: addr = 0x%x, V360_PCI_CFG = 0x%x, V360_LB_MAP1_RES = 0x%x "), tmp_addr, V360_PCI_CFG, V360_LB_MAP1_RES));
// Presently i need to write to this register many times, since if i
// write only once, it does not reliably get written to the register.
// Either some timing problem or some wrongly set paramter.
*tmp_addr = dwData; // Write code
#if 1 // def PUT_PCI_DELAY
if(1){
int i;
extern int glbl_wait, my_wait;
for(i = 0; i < 1; i++)
for(glbl_wait = 0; glbl_wait < my_wait; glbl_wait ++);
*tmp_addr = dwData; // Write code
}
DEBUGMSG(DEB_PCI_CONFIG, (TEXT("RB: 0x%x\n"), *(volatile unsigned long *)(tmp_addr)));
#endif PUT_PCI_DELAY
}
else {
*(volatile unsigned long *)(addr) = dwData; // Write code
DEBUGMSG(DEB_PCI_CONFIG, (TEXT("RB: 0x%x\n"), *(volatile unsigned long *)(addr)));
}
DEBUGMSG(DEB_PCI_CONFIG, (TEXT("WCD: (B:D:F:O) = (%d:%d:%d:0x%x), *Data=%x, addr=%x, MAP1=%x, dwConfigAddress=%x\r\n"), dwBusNo, dwDevNo, dwFuncNo, dwOffset, dwData, addr, V360_LB_MAP1_RES, dwConfigAddress));
// Switch back the area to old mode
V360_LB_MAP1_RES = old_val;
// No need to reset PCI_CFG AD_LOW bits since they would not be used.
#else (SH_PLATFORM == PLATFORM_ASPEN)
unsigned short idSel;
switch(dwDevNo) {
case 0: idSel = 0x9000; break;
case 1: idSel = 0xA000; break;
case 2: idSel = 0xC000; break;
default:
// DbgPrintf("Error: dwDevNo = %d unsupported. supported range 0-2\r\n", dwDevNo);
return;
}
// By default the 0xA4000000 range is PCI memory.
// Change that to PCI config, read dword, and change back.
V360_LB_MAP0_RES = 0x000a0000;
FPGA_PCI_CNT = (0xFF | idSel);
// Read the dword
*(unsigned long *)(PciConfigBase + dwOffset) = dwData;
// Change it back
V360_LB_MAP0_RES = 0x00060000;
// DbgPrintf("WriteConfigDword: dwDevNo = %d, dwOffset=0x%x, Data=0x%x\r\n", dwDevNo, dwOffset, dwData);
#endif (SH_PLATFORM == PLATFORM_ASPEN)
return;
#if 0
volatile DWORD *pdwConfigAddressReg = (volatile DWORD *)CONFIG_ADDRESS_REG_ADDR;
volatile DWORD *pdwConfigDataReg = (volatile DWORD *)CONFIG_DATA_REG_ADDR;
DWORD dwConfigAddress;
/* Encode Type 0 or Type 1 configuration address */
OEM_EncodeConfigAddress( dwBusNo, dwDevNo, dwFuncNo, dwOffset, &dwConfigAddress );
*pdwConfigAddressReg = dwConfigAddress;
/* Actually perform the configuration write */
*pdwConfigDataReg = dwData;
#endif
} /* OEM_WriteConfigDword() */
/* This function will encode a Type 0 or Type 1 configuration address based on */
/* the parameters passed in. */
void OEM_EncodeConfigAddress( DWORD dwBusNo, DWORD dwDevNo, DWORD dwFuncNo, DWORD dwOffset, DWORD *pdwAddress ) {
/* Assume that we need to generate Type 0 bus cycles for Bus 0, based on */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?