aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev/ppc4xx_pci.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2007-12-20 23:39:23 -0500
committerJosh Boyer <jwboyer@linux.vnet.ibm.com>2007-12-23 14:12:27 -0500
commitc839e0eff500af03de65e560c2e21c3831586e6e (patch)
treed2a896b8e95e1ae9d314a9a3de4be18349bac0e7 /arch/powerpc/sysdev/ppc4xx_pci.c
parent5738ec6d00b7abbcd4cd342af83fd18d192b0979 (diff)
[POWERPC] 4xx: PLB to PCI 2.x support
This adds to the previous patch the support for the 4xx PCI 2.x bridges. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Diffstat (limited to 'arch/powerpc/sysdev/ppc4xx_pci.c')
-rw-r--r--arch/powerpc/sysdev/ppc4xx_pci.c180
1 files changed, 179 insertions, 1 deletions
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c
index a0b62398bc6..b7d79880c9b 100644
--- a/arch/powerpc/sysdev/ppc4xx_pci.c
+++ b/arch/powerpc/sysdev/ppc4xx_pci.c
@@ -21,6 +21,36 @@ static int dma_offset_set;
21/* Move that to a useable header */ 21/* Move that to a useable header */
22extern unsigned long total_memory; 22extern unsigned long total_memory;
23 23
24static void fixup_ppc4xx_pci_bridge(struct pci_dev *dev)
25{
26 struct pci_controller *hose;
27 int i;
28
29 if (dev->devfn != 0 || dev->bus->self != NULL)
30 return;
31
32 hose = pci_bus_to_host(dev->bus);
33 if (hose == NULL)
34 return;
35
36 if (!of_device_is_compatible(hose->dn, "ibm,plb-pciex") &&
37 !of_device_is_compatible(hose->dn, "ibm,plb-pcix") &&
38 !of_device_is_compatible(hose->dn, "ibm,plb-pci"))
39 return;
40
41 /* Hide the PCI host BARs from the kernel as their content doesn't
42 * fit well in the resource management
43 */
44 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
45 dev->resource[i].start = dev->resource[i].end = 0;
46 dev->resource[i].flags = 0;
47 }
48
49 printk(KERN_INFO "PCI: Hiding 4xx host bridge resources %s\n",
50 pci_name(dev));
51}
52DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, fixup_ppc4xx_pci_bridge);
53
24static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose, 54static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose,
25 void __iomem *reg, 55 void __iomem *reg,
26 struct resource *res) 56 struct resource *res)
@@ -126,9 +156,157 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose,
126/* 156/*
127 * 4xx PCI 2.x part 157 * 4xx PCI 2.x part
128 */ 158 */
159
160static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose,
161 void __iomem *reg)
162{
163 u32 la, ma, pcila, pciha;
164 int i, j;
165
166 /* Setup outbound memory windows */
167 for (i = j = 0; i < 3; i++) {
168 struct resource *res = &hose->mem_resources[i];
169
170 /* we only care about memory windows */
171 if (!(res->flags & IORESOURCE_MEM))
172 continue;
173 if (j > 2) {
174 printk(KERN_WARNING "%s: Too many ranges\n",
175 hose->dn->full_name);
176 break;
177 }
178
179 /* Calculate register values */
180 la = res->start;
181#ifdef CONFIG_RESOURCES_64BIT
182 pciha = (res->start - hose->pci_mem_offset) >> 32;
183 pcila = (res->start - hose->pci_mem_offset) & 0xffffffffu;
184#else
185 pciha = 0;
186 pcila = res->start - hose->pci_mem_offset;
187#endif
188
189 ma = res->end + 1 - res->start;
190 if (!is_power_of_2(ma) || ma < 0x1000 || ma > 0xffffffffu) {
191 printk(KERN_WARNING "%s: Resource out of range\n",
192 hose->dn->full_name);
193 continue;
194 }
195 ma = (0xffffffffu << ilog2(ma)) | 0x1;
196 if (res->flags & IORESOURCE_PREFETCH)
197 ma |= 0x2;
198
199 /* Program register values */
200 writel(la, reg + PCIL0_PMM0LA + (0x10 * j));
201 writel(pcila, reg + PCIL0_PMM0PCILA + (0x10 * j));
202 writel(pciha, reg + PCIL0_PMM0PCIHA + (0x10 * j));
203 writel(ma, reg + PCIL0_PMM0MA + (0x10 * j));
204 j++;
205 }
206}
207
208static void __init ppc4xx_configure_pci_PTMs(struct pci_controller *hose,
209 void __iomem *reg,
210 const struct resource *res)
211{
212 resource_size_t size = res->end - res->start + 1;
213 u32 sa;
214
215 /* Calculate window size */
216 sa = (0xffffffffu << ilog2(size)) | 1;
217 sa |= 0x1;
218
219 /* RAM is always at 0 local for now */
220 writel(0, reg + PCIL0_PTM1LA);
221 writel(sa, reg + PCIL0_PTM1MS);
222
223 /* Map on PCI side */
224 early_write_config_dword(hose, hose->first_busno, 0,
225 PCI_BASE_ADDRESS_1, res->start);
226 early_write_config_dword(hose, hose->first_busno, 0,
227 PCI_BASE_ADDRESS_2, 0x00000000);
228 early_write_config_word(hose, hose->first_busno, 0,
229 PCI_COMMAND, 0x0006);
230}
231
129static void __init ppc4xx_probe_pci_bridge(struct device_node *np) 232static void __init ppc4xx_probe_pci_bridge(struct device_node *np)
130{ 233{
131 /* NYI */ 234 /* NYI */
235 struct resource rsrc_cfg;
236 struct resource rsrc_reg;
237 struct resource dma_window;
238 struct pci_controller *hose = NULL;
239 void __iomem *reg = NULL;
240 const int *bus_range;
241 int primary = 0;
242
243 /* Fetch config space registers address */
244 if (of_address_to_resource(np, 0, &rsrc_cfg)) {
245 printk(KERN_ERR "%s:Can't get PCI config register base !",
246 np->full_name);
247 return;
248 }
249 /* Fetch host bridge internal registers address */
250 if (of_address_to_resource(np, 3, &rsrc_reg)) {
251 printk(KERN_ERR "%s: Can't get PCI internal register base !",
252 np->full_name);
253 return;
254 }
255
256 /* Check if primary bridge */
257 if (of_get_property(np, "primary", NULL))
258 primary = 1;
259
260 /* Get bus range if any */
261 bus_range = of_get_property(np, "bus-range", NULL);
262
263 /* Map registers */
264 reg = ioremap(rsrc_reg.start, rsrc_reg.end + 1 - rsrc_reg.start);
265 if (reg == NULL) {
266 printk(KERN_ERR "%s: Can't map registers !", np->full_name);
267 goto fail;
268 }
269
270 /* Allocate the host controller data structure */
271 hose = pcibios_alloc_controller(np);
272 if (!hose)
273 goto fail;
274
275 hose->first_busno = bus_range ? bus_range[0] : 0x0;
276 hose->last_busno = bus_range ? bus_range[1] : 0xff;
277
278 /* Setup config space */
279 setup_indirect_pci(hose, rsrc_cfg.start, rsrc_cfg.start + 0x4, 0);
280
281 /* Disable all windows */
282 writel(0, reg + PCIL0_PMM0MA);
283 writel(0, reg + PCIL0_PMM1MA);
284 writel(0, reg + PCIL0_PMM2MA);
285 writel(0, reg + PCIL0_PTM1MS);
286 writel(0, reg + PCIL0_PTM2MS);
287
288 /* Parse outbound mapping resources */
289 pci_process_bridge_OF_ranges(hose, np, primary);
290
291 /* Parse inbound mapping resources */
292 if (ppc4xx_parse_dma_ranges(hose, reg, &dma_window) != 0)
293 goto fail;
294
295 /* Configure outbound ranges POMs */
296 ppc4xx_configure_pci_PMMs(hose, reg);
297
298 /* Configure inbound ranges PIMs */
299 ppc4xx_configure_pci_PTMs(hose, reg, &dma_window);
300
301 /* We don't need the registers anymore */
302 iounmap(reg);
303 return;
304
305 fail:
306 if (hose)
307 pcibios_free_controller(hose);
308 if (reg)
309 iounmap(reg);
132} 310}
133 311
134/* 312/*
@@ -155,7 +333,7 @@ static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose,
155 } 333 }
156 334
157 /* Calculate register values */ 335 /* Calculate register values */
158#ifdef CONFIG_PTE_64BIT 336#ifdef CONFIG_RESOURCES_64BIT
159 lah = res->start >> 32; 337 lah = res->start >> 32;
160 lal = res->start & 0xffffffffu; 338 lal = res->start & 0xffffffffu;
161 pciah = (res->start - hose->pci_mem_offset) >> 32; 339 pciah = (res->start - hose->pci_mem_offset) >> 32;