diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2007-12-20 23:39:23 -0500 |
---|---|---|
committer | Josh Boyer <jwboyer@linux.vnet.ibm.com> | 2007-12-23 14:12:27 -0500 |
commit | c839e0eff500af03de65e560c2e21c3831586e6e (patch) | |
tree | d2a896b8e95e1ae9d314a9a3de4be18349bac0e7 /arch/powerpc/sysdev | |
parent | 5738ec6d00b7abbcd4cd342af83fd18d192b0979 (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')
-rw-r--r-- | arch/powerpc/sysdev/ppc4xx_pci.c | 180 | ||||
-rw-r--r-- | arch/powerpc/sysdev/ppc4xx_pci.h | 19 |
2 files changed, 198 insertions, 1 deletions
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index a0b62398bc62..b7d79880c9b9 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 */ |
22 | extern unsigned long total_memory; | 22 | extern unsigned long total_memory; |
23 | 23 | ||
24 | static 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 | } | ||
52 | DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, fixup_ppc4xx_pci_bridge); | ||
53 | |||
24 | static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose, | 54 | static 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 | |||
160 | static 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 | |||
208 | static 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 | |||
129 | static void __init ppc4xx_probe_pci_bridge(struct device_node *np) | 232 | static 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; |
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.h b/arch/powerpc/sysdev/ppc4xx_pci.h index f9b4e6f4af2d..8b787bfdc8a5 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.h +++ b/arch/powerpc/sysdev/ppc4xx_pci.h | |||
@@ -101,6 +101,25 @@ | |||
101 | #define PCIX0_MSGOH 0x10c | 101 | #define PCIX0_MSGOH 0x10c |
102 | #define PCIX0_IM 0x1f8 | 102 | #define PCIX0_IM 0x1f8 |
103 | 103 | ||
104 | /* | ||
105 | * 4xx PCI bridge register definitions | ||
106 | */ | ||
107 | #define PCIL0_PMM0LA 0x00 | ||
108 | #define PCIL0_PMM0MA 0x04 | ||
109 | #define PCIL0_PMM0PCILA 0x08 | ||
110 | #define PCIL0_PMM0PCIHA 0x0c | ||
111 | #define PCIL0_PMM1LA 0x10 | ||
112 | #define PCIL0_PMM1MA 0x14 | ||
113 | #define PCIL0_PMM1PCILA 0x18 | ||
114 | #define PCIL0_PMM1PCIHA 0x1c | ||
115 | #define PCIL0_PMM2LA 0x20 | ||
116 | #define PCIL0_PMM2MA 0x24 | ||
117 | #define PCIL0_PMM2PCILA 0x28 | ||
118 | #define PCIL0_PMM2PCIHA 0x2c | ||
119 | #define PCIL0_PTM1MS 0x30 | ||
120 | #define PCIL0_PTM1LA 0x34 | ||
121 | #define PCIL0_PTM2MS 0x38 | ||
122 | #define PCIL0_PTM2LA 0x3c | ||
104 | 123 | ||
105 | 124 | ||
106 | #endif /* __PPC4XX_PCI_H__ */ | 125 | #endif /* __PPC4XX_PCI_H__ */ |