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 12 #include <linux/kernel.h> 13 #include <linux/pci.h> 14 #include <linux/delay.h> 15 #include <linux/string.h> 16 #include <linux/init.h> 17 18 #include <asm/io.h> 19 #include <asm/prom.h> 20 #include <asm/pci-bridge.h> 21 #include <asm/machdep.h> 22 23 static int 24 indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset, 25 int len, u32 *val) 26 { 27 struct pci_controller *hose = bus->sysdata; 28 volatile void __iomem *cfg_data; 29 u8 cfg_type = 0; 30 u32 bus_no, reg; 31 32 if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK) { 33 if (bus->number != hose->first_busno) 34 return PCIBIOS_DEVICE_NOT_FOUND; 35 if (devfn != 0) 36 return PCIBIOS_DEVICE_NOT_FOUND; 37 } 38 39 if (ppc_md.pci_exclude_device) 40 if (ppc_md.pci_exclude_device(hose, bus->number, devfn)) 41 return PCIBIOS_DEVICE_NOT_FOUND; 42 43 if (hose->indirect_type & PPC_INDIRECT_TYPE_SET_CFG_TYPE) 44 if (bus->number != hose->first_busno) 45 cfg_type = 1; 46 47 bus_no = (bus->number == hose->first_busno) ? 48 hose->self_busno : bus->number; 49 50 if (hose->indirect_type & PPC_INDIRECT_TYPE_EXT_REG) 51 reg = ((offset & 0xf00) << 16) | (offset & 0xfc); 52 else 53 reg = offset & 0xfc; 54 55 if (hose->indirect_type & PPC_INDIRECT_TYPE_BIG_ENDIAN) 56 out_be32(hose->cfg_addr, (0x80000000 | (bus_no << 16) | 57 (devfn << 8) | reg | cfg_type)); 58 else 59 out_le32(hose->cfg_addr, (0x80000000 | (bus_no << 16) | 60 (devfn << 8) | reg | cfg_type)); 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 cfg_data = hose->cfg_data + (offset & 3); 67 switch (len) { 68 case 1: 69 *val = in_8(cfg_data); 70 break; 71 case 2: 72 *val = in_le16(cfg_data); 73 break; 74 default: 75 *val = in_le32(cfg_data); 76 break; 77 } 78 return PCIBIOS_SUCCESSFUL; 79 } 80 81 static int 82 indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset, 83 int len, u32 val) 84 { 85 struct pci_controller *hose = bus->sysdata; 86 volatile void __iomem *cfg_data; 87 u8 cfg_type = 0; 88 u32 bus_no, reg; 89 90 if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK) { 91 if (bus->number != hose->first_busno) 92 return PCIBIOS_DEVICE_NOT_FOUND; 93 if (devfn != 0) 94 return PCIBIOS_DEVICE_NOT_FOUND; 95 } 96 97 if (ppc_md.pci_exclude_device) 98 if (ppc_md.pci_exclude_device(hose, bus->number, devfn)) 99 return PCIBIOS_DEVICE_NOT_FOUND; 100 101 if (hose->indirect_type & PPC_INDIRECT_TYPE_SET_CFG_TYPE) 102 if (bus->number != hose->first_busno) 103 cfg_type = 1; 104 105 bus_no = (bus->number == hose->first_busno) ? 106 hose->self_busno : bus->number; 107 108 if (hose->indirect_type & PPC_INDIRECT_TYPE_EXT_REG) 109 reg = ((offset & 0xf00) << 16) | (offset & 0xfc); 110 else 111 reg = offset & 0xfc; 112 113 if (hose->indirect_type & PPC_INDIRECT_TYPE_BIG_ENDIAN) 114 out_be32(hose->cfg_addr, (0x80000000 | (bus_no << 16) | 115 (devfn << 8) | reg | cfg_type)); 116 else 117 out_le32(hose->cfg_addr, (0x80000000 | (bus_no << 16) | 118 (devfn << 8) | reg | cfg_type)); 119 120 /* surpress setting of PCI_PRIMARY_BUS */ 121 if (hose->indirect_type & PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS) 122 if ((offset == PCI_PRIMARY_BUS) && 123 (bus->number == hose->first_busno)) 124 val &= 0xffffff00; 125 126 /* Workaround for PCI_28 Errata in 440EPx/GRx */ 127 if ((hose->indirect_type & PPC_INDIRECT_TYPE_BROKEN_MRM) && 128 offset == PCI_CACHE_LINE_SIZE) { 129 val = 0; 130 } 131 132 /* 133 * Note: the caller has already checked that offset is 134 * suitably aligned and that len is 1, 2 or 4. 135 */ 136 cfg_data = hose->cfg_data + (offset & 3); 137 switch (len) { 138 case 1: 139 out_8(cfg_data, val); 140 break; 141 case 2: 142 out_le16(cfg_data, val); 143 break; 144 default: 145 out_le32(cfg_data, val); 146 break; 147 } 148 return PCIBIOS_SUCCESSFUL; 149 } 150 151 static struct pci_ops indirect_pci_ops = 152 { 153 .read = indirect_read_config, 154 .write = indirect_write_config, 155 }; 156 157 void __init 158 setup_indirect_pci(struct pci_controller* hose, 159 resource_size_t cfg_addr, 160 resource_size_t cfg_data, u32 flags) 161 { 162 resource_size_t base = cfg_addr & PAGE_MASK; 163 void __iomem *mbase; 164 165 mbase = ioremap(base, PAGE_SIZE); 166 hose->cfg_addr = mbase + (cfg_addr & ~PAGE_MASK); 167 if ((cfg_data & PAGE_MASK) != base) 168 mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE); 169 hose->cfg_data = mbase + (cfg_data & ~PAGE_MASK); 170 hose->ops = &indirect_pci_ops; 171 hose->indirect_type = flags; 172 } 173