summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/powerpc/ppcn_60x/pci/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libbsp/powerpc/ppcn_60x/pci/pci.c')
-rw-r--r--c/src/lib/libbsp/powerpc/ppcn_60x/pci/pci.c342
1 files changed, 342 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/powerpc/ppcn_60x/pci/pci.c b/c/src/lib/libbsp/powerpc/ppcn_60x/pci/pci.c
new file mode 100644
index 0000000000..909a568d55
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/ppcn_60x/pci/pci.c
@@ -0,0 +1,342 @@
+/*
+ * 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);
+}