1/* 2 * Authors: Frank Rowand <frank_rowand@mvista.com>, 3 * Debbie Chu <debbie_chu@mvista.com>, or source@mvista.com 4 * Further modifications by Armin Kuster <akuster@mvista.com> 5 * 6 * 2000 (c) MontaVista, Software, Inc. This file is licensed under 7 * the terms of the GNU General Public License version 2. This program 8 * is licensed "as is" without any warranty of any kind, whether express 9 * or implied. 10 * 11 * Based on arch/ppc/kernel/indirect.c, Copyright (C) 1998 Gabriel Paubert. 12 */ 13 14#include <linux/pci.h> 15#include <asm/io.h> 16#include <asm/system.h> 17#include <asm/machdep.h> 18#include <linux/init.h> 19#include <linux/errno.h> 20#include <asm/ocp.h> 21#include <asm/ibm4xx.h> 22#include <asm/pci-bridge.h> 23#include <asm/ibm_ocp_pci.h> 24 25 26extern void bios_fixup(struct pci_controller *, struct pcil0_regs *); 27extern int ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, 28 unsigned char pin); 29 30void 31ppc405_pcibios_fixup_resources(struct pci_dev *dev) 32{ 33 int i; 34 unsigned long max_host_addr; 35 unsigned long min_host_addr; 36 struct resource *res; 37 38 /* 39 * openbios puts some graphics cards in the same range as the host 40 * controller uses to map to SDRAM. Fix it. 41 */ 42 43 min_host_addr = 0; 44 max_host_addr = PPC405_PCI_MEM_BASE - 1; 45 46 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { 47 res = dev->resource + i; 48 if (!res->start) 49 continue; 50 if ((res->flags & IORESOURCE_MEM) && 51 (((res->start >= min_host_addr) 52 && (res->start <= max_host_addr)) 53 || ((res->end >= min_host_addr) 54 && (res->end <= max_host_addr)) 55 || ((res->start < min_host_addr) 56 && (res->end > max_host_addr)) 57 ) 58 ) { 59 60 /* force pcibios_assign_resources() to assign a new address */ 61 res->end -= res->start; 62 res->start = 0; 63 } 64 } 65} 66 67static int 68ppc4xx_exclude_device(unsigned char bus, unsigned char devfn) 69{ 70 /* We prevent us from seeing ourselves to avoid having 71 * the kernel try to remap our BAR #1 and fuck up bus 72 * master from external PCI devices 73 */ 74 return (bus == 0 && devfn == 0); 75} 76 77void 78ppc4xx_find_bridges(void) 79{ 80 struct pci_controller *hose_a; 81 struct pcil0_regs *pcip; 82 unsigned int tmp_addr; 83 unsigned int tmp_size; 84 unsigned int reg_index; 85 unsigned int new_pmm_max = 0; 86 unsigned int new_pmm_min = 0; 87 88 isa_io_base = 0; 89 isa_mem_base = 0; 90 pci_dram_offset = 0; 91 92 /* Setup PCI32 hose */ 93 hose_a = pcibios_alloc_controller(); 94 if (!hose_a) 95 return; 96 setup_indirect_pci(hose_a, PPC405_PCI_CONFIG_ADDR, 97 PPC405_PCI_CONFIG_DATA); 98 99 pcip = ioremap(PPC4xx_PCI_LCFG_PADDR, PAGE_SIZE); 100 if (pcip != NULL) { 101 102#if defined(CONFIG_BIOS_FIXUP) 103 bios_fixup(hose_a, pcip); 104#endif 105 new_pmm_min = 0xffffffff; 106 for (reg_index = 0; reg_index < 3; reg_index++) { 107 tmp_size = in_le32(&pcip->pmm[reg_index].ma); // mask & attrs 108 /* test the enable bit */ 109 if ((tmp_size & 0x1) == 0) 110 continue; 111 tmp_addr = in_le32(&pcip->pmm[reg_index].pcila); // PCI addr 112 if (tmp_addr < PPC405_PCI_PHY_MEM_BASE) { 113 printk(KERN_DEBUG 114 "Disabling mapping to PCI mem addr 0x%8.8x\n", 115 tmp_addr); 116 out_le32(&pcip->pmm[reg_index].ma, tmp_size & ~1); // *_PMMOMA 117 continue; 118 } 119 tmp_addr = in_le32(&pcip->pmm[reg_index].la); // *_PMMOLA 120 if (tmp_addr < new_pmm_min) 121 new_pmm_min = tmp_addr; 122 tmp_addr = tmp_addr + 123 (0xffffffff - (tmp_size & 0xffffc000)); 124 if (tmp_addr > PPC405_PCI_UPPER_MEM) { 125 new_pmm_max = tmp_addr; // PPC405_PCI_UPPER_MEM 126 } else { 127 new_pmm_max = PPC405_PCI_UPPER_MEM; 128 } 129 130 } // for 131 132 iounmap(pcip); 133 } 134 135 hose_a->first_busno = 0; 136 hose_a->last_busno = 0xff; 137 hose_a->pci_mem_offset = 0; 138 139 /* Setup bridge memory/IO ranges & resources 140 * TODO: Handle firmware setting up a legacy ISA mem base 141 */ 142 hose_a->io_space.start = PPC405_PCI_LOWER_IO; 143 hose_a->io_space.end = PPC405_PCI_UPPER_IO; 144 hose_a->mem_space.start = new_pmm_min; 145 hose_a->mem_space.end = new_pmm_max; 146 hose_a->io_base_phys = PPC405_PCI_PHY_IO_BASE; 147 hose_a->io_base_virt = ioremap(hose_a->io_base_phys, 0x10000); 148 hose_a->io_resource.start = 0; 149 hose_a->io_resource.end = PPC405_PCI_UPPER_IO - PPC405_PCI_LOWER_IO; 150 hose_a->io_resource.flags = IORESOURCE_IO; 151 hose_a->io_resource.name = "PCI I/O"; 152 hose_a->mem_resources[0].start = new_pmm_min; 153 hose_a->mem_resources[0].end = new_pmm_max; 154 hose_a->mem_resources[0].flags = IORESOURCE_MEM; 155 hose_a->mem_resources[0].name = "PCI Memory"; 156 isa_io_base = (int) hose_a->io_base_virt; 157 isa_mem_base = 0; /* ISA not implemented */ 158 ISA_DMA_THRESHOLD = 0x00ffffff; /* ??? ISA not implemented */ 159 160 /* Scan busses & initial setup by pci_auto */ 161 hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno); 162 hose_a->last_busno = 0; 163 164 /* Setup ppc_md */ 165 ppc_md.pcibios_fixup = NULL; 166 ppc_md.pci_exclude_device = ppc4xx_exclude_device; 167 ppc_md.pcibios_fixup_resources = ppc405_pcibios_fixup_resources; 168 ppc_md.pci_swizzle = common_swizzle; 169 ppc_md.pci_map_irq = ppc405_map_irq; 170} 171