summaryrefslogblamecommitdiffstats
path: root/c/src/lib/libbsp/powerpc/ppcn_60x/pci/pci.c
blob: 909a568d55408a07a5757252e13ca710d9386f06 (plain) (tree)





















































































































































































































































































































































                                                                                
/*
 *  COPYRIGHT (c) 1998 by Radstone Technology
 *
 *
 * THIS FILE IS PROVIDED TO YOU, THE USER, "AS IS", WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
 * AS TO THE QUALITY AND PERFORMANCE OF ALL CODE IN THIS FILE IS WITH YOU.
 *
 * You are hereby granted permission to use, copy, modify, and distribute
 * this file, provided that this notice, plus the above copyright notice
 * and disclaimer, appears in all copies. Radstone Technology will provide
 * no support for this code.
 *
 */
#include <bsp.h>
#include <pci.h>

/* SCE 97/4/9
 *
 * Use PCI configuration space access mechanism 1
 *
 * This is the preferred access mechanism and must be used when accessing
 * bridged PCI busses.
 *
 * The address to be written to the PCI_CONFIG_ADDRESS port is constructed
 * thus (the representation below is little endian):
 *
 *  31  30   24 23        16 15        11 10        8 7          2 1   0
 *  ----------------------------------------------------------------------
 * | 1 | Resvd | Bus Number | Dev Number | Fn Number | Reg Number | 0 | 0 |
 *  ----------------------------------------------------------------------
 *
 * On bus 0, the first 'real' device is at Device number 11, the Eagle being
 * device 0. On all other busses, device numbering starts at 0.
 */
/*
 * Normal PCI device numbering on busses other than 0 is such that
 * that the first device (0) is attached to AD16, second (1) to AD17 etc.
 */
#define CONFIG_ADDRESS(Bus, Device, Function, Offset) \
    (0x80000000 | (Bus<<16) | \
    ((Device+(((Bus==0)&&(Device>0)) ? 10 : 0))<<11) | \
    (Function<<8) | \
    (Offset&~0x03))
#define BYTE_LANE_OFFSET(Offset) ((Offset)&0x3)

/*
 * Private data
 */
static unsigned8 ucMaxPCIBus;

/*
 * Public routines
 */
rtems_status_code PCIConfigWrite8(
	unsigned8 ucBusNumber,
	unsigned8 ucSlotNumber,
	unsigned8 ucFunctionNumber,
	unsigned8 ucOffset,
	unsigned8 ucValue
)
{
	ISR_Level Irql;

	/*
	 * Ensure that accesses to the addr/data ports are indivisible
	 */
	_ISR_Disable(Irql);

	/*
	 * Write to the configuration space address register
	 */
	outport_32(PCI_CONFIG_ADDR,
		   CONFIG_ADDRESS(ucBusNumber, ucSlotNumber,
				  ucFunctionNumber, ucOffset));
	/*
	 * Write to the configuration space data register with the appropriate
	 * offset
	 */
	outport_byte(PCI_CONFIG_DATA+BYTE_LANE_OFFSET(ucOffset), ucValue);

	 _ISR_Enable(Irql);

	return(RTEMS_SUCCESSFUL);
}

rtems_status_code PCIConfigWrite16(
	unsigned8 ucBusNumber,
	unsigned8 ucSlotNumber,
	unsigned8 ucFunctionNumber,
	unsigned8 ucOffset,
	unsigned16 usValue
)
{
	ISR_Level Irql;

	/*
	 * Ensure that accesses to the addr/data ports are indivisible
	 */
	_ISR_Disable(Irql);

	/*
	 * Write to the configuration space address register
	 */
	outport_32(PCI_CONFIG_ADDR,
		   CONFIG_ADDRESS(ucBusNumber, ucSlotNumber,
				  ucFunctionNumber, ucOffset));
	/*
	 * Write to the configuration space data register with the appropriate
	 * offset
	 */
	outport_16(PCI_CONFIG_DATA+BYTE_LANE_OFFSET(ucOffset), usValue);

	_ISR_Enable(Irql);

	return(RTEMS_SUCCESSFUL);
}

rtems_status_code PCIConfigWrite32(
	unsigned8 ucBusNumber,
	unsigned8 ucSlotNumber,
	unsigned8 ucFunctionNumber,
	unsigned8 ucOffset,
	unsigned32 ulValue
)
{
	ISR_Level Irql;

	/*
	 * Ensure that accesses to the addr/data ports are indivisible
	 */
	_ISR_Disable(Irql);

	/*
	 * Write to the configuration space address register
	 */
	outport_32(PCI_CONFIG_ADDR,
		   CONFIG_ADDRESS(ucBusNumber, ucSlotNumber,
				  ucFunctionNumber, ucOffset));
	/*
	 * Write to the configuration space data register with the appropriate
	 * offset
	 */
	outport_32(PCI_CONFIG_DATA, ulValue);

	_ISR_Enable(Irql);

	return(RTEMS_SUCCESSFUL);
}

