1/* 2 * PCI support for Xilinx plbv46_pci soft-core which can be used on 3 * Xilinx Virtex ML410 / ML510 boards. 4 * 5 * Copyright 2009 Roderick Colenbrander 6 * Copyright 2009 Secret Lab Technologies Ltd. 7 * 8 * The pci bridge fixup code was copied from ppc4xx_pci.c and was written 9 * by Benjamin Herrenschmidt. 10 * Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. 11 * 12 * This file is licensed under the terms of the GNU General Public License 13 * version 2. This program is licensed "as is" without any warranty of any 14 * kind, whether express or implied. 15 */ 16 17#include <linux/ioport.h> 18#include <linux/of.h> 19#include <linux/pci.h> 20#include <mm/mmu_decl.h> 21#include <asm/io.h> 22#include <asm/xilinx_pci.h> 23 24#define XPLB_PCI_ADDR 0x10c 25#define XPLB_PCI_DATA 0x110 26#define XPLB_PCI_BUS 0x114 27 28#define PCI_HOST_ENABLE_CMD PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY 29 30static const struct of_device_id xilinx_pci_match[] = { 31 { .compatible = "xlnx,plbv46-pci-1.03.a", }, 32 {} 33}; 34 35/** 36 * xilinx_pci_fixup_bridge - Block Xilinx PHB configuration. 37 */ 38static void xilinx_pci_fixup_bridge(struct pci_dev *dev) 39{ 40 struct pci_controller *hose; 41 int i; 42 43 if (dev->devfn || dev->bus->self) 44 return; 45 46 hose = pci_bus_to_host(dev->bus); 47 if (!hose) 48 return; 49 50 if (!of_match_node(xilinx_pci_match, hose->dn)) 51 return; 52 53 /* Hide the PCI host BARs from the kernel as their content doesn't 54 * fit well in the resource management 55 */ 56 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { 57 dev->resource[i].start = 0; 58 dev->resource[i].end = 0; 59 dev->resource[i].flags = 0; 60 } 61 62 dev_info(&dev->dev, "Hiding Xilinx plb-pci host bridge resources %s\n", 63 pci_name(dev)); 64} 65DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, xilinx_pci_fixup_bridge); 66 67/** 68 * xilinx_pci_exclude_device - Don't do config access for non-root bus 69 * 70 * This is a hack. Config access to any bus other than bus 0 does not 71 * currently work on the ML510 so we prevent it here. 72 */ 73static int 74xilinx_pci_exclude_device(struct pci_controller *hose, u_char bus, u8 devfn) 75{ 76 return (bus != 0); 77} 78 79/** 80 * xilinx_pci_init - Find and register a Xilinx PCI host bridge 81 */ 82void __init xilinx_pci_init(void) 83{ 84 struct pci_controller *hose; 85 struct resource r; 86 void __iomem *pci_reg; 87 struct device_node *pci_node; 88 89 pci_node = of_find_matching_node(NULL, xilinx_pci_match); 90 if(!pci_node) 91 return; 92 93 if (of_address_to_resource(pci_node, 0, &r)) { 94 pr_err("xilinx-pci: cannot resolve base address\n"); 95 return; 96 } 97 98 hose = pcibios_alloc_controller(pci_node); 99 if (!hose) { 100 pr_err("xilinx-pci: pcibios_alloc_controller() failed\n"); 101 return; 102 } 103 104 /* Setup config space */ 105 setup_indirect_pci(hose, r.start + XPLB_PCI_ADDR, 106 r.start + XPLB_PCI_DATA, 107 PPC_INDIRECT_TYPE_SET_CFG_TYPE); 108 109 /* According to the xilinx plbv46_pci documentation the soft-core starts 110 * a self-init when the bus master enable bit is set. Without this bit 111 * set the pci bus can't be scanned. 112 */ 113 early_write_config_word(hose, 0, 0, PCI_COMMAND, PCI_HOST_ENABLE_CMD); 114 115 /* Set the max latency timer to 255 */ 116 early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0xff); 117 118 /* Set the max bus number to 255 */ 119 pci_reg = of_iomap(pci_node, 0); 120 out_8(pci_reg + XPLB_PCI_BUS, 0xff); 121 iounmap(pci_reg); 122 123 /* Nothing past the root bridge is working right now. By default 124 * exclude config access to anything except bus 0 */ 125 if (!ppc_md.pci_exclude_device) 126 ppc_md.pci_exclude_device = xilinx_pci_exclude_device; 127 128 /* Register the host bridge with the linux kernel! */ 129 pci_process_bridge_OF_ranges(hose, pci_node, 1); 130 131 pr_info("xilinx-pci: Registered PCI host bridge\n"); 132} 133