summaryrefslogblamecommitdiffstats
path: root/c/src/lib/libbsp/powerpc/beatnik/pci/gt_pci_init.c
blob: 68d7467b223a70e75d4e7e622f8d9f11678ef661 (plain) (tree)





















                                                                             
                                                        
                                         
  



























































                                                                                             
                                                           











                                                                                 
                                                 
                                                                                 
                                                                                









                                                                     
                                                 
                                                                            
                                                                 







                                                                     
                                                 










                                                                                 
                                                 
                                                                                 
                                                                               








                                                                      
                                                 
                                                                            
                                                                













































                                                                            
                                                                 












































                                                                                     
                                                                                                        



























                                                                                                                           
/* PCI configuration space access */

/* 
 * Acknowledgements:
 * Valuable information was obtained from the following drivers
 *   netbsd: (C) Allegro Networks Inc; Wasabi Systems Inc.
 *   linux:  (C) MontaVista, Software, Inc; Chris Zankel, Mark A. Greer.
 *   rtems:  (C) Brookhaven National Laboratory; K. Feng
 */

/*
 * Original file header of libbsp/shared/pci.c where this file is based upon.
 *
 *  Copyright (C) 1999 valette@crf.canon.fr
 *
 *  This code is heavily 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/license/LICENSE.
 *
 *  Till Straumann, <strauman@slac.stanford.edu>, 1/2002
 *   - separated bridge detection code out of this file
 */

#include <rtems.h>
#include <bsp.h>
#include <libcpu/io.h>
#include <bsp/pci.h>
#include <rtems/bspIo.h>
#include <stdint.h>

/* set to max so we get early access to hose 0 */
unsigned	BSP_pci_hose1_bus_base = (unsigned)-1;

#define MV64x60_PCI0_CONFIG_ADDR	(BSP_MV64x60_BASE + 0xcf8)
#define MV64x60_PCI0_CONFIG_DATA	(BSP_MV64x60_BASE + 0xcfc)
#define MV64x60_PCI1_CONFIG_ADDR	(BSP_MV64x60_BASE + 0xc78)
#define MV64x60_PCI1_CONFIG_DATA	(BSP_MV64x60_BASE + 0xc7c)

#define PCI_BUS2HOSE(bus) (bus<BSP_pci_hose1_bus_base?0:1)

void detect_host_bridge(void)
{

}

typedef struct {
	volatile unsigned char *pci_config_addr;
	volatile unsigned char *pci_config_data;
} PciHoseCfg;

static PciHoseCfg hoses[2] = {
	{
		pci_config_addr:	(volatile unsigned char *)(MV64x60_PCI0_CONFIG_ADDR),
		pci_config_data:	(volatile unsigned char *)(MV64x60_PCI0_CONFIG_DATA),
	},
	{
		pci_config_addr:	(volatile unsigned char *)(MV64x60_PCI1_CONFIG_ADDR),
		pci_config_data:	(volatile unsigned char *)(MV64x60_PCI1_CONFIG_DATA),
	}
};

#define pci hoses[hose]

#define HOSE_PREAMBLE \
	uint8_t hose; \
		if (bus < BSP_pci_hose1_bus_base) { \
			hose = 0; \
		} else { \
			hose = 1; \
			bus -= BSP_pci_hose1_bus_base; \
		}


