summaryrefslogtreecommitdiffstats
path: root/bsps
diff options
context:
space:
mode:
Diffstat (limited to 'bsps')
-rw-r--r--bsps/i386/shared/pci/pci_io.c213
-rw-r--r--bsps/i386/shared/pci/pcibios.c479
-rw-r--r--bsps/mips/malta/pci/pci.c1102
-rw-r--r--bsps/powerpc/beatnik/pci/gt_pci_init.c270
-rw-r--r--bsps/powerpc/beatnik/pci/motload_fixup.c180
-rw-r--r--bsps/powerpc/beatnik/pci/pci_io_remap.c203
-rw-r--r--bsps/powerpc/beatnik/pci/pci_io_remap.h66
-rw-r--r--bsps/powerpc/mvme3100/pci/detect_host_bridge.c113
-rw-r--r--bsps/powerpc/mvme5500/pci/detect_host_bridge.c72
-rw-r--r--bsps/powerpc/mvme5500/pci/pci.c420
-rw-r--r--bsps/powerpc/mvme5500/pci/pci_interface.c100
-rw-r--r--bsps/powerpc/shared/pci/detect_raven_bridge.c197
-rw-r--r--bsps/powerpc/shared/pci/generic_clear_hberrs.c63
-rw-r--r--bsps/powerpc/shared/pci/pci.c640
-rw-r--r--bsps/powerpc/shared/pci/pcifinddevice.c212
15 files changed, 4330 insertions, 0 deletions
diff --git a/bsps/i386/shared/pci/pci_io.c b/bsps/i386/shared/pci/pci_io.c
new file mode 100644
index 0000000000..b6cd1005f0
--- /dev/null
+++ b/bsps/i386/shared/pci/pci_io.c
@@ -0,0 +1,213 @@
+/**
+ * @file
+ *
+ * PCI Support when Configuration Space is in I/O
+ */
+
+/*
+ * COPYRIGHT (c) 2016.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * 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.
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <bsp/bspimpl.h>
+
+static int pci_io_initialized = 0;
+
+/*
+ * Forward reference. Initialized at bottom.
+ */
+static const pci_config_access_functions pci_io_indirect_functions;
+
+/*
+ * Detects presense of PCI Configuration is in I/O space. If so, return
+ * pointer to accessor methods.
+ *
+ * NOTE: TBD to determine if (a) PCI Bus exists and (b) this is the
+ * access method.
+ */
+const pci_config_access_functions *pci_io_initialize(void)
+{
+ pci_io_initialized = 1;
+
+ printk( "PCI I/O Support Initialized\n" );
+
+ return &pci_io_indirect_functions;
+}
+
+/*
+ * Build PCI Address
+ */
+static inline uint32_t pci_io_build_address(
+ uint16_t bus,
+ uint16_t slot,
+ uint16_t function,
+ uint16_t offset
+)
+{
+ uint32_t bus_u32 = (uint32_t)bus;
+ uint32_t slot_u32 = (uint32_t)slot;
+ uint32_t function_u32 = (uint32_t)function;
+ uint32_t address;
+
+ /*
+ * create configuration address as per figure at
+ * http://wiki.osdev.org/PCI#Configuration_Space_Access_Mechanism_.231
+ */
+ address = (uint32_t) 0x80000000; /* Bit 31 - Enable Bit */
+ /* Bits 30-24 - Reserved */
+ address |= bus_u32 << 16; /* Bits 23-16 - Bus Number */
+ address |= slot_u32 << 11; /* Bits 15-11 - Device/Slot Number */
+ address |= function_u32 << 8; /* Bits 10-8 - Function Number */
+ address |= offset & 0xfc; /* Bits 7-2 - Offset/Register Number */
+ /* Bits 1-0 - Reserved 0 */
+ return address;
+}
+
+static int BSP_pci_read_config_byte(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ unsigned char *value
+)
+{
+ uint32_t address;
+ uint32_t tmp;
+
+ address = pci_io_build_address( bus, slot, function, offset );
+
+ /* write out the address */
+ outport_long(0xCF8, address);
+
+ /* read in the data */
+ inport_long(0xCFC, tmp);
+
+ /* (offset & 3) * 8) = 0 will choose the first byte of the 32 bits register */
+ *value = (uint16_t)(tmp >> ((offset & 3) * 8)) & 0xff;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int BSP_pci_read_config_word(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ unsigned short *value
+)
+{
+ uint32_t address;
+ uint32_t tmp;
+
+ address = pci_io_build_address( bus, slot, function, offset );
+
+ /* write out the address */
+ outport_long(0xCF8, address);
+
+ /* read in the data */
+ inport_long(0xCFC, tmp);
+
+ /* (offset & 2) * 8) = 0 will choose the first word of the 32 bits register */
+ *value = (uint16_t)(tmp >> ((offset & 2) * 8)) & 0xffff;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int BSP_pci_read_config_dword(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint32_t *value
+)
+{
+ uint32_t address;
+ uint32_t tmp;
+
+ address = pci_io_build_address( bus, slot, function, offset );
+
+ /* write out the address */
+ outport_long(0xCF8, address);
+
+ /* read in the data */
+ inport_long(0xCFC, tmp);
+
+ *value = tmp;
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int BSP_pci_write_config_byte(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ unsigned char value
+)
+{
+ uint32_t address;
+
+ address = pci_io_build_address( bus, slot, function, offset );
+
+ /* write out the address */
+ outport_long(0xCF8, address);
+
+ /* read in the data */
+ outport_byte(0xCFC, value);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int BSP_pci_write_config_word(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ unsigned short value
+)
+{
+ uint32_t address;
+
+ address = pci_io_build_address( bus, slot, function, offset );
+
+ /* write out the address */
+ outport_long(0xCF8, address);
+
+ /* read in the data */
+ outport_word(0xCFC, value);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int BSP_pci_write_config_dword(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint32_t value
+)
+{
+ uint32_t address;
+
+ address = pci_io_build_address( bus, slot, function, offset );
+
+ /* write out the address */
+ outport_long(0xCF8, address);
+
+ /* read in the data */
+ outport_long(0xCFC, value);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static const pci_config_access_functions pci_io_indirect_functions = {
+ BSP_pci_read_config_byte,
+ BSP_pci_read_config_word,
+ BSP_pci_read_config_dword,
+ BSP_pci_write_config_byte,
+ BSP_pci_write_config_word,
+ BSP_pci_write_config_dword
+};
diff --git a/bsps/i386/shared/pci/pcibios.c b/bsps/i386/shared/pci/pcibios.c
new file mode 100644
index 0000000000..173c89f3f8
--- /dev/null
+++ b/bsps/i386/shared/pci/pcibios.c
@@ -0,0 +1,479 @@
+/**
+ * @file
+ *
+ * PCI Support when Configuration Space is accessed via BIOS
+ */
+
+/*
+ * This software is Copyright (C) 1998 by T.sqware - all rights limited
+ * It is provided in to the public domain "as is", can be freely modified
+ * as far as this copyight notice is kept unchanged, but does not imply
+ * an endorsement by T.sqware of the product in which it is included.
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+#include <rtems/pci.h>
+
+#include <string.h> /* memcpy */
+
+/*
+ * This is simpliest possible PCI BIOS, it assumes that addressing
+ * is flat and that stack is big enough
+ */
+static int pcibInitialized = 0;
+static unsigned int pcibEntry;
+
+/*
+ * Array to pass data between c and __asm__ parts, at the time of
+ * writing I am not yet that familiar with extended __asm__ feature
+ * of gcc. This code is not on performance path, so we can care
+ * relatively little about performance here
+ */
+static volatile unsigned int pcibExchg[5];
+
+static int pcib_convert_err(int err);
+
+/** @brief
+ * Make device signature from bus number, device numebr and function
+ * number
+ */
+#define PCIB_DEVSIG_MAKE(b,d,f) ((b<<8)|(d<<3)|(f))
+
+/** @brief
+ * Extract valrous part from device signature
+ */
+#define PCIB_DEVSIG_BUS(x) (((x)>>8) &0xff)
+#define PCIB_DEVSIG_DEV(x) (((x)>>3) & 0x1f)
+#define PCIB_DEVSIG_FUNC(x) ((x) & 0x7)
+
+/*
+ * Forward reference. Initialized at bottom.
+ */
+static const pci_config_access_functions pci_bios_indirect_functions;
+
+/* prototype before defining */
+const pci_config_access_functions *pci_bios_initialize(void);
+
+/*
+ * Detects presense of PCI BIOS, returns pointer to accessor methods.
+ */
+const pci_config_access_functions *pci_bios_initialize(void)
+{
+ unsigned char *ucp;
+ unsigned char sum;
+ int i;
+
+ pcibInitialized = 0;
+
+ /* First, we have to look for BIOS-32 */
+ for (ucp = (unsigned char *)0xE0000;
+ ucp < (unsigned char *)0xFFFFF;
+ ucp += 0x10) {
+ if (memcmp(ucp, "_32_", 4) != 0) {
+ continue;
+ }
+
+ /* Got signature, check length */
+ if (*(ucp + 9) != 1) {
+ continue;
+ }
+
+ /* Verify checksum */
+ sum = 0;
+ for (i=0; i<16; i++) {
+ sum += *(ucp+i);
+ }
+
+ if (sum == 0) {
+ /* found */
+ break;
+ }
+ }
+
+ if (ucp >= (unsigned char *)0xFFFFF) {
+ /* BIOS-32 not found */
+ return NULL;
+ }
+
+ /* BIOS-32 found, let us find PCI BIOS */
+ ucp += 4;
+
+ pcibExchg[0] = *(unsigned int *)ucp;
+
+ __asm__ (" pusha"); /* Push all registers */
+ __asm__ (" movl pcibExchg, %edi"); /* Move entry point to esi */
+ __asm__ (" movl $0x49435024, %eax"); /* Move signature to eax */
+ __asm__ (" xorl %ebx, %ebx"); /* Zero ebx */
+ __asm__ (" pushl %cs");
+ __asm__ (" call *%edi"); /* Call entry */
+ __asm__ (" movl %eax, pcibExchg");
+ __asm__ (" movl %ebx, pcibExchg+4");
+ __asm__ (" movl %ecx, pcibExchg+8");
+ __asm__ (" movl %edx, pcibExchg+12");
+ __asm__ (" popa");
+
+ if ((pcibExchg[0] & 0xff) != 0) {
+ /* Not found */
+ return NULL;
+ }
+
+ /* Found PCI entry point */
+ pcibEntry = pcibExchg[1] + pcibExchg[3];
+
+ /* Let us check whether PCI bios is present */
+ pcibExchg[0] = pcibEntry;
+
+ __asm__ (" pusha");
+ __asm__ (" movl pcibExchg, %edi");
+ __asm__ (" movb $0xb1, %ah");
+ __asm__ (" movb $0x01, %al");
+ __asm__ (" pushl %cs");
+ __asm__ (" call *%edi");
+ __asm__ (" movl %eax, pcibExchg");
+ __asm__ (" movl %ebx, pcibExchg+4");
+ __asm__ (" movl %ecx, pcibExchg+8");
+ __asm__ (" movl %edx, pcibExchg+12");
+ __asm__ (" popa");
+
+ if ((pcibExchg[0] & 0xff00) != 0) {
+ /* Not found */
+ return NULL;
+ }
+
+ if (pcibExchg[3] != 0x20494350) {
+ /* Signature does not match */
+ return NULL;
+ }
+
+ /* Success */
+ pcibInitialized = 1;
+
+ return &pci_bios_indirect_functions;
+}
+
+/*
+ * Read byte from config space
+ */
+static int
+pcib_conf_read8(int sig, int off, uint8_t *data)
+{
+ if (!pcibInitialized) {
+ return PCIB_ERR_UNINITIALIZED;
+ }
+
+ pcibExchg[0] = pcibEntry;
+ pcibExchg[1] = sig;
+ pcibExchg[2] = off;
+
+ __asm__ (" pusha");
+ __asm__ (" movl pcibExchg, %esi");
+ __asm__ (" movb $0xb1, %ah");
+ __asm__ (" movb $0x08, %al");
+ __asm__ (" movl pcibExchg+4, %ebx");
+ __asm__ (" movl pcibExchg+8, %edi");
+ __asm__ (" pushl %cs");
+ __asm__ (" call *%esi");
+ __asm__ (" movl %eax, pcibExchg");
+ __asm__ (" movl %ecx, pcibExchg+4");
+ __asm__ (" popa");
+
+ if ((pcibExchg[0] & 0xff00) != 0) {
+ return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
+ }
+
+ *data = (unsigned char)pcibExchg[1] & 0xff;
+
+ return PCIB_ERR_SUCCESS;
+}
+
+
+/*
+ * Read word from config space
+ */
+static int
+pcib_conf_read16(int sig, int off, uint16_t *data)
+{
+ if (!pcibInitialized) {
+ return PCIB_ERR_UNINITIALIZED;
+ }
+
+ pcibExchg[0] = pcibEntry;
+ pcibExchg[1] = sig;
+ pcibExchg[2] = off;
+
+ __asm__ (" pusha");
+ __asm__ (" movl pcibExchg, %esi");
+ __asm__ (" movb $0xb1, %ah");
+ __asm__ (" movb $0x09, %al");
+ __asm__ (" movl pcibExchg+4, %ebx");
+ __asm__ (" movl pcibExchg+8, %edi");
+ __asm__ (" pushl %cs");
+ __asm__ (" call *%esi");
+ __asm__ (" movl %eax, pcibExchg");
+ __asm__ (" movl %ecx, pcibExchg+4");
+ __asm__ (" popa");
+
+ if ((pcibExchg[0] & 0xff00) != 0) {
+ return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
+ }
+
+ *data = (unsigned short)pcibExchg[1] & 0xffff;
+
+ return PCIB_ERR_SUCCESS;
+}
+
+
+/*
+ * Read dword from config space
+ */
+static int
+pcib_conf_read32(int sig, int off, uint32_t *data)
+{
+ if (!pcibInitialized) {
+ return PCIB_ERR_UNINITIALIZED;
+ }
+
+ pcibExchg[0] = pcibEntry;
+ pcibExchg[1] = sig;
+ pcibExchg[2] = off;
+
+ __asm__ (" pusha");
+ __asm__ (" movl pcibExchg, %esi");
+ __asm__ (" movb $0xb1, %ah");
+ __asm__ (" movb $0x0a, %al");
+ __asm__ (" movl pcibExchg+4, %ebx");
+ __asm__ (" movl pcibExchg+8, %edi");
+ __asm__ (" pushl %cs");
+ __asm__ (" call *%esi");
+ __asm__ (" movl %eax, pcibExchg");
+ __asm__ (" movl %ecx, pcibExchg+4");
+ __asm__ (" popa");
+
+ if ((pcibExchg[0] & 0xff00) != 0) {
+ return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
+ }
+
+ *data = (unsigned int)pcibExchg[1];
+
+ return PCIB_ERR_SUCCESS;
+}
+
+
+/*
+ * Write byte into config space
+ */
+static int
+pcib_conf_write8(int sig, int off, uint8_t data)
+{
+ if (!pcibInitialized) {
+ return PCIB_ERR_UNINITIALIZED;
+ }
+
+ pcibExchg[0] = pcibEntry;
+ pcibExchg[1] = sig;
+ pcibExchg[2] = off;
+ pcibExchg[3] = data & 0xff;
+
+ __asm__ (" pusha");
+ __asm__ (" movl pcibExchg, %esi");
+ __asm__ (" movb $0xb1, %ah");
+ __asm__ (" movb $0x0b, %al");
+ __asm__ (" movl pcibExchg+4, %ebx");
+ __asm__ (" movl pcibExchg+8, %edi");
+ __asm__ (" movl pcibExchg+12, %ecx");
+ __asm__ (" pushl %cs");
+ __asm__ (" call *%esi");
+ __asm__ (" movl %eax, pcibExchg");
+ __asm__ (" popa");
+
+ return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
+}
+
+/*
+ * Write word into config space
+ */
+static int
+pcib_conf_write16(int sig, int off, uint16_t data)
+{
+ if (!pcibInitialized) {
+ return PCIB_ERR_UNINITIALIZED;
+ }
+
+ pcibExchg[0] = pcibEntry;
+ pcibExchg[1] = sig;
+ pcibExchg[2] = off;
+ pcibExchg[3] = data & 0xffff;
+
+ __asm__ (" pusha");
+ __asm__ (" movl pcibExchg, %esi");
+ __asm__ (" movb $0xb1, %ah");
+ __asm__ (" movb $0x0c, %al");
+ __asm__ (" movl pcibExchg+4, %ebx");
+ __asm__ (" movl pcibExchg+8, %edi");
+ __asm__ (" movl pcibExchg+12, %ecx");
+ __asm__ (" pushl %cs");
+ __asm__ (" call *%esi");
+ __asm__ (" movl %eax, pcibExchg");
+ __asm__ (" popa");
+
+ return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
+}
+
+
+
+/*
+ * Write dword into config space
+ */
+static int
+pcib_conf_write32(int sig, int off, uint32_t data)
+{
+ if (!pcibInitialized){
+ return PCIB_ERR_UNINITIALIZED;
+ }
+
+ pcibExchg[0] = pcibEntry;
+ pcibExchg[1] = sig;
+ pcibExchg[2] = off;
+ pcibExchg[3] = data;
+
+ __asm__ (" pusha");
+ __asm__ (" movl pcibExchg, %esi");
+ __asm__ (" movb $0xb1, %ah");
+ __asm__ (" movb $0x0d, %al");
+ __asm__ (" movl pcibExchg+4, %ebx");
+ __asm__ (" movl pcibExchg+8, %edi");
+ __asm__ (" movl pcibExchg+12, %ecx");
+ __asm__ (" pushl %cs");
+ __asm__ (" call *%esi");
+ __asm__ (" movl %eax, pcibExchg");
+ __asm__ (" popa");
+
+ return pcib_convert_err((pcibExchg[0] >> 8) & 0xff);
+}
+
+
+static int
+pcib_convert_err(int err)
+{
+ switch(err & 0xff){
+ case 0:
+ return PCIB_ERR_SUCCESS;
+ case 0x81:
+ return PCIB_ERR_NOFUNC;
+ case 0x83:
+ return PCIB_ERR_BADVENDOR;
+ case 0x86:
+ return PCIB_ERR_DEVNOTFOUND;
+ case 0x87:
+ return PCIB_ERR_BADREG;
+ default:
+ break;
+ }
+ return PCIB_ERR_NOFUNC;
+}
+
+static int
+BSP_pci_read_config_byte(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char fun,
+ unsigned char offset,
+ unsigned char *val
+)
+{
+ int sig;
+
+ sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
+ pcib_conf_read8(sig, offset, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+BSP_pci_read_config_word(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char fun,
+ unsigned char offset,
+ unsigned short *val
+)
+{
+ int sig;
+
+ sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
+ pcib_conf_read16(sig, offset, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+BSP_pci_read_config_dword(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char fun,
+ unsigned char offset,
+ uint32_t *val
+)
+{
+ int sig;
+
+ sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
+ pcib_conf_read32(sig, offset, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+BSP_pci_write_config_byte(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char fun,
+ unsigned char offset,
+ unsigned char val
+)
+{
+ int sig;
+
+ sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
+ pcib_conf_write8(sig, offset, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+BSP_pci_write_config_word(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char fun,
+ unsigned char offset,
+ unsigned short val
+)
+{
+ int sig;
+
+ sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
+ pcib_conf_write16(sig, offset, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+BSP_pci_write_config_dword(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char fun,
+ unsigned char offset,
+ uint32_t val
+)
+{
+ int sig;
+
+ sig = PCIB_DEVSIG_MAKE(bus,slot,fun);
+ pcib_conf_write32(sig, offset, val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static const pci_config_access_functions pci_bios_indirect_functions = {
+ BSP_pci_read_config_byte,
+ BSP_pci_read_config_word,
+ BSP_pci_read_config_dword,
+ BSP_pci_write_config_byte,
+ BSP_pci_write_config_word,
+ BSP_pci_write_config_dword
+};
diff --git a/bsps/mips/malta/pci/pci.c b/bsps/mips/malta/pci/pci.c
new file mode 100644
index 0000000000..0932f07d35
--- /dev/null
+++ b/bsps/mips/malta/pci/pci.c
@@ -0,0 +1,1102 @@
+/**
+ * @file
+ *
+ * This file was based on the powerpc.
+ */
+
+/*
+ * COPYRIGHT (c) 1989-2012.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * 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.
+ */
+
+#include <rtems.h>
+#include <bsp.h>
+
+#include <bsp/pci.h>
+#include <bsp/irq.h>
+#include <rtems/bspIo.h>
+#include <rtems/endian.h>
+
+/*
+ * DEFINES
+ */
+
+#undef SHOW_PCI_SETTING
+
+// #define DEBUG_PCI 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
+
+/* define a shortcut */
+#define pci BSP_pci_configuration
+
+#ifndef PCI_CONFIG_ADDR_VAL
+#define PCI_CONFIG_ADDR_VAL(bus, slot, funcion, offset) \
+ (0x80000000|((bus)<<16)|(PCI_DEVFN((slot),(function))<<8)|(((offset)&~3)))
+#endif
+
+#ifdef DEBUG_PCI
+ #define JPRINTK(fmt, ...) printk("%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
+#else
+ #define JPRINTK(fmt, ...)
+#endif
+
+#ifndef PCI_CONFIG_WR_ADDR
+#define PCI_CONFIG_WR_ADDR( addr, val ) out_le32((uint32_t)(addr), (val))
+#endif
+
+/* Bit encode for PCI_CONFIG_HEADER_TYPE register */
+#define PCI_CONFIG_SET_ADDR(addr, bus, slot,function,offset) \
+ PCI_CONFIG_WR_ADDR( \
+ (addr), \
+ PCI_CONFIG_ADDR_VAL((bus), (slot), (function), (offset))\
+ )
+
+#define PRINT_MSG() \
+ printk("pci : Device %d:0x%02x:%d routed to interrupt_line %d\n", \
+ pbus, pslot, pfun, int_name )
+
+/*
+ * STRUCTURES
+ */
+
+/*
+ * PROTOTYPES
+ */
+void print_bars(
+ unsigned char slot,
+ unsigned char func
+);
+int direct_pci_read_config_byte(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint8_t *val
+);
+int direct_pci_read_config_word(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint16_t *val
+);
+int direct_pci_read_config_dword(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint32_t *val
+);
+int direct_pci_write_config_byte(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint8_t val
+);
+int direct_pci_write_config_word(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint16_t val
+);
+int direct_pci_write_config_dword(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint32_t val
+);
+int test_intname(
+ const struct _int_map *row,
+ int pbus,
+ int pslot,
+ int pfun,
+ int int_pin,
+ int int_name
+);
+void pci_memory_enable(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function
+);
+void pci_io_enable(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function
+);
+void pci_busmaster_enable(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function
+);
+
+/*
+ * GLOBALS
+ */
+unsigned char ucMaxPCIBus;
+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*)PCI_CONFIG_ADDR,
+ (volatile unsigned char*)PCI_CONFIG_DATA,
+ &pci_indirect_functions
+};
+
+const pci_config_access_functions pci_direct_functions = {
+ direct_pci_read_config_byte,
+ direct_pci_read_config_word,
+ direct_pci_read_config_dword,
+ direct_pci_write_config_byte,
+ direct_pci_write_config_word,
+ direct_pci_write_config_dword
+};
+
+/*
+ * PCI specific accesses. Note these are made on 32 bit
+ * boundries.
+ */
+void pci_out_32(uint32_t base, uint32_t addr, uint32_t val)
+{
+ volatile uint32_t *ptr;
+
+ ptr = (volatile uint32_t *) (base + addr);
+ *ptr = val;
+
+ JPRINTK( "%p data: 0x%x\n", ptr, val);
+}
+
+void pci_out_le32(uint32_t base, uint32_t addr, uint32_t val)
+{
+ volatile uint32_t *ptr;
+ uint32_t data = 0;
+
+ ptr = (volatile uint32_t *) (base + addr);
+ rtems_uint32_to_little_endian( val, (uint8_t *) &data);
+ *ptr = data;
+
+ JPRINTK( "%p data: 0x%x\n", ptr, data);
+}
+
+uint8_t pci_in_8( uint32_t base, uint32_t addr ) {
+ volatile uint32_t *ptr;
+ uint8_t val;
+ uint32_t data;
+
+ data = addr/4;
+ ptr = (volatile uint32_t *) (base + (data*4));
+ data = *ptr;
+
+ switch ( addr%4 ) {
+ case 0: val = (data & 0x000000ff) >> 0; break;
+ case 1: val = (data & 0x0000ff00) >> 8; break;
+ case 2: val = (data & 0x00ff0000) >> 16; break;
+ case 3: val = (data & 0xff000000) >> 24; break;
+ }
+
+ JPRINTK( "0x%x data: 0x%x raw: 0x%x\n", ptr, val, data);
+
+ return val;
+}
+
+int16_t pci_in_le16( uint32_t base, uint32_t addr ) {
+ volatile uint32_t *ptr;
+ uint16_t val;
+ uint16_t rval;
+ uint32_t data;
+
+ data = addr/4;
+ ptr = (volatile uint32_t *) (base + (data*4));
+ data = *ptr;
+ if ( addr%4 == 0 )
+ val = data & 0xffff;
+ else
+ val = (data>>16) & 0xffff;
+
+ rval = rtems_uint16_from_little_endian( (uint8_t *) &val);
+ JPRINTK( "0x%x data: 0x%x raw: 0x%x\n", ptr, rval, data);
+ return rval;
+}
+
+int16_t pci_in_16( uint32_t base, uint32_t addr ) {
+ volatile uint32_t *ptr;
+ uint16_t val;
+ uint32_t data;
+
+ data = addr/4;
+ ptr = (volatile uint32_t *) (base + (data*4));
+ data = *ptr;
+ if ( addr%4 == 0 )
+ val = data & 0xffff;
+ else
+ val = (data>>16) & 0xffff;
+
+ JPRINTK( "0x%x data: 0x%x raw: 0x%x\n", ptr, val, data);
+ return val;
+}
+
+uint32_t pci_in_32( uint32_t base, uint32_t addr ) {
+ volatile uint32_t *ptr;
+ uint32_t val;
+
+ ptr = (volatile uint32_t *) (base + addr);
+ val = *ptr;
+
+ JPRINTK( "0x%x data: 0x%x raw: 0x%x\n", ptr, val, val);
+ return val;
+}
+uint32_t pci_in_le32( uint32_t base, uint32_t addr ) {
+ volatile uint32_t *ptr;
+ uint32_t val;
+ uint32_t rval;
+
+ ptr = (volatile uint32_t *) (base + addr);
+ val = *ptr;
+ rval = rtems_uint32_from_little_endian( (uint8_t *) &val);
+
+ JPRINTK( "0x%x data: 0x%x raw: 0x%x\n", ptr, rval, val);
+ return rval;
+}
+
+void pci_out_8( uint32_t base, uint32_t addr, uint8_t val ) {
+ volatile uint32_t *ptr;
+
+ ptr = (volatile uint32_t *) (base + addr);
+ JPRINTK("Address: %p\n", ptr);
+ *ptr = val;
+ JPRINTK( "%p data: 0x%x\n", ptr, val);
+}
+
+void pci_out_le16( uint32_t base, uint32_t addr, uint16_t val ) {
+ volatile uint32_t *ptr;
+ uint32_t out_data;
+ uint32_t data;
+
+ ptr = (volatile uint32_t *) (base + (addr & ~0x3));
+ data = *ptr;
+ if ( addr%4 == 0 )
+ out_data = (data & 0xffff0000) | val;
+ else
+ out_data = ((val << 16)&0xffff0000) | (data & 0xffff);
+ rtems_uint32_to_little_endian( out_data, (uint8_t *) &data);
+ *ptr = data;
+
+ JPRINTK( "0x%x data: 0x%x\n", ptr, data);
+}
+
+void pci_out_16( uint32_t base, uint32_t addr, uint16_t val ) {
+ volatile uint32_t *ptr;
+ uint32_t out_data;
+ uint32_t data;
+
+ ptr = (volatile uint32_t *) (base + (addr & ~0x3));
+ data = *ptr;
+ if ( addr%4 == 0 )
+ out_data = (data & 0xffff0000) | val;
+ else
+ out_data = ((val << 16)&0xffff0000) | (data & 0xffff);
+ *ptr = out_data;
+
+ JPRINTK( "0x%x data: 0x%x\n", ptr, out_data);
+}
+
+/*
+ * INDIRECT PCI CONFIGURATION ACCESSES
+ */
+int indirect_pci_read_config_byte(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint8_t *val
+) {
+
+ JPRINTK("==>\n");
+ PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset);
+ *val = in_8((uint32_t) (pci.pci_config_data + (offset&3)) );
+ JPRINTK("\n\n");
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pci_read_config_word(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint16_t *val
+) {
+
+ JPRINTK("==>\n");
+
+ *val = 0xffff;
+ if (offset&1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset);
+ *val = in_16((uint32_t)(pci.pci_config_data + (offset&3)));
+
+ JPRINTK("\n\n");
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pci_read_config_dword(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint32_t *val
+) {
+ uint32_t v;
+ JPRINTK("==>\n");
+
+ *val = 0xffffffff;
+ if (offset&3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset);
+ v = in_32( (uint32_t) pci.pci_config_data );
+ *val = v;
+ if ( offset == 0x0b )
+ JPRINTK( "%x:%x %x ==> 0x%08x, 0x%08x\n", bus, slot, function, v, *val );
+
+ JPRINTK("\n\n");
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pci_write_config_byte(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint8_t val
+) {
+
+ JPRINTK("==>\n");
+
+ PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset);
+ out_8( (uint32_t) (pci.pci_config_data + (offset&3)), val);
+
+ JPRINTK("\n\n");
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pci_write_config_word(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint16_t val
+) {
+
+ JPRINTK("==>\n");
+
+ if (offset&1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset);
+ out_16((uint32_t)(pci.pci_config_data + (offset&3)), val);
+
+ JPRINTK("\n\n");
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pci_write_config_dword(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint32_t val
+) {
+
+ if (offset&3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ JPRINTK("==>\n");
+
+ /*
+ * The Base Address Registers get accessed big endian while the
+ * other registers are little endian.
+ */
+ PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset);
+ if ( bus == 0 && slot == 0x0b &&
+ (offset >= PCI_BASE_ADDRESS_0 && offset <= PCI_BASE_ADDRESS_5) ) {
+ out_32((uint32_t)pci.pci_config_data, val);
+ } else {
+ out_le32((uint32_t)pci.pci_config_data, val);
+ }
+
+ JPRINTK("\n\n");
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+/*
+ * DIRECT CONFIGUREATION ACCESSES.
+ */
+int direct_pci_read_config_byte(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint8_t *val
+) {
+ if (bus != 0 || (1<<slot & 0xff8007fe)) {
+ *val=0xff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ JPRINTK("==>\n");
+
+ *val=in_8((uint32_t) (pci.pci_config_data + ((1<<slot)&~1)
+ + (function<<8) + offset));
+
+ JPRINTK("\n\n");
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int direct_pci_read_config_word(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint16_t *val
+) {
+ *val = 0xffff;
+ if (offset&1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (bus != 0 || (1<<slot & 0xff8007fe))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ JPRINTK("==>\n");
+
+ *val=in_le16((uint32_t)
+ (pci.pci_config_data + ((1<<slot)&~1)
+ + (function<<8) + offset));
+
+ JPRINTK("\n\n");
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int direct_pci_read_config_dword(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint32_t *val
+) {
+ *val = 0xffffffff;
+ if (offset&3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (bus != 0 || (1<<slot & 0xff8007fe))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ JPRINTK("==>\n");
+
+ *val=in_le32((uint32_t)(pci.pci_config_data +
+ ((1<<slot)&~1)+(function<<8) + offset));
+
+ JPRINTK("\n\n");
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int direct_pci_write_config_byte(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint8_t val
+) {
+ if (bus != 0 || (1<<slot & 0xff8007fe))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ JPRINTK("==>\n");
+
+ out_8((uint32_t) (pci.pci_config_data + ((1<<slot)&~1) +
+ (function<<8) + offset),
+ val);
+
+ JPRINTK("\n\n");
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int direct_pci_write_config_word(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint16_t val
+) {
+ if (offset&1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (bus != 0 || (1<<slot & 0xff8007fe))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ JPRINTK("==>\n");
+
+ out_le16((uint32_t)(pci.pci_config_data + ((1<<slot)&~1) +
+ (function<<8) + offset),
+ val);
+
+ JPRINTK("\n\n");
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int direct_pci_write_config_dword(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint32_t val
+) {
+ if (offset&3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (bus != 0 || (1<<slot & 0xff8007fe))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ JPRINTK("direct_pci_write_config_dword==>\n");
+
+ out_le32((uint32_t)
+ (pci.pci_config_data + ((1<<slot)&~1)
+ + (function<<8) + offset),
+ val);
+
+ JPRINTK("\n\n");
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+/*
+ * Validate a test interrupt name and print a warning if its not one of
+ * the names defined in the routing record.
+ */
+int test_intname(
+ const struct _int_map *row,
+ int pbus,
+ int pslot,
+ int pfun,
+ int int_pin,
+ int int_name
+) {
+ int j, k;
+ int _nopin= -1, _noname= -1;
+
+ for (j=0; row->pin_route[j].pin > -1; j++) {
+ if ( row->pin_route[j].pin == int_pin ) {
+ _nopin = 0;
+
+ for (k=0; k<4 && row->pin_route[j].int_name[k] > -1; k++ ) {
+ if ( row->pin_route[j].int_name[k] == int_name ) {
+ _noname=0; break;
+ }
+ }
+ break;
+ }
+ }
+
+ if( _nopin )
+ {
+ printk(
+ "pci : Device %d:0x%02x:%d supplied a bogus interrupt_pin %d\n",
+ pbus,
+ pslot,
+ pfun,
+ int_pin
+ );
+ return -1;
+ }
+ else
+ {
+ if( _noname ) {
+ unsigned char v = row->pin_route[j].int_name[0];
+ printk(
+ "pci : Device %d:0x%02x:%d supplied a suspicious interrupt_line %d, ",
+ pbus,
+ pslot,
+ pfun,
+ int_name
+ );
+ if ((row->opts & PCI_FIXUP_OPT_OVERRIDE_NAME) && 255 !=
+ (v = row->pin_route[j].int_name[0])
+ ) {
+ printk("OVERRIDING with %d from fixup table\n", v);
+ pci_write_config_byte(pbus,pslot,pfun,PCI_INTERRUPT_LINE,v);
+ } else {
+ printk("using it anyway\n");
+ }
+ }
+ }
+ return 0;
+}
+
+int FindPCIbridge( int mybus, struct pcibridge *pb )
+{
+ int pbus, pslot;
+ uint8_t bussec, buspri;
+ uint16_t devid, vendorid, dclass;
+
+ for(pbus=0; pbus< pci_bus_count(); pbus++) {
+ for(pslot=0; pslot< PCI_MAX_DEVICES; pslot++) {
+ pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &devid);
+ if ( devid == 0xffff ) continue;
+
+ pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &vendorid);
+ if ( vendorid == 0xffff ) continue;
+
+ pci_read_config_word(pbus, pslot, 0, PCI_CLASS_DEVICE, &dclass);
+
+ if ( dclass == PCI_CLASS_BRIDGE_PCI ) {
+ pci_read_config_byte(pbus, pslot, 0, PCI_PRIMARY_BUS, &buspri);
+ pci_read_config_byte(pbus, pslot, 0, PCI_SECONDARY_BUS, &bussec);
+
+ #ifdef SHOW_PCI_SETTING
+ JPRINTK(
+ "pci : Found bridge at %d:0x%02x, mybus %d, pribus %d, secbus %d ",
+ pbus,
+ pslot,
+ mybus,
+ buspri,
+ bussec
+ );
+ #endif
+ if ( bussec == mybus ) {
+ #ifdef SHOW_PCI_SETTING
+ JPRINTK("match\n");
+ #endif
+ /* found our nearest bridge going towards the root */
+ pb->bus = pbus;
+ pb->slot = pslot;
+ return 0;
+ }
+ #ifdef SHOW_PCI_SETTING
+ JPRINTK("no match\n");
+ #endif
+ }
+
+ }
+ }
+ return -1;
+}
+
+void FixupPCI( const struct _int_map *bspmap, int (*swizzler)(int,int) )
+{
+ unsigned char cvalue;
+ uint16_t devid;
+ int ismatch, i, j, pbus, pslot, pfun, int_pin, int_name, nfuns;
+
+ /*
+ * If the device has a non-zero INTERRUPT_PIN, assign a bsp-specific
+ * INTERRUPT_NAME if one isn't already in place. Then, drivers can
+ * trivially use INTERRUPT_NAME to hook up with devices.
+ */
+
+ for (pbus=0; pbus< pci_bus_count(); pbus++) {
+ for (pslot=0; pslot< PCI_MAX_DEVICES; pslot++) {
+ pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &devid);
+ if ( devid == 0xffff ) continue;
+
+ /* got a device */
+ pci_read_config_byte(pbus, pslot, 0, PCI_HEADER_TYPE, &cvalue);
+ nfuns = cvalue & PCI_HEADER_TYPE_MULTI_FUNCTION ? PCI_MAX_FUNCTIONS : 1;
+ for (pfun=0; pfun< nfuns; pfun++) {
+
+ pci_read_config_word(pbus, pslot, pfun, PCI_DEVICE_ID, &devid);
+ if( devid == 0xffff ) continue;
+
+ pci_read_config_byte( pbus, pslot, pfun, PCI_INTERRUPT_PIN, &cvalue);
+ int_pin = cvalue;
+
+ pci_read_config_byte( pbus, pslot, pfun, PCI_INTERRUPT_LINE, &cvalue);
+ int_name = cvalue;
+
+ #ifdef SHOW_PCI_SETTING
+ {
+ unsigned short cmd,stat;
+ unsigned char lat, seclat, csize;
+
+ pci_read_config_word(pbus,pslot,pfun,PCI_COMMAND, &cmd );
+ pci_read_config_word(pbus,pslot,pfun,PCI_STATUS, &stat );
+ pci_read_config_byte(pbus,pslot,pfun,PCI_LATENCY_TIMER, &lat );
+ pci_read_config_byte(pbus,pslot,pfun,PCI_SEC_LATENCY_TIMER, &seclat);
+ pci_read_config_byte(pbus,pslot,pfun,PCI_CACHE_LINE_SIZE, &csize );
+
+ JPRINTK(
+ "pci : device %d:0x%02x:%d cmd %04X, stat %04X, latency %d, "
+ " sec_latency %d, clsize %d\n",
+ pbus,
+ pslot,
+ pfun,
+ cmd,
+ stat,
+ lat,
+ seclat,
+ csize
+ );
+ }
+ #endif
+
+ if ( int_pin > 0 ) {
+ ismatch = 0;
+
+ /*
+ * first run thru the bspmap table and see if we have an
+ * explicit configuration
+ */
+ for (i=0; bspmap[i].bus > -1; i++) {
+ if ( bspmap[i].bus == pbus && bspmap[i].slot == pslot ) {
+ ismatch = -1;
+
+ /* we have a record in the table that gives specific
+ * pins and interrupts for devices in this slot
+ */
+ if ( int_name == 255 ) {
+
+ /* find the vector associated with whatever pin the
+ * device gives us
+ */
+ for ( int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++ ){
+ if ( bspmap[i].pin_route[j].pin == int_pin ) {
+ int_name = bspmap[i].pin_route[j].int_name[0];
+ break;
+ }
+ }
+
+ if ( int_name == -1 ) {
+ printk(
+ "pci : Unable to resolve device %d:0x%02x:%d w/ "
+ "swizzled int pin %i to an interrupt_line.\n",
+ pbus,
+ pslot,
+ pfun,
+ int_pin
+ );
+ } else {
+ PRINT_MSG();
+ pci_write_config_byte(
+ pbus,
+ pslot,
+ pfun,
+ PCI_INTERRUPT_LINE,(cvalue= int_name, cvalue)
+ );
+ }
+ } else {
+ test_intname( &bspmap[i],pbus,pslot,pfun,int_pin,int_name);
+ }
+ break;
+ }
+ }
+
+ if ( !ismatch ) {
+ /*
+ * no match, which means we're on a bus someplace. Work
+ * backwards from it to one of our defined busses,
+ * swizzling thru each bridge on the way.
+ */
+
+ /* keep pbus, pslot pointed to the device being
+ * configured while we track down the bridges using
+ * tbus,tslot. We keep searching the routing table because
+ * we may end up finding our bridge in it
+ */
+
+ int tbus= pbus, tslot= pslot;
+ for (;;) {
+ for (i=0; bspmap[i].bus > -1; i++) {
+ if ( bspmap[i].bus == tbus &&
+ (bspmap[i].slot == tslot || bspmap[i].slot == -1))
+ {
+ ismatch = -1;
+
+ /* found a record for this bus, so swizzle the
+ * int_pin which we then use to find the
+ * interrupt_name.
+ */
+ if ( int_name == 255 ) {
+ /*
+ * FIXME. I can't believe this little hack
+ * is right. It does not yield an error in
+ * convienently simple situations.
+ */
+ if ( tbus ) int_pin = (*swizzler)(tslot,int_pin);
+
+ /*
+ * int_pin points to the interrupt channel
+ * this card ends up delivering interrupts
+ * on. Find the int_name servicing it.
+ */
+ for (int_name=-1, j=0;
+ bspmap[i].pin_route[j].pin > -1;
+ j++)
+ {
+ if ( bspmap[i].pin_route[j].pin == int_pin ) {
+ int_name = bspmap[i].pin_route[j].int_name[0];
+ break;
+ }
+ }
+
+ if ( int_name == -1 ) {
+ printk(
+ "pci : Unable to resolve device %d:0x%02x:%d w/ "
+ "swizzled int pin %i to an interrupt_line.\n",
+ pbus,
+ pslot,
+ pfun,
+ int_pin
+ );
+ } else {
+ PRINT_MSG();
+ pci_write_config_byte(pbus,pslot,pfun,
+ PCI_INTERRUPT_LINE,(cvalue=int_name, cvalue));
+ }
+ } else {
+ test_intname(
+ &bspmap[i],
+ pbus,
+ pslot,
+ pfun,
+ int_pin,
+ int_name
+ );
+ }
+ goto donesearch;
+ }
+ }
+ if ( !ismatch ) {
+ struct pcibridge pb;
+
+ /*
+ * Haven't found our bus in the int map, so work
+ * upwards thru the bridges till we find it.
+ */
+ if ( FindPCIbridge( tbus, &pb )== 0 ) {
+ int_pin = (*swizzler)(tslot,int_pin);
+
+ /* our next bridge up is on pb.bus, pb.slot- now
+ * instead of pointing to the device we're
+ * trying to configure, we move from bridge to
+ * bridge.
+ */
+ tbus = pb.bus;
+ tslot = pb.slot;
+ } else {
+ printk(
+ "pci : No bridge from bus %i towards root found\n",
+ tbus
+ );
+ goto donesearch;
+ }
+ }
+ }
+ }
+
+ donesearch:
+ if ( !ismatch && int_pin != 0 && int_name == 255 ) {
+ printk(
+ "pci : Unable to match device %d:0x%02x:%d with an int "
+ "routing table entry\n",
+ pbus,
+ pslot,
+ pfun
+ );
+ }
+ }
+ }
+ }
+ }
+}
+
+void print_bars(
+ unsigned char slot,
+ unsigned char func
+)
+{
+ uint32_t addr;
+
+ printk( "*** BARs for slot=%d func=%d\n", slot, func );
+ pci_read_config_dword (0, slot, func, PCI_BASE_ADDRESS_0, &addr);
+ printk("*** PCI DEVICE BAR0: 0x%lx\n", addr);
+ pci_read_config_dword (0, slot, func, PCI_BASE_ADDRESS_1, &addr);
+ printk("*** PCI DEVICE BAR1: 0x%lx\n", addr);
+ pci_read_config_dword (0, slot, func, PCI_BASE_ADDRESS_2, &addr);
+ printk("*** PCI DEVICE BAR2: 0x%lx\n", addr);
+ pci_read_config_dword (0, slot, func, PCI_BASE_ADDRESS_3, &addr);
+ printk("*** PCI DEVICE BAR3: 0x%lx\n", addr);
+ pci_read_config_dword (0, slot, func, PCI_BASE_ADDRESS_4, &addr);
+ printk("*** PCI DEVICE BAR4: 0x%lx\n", addr);
+ pci_read_config_dword (0, slot, func, PCI_BASE_ADDRESS_5, &addr);
+ printk("*** PCI DEVICE BAR5: 0x%lx\n", addr);
+}
+
+void pci_memory_enable(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function
+)
+{
+ uint16_t data;
+
+ pci_read_config_word(0, slot, function, PCI_COMMAND, &data);
+ data |= PCI_COMMAND_MEMORY;
+ pci_write_config_word(0, slot, function, PCI_COMMAND, data );
+ pci_read_config_word(0, slot, function, PCI_COMMAND, &data);
+}
+
+void pci_io_enable(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function
+)
+{
+ uint16_t data;
+
+ pci_read_config_word(0, slot, function, PCI_COMMAND, &data);
+ data |= PCI_COMMAND_IO;
+ pci_write_config_word(0, slot, function, PCI_COMMAND, data );
+}
+
+void pci_busmaster_enable(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function
+)
+{
+ uint16_t data;
+
+ pci_read_config_word(0, slot, function, PCI_COMMAND, &data);
+ data |= PCI_COMMAND_MASTER;
+ pci_write_config_word(0, slot, function, PCI_COMMAND, data );
+}
+
+/*
+ * This routine determines the maximum bus number in the system
+ */
+int pci_initialize(void)
+{
+ unsigned char slot, func, ucNumFuncs;
+ unsigned char ucHeader;
+ uint32_t class;
+ uint32_t device;
+ uint32_t vendor;
+
+ /*
+ * Initialize GT_PCI0IOREMAP
+ */
+ pci_out_32( BSP_PCI_BASE_ADDRESS, 0xf0, 0 );
+
+ /*
+ * According to Linux and BSD sources, this is needed to cover up a bug
+ * in some versions of the hardware.
+ */
+ out_le32( PCI_CONFIG_ADDR, 0x80000020 );
+ out_le32( PCI_CONFIG_DATA, 0x1be00000 );
+
+ /*
+ * Scan PCI bus 0 looking for the known Network devices and
+ * initializing the PCI for them.
+ */
+ for (slot=0;slot<PCI_MAX_DEVICES;slot++) {
+ pci_read_config_dword(0, slot, 0, PCI_VENDOR_ID, &device);
+ if (device == PCI_INVALID_VENDORDEVICEID) {
+ /* This slot is empty */
+ continue;
+ }
+
+ pci_read_config_byte(0, slot, 0, PCI_HEADER_TYPE, &ucHeader);
+ if (ucHeader & PCI_HEADER_TYPE_MULTI_FUNCTION) {
+ ucNumFuncs = PCI_MAX_FUNCTIONS;
+ } else {
+ ucNumFuncs=1;
+ }
+ for (func=0;func<ucNumFuncs;func++) {
+ pci_read_config_dword(0, slot, func, PCI_VENDOR_ID, &device);
+ if (device==PCI_INVALID_VENDORDEVICEID) {
+ /* This slot/function is empty */
+ continue;
+ }
+ vendor = device & 0xffff;
+ device = device >> 16;
+
+ /* This slot/function has a device fitted. */
+ pci_read_config_dword(0, slot, func, PCI_CLASS_REVISION, &class);
+ class >>= 16;
+
+ // printk( "FOUND DEVICE 0x%04x/0x%04x class 0x%x\n",
+ // vendor, device, class );
+ if (class == PCI_CLASS_NETWORK_ETHERNET) {
+ JPRINTK("FOUND ETHERNET\n");
+
+ pci_write_config_byte(
+ 0, slot, func, PCI_INTERRUPT_LINE, MALTA_IRQ_ETHERNET );
+
+ /*
+ * Rewrite BAR1 for RTL8139
+ */
+ if ( vendor == PCI_VENDOR_ID_REALTEK &&
+ device == PCI_DEVICE_ID_REALTEK_8139 ) {
+
+ pci_memory_enable(0, slot, func);
+ pci_io_enable(0, slot, func);
+ pci_busmaster_enable(0, slot, func);
+
+ // BAR0: IO at 0x0000_1001
+ pci_write_config_dword(0, slot, func, PCI_BASE_ADDRESS_0, 0x00001001);
+
+ // BAR1: Memory at 0x1203_1000
+ pci_write_config_dword(0, slot, func, PCI_BASE_ADDRESS_1, 0x12031000);
+
+ // print_bars( slot, func );
+ } else if ( vendor == PCI_VENDOR_ID_AMD &&
+ device == PCI_DEVICE_ID_AMD_LANCE ) {
+ print_bars( slot, func );
+ pci_memory_enable(0, slot, func);
+ pci_io_enable(0, slot, func);
+ pci_busmaster_enable(0, slot, func);
+
+ // BAR0: IO at 0x0000_1041
+ pci_write_config_dword(0, slot, func, PCI_BASE_ADDRESS_0, 0x00001041);
+
+ // BAR1: Memory at 0x1201_1020
+ pci_write_config_dword(0, slot, func, PCI_BASE_ADDRESS_1, 0x12011020);
+ print_bars( slot, func );
+ }
+
+ }
+ }
+ }
+ return PCIB_ERR_SUCCESS;
+}
+
+/*
+ * Return the number of PCI busses in the system
+ */
+unsigned char pci_bus_count(void)
+{
+ return (ucMaxPCIBus+1);
+}
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
+
diff --git a/bsps/powerpc/mvme3100/pci/detect_host_bridge.c b/bsps/powerpc/mvme3100/pci/detect_host_bridge.c
new file mode 100644
index 0000000000..8488c99dc5
--- /dev/null
+++ b/bsps/powerpc/mvme3100/pci/detect_host_bridge.c
@@ -0,0 +1,113 @@
+/* PCI Initialization */
+
+/*
+ * Authorship
+ * ----------
+ * This software ('mvme3100' RTEMS BSP) was created by
+ *
+ * Till Straumann <strauman@slac.stanford.edu>, 2005-2007,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * The 'mvme3100' 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 <bsp.h>
+#include <bsp/pci.h>
+#include <bsp/irq.h>
+#include <bsp/openpic.h>
+#include <inttypes.h>
+
+/* Motload configures PCI interrupts to start at 16 and up but
+ * we'd rather have them starting at 0.
+ * Use this callback to fix them up.
+ */
+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_EXT_IRQ_NUMBER ) {
+ pci_write_config_byte( bus, slot, fun, PCI_INTERRUPT_LINE, line - BSP_EXT_IRQ_NUMBER );
+ }
+
+ return 0;
+}
+
+void BSP_motload_pci_fixup(void)
+{
+ BSP_pciScan(0, fixup_irq_line, 0);
+}
+
+void detect_host_bridge(void)
+{
+ OpenPIC = (volatile struct OpenPIC *) (BSP_8540_CCSR_BASE + BSP_OPEN_PIC_BASE_OFFSET);
+}
+
+static int
+dump_dev_cb(
+ int bus,
+ int dev,
+ int fun,
+ void *uarg
+)
+{
+ uint16_t vi,di;
+ uint16_t cd,st;
+ uint32_t b1,b2;
+ uint8_t il,ip;
+
+ pci_read_config_word (bus, dev, fun, PCI_VENDOR_ID, &vi);
+ pci_read_config_word (bus, dev, fun, PCI_DEVICE_ID, &di);
+ pci_read_config_word (bus, dev, fun, PCI_COMMAND, &cd);
+ pci_read_config_word (bus, dev, fun, PCI_STATUS, &st);
+ pci_read_config_dword(bus, dev, fun, PCI_BASE_ADDRESS_0, &b1);
+ pci_read_config_dword(bus, dev, fun, PCI_BASE_ADDRESS_1, &b2);
+ pci_read_config_byte (bus, dev, fun, PCI_INTERRUPT_LINE, &il);
+ pci_read_config_byte (bus, dev, fun, PCI_INTERRUPT_PIN, &ip);
+
+ printk("%3d:0x%02x:%d 0x%04x-0x%04x: 0x%04x 0x%04x 0x%08" PRIx32 " 0x%08" PRIx32 " %d -> %3d (=0x%02x)\n",
+ bus, dev, fun, vi, di, cd, st, b1, b2, ip, il, il);
+ return 0;
+}
+
+void
+BSP_pciConfigDump_early(void)
+{
+ printk("BUS:SLOT:FUN VENDOR-DEV_ID: COMMAND STATUS BASE_ADDR0 BASE_ADDR1 IRQ_PIN -> IRQ_LINE\n");
+ BSP_pciScan(0, dump_dev_cb, 0);
+}
diff --git a/bsps/powerpc/mvme5500/pci/detect_host_bridge.c b/bsps/powerpc/mvme5500/pci/detect_host_bridge.c
new file mode 100644
index 0000000000..3bd5b00d7a
--- /dev/null
+++ b/bsps/powerpc/mvme5500/pci/detect_host_bridge.c
@@ -0,0 +1,72 @@
+/*
+ * detect_host_bridge.c
+ *
+ * This code is inspired by detect_grackle_bridge.c of SVGM BSP
+ * written by Till Straumann
+ * Copyright (C) 2001, 2003 Till Straumann <strauman@slac.stanford.edu>
+ *
+ * Copyright (C) 2004 S. Kate Feng, <feng1@bnl.gov>
+ * wrote it to support the MVME5500 board.
+ *
+ */
+#include <libcpu/io.h>
+#include <rtems/bspIo.h> /* printk */
+
+#include <bsp/pci.h>
+#include <bsp/gtreg.h>
+#include <bsp/gtpcireg.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#define PCI_DEBUG 0
+
+#define HOSTBRIDGET_ERROR 0xf0000000
+
+unsigned long _BSP_clear_hostbridge_errors(int enableMCP, int quiet)
+{
+ uint32_t pcidata, pcidata1;
+ int PciLocal, busNumber=0;
+
+ /* On the mvme5500 board, the GT64260B system controller had the MCP
+ * signal pulled up high. Thus, the MCP signal is not used as it is
+ * on other boards such as mvme2307.
+ */
+ if (enableMCP) return(-1);
+ for (PciLocal=0; PciLocal<1; PciLocal++ ) {
+ pci_read_config_dword(busNumber,
+ 0,
+ 0,
+ PCI_COMMAND,
+ &pcidata);
+
+ if (!quiet)
+ printk("Before _BSP_clear_hostbridge_errors(): 0x%" PRIx32 ", cause 0x%lx\n",
+ pcidata, inl(0x1d58));
+
+ outl(0,0x1d58);
+
+ /* Clear the error on the host bridge */
+ pcidata1= pcidata;
+ pcidata1 |= PCI_STATUS_CLRERR_MASK;
+ pcidata1 |= 0x140;
+ pci_write_config_dword(busNumber,
+ 0,
+ 0,
+ PCI_COMMAND,
+ pcidata1);
+
+ pci_read_config_dword(busNumber,
+ 0,
+ 0,
+ PCI_COMMAND,
+ &pcidata1);
+
+ if (!quiet) printk("After _BSP_clear_hostbridge_errors(): sts 0x%" PRIx32 "\n",
+ pcidata1);
+ if (pcidata1 & HOSTBRIDGET_ERROR) printk("BSP_clear_hostbridge_errors(): unable to clear pending hostbridge errors\n");
+ busNumber += BSP_MAX_PCI_BUS_ON_PCI0;
+ }
+ return(pcidata & HOSTBRIDGET_ERROR);
+}
diff --git a/bsps/powerpc/mvme5500/pci/pci.c b/bsps/powerpc/mvme5500/pci/pci.c
new file mode 100644
index 0000000000..8ef5876047
--- /dev/null
+++ b/bsps/powerpc/mvme5500/pci/pci.c
@@ -0,0 +1,420 @@
+/*
+ * 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);
+}
+
diff --git a/bsps/powerpc/mvme5500/pci/pci_interface.c b/bsps/powerpc/mvme5500/pci/pci_interface.c
new file mode 100644
index 0000000000..9f7be59151
--- /dev/null
+++ b/bsps/powerpc/mvme5500/pci/pci_interface.c
@@ -0,0 +1,100 @@
+/* pci_interface.c
+ *
+ * Copyright 2004, 2006, 2007 All rights reserved. (NDA items)
+ * Brookhaven National Laboratory and Shuchen Kate Feng <feng1@bnl.gov>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution.
+ *
+ * 8/17/2006 : S. Kate Feng
+ * uses in_le32()/out_le32(), instead of inl()/outl() for compatibility.
+ *
+ * 11/2008 : Enable "PCI Read Agressive Prefetch",
+ * "PCI Read Line Agressive Prefetch", and
+ * "PCI Read Multiple Agressive Prefetch" to improve the
+ * performance of the PCI based applications (e.g. 1GHz NIC).
+ */
+
+#include <libcpu/io.h>
+#include <rtems/bspIo.h> /* printk */
+
+#include <bsp.h>
+#include <bsp/pci.h>
+#include <bsp/gtreg.h>
+#include <bsp/gtpcireg.h>
+
+#include <inttypes.h>
+
+#define PCI_DEBUG 0
+
+#if 0
+#define CPU2PCI_ORDER
+#define PCI2CPU_ORDER
+#endif
+
+/* PCI Read Agressive Prefetch Enable (1<<16 ),
+ * PCI Read Line Agressive Prefetch Enable( 1<<17),
+ * PCI Read Multiple Agressive Prefetch Enable (1<<18).
+ */
+#ifdef PCI2CPU_ORDER
+#define PCI_ACCCTLBASEL_VALUE 0x01079000
+#else
+#define PCI_ACCCTLBASEL_VALUE 0x01071000
+#endif
+
+
+#define ConfSBDis 0x10000000 /* 1: disable, 0: enable */
+#define IOSBDis 0x20000000 /* 1: disable, 0: enable */
+#define ConfIOSBDis 0x30000000
+#define CpuPipeline 0x00002000 /* optional, 1:enable, 0:disable */
+
+/* CPU to PCI ordering register */
+#define DLOCK_ORDER_REG 0x2D0 /* Deadlock and Ordering register */
+#define PCI0OrEn 0x00000001
+#define PCI1OrEn 0x00000020
+#define PCIOrEn 0x40000000
+#define PCIOrEnMASK 0x40000021
+
+#define CNT_SYNC_REG 0x2E0 /* Counters and Sync Barrier register */
+#define L0SyncBar 0x00001000
+#define L1SyncBar 0x00002000
+#define DSyncBar 0x00004000
+#define SyncBarMode 0x00008000
+#define SyncBarMASK 0x0000f000
+
+#define WRTBK_PRIO_BUFFER 0x2d8 /* writback priority and buffer depth */
+
+#define ADDR_PIPELINE 0x00020000
+
+void pciAccessInit(void);
+
+void pci_interface(void)
+{
+
+#ifdef CPU2PCI_ORDER
+ /* MOTLOad deafult : 0x07ff8600 */
+ out_le32((volatile uint32_t *)(GT64x60_REG_BASE+CNT_SYNC_REG), 0x07fff600);
+#endif
+ /* asserts SERR upon various detection */
+ out_le32((volatile uint32_t *)(GT64x60_REG_BASE+0xc28), 0x3fffff);
+ pciAccessInit();
+}
+
+void pciAccessInit(void)
+{
+ unsigned int PciLocal, data;
+
+ for (PciLocal=0; PciLocal < 2; PciLocal++) {
+ data = in_le32((volatile uint32_t *)(GT64x60_REG_BASE+PCI0_ACCESS_CNTL_BASE0_LOW+(PciLocal * 0x80)));
+#if 0
+ printk("PCI%d_ACCESS_CNTL_BASE0_LOW was 0x%x\n",PciLocal,data);
+#endif
+ data |= PCI_ACCCTLBASEL_VALUE;
+ data &= ~0x300000;
+ out_le32((volatile uint32_t *)(GT64x60_REG_BASE+PCI0_ACCESS_CNTL_BASE0_LOW+(PciLocal * 0x80)), data);
+#if 0
+ printf("PCI%d_ACCESS_CNTL_BASE0_LOW now 0x%" PRIx32 "\n",PciLocal,in_le32((volatile uint32_t *)(GT64x60_REG_BASE+PCI0_ACCESS_CNTL_BASE0_LOW+(PciLocal * 0x80))));
+#endif
+ }
+}
+
diff --git a/bsps/powerpc/shared/pci/detect_raven_bridge.c b/bsps/powerpc/shared/pci/detect_raven_bridge.c
new file mode 100644
index 0000000000..0a1c04a2e2
--- /dev/null
+++ b/bsps/powerpc/shared/pci/detect_raven_bridge.c
@@ -0,0 +1,197 @@
+#include <libcpu/io.h>
+#include <libcpu/spr.h>
+#include <inttypes.h>
+
+#include <bsp.h>
+#include <bsp/pci.h>
+#include <bsp/consoleIo.h>
+#include <bsp/residual.h>
+#include <bsp/openpic.h>
+#include <bsp/irq.h>
+
+#include <rtems/bspIo.h>
+#include <libcpu/cpuIdent.h>
+
+#define SHOW_RAVEN_SETTINGS
+
+#define RAVEN_MPIC_IOSPACE_ENABLE 0x0001
+#define RAVEN_MPIC_MEMSPACE_ENABLE 0x0002
+#define RAVEN_MASTER_ENABLE 0x0004
+#define RAVEN_PARITY_CHECK_ENABLE 0x0040
+#define RAVEN_SYSTEM_ERROR_ENABLE 0x0100
+#define RAVEN_CLEAR_EVENTS_MASK 0xf9000000
+
+#define RAVEN_MPIC_MEREN ((volatile unsigned *)0xfeff0020)
+#define RAVEN_MPIC_MERST ((volatile unsigned *)0xfeff0024)
+#define MEREN_VAL 0x2f00
+
+#define pci BSP_pci_configuration
+
+extern const pci_config_access_functions pci_direct_functions;
+extern const pci_config_access_functions pci_indirect_functions;
+
+#if defined(mvme2100)
+/* FIXME - this should really be in a separate file - the 2100 doesn't
+ * have a raven chip so there is no point having 2100 code here
+ */
+
+extern unsigned int EUMBBAR;
+
+void detect_host_bridge(void)
+{
+ /*
+ * If the processor is an 8240 or an 8245 then the PIC is built
+ * in instead of being on the PCI bus. The MVME2100 is using Processor
+ * Address Map B (CHRP) although the Programmer's Reference Guide says
+ * it defaults to Map A.
+ */
+ /* We have an EPIC Interrupt Controller */
+ OpenPIC = (volatile struct OpenPIC *) (EUMBBAR + BSP_OPEN_PIC_BASE_OFFSET);
+ pci.pci_functions = &pci_indirect_functions;
+ pci.pci_config_addr = (volatile unsigned char *) 0xfec00000;
+ pci.pci_config_data = (volatile unsigned char *) 0xfee00000;
+}
+
+#else
+
+#if 0
+/* Unfortunately, PCI config space access to empty slots generates
+ * a 'signalled master abort' condition --> we can't really use
+ * the machine check interrupt for memory probing unless
+ * we use probing for PCI scanning also (which would make
+ * all that code either BSP dependent or requiring yet another
+ * API, sigh...).
+ * So for the moment, we just don't use MCP on all mvme2xxx
+ * boards (using the generic, hostbridge-independent 'clear'
+ * implementation [generic_clear_hberrs.c]).
+ */
+/*
+ * enableMCP: whether to enable MCP checkstop / machine check interrupts
+ * on the hostbridge and in HID0.
+ *
+ * NOTE: HID0 and MEREN are left alone if this flag is 0
+ *
+ * quiet : be silent
+ *
+ * RETURNS : raven MERST register contents (lowermost 16 bits), 0 if
+ * there were no errors
+ */
+unsigned long
+_BSP_clear_hostbridge_errors(int enableMCP, int quiet)
+{
+unsigned merst;
+
+ merst = in_be32(RAVEN_MPIC_MERST);
+ /* write back value to clear status */
+ out_be32(RAVEN_MPIC_MERST, merst);
+
+ if (enableMCP) {
+ if (!quiet)
+ printk("Enabling MCP generation on hostbridge errors\n");
+ out_be32(RAVEN_MPIC_MEREN, MEREN_VAL);
+ } else {
+ out_be32(RAVEN_MPIC_MEREN, 0);
+ if ( !quiet && enableMCP ) {
+ printk("leaving MCP interrupt disabled\n");
+ }
+ }
+ return (merst & 0xffff);
+}
+#endif
+
+void detect_host_bridge(void)
+{
+ PPC_DEVICE *hostbridge;
+ uint32_t id0;
+ uint32_t tmp;
+
+ /*
+ * This code assumes that the host bridge is located at
+ * bus 0, dev 0, func 0 AND that the old pre PCI 2.1
+ * standard devices detection mechanism that was used on PC
+ * (still used in BSD source code) works.
+ */
+ hostbridge=residual_find_device(&residualCopy, PROCESSORDEVICE, NULL,
+ BridgeController,
+ PCIBridge, -1, 0);
+ if (hostbridge) {
+ if (hostbridge->DeviceId.Interface==PCIBridgeIndirect) {
+ pci.pci_functions=&pci_indirect_functions;
+ /* Should be extracted from residual data,
+ * indeed MPC106 in CHRP mode is different,
+ * but we should not use residual data in
+ * this case anyway.
+ */
+ pci.pci_config_addr = ((volatile unsigned char *)
+ (ptr_mem_map->io_base+0xcf8));
+ pci.pci_config_data = ptr_mem_map->io_base+0xcfc;
+ } else if(hostbridge->DeviceId.Interface==PCIBridgeDirect) {
+ pci.pci_functions=&pci_direct_functions;
+ pci.pci_config_data=(unsigned char *) 0x80800000;
+ } else {
+ }
+ } else {
+ /* Let us try by experimentation at our own risk! */
+ pci.pci_functions = &pci_direct_functions;
+ /* On all direct bridges I know the host bridge itself
+ * appears as device 0 function 0.
+ */
+ pci_read_config_dword(0, 0, 0, PCI_VENDOR_ID, &id0);
+ if (id0==~0U) {
+ pci.pci_functions = &pci_indirect_functions;
+ pci.pci_config_addr = ((volatile unsigned char*)
+ (ptr_mem_map->io_base+0xcf8));
+ pci.pci_config_data = ((volatile unsigned char*)ptr_mem_map->io_base+0xcfc);
+ }
+ /* Here we should check that the host bridge is actually
+ * present, but if it not, we are in such a desperate
+ * situation, that we probably can't even tell it.
+ */
+ }
+ pci_read_config_dword(0, 0, 0, 0, &id0);
+#ifdef SHOW_RAVEN_SETTINGS
+ printk("idreg 0 = 0x%" PRIu32 "\n",id0);
+#endif
+ if((id0 == PCI_VENDOR_ID_MOTOROLA +
+ (PCI_DEVICE_ID_MOTOROLA_RAVEN<<16)) ||
+ (id0 == PCI_VENDOR_ID_MOTOROLA +
+ (PCI_DEVICE_ID_MOTOROLA_HAWK<<16))) {
+ /*
+ * We have a Raven bridge. We will get information about its settings
+ */
+ pci_read_config_dword(0, 0, 0, PCI_COMMAND, &id0);
+#ifdef SHOW_RAVEN_SETTING
+ printk("RAVEN PCI command register = %x\n",id0);
+#endif
+ id0 |= RAVEN_CLEAR_EVENTS_MASK;
+ pci_write_config_dword(0, 0, 0, PCI_COMMAND, id0);
+ pci_read_config_dword(0, 0, 0, PCI_COMMAND, &id0);
+#ifdef SHOW_RAVEN_SETTING
+ printk("After error clearing RAVEN PCI command register = %x\n",id0);
+#endif
+
+ if (id0 & RAVEN_MPIC_IOSPACE_ENABLE) {
+ pci_read_config_dword(0, 0, 0,PCI_BASE_ADDRESS_0, &tmp);
+#ifdef SHOW_RAVEN_SETTING
+ printk("Raven MPIC is accessed via IO Space Access at address : %x\n",(tmp & ~0x1));
+#endif
+ }
+ if (id0 & RAVEN_MPIC_MEMSPACE_ENABLE) {
+ pci_read_config_dword(0, 0, 0,PCI_BASE_ADDRESS_1, &tmp);
+#ifdef SHOW_RAVEN_SETTING
+ printk("Raven MPIC is accessed via memory Space Access at address : %x\n", tmp);
+#endif
+ OpenPIC=(volatile struct OpenPIC *) (tmp + PREP_ISA_MEM_BASE);
+ printk("OpenPIC found at %p.\n", OpenPIC);
+ }
+ }
+
+#if BSP_PCI_IRQ_NUMBER > 0
+ if (OpenPIC == (volatile struct OpenPIC *)0) {
+ rtems_panic("OpenPic Not found\n");
+ }
+#endif
+
+}
+
+#endif
diff --git a/bsps/powerpc/shared/pci/generic_clear_hberrs.c b/bsps/powerpc/shared/pci/generic_clear_hberrs.c
new file mode 100644
index 0000000000..1bc4009b15
--- /dev/null
+++ b/bsps/powerpc/shared/pci/generic_clear_hberrs.c
@@ -0,0 +1,63 @@
+#include <libcpu/io.h>
+#include <libcpu/spr.h>
+
+#include <bsp.h>
+#include <bsp/pci.h>
+
+#include <rtems/bspIo.h>
+
+#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) or the error bits or 0 if there were no errors.
+ *
+ */
+
+unsigned short
+(*_BSP_clear_vmebridge_errors)(int) = 0;
+
+unsigned long
+_BSP_clear_hostbridge_errors(int enableMCP, int quiet)
+{
+unsigned long rval;
+unsigned short pcistat;
+int count;
+
+ if (enableMCP)
+ return -1; /* exceptions not supported / MCP not wired */
+
+ /* read error status for info return */
+ pci_read_config_word(0,0,0,PCI_STATUS,&pcistat);
+ rval = pcistat;
+
+ count=10;
+ do {
+ /* clear error reporting registers */
+
+ /* clear PCI status register */
+ pci_write_config_word(0,0,0,PCI_STATUS, PCI_ERR_BITS);
+
+ /* read new status */
+ pci_read_config_word(0,0,0,PCI_STATUS, &pcistat);
+
+ } while ( ! PCI_STATUS_OK(pcistat) && count-- );
+
+ if ( !PCI_STATUS_OK(rval) && !quiet) {
+ printk("Cleared PCI errors: pci_stat was 0x%04lx\n", rval);
+ }
+ if ( !PCI_STATUS_OK(pcistat) ) {
+ printk("Unable to clear PCI errors: still 0x%04x after 10 attempts\n", pcistat);
+ }
+
+ rval &= PCI_ERR_BITS;
+
+ /* Some VME bridges (Tsi148) don'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/shared/pci/pci.c b/bsps/powerpc/shared/pci/pci.c
new file mode 100644
index 0000000000..f75151ad46
--- /dev/null
+++ b/bsps/powerpc/shared/pci/pci.c
@@ -0,0 +1,640 @@
+/*
+ * pci.c : this file contains basic PCI Io functions.
+ *
+ * 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>
+
+#undef SHOW_PCI_SETTING
+
+/* 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
+
+/* define a shortcut */
+#define pci BSP_pci_configuration
+
+#ifndef PCI_CONFIG_ADDR_VAL
+#define PCI_CONFIG_ADDR_VAL(bus, slot, funcion, offset) \
+ (0x80<<24|((bus)<<16)|(PCI_DEVFN((slot),(function))<<8)|(((offset)&~3)))
+#endif
+
+#ifndef PCI_CONFIG_WR_ADDR
+#define PCI_CONFIG_WR_ADDR( addr, val ) out_le32((volatile uint32_t*)(addr), (val))
+#endif
+
+#define PCI_CONFIG_SET_ADDR(addr, bus, slot,function,offset) \
+ PCI_CONFIG_WR_ADDR((addr), PCI_CONFIG_ADDR_VAL((bus), (slot), (function), (offset)))
+
+
+extern void detect_host_bridge(void);
+
+/*
+ * Bit encode for PCI_CONFIG_HEADER_TYPE register
+ */
+unsigned char ucMaxPCIBus;
+
+static int
+indirect_pci_read_config_byte(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint8_t *val
+) {
+ PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset);
+ *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
+) {
+ *val = 0xffff;
+ if (offset&1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset);
+ *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
+) {
+ *val = 0xffffffff;
+ if (offset&3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset);
+ *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
+) {
+ PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset);
+ 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
+) {
+ if (offset&1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset);
+ 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
+) {
+ if (offset&3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ PCI_CONFIG_SET_ADDR(pci.pci_config_addr, bus, slot, function, offset);
+ out_le32((volatile uint32_t *)pci.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*)PCI_CONFIG_ADDR,
+ (volatile unsigned char*)PCI_CONFIG_DATA,
+ &pci_indirect_functions
+};
+
+static int
+direct_pci_read_config_byte(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint8_t *val
+) {
+ if (bus != 0 || (1<<slot & 0xff8007fe)) {
+ *val=0xff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ *val=in_8(pci.pci_config_data + ((1<<slot)&~1)
+ + (function<<8) + offset);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+direct_pci_read_config_word(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint16_t *val
+) {
+ *val = 0xffff;
+ if (offset&1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (bus != 0 || (1<<slot & 0xff8007fe))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ *val=in_le16((volatile uint16_t *)
+ (pci.pci_config_data + ((1<<slot)&~1)
+ + (function<<8) + offset));
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+direct_pci_read_config_dword(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint32_t *val
+) {
+ *val = 0xffffffff;
+ if (offset&3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (bus != 0 || (1<<slot & 0xff8007fe))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ *val=in_le32((volatile uint32_t *)
+ (pci.pci_config_data + ((1<<slot)&~1)
+ + (function<<8) + offset));
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+direct_pci_write_config_byte(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint8_t val
+) {
+ if (bus != 0 || (1<<slot & 0xff8007fe))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ out_8(pci.pci_config_data + ((1<<slot)&~1)
+ + (function<<8) + offset,
+ val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+direct_pci_write_config_word(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint16_t val
+) {
+ if (offset&1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (bus != 0 || (1<<slot & 0xff8007fe))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ out_le16((volatile uint16_t *)
+ (pci.pci_config_data + ((1<<slot)&~1)
+ + (function<<8) + offset),
+ val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+direct_pci_write_config_dword(
+ unsigned char bus,
+ unsigned char slot,
+ unsigned char function,
+ unsigned char offset,
+ uint32_t val
+) {
+ if (offset&3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (bus != 0 || (1<<slot & 0xff8007fe))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ out_le32((volatile uint32_t *)
+ (pci.pci_config_data + ((1<<slot)&~1)
+ + (function<<8) + offset),
+ val);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+const pci_config_access_functions pci_direct_functions = {
+ direct_pci_read_config_byte,
+ direct_pci_read_config_word,
+ direct_pci_read_config_dword,
+ direct_pci_write_config_byte,
+ direct_pci_write_config_word,
+ direct_pci_write_config_dword
+};
+
+#define PRINT_MSG() \
+ printk("pci : Device %d:0x%02x:%d routed to interrupt_line %d\n", \
+ pbus, pslot, pfun, int_name )
+
+/*
+** Validate a test interrupt name and print a warning if its not one of
+** the names defined in the routing record.
+*/
+static int test_intname(
+ const struct _int_map *row,
+ int pbus,
+ int pslot,
+ int pfun,
+ int int_pin,
+ int int_name
+) {
+ int j, k;
+ int _nopin= -1, _noname= -1;
+
+ for (j=0; row->pin_route[j].pin > -1; j++) {
+ if ( row->pin_route[j].pin == int_pin ) {
+ _nopin = 0;
+
+ for (k=0; k<4 && row->pin_route[j].int_name[k] > -1; k++ ) {
+ if ( row->pin_route[j].int_name[k] == int_name ) {
+ _noname=0; break;
+ }
+ }
+ break;
+ }
+ }
+
+ if( _nopin )
+ {
+ printk("pci : Device %d:0x%02x:%d supplied a bogus interrupt_pin %d\n", pbus, pslot, pfun, int_pin );
+ return -1;
+ }
+ else
+ {
+ if( _noname ) {
+ unsigned char v = row->pin_route[j].int_name[0];
+ printk("pci : Device %d:0x%02x:%d supplied a suspicious interrupt_line %d, ", pbus, pslot, pfun, int_name );
+ if ( (row->opts & PCI_FIXUP_OPT_OVERRIDE_NAME) && 255 != (v = row->pin_route[j].int_name[0]) ) {
+ printk("OVERRIDING with %d from fixup table\n", v);
+ pci_write_config_byte(pbus,pslot,pfun,PCI_INTERRUPT_LINE,v);
+ } else {
+ printk("using it anyway\n");
+ }
+ }
+ }
+ return 0;
+}
+
+struct pcibridge
+{
+ int bus;
+ int slot;
+};
+
+static int FindPCIbridge( int mybus, struct pcibridge *pb )
+{
+ int pbus, pslot;
+ uint8_t bussec, buspri;
+ uint16_t devid, vendorid, dclass;
+
+ for(pbus=0; pbus< pci_bus_count(); pbus++) {
+ for(pslot=0; pslot< PCI_MAX_DEVICES; pslot++) {
+ pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &devid);
+ if ( devid == 0xffff ) continue;
+
+ pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &vendorid);
+ if ( vendorid == 0xffff ) continue;
+
+ pci_read_config_word(pbus, pslot, 0, PCI_CLASS_DEVICE, &dclass);
+
+ if ( dclass == PCI_CLASS_BRIDGE_PCI ) {
+ pci_read_config_byte(pbus, pslot, 0, PCI_PRIMARY_BUS, &buspri);
+ pci_read_config_byte(pbus, pslot, 0, PCI_SECONDARY_BUS, &bussec);
+
+#ifdef SHOW_PCI_SETTING
+ printk("pci : Found bridge at %d:0x%02x, mybus %d, pribus %d, secbus %d ",
+ pbus, pslot, mybus, buspri, bussec );
+#endif
+ if ( bussec == mybus ) {
+#ifdef SHOW_PCI_SETTING
+ printk("match\n");
+#endif
+ /* found our nearest bridge going towards the root */
+ pb->bus = pbus;
+ pb->slot = pslot;
+
+ return 0;
+ }
+#ifdef SHOW_PCI_SETTING
+ printk("no match\n");
+#endif
+ }
+
+ }
+ }
+ return -1;
+}
+
+void FixupPCI( const struct _int_map *bspmap, int (*swizzler)(int,int) )
+{
+ unsigned char cvalue;
+ uint16_t devid;
+ int ismatch, i, j, pbus, pslot, pfun, int_pin, int_name, nfuns;
+
+ /*
+ * If the device has a non-zero INTERRUPT_PIN, assign a bsp-specific
+ * INTERRUPT_NAME if one isn't already in place. Then, drivers can
+ * trivially use INTERRUPT_NAME to hook up with devices.
+ */
+
+ for (pbus=0; pbus< pci_bus_count(); pbus++) {
+ for (pslot=0; pslot< PCI_MAX_DEVICES; pslot++) {
+ pci_read_config_word(pbus, pslot, 0, PCI_DEVICE_ID, &devid);
+ if ( devid == 0xffff ) continue;
+
+ /* got a device */
+ pci_read_config_byte(pbus, pslot, 0, PCI_HEADER_TYPE, &cvalue);
+ nfuns = cvalue & PCI_HEADER_TYPE_MULTI_FUNCTION ? PCI_MAX_FUNCTIONS : 1;
+
+ for (pfun=0; pfun< nfuns; pfun++) {
+ pci_read_config_word(pbus, pslot, pfun, PCI_DEVICE_ID, &devid);
+ if( devid == 0xffff ) continue;
+
+ pci_read_config_byte( pbus, pslot, pfun, PCI_INTERRUPT_PIN, &cvalue);
+ int_pin = cvalue;
+
+ pci_read_config_byte( pbus, pslot, pfun, PCI_INTERRUPT_LINE, &cvalue);
+ int_name = cvalue;
+
+ /* printk("pci : device %d:0x%02x:%i devid %04x, intpin %d, intline %d\n",
+ pbus, pslot, pfun, devid, int_pin, int_name ); */
+
+#ifdef SHOW_PCI_SETTING
+ {
+ unsigned short cmd,stat;
+ unsigned char lat, seclat, csize;
+
+ pci_read_config_word(pbus,pslot,pfun,PCI_COMMAND, &cmd );
+ pci_read_config_word(pbus,pslot,pfun,PCI_STATUS, &stat );
+ pci_read_config_byte(pbus,pslot,pfun,PCI_LATENCY_TIMER, &lat );
+ pci_read_config_byte(pbus,pslot,pfun,PCI_SEC_LATENCY_TIMER, &seclat );
+ pci_read_config_byte(pbus,pslot,pfun,PCI_CACHE_LINE_SIZE, &csize );
+
+
+ printk("pci : device %d:0x%02x:%d cmd %04X, stat %04X, latency %d, "
+ " sec_latency %d, clsize %d\n", pbus, pslot, pfun, cmd, stat,
+ lat, seclat, csize);
+ }
+#endif
+
+ if ( int_pin > 0 ) {
+ ismatch = 0;
+
+ /*
+ * first run thru the bspmap table and see if we have an
+ * explicit configuration
+ */
+ for (i=0; bspmap[i].bus > -1; i++) {
+ if ( bspmap[i].bus == pbus && bspmap[i].slot == pslot ) {
+ ismatch = -1;
+ /* we have a record in the table that gives specific
+ * pins and interrupts for devices in this slot */
+ if ( int_name == 255 ) {
+ /* find the vector associated with whatever pin the
+ * device gives us
+ */
+ for ( int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++ ) {
+ if ( bspmap[i].pin_route[j].pin == int_pin ) {
+ int_name = bspmap[i].pin_route[j].int_name[0];
+ break;
+ }
+ }
+ if ( int_name == -1 ) {
+ printk("pci : Unable to resolve device %d:0x%02x:%d w/ swizzled int "
+ "pin %i to an interrupt_line.\n", pbus, pslot, pfun, int_pin );
+ } else {
+ PRINT_MSG();
+ pci_write_config_byte( pbus,pslot,pfun,
+ PCI_INTERRUPT_LINE,(cvalue= int_name, cvalue));
+ }
+ } else {
+ test_intname( &bspmap[i],pbus,pslot,pfun,int_pin,int_name);
+ }
+ break;
+ }
+ }
+
+ if ( !ismatch ) {
+ /*
+ * no match, which means we're on a bus someplace. Work
+ * backwards from it to one of our defined busses,
+ * swizzling thru each bridge on the way.
+ */
+
+ /* keep pbus, pslot pointed to the device being
+ * configured while we track down the bridges using
+ * tbus,tslot. We keep searching the routing table because
+ * we may end up finding our bridge in it
+ */
+
+ int tbus= pbus, tslot= pslot;
+
+ for (;;) {
+ for (i=0; bspmap[i].bus > -1; i++) {
+ if ( bspmap[i].bus == tbus &&
+ (bspmap[i].slot == tslot || bspmap[i].slot == -1) ) {
+ ismatch = -1;
+ /* found a record for this bus, so swizzle the
+ * int_pin which we then use to find the
+ * interrupt_name.
+ */
+
+ if ( int_name == 255 ) {
+ /*
+ * FIXME. I can't believe this little hack
+ * is right. It does not yield an error in
+ * convienently simple situations.
+ */
+ if ( tbus ) int_pin = (*swizzler)(tslot,int_pin);
+
+ /*
+ * int_pin points to the interrupt channel
+ * this card ends up delivering interrupts
+ * on. Find the int_name servicing it.
+ */
+ for (int_name=-1, j=0; bspmap[i].pin_route[j].pin > -1; j++){
+ if ( bspmap[i].pin_route[j].pin == int_pin ) {
+ int_name = bspmap[i].pin_route[j].int_name[0];
+ break;
+ }
+ }
+
+ if ( int_name == -1 ) {
+ printk("pci : Unable to resolve device %d:0x%02x:%d w/ swizzled "
+ "int pin %i to an interrupt_line.\n",
+ pbus, pslot, pfun, int_pin );
+ } else {
+ PRINT_MSG();
+ pci_write_config_byte(pbus,pslot,pfun,
+ PCI_INTERRUPT_LINE,(cvalue=int_name, cvalue));
+ }
+ } else {
+ test_intname(&bspmap[i],pbus,pslot,pfun,int_pin,int_name);
+ }
+ goto donesearch;
+ }
+ }
+
+ if ( !ismatch ) {
+ struct pcibridge pb;
+
+ /*
+ * Haven't found our bus in the int map, so work
+ * upwards thru the bridges till we find it.
+ */
+
+ if ( FindPCIbridge( tbus, &pb )== 0 ) {
+ int_pin = (*swizzler)(tslot,int_pin);
+
+ /* our next bridge up is on pb.bus, pb.slot- now
+ * instead of pointing to the device we're
+ * trying to configure, we move from bridge to
+ * bridge.
+ */
+
+ tbus = pb.bus;
+ tslot = pb.slot;
+ } else {
+ printk("pci : No bridge from bus %i towards root found\n",
+ tbus );
+ goto donesearch;
+ }
+ }
+ }
+ }
+donesearch:
+
+ if ( !ismatch && int_pin != 0 && int_name == 255 ) {
+ printk("pci : Unable to match device %d:0x%02x:%d with an int "
+ "routing table entry\n", pbus, pslot, pfun );
+ }
+ }
+ }
+ }
+ }
+}
+
+/*
+ * This routine determines the maximum bus number in the system
+ */
+int pci_initialize(void)
+{
+ unsigned char ucSlotNumber, ucFnNumber, ucNumFuncs;
+ unsigned char ucHeader;
+ unsigned char ucMaxSubordinate;
+ uint32_t ulClass;
+ uint32_t ulDeviceID;
+
+ detect_host_bridge();
+
+ /*
+ * Scan PCI bus 0 looking for PCI-PCI bridges
+ */
+ for (ucSlotNumber=0;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) {
+ pci_read_config_dword(0, ucSlotNumber, 0, PCI_VENDOR_ID, &ulDeviceID);
+ if (ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
+ /* This slot is empty */
+ continue;
+ }
+ pci_read_config_byte(0, ucSlotNumber, 0, PCI_HEADER_TYPE, &ucHeader);
+ if (ucHeader&PCI_HEADER_TYPE_MULTI_FUNCTION) {
+ ucNumFuncs=PCI_MAX_FUNCTIONS;
+ } else {
+ ucNumFuncs=1;
+ }
+ for (ucFnNumber=0;ucFnNumber<ucNumFuncs;ucFnNumber++) {
+ pci_read_config_dword(0, 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(0, ucSlotNumber, ucFnNumber,
+ PCI_CLASS_REVISION, &ulClass);
+ ulClass >>= 16;
+ if (ulClass == PCI_CLASS_BRIDGE_PCI) {
+ /* We have found a PCI-PCI bridge */
+ pci_read_config_byte(0, ucSlotNumber, ucFnNumber,
+ PCI_SUBORDINATE_BUS, &ucMaxSubordinate);
+ if (ucMaxSubordinate>ucMaxPCIBus) {
+ ucMaxPCIBus=ucMaxSubordinate;
+ }
+ }
+ }
+ }
+ return PCIB_ERR_SUCCESS;
+}
+
+/*
+ * Return the number of PCI busses in the system
+ */
+unsigned char pci_bus_count(void)
+{
+ return (ucMaxPCIBus+1);
+}
diff --git a/bsps/powerpc/shared/pci/pcifinddevice.c b/bsps/powerpc/shared/pci/pcifinddevice.c
new file mode 100644
index 0000000000..8aad50547a
--- /dev/null
+++ b/bsps/powerpc/shared/pci/pcifinddevice.c
@@ -0,0 +1,212 @@
+/* find a particular PCI device
+ * (we assume, the firmware configured the PCI bus[es] for us)
+ */
+
+/*
+ * Authorship
+ * ----------
+ * This software was created by
+ * Till Straumann <strauman@slac.stanford.edu>, 2001,
+ * Stanford Linear Accelerator Center, Stanford University.
+ *
+ * Acknowledgement of sponsorship
+ * ------------------------------
+ * This software 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 <inttypes.h>
+#include <bsp/pci.h>
+#include <rtems/bspIo.h>
+#include <stdio.h>
+
+/* Stolen from i386... */
+
+/*
+ * Make device signature from bus number, device number and function
+ * number
+ */
+#define PCIB_DEVSIG_MAKE(b,d,f) ((b<<8)|(d<<3)|(f))
+
+/*
+ * Extract various parts from device signature
+ */
+#define PCIB_DEVSIG_BUS(x) (((x)>>8) &0xff)
+#define PCIB_DEVSIG_DEV(x) (((x)>>3) & 0x1f)
+#define PCIB_DEVSIG_FUNC(x) ((x) & 0x7)
+
+typedef struct {
+ unsigned short vid,did;
+ int inst;
+} fd_arg;
+
+static int
+find_dev_cb(
+ int bus,
+ int dev,
+ int fun,
+ void *uarg
+) {
+fd_arg *a = uarg;
+unsigned short s;
+
+ pci_read_config_word(bus,dev,fun,PCI_VENDOR_ID,&s);
+ if (a->vid == s) {
+ pci_read_config_word(bus,dev,fun,PCI_DEVICE_ID,&s);
+ if (a->did == s && 0 == a->inst-- ) {
+ a->inst = PCIB_DEVSIG_MAKE( bus, dev, fun );
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+pci_find_device(
+ unsigned short vendorid,
+ unsigned short deviceid,
+ int instance,
+ int *pbus,
+ int *pdev,
+ int *pfun
+) {
+fd_arg a;
+void *h;
+ a.vid = vendorid;
+ a.did = deviceid;
+ a.inst = instance;
+
+ if ( (h = BSP_pciScan(0, find_dev_cb, (void*)&a)) ) {
+ *pbus = PCIB_DEVSIG_BUS( a.inst );
+ *pdev = PCIB_DEVSIG_DEV( a.inst );
+ *pfun = PCIB_DEVSIG_FUNC( a.inst );
+ return 0;
+ }
+ return -1;
+}
+
+static int
+dump_dev_cb(
+ int bus,
+ int dev,
+ int fun,
+ void *uarg
+)
+{
+ uint16_t vi,di;
+ uint16_t cd,st;
+ uint32_t b1,b2;
+ uint8_t il,ip;
+ FILE *f = uarg;
+
+ pci_read_config_word (bus, dev, fun, PCI_VENDOR_ID, &vi);
+ pci_read_config_word (bus, dev, fun, PCI_DEVICE_ID, &di);
+ pci_read_config_word (bus, dev, fun, PCI_COMMAND, &cd);
+ pci_read_config_word (bus, dev, fun, PCI_STATUS, &st);
+ pci_read_config_dword(bus, dev, fun, PCI_BASE_ADDRESS_0, &b1);
+ pci_read_config_dword(bus, dev, fun, PCI_BASE_ADDRESS_1, &b2);
+ pci_read_config_byte (bus, dev, fun, PCI_INTERRUPT_LINE, &il);
+ pci_read_config_byte (bus, dev, fun, PCI_INTERRUPT_PIN, &ip);
+
+ /* fprintf(f,"%3d:0x%02x:%d 0x%04x-0x%04x: 0x%04x 0x%04x 0x%08x 0x%08x %d -> %3d (=0x%02x)\n", */
+ fprintf(f,"%3d:0x%02x:%d 0x%04x-0x%04x: 0x%04x 0x%04x 0x%08" PRIx32 " 0x%08" PRIx32 " %d -> %3d (=0x%02x)\n",
+ bus, dev, fun, vi, di, cd, st, b1, b2, ip, il, il);
+ return 0;
+}
+
+void
+BSP_pciConfigDump(FILE *f)
+{
+ if ( !f )
+ f = stdout;
+ fprintf(f,"BUS:SLOT:FUN VENDOR-DEV_ID: COMMAND STATUS BASE_ADDR0 BASE_ADDR1 IRQ_PIN -> IRQ_LINE\n");
+ BSP_pciScan(0, dump_dev_cb, f);
+}
+
+BSP_PciScanHandle
+BSP_pciScan(
+ BSP_PciScanHandle handle,
+ BSP_PciScannerCb cb,
+ void *uarg
+) {
+
+ uint32_t d;
+ unsigned char bus,dev,fun,hd;
+
+ bus = PCIB_DEVSIG_BUS( (unsigned long)handle );
+ dev = PCIB_DEVSIG_DEV( (unsigned long)handle );
+ fun = PCIB_DEVSIG_FUNC( (unsigned long)handle );
+
+ hd = fun > 0 ? PCI_MAX_FUNCTIONS : 1;
+
+ for (; bus<pci_bus_count(); bus++, dev=0) {
+ for (; dev<PCI_MAX_DEVICES; dev++, fun=0) {
+ for (; fun<hd; fun++) {
+ /*
+ * The last devfn id/slot is special; must skip it
+ */
+ if (PCI_MAX_DEVICES-1==dev && PCI_MAX_FUNCTIONS-1 == fun)
+ break;
+
+ (void)pci_read_config_dword(bus,dev,0,PCI_VENDOR_ID,&d);
+ if (PCI_INVALID_VENDORDEVICEID == d)
+ continue;
+
+ if ( 0 == fun ) {
+ pci_read_config_byte(bus,dev,0, PCI_HEADER_TYPE, &hd);
+ hd = (hd & PCI_HEADER_TYPE_MULTI_FUNCTION ? PCI_MAX_FUNCTIONS : 1);
+ }
+
+ (void)pci_read_config_dword(bus,dev,fun,PCI_VENDOR_ID,&d);
+ if (PCI_INVALID_VENDORDEVICEID == d)
+ continue;
+#ifdef PCI_DEBUG
+ printk("BSP_pciScan: found 0x%08x at %d/x%02x/%d\n",d,bus,dev,fun);
+#endif
+ if ( cb(bus,dev,fun,uarg) > 0 ) {
+ if ( ++fun >= hd ) {
+ fun = 0;
+ if ( ++dev >= PCI_MAX_DEVICES ) {
+ dev = 0;
+ bus++;
+ }
+ }
+ return (void*) PCIB_DEVSIG_MAKE(bus,dev,fun);
+ }
+ }
+ }
+ }
+ return 0;
+}