diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-23 12:50:58 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-23 15:18:45 +0200 |
commit | 5a4e3dc0a5af631b1723858bc50a9af1545392fb (patch) | |
tree | f2825a86e99fbf1982fc484278483a03728ccc3a /bsps/powerpc/beatnik | |
parent | bsps/sh: Move console.c to bsps (diff) | |
download | rtems-5a4e3dc0a5af631b1723858bc50a9af1545392fb.tar.bz2 |
bsps: Move PCI drivers to bsps
This patch is a part of the BSP source reorganization.
Update #3285.
Diffstat (limited to 'bsps/powerpc/beatnik')
-rw-r--r-- | bsps/powerpc/beatnik/pci/gt_pci_init.c | 270 | ||||
-rw-r--r-- | bsps/powerpc/beatnik/pci/motload_fixup.c | 180 | ||||
-rw-r--r-- | bsps/powerpc/beatnik/pci/pci_io_remap.c | 203 | ||||
-rw-r--r-- | bsps/powerpc/beatnik/pci/pci_io_remap.h | 66 |
4 files changed, 719 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; +} diff --git a/bsps/powerpc/beatnik/pci/motload_fixup.c b/bsps/powerpc/beatnik/pci/motload_fixup.c new file mode 100644 index 0000000000..21d55916cb --- /dev/null +++ b/bsps/powerpc/beatnik/pci/motload_fixup.c @@ -0,0 +1,180 @@ +/* remap the zero-based PCI IO spaces of both hoses to a single + * address space + * + * This must be called AFTER to BSP_pci_initialize() + */ + +/* + * Authorship + * ---------- + * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was + * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * The 'beatnik' BSP was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ +#include <rtems.h> +#include <bsp.h> +#include <libcpu/io.h> +#include <bsp/pci.h> +#include <bsp/irq.h> +#include <rtems/bspIo.h> +#include <bsp/gtreg.h> +#include "pci_io_remap.h" + +static int +fixup_irq_line(int bus, int slot, int fun, void *uarg) +{ +unsigned char line; + pci_read_config_byte( bus, slot, fun, PCI_INTERRUPT_LINE, &line); + if ( line < BSP_IRQ_GPP_0 ) { + pci_write_config_byte( bus, slot, fun, PCI_INTERRUPT_LINE, line + BSP_IRQ_GPP_0 ); + } + + return 0; +} + +void BSP_motload_pci_fixup(void) +{ +uint32_t b0,b1,r0,r1,lim,dis; + + /* MotLoad on the mvme5500 and mvme6100 configures the PCI + * busses nicely, i.e., the values read from the memory address + * space BARs by means of PCI config cycles directly reflect the + * CPU memory map. Thus, the presence of two hoses is already hidden. + * + * Unfortunately, all PCI I/O addresses are 'zero-based' i.e., + * a hose-specific base address would have to be added to + * the values read from config space. + * + * We fix this here so I/O BARs also reflect the CPU memory map. + * + * Furthermore, the mvme5500 uses + * f000.0000 + * ..f07f.ffff for PCI-0 / hose0 + * + * and + * + * f080.0000 + * ..f0ff.0000 for PCI-1 / hose 0 + * + * whereas the mvme6100 does it the other way round... + */ + + b0 = in_le32( (volatile uint32_t*)(BSP_MV64x60_BASE + GT_PCI0_IO_Low_Decode) ); + b1 = in_le32( (volatile uint32_t*)(BSP_MV64x60_BASE + GT_PCI1_IO_Low_Decode) ); + + r0 = in_le32( (volatile uint32_t*)(BSP_MV64x60_BASE + GT_PCI0_IO_Remap) ); + r1 = in_le32( (volatile uint32_t*)(BSP_MV64x60_BASE + GT_PCI1_IO_Remap) ); + + switch ( BSP_getDiscoveryVersion(0) ) { + case MV_64360: + /* In case of the MV64360 the 'limit' is actually a 'size'! + * Disable by setting special bits in the 'BAR disable reg'. + */ + dis = in_le32( (volatile uint32_t*)(BSP_MV64x60_BASE + MV_64360_BASE_ADDR_DISBL) ); + /* disable PCI0 I/O and PCI1 I/O */ + out_le32( (volatile uint32_t*)(BSP_MV64x60_BASE + MV_64360_BASE_ADDR_DISBL), dis | (1<<9) | (1<<14) ); + /* remap busses on hose 0; if the remap register was already set, assume + * that someone else [such as the bootloader] already performed the fixup + */ + if ( (b0 & 0xffff) && 0 == (r0 & 0xffff) ) { + rtems_pci_io_remap( 0, BSP_pci_hose1_bus_base, (b0 & 0xffff)<<16 ); + out_le32( (volatile uint32_t*)(BSP_MV64x60_BASE + GT_PCI0_IO_Remap), (b0 & 0xffff) ); + } + + /* remap busses on hose 1 */ + if ( (b1 & 0xffff) && 0 == (r1 & 0xffff) ) { + rtems_pci_io_remap( BSP_pci_hose1_bus_base, pci_bus_count(), (b1 & 0xffff)<<16 ); + out_le32( (volatile uint32_t*)(BSP_MV64x60_BASE + GT_PCI1_IO_Remap), (b1 & 0xffff) ); + } + + /* re-enable */ + out_le32( (volatile uint32_t*)(BSP_MV64x60_BASE + MV_64360_BASE_ADDR_DISBL), dis ); + break; + + case GT_64260_A: + case GT_64260_B: + + if ( (b0 & 0xfff) && 0 == (r0 & 0xfff) ) { /* base are only 12 bits */ + /* switch window off by setting the limit < base */ + lim = in_le32( (volatile uint32_t*)(BSP_MV64x60_BASE + GT_PCI0_IO_High_Decode) ); + out_le32( (volatile uint32_t*)(BSP_MV64x60_BASE + GT_PCI0_IO_High_Decode), 0 ); + /* remap busses on hose 0 */ + rtems_pci_io_remap( 0, BSP_pci_hose1_bus_base, (b0 & 0xfff)<<20 ); + + /* BTW: it seems that writing the base register also copies the + * value into the 'remap' register automatically (??) + */ + out_le32( (volatile uint32_t*)(BSP_MV64x60_BASE + GT_PCI0_IO_Remap), (b0 & 0xfff) ); + + /* re-enable */ + out_le32( (volatile uint32_t*)(BSP_MV64x60_BASE + GT_PCI0_IO_High_Decode), lim ); + } + + if ( (b1 & 0xfff) && 0 == (r1 & 0xfff) ) { /* base are only 12 bits */ + /* switch window off by setting the limit < base */ + lim = in_le32( (volatile uint32_t*)(BSP_MV64x60_BASE + GT_PCI1_IO_High_Decode) ); + out_le32( (volatile uint32_t*)(BSP_MV64x60_BASE + GT_PCI1_IO_High_Decode), 0 ); + + /* remap busses on hose 1 */ + rtems_pci_io_remap( BSP_pci_hose1_bus_base, pci_bus_count(), (b1 & 0xfff)<<20 ); + + out_le32( (volatile uint32_t*)(BSP_MV64x60_BASE + GT_PCI1_IO_Remap), (b1 & 0xfff) ); + + /* re-enable */ + out_le32( (volatile uint32_t*)(BSP_MV64x60_BASE + GT_PCI1_IO_High_Decode), lim ); + } + break; + + default: + rtems_panic("Unknown discovery version; switch in file: "__FILE__" not implemented (yet)"); + break; /* never get here */ + } + + /* Fixup the IRQ lines; the mvme6100 maps them nicely into our scheme, i.e., GPP + * interrupts start at 64 upwards + * + * The mvme5500 is apparently initialized differently :-(. GPP interrupts start at 0 + * Since all PCI interrupts are wired to GPP we simply check for a value < 64 and + * reprogram the interrupt line register. + */ + BSP_pciScan(0, fixup_irq_line, 0); +} + + diff --git a/bsps/powerpc/beatnik/pci/pci_io_remap.c b/bsps/powerpc/beatnik/pci/pci_io_remap.c new file mode 100644 index 0000000000..56118d01d5 --- /dev/null +++ b/bsps/powerpc/beatnik/pci/pci_io_remap.c @@ -0,0 +1,203 @@ +/* Adjust a PCI bus range's I/O address space by adding an offset */ + +/* + * Authorship + * ---------- + * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was + * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * The 'beatnik' BSP was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +#include <rtems.h> +#include <rtems/bspIo.h> +#include <bsp/pci.h> +#include <stdint.h> +#include "pci_io_remap.h" + +#ifndef PCI_MULTI_FUN +#define PCI_MULTI_FUN 0x80 +#endif + +#ifndef PCI_HEADER_TYPE_MSK +#define PCI_HEADER_TYPE_MSK 0x7f +#endif + +/* Reconfigure all I/O base address registers for a range of PCI busses + * (from and including 'bus_from' up to and not including 'bus_to'). + * adding an offset. This involves adjusting the base and limit registers + * of PCI-PCI bridges, too. + * + * RESTRICTIONS: 'offset' must be 4k aligned (PCI req.); no argument check + * on the bus numbers is done. + * + * RETURNS: 0 on success and a number > 0 indicating the number of + * non-32bit bridges found where the offset couldn't be added. + * Devices behind such a bridge are not accessible through I/O + * and should probably be switched off (not done by this code). + */ +int +rtems_pci_io_remap(int bus_from, int bus_to, uint32_t offset) +{ + int rval = 0; + int bus, dev, fun, maxf; + int bar, numBars = 0; + uint8_t b; + uint16_t s; + uint32_t d; + unsigned int bas, lim; + + if ( offset & ((1<<12)-1) ) { + rtems_panic("rtems_pci_io_remap(): offset must be 4k aligned"); + return -1; + } + + + for ( bus=bus_from; bus < bus_to; bus++ ) { + for ( dev = 0; dev<PCI_MAX_DEVICES; dev++ ) { + + maxf = 1; + + for ( fun = 0; fun < maxf; fun++ ) { + pci_read_config_word( bus, dev, fun, PCI_VENDOR_ID, &s ); + if ( 0xffff == s ) + continue; + + pci_read_config_byte( bus, dev, fun, PCI_HEADER_TYPE, &b ); + + /* readjust the max. function number to scan if this is a multi-function + * device. + */ + if ( 0 == fun && (PCI_MULTI_FUN & b) ) + maxf = PCI_MAX_FUNCTIONS; + + /* Check the header type; panic if unknown. + * header type 0 has 6 bars, header type 1 (PCI-PCI bridge) has 2 + */ + b &= PCI_HEADER_TYPE_MSK; + switch ( b ) { + default: + printk("PCI header type %i (@%i/%i/%i)\n", b, bus, dev, fun); + rtems_panic("rtems_pci_io_remap(): unknown PCI header type"); + return -1; /* keep compiler happy */ + + case PCI_HEADER_TYPE_CARDBUS: + printk("PCI header type %i (@%i/%i/%i)\n", b, bus, dev, fun); + rtems_panic("rtems_pci_io_remap(): don't know how to deal with Cardbus bridge"); + return -1; + + case PCI_HEADER_TYPE_NORMAL: + numBars = 6*4; /* loop below counts reg. offset in bytes */ + break; + + case PCI_HEADER_TYPE_BRIDGE: + numBars = 2*4; /* loop below counts reg. offset in bytes */ + break; + + } + + for ( bar = 0; bar < numBars; bar+=4 ) { + pci_read_config_dword( bus, dev, fun, PCI_BASE_ADDRESS_0 + bar, &d ); + if ( PCI_BASE_ADDRESS_SPACE_IO & d ) { + /* It's an I/O BAR; remap */ + d &= PCI_BASE_ADDRESS_IO_MASK; + if ( d ) { + /* IO bar was configured; add offset */ + d += offset; + pci_write_config_dword( bus, dev, fun, PCI_BASE_ADDRESS_0 + bar, d ); + } + } else { + /* skip upper half of 64-bit window */ + d &= PCI_BASE_ADDRESS_MEM_TYPE_MASK; + if ( PCI_BASE_ADDRESS_MEM_TYPE_64 == d ) + bar+=4; + } + } + + /* Now it's time to deal with bridges */ + if ( PCI_HEADER_TYPE_BRIDGE == b ) { + /* must adjust the limit registers */ + pci_read_config_byte( bus, dev, fun, PCI_IO_LIMIT, &b ); + pci_read_config_word( bus, dev, fun, PCI_IO_LIMIT_UPPER16, &s ); + lim = (s<<16) + (( b & PCI_IO_RANGE_MASK ) << 8); + lim += offset; + + pci_read_config_byte( bus, dev, fun, PCI_IO_BASE, &b ); + pci_read_config_word( bus, dev, fun, PCI_IO_BASE_UPPER16, &s ); + bas = (s<<16) + (( b & PCI_IO_RANGE_MASK ) << 8); + bas += offset; + + b &= PCI_IO_RANGE_TYPE_MASK; + switch ( b ) { + default: + printk("Unknown IO range type 0x%x (@%i/%i/%i)\n", b, bus, dev, fun); + rtems_panic("rtems_pci_io_remap(): unknown IO range type"); + return -1; + + case PCI_IO_RANGE_TYPE_16: + if ( bas > 0xffff || lim > 0xffff ) { + printk("PCI I/O range type 1 (16bit) bridge (@%i/%i/%i) found:\n", bus, dev, fun); + printk("WARNING: base (0x%08x) or limit (0x%08x) exceed 16-bit;\n", bas, lim); + printk(" devices behind this bridge are NOT accessible!\n"); + + /* FIXME: should we disable devices behind this bridge ? */ + bas = lim = 0; + } + break; + + case PCI_IO_RANGE_TYPE_32: + break; + } + + b = (uint8_t)((bas>>8) & PCI_IO_RANGE_MASK); + pci_write_config_byte( bus, dev, fun, PCI_IO_BASE, b ); + + s = (uint16_t)((bas>>16)&0xffff); + pci_write_config_word( bus, dev, fun, PCI_IO_BASE_UPPER16, s); + + b = (uint8_t)((lim>>8) & PCI_IO_RANGE_MASK); + pci_write_config_byte( bus, dev, fun, PCI_IO_LIMIT, b ); + s = (uint16_t)((lim>>16)&0xffff); + pci_write_config_word( bus, dev, fun, PCI_IO_LIMIT_UPPER16, s ); + } + } + } + } + return rval; +} diff --git a/bsps/powerpc/beatnik/pci/pci_io_remap.h b/bsps/powerpc/beatnik/pci/pci_io_remap.h new file mode 100644 index 0000000000..533519a2ae --- /dev/null +++ b/bsps/powerpc/beatnik/pci/pci_io_remap.h @@ -0,0 +1,66 @@ +#ifndef RTEMS_PCI_IO_REMAP_H +#define RTEMS_PCI_IO_REMAP_H +/* Reconfigure all I/O base address registers for a range of PCI busses + * (from and including 'bus_from' up to and not including 'bus_to'). + * adding an offset. This involves adjusting the base and limit registers + * of PCI-PCI bridges, too. + * + * RESTRICTIONS: 'offset' must be 4k aligned (PCI req.); no argument check + * on the bus numbers is done. + * + * RETURNS: 0 on success and a number > 0 indicating the number of + * non-32bit bridges found where the offset couldn't be added. + * Devices behind such a bridge are not accessible through I/O + * and should probably be switched off (not done by this code). + */ + +int +rtems_pci_io_remap(int bus_from, int bus_to, uint32_t offset); + +/* + * Authorship + * ---------- + * This software ('beatnik' RTEMS BSP for MVME6100 and MVME5500) was + * created by Till Straumann <strauman@slac.stanford.edu>, 2005-2007, + * Stanford Linear Accelerator Center, Stanford University. + * + * Acknowledgement of sponsorship + * ------------------------------ + * The 'beatnik' BSP was produced by + * the Stanford Linear Accelerator Center, Stanford University, + * under Contract DE-AC03-76SFO0515 with the Department of Energy. + * + * Government disclaimer of liability + * ---------------------------------- + * Neither the United States nor the United States Department of Energy, + * nor any of their employees, makes any warranty, express or implied, or + * assumes any legal liability or responsibility for the accuracy, + * completeness, or usefulness of any data, apparatus, product, or process + * disclosed, or represents that its use would not infringe privately owned + * rights. + * + * Stanford disclaimer of liability + * -------------------------------- + * Stanford University makes no representations or warranties, express or + * implied, nor assumes any liability for the use of this software. + * + * Stanford disclaimer of copyright + * -------------------------------- + * Stanford University, owner of the copyright, hereby disclaims its + * copyright and all other rights in this software. Hence, anyone may + * freely use it for any purpose without restriction. + * + * Maintenance of notices + * ---------------------- + * In the interest of clarity regarding the origin and status of this + * SLAC software, this and all the preceding Stanford University notices + * are to remain affixed to any copy or derivative of this software made + * or distributed by the recipient and are to be affixed to any copy of + * software made or distributed by the recipient that contains a copy or + * derivative of this software. + * + * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03 + */ + +#endif + |