summaryrefslogtreecommitdiffstats
path: root/u-boot/drivers/pci
diff options
context:
space:
mode:
Diffstat (limited to 'u-boot/drivers/pci')
-rw-r--r--u-boot/drivers/pci/Makefile53
-rw-r--r--u-boot/drivers/pci/fsl_pci_init.c699
-rw-r--r--u-boot/drivers/pci/pci.c733
-rw-r--r--u-boot/drivers/pci/pci_auto.c424
-rw-r--r--u-boot/drivers/pci/pci_indirect.c137
-rw-r--r--u-boot/drivers/pci/pci_ixp.c571
-rw-r--r--u-boot/drivers/pci/pci_sh4.c98
-rw-r--r--u-boot/drivers/pci/pci_sh7751.c203
-rw-r--r--u-boot/drivers/pci/pci_sh7780.c108
-rw-r--r--u-boot/drivers/pci/tsi108_pci.c183
-rw-r--r--u-boot/drivers/pci/w83c553f.c222
11 files changed, 3431 insertions, 0 deletions
diff --git a/u-boot/drivers/pci/Makefile b/u-boot/drivers/pci/Makefile
new file mode 100644
index 0000000..ee0c64d
--- /dev/null
+++ b/u-boot/drivers/pci/Makefile
@@ -0,0 +1,53 @@
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB := $(obj)libpci.o
+
+COBJS-$(CONFIG_FSL_PCI_INIT) += fsl_pci_init.o
+COBJS-$(CONFIG_PCI) += pci.o pci_auto.o pci_indirect.o
+COBJS-$(CONFIG_IXP_PCI) += pci_ixp.o
+COBJS-$(CONFIG_SH4_PCI) += pci_sh4.o
+COBJS-$(CONFIG_SH7751_PCI) +=pci_sh7751.o
+COBJS-$(CONFIG_SH7780_PCI) +=pci_sh7780.o
+COBJS-$(CONFIG_TSI108_PCI) += tsi108_pci.o
+COBJS-$(CONFIG_WINBOND_83C553) += w83c553f.o
+
+COBJS := $(COBJS-y)
+SRCS := $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+
+all: $(LIB)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/u-boot/drivers/pci/fsl_pci_init.c b/u-boot/drivers/pci/fsl_pci_init.c
new file mode 100644
index 0000000..3118b85
--- /dev/null
+++ b/u-boot/drivers/pci/fsl_pci_init.c
@@ -0,0 +1,699 @@
+/*
+ * Copyright 2007-2010 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <asm/fsl_serdes.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * PCI/PCIE Controller initialization for mpc85xx/mpc86xx soc's
+ *
+ * Initialize controller and call the common driver/pci pci_hose_scan to
+ * scan for bridges and devices.
+ *
+ * Hose fields which need to be pre-initialized by board specific code:
+ * regions[]
+ * first_busno
+ *
+ * Fields updated:
+ * last_busno
+ */
+
+#include <pci.h>
+#include <asm/io.h>
+#include <asm/fsl_pci.h>
+
+/* Freescale-specific PCI config registers */
+#define FSL_PCI_PBFR 0x44
+#define FSL_PCIE_CAP_ID 0x4c
+#define FSL_PCIE_CFG_RDY 0x4b0
+#define FSL_PROG_IF_AGENT 0x1
+
+void pciauto_prescan_setup_bridge(struct pci_controller *hose,
+ pci_dev_t dev, int sub_bus);
+void pciauto_postscan_setup_bridge(struct pci_controller *hose,
+ pci_dev_t dev, int sub_bus);
+void pciauto_config_init(struct pci_controller *hose);
+
+#ifndef CONFIG_SYS_PCI_MEMORY_BUS
+#define CONFIG_SYS_PCI_MEMORY_BUS 0
+#endif
+
+#ifndef CONFIG_SYS_PCI_MEMORY_PHYS
+#define CONFIG_SYS_PCI_MEMORY_PHYS 0
+#endif
+
+#if defined(CONFIG_SYS_PCI_64BIT) && !defined(CONFIG_SYS_PCI64_MEMORY_BUS)
+#define CONFIG_SYS_PCI64_MEMORY_BUS (64ull*1024*1024*1024)
+#endif
+
+/* Setup one inbound ATMU window.
+ *
+ * We let the caller decide what the window size should be
+ */
+static void set_inbound_window(volatile pit_t *pi,
+ struct pci_region *r,
+ u64 size)
+{
+ u32 sz = (__ilog2_u64(size) - 1);
+ u32 flag = PIWAR_EN | PIWAR_LOCAL |
+ PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
+
+ out_be32(&pi->pitar, r->phys_start >> 12);
+ out_be32(&pi->piwbar, r->bus_start >> 12);
+#ifdef CONFIG_SYS_PCI_64BIT
+ out_be32(&pi->piwbear, r->bus_start >> 44);
+#else
+ out_be32(&pi->piwbear, 0);
+#endif
+ if (r->flags & PCI_REGION_PREFETCH)
+ flag |= PIWAR_PF;
+ out_be32(&pi->piwar, flag | sz);
+}
+
+int fsl_setup_hose(struct pci_controller *hose, unsigned long addr)
+{
+ volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *) addr;
+
+ /* Reset hose to make sure its in a clean state */
+ memset(hose, 0, sizeof(struct pci_controller));
+
+ pci_setup_indirect(hose, (u32)&pci->cfg_addr, (u32)&pci->cfg_data);
+
+ return fsl_is_pci_agent(hose);
+}
+
+static int fsl_pci_setup_inbound_windows(struct pci_controller *hose,
+ u64 out_lo, u8 pcie_cap,
+ volatile pit_t *pi)
+{
+ struct pci_region *r = hose->regions + hose->region_count;
+ u64 sz = min((u64)gd->ram_size, (1ull << 32));
+
+ phys_addr_t phys_start = CONFIG_SYS_PCI_MEMORY_PHYS;
+ pci_addr_t bus_start = CONFIG_SYS_PCI_MEMORY_BUS;
+ pci_size_t pci_sz;
+
+ /* we have no space available for inbound memory mapping */
+ if (bus_start > out_lo) {
+ printf ("no space for inbound mapping of memory\n");
+ return 0;
+ }
+
+ /* limit size */
+ if ((bus_start + sz) > out_lo) {
+ sz = out_lo - bus_start;
+ debug ("limiting size to %llx\n", sz);
+ }
+
+ pci_sz = 1ull << __ilog2_u64(sz);
+ /*
+ * we can overlap inbound/outbound windows on PCI-E since RX & TX
+ * links a separate
+ */
+ if ((pcie_cap == PCI_CAP_ID_EXP) && (pci_sz < sz)) {
+ debug ("R0 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)bus_start, (u64)phys_start, (u64)sz);
+ pci_set_region(r, bus_start, phys_start, sz,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
+ PCI_REGION_PREFETCH);
+
+ /* if we aren't an exact power of two match, pci_sz is smaller
+ * round it up to the next power of two. We report the actual
+ * size to pci region tracking.
+ */
+ if (pci_sz != sz)
+ sz = 2ull << __ilog2_u64(sz);
+
+ set_inbound_window(pi--, r++, sz);
+ sz = 0; /* make sure we dont set the R2 window */
+ } else {
+ debug ("R0 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)bus_start, (u64)phys_start, (u64)pci_sz);
+ pci_set_region(r, bus_start, phys_start, pci_sz,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
+ PCI_REGION_PREFETCH);
+ set_inbound_window(pi--, r++, pci_sz);
+
+ sz -= pci_sz;
+ bus_start += pci_sz;
+ phys_start += pci_sz;
+
+ pci_sz = 1ull << __ilog2_u64(sz);
+ if (sz) {
+ debug ("R1 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)bus_start, (u64)phys_start, (u64)pci_sz);
+ pci_set_region(r, bus_start, phys_start, pci_sz,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
+ PCI_REGION_PREFETCH);
+ set_inbound_window(pi--, r++, pci_sz);
+ sz -= pci_sz;
+ bus_start += pci_sz;
+ phys_start += pci_sz;
+ }
+ }
+
+#if defined(CONFIG_PHYS_64BIT) && defined(CONFIG_SYS_PCI_64BIT)
+ /*
+ * On 64-bit capable systems, set up a mapping for all of DRAM
+ * in high pci address space.
+ */
+ pci_sz = 1ull << __ilog2_u64(gd->ram_size);
+ /* round up to the next largest power of two */
+ if (gd->ram_size > pci_sz)
+ pci_sz = 1ull << (__ilog2_u64(gd->ram_size) + 1);
+ debug ("R64 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)CONFIG_SYS_PCI64_MEMORY_BUS,
+ (u64)CONFIG_SYS_PCI_MEMORY_PHYS,
+ (u64)pci_sz);
+ pci_set_region(r,
+ CONFIG_SYS_PCI64_MEMORY_BUS,
+ CONFIG_SYS_PCI_MEMORY_PHYS,
+ pci_sz,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
+ PCI_REGION_PREFETCH);
+ set_inbound_window(pi--, r++, pci_sz);
+#else
+ pci_sz = 1ull << __ilog2_u64(sz);
+ if (sz) {
+ debug ("R2 bus_start: %llx phys_start: %llx size: %llx\n",
+ (u64)bus_start, (u64)phys_start, (u64)pci_sz);
+ pci_set_region(r, bus_start, phys_start, pci_sz,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY |
+ PCI_REGION_PREFETCH);
+ sz -= pci_sz;
+ bus_start += pci_sz;
+ phys_start += pci_sz;
+ set_inbound_window(pi--, r++, pci_sz);
+ }
+#endif
+
+#ifdef CONFIG_PHYS_64BIT
+ if (sz && (((u64)gd->ram_size) < (1ull << 32)))
+ printf("Was not able to map all of memory via "
+ "inbound windows -- %lld remaining\n", sz);
+#endif
+
+ hose->region_count = r - hose->regions;
+
+ return 1;
+}
+
+void fsl_pci_init(struct pci_controller *hose, struct fsl_pci_info *pci_info)
+{
+ u32 cfg_addr = (u32)&((ccsr_fsl_pci_t *)pci_info->regs)->cfg_addr;
+ u32 cfg_data = (u32)&((ccsr_fsl_pci_t *)pci_info->regs)->cfg_data;
+ u16 temp16;
+ u32 temp32;
+ int enabled, r, inbound = 0;
+ u16 ltssm;
+ u8 temp8, pcie_cap;
+ volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *)cfg_addr;
+ struct pci_region *reg = hose->regions + hose->region_count;
+ pci_dev_t dev = PCI_BDF(hose->first_busno, 0, 0);
+
+ /* Initialize ATMU registers based on hose regions and flags */
+ volatile pot_t *po = &pci->pot[1]; /* skip 0 */
+ volatile pit_t *pi = &pci->pit[2]; /* ranges from: 3 to 1 */
+
+ u64 out_hi = 0, out_lo = -1ULL;
+ u32 pcicsrbar, pcicsrbar_sz;
+
+ pci_setup_indirect(hose, cfg_addr, cfg_data);
+
+ /* Handle setup of outbound windows first */
+ for (r = 0; r < hose->region_count; r++) {
+ unsigned long flags = hose->regions[r].flags;
+ u32 sz = (__ilog2_u64((u64)hose->regions[r].size) - 1);
+
+ flags &= PCI_REGION_SYS_MEMORY|PCI_REGION_TYPE;
+ if (flags != PCI_REGION_SYS_MEMORY) {
+ u64 start = hose->regions[r].bus_start;
+ u64 end = start + hose->regions[r].size;
+
+ out_be32(&po->powbar, hose->regions[r].phys_start >> 12);
+ out_be32(&po->potar, start >> 12);
+#ifdef CONFIG_SYS_PCI_64BIT
+ out_be32(&po->potear, start >> 44);
+#else
+ out_be32(&po->potear, 0);
+#endif
+ if (hose->regions[r].flags & PCI_REGION_IO) {
+ out_be32(&po->powar, POWAR_EN | sz |
+ POWAR_IO_READ | POWAR_IO_WRITE);
+ } else {
+ out_be32(&po->powar, POWAR_EN | sz |
+ POWAR_MEM_READ | POWAR_MEM_WRITE);
+ out_lo = min(start, out_lo);
+ out_hi = max(end, out_hi);
+ }
+ po++;
+ }
+ }
+ debug("Outbound memory range: %llx:%llx\n", out_lo, out_hi);
+
+ /* setup PCSRBAR/PEXCSRBAR */
+ pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_0, 0xffffffff);
+ pci_hose_read_config_dword (hose, dev, PCI_BASE_ADDRESS_0, &pcicsrbar_sz);
+ pcicsrbar_sz = ~pcicsrbar_sz + 1;
+
+ if (out_hi < (0x100000000ull - pcicsrbar_sz) ||
+ (out_lo > 0x100000000ull))
+ pcicsrbar = 0x100000000ull - pcicsrbar_sz;
+ else
+ pcicsrbar = (out_lo - pcicsrbar_sz) & -pcicsrbar_sz;
+ pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_0, pcicsrbar);
+
+ out_lo = min(out_lo, (u64)pcicsrbar);
+
+ debug("PCICSRBAR @ 0x%x\n", pcicsrbar);
+
+ pci_set_region(reg++, pcicsrbar, CONFIG_SYS_CCSRBAR_PHYS,
+ pcicsrbar_sz, PCI_REGION_SYS_MEMORY);
+ hose->region_count++;
+
+ /* see if we are a PCIe or PCI controller */
+ pci_hose_read_config_byte(hose, dev, FSL_PCIE_CAP_ID, &pcie_cap);
+
+ /* inbound */
+ inbound = fsl_pci_setup_inbound_windows(hose, out_lo, pcie_cap, pi);
+
+ for (r = 0; r < hose->region_count; r++)
+ debug("PCI reg:%d %016llx:%016llx %016llx %08x\n", r,
+ (u64)hose->regions[r].phys_start,
+ hose->regions[r].bus_start,
+ hose->regions[r].size,
+ hose->regions[r].flags);
+
+ pci_register_hose(hose);
+ pciauto_config_init(hose); /* grab pci_{mem,prefetch,io} */
+ hose->current_busno = hose->first_busno;
+
+ out_be32(&pci->pedr, 0xffffffff); /* Clear any errors */
+ out_be32(&pci->peer, ~0x20140); /* Enable All Error Interupts except
+ * - Master abort (pci)
+ * - Master PERR (pci)
+ * - ICCA (PCIe)
+ */
+ pci_hose_read_config_dword(hose, dev, PCI_DCR, &temp32);
+ temp32 |= 0xf000e; /* set URR, FER, NFER (but not CER) */
+ pci_hose_write_config_dword(hose, dev, PCI_DCR, temp32);
+
+ if (pcie_cap == PCI_CAP_ID_EXP) {
+ pci_hose_read_config_word(hose, dev, PCI_LTSSM, &ltssm);
+ enabled = ltssm >= PCI_LTSSM_L0;
+
+#ifdef CONFIG_FSL_PCIE_RESET
+ if (ltssm == 1) {
+ int i;
+ debug("....PCIe link error. " "LTSSM=0x%02x.", ltssm);
+ /* assert PCIe reset */
+ setbits_be32(&pci->pdb_stat, 0x08000000);
+ (void) in_be32(&pci->pdb_stat);
+ udelay(100);
+ debug(" Asserting PCIe reset @%x = %x\n",
+ &pci->pdb_stat, in_be32(&pci->pdb_stat));
+ /* clear PCIe reset */
+ clrbits_be32(&pci->pdb_stat, 0x08000000);
+ asm("sync;isync");
+ for (i=0; i<100 && ltssm < PCI_LTSSM_L0; i++) {
+ pci_hose_read_config_word(hose, dev, PCI_LTSSM,
+ &ltssm);
+ udelay(1000);
+ debug("....PCIe link error. "
+ "LTSSM=0x%02x.\n", ltssm);
+ }
+ enabled = ltssm >= PCI_LTSSM_L0;
+
+ /* we need to re-write the bar0 since a reset will
+ * clear it
+ */
+ pci_hose_write_config_dword(hose, dev,
+ PCI_BASE_ADDRESS_0, pcicsrbar);
+ }
+#endif
+
+ if (!enabled) {
+ /* Let the user know there's no PCIe link */
+ printf("no link, regs @ 0x%lx\n", pci_info->regs);
+ hose->last_busno = hose->first_busno;
+ return;
+ }
+
+ out_be32(&pci->pme_msg_det, 0xffffffff);
+ out_be32(&pci->pme_msg_int_en, 0xffffffff);
+
+ /* Print the negotiated PCIe link width */
+ pci_hose_read_config_word(hose, dev, PCI_LSR, &temp16);
+ printf("x%d, regs @ 0x%lx\n", (temp16 & 0x3f0 ) >> 4,
+ pci_info->regs);
+
+ hose->current_busno++; /* Start scan with secondary */
+ pciauto_prescan_setup_bridge(hose, dev, hose->current_busno);
+ }
+
+ /* Use generic setup_device to initialize standard pci regs,
+ * but do not allocate any windows since any BAR found (such
+ * as PCSRBAR) is not in this cpu's memory space.
+ */
+ pciauto_setup_device(hose, dev, 0, hose->pci_mem,
+ hose->pci_prefetch, hose->pci_io);
+
+ if (inbound) {
+ pci_hose_read_config_word(hose, dev, PCI_COMMAND, &temp16);
+ pci_hose_write_config_word(hose, dev, PCI_COMMAND,
+ temp16 | PCI_COMMAND_MEMORY);
+ }
+
+#ifndef CONFIG_PCI_NOSCAN
+ pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &temp8);
+
+ /* Programming Interface (PCI_CLASS_PROG)
+ * 0 == pci host or pcie root-complex,
+ * 1 == pci agent or pcie end-point
+ */
+ if (!temp8) {
+ debug(" Scanning PCI bus %02x\n",
+ hose->current_busno);
+ hose->last_busno = pci_hose_scan_bus(hose, hose->current_busno);
+ } else {
+ debug(" Not scanning PCI bus %02x. PI=%x\n",
+ hose->current_busno, temp8);
+ hose->last_busno = hose->current_busno;
+ }
+
+ /* if we are PCIe - update limit regs and subordinate busno
+ * for the virtual P2P bridge
+ */
+ if (pcie_cap == PCI_CAP_ID_EXP) {
+ pciauto_postscan_setup_bridge(hose, dev, hose->last_busno);
+ }
+#else
+ hose->last_busno = hose->current_busno;
+#endif
+
+ /* Clear all error indications */
+ if (pcie_cap == PCI_CAP_ID_EXP)
+ out_be32(&pci->pme_msg_det, 0xffffffff);
+ out_be32(&pci->pedr, 0xffffffff);
+
+ pci_hose_read_config_word (hose, dev, PCI_DSR, &temp16);
+ if (temp16) {
+ pci_hose_write_config_word(hose, dev, PCI_DSR, 0xffff);
+ }
+
+ pci_hose_read_config_word (hose, dev, PCI_SEC_STATUS, &temp16);
+ if (temp16) {
+ pci_hose_write_config_word(hose, dev, PCI_SEC_STATUS, 0xffff);
+ }
+}
+
+int fsl_is_pci_agent(struct pci_controller *hose)
+{
+ u8 prog_if;
+ pci_dev_t dev = PCI_BDF(hose->first_busno, 0, 0);
+
+ pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &prog_if);
+
+ return (prog_if == FSL_PROG_IF_AGENT);
+}
+
+int fsl_pci_init_port(struct fsl_pci_info *pci_info,
+ struct pci_controller *hose, int busno)
+{
+ volatile ccsr_fsl_pci_t *pci;
+ struct pci_region *r;
+ pci_dev_t dev = PCI_BDF(busno,0,0);
+ u8 pcie_cap;
+
+ pci = (ccsr_fsl_pci_t *) pci_info->regs;
+
+ /* on non-PCIe controllers we don't have pme_msg_det so this code
+ * should do nothing since the read will return 0
+ */
+ if (in_be32(&pci->pme_msg_det)) {
+ out_be32(&pci->pme_msg_det, 0xffffffff);
+ debug (" with errors. Clearing. Now 0x%08x",
+ pci->pme_msg_det);
+ }
+
+ r = hose->regions + hose->region_count;
+
+ /* outbound memory */
+ pci_set_region(r++,
+ pci_info->mem_bus,
+ pci_info->mem_phys,
+ pci_info->mem_size,
+ PCI_REGION_MEM);
+
+ /* outbound io */
+ pci_set_region(r++,
+ pci_info->io_bus,
+ pci_info->io_phys,
+ pci_info->io_size,
+ PCI_REGION_IO);
+
+ hose->region_count = r - hose->regions;
+ hose->first_busno = busno;
+
+ fsl_pci_init(hose, pci_info);
+
+ if (fsl_is_pci_agent(hose)) {
+ fsl_pci_config_unlock(hose);
+ hose->last_busno = hose->first_busno;
+ }
+
+ pci_hose_read_config_byte(hose, dev, FSL_PCIE_CAP_ID, &pcie_cap);
+ printf("PCI%s%x: Bus %02x - %02x\n", pcie_cap == PCI_CAP_ID_EXP ?
+ "e" : "", pci_info->pci_num,
+ hose->first_busno, hose->last_busno);
+
+ return(hose->last_busno + 1);
+}
+
+/* Enable inbound PCI config cycles for agent/endpoint interface */
+void fsl_pci_config_unlock(struct pci_controller *hose)
+{
+ pci_dev_t dev = PCI_BDF(hose->first_busno,0,0);
+ u8 agent;
+ u8 pcie_cap;
+ u16 pbfr;
+
+ pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &agent);
+ if (!agent)
+ return;
+
+ pci_hose_read_config_byte(hose, dev, FSL_PCIE_CAP_ID, &pcie_cap);
+ if (pcie_cap != 0x0) {
+ /* PCIe - set CFG_READY bit of Configuration Ready Register */
+ pci_hose_write_config_byte(hose, dev, FSL_PCIE_CFG_RDY, 0x1);
+ } else {
+ /* PCI - clear ACL bit of PBFR */
+ pci_hose_read_config_word(hose, dev, FSL_PCI_PBFR, &pbfr);
+ pbfr &= ~0x20;
+ pci_hose_write_config_word(hose, dev, FSL_PCI_PBFR, pbfr);
+ }
+}
+
+#if defined(CONFIG_PCIE1) || defined(CONFIG_PCIE2) || \
+ defined(CONFIG_PCIE3) || defined(CONFIG_PCIE4)
+int fsl_configure_pcie(struct fsl_pci_info *info,
+ struct pci_controller *hose,
+ const char *connected, int busno)
+{
+ int is_endpoint;
+
+ set_next_law(info->mem_phys, law_size_bits(info->mem_size), info->law);
+ set_next_law(info->io_phys, law_size_bits(info->io_size), info->law);
+
+ is_endpoint = fsl_setup_hose(hose, info->regs);
+ printf("PCIe%u: %s", info->pci_num,
+ is_endpoint ? "Endpoint" : "Root Complex");
+ if (connected)
+ printf(" of %s", connected);
+ puts(", ");
+
+ return fsl_pci_init_port(info, hose, busno);
+}
+
+#if defined(CONFIG_FSL_CORENET)
+ #define _DEVDISR_PCIE1 FSL_CORENET_DEVDISR_PCIE1
+ #define _DEVDISR_PCIE2 FSL_CORENET_DEVDISR_PCIE2
+ #define _DEVDISR_PCIE3 FSL_CORENET_DEVDISR_PCIE3
+ #define _DEVDISR_PCIE4 FSL_CORENET_DEVDISR_PCIE4
+ #define CONFIG_SYS_MPC8xxx_GUTS_ADDR CONFIG_SYS_MPC85xx_GUTS_ADDR
+#elif defined(CONFIG_MPC85xx)
+ #define _DEVDISR_PCIE1 MPC85xx_DEVDISR_PCIE
+ #define _DEVDISR_PCIE2 MPC85xx_DEVDISR_PCIE2
+ #define _DEVDISR_PCIE3 MPC85xx_DEVDISR_PCIE3
+ #define _DEVDISR_PCIE4 0
+ #define CONFIG_SYS_MPC8xxx_GUTS_ADDR CONFIG_SYS_MPC85xx_GUTS_ADDR
+#elif defined(CONFIG_MPC86xx)
+ #define _DEVDISR_PCIE1 MPC86xx_DEVDISR_PCIE1
+ #define _DEVDISR_PCIE2 MPC86xx_DEVDISR_PCIE2
+ #define _DEVDISR_PCIE3 0
+ #define _DEVDISR_PCIE4 0
+ #define CONFIG_SYS_MPC8xxx_GUTS_ADDR \
+ (&((immap_t *)CONFIG_SYS_IMMR)->im_gur)
+#else
+#error "No defines for DEVDISR_PCIE"
+#endif
+
+/* Implement a dummy function for those platforms w/o SERDES */
+static const char *__board_serdes_name(enum srds_prtcl device)
+{
+ switch (device) {
+#ifdef CONFIG_SYS_PCIE1_NAME
+ case PCIE1:
+ return CONFIG_SYS_PCIE1_NAME;
+#endif
+#ifdef CONFIG_SYS_PCIE2_NAME
+ case PCIE2:
+ return CONFIG_SYS_PCIE2_NAME;
+#endif
+#ifdef CONFIG_SYS_PCIE3_NAME
+ case PCIE3:
+ return CONFIG_SYS_PCIE3_NAME;
+#endif
+#ifdef CONFIG_SYS_PCIE4_NAME
+ case PCIE4:
+ return CONFIG_SYS_PCIE4_NAME;
+#endif
+ default:
+ return NULL;
+ }
+
+ return NULL;
+}
+
+__attribute__((weak, alias("__board_serdes_name"))) const char *
+board_serdes_name(enum srds_prtcl device);
+
+static u32 devdisr_mask[] = {
+ _DEVDISR_PCIE1,
+ _DEVDISR_PCIE2,
+ _DEVDISR_PCIE3,
+ _DEVDISR_PCIE4,
+};
+
+int fsl_pcie_init_ctrl(int busno, u32 devdisr, enum srds_prtcl dev,
+ struct fsl_pci_info *pci_info)
+{
+ struct pci_controller *hose;
+ int num = dev - PCIE1;
+
+ hose = calloc(1, sizeof(struct pci_controller));
+ if (!hose)
+ return busno;
+
+ if (is_serdes_configured(dev) && !(devdisr & devdisr_mask[num])) {
+ busno = fsl_configure_pcie(pci_info, hose,
+ board_serdes_name(dev), busno);
+ } else {
+ printf("PCIe%d: disabled\n", num + 1);
+ }
+
+ return busno;
+}
+
+int fsl_pcie_init_board(int busno)
+{
+ struct fsl_pci_info pci_info;
+ ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC8xxx_GUTS_ADDR;
+ u32 devdisr = in_be32(&gur->devdisr);
+
+#ifdef CONFIG_PCIE1
+ SET_STD_PCIE_INFO(pci_info, 1);
+ busno = fsl_pcie_init_ctrl(busno, devdisr, PCIE1, &pci_info);
+#else
+ setbits_be32(&gur->devdisr, _DEVDISR_PCIE1); /* disable */
+#endif
+
+#ifdef CONFIG_PCIE2
+ SET_STD_PCIE_INFO(pci_info, 2);
+ busno = fsl_pcie_init_ctrl(busno, devdisr, PCIE2, &pci_info);
+#else
+ setbits_be32(&gur->devdisr, _DEVDISR_PCIE2); /* disable */
+#endif
+
+#ifdef CONFIG_PCIE3
+ SET_STD_PCIE_INFO(pci_info, 3);
+ busno = fsl_pcie_init_ctrl(busno, devdisr, PCIE3, &pci_info);
+#else
+ setbits_be32(&gur->devdisr, _DEVDISR_PCIE3); /* disable */
+#endif
+
+#ifdef CONFIG_PCIE4
+ SET_STD_PCIE_INFO(pci_info, 4);
+ busno = fsl_pcie_init_ctrl(busno, devdisr, PCIE4, &pci_info);
+#else
+ setbits_be32(&gur->devdisr, _DEVDISR_PCIE4); /* disable */
+#endif
+
+ return busno;
+}
+#else
+int fsl_pcie_init_ctrl(int busno, u32 devdisr, enum srds_prtcl dev,
+ struct fsl_pci_info *pci_info)
+{
+ return busno;
+}
+
+int fsl_pcie_init_board(int busno)
+{
+ return busno;
+}
+#endif
+
+#ifdef CONFIG_OF_BOARD_SETUP
+#include <libfdt.h>
+#include <fdt_support.h>
+
+void ft_fsl_pci_setup(void *blob, const char *pci_compat,
+ unsigned long ctrl_addr)
+{
+ int off;
+ u32 bus_range[2];
+ phys_addr_t p_ctrl_addr = (phys_addr_t)ctrl_addr;
+ struct pci_controller *hose;
+
+ hose = find_hose_by_cfg_addr((void *)(ctrl_addr));
+
+ /* convert ctrl_addr to true physical address */
+ p_ctrl_addr = (phys_addr_t)ctrl_addr - CONFIG_SYS_CCSRBAR;
+ p_ctrl_addr += CONFIG_SYS_CCSRBAR_PHYS;
+
+ off = fdt_node_offset_by_compat_reg(blob, pci_compat, p_ctrl_addr);
+
+ if (off < 0)
+ return;
+
+ /* We assume a cfg_addr not being set means we didn't setup the controller */
+ if ((hose == NULL) || (hose->cfg_addr == NULL)) {
+ fdt_del_node(blob, off);
+ } else {
+ bus_range[0] = 0;
+ bus_range[1] = hose->last_busno - hose->first_busno;
+ fdt_setprop(blob, off, "bus-range", &bus_range[0], 2*4);
+ fdt_pci_dma_ranges(blob, off, hose);
+ }
+}
+#endif
diff --git a/u-boot/drivers/pci/pci.c b/u-boot/drivers/pci/pci.c
new file mode 100644
index 0000000..cdfc4fb
--- /dev/null
+++ b/u-boot/drivers/pci/pci.c
@@ -0,0 +1,733 @@
+/*
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ *
+ * (C) Copyright 2002, 2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * PCI routines
+ */
+
+#include <common.h>
+
+#include <command.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#define PCI_HOSE_OP(rw, size, type) \
+int pci_hose_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, \
+ int offset, type value) \
+{ \
+ return hose->rw##_##size(hose, dev, offset, value); \
+}
+
+PCI_HOSE_OP(read, byte, u8 *)
+PCI_HOSE_OP(read, word, u16 *)
+PCI_HOSE_OP(read, dword, u32 *)
+PCI_HOSE_OP(write, byte, u8)
+PCI_HOSE_OP(write, word, u16)
+PCI_HOSE_OP(write, dword, u32)
+
+#ifndef CONFIG_IXP425
+#define PCI_OP(rw, size, type, error_code) \
+int pci_##rw##_config_##size(pci_dev_t dev, int offset, type value) \
+{ \
+ struct pci_controller *hose = pci_bus_to_hose(PCI_BUS(dev)); \
+ \
+ if (!hose) \
+ { \
+ error_code; \
+ return -1; \
+ } \
+ \
+ return pci_hose_##rw##_config_##size(hose, dev, offset, value); \
+}
+
+PCI_OP(read, byte, u8 *, *value = 0xff)
+PCI_OP(read, word, u16 *, *value = 0xffff)
+PCI_OP(read, dword, u32 *, *value = 0xffffffff)
+PCI_OP(write, byte, u8, )
+PCI_OP(write, word, u16, )
+PCI_OP(write, dword, u32, )
+#endif /* CONFIG_IXP425 */
+
+#define PCI_READ_VIA_DWORD_OP(size, type, off_mask) \
+int pci_hose_read_config_##size##_via_dword(struct pci_controller *hose,\
+ pci_dev_t dev, \
+ int offset, type val) \
+{ \
+ u32 val32; \
+ \
+ if (pci_hose_read_config_dword(hose, dev, offset & 0xfc, &val32) < 0) { \
+ *val = -1; \
+ return -1; \
+ } \
+ \
+ *val = (val32 >> ((offset & (int)off_mask) * 8)); \
+ \
+ return 0; \
+}
+
+#define PCI_WRITE_VIA_DWORD_OP(size, type, off_mask, val_mask) \
+int pci_hose_write_config_##size##_via_dword(struct pci_controller *hose,\
+ pci_dev_t dev, \
+ int offset, type val) \
+{ \
+ u32 val32, mask, ldata, shift; \
+ \
+ if (pci_hose_read_config_dword(hose, dev, offset & 0xfc, &val32) < 0)\
+ return -1; \
+ \
+ shift = ((offset & (int)off_mask) * 8); \
+ ldata = (((unsigned long)val) & val_mask) << shift; \
+ mask = val_mask << shift; \
+ val32 = (val32 & ~mask) | ldata; \
+ \
+ if (pci_hose_write_config_dword(hose, dev, offset & 0xfc, val32) < 0)\
+ return -1; \
+ \
+ return 0; \
+}
+
+PCI_READ_VIA_DWORD_OP(byte, u8 *, 0x03)
+PCI_READ_VIA_DWORD_OP(word, u16 *, 0x02)
+PCI_WRITE_VIA_DWORD_OP(byte, u8, 0x03, 0x000000ff)
+PCI_WRITE_VIA_DWORD_OP(word, u16, 0x02, 0x0000ffff)
+
+/* Get a virtual address associated with a BAR region */
+void *pci_map_bar(pci_dev_t pdev, int bar, int flags)
+{
+ pci_addr_t pci_bus_addr;
+ u32 bar_response;
+
+ /* read BAR address */
+ pci_read_config_dword(pdev, bar, &bar_response);
+ pci_bus_addr = (pci_addr_t)(bar_response & ~0xf);
+
+ /*
+ * Pass "0" as the length argument to pci_bus_to_virt. The arg
+ * isn't actualy used on any platform because u-boot assumes a static
+ * linear mapping. In the future, this could read the BAR size
+ * and pass that as the size if needed.
+ */
+ return pci_bus_to_virt(pdev, pci_bus_addr, flags, 0, MAP_NOCACHE);
+}
+
+/*
+ *
+ */
+
+static struct pci_controller* hose_head;
+
+void pci_register_hose(struct pci_controller* hose)
+{
+ struct pci_controller **phose = &hose_head;
+
+ while(*phose)
+ phose = &(*phose)->next;
+
+ hose->next = NULL;
+
+ *phose = hose;
+}
+
+struct pci_controller *pci_bus_to_hose (int bus)
+{
+ struct pci_controller *hose;
+
+ for (hose = hose_head; hose; hose = hose->next)
+ if (bus >= hose->first_busno && bus <= hose->last_busno)
+ return hose;
+
+ printf("pci_bus_to_hose() failed\n");
+ return NULL;
+}
+
+struct pci_controller *find_hose_by_cfg_addr(void *cfg_addr)
+{
+ struct pci_controller *hose;
+
+ for (hose = hose_head; hose; hose = hose->next) {
+ if (hose->cfg_addr == cfg_addr)
+ return hose;
+ }
+
+ return NULL;
+}
+
+int pci_last_busno(void)
+{
+ struct pci_controller *hose = hose_head;
+
+ if (!hose)
+ return -1;
+
+ while (hose->next)
+ hose = hose->next;
+
+ return hose->last_busno;
+}
+
+#ifndef CONFIG_IXP425
+pci_dev_t pci_find_devices(struct pci_device_id *ids, int index)
+{
+ struct pci_controller * hose;
+ u16 vendor, device;
+ u8 header_type;
+ pci_dev_t bdf;
+ int i, bus, found_multi = 0;
+
+ for (hose = hose_head; hose; hose = hose->next)
+ {
+#ifdef CONFIG_SYS_SCSI_SCAN_BUS_REVERSE
+ for (bus = hose->last_busno; bus >= hose->first_busno; bus--)
+#else
+ for (bus = hose->first_busno; bus <= hose->last_busno; bus++)
+#endif
+ for (bdf = PCI_BDF(bus,0,0);
+#if defined(CONFIG_ELPPC) || defined(CONFIG_PPMC7XX)
+ bdf < PCI_BDF(bus,PCI_MAX_PCI_DEVICES-1,PCI_MAX_PCI_FUNCTIONS-1);
+#else
+ bdf < PCI_BDF(bus+1,0,0);
+#endif
+ bdf += PCI_BDF(0,0,1))
+ {
+ if (!PCI_FUNC(bdf)) {
+ pci_read_config_byte(bdf,
+ PCI_HEADER_TYPE,
+ &header_type);
+
+ found_multi = header_type & 0x80;
+ } else {
+ if (!found_multi)
+ continue;
+ }
+
+ pci_read_config_word(bdf,
+ PCI_VENDOR_ID,
+ &vendor);
+ pci_read_config_word(bdf,
+ PCI_DEVICE_ID,
+ &device);
+
+ for (i=0; ids[i].vendor != 0; i++)
+ if (vendor == ids[i].vendor &&
+ device == ids[i].device)
+ {
+ if (index <= 0)
+ return bdf;
+
+ index--;
+ }
+ }
+ }
+
+ return (-1);
+}
+#endif /* CONFIG_IXP425 */
+
+pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index)
+{
+ static struct pci_device_id ids[2] = {{}, {0, 0}};
+
+ ids[0].vendor = vendor;
+ ids[0].device = device;
+
+ return pci_find_devices(ids, index);
+}
+
+/*
+ *
+ */
+
+int __pci_hose_phys_to_bus (struct pci_controller *hose,
+ phys_addr_t phys_addr,
+ unsigned long flags,
+ unsigned long skip_mask,
+ pci_addr_t *ba)
+{
+ struct pci_region *res;
+ pci_addr_t bus_addr;
+ int i;
+
+ for (i = 0; i < hose->region_count; i++) {
+ res = &hose->regions[i];
+
+ if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
+ continue;
+
+ if (res->flags & skip_mask)
+ continue;
+
+ bus_addr = phys_addr - res->phys_start + res->bus_start;
+
+ if (bus_addr >= res->bus_start &&
+ bus_addr < res->bus_start + res->size) {
+ *ba = bus_addr;
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+pci_addr_t pci_hose_phys_to_bus (struct pci_controller *hose,
+ phys_addr_t phys_addr,
+ unsigned long flags)
+{
+ pci_addr_t bus_addr = 0;
+ int ret;
+
+ if (!hose) {
+ puts ("pci_hose_phys_to_bus: invalid hose\n");
+ return bus_addr;
+ }
+
+ /* if PCI_REGION_MEM is set we do a two pass search with preference
+ * on matches that don't have PCI_REGION_SYS_MEMORY set */
+ if ((flags & PCI_REGION_MEM) == PCI_REGION_MEM) {
+ ret = __pci_hose_phys_to_bus(hose, phys_addr,
+ flags, PCI_REGION_SYS_MEMORY, &bus_addr);
+ if (!ret)
+ return bus_addr;
+ }
+
+ ret = __pci_hose_phys_to_bus(hose, phys_addr, flags, 0, &bus_addr);
+
+ if (ret)
+ puts ("pci_hose_phys_to_bus: invalid physical address\n");
+
+ return bus_addr;
+}
+
+int __pci_hose_bus_to_phys (struct pci_controller *hose,
+ pci_addr_t bus_addr,
+ unsigned long flags,
+ unsigned long skip_mask,
+ phys_addr_t *pa)
+{
+ struct pci_region *res;
+ int i;
+
+ for (i = 0; i < hose->region_count; i++) {
+ res = &hose->regions[i];
+
+ if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
+ continue;
+
+ if (res->flags & skip_mask)
+ continue;
+
+ if (bus_addr >= res->bus_start &&
+ bus_addr < res->bus_start + res->size) {
+ *pa = (bus_addr - res->bus_start + res->phys_start);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+phys_addr_t pci_hose_bus_to_phys(struct pci_controller* hose,
+ pci_addr_t bus_addr,
+ unsigned long flags)
+{
+ phys_addr_t phys_addr = 0;
+ int ret;
+
+ if (!hose) {
+ puts ("pci_hose_bus_to_phys: invalid hose\n");
+ return phys_addr;
+ }
+
+ /* if PCI_REGION_MEM is set we do a two pass search with preference
+ * on matches that don't have PCI_REGION_SYS_MEMORY set */
+ if ((flags & PCI_REGION_MEM) == PCI_REGION_MEM) {
+ ret = __pci_hose_bus_to_phys(hose, bus_addr,
+ flags, PCI_REGION_SYS_MEMORY, &phys_addr);
+ if (!ret)
+ return phys_addr;
+ }
+
+ ret = __pci_hose_bus_to_phys(hose, bus_addr, flags, 0, &phys_addr);
+
+ if (ret)
+ puts ("pci_hose_bus_to_phys: invalid physical address\n");
+
+ return phys_addr;
+}
+
+/*
+ *
+ */
+
+int pci_hose_config_device(struct pci_controller *hose,
+ pci_dev_t dev,
+ unsigned long io,
+ pci_addr_t mem,
+ unsigned long command)
+{
+ unsigned int bar_response, old_command;
+ pci_addr_t bar_value;
+ pci_size_t bar_size;
+ unsigned char pin;
+ int bar, found_mem64;
+
+ debug ("PCI Config: I/O=0x%lx, Memory=0x%llx, Command=0x%lx\n",
+ io, (u64)mem, command);
+
+ pci_hose_write_config_dword (hose, dev, PCI_COMMAND, 0);
+
+ for (bar = PCI_BASE_ADDRESS_0; bar <= PCI_BASE_ADDRESS_5; bar += 4) {
+ pci_hose_write_config_dword (hose, dev, bar, 0xffffffff);
+ pci_hose_read_config_dword (hose, dev, bar, &bar_response);
+
+ if (!bar_response)
+ continue;
+
+ found_mem64 = 0;
+
+ /* Check the BAR type and set our address mask */
+ if (bar_response & PCI_BASE_ADDRESS_SPACE) {
+ bar_size = ~(bar_response & PCI_BASE_ADDRESS_IO_MASK) + 1;
+ /* round up region base address to a multiple of size */
+ io = ((io - 1) | (bar_size - 1)) + 1;
+ bar_value = io;
+ /* compute new region base address */
+ io = io + bar_size;
+ } else {
+ if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+ PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ u32 bar_response_upper;
+ u64 bar64;
+ pci_hose_write_config_dword(hose, dev, bar+4, 0xffffffff);
+ pci_hose_read_config_dword(hose, dev, bar+4, &bar_response_upper);
+
+ bar64 = ((u64)bar_response_upper << 32) | bar_response;
+
+ bar_size = ~(bar64 & PCI_BASE_ADDRESS_MEM_MASK) + 1;
+ found_mem64 = 1;
+ } else {
+ bar_size = (u32)(~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1);
+ }
+
+ /* round up region base address to multiple of size */
+ mem = ((mem - 1) | (bar_size - 1)) + 1;
+ bar_value = mem;
+ /* compute new region base address */
+ mem = mem + bar_size;
+ }
+
+ /* Write it out and update our limit */
+ pci_hose_write_config_dword (hose, dev, bar, (u32)bar_value);
+
+ if (found_mem64) {
+ bar += 4;
+#ifdef CONFIG_SYS_PCI_64BIT
+ pci_hose_write_config_dword(hose, dev, bar, (u32)(bar_value>>32));
+#else
+ pci_hose_write_config_dword (hose, dev, bar, 0x00000000);
+#endif
+ }
+ }
+
+ /* Configure Cache Line Size Register */
+ pci_hose_write_config_byte (hose, dev, PCI_CACHE_LINE_SIZE, 0x08);
+
+ /* Configure Latency Timer */
+ pci_hose_write_config_byte (hose, dev, PCI_LATENCY_TIMER, 0x80);
+
+ /* Disable interrupt line, if device says it wants to use interrupts */
+ pci_hose_read_config_byte (hose, dev, PCI_INTERRUPT_PIN, &pin);
+ if (pin != 0) {
+ pci_hose_write_config_byte (hose, dev, PCI_INTERRUPT_LINE, 0xff);
+ }
+
+ pci_hose_read_config_dword (hose, dev, PCI_COMMAND, &old_command);
+ pci_hose_write_config_dword (hose, dev, PCI_COMMAND,
+ (old_command & 0xffff0000) | command);
+
+ return 0;
+}
+
+/*
+ *
+ */
+
+struct pci_config_table *pci_find_config(struct pci_controller *hose,
+ unsigned short class,
+ unsigned int vendor,
+ unsigned int device,
+ unsigned int bus,
+ unsigned int dev,
+ unsigned int func)
+{
+ struct pci_config_table *table;
+
+ for (table = hose->config_table; table && table->vendor; table++) {
+ if ((table->vendor == PCI_ANY_ID || table->vendor == vendor) &&
+ (table->device == PCI_ANY_ID || table->device == device) &&
+ (table->class == PCI_ANY_ID || table->class == class) &&
+ (table->bus == PCI_ANY_ID || table->bus == bus) &&
+ (table->dev == PCI_ANY_ID || table->dev == dev) &&
+ (table->func == PCI_ANY_ID || table->func == func)) {
+ return table;
+ }
+ }
+
+ return NULL;
+}
+
+void pci_cfgfunc_config_device(struct pci_controller *hose,
+ pci_dev_t dev,
+ struct pci_config_table *entry)
+{
+ pci_hose_config_device(hose, dev, entry->priv[0], entry->priv[1], entry->priv[2]);
+}
+
+void pci_cfgfunc_do_nothing(struct pci_controller *hose,
+ pci_dev_t dev, struct pci_config_table *entry)
+{
+}
+
+/*
+ *
+ */
+
+/* HJF: Changed this to return int. I think this is required
+ * to get the correct result when scanning bridges
+ */
+extern int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev);
+extern void pciauto_config_init(struct pci_controller *hose);
+
+#if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI_SCAN_SHOW)
+const char * pci_class_str(u8 class)
+{
+ switch (class) {
+ case PCI_CLASS_NOT_DEFINED:
+ return "Build before PCI Rev2.0";
+ break;
+ case PCI_BASE_CLASS_STORAGE:
+ return "Mass storage controller";
+ break;
+ case PCI_BASE_CLASS_NETWORK:
+ return "Network controller";
+ break;
+ case PCI_BASE_CLASS_DISPLAY:
+ return "Display controller";
+ break;
+ case PCI_BASE_CLASS_MULTIMEDIA:
+ return "Multimedia device";
+ break;
+ case PCI_BASE_CLASS_MEMORY:
+ return "Memory controller";
+ break;
+ case PCI_BASE_CLASS_BRIDGE:
+ return "Bridge device";
+ break;
+ case PCI_BASE_CLASS_COMMUNICATION:
+ return "Simple comm. controller";
+ break;
+ case PCI_BASE_CLASS_SYSTEM:
+ return "Base system peripheral";
+ break;
+ case PCI_BASE_CLASS_INPUT:
+ return "Input device";
+ break;
+ case PCI_BASE_CLASS_DOCKING:
+ return "Docking station";
+ break;
+ case PCI_BASE_CLASS_PROCESSOR:
+ return "Processor";
+ break;
+ case PCI_BASE_CLASS_SERIAL:
+ return "Serial bus controller";
+ break;
+ case PCI_BASE_CLASS_INTELLIGENT:
+ return "Intelligent controller";
+ break;
+ case PCI_BASE_CLASS_SATELLITE:
+ return "Satellite controller";
+ break;
+ case PCI_BASE_CLASS_CRYPT:
+ return "Cryptographic device";
+ break;
+ case PCI_BASE_CLASS_SIGNAL_PROCESSING:
+ return "DSP";
+ break;
+ case PCI_CLASS_OTHERS:
+ return "Does not fit any class";
+ break;
+ default:
+ return "???";
+ break;
+ };
+}
+#endif /* CONFIG_CMD_PCI || CONFIG_PCI_SCAN_SHOW */
+
+int __pci_skip_dev(struct pci_controller *hose, pci_dev_t dev)
+{
+ /*
+ * Check if pci device should be skipped in configuration
+ */
+ if (dev == PCI_BDF(hose->first_busno, 0, 0)) {
+#if defined(CONFIG_PCI_CONFIG_HOST_BRIDGE) /* don't skip host bridge */
+ /*
+ * Only skip configuration if "pciconfighost" is not set
+ */
+ if (getenv("pciconfighost") == NULL)
+ return 1;
+#else
+ return 1;
+#endif
+ }
+
+ return 0;
+}
+int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev)
+ __attribute__((weak, alias("__pci_skip_dev")));
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+int __pci_print_dev(struct pci_controller *hose, pci_dev_t dev)
+{
+ if (dev == PCI_BDF(hose->first_busno, 0, 0))
+ return 0;
+
+ return 1;
+}
+int pci_print_dev(struct pci_controller *hose, pci_dev_t dev)
+ __attribute__((weak, alias("__pci_print_dev")));
+#endif /* CONFIG_PCI_SCAN_SHOW */
+
+int pci_hose_scan_bus(struct pci_controller *hose, int bus)
+{
+ unsigned int sub_bus, found_multi=0;
+ unsigned short vendor, device, class;
+ unsigned char header_type;
+ struct pci_config_table *cfg;
+ pci_dev_t dev;
+#ifdef CONFIG_PCI_SCAN_SHOW
+ static int indent = 0;
+#endif
+
+ sub_bus = bus;
+
+ for (dev = PCI_BDF(bus,0,0);
+ dev < PCI_BDF(bus,PCI_MAX_PCI_DEVICES-1,PCI_MAX_PCI_FUNCTIONS-1);
+ dev += PCI_BDF(0,0,1)) {
+
+ if (pci_skip_dev(hose, dev))
+ continue;
+
+ if (PCI_FUNC(dev) && !found_multi)
+ continue;
+
+ pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &header_type);
+
+ pci_hose_read_config_word(hose, dev, PCI_VENDOR_ID, &vendor);
+
+ if (vendor == 0xffff || vendor == 0x0000)
+ continue;
+
+ if (!PCI_FUNC(dev))
+ found_multi = header_type & 0x80;
+
+ debug ("PCI Scan: Found Bus %d, Device %d, Function %d\n",
+ PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev) );
+
+ pci_hose_read_config_word(hose, dev, PCI_DEVICE_ID, &device);
+ pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class);
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+ indent++;
+
+ /* Print leading space, including bus indentation */
+ printf("%*c", indent + 1, ' ');
+
+ if (pci_print_dev(hose, dev)) {
+ printf("%02x:%02x.%-*x - %04x:%04x - %s\n",
+ PCI_BUS(dev), PCI_DEV(dev), 6 - indent, PCI_FUNC(dev),
+ vendor, device, pci_class_str(class >> 8));
+ }
+#endif
+
+ cfg = pci_find_config(hose, class, vendor, device,
+ PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev));
+ if (cfg) {
+ cfg->config_device(hose, dev, cfg);
+ sub_bus = max(sub_bus, hose->current_busno);
+#ifdef CONFIG_PCI_PNP
+ } else {
+ int n = pciauto_config_device(hose, dev);
+
+ sub_bus = max(sub_bus, n);
+#endif
+ }
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+ indent--;
+#endif
+
+ if (hose->fixup_irq)
+ hose->fixup_irq(hose, dev);
+ }
+
+ return sub_bus;
+}
+
+int pci_hose_scan(struct pci_controller *hose)
+{
+ /* Start scan at current_busno.
+ * PCIe will start scan at first_busno+1.
+ */
+ /* For legacy support, ensure current>=first */
+ if (hose->first_busno > hose->current_busno)
+ hose->current_busno = hose->first_busno;
+#ifdef CONFIG_PCI_PNP
+ pciauto_config_init(hose);
+#endif
+ return pci_hose_scan_bus(hose, hose->current_busno);
+}
+
+void pci_init(void)
+{
+#if defined(CONFIG_PCI_BOOTDELAY)
+ char *s;
+ int i;
+
+ /* wait "pcidelay" ms (if defined)... */
+ s = getenv ("pcidelay");
+ if (s) {
+ int val = simple_strtoul (s, NULL, 10);
+ for (i=0; i<val; i++)
+ udelay (1000);
+ }
+#endif /* CONFIG_PCI_BOOTDELAY */
+
+ hose_head = NULL;
+
+ /* now call board specific pci_init()... */
+ pci_init_board();
+}
diff --git a/u-boot/drivers/pci/pci_auto.c b/u-boot/drivers/pci/pci_auto.c
new file mode 100644
index 0000000..87ee2c2
--- /dev/null
+++ b/u-boot/drivers/pci/pci_auto.c
@@ -0,0 +1,424 @@
+/*
+ * arch/powerpc/kernel/pci_auto.c
+ *
+ * PCI autoconfiguration library
+ *
+ * Author: Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <common.h>
+
+#include <pci.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define DEBUGF(x...) printf(x)
+#else
+#define DEBUGF(x...)
+#endif /* DEBUG */
+
+#define PCIAUTO_IDE_MODE_MASK 0x05
+
+/* the user can define CONFIG_SYS_PCI_CACHE_LINE_SIZE to avoid problems */
+#ifndef CONFIG_SYS_PCI_CACHE_LINE_SIZE
+#define CONFIG_SYS_PCI_CACHE_LINE_SIZE 8
+#endif
+
+/*
+ *
+ */
+
+void pciauto_region_init(struct pci_region* res)
+{
+ /*
+ * Avoid allocating PCI resources from address 0 -- this is illegal
+ * according to PCI 2.1 and moreover, this is known to cause Linux IDE
+ * drivers to fail. Use a reasonable starting value of 0x1000 instead.
+ */
+ res->bus_lower = res->bus_start ? res->bus_start : 0x1000;
+}
+
+void pciauto_region_align(struct pci_region *res, pci_size_t size)
+{
+ res->bus_lower = ((res->bus_lower - 1) | (size - 1)) + 1;
+}
+
+int pciauto_region_allocate(struct pci_region* res, pci_size_t size, pci_addr_t *bar)
+{
+ pci_addr_t addr;
+
+ if (!res) {
+ DEBUGF("No resource");
+ goto error;
+ }
+
+ addr = ((res->bus_lower - 1) | (size - 1)) + 1;
+
+ if (addr - res->bus_start + size > res->size) {
+ DEBUGF("No room in resource");
+ goto error;
+ }
+
+ res->bus_lower = addr + size;
+
+ DEBUGF("address=0x%llx bus_lower=0x%llx", (u64)addr, (u64)res->bus_lower);
+
+ *bar = addr;
+ return 0;
+
+ error:
+ *bar = (pci_addr_t)-1;
+ return -1;
+}
+
+/*
+ *
+ */
+
+void pciauto_setup_device(struct pci_controller *hose,
+ pci_dev_t dev, int bars_num,
+ struct pci_region *mem,
+ struct pci_region *prefetch,
+ struct pci_region *io)
+{
+ unsigned int bar_response;
+ pci_addr_t bar_value;
+ pci_size_t bar_size;
+ unsigned int cmdstat = 0;
+ struct pci_region *bar_res;
+ int bar, bar_nr = 0;
+ int found_mem64 = 0;
+
+ pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &cmdstat);
+ cmdstat = (cmdstat & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) | PCI_COMMAND_MASTER;
+
+ for (bar = PCI_BASE_ADDRESS_0; bar < PCI_BASE_ADDRESS_0 + (bars_num*4); bar += 4) {
+ /* Tickle the BAR and get the response */
+ pci_hose_write_config_dword(hose, dev, bar, 0xffffffff);
+ pci_hose_read_config_dword(hose, dev, bar, &bar_response);
+
+ /* If BAR is not implemented go to the next BAR */
+ if (!bar_response)
+ continue;
+
+ found_mem64 = 0;
+
+ /* Check the BAR type and set our address mask */
+ if (bar_response & PCI_BASE_ADDRESS_SPACE) {
+ bar_size = ((~(bar_response & PCI_BASE_ADDRESS_IO_MASK))
+ & 0xffff) + 1;
+ bar_res = io;
+
+ DEBUGF("PCI Autoconfig: BAR %d, I/O, size=0x%llx, ", bar_nr, (u64)bar_size);
+ } else {
+ if ( (bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+ PCI_BASE_ADDRESS_MEM_TYPE_64) {
+ u32 bar_response_upper;
+ u64 bar64;
+ pci_hose_write_config_dword(hose, dev, bar+4, 0xffffffff);
+ pci_hose_read_config_dword(hose, dev, bar+4, &bar_response_upper);
+
+ bar64 = ((u64)bar_response_upper << 32) | bar_response;
+
+ bar_size = ~(bar64 & PCI_BASE_ADDRESS_MEM_MASK) + 1;
+ found_mem64 = 1;
+ } else {
+ bar_size = (u32)(~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1);
+ }
+ if (prefetch && (bar_response & PCI_BASE_ADDRESS_MEM_PREFETCH))
+ bar_res = prefetch;
+ else
+ bar_res = mem;
+
+ DEBUGF("PCI Autoconfig: BAR %d, Mem, size=0x%llx, ", bar_nr, (u64)bar_size);
+ }
+
+ if (pciauto_region_allocate(bar_res, bar_size, &bar_value) == 0) {
+ /* Write it out and update our limit */
+ pci_hose_write_config_dword(hose, dev, bar, (u32)bar_value);
+
+ if (found_mem64) {
+ bar += 4;
+#ifdef CONFIG_SYS_PCI_64BIT
+ pci_hose_write_config_dword(hose, dev, bar, (u32)(bar_value>>32));
+#else
+ /*
+ * If we are a 64-bit decoder then increment to the
+ * upper 32 bits of the bar and force it to locate
+ * in the lower 4GB of memory.
+ */
+ pci_hose_write_config_dword(hose, dev, bar, 0x00000000);
+#endif
+ }
+
+ cmdstat |= (bar_response & PCI_BASE_ADDRESS_SPACE) ?
+ PCI_COMMAND_IO : PCI_COMMAND_MEMORY;
+ }
+
+ DEBUGF("\n");
+
+ bar_nr++;
+ }
+
+ pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat);
+ pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE,
+ CONFIG_SYS_PCI_CACHE_LINE_SIZE);
+ pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80);
+}
+
+void pciauto_prescan_setup_bridge(struct pci_controller *hose,
+ pci_dev_t dev, int sub_bus)
+{
+ struct pci_region *pci_mem = hose->pci_mem;
+ struct pci_region *pci_prefetch = hose->pci_prefetch;
+ struct pci_region *pci_io = hose->pci_io;
+ unsigned int cmdstat;
+
+ pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &cmdstat);
+
+ /* Configure bus number registers */
+ pci_hose_write_config_byte(hose, dev, PCI_PRIMARY_BUS,
+ PCI_BUS(dev) - hose->first_busno);
+ pci_hose_write_config_byte(hose, dev, PCI_SECONDARY_BUS,
+ sub_bus - hose->first_busno);
+ pci_hose_write_config_byte(hose, dev, PCI_SUBORDINATE_BUS, 0xff);
+
+ if (pci_mem) {
+ /* Round memory allocator to 1MB boundary */
+ pciauto_region_align(pci_mem, 0x100000);
+
+ /* Set up memory and I/O filter limits, assume 32-bit I/O space */
+ pci_hose_write_config_word(hose, dev, PCI_MEMORY_BASE,
+ (pci_mem->bus_lower & 0xfff00000) >> 16);
+
+ cmdstat |= PCI_COMMAND_MEMORY;
+ }
+
+ if (pci_prefetch) {
+ /* Round memory allocator to 1MB boundary */
+ pciauto_region_align(pci_prefetch, 0x100000);
+
+ /* Set up memory and I/O filter limits, assume 32-bit I/O space */
+ pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_BASE,
+ (pci_prefetch->bus_lower & 0xfff00000) >> 16);
+
+ cmdstat |= PCI_COMMAND_MEMORY;
+ } else {
+ /* We don't support prefetchable memory for now, so disable */
+ pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_BASE, 0x1000);
+ pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_LIMIT, 0x0);
+ }
+
+ if (pci_io) {
+ /* Round I/O allocator to 4KB boundary */
+ pciauto_region_align(pci_io, 0x1000);
+
+ pci_hose_write_config_byte(hose, dev, PCI_IO_BASE,
+ (pci_io->bus_lower & 0x0000f000) >> 8);
+ pci_hose_write_config_word(hose, dev, PCI_IO_BASE_UPPER16,
+ (pci_io->bus_lower & 0xffff0000) >> 16);
+
+ cmdstat |= PCI_COMMAND_IO;
+ }
+
+ /* Enable memory and I/O accesses, enable bus master */
+ pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat | PCI_COMMAND_MASTER);
+}
+
+void pciauto_postscan_setup_bridge(struct pci_controller *hose,
+ pci_dev_t dev, int sub_bus)
+{
+ struct pci_region *pci_mem = hose->pci_mem;
+ struct pci_region *pci_prefetch = hose->pci_prefetch;
+ struct pci_region *pci_io = hose->pci_io;
+
+ /* Configure bus number registers */
+ pci_hose_write_config_byte(hose, dev, PCI_SUBORDINATE_BUS,
+ sub_bus - hose->first_busno);
+
+ if (pci_mem) {
+ /* Round memory allocator to 1MB boundary */
+ pciauto_region_align(pci_mem, 0x100000);
+
+ pci_hose_write_config_word(hose, dev, PCI_MEMORY_LIMIT,
+ (pci_mem->bus_lower-1) >> 16);
+ }
+
+ if (pci_prefetch) {
+ /* Round memory allocator to 1MB boundary */
+ pciauto_region_align(pci_prefetch, 0x100000);
+
+ pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_LIMIT,
+ (pci_prefetch->bus_lower-1) >> 16);
+ }
+
+ if (pci_io) {
+ /* Round I/O allocator to 4KB boundary */
+ pciauto_region_align(pci_io, 0x1000);
+
+ pci_hose_write_config_byte(hose, dev, PCI_IO_LIMIT,
+ ((pci_io->bus_lower-1) & 0x0000f000) >> 8);
+ pci_hose_write_config_word(hose, dev, PCI_IO_LIMIT_UPPER16,
+ ((pci_io->bus_lower-1) & 0xffff0000) >> 16);
+ }
+}
+
+/*
+ *
+ */
+
+void pciauto_config_init(struct pci_controller *hose)
+{
+ int i;
+
+ hose->pci_io = hose->pci_mem = NULL;
+
+ for (i=0; i<hose->region_count; i++) {
+ switch(hose->regions[i].flags) {
+ case PCI_REGION_IO:
+ if (!hose->pci_io ||
+ hose->pci_io->size < hose->regions[i].size)
+ hose->pci_io = hose->regions + i;
+ break;
+ case PCI_REGION_MEM:
+ if (!hose->pci_mem ||
+ hose->pci_mem->size < hose->regions[i].size)
+ hose->pci_mem = hose->regions + i;
+ break;
+ case (PCI_REGION_MEM | PCI_REGION_PREFETCH):
+ if (!hose->pci_prefetch ||
+ hose->pci_prefetch->size < hose->regions[i].size)
+ hose->pci_prefetch = hose->regions + i;
+ break;
+ }
+ }
+
+
+ if (hose->pci_mem) {
+ pciauto_region_init(hose->pci_mem);
+
+ DEBUGF("PCI Autoconfig: Bus Memory region: [0x%llx-0x%llx],\n"
+ "\t\tPhysical Memory [%llx-%llxx]\n",
+ (u64)hose->pci_mem->bus_start,
+ (u64)(hose->pci_mem->bus_start + hose->pci_mem->size - 1),
+ (u64)hose->pci_mem->phys_start,
+ (u64)(hose->pci_mem->phys_start + hose->pci_mem->size - 1));
+ }
+
+ if (hose->pci_prefetch) {
+ pciauto_region_init(hose->pci_prefetch);
+
+ DEBUGF("PCI Autoconfig: Bus Prefetchable Mem: [0x%llx-0x%llx],\n"
+ "\t\tPhysical Memory [%llx-%llx]\n",
+ (u64)hose->pci_prefetch->bus_start,
+ (u64)(hose->pci_prefetch->bus_start +
+ hose->pci_prefetch->size - 1),
+ (u64)hose->pci_prefetch->phys_start,
+ (u64)(hose->pci_prefetch->phys_start +
+ hose->pci_prefetch->size - 1));
+ }
+
+ if (hose->pci_io) {
+ pciauto_region_init(hose->pci_io);
+
+ DEBUGF("PCI Autoconfig: Bus I/O region: [0x%llx-0x%llx],\n"
+ "\t\tPhysical Memory: [%llx-%llx]\n",
+ (u64)hose->pci_io->bus_start,
+ (u64)(hose->pci_io->bus_start + hose->pci_io->size - 1),
+ (u64)hose->pci_io->phys_start,
+ (u64)(hose->pci_io->phys_start + hose->pci_io->size - 1));
+
+ }
+}
+
+/* HJF: Changed this to return int. I think this is required
+ * to get the correct result when scanning bridges
+ */
+int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev)
+{
+ unsigned int sub_bus = PCI_BUS(dev);
+ unsigned short class;
+ unsigned char prg_iface;
+ int n;
+
+ pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class);
+
+ switch(class) {
+ case PCI_CLASS_PROCESSOR_POWERPC: /* an agent or end-point */
+ DEBUGF("PCI AutoConfig: Found PowerPC device\n");
+ pciauto_setup_device(hose, dev, 6, hose->pci_mem,
+ hose->pci_prefetch, hose->pci_io);
+ break;
+
+ case PCI_CLASS_BRIDGE_PCI:
+ hose->current_busno++;
+ pciauto_setup_device(hose, dev, 2, hose->pci_mem, hose->pci_prefetch, hose->pci_io);
+
+ DEBUGF("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_DEV(dev));
+
+ /* Passing in current_busno allows for sibling P2P bridges */
+ pciauto_prescan_setup_bridge(hose, dev, hose->current_busno);
+ /*
+ * need to figure out if this is a subordinate bridge on the bus
+ * to be able to properly set the pri/sec/sub bridge registers.
+ */
+ n = pci_hose_scan_bus(hose, hose->current_busno);
+
+ /* figure out the deepest we've gone for this leg */
+ sub_bus = max(n, sub_bus);
+ pciauto_postscan_setup_bridge(hose, dev, sub_bus);
+
+ sub_bus = hose->current_busno;
+ break;
+
+ case PCI_CLASS_STORAGE_IDE:
+ pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &prg_iface);
+ if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) {
+ DEBUGF("PCI Autoconfig: Skipping legacy mode IDE controller\n");
+ return sub_bus;
+ }
+
+ pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_prefetch, hose->pci_io);
+ break;
+
+ case PCI_CLASS_BRIDGE_CARDBUS:
+ /* just do a minimal setup of the bridge, let the OS take care of the rest */
+ pciauto_setup_device(hose, dev, 0, hose->pci_mem, hose->pci_prefetch, hose->pci_io);
+
+ DEBUGF("PCI Autoconfig: Found P2CardBus bridge, device %d\n", PCI_DEV(dev));
+
+ hose->current_busno++;
+ break;
+
+#if defined(CONFIG_PCIAUTO_SKIP_HOST_BRIDGE)
+ case PCI_CLASS_BRIDGE_OTHER:
+ DEBUGF("PCI Autoconfig: Skipping bridge device %d\n",
+ PCI_DEV(dev));
+ break;
+#endif
+#if defined(CONFIG_MPC834x) && !defined(CONFIG_VME8349)
+ case PCI_CLASS_BRIDGE_OTHER:
+ /*
+ * The host/PCI bridge 1 seems broken in 8349 - it presents
+ * itself as 'PCI_CLASS_BRIDGE_OTHER' and appears as an _agent_
+ * device claiming resources io/mem/irq.. we only allow for
+ * the PIMMR window to be allocated (BAR0 - 1MB size)
+ */
+ DEBUGF("PCI Autoconfig: Broken bridge found, only minimal config\n");
+ pciauto_setup_device(hose, dev, 0, hose->pci_mem, hose->pci_prefetch, hose->pci_io);
+ break;
+#endif
+ default:
+ pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_prefetch, hose->pci_io);
+ break;
+ }
+
+ return sub_bus;
+}
diff --git a/u-boot/drivers/pci/pci_indirect.c b/u-boot/drivers/pci/pci_indirect.c
new file mode 100644
index 0000000..2070d01
--- /dev/null
+++ b/u-boot/drivers/pci/pci_indirect.c
@@ -0,0 +1,137 @@
+/*
+ * Support for indirect PCI bridges.
+ *
+ * Copyright (C) 1998 Gabriel Paubert.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <common.h>
+
+#if (!defined(__I386__) && !defined(CONFIG_IXDP425))
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+
+#define cfg_read(val, addr, type, op) *val = op((type)(addr))
+#define cfg_write(val, addr, type, op) op((type *)(addr), (val))
+
+#ifdef CONFIG_IXP425
+extern unsigned char in_8 (volatile unsigned *addr);
+extern unsigned short in_le16 (volatile unsigned *addr);
+extern unsigned in_le32 (volatile unsigned *addr);
+extern void out_8 (volatile unsigned *addr, char val);
+extern void out_le16 (volatile unsigned *addr, unsigned short val);
+extern void out_le32 (volatile unsigned *addr, unsigned int val);
+#endif /* CONFIG_IXP425 */
+
+#if defined(CONFIG_MPC8260)
+#define INDIRECT_PCI_OP(rw, size, type, op, mask) \
+static int \
+indirect_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, int offset, type val) \
+{ \
+ u32 b, d,f; \
+ b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \
+ b = b - hose->first_busno; \
+ dev = PCI_BDF(b, d, f); \
+ out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \
+ sync(); \
+ cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \
+ return 0; \
+}
+#elif defined(CONFIG_E500) || defined(CONFIG_MPC86xx)
+#define INDIRECT_PCI_OP(rw, size, type, op, mask) \
+static int \
+indirect_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, int offset, type val) \
+{ \
+ u32 b, d,f; \
+ b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \
+ b = b - hose->first_busno; \
+ dev = PCI_BDF(b, d, f); \
+ *(hose->cfg_addr) = dev | (offset & 0xfc) | ((offset & 0xf00) << 16) | 0x80000000; \
+ sync(); \
+ cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \
+ return 0; \
+}
+#elif defined(CONFIG_440GX) || defined(CONFIG_440GP) || defined(CONFIG_440SP) || \
+ defined(CONFIG_440SPE) || defined(CONFIG_460EX) || defined(CONFIG_460GT)
+#define INDIRECT_PCI_OP(rw, size, type, op, mask) \
+static int \
+indirect_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, int offset, type val) \
+{ \
+ u32 b, d,f; \
+ b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \
+ b = b - hose->first_busno; \
+ dev = PCI_BDF(b, d, f); \
+ if (PCI_BUS(dev) > 0) \
+ out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000001); \
+ else \
+ out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \
+ cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \
+ return 0; \
+}
+#else
+#define INDIRECT_PCI_OP(rw, size, type, op, mask) \
+static int \
+indirect_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, int offset, type val) \
+{ \
+ u32 b, d,f; \
+ b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \
+ b = b - hose->first_busno; \
+ dev = PCI_BDF(b, d, f); \
+ out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \
+ cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \
+ return 0; \
+}
+#endif
+
+#define INDIRECT_PCI_OP_ERRATA6(rw, size, type, op, mask) \
+static int \
+indirect_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, int offset, type val) \
+{ \
+ unsigned int msr = mfmsr(); \
+ mtmsr(msr & ~(MSR_EE | MSR_CE)); \
+ out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \
+ cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \
+ out_le32(hose->cfg_addr, 0x00000000); \
+ mtmsr(msr); \
+ return 0; \
+}
+
+INDIRECT_PCI_OP(read, byte, u8 *, in_8, 3)
+INDIRECT_PCI_OP(read, word, u16 *, in_le16, 2)
+INDIRECT_PCI_OP(read, dword, u32 *, in_le32, 0)
+#ifdef CONFIG_405GP
+INDIRECT_PCI_OP_ERRATA6(write, byte, u8, out_8, 3)
+INDIRECT_PCI_OP_ERRATA6(write, word, u16, out_le16, 2)
+INDIRECT_PCI_OP_ERRATA6(write, dword, u32, out_le32, 0)
+#else
+INDIRECT_PCI_OP(write, byte, u8, out_8, 3)
+INDIRECT_PCI_OP(write, word, u16, out_le16, 2)
+INDIRECT_PCI_OP(write, dword, u32, out_le32, 0)
+#endif
+
+void pci_setup_indirect(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
+{
+ pci_set_ops(hose,
+ indirect_read_config_byte,
+ indirect_read_config_word,
+ indirect_read_config_dword,
+ indirect_write_config_byte,
+ indirect_write_config_word,
+ indirect_write_config_dword);
+
+ hose->cfg_addr = (unsigned int *) cfg_addr;
+ hose->cfg_data = (unsigned char *) cfg_data;
+}
+
+#endif /* !__I386__ && !CONFIG_IXDP425 */
diff --git a/u-boot/drivers/pci/pci_ixp.c b/u-boot/drivers/pci/pci_ixp.c
new file mode 100644
index 0000000..3b303b4
--- /dev/null
+++ b/u-boot/drivers/pci/pci_ixp.c
@@ -0,0 +1,571 @@
+/*
+ * IXP PCI Init
+ * (C) Copyright 2004 eslab.whut.edu.cn
+ * Yue Hu(huyue_whut@yahoo.com.cn), Ligong Xue(lgxue@hotmail.com)
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+
+#include <common.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <pci.h>
+#include <asm/arch/ixp425.h>
+#include <asm/arch/ixp425pci.h>
+
+static void non_prefetch_read (unsigned int addr, unsigned int cmd,
+ unsigned int *data);
+static void non_prefetch_write (unsigned int addr, unsigned int cmd,
+ unsigned int data);
+static void configure_pins (void);
+static void sys_pci_gpio_clock_config (void);
+static void pci_bus_scan (void);
+static int pci_device_exists (unsigned int deviceNo);
+static void sys_pci_bar_info_get (unsigned int devnum, unsigned int bus,
+ unsigned int dev, unsigned int func);
+static void sys_pci_device_bars_write (void);
+static void calc_bars (PciBar * Bars[], unsigned int nBars,
+ unsigned int startAddr);
+
+#define PCI_MEMORY_BUS 0x00000000
+#define PCI_MEMORY_PHY 0x48000000
+#define PCI_MEMORY_SIZE 0x04000000
+
+#define PCI_MEM_BUS 0x40000000
+#define PCI_MEM_PHY 0x00000000
+#define PCI_MEM_SIZE 0x04000000
+
+#define PCI_IO_BUS 0x40000000
+#define PCI_IO_PHY 0x50000000
+#define PCI_IO_SIZE 0x10000000
+
+struct pci_controller hose;
+
+unsigned int nDevices;
+unsigned int nMBars;
+unsigned int nIOBars;
+PciBar *memBars[IXP425_PCI_MAX_BAR];
+PciBar *ioBars[IXP425_PCI_MAX_BAR];
+PciDevice devices[IXP425_PCI_MAX_FUNC_ON_BUS];
+
+int pci_read_config_dword (pci_dev_t dev, int where, unsigned int *val)
+{
+ unsigned int retval;
+ unsigned int addr;
+
+ /*address bits 31:28 specify the device 10:8 specify the function */
+ /*Set the address to be read */
+ addr = BIT ((31 - dev)) | (where & ~3);
+ non_prefetch_read (addr, NP_CMD_CONFIGREAD, &retval);
+
+ *val = retval;
+
+ return (OK);
+}
+
+int pci_read_config_word (pci_dev_t dev, int where, unsigned short *val)
+{
+ unsigned int n;
+ unsigned int retval;
+ unsigned int addr;
+ unsigned int byteEnables;
+
+ n = where % 4;
+ /*byte enables are 4 bits active low, the position of each
+ bit maps to the byte that it enables */
+ byteEnables =
+ (~(BIT (n) | BIT ((n + 1)))) &
+ IXP425_PCI_BOTTOM_NIBBLE_OF_LONG_MASK;
+ byteEnables = byteEnables << PCI_NP_CBE_BESL;
+ /*address bits 31:28 specify the device 10:8 specify the function */
+ /*Set the address to be read */
+ addr = BIT ((31 - dev)) | (where & ~3);
+ non_prefetch_read (addr, byteEnables | NP_CMD_CONFIGREAD, &retval);
+
+ /*Pick out the word we are interested in */
+ *val = (retval >> (8 * n));
+
+ return (OK);
+}
+
+int pci_read_config_byte (pci_dev_t dev, int where, unsigned char *val)
+{
+ unsigned int retval;
+ unsigned int n;
+ unsigned int byteEnables;
+ unsigned int addr;
+
+ n = where % 4;
+ /*byte enables are 4 bits, active low, the position of each
+ bit maps to the byte that it enables */
+ byteEnables = (~BIT (n)) & IXP425_PCI_BOTTOM_NIBBLE_OF_LONG_MASK;
+ byteEnables = byteEnables << PCI_NP_CBE_BESL;
+
+ /*address bits 31:28 specify the device, 10:8 specify the function */
+ /*Set the address to be read */
+ addr = BIT ((31 - dev)) | (where & ~3);
+ non_prefetch_read (addr, byteEnables | NP_CMD_CONFIGREAD, &retval);
+ /*Pick out the byte we are interested in */
+ *val = (retval >> (8 * n));
+
+ return (OK);
+}
+
+int pci_write_config_byte (pci_dev_t dev, int where, unsigned char val)
+{
+ unsigned int addr;
+ unsigned int byteEnables;
+ unsigned int n;
+ unsigned int ldata;
+
+ n = where % 4;
+ /*byte enables are 4 bits active low, the position of each
+ bit maps to the byte that it enables */
+ byteEnables = (~BIT (n)) & IXP425_PCI_BOTTOM_NIBBLE_OF_LONG_MASK;
+ byteEnables = byteEnables << PCI_NP_CBE_BESL;
+ ldata = val << (8 * n);
+ /*address bits 31:28 specify the device 10:8 specify the function */
+ /*Set the address to be written */
+ addr = BIT ((31 - dev)) | (where & ~3);
+ non_prefetch_write (addr, byteEnables | NP_CMD_CONFIGWRITE, ldata);
+
+ return (OK);
+}
+
+int pci_write_config_word (pci_dev_t dev, int where, unsigned short val)
+{
+ unsigned int addr;
+ unsigned int byteEnables;
+ unsigned int n;
+ unsigned int ldata;
+
+ n = where % 4;
+ /*byte enables are 4 bits active low, the position of each
+ bit maps to the byte that it enables */
+ byteEnables =
+ (~(BIT (n) | BIT ((n + 1)))) &
+ IXP425_PCI_BOTTOM_NIBBLE_OF_LONG_MASK;
+ byteEnables = byteEnables << PCI_NP_CBE_BESL;
+ ldata = val << (8 * n);
+ /*address bits 31:28 specify the device 10:8 specify the function */
+ /*Set the address to be written */
+ addr = BIT (31 - dev) | (where & ~3);
+ non_prefetch_write (addr, byteEnables | NP_CMD_CONFIGWRITE, ldata);
+
+ return (OK);
+}
+
+int pci_write_config_dword (pci_dev_t dev, int where, unsigned int val)
+{
+ unsigned int addr;
+
+ /*address bits 31:28 specify the device 10:8 specify the function */
+ /*Set the address to be written */
+ addr = BIT (31 - dev) | (where & ~3);
+ non_prefetch_write (addr, NP_CMD_CONFIGWRITE, val);
+
+ return (OK);
+}
+
+void non_prefetch_read (unsigned int addr,
+ unsigned int cmd, unsigned int *data)
+{
+ REG_WRITE (PCI_CSR_BASE, PCI_NP_AD_OFFSET, addr);
+
+ /*set up and execute the read */
+ REG_WRITE (PCI_CSR_BASE, PCI_NP_CBE_OFFSET, cmd);
+
+ /*The result of the read is now in np_rdata */
+ REG_READ (PCI_CSR_BASE, PCI_NP_RDATA_OFFSET, *data);
+
+ return;
+}
+
+void non_prefetch_write (unsigned int addr,
+ unsigned int cmd, unsigned int data)
+{
+
+ REG_WRITE (PCI_CSR_BASE, PCI_NP_AD_OFFSET, addr);
+ /*set up the write */
+ REG_WRITE (PCI_CSR_BASE, PCI_NP_CBE_OFFSET, cmd);
+ /*Execute the write by writing to NP_WDATA */
+ REG_WRITE (PCI_CSR_BASE, PCI_NP_WDATA_OFFSET, data);
+
+ return;
+}
+
+/*
+ * PCI controller config registers are accessed through these functions
+ * i.e. these allow us to set up our own BARs etc.
+ */
+void crp_read (unsigned int offset, unsigned int *data)
+{
+ REG_WRITE (PCI_CSR_BASE, PCI_CRP_AD_CBE_OFFSET, offset);
+ REG_READ (PCI_CSR_BASE, PCI_CRP_RDATA_OFFSET, *data);
+}
+
+void crp_write (unsigned int offset, unsigned int data)
+{
+ /*The CRP address register bit 16 indicates that we want to do a write */
+ REG_WRITE (PCI_CSR_BASE, PCI_CRP_AD_CBE_OFFSET,
+ PCI_CRP_WRITE | offset);
+ REG_WRITE (PCI_CSR_BASE, PCI_CRP_WDATA_OFFSET, data);
+}
+
+/*struct pci_controller *hose*/
+void pci_ixp_init (struct pci_controller *hose)
+{
+ unsigned int regval;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0x00;
+
+ /* System memory space */
+ pci_set_region (hose->regions + 0,
+ PCI_MEMORY_BUS,
+ PCI_MEMORY_PHY, PCI_MEMORY_SIZE, PCI_REGION_SYS_MEMORY);
+
+ /* PCI memory space */
+ pci_set_region (hose->regions + 1,
+ PCI_MEM_BUS,
+ PCI_MEM_PHY, PCI_MEM_SIZE, PCI_REGION_MEM);
+ /* PCI I/O space */
+ pci_set_region (hose->regions + 2,
+ PCI_IO_BUS, PCI_IO_PHY, PCI_IO_SIZE, PCI_REGION_IO);
+
+ hose->region_count = 3;
+
+ pci_register_hose (hose);
+
+/*
+ ==========================================================
+ Init IXP PCI
+ ==========================================================
+*/
+ REG_READ (PCI_CSR_BASE, PCI_CSR_OFFSET, regval);
+ regval |= 1 << 2;
+ REG_WRITE (PCI_CSR_BASE, PCI_CSR_OFFSET, regval);
+
+ configure_pins ();
+
+ READ_GPIO_REG (IXP425_GPIO_GPOUTR, regval);
+ WRITE_GPIO_REG (IXP425_GPIO_GPOUTR, regval & (~(1 << 13)));
+ udelay (533);
+ sys_pci_gpio_clock_config ();
+ REG_WRITE (PCI_CSR_BASE, PCI_INTEN_OFFSET, 0);
+ udelay (100);
+ READ_GPIO_REG (IXP425_GPIO_GPOUTR, regval);
+ WRITE_GPIO_REG (IXP425_GPIO_GPOUTR, regval | (1 << 13));
+ udelay (533);
+ crp_write (PCI_CFG_BASE_ADDRESS_0, IXP425_PCI_BAR_0_DEFAULT);
+ crp_write (PCI_CFG_BASE_ADDRESS_1, IXP425_PCI_BAR_1_DEFAULT);
+ crp_write (PCI_CFG_BASE_ADDRESS_2, IXP425_PCI_BAR_2_DEFAULT);
+ crp_write (PCI_CFG_BASE_ADDRESS_3, IXP425_PCI_BAR_3_DEFAULT);
+ crp_write (PCI_CFG_BASE_ADDRESS_4, IXP425_PCI_BAR_4_DEFAULT);
+ crp_write (PCI_CFG_BASE_ADDRESS_5, IXP425_PCI_BAR_5_DEFAULT);
+ /*Setup PCI-AHB and AHB-PCI address mappings */
+ REG_WRITE (PCI_CSR_BASE, PCI_AHBMEMBASE_OFFSET,
+ IXP425_PCI_AHBMEMBASE_DEFAULT);
+
+ REG_WRITE (PCI_CSR_BASE, PCI_AHBIOBASE_OFFSET,
+ IXP425_PCI_AHBIOBASE_DEFAULT);
+
+ REG_WRITE (PCI_CSR_BASE, PCI_PCIMEMBASE_OFFSET,
+ IXP425_PCI_PCIMEMBASE_DEFAULT);
+
+ crp_write (PCI_CFG_SUB_VENDOR_ID, IXP425_PCI_SUB_VENDOR_SYSTEM);
+
+ REG_READ (PCI_CSR_BASE, PCI_CSR_OFFSET, regval);
+ regval |= PCI_CSR_IC | PCI_CSR_ABE | PCI_CSR_PDS;
+ REG_WRITE (PCI_CSR_BASE, PCI_CSR_OFFSET, regval);
+ crp_write (PCI_CFG_COMMAND, PCI_CFG_CMD_MAE | PCI_CFG_CMD_BME);
+ udelay (1000);
+
+ pci_write_config_word (0, PCI_CFG_COMMAND, INITIAL_PCI_CMD);
+ REG_WRITE (PCI_CSR_BASE, PCI_ISR_OFFSET, PCI_ISR_PSE
+ | PCI_ISR_PFE | PCI_ISR_PPE | PCI_ISR_AHBE);
+#ifdef CONFIG_PCI_SCAN_SHOW
+ printf ("Device bus dev func deviceID vendorID \n");
+#endif
+ pci_bus_scan ();
+}
+
+void configure_pins (void)
+{
+ unsigned int regval;
+
+ /* Disable clock on GPIO PIN 14 */
+ READ_GPIO_REG (IXP425_GPIO_GPCLKR, regval);
+ WRITE_GPIO_REG (IXP425_GPIO_GPCLKR, regval & (~(1 << 8)));
+ READ_GPIO_REG (IXP425_GPIO_GPCLKR, regval);
+
+ READ_GPIO_REG (IXP425_GPIO_GPOER, regval);
+ WRITE_GPIO_REG (IXP425_GPIO_GPOER,
+ (((~(3 << 13)) & regval) | (0xf << 8)));
+ READ_GPIO_REG (IXP425_GPIO_GPOER, regval);
+
+ READ_GPIO_REG (IXP425_GPIO_GPIT2R, regval);
+ WRITE_GPIO_REG (IXP425_GPIO_GPIT2R,
+ (regval &
+ ((0x1 << 9) | (0x1 << 6) | (0x1 << 3) | 0x1)));
+ READ_GPIO_REG (IXP425_GPIO_GPIT2R, regval);
+
+ READ_GPIO_REG (IXP425_GPIO_GPISR, regval);
+ WRITE_GPIO_REG (IXP425_GPIO_GPISR, (regval | (0xf << 8)));
+ READ_GPIO_REG (IXP425_GPIO_GPISR, regval);
+}
+
+void sys_pci_gpio_clock_config (void)
+{
+ unsigned int regval;
+
+ READ_GPIO_REG (IXP425_GPIO_GPCLKR, regval);
+ regval |= 0x1 << 4;
+ WRITE_GPIO_REG (IXP425_GPIO_GPCLKR, regval);
+ READ_GPIO_REG (IXP425_GPIO_GPCLKR, regval);
+ regval |= 0x1 << 8;
+ WRITE_GPIO_REG (IXP425_GPIO_GPCLKR, regval);
+}
+
+void pci_bus_scan (void)
+{
+ unsigned int bus = 0, dev, func = 0;
+ unsigned short data16;
+ unsigned int data32;
+ unsigned char intPin;
+
+ /* Assign first device to ourselves */
+ devices[0].bus = 0;
+ devices[0].device = 0;
+ devices[0].func = 0;
+
+ crp_read (PCI_CFG_VENDOR_ID, &data32);
+
+ devices[0].vendor_id = data32 & IXP425_PCI_BOTTOM_WORD_OF_LONG_MASK;
+ devices[0].device_id = data32 >> 16;
+ devices[0].error = FALSE;
+ devices[0].bar[NO_BAR].size = 0; /*dummy - required */
+
+ nDevices = 1;
+
+ nMBars = 0;
+ nIOBars = 0;
+
+ for (dev = 0; dev < IXP425_PCI_MAX_DEV; dev++) {
+
+ /*Check whether a device is present */
+ if (pci_device_exists (dev) != TRUE) {
+
+ /*Clear error bits in ISR, write 1 to clear */
+ REG_WRITE (PCI_CSR_BASE, PCI_ISR_OFFSET, PCI_ISR_PSE
+ | PCI_ISR_PFE | PCI_ISR_PPE |
+ PCI_ISR_AHBE);
+ continue;
+ }
+
+ /*A device is present, add an entry to the array */
+ devices[nDevices].bus = bus;
+ devices[nDevices].device = dev;
+ devices[nDevices].func = func;
+
+ pci_read_config_word (dev, PCI_CFG_VENDOR_ID, &data16);
+
+ devices[nDevices].vendor_id = data16;
+
+ pci_read_config_word (dev, PCI_CFG_DEVICE_ID, &data16);
+ devices[nDevices].device_id = data16;
+
+ /*The device is functioning correctly, set error to FALSE */
+ devices[nDevices].error = FALSE;
+
+ /*Figure out what BARs are on this device */
+ sys_pci_bar_info_get (nDevices, bus, dev, func);
+ /*Figure out what INTX# line the card uses */
+ pci_read_config_byte (dev, PCI_CFG_DEV_INT_PIN, &intPin);
+
+ /*assign the appropriate irq line */
+ if (intPin > PCI_IRQ_LINES) {
+ devices[nDevices].error = TRUE;
+ } else if (intPin != 0) {
+ /*This device uses an interrupt line */
+ /*devices[nDevices].irq = ixp425PciIntTranslate[dev][intPin-1]; */
+ devices[nDevices].irq = intPin;
+ }
+#ifdef CONFIG_PCI_SCAN_SHOW
+ printf ("%06d %03d %03d %04d %08d %08x\n", nDevices,
+ devices[nDevices].vendor_id);
+#endif
+ nDevices++;
+
+ }
+
+ calc_bars (memBars, nMBars, IXP425_PCI_BAR_MEM_BASE);
+ sys_pci_device_bars_write ();
+
+ REG_WRITE (PCI_CSR_BASE, PCI_ISR_OFFSET, PCI_ISR_PSE
+ | PCI_ISR_PFE | PCI_ISR_PPE | PCI_ISR_AHBE);
+}
+
+void sys_pci_bar_info_get (unsigned int devnum,
+ unsigned int bus,
+ unsigned int dev, unsigned int func)
+{
+ unsigned int data32;
+ unsigned int tmp;
+ unsigned int size;
+
+ pci_write_config_dword (devnum,
+ PCI_CFG_BASE_ADDRESS_0, IXP425_PCI_BAR_QUERY);
+ pci_read_config_dword (devnum, PCI_CFG_BASE_ADDRESS_0, &data32);
+
+ devices[devnum].bar[0].address = (data32 & 1);
+
+ if (data32 & 1) {
+ /* IO space */
+ tmp = data32 & ~0x3;
+ size = ~(tmp - 1);
+ devices[devnum].bar[0].size = size;
+
+ if (nIOBars < IXP425_PCI_MAX_BAR) {
+ ioBars[nIOBars++] = &devices[devnum].bar[0];
+ }
+ } else {
+ /* Mem space */
+ tmp = data32 & ~IXP425_PCI_BOTTOM_NIBBLE_OF_LONG_MASK;
+ size = ~(tmp - 1);
+ devices[devnum].bar[0].size = size;
+
+ if (nMBars < IXP425_PCI_MAX_BAR) {
+ memBars[nMBars++] = &devices[devnum].bar[0];
+ } else {
+ devices[devnum].error = TRUE;
+ }
+
+ }
+
+ devices[devnum].bar[1].size = 0;
+}
+
+void sortBars (PciBar * Bars[], unsigned int nBars)
+{
+ unsigned int i, j;
+ PciBar *tmp;
+
+ if (nBars == 0) {
+ return;
+ }
+
+ /* Sort biggest to smallest */
+ for (i = 0; i < nBars - 1; i++) {
+ for (j = i + 1; j < nBars; j++) {
+ if (Bars[j]->size > Bars[i]->size) {
+ /* swap them */
+ tmp = Bars[i];
+ Bars[i] = Bars[j];
+ Bars[j] = tmp;
+ }
+ }
+ }
+}
+
+void calc_bars (PciBar * Bars[], unsigned int nBars, unsigned int startAddr)
+{
+ unsigned int i;
+
+ if (nBars == 0) {
+ return;
+ }
+
+ for (i = 0; i < nBars; i++) {
+ Bars[i]->address |= startAddr;
+ startAddr += Bars[i]->size;
+ }
+}
+
+void sys_pci_device_bars_write (void)
+{
+ unsigned int i;
+ int addr;
+
+ for (i = 1; i < nDevices; i++) {
+ if (devices[i].error) {
+ continue;
+ }
+
+ pci_write_config_dword (devices[i].device,
+ PCI_CFG_BASE_ADDRESS_0,
+ devices[i].bar[0].address);
+ addr = BIT (31 - devices[i].device) |
+ (0 << PCI_NP_AD_FUNCSL) |
+ (PCI_CFG_BASE_ADDRESS_0 & ~3);
+ pci_write_config_dword (devices[i].device,
+ PCI_CFG_DEV_INT_LINE, devices[i].irq);
+
+ pci_write_config_word (devices[i].device,
+ PCI_CFG_COMMAND, INITIAL_PCI_CMD);
+
+ }
+}
+
+
+int pci_device_exists (unsigned int deviceNo)
+{
+ unsigned int vendorId;
+ unsigned int regval;
+
+ pci_read_config_dword (deviceNo, PCI_CFG_VENDOR_ID, &vendorId);
+
+ /* There are two ways to find out an empty device.
+ * 1. check Master Abort bit after the access.
+ * 2. check whether the vendor id read back is 0x0.
+ */
+ REG_READ (PCI_CSR_BASE, PCI_ISR_OFFSET, regval);
+ if ((vendorId != 0x0) && ((regval & PCI_ISR_PFE) == 0)) {
+ return TRUE;
+ }
+ /*no device present, make sure that the master abort bit is reset */
+
+ REG_WRITE (PCI_CSR_BASE, PCI_ISR_OFFSET, PCI_ISR_PFE);
+ return FALSE;
+}
+
+pci_dev_t pci_find_devices (struct pci_device_id * ids, int devNo)
+{
+ unsigned int i;
+ unsigned int devdidvid;
+ unsigned int didvid;
+ unsigned int vendorId, deviceId;
+
+ vendorId = ids->vendor;
+ deviceId = ids->device;
+ didvid = ((deviceId << 16) & IXP425_PCI_TOP_WORD_OF_LONG_MASK) |
+ (vendorId & IXP425_PCI_BOTTOM_WORD_OF_LONG_MASK);
+
+ for (i = devNo + 1; i < nDevices; i++) {
+
+ pci_read_config_dword (devices[i].device, PCI_CFG_VENDOR_ID,
+ &devdidvid);
+
+ if (devdidvid == didvid) {
+ return devices[i].device;
+ }
+ }
+ return -1;
+}
diff --git a/u-boot/drivers/pci/pci_sh4.c b/u-boot/drivers/pci/pci_sh4.c
new file mode 100644
index 0000000..62915b6
--- /dev/null
+++ b/u-boot/drivers/pci/pci_sh4.c
@@ -0,0 +1,98 @@
+/*
+ * SH4 PCI Controller (PCIC) for U-Boot.
+ * (C) Dustin McIntire (dustin@sensoria.com)
+ * (C) 2007,2008 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+ * (C) 2008 Yusuke Goda <goda.yusuke@renesas.com>
+ *
+ * u-boot/arch/sh/cpu/sh4/pci-sh4.c
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+#include <pci.h>
+
+int pci_sh4_init(struct pci_controller *hose)
+{
+ hose->first_busno = 0;
+ hose->region_count = 0;
+ hose->last_busno = 0xff;
+
+ /* PCI memory space */
+ pci_set_region(hose->regions + 0,
+ CONFIG_PCI_MEM_BUS,
+ CONFIG_PCI_MEM_PHYS,
+ CONFIG_PCI_MEM_SIZE,
+ PCI_REGION_MEM);
+ hose->region_count++;
+
+ /* PCI IO space */
+ pci_set_region(hose->regions + 1,
+ CONFIG_PCI_IO_BUS,
+ CONFIG_PCI_IO_PHYS,
+ CONFIG_PCI_IO_SIZE,
+ PCI_REGION_IO);
+ hose->region_count++;
+
+#if defined(CONFIG_PCI_SYS_BUS)
+ /* PCI System Memory space */
+ pci_set_region(hose->regions + 2,
+ CONFIG_PCI_SYS_BUS,
+ CONFIG_PCI_SYS_PHYS,
+ CONFIG_PCI_SYS_SIZE,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+ hose->region_count++;
+#endif
+
+ udelay(1000);
+
+ pci_set_ops(hose,
+ pci_hose_read_config_byte_via_dword,
+ pci_hose_read_config_word_via_dword,
+ pci_sh4_read_config_dword,
+ pci_hose_write_config_byte_via_dword,
+ pci_hose_write_config_word_via_dword,
+ pci_sh4_write_config_dword);
+
+ pci_register_hose(hose);
+
+ udelay(1000);
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+ printf("PCI: Bus Dev VenId DevId Class Int\n");
+#endif
+ hose->last_busno = pci_hose_scan(hose);
+ return 0;
+}
+
+int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev)
+{
+ return 0;
+}
+
+#ifdef CONFIG_PCI_SCAN_SHOW
+int pci_print_dev(struct pci_controller *hose, pci_dev_t dev)
+{
+ return 1;
+}
+#endif /* CONFIG_PCI_SCAN_SHOW */
diff --git a/u-boot/drivers/pci/pci_sh7751.c b/u-boot/drivers/pci/pci_sh7751.c
new file mode 100644
index 0000000..df6d76f
--- /dev/null
+++ b/u-boot/drivers/pci/pci_sh7751.c
@@ -0,0 +1,203 @@
+/*
+ * SH7751 PCI Controller (PCIC) for U-Boot.
+ * (C) Dustin McIntire (dustin@sensoria.com)
+ * (C) 2007,2008 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <pci.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+
+/* Register addresses and such */
+#define SH7751_BCR1 (vu_long *)0xFF800000
+#define SH7751_BCR2 (vu_short *)0xFF800004
+#define SH7751_WCR1 (vu_long *)0xFF800008
+#define SH7751_WCR2 (vu_long *)0xFF80000C
+#define SH7751_WCR3 (vu_long *)0xFF800010
+#define SH7751_MCR (vu_long *)0xFF800014
+#define SH7751_BCR3 (vu_short *)0xFF800050
+#define SH7751_PCICONF0 (vu_long *)0xFE200000
+#define SH7751_PCICONF1 (vu_long *)0xFE200004
+#define SH7751_PCICONF2 (vu_long *)0xFE200008
+#define SH7751_PCICONF3 (vu_long *)0xFE20000C
+#define SH7751_PCICONF4 (vu_long *)0xFE200010
+#define SH7751_PCICONF5 (vu_long *)0xFE200014
+#define SH7751_PCICONF6 (vu_long *)0xFE200018
+#define SH7751_PCICR (vu_long *)0xFE200100
+#define SH7751_PCILSR0 (vu_long *)0xFE200104
+#define SH7751_PCILSR1 (vu_long *)0xFE200108
+#define SH7751_PCILAR0 (vu_long *)0xFE20010C
+#define SH7751_PCILAR1 (vu_long *)0xFE200110
+#define SH7751_PCIMBR (vu_long *)0xFE2001C4
+#define SH7751_PCIIOBR (vu_long *)0xFE2001C8
+#define SH7751_PCIPINT (vu_long *)0xFE2001CC
+#define SH7751_PCIPINTM (vu_long *)0xFE2001D0
+#define SH7751_PCICLKR (vu_long *)0xFE2001D4
+#define SH7751_PCIBCR1 (vu_long *)0xFE2001E0
+#define SH7751_PCIBCR2 (vu_long *)0xFE2001E4
+#define SH7751_PCIWCR1 (vu_long *)0xFE2001E8
+#define SH7751_PCIWCR2 (vu_long *)0xFE2001EC
+#define SH7751_PCIWCR3 (vu_long *)0xFE2001F0
+#define SH7751_PCIMCR (vu_long *)0xFE2001F4
+#define SH7751_PCIBCR3 (vu_long *)0xFE2001F8
+
+#define BCR1_BREQEN 0x00080000
+#define PCI_SH7751_ID 0x35051054
+#define PCI_SH7751R_ID 0x350E1054
+#define SH7751_PCICONF1_WCC 0x00000080
+#define SH7751_PCICONF1_PER 0x00000040
+#define SH7751_PCICONF1_BUM 0x00000004
+#define SH7751_PCICONF1_MES 0x00000002
+#define SH7751_PCICONF1_CMDS 0x000000C6
+#define SH7751_PCI_HOST_BRIDGE 0x6
+#define SH7751_PCICR_PREFIX 0xa5000000
+#define SH7751_PCICR_PRST 0x00000002
+#define SH7751_PCICR_CFIN 0x00000001
+#define SH7751_PCIPINT_D3 0x00000002
+#define SH7751_PCIPINT_D0 0x00000001
+#define SH7751_PCICLKR_PREFIX 0xa5000000
+
+#define SH7751_PCI_MEM_BASE 0xFD000000
+#define SH7751_PCI_MEM_SIZE 0x01000000
+#define SH7751_PCI_IO_BASE 0xFE240000
+#define SH7751_PCI_IO_SIZE 0x00040000
+
+#define SH7751_CS3_BASE_ADDR 0x0C000000
+#define SH7751_P2CS3_BASE_ADDR 0xAC000000
+
+#define SH7751_PCIPAR (vu_long *)0xFE2001C0
+#define SH7751_PCIPDR (vu_long *)0xFE200220
+
+#define p4_in(addr) (*addr)
+#define p4_out(data, addr) (*addr) = (data)
+
+/* Double word */
+int pci_sh4_read_config_dword(struct pci_controller *hose,
+ pci_dev_t dev, int offset, u32 *value)
+{
+ u32 par_data = 0x80000000 | dev;
+
+ p4_out(par_data | (offset & 0xfc), SH7751_PCIPAR);
+ *value = p4_in(SH7751_PCIPDR);
+
+ return 0;
+}
+
+int pci_sh4_write_config_dword(struct pci_controller *hose,
+ pci_dev_t dev, int offset, u32 value)
+{
+ u32 par_data = 0x80000000 | dev;
+
+ p4_out(par_data | (offset & 0xfc), SH7751_PCIPAR);
+ p4_out(value, SH7751_PCIPDR);
+
+ return 0;
+}
+
+int pci_sh7751_init(struct pci_controller *hose)
+{
+ /* Double-check that we're a 7751 or 7751R chip */
+ if (p4_in(SH7751_PCICONF0) != PCI_SH7751_ID
+ && p4_in(SH7751_PCICONF0) != PCI_SH7751R_ID) {
+ printf("PCI: Unknown PCI host bridge.\n");
+ return 1;
+ }
+ printf("PCI: SH7751 PCI host bridge found.\n");
+
+ /* Double-check some BSC config settings */
+ /* (Area 3 non-MPX 32-bit, PCI bus pins) */
+ if ((p4_in(SH7751_BCR1) & 0x20008) == 0x20000) {
+ printf("SH7751_BCR1 value is wrong(0x%08X)\n",
+ (unsigned int)p4_in(SH7751_BCR1));
+ return 2;
+ }
+ if ((p4_in(SH7751_BCR2) & 0xC0) != 0xC0) {
+ printf("SH7751_BCR2 value is wrong(0x%08X)\n",
+ (unsigned int)p4_in(SH7751_BCR2));
+ return 3;
+ }
+ if (p4_in(SH7751_BCR2) & 0x01) {
+ printf("SH7751_BCR2 value is wrong(0x%08X)\n",
+ (unsigned int)p4_in(SH7751_BCR2));
+ return 4;
+ }
+
+ /* Force BREQEN in BCR1 to allow PCIC access */
+ p4_out((p4_in(SH7751_BCR1) | BCR1_BREQEN), SH7751_BCR1);
+
+ /* Toggle PCI reset pin */
+ p4_out((SH7751_PCICR_PREFIX | SH7751_PCICR_PRST), SH7751_PCICR);
+ udelay(32);
+ p4_out(SH7751_PCICR_PREFIX, SH7751_PCICR);
+
+ /* Set cmd bits: WCC, PER, BUM, MES */
+ /* (Addr/Data stepping, Parity enabled, Bus Master, Memory enabled) */
+ p4_out(0xfb900047, SH7751_PCICONF1); /* K.Kino */
+
+ /* Define this host as the host bridge */
+ p4_out((SH7751_PCI_HOST_BRIDGE << 24), SH7751_PCICONF2);
+
+ /* Force PCI clock(s) on */
+ p4_out(0, SH7751_PCICLKR);
+ p4_out(0x03, SH7751_PCICLKR);
+
+ /* Clear powerdown IRQs, also mask them (unused) */
+ p4_out((SH7751_PCIPINT_D0 | SH7751_PCIPINT_D3), SH7751_PCIPINT);
+ p4_out(0, SH7751_PCIPINTM);
+
+ p4_out(0xab000001, SH7751_PCICONF4);
+
+ /* Set up target memory mappings (for external DMA access) */
+ /* Map both P0 and P2 range to Area 3 RAM for ease of use */
+ p4_out((64 - 1) << 20, SH7751_PCILSR0);
+ p4_out(SH7751_CS3_BASE_ADDR, SH7751_PCILAR0);
+ p4_out(0, SH7751_PCILSR1);
+ p4_out(0, SH7751_PCILAR1);
+ p4_out(SH7751_CS3_BASE_ADDR, SH7751_PCICONF5);
+ p4_out(0xd0000000, SH7751_PCICONF6);
+
+ /* Map memory window to same address on PCI bus */
+ p4_out(SH7751_PCI_MEM_BASE, SH7751_PCIMBR);
+
+ /* Map IO window to same address on PCI bus */
+ p4_out(0x2000 & 0xfffc0000, SH7751_PCIIOBR);
+
+ /* set BREQEN */
+ p4_out(inl(SH7751_BCR1) | 0x00080000, SH7751_BCR1);
+
+ /* Copy BSC registers into PCI BSC */
+ p4_out(inl(SH7751_BCR1), SH7751_PCIBCR1);
+ p4_out(inw(SH7751_BCR2), SH7751_PCIBCR2);
+ p4_out(inw(SH7751_BCR3), SH7751_PCIBCR3);
+ p4_out(inl(SH7751_WCR1), SH7751_PCIWCR1);
+ p4_out(inl(SH7751_WCR2), SH7751_PCIWCR2);
+ p4_out(inl(SH7751_WCR3), SH7751_PCIWCR3);
+ p4_out(inl(SH7751_MCR), SH7751_PCIMCR);
+
+ /* Finally, set central function init complete */
+ p4_out((SH7751_PCICR_PREFIX | SH7751_PCICR_CFIN), SH7751_PCICR);
+
+ pci_sh4_init(hose);
+
+ return 0;
+}
diff --git a/u-boot/drivers/pci/pci_sh7780.c b/u-boot/drivers/pci/pci_sh7780.c
new file mode 100644
index 0000000..bc06f49
--- /dev/null
+++ b/u-boot/drivers/pci/pci_sh7780.c
@@ -0,0 +1,108 @@
+/*
+ * SH7780 PCI Controller (PCIC) for U-Boot.
+ * (C) Dustin McIntire (dustin@sensoria.com)
+ * (C) 2007,2008 Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
+ * (C) 2008 Yusuke Goda <goda.yusuke@renesas.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#include <pci.h>
+#include <asm/processor.h>
+#include <asm/pci.h>
+#include <asm/io.h>
+
+#define SH7780_VENDOR_ID 0x1912
+#define SH7780_DEVICE_ID 0x0002
+#define SH7780_PCICR_PREFIX 0xA5000000
+#define SH7780_PCICR_PFCS 0x00000800
+#define SH7780_PCICR_FTO 0x00000400
+#define SH7780_PCICR_PFE 0x00000200
+#define SH7780_PCICR_TBS 0x00000100
+#define SH7780_PCICR_ARBM 0x00000040
+#define SH7780_PCICR_IOCS 0x00000004
+#define SH7780_PCICR_PRST 0x00000002
+#define SH7780_PCICR_CFIN 0x00000001
+
+#define p4_in(addr) (*(vu_long *)addr)
+#define p4_out(data, addr) (*(vu_long *)addr) = (data)
+#define p4_inw(addr) (*(vu_short *)addr)
+#define p4_outw(data, addr) (*(vu_short *)addr) = (data)
+
+int pci_sh4_read_config_dword(struct pci_controller *hose,
+ pci_dev_t dev, int offset, u32 *value)
+{
+ u32 par_data = 0x80000000 | dev;
+
+ p4_out(par_data | (offset & 0xfc), SH7780_PCIPAR);
+ *value = p4_in(SH7780_PCIPDR);
+
+ return 0;
+}
+
+int pci_sh4_write_config_dword(struct pci_controller *hose,
+ pci_dev_t dev, int offset, u32 value)
+{
+ u32 par_data = 0x80000000 | dev;
+
+ p4_out(par_data | (offset & 0xfc), SH7780_PCIPAR);
+ p4_out(value, SH7780_PCIPDR);
+ return 0;
+}
+
+int pci_sh7780_init(struct pci_controller *hose)
+{
+ p4_out(0x01, SH7780_PCIECR);
+
+ if (p4_inw(SH7780_PCIVID) != SH7780_VENDOR_ID
+ && p4_inw(SH7780_PCIDID) != SH7780_DEVICE_ID) {
+ printf("PCI: Unknown PCI host bridge.\n");
+ return -1;
+ }
+ printf("PCI: SH7780 PCI host bridge found.\n");
+
+ /* Toggle PCI reset pin */
+ p4_out((SH7780_PCICR_PREFIX | SH7780_PCICR_PRST), SH7780_PCICR);
+ udelay(100000);
+ p4_out(SH7780_PCICR_PREFIX, SH7780_PCICR);
+ p4_outw(0x0047, SH7780_PCICMD);
+
+ p4_out(CONFIG_SH7780_PCI_LSR, SH7780_PCILSR0);
+ p4_out(CONFIG_SH7780_PCI_LAR, SH7780_PCILAR0);
+ p4_out(0x00000000, SH7780_PCILSR1);
+ p4_out(0, SH7780_PCILAR1);
+ p4_out(CONFIG_SH7780_PCI_BAR, SH7780_PCIMBAR0);
+ p4_out(0x00000000, SH7780_PCIMBAR1);
+
+ p4_out(0xFD000000, SH7780_PCIMBR0);
+ p4_out(0x00FC0000, SH7780_PCIMBMR0);
+
+ /* if use Operand Cache then enable PCICSCR Soonp bits. */
+ p4_out(0x08000000, SH7780_PCICSAR0);
+ p4_out(0x0000001B, SH7780_PCICSCR0); /* Snoop bit :On */
+
+ p4_out((SH7780_PCICR_PREFIX | SH7780_PCICR_CFIN | SH7780_PCICR_ARBM
+ | SH7780_PCICR_FTO | SH7780_PCICR_PFCS | SH7780_PCICR_PFE),
+ SH7780_PCICR);
+
+ pci_sh4_init(hose);
+ return 0;
+}
diff --git a/u-boot/drivers/pci/tsi108_pci.c b/u-boot/drivers/pci/tsi108_pci.c
new file mode 100644
index 0000000..c568bf9
--- /dev/null
+++ b/u-boot/drivers/pci/tsi108_pci.c
@@ -0,0 +1,183 @@
+/*
+ * (C) Copyright 2004 Tundra Semiconductor Corp.
+ * Alex Bounine <alexandreb@tundra.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * PCI initialisation for the Tsi108 EMU board.
+ */
+
+#include <config.h>
+
+#include <common.h>
+#include <pci.h>
+#include <asm/io.h>
+#include <tsi108.h>
+#if defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#include <fdt_support.h>
+#endif
+
+struct pci_controller local_hose;
+
+void tsi108_clear_pci_error (void)
+{
+ u32 err_stat, err_addr, pci_stat;
+
+ /*
+ * Quietly clear errors signalled as result of PCI/X configuration read
+ * requests.
+ */
+ /* Read PB Error Log Registers */
+ err_stat = *(volatile u32 *)(CONFIG_SYS_TSI108_CSR_BASE +
+ TSI108_PB_REG_OFFSET + PB_ERRCS);
+ err_addr = *(volatile u32 *)(CONFIG_SYS_TSI108_CSR_BASE +
+ TSI108_PB_REG_OFFSET + PB_AERR);
+ if (err_stat & PB_ERRCS_ES) {
+ /* Clear PCI/X bus errors if applicable */
+ if ((err_addr & 0xFF000000) == CONFIG_SYS_PCI_CFG_BASE) {
+ /* Clear error flag */
+ *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE +
+ TSI108_PB_REG_OFFSET + PB_ERRCS) =
+ PB_ERRCS_ES;
+
+ /* Clear read error reported in PB_ISR */
+ *(u32 *) (CONFIG_SYS_TSI108_CSR_BASE +
+ TSI108_PB_REG_OFFSET + PB_ISR) =
+ PB_ISR_PBS_RD_ERR;
+
+ /* Clear errors reported by PCI CSR (Normally Master Abort) */
+ pci_stat = *(volatile u32 *)(CONFIG_SYS_TSI108_CSR_BASE +
+ TSI108_PCI_REG_OFFSET +
+ PCI_CSR);
+ *(volatile u32 *)(CONFIG_SYS_TSI108_CSR_BASE +
+ TSI108_PCI_REG_OFFSET + PCI_CSR) =
+ pci_stat;
+
+ *(volatile u32 *)(CONFIG_SYS_TSI108_CSR_BASE +
+ TSI108_PCI_REG_OFFSET +
+ PCI_IRP_STAT) = PCI_IRP_STAT_P_CSR;
+ }
+ }
+
+ return;
+}
+
+unsigned int __get_pci_config_dword (u32 addr)
+{
+ unsigned int retval;
+
+ __asm__ __volatile__ (" lwbrx %0,0,%1\n"
+ "1: eieio\n"
+ "2:\n"
+ ".section .fixup,\"ax\"\n"
+ "3: li %0,-1\n"
+ " b 2b\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 2\n"
+ " .long 1b,3b\n"
+ ".section .text.__get_pci_config_dword"
+ : "=r"(retval) : "r"(addr));
+
+ return (retval);
+}
+
+static int tsi108_read_config_dword (struct pci_controller *hose,
+ pci_dev_t dev, int offset, u32 * value)
+{
+ dev &= (CONFIG_SYS_PCI_CFG_SIZE - 1);
+ dev |= (CONFIG_SYS_PCI_CFG_BASE | (offset & 0xfc));
+ *value = __get_pci_config_dword(dev);
+ if (0xFFFFFFFF == *value)
+ tsi108_clear_pci_error ();
+ return 0;
+}
+
+static int tsi108_write_config_dword (struct pci_controller *hose,
+ pci_dev_t dev, int offset, u32 value)
+{
+ dev &= (CONFIG_SYS_PCI_CFG_SIZE - 1);
+ dev |= (CONFIG_SYS_PCI_CFG_BASE | (offset & 0xfc));
+
+ out_le32 ((volatile unsigned *)dev, value);
+
+ return 0;
+}
+
+void pci_init_board (void)
+{
+ struct pci_controller *hose = (struct pci_controller *)&local_hose;
+
+ hose->first_busno = 0;
+ hose->last_busno = 0xff;
+
+ pci_set_region (hose->regions + 0,
+ CONFIG_SYS_PCI_MEMORY_BUS,
+ CONFIG_SYS_PCI_MEMORY_PHYS,
+ CONFIG_SYS_PCI_MEMORY_SIZE, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ /* PCI memory space */
+ pci_set_region (hose->regions + 1,
+ CONFIG_SYS_PCI_MEM_BUS,
+ CONFIG_SYS_PCI_MEM_PHYS, CONFIG_SYS_PCI_MEM_SIZE, PCI_REGION_MEM);
+
+ /* PCI I/O space */
+ pci_set_region (hose->regions + 2,
+ CONFIG_SYS_PCI_IO_BUS,
+ CONFIG_SYS_PCI_IO_PHYS, CONFIG_SYS_PCI_IO_SIZE, PCI_REGION_IO);
+
+ hose->region_count = 3;
+
+ pci_set_ops (hose,
+ pci_hose_read_config_byte_via_dword,
+ pci_hose_read_config_word_via_dword,
+ tsi108_read_config_dword,
+ pci_hose_write_config_byte_via_dword,
+ pci_hose_write_config_word_via_dword,
+ tsi108_write_config_dword);
+
+ pci_register_hose (hose);
+
+ hose->last_busno = pci_hose_scan (hose);
+
+ debug ("Done PCI initialization\n");
+ return;
+}
+
+#if defined(CONFIG_OF_LIBFDT)
+void ft_pci_setup(void *blob, bd_t *bd)
+{
+ int nodeoffset;
+ int tmp[2];
+ const char *path;
+
+ nodeoffset = fdt_path_offset(blob, "/aliases");
+ if (nodeoffset >= 0) {
+ path = fdt_getprop(blob, nodeoffset, "pci", NULL);
+ if (path) {
+ tmp[0] = cpu_to_be32(local_hose.first_busno);
+ tmp[1] = cpu_to_be32(local_hose.last_busno);
+ do_fixup_by_path(blob, path, "bus-range",
+ &tmp, sizeof(tmp), 1);
+ }
+ }
+}
+#endif /* CONFIG_OF_LIBFDT */
diff --git a/u-boot/drivers/pci/w83c553f.c b/u-boot/drivers/pci/w83c553f.c
new file mode 100644
index 0000000..8561422
--- /dev/null
+++ b/u-boot/drivers/pci/w83c553f.c
@@ -0,0 +1,222 @@
+/*
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Initialisation of the PCI-to-ISA bridge and disabling the BIOS
+ * write protection (for flash) in function 0 of the chip.
+ * Enabling function 1 (IDE controller of the chip.
+ */
+
+#include <common.h>
+#include <config.h>
+
+#include <asm/io.h>
+#include <pci.h>
+
+#include <w83c553f.h>
+
+#define out8(addr,val) do { \
+ out_8((u8*) (addr),(val)); udelay(1); \
+ } while (0)
+#define out16(addr,val) do { \
+ out_be16((u16*) (addr),(val)); udelay(1); \
+ } while (0)
+
+extern uint ide_bus_offset[CONFIG_SYS_IDE_MAXBUS];
+
+void initialise_pic(void);
+void initialise_dma(void);
+
+void initialise_w83c553f(void)
+{
+ pci_dev_t devbusfn;
+ unsigned char reg8;
+ unsigned short reg16;
+ unsigned int reg32;
+
+ devbusfn = pci_find_device(W83C553F_VID, W83C553F_DID, 0);
+ if (devbusfn == -1)
+ {
+ printf("Error: Cannot find W83C553F controller on any PCI bus.");
+ return;
+ }
+
+ pci_read_config_word(devbusfn, PCI_COMMAND, &reg16);
+ reg16 |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+ pci_write_config_word(devbusfn, PCI_COMMAND, reg16);
+
+ pci_read_config_byte(devbusfn, WINBOND_IPADCR, &reg8);
+ /* 16 MB ISA memory space */
+ reg8 |= (IPADCR_IPATOM4 | IPADCR_IPATOM5 | IPADCR_IPATOM6 | IPADCR_IPATOM7);
+ reg8 &= ~IPADCR_MBE512;
+ pci_write_config_byte(devbusfn, WINBOND_IPADCR, reg8);
+
+ pci_read_config_byte(devbusfn, WINBOND_CSCR, &reg8);
+ /* switch off BIOS write protection */
+ reg8 |= CSCR_UBIOSCSE;
+ reg8 &= ~CSCR_BIOSWP;
+ pci_write_config_byte(devbusfn, WINBOND_CSCR, reg8);
+
+ /*
+ * Interrupt routing:
+ * - IDE -> IRQ 9/0
+ * - INTA -> IRQ 10
+ * - INTB -> IRQ 11
+ * - INTC -> IRQ 14
+ * - INTD -> IRQ 15
+ */
+ pci_write_config_byte(devbusfn, WINBOND_IDEIRCR, 0x90);
+ pci_write_config_word(devbusfn, WINBOND_PCIIRCR, 0xABEF);
+
+ /*
+ * Read IDE bus offsets from function 1 device.
+ * We must unmask the LSB indicating that ist is an IO address.
+ */
+ devbusfn |= PCI_BDF(0,0,1);
+
+ /*
+ * Switch off legacy IRQ for IDE and IDE port 1.
+ */
+ pci_write_config_byte(devbusfn, 0x09, 0x8F);
+
+ pci_read_config_dword(devbusfn, WINDOND_IDECSR, &reg32);
+ reg32 &= ~(IDECSR_LEGIRQ | IDECSR_P1EN | IDECSR_P1F16);
+ pci_write_config_dword(devbusfn, WINDOND_IDECSR, reg32);
+
+ pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0, &ide_bus_offset[0]);
+ ide_bus_offset[0] &= ~1;
+#if CONFIG_SYS_IDE_MAXBUS > 1
+ pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_2, &ide_bus_offset[1]);
+ ide_bus_offset[1] &= ~1;
+#endif
+
+ /*
+ * Enable function 1, IDE -> busmastering and IO space access
+ */
+ pci_read_config_word(devbusfn, PCI_COMMAND, &reg16);
+ reg16 |= PCI_COMMAND_MASTER | PCI_COMMAND_IO;
+ pci_write_config_word(devbusfn, PCI_COMMAND, reg16);
+
+ /*
+ * Initialise ISA interrupt controller
+ */
+ initialise_pic();
+
+ /*
+ * Initialise DMA controller
+ */
+ initialise_dma();
+}
+
+void initialise_pic(void)
+{
+ out8(W83C553F_PIC1_ICW1, 0x11);
+ out8(W83C553F_PIC1_ICW2, 0x08);
+ out8(W83C553F_PIC1_ICW3, 0x04);
+ out8(W83C553F_PIC1_ICW4, 0x01);
+ out8(W83C553F_PIC1_OCW1, 0xfb);
+ out8(W83C553F_PIC1_ELC, 0x20);
+
+ out8(W83C553F_PIC2_ICW1, 0x11);
+ out8(W83C553F_PIC2_ICW2, 0x08);
+ out8(W83C553F_PIC2_ICW3, 0x02);
+ out8(W83C553F_PIC2_ICW4, 0x01);
+ out8(W83C553F_PIC2_OCW1, 0xff);
+ out8(W83C553F_PIC2_ELC, 0xce);
+
+ out8(W83C553F_TMR1_CMOD, 0x74);
+
+ out8(W83C553F_PIC2_OCW1, 0x20);
+ out8(W83C553F_PIC1_OCW1, 0x20);
+
+ out8(W83C553F_PIC2_OCW1, 0x2b);
+ out8(W83C553F_PIC1_OCW1, 0x2b);
+}
+
+void initialise_dma(void)
+{
+ unsigned int channel;
+ unsigned int rvalue1, rvalue2;
+
+ /* perform a H/W reset of the devices */
+
+ out8(W83C553F_DMA1 + W83C553F_DMA1_MC, 0x00);
+ out16(W83C553F_DMA2 + W83C553F_DMA2_MC, 0x0000);
+
+ /* initialise all channels to a sane state */
+
+ for (channel = 0; channel < 4; channel++) {
+ /*
+ * dependent upon the channel, setup the specifics:
+ *
+ * demand
+ * address-increment
+ * autoinitialize-disable
+ * verify-transfer
+ */
+
+ switch (channel) {
+ case 0:
+ rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH0SEL|W83C553F_MODE_TT_VERIFY);
+ rvalue2 = (W83C553F_MODE_TM_CASCADE|W83C553F_MODE_CH0SEL);
+ break;
+ case 1:
+ rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH1SEL|W83C553F_MODE_TT_VERIFY);
+ rvalue2 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH1SEL|W83C553F_MODE_TT_VERIFY);
+ break;
+ case 2:
+ rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH2SEL|W83C553F_MODE_TT_VERIFY);
+ rvalue2 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH2SEL|W83C553F_MODE_TT_VERIFY);
+ break;
+ case 3:
+ rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH3SEL|W83C553F_MODE_TT_VERIFY);
+ rvalue2 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH3SEL|W83C553F_MODE_TT_VERIFY);
+ break;
+ default:
+ rvalue1 = 0x00;
+ rvalue2 = 0x00;
+ break;
+ }
+
+ /* write to write mode registers */
+
+ out8(W83C553F_DMA1 + W83C553F_DMA1_WM, rvalue1 & 0xFF);
+ out16(W83C553F_DMA2 + W83C553F_DMA2_WM, rvalue2 & 0x00FF);
+ }
+
+ /* enable all channels */
+
+ out8(W83C553F_DMA1 + W83C553F_DMA1_CM, 0x00);
+ out16(W83C553F_DMA2 + W83C553F_DMA2_CM, 0x0000);
+ /*
+ * initialize the global DMA configuration
+ *
+ * DACK# active low
+ * DREQ active high
+ * fixed priority
+ * channel group enable
+ */
+
+ out8(W83C553F_DMA1 + W83C553F_DMA1_CS, 0x00);
+ out16(W83C553F_DMA2 + W83C553F_DMA2_CS, 0x0000);
+}