diff options
Diffstat (limited to 'bsps/powerpc/beatnik/pci/gt_pci_init.c')
-rw-r--r-- | bsps/powerpc/beatnik/pci/gt_pci_init.c | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/bsps/powerpc/beatnik/pci/gt_pci_init.c b/bsps/powerpc/beatnik/pci/gt_pci_init.c new file mode 100644 index 0000000000..68d7467b22 --- /dev/null +++ b/bsps/powerpc/beatnik/pci/gt_pci_init.c @@ -0,0 +1,270 @@ +/* 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; +} |