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