/*
* pci.c : this file contains basic PCI Io functions.
*
* CopyRight (C) 1999 valette@crf.canon.fr
*
* This code is heavilly inspired by the public specification of STREAM V2
* that can be found at :
*
* <http://www.chorus.com/Documentation/index.html> by following
* the STREAM API Specification Document link.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/rtems/license.html.
*
* Copyright 2004, 2008 Brookhaven National Laboratory and
* Shuchen K. Feng, <feng1@bnl.gov>
*
* - to be consistent with the original pci.c written by Eric Valette
* - added 2nd PCI support for discovery based PCI bridge (e.g. mvme5500/mvme6100)
* - added bus support for the expansion of PMCSpan as per request by Peter
*/
#define PCI_MAIN
#include <libcpu/io.h>
#include <rtems/bspIo.h> /* printk */
#include <bsp/irq.h>
#include <bsp/pci.h>
#include <bsp/gtreg.h>
#include <bsp/gtpcireg.h>
#include <bsp.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#define PCI_DEBUG 0
#define PCI_PRINT 1
/* allow for overriding these definitions */
#ifndef PCI_CONFIG_ADDR
#define PCI_CONFIG_ADDR 0xcf8
#endif
#ifndef PCI_CONFIG_DATA
#define PCI_CONFIG_DATA 0xcfc
#endif
#ifndef PCI1_CONFIG_ADDR
#define PCI1_CONFIG_ADDR 0xc78
#endif
#ifndef PCI1_CONFIG_DATA
#define PCI1_CONFIG_DATA 0xc7c
#endif
#define HOSTBRIDGET_ERROR 0xf0000000
#define GT64x60_PCI_CONFIG_ADDR GT64x60_REG_BASE + PCI_CONFIG_ADDR
#define GT64x60_PCI_CONFIG_DATA GT64x60_REG_BASE + PCI_CONFIG_DATA
#define GT64x60_PCI1_CONFIG_ADDR GT64x60_REG_BASE + PCI1_CONFIG_ADDR
#define GT64x60_PCI1_CONFIG_DATA GT64x60_REG_BASE + PCI1_CONFIG_DATA
static int numPCIDevs=0;
static DiscoveryChipVersion BSP_sysControllerVersion = 0;
static BSP_VMEchipTypes BSP_VMEinterface = 0;
static rtems_pci_config_t BSP_pci[2]={
{(volatile unsigned char*) (GT64x60_PCI_CONFIG_ADDR),
(volatile unsigned char*) (GT64x60_PCI_CONFIG_DATA),
0 /* defined at BSP_pci_configuration */},
{(volatile unsigned char*) (GT64x60_PCI1_CONFIG_ADDR),
(volatile unsigned char*) (GT64x60_PCI1_CONFIG_DATA),
0 /* defined at BSP_pci_configuration */}
};
/* Pack RegNum,FuncNum,DevNum,BusNum,and ConfigEnable for
* PCI Configuration Address Register
*/
#define pciConfigPack(bus,dev,func,offset)\
((offset&~3)<<24)|(PCI_DEVFN(dev,func)<<16)|(bus<<8)|0x80
/*
* Bit encode for PCI_CONFIG_HEADER_TYPE register
*/
static unsigned char ucMaxPCIBus=0;
/* Please note that PCI0 and PCI1 does not correlate with the busNum 0 and 1.
*/
static int indirect_pci_read_config_byte(unsigned char bus,unsigned char dev,unsigned char func,
unsigned char offset, uint8_t *val)
{
int n=0;
if (bus>= BSP_MAX_PCI_BUS_ON_PCI0) {
bus-=BSP_MAX_PCI_BUS_ON_PCI0;
n=1;
}
*val = 0xff;
if (offset & ~0xff) return PCIBIOS_BAD_REGISTER_NUMBER;
#if 0
printk("addr %x, data %x, pack %x \n", BSP_pci[n].pci_config_addr),
BSP_pci[n].config_data,pciConfigPack(bus,dev,func,offset));
#endif
out_be32((volatile uint32_t *) BSP_pci[n].pci_config_addr, pciConfigPack(bus,dev,func,offset));
*val = in_8(BSP_pci[n].pci_config_data + (offset&3));
return PCIBIOS_SUCCESSFUL;
}
static int indirect_pci_read_config_word(unsigned char bus, unsigned char dev,
unsigned char func, unsigned char offset, uint16_t *val)
{
int n=0;
if (bus>= BSP_MAX_PCI_BUS_ON_PCI0) {
bus-=BSP_MAX_PCI_BUS_ON_PCI0;
n=1;
}
*val = 0xffff;
if ((offset&1)|| (offset & ~0xff)) return PCIBIOS_BAD_REGISTER_NUMBER;
#if 0
printk("addr %x, data %x, pack %x \n", config_addr,
config_data,pciConfigPack(bus,dev,func,offset));
#endif
out_be32((volatile uint32_t *) BSP_pci[n].pci_config_addr, pciConfigPack(bus,dev,func,offset));
*val = in_le16((volatile uint16_t *) (BSP_pci[n].pci_config_data + (offset&2)));
return PCIBIOS_SUCCESSFUL;
}
static int indirect_pci_read_config_dword(unsigned char bus, unsigned char dev,
unsigned char func, unsigned char offset, uint32_t *val)
{
int n=0;
if (bus>= BSP_MAX_PCI_BUS_ON_PCI0) {
bus-=BSP_MAX_PCI_BUS_ON_PCI0;
n=1;
}
*val = 0xffffffff;
if ((offset&3)|| (offset & ~0xff)) return PCIBIOS_BAD_REGISTER_NUMBER;
out_be32((volatile uint32_t *)BSP_pci[n].pci_config_addr, pciConfigPack(bus,dev,func,offset));
*val = in_le32((volatile uint32_t *)BSP_pci[n].pci_config_data);
return PCIBIOS_SUCCESSFUL;
}
static int indirect_pci_write_config_byte(unsigned char bus, unsigned char dev,unsigned char func, unsigned char offset, uint8_t val)
{
int n=0;
if (bus>= BSP_MAX_PCI_BUS_ON_PCI0) {
bus-=BSP_MAX_PCI_BUS_ON_PCI0;
n=1;
}
if (offset & ~0xff) return PCIBIOS_BAD_REGISTER_NUMBER;
out_be32((volatile uint32_t *)BSP_pci[n].pci_config_addr, pciConfigPack(bus,dev,func,offset));
out_8((volatile uint8_t *) (BSP_pci[n].pci_config_data + (offset&3)), val);
return PCIBIOS_SUCCESSFUL;
}
static int indirect_pci_write_config_word(unsigned char bus, unsigned char dev,unsigned char func, unsigned char offset, uint16_t val)
{
int n=0;
if (bus>= BSP_MAX_PCI_BUS_ON_PCI0) {
bus-=BSP_MAX_PCI_BUS_ON_PCI0;
n=1;
}
if ((offset&1)|| (offset & ~0xff)) return PCIBIOS_BAD_REGISTER_NUMBER;
out_be32((volatile uint32_t *)BSP_pci[n].pci_config_addr, pciConfigPack(bus,dev,func,offset));
out_le16((volatile uint16_t *)(BSP_pci[n].pci_config_data + (offset&3)), val);
return PCIBIOS_SUCCESSFUL;
}
static int indirect_pci_write_config_dword(unsigned char bus,unsigned char dev,unsigned char func, unsigned char offset, uint32_t val)
{
int n=0;
if (bus>= BSP_MAX_PCI_BUS_ON_PCI0) {
bus-=BSP_MAX_PCI_BUS_ON_PCI0;
n=1;
}
if ((offset&3)|| (offset & ~0xff)) return PCIBIOS_BAD_REGISTER_NUMBER;
out_be32((volatile uint32_t *)BSP_pci[n].pci_config_addr, pciConfigPack(bus,dev,func,offset));
out_le32((volatile uint32_t *)BSP_pci[n].pci_config_data, val);
return PCIBIOS_SUCCESSFUL;
}
const pci_config_access_functions pci_indirect_functions = {
indirect_pci_read_config_byte,
indirect_pci_read_config_word,
indirect_pci_read_config_dword,
indirect_pci_write_config_byte,
indirect_pci_write_config_word,
indirect_pci_write_config_dword
};
rtems_pci_config_t BSP_pci_configuration = {
(volatile unsigned char*) (GT64x60_PCI_CONFIG_ADDR),
(volatile unsigned char*) (GT64x60_PCI_CONFIG_DATA),
&pci_indirect_functions};
DiscoveryChipVersion BSP_getDiscoveryChipVersion(void)
{
return(BSP_sysControllerVersion);
}
BSP_VMEchipTypes BSP_getVMEchipType(void)
{
return(BSP_VMEinterface);
}
/*
* This routine determines the maximum bus number in the system.
* The PCI_SUBORDINATE_BUS is not supported in GT6426xAB. Thus,
* it's not used.
*
*/
int pci_initialize(void)
{
int deviceFound;
unsigned char ucBusNumber, ucSlotNumber, ucFnNumber, ucNumFuncs, data8;
uint32_t ulHeader, ulClass, ulDeviceID;
#if PCI_DEBUG
uint32_t pcidata;
#endif
/*
* Scan PCI0 and PCI1 buses
*/
for (ucBusNumber=0; ucBusNumber<BSP_MAX_PCI_BUS; ucBusNumber++) {
deviceFound=0;
for (ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) {
ucFnNumber = 0;
pci_read_config_dword(ucBusNumber,
ucSlotNumber,
0,
PCI_VENDOR_ID,
&ulDeviceID);
if( ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
/* This slot is empty */
continue;
}
if (++numPCIDevs > PCI_MAX_DEVICES) {
rtems_panic("Too many PCI devices found; increase PCI_MAX_DEVICES in pci.h\n");
}
if (!deviceFound) deviceFound=1;
switch(ulDeviceID) {
case (PCI_VENDOR_ID_MARVELL+(PCI_DEVICE_ID_MARVELL_GT6426xAB<<16)):
pci_read_config_byte(0,0,0,PCI_REVISION_ID, &data8);
switch(data8) {
case 0x10:
BSP_sysControllerVersion = GT64260A;
#if PCI_PRINT
printk("Marvell GT64260A (Discovery I) hostbridge detected at bus%d slot%d\n",
ucBusNumber,ucSlotNumber);
#endif
break;
case 0x20:
BSP_sysControllerVersion = GT64260B;
#if PCI_PRINT
printk("Marvell GT64260B (Discovery I) hostbridge detected at bus%d slot%d\n",
ucBusNumber,ucSlotNumber);
#endif
break;
default:
printk("Undefined revsion of GT64260 chip\n");
break;
}
break;
case PCI_VENDOR_ID_TUNDRA:
#if PCI_PRINT
printk("TUNDRA PCI-VME bridge detected at bus%d slot%d\n",
ucBusNumber,ucSlotNumber);
#endif
break;
case (PCI_VENDOR_ID_DEC+(PCI_DEVICE_ID_DEC_21150<<16)):
#if PCI_PRINT
printk("DEC21150 PCI-PCI bridge detected at bus%d slot%d\n",
ucBusNumber,ucSlotNumber);
#endif
break;
default :
#if PCI_PRINT
printk("BSP unlisted vendor, Bus%d Slot%d DeviceID 0x%" PRIx32 "\n",
ucBusNumber,ucSlotNumber, ulDeviceID);
#endif
/* Kate Feng : device not supported by BSP needs to remap the IRQ line on mvme5500/mvme6100 */
pci_read_config_byte(ucBusNumber,ucSlotNumber,0,PCI_INTERRUPT_LINE,&data8);
if (data8 < BSP_GPP_IRQ_LOWEST_OFFSET) pci_write_config_byte(ucBusNumber,
ucSlotNumber,0,PCI_INTERRUPT_LINE,BSP_GPP_IRQ_LOWEST_OFFSET+data8);
break;
}
#if PCI_DEBUG
pci_read_config_dword(ucBusNumber,
ucSlotNumber,
0,
PCI_BASE_ADDRESS_0,
&data);
printk("Bus%d BASE_ADDRESS_0 0x%x \n",ucBusNumber, data);
pci_read_config_dword(ucBusNumber,
ucSlotNumber,
0,
PCI_BASE_ADDRESS_1,
&data);
printk("Bus%d BASE_ADDRESS_1 0x%x \n",ucBusNumber, data);
pci_read_config_dword(ucBusNumber,
ucSlotNumber,
0,
PCI_BASE_ADDRESS_2,
&data);
printk("Bus%d BASE_ADDRESS_2 0x%x \n", ucBusNumber, data);
pci_read_config_dword(ucBusNumber,
ucSlotNumber,
0,
PCI_BASE_ADDRESS_3,
&data);
printk("Bus%d BASE_ADDRESS_3 0x%x \n", ucBusNumber, data);
pci_read_config_word(ucBusNumber,
ucSlotNumber,
0,
PCI_INTERRUPT_LINE,
&sdata);
printk("Bus%d INTERRUPT_LINE 0x%x \n", ucBusNumber, sdata);
/* We always enable internal memory. */
pci_read_config_dword(ucBusNumber,
ucSlotNumber,
0,
PCI_MEM_BASE_ADDR,
&pcidata);
printk("Bus%d MEM_BASE_ADDR 0x%x \n", ucBusNumber,pcidata);
/* We always enable internal IO. */
pci_read_config_dword(ucBusNumber,
ucSlotNumber,
0,
PCI_IO_BASE_ADDR,
&pcidata);
printk("Bus%d IO_BASE_ADDR 0x%x \n", ucBusNumber,pcidata);
#endif
pci_read_config_dword(ucBusNumber,
ucSlotNumber,
0,
PCI_CACHE_LINE_SIZE,
&ulHeader);
if ((ulHeader>>16)&PCI_HEADER_TYPE_MULTI_FUNCTION)
ucNumFuncs=PCI_MAX_FUNCTIONS;
else
ucNumFuncs=1;
#if PCI_DEBUG
printk("Bus%d Slot 0x%x HEADER/LAT/CACHE 0x%x \n",
ucBusNumber, ucSlotNumber, ulHeader);
#endif
for (ucFnNumber=1;ucFnNumber<ucNumFuncs;ucFnNumber++) {
pci_read_config_dword(ucBusNumber,
ucSlotNumber,
ucFnNumber,
PCI_VENDOR_ID,
&ulDeviceID);
if (ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
/* This slot/function is empty */
continue;
}
/* This slot/function has a device fitted.*/
pci_read_config_dword(ucBusNumber,
ucSlotNumber,
ucFnNumber,
PCI_CLASS_REVISION,
&ulClass);
#if PCI_DEBUG
printk("Bus%d Slot 0x%x Func %d classID 0x%x \n",ucBusNumber,ucSlotNumber,
ucFnNumber, ulClass);
#endif
}
}
if (deviceFound) ucMaxPCIBus++;
} /* for (ucBusNumber=0; ucBusNumber<BSP_MAX_PCI_BUS; ... */
#if PCI_DEBUG
printk("number of PCI buses: %d, numPCIDevs %d\n",
pci_bus_count(), numPCIDevs);
#endif
pci_interface();
return(0);
}
void FixupPCI( const struct _int_map *bspmap, int (*swizzler)(int,int) )
{
}
/*
* Return the number of PCI buses in the system
*/
unsigned char pci_bus_count()
{
return(ucMaxPCIBus);
}