| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |  | 
|  | 26 | extern void bios_fixup(struct pci_controller *, struct pcil0_regs *); | 
|  | 27 | extern int ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, | 
|  | 28 | unsigned char pin); | 
|  | 29 |  | 
|  | 30 | void | 
|  | 31 | ppc405_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 |  | 
|  | 67 | static int | 
|  | 68 | ppc4xx_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 |  | 
|  | 77 | void | 
|  | 78 | ppc4xx_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 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | 
| Simon Arlott | a8de5ce | 2007-05-12 05:42:54 +1000 | [diff] [blame] | 140 | * TODO: Handle firmware setting up a legacy ISA mem base | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | } |