diff options
Diffstat (limited to 'arch/ppc/syslib/ppc405_pci.c')
-rw-r--r-- | arch/ppc/syslib/ppc405_pci.c | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/arch/ppc/syslib/ppc405_pci.c b/arch/ppc/syslib/ppc405_pci.c new file mode 100644 index 000000000000..81c83bf98df4 --- /dev/null +++ b/arch/ppc/syslib/ppc405_pci.c @@ -0,0 +1,177 @@ +/* + * Authors: Frank Rowand <frank_rowand@mvista.com>, + * Debbie Chu <debbie_chu@mvista.com>, or source@mvista.com + * Further modifications by Armin Kuster <akuster@mvista.com> + * + * 2000 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + * + * Based on arch/ppc/kernel/indirect.c, Copyright (C) 1998 Gabriel Paubert. + */ + +#include <linux/pci.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/machdep.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <asm/ocp.h> +#include <asm/ibm4xx.h> +#include <asm/pci-bridge.h> +#include <asm/ibm_ocp_pci.h> + + +extern void bios_fixup(struct pci_controller *, struct pcil0_regs *); +extern int ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, + unsigned char pin); + +void +ppc405_pcibios_fixup_resources(struct pci_dev *dev) +{ + int i; + unsigned long max_host_addr; + unsigned long min_host_addr; + struct resource *res; + + /* + * openbios puts some graphics cards in the same range as the host + * controller uses to map to SDRAM. Fix it. + */ + + min_host_addr = 0; + max_host_addr = PPC405_PCI_MEM_BASE - 1; + + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + res = dev->resource + i; + if (!res->start) + continue; + if ((res->flags & IORESOURCE_MEM) && + (((res->start >= min_host_addr) + && (res->start <= max_host_addr)) + || ((res->end >= min_host_addr) + && (res->end <= max_host_addr)) + || ((res->start < min_host_addr) + && (res->end > max_host_addr)) + ) + ) { + + /* force pcibios_assign_resources() to assign a new address */ + res->end -= res->start; + res->start = 0; + } + } +} + +static int +ppc4xx_exclude_device(unsigned char bus, unsigned char devfn) +{ + /* We prevent us from seeing ourselves to avoid having + * the kernel try to remap our BAR #1 and fuck up bus + * master from external PCI devices + */ + return (bus == 0 && devfn == 0); +} + +void +ppc4xx_find_bridges(void) +{ + struct pci_controller *hose_a; + struct pcil0_regs *pcip; + unsigned int tmp_addr; + unsigned int tmp_size; + unsigned int reg_index; + unsigned int new_pmm_max = 0; + unsigned int new_pmm_min = 0; + + isa_io_base = 0; + isa_mem_base = 0; + pci_dram_offset = 0; + +#if (PSR_PCI_ARBIT_EN > 1) + /* Check if running in slave mode */ + if ((mfdcr(DCRN_CHPSR) & PSR_PCI_ARBIT_EN) == 0) { + printk("Running as PCI slave, kernel PCI disabled !\n"); + return; + } +#endif + /* Setup PCI32 hose */ + hose_a = pcibios_alloc_controller(); + if (!hose_a) + return; + setup_indirect_pci(hose_a, PPC405_PCI_CONFIG_ADDR, + PPC405_PCI_CONFIG_DATA); + + pcip = ioremap(PPC4xx_PCI_LCFG_PADDR, PAGE_SIZE); + if (pcip != NULL) { + +#if defined(CONFIG_BIOS_FIXUP) + bios_fixup(hose_a, pcip); +#endif + new_pmm_min = 0xffffffff; + for (reg_index = 0; reg_index < 3; reg_index++) { + tmp_size = in_le32(&pcip->pmm[reg_index].ma); // mask & attrs + /* test the enable bit */ + if ((tmp_size & 0x1) == 0) + continue; + tmp_addr = in_le32(&pcip->pmm[reg_index].pcila); // PCI addr + if (tmp_addr < PPC405_PCI_PHY_MEM_BASE) { + printk(KERN_DEBUG + "Disabling mapping to PCI mem addr 0x%8.8x\n", + tmp_addr); + out_le32(&pcip->pmm[reg_index].ma, tmp_size & ~1); // *_PMMOMA + continue; + } + tmp_addr = in_le32(&pcip->pmm[reg_index].la); // *_PMMOLA + if (tmp_addr < new_pmm_min) + new_pmm_min = tmp_addr; + tmp_addr = tmp_addr + + (0xffffffff - (tmp_size & 0xffffc000)); + if (tmp_addr > PPC405_PCI_UPPER_MEM) { + new_pmm_max = tmp_addr; // PPC405_PCI_UPPER_MEM + } else { + new_pmm_max = PPC405_PCI_UPPER_MEM; + } + + } // for + + iounmap(pcip); + } + + hose_a->first_busno = 0; + hose_a->last_busno = 0xff; + hose_a->pci_mem_offset = 0; + + /* Setup bridge memory/IO ranges & resources + * TODO: Handle firmwares setting up a legacy ISA mem base + */ + hose_a->io_space.start = PPC405_PCI_LOWER_IO; + hose_a->io_space.end = PPC405_PCI_UPPER_IO; + hose_a->mem_space.start = new_pmm_min; + hose_a->mem_space.end = new_pmm_max; + hose_a->io_base_phys = PPC405_PCI_PHY_IO_BASE; + hose_a->io_base_virt = ioremap(hose_a->io_base_phys, 0x10000); + hose_a->io_resource.start = 0; + hose_a->io_resource.end = PPC405_PCI_UPPER_IO - PPC405_PCI_LOWER_IO; + hose_a->io_resource.flags = IORESOURCE_IO; + hose_a->io_resource.name = "PCI I/O"; + hose_a->mem_resources[0].start = new_pmm_min; + hose_a->mem_resources[0].end = new_pmm_max; + hose_a->mem_resources[0].flags = IORESOURCE_MEM; + hose_a->mem_resources[0].name = "PCI Memory"; + isa_io_base = (int) hose_a->io_base_virt; + isa_mem_base = 0; /* ISA not implemented */ + ISA_DMA_THRESHOLD = 0x00ffffff; /* ??? ISA not implemented */ + + /* Scan busses & initial setup by pci_auto */ + hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno); + hose_a->last_busno = 0; + + /* Setup ppc_md */ + ppc_md.pcibios_fixup = NULL; + ppc_md.pci_exclude_device = ppc4xx_exclude_device; + ppc_md.pcibios_fixup_resources = ppc405_pcibios_fixup_resources; + ppc_md.pci_swizzle = common_swizzle; + ppc_md.pci_map_irq = ppc405_map_irq; +} |