1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2006 PA Semi, Inc 4 * 5 * Authors: Kip Walker, PA Semi 6 * Olof Johansson, PA Semi 7 * 8 * Maintained by: Olof Johansson <olof@lixom.net> 9 * 10 * Based on arch/powerpc/platforms/maple/pci.c 11 */ 12 13 14 #include <linux/kernel.h> 15 #include <linux/of_address.h> 16 #include <linux/pci.h> 17 18 #include <asm/pci-bridge.h> 19 #include <asm/isa-bridge.h> 20 #include <asm/machdep.h> 21 22 #include <asm/ppc-pci.h> 23 24 #include "pasemi.h" 25 26 #define PA_PXP_CFA(bus, devfn, off) (((bus) << 20) | ((devfn) << 12) | (off)) 27 28 static inline int pa_pxp_offset_valid(u8 bus, u8 devfn, int offset) 29 { 30 /* Device 0 Function 0 is special: It's config space spans function 1 as 31 * well, so allow larger offset. It's really a two-function device but the 32 * second function does not probe. 33 */ 34 if (bus == 0 && devfn == 0) 35 return offset < 8192; 36 else 37 return offset < 4096; 38 } 39 40 static void volatile __iomem *pa_pxp_cfg_addr(struct pci_controller *hose, 41 u8 bus, u8 devfn, int offset) 42 { 43 return hose->cfg_data + PA_PXP_CFA(bus, devfn, offset); 44 } 45 46 static inline int is_root_port(int busno, int devfn) 47 { 48 return ((busno == 0) && (PCI_FUNC(devfn) < 4) && 49 ((PCI_SLOT(devfn) == 16) || (PCI_SLOT(devfn) == 17))); 50 } 51 52 static inline int is_5945_reg(int reg) 53 { 54 return (((reg >= 0x18) && (reg < 0x34)) || 55 ((reg >= 0x158) && (reg < 0x178))); 56 } 57 58 static int workaround_5945(struct pci_bus *bus, unsigned int devfn, 59 int offset, int len, u32 *val) 60 { 61 struct pci_controller *hose; 62 void volatile __iomem *addr, *dummy; 63 int byte; 64 u32 tmp; 65 66 if (!is_root_port(bus->number, devfn) || !is_5945_reg(offset)) 67 return 0; 68 69 hose = pci_bus_to_host(bus); 70 71 addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset & ~0x3); 72 byte = offset & 0x3; 73 74 /* Workaround bug 5945: write 0 to a dummy register before reading, 75 * and write back what we read. We must read/write the full 32-bit 76 * contents so we need to shift and mask by hand. 77 */ 78 dummy = pa_pxp_cfg_addr(hose, bus->number, devfn, 0x10); 79 out_le32(dummy, 0); 80 tmp = in_le32(addr); 81 out_le32(addr, tmp); 82 83 switch (len) { 84 case 1: 85 *val = (tmp >> (8*byte)) & 0xff; 86 break; 87 case 2: 88 if (byte == 0) 89 *val = tmp & 0xffff; 90 else 91 *val = (tmp >> 16) & 0xffff; 92 break; 93 default: 94 *val = tmp; 95 break; 96 } 97 98 return 1; 99 } 100 101 #ifdef CONFIG_PPC_PASEMI_NEMO 102 #define PXP_ERR_CFG_REG 0x4 103 #define PXP_IGNORE_PCIE_ERRORS 0x800 104 #define SB600_BUS 5 105 106 static void sb600_set_flag(int bus) 107 { 108 static void __iomem *iob_mapbase = NULL; 109 struct resource res; 110 struct device_node *dn; 111 int err; 112 113 if (iob_mapbase == NULL) { 114 dn = of_find_compatible_node(NULL, "isa", "pasemi,1682m-iob"); 115 if (!dn) { 116 pr_crit("NEMO SB600 missing iob node\n"); 117 return; 118 } 119 120 err = of_address_to_resource(dn, 0, &res); 121 of_node_put(dn); 122 123 if (err) { 124 pr_crit("NEMO SB600 missing resource\n"); 125 return; 126 } 127 128 pr_info("NEMO SB600 IOB base %08llx\n",res.start); 129 130 iob_mapbase = ioremap(res.start + 0x100, 0x94); 131 } 132 133 if (iob_mapbase != NULL) { 134 if (bus == SB600_BUS) { 135 /* 136 * This is the SB600's bus, tell the PCI-e root port 137 * to allow non-zero devices to enumerate. 138 */ 139 out_le32(iob_mapbase + PXP_ERR_CFG_REG, in_le32(iob_mapbase + PXP_ERR_CFG_REG) | PXP_IGNORE_PCIE_ERRORS); 140 } else { 141 /* 142 * Only scan device 0 on other busses 143 */ 144 out_le32(iob_mapbase + PXP_ERR_CFG_REG, in_le32(iob_mapbase + PXP_ERR_CFG_REG) & ~PXP_IGNORE_PCIE_ERRORS); 145 } 146 } 147 } 148 149 #else 150 151 static void sb600_set_flag(int bus) 152 { 153 } 154 #endif 155 156 static int pa_pxp_read_config(struct pci_bus *bus, unsigned int devfn, 157 int offset, int len, u32 *val) 158 { 159 struct pci_controller *hose; 160 void volatile __iomem *addr; 161 162 hose = pci_bus_to_host(bus); 163 if (!hose) 164 return PCIBIOS_DEVICE_NOT_FOUND; 165 166 if (!pa_pxp_offset_valid(bus->number, devfn, offset)) 167 return PCIBIOS_BAD_REGISTER_NUMBER; 168 169 if (workaround_5945(bus, devfn, offset, len, val)) 170 return PCIBIOS_SUCCESSFUL; 171 172 addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset); 173 174 sb600_set_flag(bus->number); 175 176 /* 177 * Note: the caller has already checked that offset is 178 * suitably aligned and that len is 1, 2 or 4. 179 */ 180 switch (len) { 181 case 1: 182 *val = in_8(addr); 183 break; 184 case 2: 185 *val = in_le16(addr); 186 break; 187 default: 188 *val = in_le32(addr); 189 break; 190 } 191 192 return PCIBIOS_SUCCESSFUL; 193 } 194 195 static int pa_pxp_write_config(struct pci_bus *bus, unsigned int devfn, 196 int offset, int len, u32 val) 197 { 198 struct pci_controller *hose; 199 void volatile __iomem *addr; 200 201 hose = pci_bus_to_host(bus); 202 if (!hose) 203 return PCIBIOS_DEVICE_NOT_FOUND; 204 205 if (!pa_pxp_offset_valid(bus->number, devfn, offset)) 206 return PCIBIOS_BAD_REGISTER_NUMBER; 207 208 addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset); 209 210 sb600_set_flag(bus->number); 211 212 /* 213 * Note: the caller has already checked that offset is 214 * suitably aligned and that len is 1, 2 or 4. 215 */ 216 switch (len) { 217 case 1: 218 out_8(addr, val); 219 break; 220 case 2: 221 out_le16(addr, val); 222 break; 223 default: 224 out_le32(addr, val); 225 break; 226 } 227 return PCIBIOS_SUCCESSFUL; 228 } 229 230 static struct pci_ops pa_pxp_ops = { 231 .read = pa_pxp_read_config, 232 .write = pa_pxp_write_config, 233 }; 234 235 static void __init setup_pa_pxp(struct pci_controller *hose) 236 { 237 hose->ops = &pa_pxp_ops; 238 hose->cfg_data = ioremap(0xe0000000, 0x10000000); 239 } 240 241 static int __init pas_add_bridge(struct device_node *dev) 242 { 243 struct pci_controller *hose; 244 245 pr_debug("Adding PCI host bridge %pOF\n", dev); 246 247 hose = pcibios_alloc_controller(dev); 248 if (!hose) 249 return -ENOMEM; 250 251 hose->first_busno = 0; 252 hose->last_busno = 0xff; 253 hose->controller_ops = pasemi_pci_controller_ops; 254 255 setup_pa_pxp(hose); 256 257 pr_info("Found PA-PXP PCI host bridge.\n"); 258 259 /* Interpret the "ranges" property */ 260 pci_process_bridge_OF_ranges(hose, dev, 1); 261 262 /* 263 * Scan for an isa bridge. This is needed to find the SB600 on the nemo 264 * and does nothing on machines without one. 265 */ 266 isa_bridge_find_early(hose); 267 268 return 0; 269 } 270 271 void __init pas_pci_init(void) 272 { 273 struct device_node *root = of_find_node_by_path("/"); 274 struct device_node *np; 275 int res; 276 277 pci_set_flags(PCI_SCAN_ALL_PCIE_DEVS); 278 279 np = of_find_compatible_node(root, NULL, "pasemi,rootbus"); 280 if (np) { 281 res = pas_add_bridge(np); 282 of_node_put(np); 283 } 284 of_node_put(root); 285 } 286 287 void __iomem *__init pasemi_pci_getcfgaddr(struct pci_dev *dev, int offset) 288 { 289 struct pci_controller *hose; 290 291 hose = pci_bus_to_host(dev->bus); 292 293 return (void __iomem *)pa_pxp_cfg_addr(hose, dev->bus->number, dev->devfn, offset); 294 } 295 296 struct pci_controller_ops pasemi_pci_controller_ops; 297
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.