rtems_status_code PCIConfigRead8(
	unsigned8 ucBusNumber,
	unsigned8 ucSlotNumber,
	unsigned8 ucFunctionNumber,
	unsigned8 ucOffset,
	unsigned8 *pucValue
)
{
	ISR_Level Irql;

	/*
	 * Ensure that accesses to the addr/data ports are indivisible
	 */
	_ISR_Disable(Irql);

	/*
	 * Write to the configuration space address register
	 */
	outport_32(PCI_CONFIG_ADDR,
		   CONFIG_ADDRESS(ucBusNumber, ucSlotNumber,
				  ucFunctionNumber, ucOffset));
	/*
	 * Read from the configuration space data register with the appropriate
	 * offset
	 */
	inport_byte(PCI_CONFIG_DATA+BYTE_LANE_OFFSET(ucOffset), *pucValue);

	_ISR_Enable(Irql);

	return(RTEMS_SUCCESSFUL);
}

rtems_status_code PCIConfigRead16(
	unsigned8 ucBusNumber,
	unsigned8 ucSlotNumber,
	unsigned8 ucFunctionNumber,
	unsigned8 ucOffset,
	unsigned16 *pusValue
)
{
	ISR_Level Irql;

	/*
	 * Ensure that accesses to the addr/data ports are indivisible
	 */
	_ISR_Disable(Irql);

	/*
	 * Write to the configuration space address register
	 */
	outport_32(PCI_CONFIG_ADDR,
		   CONFIG_ADDRESS(ucBusNumber, ucSlotNumber,
				  ucFunctionNumber, ucOffset));
	/*
	 * Read from the configuration space data register with the appropriate
	 * offset
	 */
	inport_16(PCI_CONFIG_DATA+BYTE_LANE_OFFSET(ucOffset), *pusValue);

	_ISR_Enable(Irql);

	return(RTEMS_SUCCESSFUL);
}

rtems_status_code PCIConfigRead32(
	unsigned8 ucBusNumber,
	unsigned8 ucSlotNumber,
	unsigned8 ucFunctionNumber,
	unsigned8 ucOffset,
	unsigned32 *pulValue
)
{
	ISR_Level Irql;

	/*
	 * Ensure that accesses to the addr/data ports are indivisible
	 */
	_ISR_Disable(Irql);

	/*
	 * Write to the configuration space address register
	 */
	outport_32(PCI_CONFIG_ADDR,
		   CONFIG_ADDRESS(ucBusNumber, ucSlotNumber,
				  ucFunctionNumber, ucOffset));
	/*
	 * Read from the configuration space data register with the appropriate
	 * offset
	 */
	inport_32(PCI_CONFIG_DATA, *pulValue);

	_ISR_Enable(Irql);

	return(RTEMS_SUCCESSFUL);
}

/*
 * This routine determines the maximum bus number in the system
 */
void InitializePCI()
{
	unsigned8 ucSlotNumber, ucFnNumber, ucNumFuncs;
	unsigned8 ucHeader;
	unsigned8 ucBaseClass, ucSubClass, ucMaxSubordinate;
	unsigned32 ulDeviceID;

	/*
	 * Scan PCI bus 0 looking for PCI-PCI bridges
	 */
	for(ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++)
	{
		(void)PCIConfigRead32(0,
				      ucSlotNumber,
				      0,
				      PCI_CONFIG_VENDOR_LOW,
				      &ulDeviceID);
		if(ulDeviceID==PCI_INVALID_VENDORDEVICEID)
		{
			/*
			 * This slot is empty
			 */
			continue;
		}
		(void)PCIConfigRead8(0,
				     ucSlotNumber,
				     0,
				     PCI_CONFIG_HEADER_TYPE,
				     &ucHeader);
		if(ucHeader&PCI_MULTI_FUNCTION)
		{
			ucNumFuncs=PCI_MAX_FUNCTIONS;
		}
		else
		{
			ucNumFuncs=1;
		}
		for(ucFnNumber=0;ucFnNumber<ucNumFuncs;ucFnNumber++)
		{
			(void)PCIConfigRead32(0,
					      ucSlotNumber,
					      ucFnNumber,
					      PCI_CONFIG_VENDOR_LOW,
					      &ulDeviceID);
			if(ulDeviceID==PCI_INVALID_VENDORDEVICEID)
			{
				/*
				 * This slot/function is empty
				 */
				continue;
			}

			/*
			 * This slot/function has a device fitted.
			 */
			(void)PCIConfigRead8(0,
					     ucSlotNumber,
					     ucFnNumber,
					     PCI_CONFIG_CLASS_CODE_U,
					     &ucBaseClass);
			(void)PCIConfigRead8(0,
					     ucSlotNumber,
					     ucFnNumber,
					     PCI_CONFIG_CLASS_CODE_M,
					     &ucSubClass);
			if((ucBaseClass==PCI_BASE_CLASS_BRIDGE) &&
			   (ucSubClass==PCI_SUB_CLASS_BRIDGE_PCI))
			{
				/*
				 * We have found a PCI-PCI bridge
				 */
				(void)PCIConfigRead8(0,
						     ucSlotNumber,
						     ucFnNumber,
						     PCI_BRIDGE_SUBORDINATE_BUS,
						     &ucMaxSubordinate);
				if(ucMaxSubordinate>ucMaxPCIBus)
				{
					ucMaxPCIBus=ucMaxSubordinate;
				}
			}
		}
	}
}

/*
 * Return the number of PCI busses in the system
 */
unsigned8 BusCountPCI()
{
	return(ucMaxPCIBus+1);
}