18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * SDK7786 FPGA PCIe mux handling 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2010 Paul Mundt 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "PCI: " fmt 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/pci.h> 128c2ecf20Sopenharmony_ci#include <mach/fpga.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* 158c2ecf20Sopenharmony_ci * The SDK7786 FPGA supports mangling of most of the slots in some way or 168c2ecf20Sopenharmony_ci * another. Slots 3/4 are special in that only one can be supported at a 178c2ecf20Sopenharmony_ci * time, and both appear on port 3 to the PCI bus scan. Enabling slot 4 188c2ecf20Sopenharmony_ci * (the horizontal edge connector) will disable slot 3 entirely. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Misconfigurations can be detected through the FPGA via the slot 218c2ecf20Sopenharmony_ci * resistors to determine card presence. Hotplug remains unsupported. 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_cistatic unsigned int slot4en __initdata; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cichar *__init pcibios_setup(char *str) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci if (strcmp(str, "slot4en") == 0) { 288c2ecf20Sopenharmony_ci slot4en = 1; 298c2ecf20Sopenharmony_ci return NULL; 308c2ecf20Sopenharmony_ci } 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci return str; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic int __init sdk7786_pci_init(void) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci u16 data = fpga_read_reg(PCIECR); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci /* 408c2ecf20Sopenharmony_ci * Enable slot #4 if it's been specified on the command line. 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * Optionally reroute if slot #4 has a card present while slot #3 438c2ecf20Sopenharmony_ci * does not, regardless of command line value. 448c2ecf20Sopenharmony_ci * 458c2ecf20Sopenharmony_ci * Card presence is logically inverted. 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci slot4en ?: (!(data & PCIECR_PRST4) && (data & PCIECR_PRST3)); 488c2ecf20Sopenharmony_ci if (slot4en) { 498c2ecf20Sopenharmony_ci pr_info("Activating PCIe slot#4 (disabling slot#3)\n"); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci data &= ~PCIECR_PCIEMUX1; 528c2ecf20Sopenharmony_ci fpga_write_reg(data, PCIECR); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci /* Warn about forced rerouting if slot#3 is occupied */ 558c2ecf20Sopenharmony_ci if ((data & PCIECR_PRST3) == 0) { 568c2ecf20Sopenharmony_ci pr_warn("Unreachable card detected in slot#3\n"); 578c2ecf20Sopenharmony_ci return -EBUSY; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci } else 608c2ecf20Sopenharmony_ci pr_info("PCIe slot#4 disabled\n"); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci return 0; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_cipostcore_initcall(sdk7786_pci_init); 65