10dad5d26SRalf Baechle /* 20dad5d26SRalf Baechle * Copyright (C) 1999, 2000, 2004, 2005 MIPS Technologies, Inc. 30dad5d26SRalf Baechle * All rights reserved. 40dad5d26SRalf Baechle * Authors: Carsten Langgaard <carstenl@mips.com> 50dad5d26SRalf Baechle * Maciej W. Rozycki <macro@mips.com> 60dad5d26SRalf Baechle * 70dad5d26SRalf Baechle * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) 80dad5d26SRalf Baechle * 90dad5d26SRalf Baechle * This program is free software; you can distribute it and/or modify it 100dad5d26SRalf Baechle * under the terms of the GNU General Public License (Version 2) as 110dad5d26SRalf Baechle * published by the Free Software Foundation. 120dad5d26SRalf Baechle * 130dad5d26SRalf Baechle * This program is distributed in the hope it will be useful, but WITHOUT 140dad5d26SRalf Baechle * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 150dad5d26SRalf Baechle * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 160dad5d26SRalf Baechle * for more details. 170dad5d26SRalf Baechle * 180dad5d26SRalf Baechle * You should have received a copy of the GNU General Public License along 190dad5d26SRalf Baechle * with this program; if not, write to the Free Software Foundation, Inc., 200dad5d26SRalf Baechle * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 210dad5d26SRalf Baechle * 220dad5d26SRalf Baechle * MIPS boards specific PCI support. 230dad5d26SRalf Baechle */ 240dad5d26SRalf Baechle #include <linux/types.h> 250dad5d26SRalf Baechle #include <linux/pci.h> 260dad5d26SRalf Baechle #include <linux/kernel.h> 270dad5d26SRalf Baechle #include <linux/init.h> 280dad5d26SRalf Baechle 290dad5d26SRalf Baechle #include <asm/gt64120.h> 30e83f7e02SPaul Burton #include <asm/mips-cps.h> 310dad5d26SRalf Baechle #include <asm/mips-boards/generic.h> 320dad5d26SRalf Baechle #include <asm/mips-boards/bonito64.h> 330dad5d26SRalf Baechle #include <asm/mips-boards/msc01_pci.h> 340dad5d26SRalf Baechle 350dad5d26SRalf Baechle static struct resource bonito64_mem_resource = { 360dad5d26SRalf Baechle .name = "Bonito PCI MEM", 370dad5d26SRalf Baechle .flags = IORESOURCE_MEM, 380dad5d26SRalf Baechle }; 390dad5d26SRalf Baechle 400dad5d26SRalf Baechle static struct resource bonito64_io_resource = { 410dad5d26SRalf Baechle .name = "Bonito PCI I/O", 420dad5d26SRalf Baechle .start = 0x00000000UL, 430dad5d26SRalf Baechle .end = 0x000fffffUL, 440dad5d26SRalf Baechle .flags = IORESOURCE_IO, 450dad5d26SRalf Baechle }; 460dad5d26SRalf Baechle 470dad5d26SRalf Baechle static struct resource gt64120_mem_resource = { 480dad5d26SRalf Baechle .name = "GT-64120 PCI MEM", 490dad5d26SRalf Baechle .flags = IORESOURCE_MEM, 500dad5d26SRalf Baechle }; 510dad5d26SRalf Baechle 520dad5d26SRalf Baechle static struct resource gt64120_io_resource = { 530dad5d26SRalf Baechle .name = "GT-64120 PCI I/O", 540dad5d26SRalf Baechle .flags = IORESOURCE_IO, 550dad5d26SRalf Baechle }; 560dad5d26SRalf Baechle 570dad5d26SRalf Baechle static struct resource msc_mem_resource = { 580dad5d26SRalf Baechle .name = "MSC PCI MEM", 590dad5d26SRalf Baechle .flags = IORESOURCE_MEM, 600dad5d26SRalf Baechle }; 610dad5d26SRalf Baechle 620dad5d26SRalf Baechle static struct resource msc_io_resource = { 630dad5d26SRalf Baechle .name = "MSC PCI I/O", 640dad5d26SRalf Baechle .flags = IORESOURCE_IO, 650dad5d26SRalf Baechle }; 660dad5d26SRalf Baechle 670dad5d26SRalf Baechle extern struct pci_ops bonito64_pci_ops; 680dad5d26SRalf Baechle extern struct pci_ops gt64xxx_pci0_ops; 690dad5d26SRalf Baechle extern struct pci_ops msc_pci_ops; 700dad5d26SRalf Baechle 710dad5d26SRalf Baechle static struct pci_controller bonito64_controller = { 720dad5d26SRalf Baechle .pci_ops = &bonito64_pci_ops, 730dad5d26SRalf Baechle .io_resource = &bonito64_io_resource, 740dad5d26SRalf Baechle .mem_resource = &bonito64_mem_resource, 750dad5d26SRalf Baechle .io_offset = 0x00000000UL, 760dad5d26SRalf Baechle }; 770dad5d26SRalf Baechle 780dad5d26SRalf Baechle static struct pci_controller gt64120_controller = { 790dad5d26SRalf Baechle .pci_ops = >64xxx_pci0_ops, 800dad5d26SRalf Baechle .io_resource = >64120_io_resource, 810dad5d26SRalf Baechle .mem_resource = >64120_mem_resource, 820dad5d26SRalf Baechle }; 830dad5d26SRalf Baechle 840dad5d26SRalf Baechle static struct pci_controller msc_controller = { 850dad5d26SRalf Baechle .pci_ops = &msc_pci_ops, 860dad5d26SRalf Baechle .io_resource = &msc_io_resource, 870dad5d26SRalf Baechle .mem_resource = &msc_mem_resource, 880dad5d26SRalf Baechle }; 890dad5d26SRalf Baechle 900dad5d26SRalf Baechle void __init mips_pcibios_init(void) 910dad5d26SRalf Baechle { 920dad5d26SRalf Baechle struct pci_controller *controller; 930dad5d26SRalf Baechle resource_size_t start, end, map, start1, end1, map1, map2, map3, mask; 940dad5d26SRalf Baechle 950dad5d26SRalf Baechle switch (mips_revision_sconid) { 960dad5d26SRalf Baechle case MIPS_REVISION_SCON_GT64120: 970dad5d26SRalf Baechle /* 980dad5d26SRalf Baechle * Due to a bug in the Galileo system controller, we need 990dad5d26SRalf Baechle * to setup the PCI BAR for the Galileo internal registers. 1000dad5d26SRalf Baechle * This should be done in the bios/bootprom and will be 1010dad5d26SRalf Baechle * fixed in a later revision of YAMON (the MIPS boards 1020dad5d26SRalf Baechle * boot prom). 1030dad5d26SRalf Baechle */ 1040dad5d26SRalf Baechle GT_WRITE(GT_PCI0_CFGADDR_OFS, 1050dad5d26SRalf Baechle (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | /* Local bus */ 1060dad5d26SRalf Baechle (0 << GT_PCI0_CFGADDR_DEVNUM_SHF) | /* GT64120 dev */ 1070dad5d26SRalf Baechle (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | /* Function 0*/ 1080dad5d26SRalf Baechle ((0x20/4) << GT_PCI0_CFGADDR_REGNUM_SHF) | /* BAR 4*/ 1090dad5d26SRalf Baechle GT_PCI0_CFGADDR_CONFIGEN_BIT); 1100dad5d26SRalf Baechle 1110dad5d26SRalf Baechle /* Perform the write */ 1120dad5d26SRalf Baechle GT_WRITE(GT_PCI0_CFGDATA_OFS, CPHYSADDR(MIPS_GT_BASE)); 1130dad5d26SRalf Baechle 1140dad5d26SRalf Baechle /* Set up resource ranges from the controller's registers. */ 1150dad5d26SRalf Baechle start = GT_READ(GT_PCI0M0LD_OFS); 1160dad5d26SRalf Baechle end = GT_READ(GT_PCI0M0HD_OFS); 1170dad5d26SRalf Baechle map = GT_READ(GT_PCI0M0REMAP_OFS); 1180dad5d26SRalf Baechle end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK); 1190dad5d26SRalf Baechle start1 = GT_READ(GT_PCI0M1LD_OFS); 1200dad5d26SRalf Baechle end1 = GT_READ(GT_PCI0M1HD_OFS); 1210dad5d26SRalf Baechle map1 = GT_READ(GT_PCI0M1REMAP_OFS); 1220dad5d26SRalf Baechle end1 = (end1 & GT_PCI_HD_MSK) | (start1 & ~GT_PCI_HD_MSK); 1230dad5d26SRalf Baechle /* Cannot support multiple windows, use the wider. */ 1240dad5d26SRalf Baechle if (end1 - start1 > end - start) { 1250dad5d26SRalf Baechle start = start1; 1260dad5d26SRalf Baechle end = end1; 1270dad5d26SRalf Baechle map = map1; 1280dad5d26SRalf Baechle } 1290dad5d26SRalf Baechle mask = ~(start ^ end); 1300dad5d26SRalf Baechle /* We don't support remapping with a discontiguous mask. */ 1310dad5d26SRalf Baechle BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) && 1320dad5d26SRalf Baechle mask != ~((mask & -mask) - 1)); 1330dad5d26SRalf Baechle gt64120_mem_resource.start = start; 1340dad5d26SRalf Baechle gt64120_mem_resource.end = end; 1350dad5d26SRalf Baechle gt64120_controller.mem_offset = (start & mask) - (map & mask); 1360dad5d26SRalf Baechle /* Addresses are 36-bit, so do shifts in the destinations. */ 1370dad5d26SRalf Baechle gt64120_mem_resource.start <<= GT_PCI_DCRM_SHF; 1380dad5d26SRalf Baechle gt64120_mem_resource.end <<= GT_PCI_DCRM_SHF; 1390dad5d26SRalf Baechle gt64120_mem_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1; 1400dad5d26SRalf Baechle gt64120_controller.mem_offset <<= GT_PCI_DCRM_SHF; 1410dad5d26SRalf Baechle 1420dad5d26SRalf Baechle start = GT_READ(GT_PCI0IOLD_OFS); 1430dad5d26SRalf Baechle end = GT_READ(GT_PCI0IOHD_OFS); 1440dad5d26SRalf Baechle map = GT_READ(GT_PCI0IOREMAP_OFS); 1450dad5d26SRalf Baechle end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK); 1460dad5d26SRalf Baechle mask = ~(start ^ end); 1470dad5d26SRalf Baechle /* We don't support remapping with a discontiguous mask. */ 1480dad5d26SRalf Baechle BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) && 1490dad5d26SRalf Baechle mask != ~((mask & -mask) - 1)); 1500dad5d26SRalf Baechle gt64120_io_resource.start = map & mask; 1510dad5d26SRalf Baechle gt64120_io_resource.end = (map & mask) | ~mask; 1520dad5d26SRalf Baechle gt64120_controller.io_offset = 0; 1530dad5d26SRalf Baechle /* Addresses are 36-bit, so do shifts in the destinations. */ 1540dad5d26SRalf Baechle gt64120_io_resource.start <<= GT_PCI_DCRM_SHF; 1550dad5d26SRalf Baechle gt64120_io_resource.end <<= GT_PCI_DCRM_SHF; 1560dad5d26SRalf Baechle gt64120_io_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1; 1570dad5d26SRalf Baechle 1580dad5d26SRalf Baechle controller = >64120_controller; 1590dad5d26SRalf Baechle break; 1600dad5d26SRalf Baechle 1610dad5d26SRalf Baechle case MIPS_REVISION_SCON_BONITO: 1620dad5d26SRalf Baechle /* Set up resource ranges from the controller's registers. */ 1630dad5d26SRalf Baechle map = BONITO_PCIMAP; 1640dad5d26SRalf Baechle map1 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO0) >> 1650dad5d26SRalf Baechle BONITO_PCIMAP_PCIMAP_LO0_SHIFT; 1660dad5d26SRalf Baechle map2 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO1) >> 1670dad5d26SRalf Baechle BONITO_PCIMAP_PCIMAP_LO1_SHIFT; 1680dad5d26SRalf Baechle map3 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO2) >> 1690dad5d26SRalf Baechle BONITO_PCIMAP_PCIMAP_LO2_SHIFT; 1700dad5d26SRalf Baechle /* Combine as many adjacent windows as possible. */ 1710dad5d26SRalf Baechle map = map1; 1720dad5d26SRalf Baechle start = BONITO_PCILO0_BASE; 1730dad5d26SRalf Baechle end = 1; 1740dad5d26SRalf Baechle if (map3 == map2 + 1) { 1750dad5d26SRalf Baechle map = map2; 1760dad5d26SRalf Baechle start = BONITO_PCILO1_BASE; 1770dad5d26SRalf Baechle end++; 1780dad5d26SRalf Baechle } 1790dad5d26SRalf Baechle if (map2 == map1 + 1) { 1800dad5d26SRalf Baechle map = map1; 1810dad5d26SRalf Baechle start = BONITO_PCILO0_BASE; 1820dad5d26SRalf Baechle end++; 1830dad5d26SRalf Baechle } 1840dad5d26SRalf Baechle bonito64_mem_resource.start = start; 1850dad5d26SRalf Baechle bonito64_mem_resource.end = start + 1860dad5d26SRalf Baechle BONITO_PCIMAP_WINBASE(end) - 1; 1870dad5d26SRalf Baechle bonito64_controller.mem_offset = start - 1880dad5d26SRalf Baechle BONITO_PCIMAP_WINBASE(map); 1890dad5d26SRalf Baechle 1900dad5d26SRalf Baechle controller = &bonito64_controller; 1910dad5d26SRalf Baechle break; 1920dad5d26SRalf Baechle 1930dad5d26SRalf Baechle case MIPS_REVISION_SCON_SOCIT: 1940dad5d26SRalf Baechle case MIPS_REVISION_SCON_ROCIT: 1950dad5d26SRalf Baechle case MIPS_REVISION_SCON_SOCITSC: 1960dad5d26SRalf Baechle case MIPS_REVISION_SCON_SOCITSCP: 1970dad5d26SRalf Baechle /* Set up resource ranges from the controller's registers. */ 1980dad5d26SRalf Baechle MSC_READ(MSC01_PCI_SC2PMBASL, start); 1990dad5d26SRalf Baechle MSC_READ(MSC01_PCI_SC2PMMSKL, mask); 2000dad5d26SRalf Baechle MSC_READ(MSC01_PCI_SC2PMMAPL, map); 2010dad5d26SRalf Baechle msc_mem_resource.start = start & mask; 2020dad5d26SRalf Baechle msc_mem_resource.end = (start & mask) | ~mask; 2030dad5d26SRalf Baechle msc_controller.mem_offset = (start & mask) - (map & mask); 204237036deSPaul Burton if (mips_cm_numiocu()) { 205237036deSPaul Burton write_gcr_reg0_base(start); 206237036deSPaul Burton write_gcr_reg0_mask(mask | 207237036deSPaul Burton CM_GCR_REGn_MASK_CMTGT_IOCU0); 208237036deSPaul Burton } 2090dad5d26SRalf Baechle MSC_READ(MSC01_PCI_SC2PIOBASL, start); 2100dad5d26SRalf Baechle MSC_READ(MSC01_PCI_SC2PIOMSKL, mask); 2110dad5d26SRalf Baechle MSC_READ(MSC01_PCI_SC2PIOMAPL, map); 2120dad5d26SRalf Baechle msc_io_resource.start = map & mask; 2130dad5d26SRalf Baechle msc_io_resource.end = (map & mask) | ~mask; 2140dad5d26SRalf Baechle msc_controller.io_offset = 0; 2150dad5d26SRalf Baechle ioport_resource.end = ~mask; 216237036deSPaul Burton if (mips_cm_numiocu()) { 217237036deSPaul Burton write_gcr_reg1_base(start); 218237036deSPaul Burton write_gcr_reg1_mask(mask | 219237036deSPaul Burton CM_GCR_REGn_MASK_CMTGT_IOCU0); 220237036deSPaul Burton } 2210dad5d26SRalf Baechle /* If ranges overlap I/O takes precedence. */ 2220dad5d26SRalf Baechle start = start & mask; 2230dad5d26SRalf Baechle end = start | ~mask; 2240dad5d26SRalf Baechle if ((start >= msc_mem_resource.start && 2250dad5d26SRalf Baechle start <= msc_mem_resource.end) || 2260dad5d26SRalf Baechle (end >= msc_mem_resource.start && 2270dad5d26SRalf Baechle end <= msc_mem_resource.end)) { 2280dad5d26SRalf Baechle /* Use the larger space. */ 2290dad5d26SRalf Baechle start = max(start, msc_mem_resource.start); 2300dad5d26SRalf Baechle end = min(end, msc_mem_resource.end); 2310dad5d26SRalf Baechle if (start - msc_mem_resource.start >= 2320dad5d26SRalf Baechle msc_mem_resource.end - end) 2330dad5d26SRalf Baechle msc_mem_resource.end = start - 1; 2340dad5d26SRalf Baechle else 2350dad5d26SRalf Baechle msc_mem_resource.start = end + 1; 2360dad5d26SRalf Baechle } 2370dad5d26SRalf Baechle 2380dad5d26SRalf Baechle controller = &msc_controller; 2390dad5d26SRalf Baechle break; 2400dad5d26SRalf Baechle default: 2410dad5d26SRalf Baechle return; 2420dad5d26SRalf Baechle } 2430dad5d26SRalf Baechle 24427547abfSDeng-Cheng Zhu /* PIIX4 ACPI starts at 0x1000 */ 24527547abfSDeng-Cheng Zhu if (controller->io_resource->start < 0x00001000UL) 24627547abfSDeng-Cheng Zhu controller->io_resource->start = 0x00001000UL; 2470dad5d26SRalf Baechle 2480dad5d26SRalf Baechle iomem_resource.end &= 0xfffffffffULL; /* 64 GB */ 2490dad5d26SRalf Baechle ioport_resource.end = controller->io_resource->end; 2500dad5d26SRalf Baechle 2510dad5d26SRalf Baechle controller->io_map_base = mips_io_port_base; 2520dad5d26SRalf Baechle 2530dad5d26SRalf Baechle register_pci_controller(controller); 2540dad5d26SRalf Baechle } 255