Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:52

0001 /* PCI configuration space access */
0002 
0003 /* 
0004  * Acknowledgements:
0005  * Valuable information was obtained from the following drivers
0006  *   netbsd: (C) Allegro Networks Inc; Wasabi Systems Inc.
0007  *   linux:  (C) MontaVista, Software, Inc; Chris Zankel, Mark A. Greer.
0008  *   rtems:  (C) Brookhaven National Laboratory; K. Feng
0009  */
0010 
0011 /*
0012  * Original file header of libbsp/shared/pci.c where this file is based upon.
0013  *
0014  *  Copyright (C) 1999 valette@crf.canon.fr
0015  *
0016  *  This code is heavily inspired by the public specification of STREAM V2
0017  *  that can be found at :
0018  *
0019  *      <http://www.chorus.com/Documentation/index.html> by following
0020  *  the STREAM API Specification Document link.
0021  *
0022  *  The license and distribution terms for this file may be
0023  *  found in the file LICENSE in this distribution or at
0024  *  http://www.rtems.org/license/LICENSE.
0025  *
0026  *  Till Straumann, <strauman@slac.stanford.edu>, 1/2002
0027  *   - separated bridge detection code out of this file
0028  */
0029 
0030 #include <rtems.h>
0031 #include <bsp.h>
0032 #include <libcpu/io.h>
0033 #include <bsp/pci.h>
0034 #include <rtems/bspIo.h>
0035 #include <stdint.h>
0036 
0037 /* set to max so we get early access to hose 0 */
0038 unsigned    BSP_pci_hose1_bus_base = (unsigned)-1;
0039 
0040 #define MV64x60_PCI0_CONFIG_ADDR    (BSP_MV64x60_BASE + 0xcf8)
0041 #define MV64x60_PCI0_CONFIG_DATA    (BSP_MV64x60_BASE + 0xcfc)
0042 #define MV64x60_PCI1_CONFIG_ADDR    (BSP_MV64x60_BASE + 0xc78)
0043 #define MV64x60_PCI1_CONFIG_DATA    (BSP_MV64x60_BASE + 0xc7c)
0044 
0045 #define PCI_BUS2HOSE(bus) (bus<BSP_pci_hose1_bus_base?0:1)
0046 
0047 void detect_host_bridge(void)
0048 {
0049 
0050 }
0051 
0052 typedef struct {
0053     volatile unsigned char *pci_config_addr;
0054     volatile unsigned char *pci_config_data;
0055 } PciHoseCfg;
0056 
0057 static PciHoseCfg hoses[2] = {
0058     {
0059         pci_config_addr:    (volatile unsigned char *)(MV64x60_PCI0_CONFIG_ADDR),
0060         pci_config_data:    (volatile unsigned char *)(MV64x60_PCI0_CONFIG_DATA),
0061     },
0062     {
0063         pci_config_addr:    (volatile unsigned char *)(MV64x60_PCI1_CONFIG_ADDR),
0064         pci_config_data:    (volatile unsigned char *)(MV64x60_PCI1_CONFIG_DATA),
0065     }
0066 };
0067 
0068 #define pci hoses[hose]
0069 
0070 #define HOSE_PREAMBLE \
0071     uint8_t hose; \
0072         if (bus < BSP_pci_hose1_bus_base) { \
0073             hose = 0; \
0074         } else { \
0075             hose = 1; \
0076             bus -= BSP_pci_hose1_bus_base; \
0077         }
0078 
0079 
0080 /* Sigh; we have to copy those out from the shared area... */
0081 static int
0082 indirect_pci_read_config_byte(unsigned char bus, unsigned char slot,
0083                   unsigned char function, 
0084                   unsigned char offset, uint8_t *val) {
0085 HOSE_PREAMBLE;
0086     out_be32((volatile uint32_t *) pci.pci_config_addr,
0087          0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
0088     *val = in_8(pci.pci_config_data + (offset&3));
0089     return PCIBIOS_SUCCESSFUL;
0090 }
0091 
0092 static int
0093 indirect_pci_read_config_word(unsigned char bus, unsigned char slot,
0094                   unsigned char function, 
0095                   unsigned char offset, uint16_t *val) {
0096 HOSE_PREAMBLE;
0097     *val = 0xffff; 
0098     if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
0099     out_be32((uint32_t*) pci.pci_config_addr,
0100          0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
0101     *val = in_le16((volatile uint16_t *)(pci.pci_config_data + (offset&3)));
0102     return PCIBIOS_SUCCESSFUL;
0103 }
0104 
0105 static int
0106 indirect_pci_read_config_dword(unsigned char bus, unsigned char slot,
0107                   unsigned char function, 
0108                   unsigned char offset, uint32_t *val) {
0109 HOSE_PREAMBLE;
0110     *val = 0xffffffff; 
0111     if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
0112     out_be32((uint32_t*) pci.pci_config_addr,
0113          0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|(offset<<24));
0114     *val = in_le32((volatile uint32_t *)pci.pci_config_data);
0115     return PCIBIOS_SUCCESSFUL;
0116 }
0117 
0118 static int
0119 indirect_pci_write_config_byte(unsigned char bus, unsigned char slot,
0120                    unsigned char function, 
0121                    unsigned char offset, uint8_t val) {
0122 HOSE_PREAMBLE;
0123     out_be32((uint32_t*) pci.pci_config_addr,
0124          0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
0125     out_8(pci.pci_config_data + (offset&3), val);
0126     return PCIBIOS_SUCCESSFUL;
0127 }
0128 
0129 static int
0130 indirect_pci_write_config_word(unsigned char bus, unsigned char slot,
0131                    unsigned char function, 
0132                    unsigned char offset, uint16_t val) {
0133 HOSE_PREAMBLE;
0134     if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
0135     out_be32((uint32_t*) pci.pci_config_addr,
0136          0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|((offset&~3)<<24));
0137     out_le16((volatile uint16_t *)(pci.pci_config_data + (offset&3)), val);
0138     return PCIBIOS_SUCCESSFUL;
0139 }
0140 
0141 static int
0142 indirect_pci_write_config_dword(unsigned char bus, unsigned char slot,
0143                 unsigned char function, 
0144                 unsigned char offset, uint32_t val) {
0145 HOSE_PREAMBLE;
0146     if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
0147     out_be32((uint32_t*) pci.pci_config_addr,
0148          0x80|(bus<<8)|(PCI_DEVFN(slot,function)<<16)|(offset<<24));
0149     out_le32((volatile uint32_t *)pci.pci_config_data, val);
0150     return PCIBIOS_SUCCESSFUL;
0151 }
0152 
0153 const pci_config_access_functions pci_hosed_indirect_functions = {
0154     indirect_pci_read_config_byte,
0155     indirect_pci_read_config_word,
0156     indirect_pci_read_config_dword,
0157     indirect_pci_write_config_byte,
0158     indirect_pci_write_config_word,
0159     indirect_pci_write_config_dword
0160 };
0161 
0162 
0163 extern unsigned char ucMaxPCIBus; /* importing this is ugly */
0164 
0165 /* This is a very ugly hack. I don't want to change the shared
0166  * code to support multiple hoses so we hide everything under
0167  * the hood with horrible kludges for now. Sorry.
0168  */
0169 void
0170 BSP_pci_initialize(void)
0171 {
0172 
0173 #if 0   /* These values are already set up for the shared/pci.c code      */
0174 {
0175 extern pci_config_access_functions pci_indirect_functions;
0176         /* by means of the PCI_CONFIG_ADDR/PCI_CONFIG_DATA macros (bsp.h) */
0177     BSP_pci_configuration.pci_config_addr = hoses[0].pci_config_addr;
0178     BSP_pci_configuration.pci_config_data = hoses[0].pci_config_data;
0179     BSP_pci_configuration.pci_functions   = &pci_indirect_functions;
0180 }
0181 #endif
0182     /* initialize the first hose */
0183     /* scan hose 0 and sets the maximum bus number */
0184     pci_initialize();
0185     /* remember the boundary */
0186     BSP_pci_hose1_bus_base = pci_bus_count();
0187     /* so far, so good -- now comes the cludgy part: */
0188     /* hack/reset the bus count */
0189     ucMaxPCIBus = 0;
0190     /* scan hose 1 */
0191     BSP_pci_configuration.pci_config_addr = hoses[1].pci_config_addr;
0192     BSP_pci_configuration.pci_config_data = hoses[1].pci_config_data;
0193     pci_initialize();
0194     /* check for overflow of an unsigned char */
0195     if ( BSP_pci_hose1_bus_base + pci_bus_count() > 255 ) {
0196         rtems_panic("Too many PCI busses in the system");
0197     }
0198     /* readjust total number */
0199     ucMaxPCIBus+=BSP_pci_hose1_bus_base;
0200 
0201     /* install new access functions that can hide the hoses */
0202     BSP_pci_configuration.pci_config_addr = (volatile unsigned char *)0xdeadbeef;
0203     BSP_pci_configuration.pci_config_data = (volatile unsigned char *)0xdeadbeef;
0204     BSP_pci_configuration.pci_functions   = &pci_hosed_indirect_functions;
0205 }
0206 
0207 #define PCI_ERR_BITS        0xf900
0208 #define PCI_STATUS_OK(x)    (!((x)&PCI_ERR_BITS))
0209 
0210 /* For now, just clear errors in the PCI status reg.
0211  *
0212  * Returns: (for diagnostic purposes)
0213  *          original settings (i.e. before applying the clearing
0214  *          sequence) 
0215  *          (pci_status(hose_1)&0xff00) | ((pci_status(hose_2)>>8)&0xff)
0216  */
0217 
0218 static unsigned long clear_hose_errors(int bus, int quiet)
0219 {
0220 unsigned long   rval;
0221 uint16_t        pcistat;
0222 int             count;
0223 int             hose = PCI_BUS2HOSE(bus);
0224 
0225     /* read error status for info return */
0226     pci_read_config_word(bus,0,0,PCI_STATUS,&pcistat);
0227     rval = pcistat;
0228 
0229     count=10;
0230     do {
0231         /* clear error reporting registers */
0232 
0233         /* clear PCI status register */
0234         pci_write_config_word(bus,0,0,PCI_STATUS, PCI_ERR_BITS);
0235 
0236         /* read  new status */
0237         pci_read_config_word(bus,0,0,PCI_STATUS, &pcistat);
0238 
0239     } while ( ! PCI_STATUS_OK(pcistat) && count-- );
0240 
0241     if ( !PCI_STATUS_OK(rval) && !quiet) {
0242         printk("Cleared PCI errors at discovery (hose %i): pci_stat was 0x%04lx\n", hose, rval);
0243     }
0244     if ( !PCI_STATUS_OK(pcistat) ) {
0245         printk("Unable to clear PCI errors at discovery (hose %i) still 0x%04x after 10 attempts\n",hose, pcistat);
0246     }
0247     return rval;
0248 }
0249 
0250 unsigned short
0251 (*_BSP_clear_vmebridge_errors)(int) = 0;
0252 
0253 unsigned long
0254 _BSP_clear_hostbridge_errors(int enableMCP, int quiet)
0255 {
0256 unsigned long   rval;
0257 
0258     /* MCP is not connected */
0259     if ( enableMCP )
0260         return -1;
0261 
0262     rval  = (clear_hose_errors(0, quiet) & PCI_ERR_BITS)>>8;
0263     rval |= clear_hose_errors(BSP_pci_hose1_bus_base, quiet) & PCI_ERR_BITS;
0264 
0265     /* Tsi148 doesn't propagate VME bus errors to PCI status reg. */
0266     if ( _BSP_clear_vmebridge_errors )
0267         rval |= _BSP_clear_vmebridge_errors(quiet)<<16;
0268 
0269     return rval;
0270 }