/* * 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 #include /* 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;ucSlotNumberucMaxPCIBus) { ucMaxPCIBus=ucMaxSubordinate; } } } } } /* * Return the number of PCI busses in the system */ unsigned8 BusCountPCI() { return(ucMaxPCIBus+1); }