Linux-2.6.12-rc2
[linux-2.6/next.git] / arch / ppc / syslib / indirect_pci.c
bloba5a752609e2c426c265a4c52fd274956a1f63d09
1 /*
2 * Support for indirect PCI bridges.
4 * Copyright (C) 1998 Gabriel Paubert.
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.
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 #include <linux/bootmem.h>
19 #include <asm/io.h>
20 #include <asm/prom.h>
21 #include <asm/pci-bridge.h>
22 #include <asm/machdep.h>
24 #ifdef CONFIG_PPC_INDIRECT_PCI_BE
25 #define PCI_CFG_OUT out_be32
26 #else
27 #define PCI_CFG_OUT out_le32
28 #endif
30 static int
31 indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
32 int len, u32 *val)
34 struct pci_controller *hose = bus->sysdata;
35 volatile void __iomem *cfg_data;
36 u8 cfg_type = 0;
38 if (ppc_md.pci_exclude_device)
39 if (ppc_md.pci_exclude_device(bus->number, devfn))
40 return PCIBIOS_DEVICE_NOT_FOUND;
42 if (hose->set_cfg_type)
43 if (bus->number != hose->first_busno)
44 cfg_type = 1;
46 PCI_CFG_OUT(hose->cfg_addr,
47 (0x80000000 | ((bus->number - hose->bus_offset) << 16)
48 | (devfn << 8) | ((offset & 0xfc) | cfg_type)));
51 * Note: the caller has already checked that offset is
52 * suitably aligned and that len is 1, 2 or 4.
54 cfg_data = hose->cfg_data + (offset & 3);
55 switch (len) {
56 case 1:
57 *val = in_8(cfg_data);
58 break;
59 case 2:
60 *val = in_le16(cfg_data);
61 break;
62 default:
63 *val = in_le32(cfg_data);
64 break;
66 return PCIBIOS_SUCCESSFUL;
69 static int
70 indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
71 int len, u32 val)
73 struct pci_controller *hose = bus->sysdata;
74 volatile void __iomem *cfg_data;
75 u8 cfg_type = 0;
77 if (ppc_md.pci_exclude_device)
78 if (ppc_md.pci_exclude_device(bus->number, devfn))
79 return PCIBIOS_DEVICE_NOT_FOUND;
81 if (hose->set_cfg_type)
82 if (bus->number != hose->first_busno)
83 cfg_type = 1;
85 PCI_CFG_OUT(hose->cfg_addr,
86 (0x80000000 | ((bus->number - hose->bus_offset) << 16)
87 | (devfn << 8) | ((offset & 0xfc) | cfg_type)));
90 * Note: the caller has already checked that offset is
91 * suitably aligned and that len is 1, 2 or 4.
93 cfg_data = hose->cfg_data + (offset & 3);
94 switch (len) {
95 case 1:
96 out_8(cfg_data, val);
97 break;
98 case 2:
99 out_le16(cfg_data, val);
100 break;
101 default:
102 out_le32(cfg_data, val);
103 break;
105 return PCIBIOS_SUCCESSFUL;
108 static struct pci_ops indirect_pci_ops =
110 indirect_read_config,
111 indirect_write_config
114 void __init
115 setup_indirect_pci_nomap(struct pci_controller* hose, void __iomem * cfg_addr,
116 void __iomem * cfg_data)
118 hose->cfg_addr = cfg_addr;
119 hose->cfg_data = cfg_data;
120 hose->ops = &indirect_pci_ops;
123 void __init
124 setup_indirect_pci(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
126 unsigned long base = cfg_addr & PAGE_MASK;
127 void __iomem *mbase, *addr, *data;
129 mbase = ioremap(base, PAGE_SIZE);
130 addr = mbase + (cfg_addr & ~PAGE_MASK);
131 if ((cfg_data & PAGE_MASK) != base)
132 mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE);
133 data = mbase + (cfg_data & ~PAGE_MASK);
134 setup_indirect_pci_nomap(hose, addr, data);