1/* 2 * Support for indirect PCI bridges. 3 * 4 * Copyright (C) 1998 Gabriel Paubert. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 * 11 * "Temporary" MPC8548 Errata file - 12 * The standard indirect_pci code should work with future silicon versions. 13 */ 14 15#include <linux/kernel.h> 16#include <linux/pci.h> 17#include <linux/delay.h> 18#include <linux/string.h> 19#include <linux/init.h> 20#include <linux/bootmem.h> 21 22#include <asm/io.h> 23#include <asm/prom.h> 24#include <asm/pci-bridge.h> 25#include <asm/machdep.h> 26 27#define PCI_CFG_OUT out_be32 28 29/* ERRATA PCI-Ex 14 PCIE Controller timeout */ 30#define PCIE_FIX out_be32(hose->cfg_addr+0x4, 0x0400ffff) 31 32 33static int 34indirect_read_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset, 35 int len, u32 *val) 36{ 37 struct pci_controller *hose = bus->sysdata; 38 volatile void __iomem *cfg_data; 39 u32 temp; 40 41 if (ppc_md.pci_exclude_device) 42 if (ppc_md.pci_exclude_device(bus->number, devfn)) 43 return PCIBIOS_DEVICE_NOT_FOUND; 44 45 /* Possible artifact of CDCpp50937 needs further investigation */ 46 if (devfn != 0x0 && bus->number == 0xff) 47 return PCIBIOS_DEVICE_NOT_FOUND; 48 49 PCIE_FIX; 50 if (bus->number == 0xff) { 51 PCI_CFG_OUT(hose->cfg_addr, 52 (0x80000000 | ((offset & 0xf00) << 16) | 53 ((bus->number - hose->bus_offset) << 16) 54 | (devfn << 8) | ((offset & 0xfc) ))); 55 } else { 56 PCI_CFG_OUT(hose->cfg_addr, 57 (0x80000001 | ((offset & 0xf00) << 16) | 58 ((bus->number - hose->bus_offset) << 16) 59 | (devfn << 8) | ((offset & 0xfc) ))); 60 } 61 62 /* 63 * Note: the caller has already checked that offset is 64 * suitably aligned and that len is 1, 2 or 4. 65 */ 66 /* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */ 67 cfg_data = hose->cfg_data; 68 PCIE_FIX; 69 temp = in_le32(cfg_data); 70 switch (len) { 71 case 1: 72 *val = (temp >> (((offset & 3))*8)) & 0xff; 73 break; 74 case 2: 75 *val = (temp >> (((offset & 3))*8)) & 0xffff; 76 break; 77 default: 78 *val = temp; 79 break; 80 } 81 return PCIBIOS_SUCCESSFUL; 82} 83 84static int 85indirect_write_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset, 86 int len, u32 val) 87{ 88 struct pci_controller *hose = bus->sysdata; 89 volatile void __iomem *cfg_data; 90 u32 temp; 91 92 if (ppc_md.pci_exclude_device) 93 if (ppc_md.pci_exclude_device(bus->number, devfn)) 94 return PCIBIOS_DEVICE_NOT_FOUND; 95 96 /* Possible artifact of CDCpp50937 needs further investigation */ 97 if (devfn != 0x0 && bus->number == 0xff) 98 return PCIBIOS_DEVICE_NOT_FOUND; 99 100 PCIE_FIX; 101 if (bus->number == 0xff) { 102 PCI_CFG_OUT(hose->cfg_addr, 103 (0x80000000 | ((offset & 0xf00) << 16) | 104 ((bus->number - hose->bus_offset) << 16) 105 | (devfn << 8) | ((offset & 0xfc) ))); 106 } else { 107 PCI_CFG_OUT(hose->cfg_addr, 108 (0x80000001 | ((offset & 0xf00) << 16) | 109 ((bus->number - hose->bus_offset) << 16) 110 | (devfn << 8) | ((offset & 0xfc) ))); 111 } 112 113 /* 114 * Note: the caller has already checked that offset is 115 * suitably aligned and that len is 1, 2 or 4. 116 */ 117 /* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */ 118 cfg_data = hose->cfg_data; 119 switch (len) { 120 case 1: 121 PCIE_FIX; 122 temp = in_le32(cfg_data); 123 temp = (temp & ~(0xff << ((offset & 3) * 8))) | 124 (val << ((offset & 3) * 8)); 125 PCIE_FIX; 126 out_le32(cfg_data, temp); 127 break; 128 case 2: 129 PCIE_FIX; 130 temp = in_le32(cfg_data); 131 temp = (temp & ~(0xffff << ((offset & 3) * 8))); 132 temp |= (val << ((offset & 3) * 8)) ; 133 PCIE_FIX; 134 out_le32(cfg_data, temp); 135 break; 136 default: 137 PCIE_FIX; 138 out_le32(cfg_data, val); 139 break; 140 } 141 PCIE_FIX; 142 return PCIBIOS_SUCCESSFUL; 143} 144 145static struct pci_ops indirect_pcie_ops = { 146 indirect_read_config_pcie, 147 indirect_write_config_pcie 148}; 149 150void __init 151setup_indirect_pcie_nomap(struct pci_controller* hose, void __iomem * cfg_addr, 152 void __iomem * cfg_data) 153{ 154 hose->cfg_addr = cfg_addr; 155 hose->cfg_data = cfg_data; 156 hose->ops = &indirect_pcie_ops; 157} 158 159void __init 160setup_indirect_pcie(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data) 161{ 162 unsigned long base = cfg_addr & PAGE_MASK; 163 void __iomem *mbase, *addr, *data; 164 165 mbase = ioremap(base, PAGE_SIZE); 166 addr = mbase + (cfg_addr & ~PAGE_MASK); 167 if ((cfg_data & PAGE_MASK) != base) 168 mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE); 169 data = mbase + (cfg_data & ~PAGE_MASK); 170 setup_indirect_pcie_nomap(hose, addr, data); 171} 172