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