1/* 2 * Copyright (C) 1999, 2000, 2004, 2005 MIPS Technologies, Inc. 3 * All rights reserved. 4 * Authors: Carsten Langgaard <carstenl@mips.com> 5 * Maciej W. Rozycki <macro@mips.com> 6 * 7 * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) 8 * 9 * This program is free software; you can distribute it and/or modify it 10 * under the terms of the GNU General Public License (Version 2) as 11 * published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope it will be useful, but WITHOUT 14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 * for more details. 17 * 18 * You should have received a copy of the GNU General Public License along 19 * with this program; if not, write to the Free Software Foundation, Inc., 20 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 21 * 22 * MIPS boards specific PCI support. 23 */ 24#include <linux/types.h> 25#include <linux/pci.h> 26#include <linux/kernel.h> 27#include <linux/init.h> 28 29#include <asm/gt64120.h> 30#include <asm/mips-cm.h> 31#include <asm/mips-boards/generic.h> 32#include <asm/mips-boards/bonito64.h> 33#include <asm/mips-boards/msc01_pci.h> 34 35static struct resource bonito64_mem_resource = { 36 .name = "Bonito PCI MEM", 37 .flags = IORESOURCE_MEM, 38}; 39 40static struct resource bonito64_io_resource = { 41 .name = "Bonito PCI I/O", 42 .start = 0x00000000UL, 43 .end = 0x000fffffUL, 44 .flags = IORESOURCE_IO, 45}; 46 47static struct resource gt64120_mem_resource = { 48 .name = "GT-64120 PCI MEM", 49 .flags = IORESOURCE_MEM, 50}; 51 52static struct resource gt64120_io_resource = { 53 .name = "GT-64120 PCI I/O", 54 .flags = IORESOURCE_IO, 55}; 56 57static struct resource msc_mem_resource = { 58 .name = "MSC PCI MEM", 59 .flags = IORESOURCE_MEM, 60}; 61 62static struct resource msc_io_resource = { 63 .name = "MSC PCI I/O", 64 .flags = IORESOURCE_IO, 65}; 66 67extern struct pci_ops bonito64_pci_ops; 68extern struct pci_ops gt64xxx_pci0_ops; 69extern struct pci_ops msc_pci_ops; 70 71static struct pci_controller bonito64_controller = { 72 .pci_ops = &bonito64_pci_ops, 73 .io_resource = &bonito64_io_resource, 74 .mem_resource = &bonito64_mem_resource, 75 .io_offset = 0x00000000UL, 76}; 77 78static struct pci_controller gt64120_controller = { 79 .pci_ops = >64xxx_pci0_ops, 80 .io_resource = >64120_io_resource, 81 .mem_resource = >64120_mem_resource, 82}; 83 84static struct pci_controller msc_controller = { 85 .pci_ops = &msc_pci_ops, 86 .io_resource = &msc_io_resource, 87 .mem_resource = &msc_mem_resource, 88}; 89 90void __init mips_pcibios_init(void) 91{ 92 struct pci_controller *controller; 93 resource_size_t start, end, map, start1, end1, map1, map2, map3, mask; 94 95 switch (mips_revision_sconid) { 96 case MIPS_REVISION_SCON_GT64120: 97 /* 98 * Due to a bug in the Galileo system controller, we need 99 * to setup the PCI BAR for the Galileo internal registers. 100 * This should be done in the bios/bootprom and will be 101 * fixed in a later revision of YAMON (the MIPS boards 102 * boot prom). 103 */ 104 GT_WRITE(GT_PCI0_CFGADDR_OFS, 105 (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | /* Local bus */ 106 (0 << GT_PCI0_CFGADDR_DEVNUM_SHF) | /* GT64120 dev */ 107 (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | /* Function 0*/ 108 ((0x20/4) << GT_PCI0_CFGADDR_REGNUM_SHF) | /* BAR 4*/ 109 GT_PCI0_CFGADDR_CONFIGEN_BIT); 110 111 /* Perform the write */ 112 GT_WRITE(GT_PCI0_CFGDATA_OFS, CPHYSADDR(MIPS_GT_BASE)); 113 114 /* Set up resource ranges from the controller's registers. */ 115 start = GT_READ(GT_PCI0M0LD_OFS); 116 end = GT_READ(GT_PCI0M0HD_OFS); 117 map = GT_READ(GT_PCI0M0REMAP_OFS); 118 end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK); 119 start1 = GT_READ(GT_PCI0M1LD_OFS); 120 end1 = GT_READ(GT_PCI0M1HD_OFS); 121 map1 = GT_READ(GT_PCI0M1REMAP_OFS); 122 end1 = (end1 & GT_PCI_HD_MSK) | (start1 & ~GT_PCI_HD_MSK); 123 /* Cannot support multiple windows, use the wider. */ 124 if (end1 - start1 > end - start) { 125 start = start1; 126 end = end1; 127 map = map1; 128 } 129 mask = ~(start ^ end); 130 /* We don't support remapping with a discontiguous mask. */ 131 BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) && 132 mask != ~((mask & -mask) - 1)); 133 gt64120_mem_resource.start = start; 134 gt64120_mem_resource.end = end; 135 gt64120_controller.mem_offset = (start & mask) - (map & mask); 136 /* Addresses are 36-bit, so do shifts in the destinations. */ 137 gt64120_mem_resource.start <<= GT_PCI_DCRM_SHF; 138 gt64120_mem_resource.end <<= GT_PCI_DCRM_SHF; 139 gt64120_mem_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1; 140 gt64120_controller.mem_offset <<= GT_PCI_DCRM_SHF; 141 142 start = GT_READ(GT_PCI0IOLD_OFS); 143 end = GT_READ(GT_PCI0IOHD_OFS); 144 map = GT_READ(GT_PCI0IOREMAP_OFS); 145 end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK); 146 mask = ~(start ^ end); 147 /* We don't support remapping with a discontiguous mask. */ 148 BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) && 149 mask != ~((mask & -mask) - 1)); 150 gt64120_io_resource.start = map & mask; 151 gt64120_io_resource.end = (map & mask) | ~mask; 152 gt64120_controller.io_offset = 0; 153 /* Addresses are 36-bit, so do shifts in the destinations. */ 154 gt64120_io_resource.start <<= GT_PCI_DCRM_SHF; 155 gt64120_io_resource.end <<= GT_PCI_DCRM_SHF; 156 gt64120_io_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1; 157 158 controller = >64120_controller; 159 break; 160 161 case MIPS_REVISION_SCON_BONITO: 162 /* Set up resource ranges from the controller's registers. */ 163 map = BONITO_PCIMAP; 164 map1 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO0) >> 165 BONITO_PCIMAP_PCIMAP_LO0_SHIFT; 166 map2 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO1) >> 167 BONITO_PCIMAP_PCIMAP_LO1_SHIFT; 168 map3 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO2) >> 169 BONITO_PCIMAP_PCIMAP_LO2_SHIFT; 170 /* Combine as many adjacent windows as possible. */ 171 map = map1; 172 start = BONITO_PCILO0_BASE; 173 end = 1; 174 if (map3 == map2 + 1) { 175 map = map2; 176 start = BONITO_PCILO1_BASE; 177 end++; 178 } 179 if (map2 == map1 + 1) { 180 map = map1; 181 start = BONITO_PCILO0_BASE; 182 end++; 183 } 184 bonito64_mem_resource.start = start; 185 bonito64_mem_resource.end = start + 186 BONITO_PCIMAP_WINBASE(end) - 1; 187 bonito64_controller.mem_offset = start - 188 BONITO_PCIMAP_WINBASE(map); 189 190 controller = &bonito64_controller; 191 break; 192 193 case MIPS_REVISION_SCON_SOCIT: 194 case MIPS_REVISION_SCON_ROCIT: 195 case MIPS_REVISION_SCON_SOCITSC: 196 case MIPS_REVISION_SCON_SOCITSCP: 197 /* Set up resource ranges from the controller's registers. */ 198 MSC_READ(MSC01_PCI_SC2PMBASL, start); 199 MSC_READ(MSC01_PCI_SC2PMMSKL, mask); 200 MSC_READ(MSC01_PCI_SC2PMMAPL, map); 201 msc_mem_resource.start = start & mask; 202 msc_mem_resource.end = (start & mask) | ~mask; 203 msc_controller.mem_offset = (start & mask) - (map & mask); 204 if (mips_cm_numiocu()) { 205 write_gcr_reg0_base(start); 206 write_gcr_reg0_mask(mask | 207 CM_GCR_REGn_MASK_CMTGT_IOCU0); 208 } 209 MSC_READ(MSC01_PCI_SC2PIOBASL, start); 210 MSC_READ(MSC01_PCI_SC2PIOMSKL, mask); 211 MSC_READ(MSC01_PCI_SC2PIOMAPL, map); 212 msc_io_resource.start = map & mask; 213 msc_io_resource.end = (map & mask) | ~mask; 214 msc_controller.io_offset = 0; 215 ioport_resource.end = ~mask; 216 if (mips_cm_numiocu()) { 217 write_gcr_reg1_base(start); 218 write_gcr_reg1_mask(mask | 219 CM_GCR_REGn_MASK_CMTGT_IOCU0); 220 } 221 /* If ranges overlap I/O takes precedence. */ 222 start = start & mask; 223 end = start | ~mask; 224 if ((start >= msc_mem_resource.start && 225 start <= msc_mem_resource.end) || 226 (end >= msc_mem_resource.start && 227 end <= msc_mem_resource.end)) { 228 /* Use the larger space. */ 229 start = max(start, msc_mem_resource.start); 230 end = min(end, msc_mem_resource.end); 231 if (start - msc_mem_resource.start >= 232 msc_mem_resource.end - end) 233 msc_mem_resource.end = start - 1; 234 else 235 msc_mem_resource.start = end + 1; 236 } 237 238 controller = &msc_controller; 239 break; 240 default: 241 return; 242 } 243 244 /* PIIX4 ACPI starts at 0x1000 */ 245 if (controller->io_resource->start < 0x00001000UL) 246 controller->io_resource->start = 0x00001000UL; 247 248 iomem_resource.end &= 0xfffffffffULL; /* 64 GB */ 249 ioport_resource.end = controller->io_resource->end; 250 251 controller->io_map_base = mips_io_port_base; 252 253 register_pci_controller(controller); 254} 255