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