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