18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 1999, 2000, 2004, 2005 MIPS Technologies, Inc. 48c2ecf20Sopenharmony_ci * All rights reserved. 58c2ecf20Sopenharmony_ci * Authors: Carsten Langgaard <carstenl@mips.com> 68c2ecf20Sopenharmony_ci * Maciej W. Rozycki <macro@mips.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * MIPS boards specific PCI support. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci#include <linux/types.h> 138c2ecf20Sopenharmony_ci#include <linux/pci.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <asm/gt64120.h> 188c2ecf20Sopenharmony_ci#include <asm/mips-cps.h> 198c2ecf20Sopenharmony_ci#include <asm/mips-boards/generic.h> 208c2ecf20Sopenharmony_ci#include <asm/mips-boards/bonito64.h> 218c2ecf20Sopenharmony_ci#include <asm/mips-boards/msc01_pci.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic struct resource bonito64_mem_resource = { 248c2ecf20Sopenharmony_ci .name = "Bonito PCI MEM", 258c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic struct resource bonito64_io_resource = { 298c2ecf20Sopenharmony_ci .name = "Bonito PCI I/O", 308c2ecf20Sopenharmony_ci .start = 0x00000000UL, 318c2ecf20Sopenharmony_ci .end = 0x000fffffUL, 328c2ecf20Sopenharmony_ci .flags = IORESOURCE_IO, 338c2ecf20Sopenharmony_ci}; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic struct resource gt64120_mem_resource = { 368c2ecf20Sopenharmony_ci .name = "GT-64120 PCI MEM", 378c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic struct resource gt64120_io_resource = { 418c2ecf20Sopenharmony_ci .name = "GT-64120 PCI I/O", 428c2ecf20Sopenharmony_ci .flags = IORESOURCE_IO, 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic struct resource msc_mem_resource = { 468c2ecf20Sopenharmony_ci .name = "MSC PCI MEM", 478c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic struct resource msc_io_resource = { 518c2ecf20Sopenharmony_ci .name = "MSC PCI I/O", 528c2ecf20Sopenharmony_ci .flags = IORESOURCE_IO, 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ciextern struct pci_ops bonito64_pci_ops; 568c2ecf20Sopenharmony_ciextern struct pci_ops gt64xxx_pci0_ops; 578c2ecf20Sopenharmony_ciextern struct pci_ops msc_pci_ops; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic struct pci_controller bonito64_controller = { 608c2ecf20Sopenharmony_ci .pci_ops = &bonito64_pci_ops, 618c2ecf20Sopenharmony_ci .io_resource = &bonito64_io_resource, 628c2ecf20Sopenharmony_ci .mem_resource = &bonito64_mem_resource, 638c2ecf20Sopenharmony_ci .io_offset = 0x00000000UL, 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic struct pci_controller gt64120_controller = { 678c2ecf20Sopenharmony_ci .pci_ops = >64xxx_pci0_ops, 688c2ecf20Sopenharmony_ci .io_resource = >64120_io_resource, 698c2ecf20Sopenharmony_ci .mem_resource = >64120_mem_resource, 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic struct pci_controller msc_controller = { 738c2ecf20Sopenharmony_ci .pci_ops = &msc_pci_ops, 748c2ecf20Sopenharmony_ci .io_resource = &msc_io_resource, 758c2ecf20Sopenharmony_ci .mem_resource = &msc_mem_resource, 768c2ecf20Sopenharmony_ci}; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_civoid __init mips_pcibios_init(void) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct pci_controller *controller; 818c2ecf20Sopenharmony_ci resource_size_t start, end, map, start1, end1, map1, map2, map3, mask; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci switch (mips_revision_sconid) { 848c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_GT64120: 858c2ecf20Sopenharmony_ci /* 868c2ecf20Sopenharmony_ci * Due to a bug in the Galileo system controller, we need 878c2ecf20Sopenharmony_ci * to setup the PCI BAR for the Galileo internal registers. 888c2ecf20Sopenharmony_ci * This should be done in the bios/bootprom and will be 898c2ecf20Sopenharmony_ci * fixed in a later revision of YAMON (the MIPS boards 908c2ecf20Sopenharmony_ci * boot prom). 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_ci GT_WRITE(GT_PCI0_CFGADDR_OFS, 938c2ecf20Sopenharmony_ci (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | /* Local bus */ 948c2ecf20Sopenharmony_ci (0 << GT_PCI0_CFGADDR_DEVNUM_SHF) | /* GT64120 dev */ 958c2ecf20Sopenharmony_ci (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | /* Function 0*/ 968c2ecf20Sopenharmony_ci ((0x20/4) << GT_PCI0_CFGADDR_REGNUM_SHF) | /* BAR 4*/ 978c2ecf20Sopenharmony_ci GT_PCI0_CFGADDR_CONFIGEN_BIT); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci /* Perform the write */ 1008c2ecf20Sopenharmony_ci GT_WRITE(GT_PCI0_CFGDATA_OFS, CPHYSADDR(MIPS_GT_BASE)); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci /* Set up resource ranges from the controller's registers. */ 1038c2ecf20Sopenharmony_ci start = GT_READ(GT_PCI0M0LD_OFS); 1048c2ecf20Sopenharmony_ci end = GT_READ(GT_PCI0M0HD_OFS); 1058c2ecf20Sopenharmony_ci map = GT_READ(GT_PCI0M0REMAP_OFS); 1068c2ecf20Sopenharmony_ci end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK); 1078c2ecf20Sopenharmony_ci start1 = GT_READ(GT_PCI0M1LD_OFS); 1088c2ecf20Sopenharmony_ci end1 = GT_READ(GT_PCI0M1HD_OFS); 1098c2ecf20Sopenharmony_ci map1 = GT_READ(GT_PCI0M1REMAP_OFS); 1108c2ecf20Sopenharmony_ci end1 = (end1 & GT_PCI_HD_MSK) | (start1 & ~GT_PCI_HD_MSK); 1118c2ecf20Sopenharmony_ci /* Cannot support multiple windows, use the wider. */ 1128c2ecf20Sopenharmony_ci if (end1 - start1 > end - start) { 1138c2ecf20Sopenharmony_ci start = start1; 1148c2ecf20Sopenharmony_ci end = end1; 1158c2ecf20Sopenharmony_ci map = map1; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci mask = ~(start ^ end); 1188c2ecf20Sopenharmony_ci /* We don't support remapping with a discontiguous mask. */ 1198c2ecf20Sopenharmony_ci BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) && 1208c2ecf20Sopenharmony_ci mask != ~((mask & -mask) - 1)); 1218c2ecf20Sopenharmony_ci gt64120_mem_resource.start = start; 1228c2ecf20Sopenharmony_ci gt64120_mem_resource.end = end; 1238c2ecf20Sopenharmony_ci gt64120_controller.mem_offset = (start & mask) - (map & mask); 1248c2ecf20Sopenharmony_ci /* Addresses are 36-bit, so do shifts in the destinations. */ 1258c2ecf20Sopenharmony_ci gt64120_mem_resource.start <<= GT_PCI_DCRM_SHF; 1268c2ecf20Sopenharmony_ci gt64120_mem_resource.end <<= GT_PCI_DCRM_SHF; 1278c2ecf20Sopenharmony_ci gt64120_mem_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1; 1288c2ecf20Sopenharmony_ci gt64120_controller.mem_offset <<= GT_PCI_DCRM_SHF; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci start = GT_READ(GT_PCI0IOLD_OFS); 1318c2ecf20Sopenharmony_ci end = GT_READ(GT_PCI0IOHD_OFS); 1328c2ecf20Sopenharmony_ci map = GT_READ(GT_PCI0IOREMAP_OFS); 1338c2ecf20Sopenharmony_ci end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK); 1348c2ecf20Sopenharmony_ci mask = ~(start ^ end); 1358c2ecf20Sopenharmony_ci /* We don't support remapping with a discontiguous mask. */ 1368c2ecf20Sopenharmony_ci BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) && 1378c2ecf20Sopenharmony_ci mask != ~((mask & -mask) - 1)); 1388c2ecf20Sopenharmony_ci gt64120_io_resource.start = map & mask; 1398c2ecf20Sopenharmony_ci gt64120_io_resource.end = (map & mask) | ~mask; 1408c2ecf20Sopenharmony_ci gt64120_controller.io_offset = 0; 1418c2ecf20Sopenharmony_ci /* Addresses are 36-bit, so do shifts in the destinations. */ 1428c2ecf20Sopenharmony_ci gt64120_io_resource.start <<= GT_PCI_DCRM_SHF; 1438c2ecf20Sopenharmony_ci gt64120_io_resource.end <<= GT_PCI_DCRM_SHF; 1448c2ecf20Sopenharmony_ci gt64120_io_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci controller = >64120_controller; 1478c2ecf20Sopenharmony_ci break; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_BONITO: 1508c2ecf20Sopenharmony_ci /* Set up resource ranges from the controller's registers. */ 1518c2ecf20Sopenharmony_ci map = BONITO_PCIMAP; 1528c2ecf20Sopenharmony_ci map1 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO0) >> 1538c2ecf20Sopenharmony_ci BONITO_PCIMAP_PCIMAP_LO0_SHIFT; 1548c2ecf20Sopenharmony_ci map2 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO1) >> 1558c2ecf20Sopenharmony_ci BONITO_PCIMAP_PCIMAP_LO1_SHIFT; 1568c2ecf20Sopenharmony_ci map3 = (BONITO_PCIMAP & BONITO_PCIMAP_PCIMAP_LO2) >> 1578c2ecf20Sopenharmony_ci BONITO_PCIMAP_PCIMAP_LO2_SHIFT; 1588c2ecf20Sopenharmony_ci /* Combine as many adjacent windows as possible. */ 1598c2ecf20Sopenharmony_ci map = map1; 1608c2ecf20Sopenharmony_ci start = BONITO_PCILO0_BASE; 1618c2ecf20Sopenharmony_ci end = 1; 1628c2ecf20Sopenharmony_ci if (map3 == map2 + 1) { 1638c2ecf20Sopenharmony_ci map = map2; 1648c2ecf20Sopenharmony_ci start = BONITO_PCILO1_BASE; 1658c2ecf20Sopenharmony_ci end++; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci if (map2 == map1 + 1) { 1688c2ecf20Sopenharmony_ci map = map1; 1698c2ecf20Sopenharmony_ci start = BONITO_PCILO0_BASE; 1708c2ecf20Sopenharmony_ci end++; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci bonito64_mem_resource.start = start; 1738c2ecf20Sopenharmony_ci bonito64_mem_resource.end = start + 1748c2ecf20Sopenharmony_ci BONITO_PCIMAP_WINBASE(end) - 1; 1758c2ecf20Sopenharmony_ci bonito64_controller.mem_offset = start - 1768c2ecf20Sopenharmony_ci BONITO_PCIMAP_WINBASE(map); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci controller = &bonito64_controller; 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_SOCIT: 1828c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_ROCIT: 1838c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_SOCITSC: 1848c2ecf20Sopenharmony_ci case MIPS_REVISION_SCON_SOCITSCP: 1858c2ecf20Sopenharmony_ci /* Set up resource ranges from the controller's registers. */ 1868c2ecf20Sopenharmony_ci MSC_READ(MSC01_PCI_SC2PMBASL, start); 1878c2ecf20Sopenharmony_ci MSC_READ(MSC01_PCI_SC2PMMSKL, mask); 1888c2ecf20Sopenharmony_ci MSC_READ(MSC01_PCI_SC2PMMAPL, map); 1898c2ecf20Sopenharmony_ci msc_mem_resource.start = start & mask; 1908c2ecf20Sopenharmony_ci msc_mem_resource.end = (start & mask) | ~mask; 1918c2ecf20Sopenharmony_ci msc_controller.mem_offset = (start & mask) - (map & mask); 1928c2ecf20Sopenharmony_ci if (mips_cps_numiocu(0)) { 1938c2ecf20Sopenharmony_ci write_gcr_reg0_base(start); 1948c2ecf20Sopenharmony_ci write_gcr_reg0_mask(mask | 1958c2ecf20Sopenharmony_ci CM_GCR_REGn_MASK_CMTGT_IOCU0); 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci MSC_READ(MSC01_PCI_SC2PIOBASL, start); 1988c2ecf20Sopenharmony_ci MSC_READ(MSC01_PCI_SC2PIOMSKL, mask); 1998c2ecf20Sopenharmony_ci MSC_READ(MSC01_PCI_SC2PIOMAPL, map); 2008c2ecf20Sopenharmony_ci msc_io_resource.start = map & mask; 2018c2ecf20Sopenharmony_ci msc_io_resource.end = (map & mask) | ~mask; 2028c2ecf20Sopenharmony_ci msc_controller.io_offset = 0; 2038c2ecf20Sopenharmony_ci ioport_resource.end = ~mask; 2048c2ecf20Sopenharmony_ci if (mips_cps_numiocu(0)) { 2058c2ecf20Sopenharmony_ci write_gcr_reg1_base(start); 2068c2ecf20Sopenharmony_ci write_gcr_reg1_mask(mask | 2078c2ecf20Sopenharmony_ci CM_GCR_REGn_MASK_CMTGT_IOCU0); 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci /* If ranges overlap I/O takes precedence. */ 2108c2ecf20Sopenharmony_ci start = start & mask; 2118c2ecf20Sopenharmony_ci end = start | ~mask; 2128c2ecf20Sopenharmony_ci if ((start >= msc_mem_resource.start && 2138c2ecf20Sopenharmony_ci start <= msc_mem_resource.end) || 2148c2ecf20Sopenharmony_ci (end >= msc_mem_resource.start && 2158c2ecf20Sopenharmony_ci end <= msc_mem_resource.end)) { 2168c2ecf20Sopenharmony_ci /* Use the larger space. */ 2178c2ecf20Sopenharmony_ci start = max(start, msc_mem_resource.start); 2188c2ecf20Sopenharmony_ci end = min(end, msc_mem_resource.end); 2198c2ecf20Sopenharmony_ci if (start - msc_mem_resource.start >= 2208c2ecf20Sopenharmony_ci msc_mem_resource.end - end) 2218c2ecf20Sopenharmony_ci msc_mem_resource.end = start - 1; 2228c2ecf20Sopenharmony_ci else 2238c2ecf20Sopenharmony_ci msc_mem_resource.start = end + 1; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci controller = &msc_controller; 2278c2ecf20Sopenharmony_ci break; 2288c2ecf20Sopenharmony_ci default: 2298c2ecf20Sopenharmony_ci return; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* PIIX4 ACPI starts at 0x1000 */ 2338c2ecf20Sopenharmony_ci if (controller->io_resource->start < 0x00001000UL) 2348c2ecf20Sopenharmony_ci controller->io_resource->start = 0x00001000UL; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci iomem_resource.end &= 0xfffffffffULL; /* 64 GB */ 2378c2ecf20Sopenharmony_ci ioport_resource.end = controller->io_resource->end; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci controller->io_map_base = mips_io_port_base; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci register_pci_controller(controller); 2428c2ecf20Sopenharmony_ci} 243