/* Sigh; we have to copy those out from the shared area... */
static int
indirect_pci_read_config_byte(unsigned char bus, unsigned char slot,
			      unsigned char function, 
			      unsigned char offset, uint8_t *val) {
HOSE_PREAMBLE;
	out_be32((volatile uint32_t *) pci.pci_config_addr,
		 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
	*val = in_8(pci.pci_config_data + (offset&3));
	return PCIBIOS_SUCCESSFUL;
}

static int
indirect_pci_read_config_word(unsigned char bus, unsigned char slot,
			      unsigned char function, 
			      unsigned char offset, uint16_t *val) {
HOSE_PREAMBLE;
	*val = 0xffff; 
	if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
	out_be32((uint32_t*) pci.pci_config_addr,
		 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
	*val = in_le16((volatile uint16_t *)(pci.pci_config_data + (offset&3)));
	return PCIBIOS_SUCCESSFUL;
}

static int
indirect_pci_read_config_dword(unsigned char bus, unsigned char slot,
			      unsigned char function, 
			      unsigned char offset, uint32_t *val) {
HOSE_PREAMBLE;
	*val = 0xffffffff; 
	if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
	out_be32((uint32_t*) pci.pci_config_addr,
		 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|(offset<<24));
	*val = in_le32((volatile uint32_t *)pci.pci_config_data);
	return PCIBIOS_SUCCESSFUL;
}

static int
indirect_pci_write_config_byte(unsigned char bus, unsigned char slot,
			       unsigned char function, 
			       unsigned char offset, uint8_t val) {
HOSE_PREAMBLE;
	out_be32((uint32_t*) pci.pci_config_addr,
		 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
	out_8(pci.pci_config_data + (offset&3), val);
	return PCIBIOS_SUCCESSFUL;
}

static int
indirect_pci_write_config_word(unsigned char bus, unsigned char slot,
			       unsigned char function, 
			       unsigned char offset, uint16_t val) {
HOSE_PREAMBLE;
	if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
	out_be32((uint32_t*) pci.pci_config_addr,
		 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
	out_le16((volatile uint16_t *)(pci.pci_config_data + (offset&3)), val);
	return PCIBIOS_SUCCESSFUL;
}

static int
indirect_pci_write_config_dword(unsigned char bus, unsigned char slot,
				unsigned char function, 
				unsigned char offset, uint32_t val) {
HOSE_PREAMBLE;
	if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
	out_be32((uint32_t*) pci.pci_config_addr,
		 0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|(offset<<24));
	out_le32((volatile uint32_t *)pci.pci_config_data, val);
	return PCIBIOS_SUCCESSFUL;
}

const pci_config_access_functions pci_hosed_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
};


extern unsigned char ucMaxPCIBus; /* importing this is ugly */

/* This is a very ugly hack. I don't want to change the shared
 * code to support multiple hoses so we hide everything under
 * the hood with horrible kludges for now. Sorry.
 */
void
BSP_pci_initialize(void)
{

#if 0	/* These values are already set up for the shared/pci.c code      */
{
extern pci_config_access_functions pci_indirect_functions;
        /* by means of the PCI_CONFIG_ADDR/PCI_CONFIG_DATA macros (bsp.h) */
	BSP_pci_configuration.pci_config_addr = hoses[0].pci_config_addr;
	BSP_pci_configuration.pci_config_data = hoses[0].pci_config_data;
	BSP_pci_configuration.pci_functions   = &pci_indirect_functions;
}
#endif
	/* initialize the first hose */
	/* scan hose 0 and sets the maximum bus number */
	pci_initialize();
	/* remember the boundary */
	BSP_pci_hose1_bus_base = pci_bus_count();
	/* so far, so good -- now comes the cludgy part: */
	/* hack/reset the bus count */
	ucMaxPCIBus = 0;
	/* scan hose 1 */
	BSP_pci_configuration.pci_config_addr = hoses[1].pci_config_addr;
	BSP_pci_configuration.pci_config_data = hoses[1].pci_config_data;
	pci_initialize();
	/* check for overflow of an unsigned char */
	if ( BSP_pci_hose1_bus_base + pci_bus_count() > 255 ) {
		rtems_panic("Too many PCI busses in the system");
	}
	/* readjust total number */
	ucMaxPCIBus+=BSP_pci_hose1_bus_base;

	/* install new access functions that can hide the hoses */
	BSP_pci_configuration.pci_config_addr = (volatile unsigned char *)0xdeadbeef;
	BSP_pci_configuration.pci_config_data = (volatile unsigned char *)0xdeadbeef;
	BSP_pci_configuration.pci_functions   = &pci_hosed_indirect_functions;
}

#define PCI_ERR_BITS		0xf900
#define PCI_STATUS_OK(x)	(!((x)&PCI_ERR_BITS))

/* For now, just clear errors in the PCI status reg.
 *
 * Returns: (for diagnostic purposes)
 *          original settings (i.e. before applying the clearing
 *          sequence) 
 *          (pci_status(hose_1)&0xff00) | ((pci_status(hose_2)>>8)&0xff)
 */

static unsigned long clear_hose_errors(int bus, int quiet)
{
unsigned long	rval;
uint16_t        pcistat;
int				count;
int				hose = PCI_BUS2HOSE(bus);

	/* read error status for info return */
	pci_read_config_word(bus,0,0,PCI_STATUS,&pcistat);
	rval = pcistat;

	count=10;
	do {
		/* clear error reporting registers */

		/* clear PCI status register */
		pci_write_config_word(bus,0,0,PCI_STATUS, PCI_ERR_BITS);

		/* read  new status */
		pci_read_config_word(bus,0,0,PCI_STATUS, &pcistat);

	} while ( ! PCI_STATUS_OK(pcistat) && count-- );

	if ( !PCI_STATUS_OK(rval) && !quiet) {
		printk("Cleared PCI errors at discovery (hose %i): pci_stat was 0x%04lx\n", hose, rval);
	}
	if ( !PCI_STATUS_OK(pcistat) ) {
		printk("Unable to clear PCI errors at discovery (hose %i) still 0x%04x after 10 attempts\n",hose, pcistat);
	}
	return rval;
}

unsigned short
(*_BSP_clear_vmebridge_errors)(int) = 0;

unsigned long
_BSP_clear_hostbridge_errors(int enableMCP, int quiet)
{
unsigned long	rval;

	/* MCP is not connected */
	if ( enableMCP )
		return -1;

	rval  = (clear_hose_errors(0, quiet) & PCI_ERR_BITS)>>8;
	rval |= clear_hose_errors(BSP_pci_hose1_bus_base, quiet) & PCI_ERR_BITS;

	/* Tsi148 doesn't propagate VME bus errors to PCI status reg. */
	if ( _BSP_clear_vmebridge_errors )
		rval |= _BSP_clear_vmebridge_errors(quiet)<<16;

	return rval;
}