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 + -
显示快捷键?