blob: 20a0eac0dc3a3fbd8ca4a6f3bbd59e6a64295dc3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * PCI code for the Freescale MPC52xx embedded CPU.
3 *
4 *
5 * Maintainer : Sylvain Munaut <tnt@246tNt.com>
6 *
7 * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
8 *
9 * This file is licensed under the terms of the GNU General Public License
10 * version 2. This program is licensed "as is" without any warranty of any
11 * kind, whether express or implied.
12 */
13
Linus Torvalds1da177e2005-04-16 15:20:36 -070014
15#include <asm/pci.h>
16
17#include <asm/mpc52xx.h>
18#include "mpc52xx_pci.h"
19
20#include <asm/delay.h>
Paul Mackerrasfd582ec2005-10-11 22:08:12 +100021#include <asm/machdep.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
23
Sylvain Munautdb674ed2006-01-06 00:11:36 -080024/* This macro is defined to activate the workaround for the bug
25 435 of the MPC5200 (L25R). With it activated, we don't do any
26 32 bits configuration access during type-1 cycles */
27#define MPC5200_BUG_435_WORKAROUND
28
29
Linus Torvalds1da177e2005-04-16 15:20:36 -070030static int
31mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
32 int offset, int len, u32 *val)
33{
34 struct pci_controller *hose = bus->sysdata;
35 u32 value;
36
37 if (ppc_md.pci_exclude_device)
38 if (ppc_md.pci_exclude_device(bus->number, devfn))
39 return PCIBIOS_DEVICE_NOT_FOUND;
40
41 out_be32(hose->cfg_addr,
42 (1 << 31) |
43 ((bus->number - hose->bus_offset) << 16) |
44 (devfn << 8) |
45 (offset & 0xfc));
Sylvain Munautdb674ed2006-01-06 00:11:36 -080046 mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
Sylvain Munautdb674ed2006-01-06 00:11:36 -080048#ifdef MPC5200_BUG_435_WORKAROUND
49 if (bus->number != hose->bus_offset) {
50 switch (len) {
51 case 1:
52 value = in_8(((u8 __iomem *)hose->cfg_data) + (offset & 3));
53 break;
54 case 2:
55 value = in_le16(((u16 __iomem *)hose->cfg_data) + ((offset>>1) & 1));
56 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Sylvain Munautdb674ed2006-01-06 00:11:36 -080058 default:
59 value = in_le16((u16 __iomem *)hose->cfg_data) |
60 (in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16);
61 break;
62 }
63 }
64 else
65#endif
66 {
67 value = in_le32(hose->cfg_data);
68
69 if (len != 4) {
70 value >>= ((offset & 0x3) << 3);
71 value &= 0xffffffff >> (32 - (len << 3));
72 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 }
74
75 *val = value;
76
77 out_be32(hose->cfg_addr, 0);
Sylvain Munautdb674ed2006-01-06 00:11:36 -080078 mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80 return PCIBIOS_SUCCESSFUL;
81}
82
83static int
84mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
85 int offset, int len, u32 val)
86{
87 struct pci_controller *hose = bus->sysdata;
88 u32 value, mask;
89
90 if (ppc_md.pci_exclude_device)
91 if (ppc_md.pci_exclude_device(bus->number, devfn))
92 return PCIBIOS_DEVICE_NOT_FOUND;
93
94 out_be32(hose->cfg_addr,
95 (1 << 31) |
96 ((bus->number - hose->bus_offset) << 16) |
97 (devfn << 8) |
98 (offset & 0xfc));
Sylvain Munautdb674ed2006-01-06 00:11:36 -080099 mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Sylvain Munautdb674ed2006-01-06 00:11:36 -0800101#ifdef MPC5200_BUG_435_WORKAROUND
102 if (bus->number != hose->bus_offset) {
103 switch (len) {
104 case 1:
105 out_8(((u8 __iomem *)hose->cfg_data) +
106 (offset & 3), val);
107 break;
108 case 2:
109 out_le16(((u16 __iomem *)hose->cfg_data) +
110 ((offset>>1) & 1), val);
111 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112
Sylvain Munautdb674ed2006-01-06 00:11:36 -0800113 default:
114 out_le16((u16 __iomem *)hose->cfg_data,
115 (u16)val);
116 out_le16(((u16 __iomem *)hose->cfg_data) + 1,
117 (u16)(val>>16));
118 break;
119 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 }
Sylvain Munautdb674ed2006-01-06 00:11:36 -0800121 else
122#endif
123 {
124 if (len != 4) {
125 value = in_le32(hose->cfg_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
Sylvain Munautdb674ed2006-01-06 00:11:36 -0800127 offset = (offset & 0x3) << 3;
128 mask = (0xffffffff >> (32 - (len << 3)));
129 mask <<= offset;
130
131 value &= ~mask;
132 val = value | ((val << offset) & mask);
133 }
134
135 out_le32(hose->cfg_data, val);
136 }
137 mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
139 out_be32(hose->cfg_addr, 0);
Sylvain Munautdb674ed2006-01-06 00:11:36 -0800140 mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
142 return PCIBIOS_SUCCESSFUL;
143}
144
145static struct pci_ops mpc52xx_pci_ops = {
146 .read = mpc52xx_pci_read_config,
147 .write = mpc52xx_pci_write_config
148};
149
150
151static void __init
152mpc52xx_pci_setup(struct mpc52xx_pci __iomem *pci_regs)
153{
Sylvain Munaut041cb622006-01-06 00:11:37 -0800154 u32 tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
156 /* Setup control regs */
Sylvain Munaut041cb622006-01-06 00:11:37 -0800157 tmp = in_be32(&pci_regs->scr);
158 tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
159 out_be32(&pci_regs->scr, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
161 /* Setup windows */
162 out_be32(&pci_regs->iw0btar, MPC52xx_PCI_IWBTAR_TRANSLATION(
163 MPC52xx_PCI_MEM_START + MPC52xx_PCI_MEM_OFFSET,
164 MPC52xx_PCI_MEM_START,
165 MPC52xx_PCI_MEM_SIZE ));
166
167 out_be32(&pci_regs->iw1btar, MPC52xx_PCI_IWBTAR_TRANSLATION(
168 MPC52xx_PCI_MMIO_START + MPC52xx_PCI_MEM_OFFSET,
169 MPC52xx_PCI_MMIO_START,
170 MPC52xx_PCI_MMIO_SIZE ));
171
172 out_be32(&pci_regs->iw2btar, MPC52xx_PCI_IWBTAR_TRANSLATION(
173 MPC52xx_PCI_IO_BASE,
174 MPC52xx_PCI_IO_START,
175 MPC52xx_PCI_IO_SIZE ));
176
177 out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(
178 ( MPC52xx_PCI_IWCR_ENABLE | /* iw0btar */
179 MPC52xx_PCI_IWCR_READ_MULTI |
180 MPC52xx_PCI_IWCR_MEM ),
181 ( MPC52xx_PCI_IWCR_ENABLE | /* iw1btar */
182 MPC52xx_PCI_IWCR_READ |
183 MPC52xx_PCI_IWCR_MEM ),
184 ( MPC52xx_PCI_IWCR_ENABLE | /* iw2btar */
185 MPC52xx_PCI_IWCR_IO )
186 ));
187
188
189 out_be32(&pci_regs->tbatr0,
190 MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO );
191 out_be32(&pci_regs->tbatr1,
192 MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM );
193
194 out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD);
195
196 /* Reset the exteral bus ( internal PCI controller is NOT resetted ) */
197 /* Not necessary and can be a bad thing if for example the bootloader
198 is displaying a splash screen or ... Just left here for
199 documentation purpose if anyone need it */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 tmp = in_be32(&pci_regs->gscr);
Sylvain Munaut041cb622006-01-06 00:11:37 -0800201#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR);
203 udelay(50);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204#endif
Sylvain Munaut041cb622006-01-06 00:11:37 -0800205 out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206}
207
Sylvain Munautdbeb1982006-01-06 00:11:35 -0800208static void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209mpc52xx_pci_fixup_resources(struct pci_dev *dev)
210{
211 int i;
212
213 /* We don't rely on boot loader for PCI and resets all
214 devices */
215 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
216 struct resource *res = &dev->resource[i];
217 if (res->end > res->start) { /* Only valid resources */
218 res->end -= res->start;
219 res->start = 0;
220 res->flags |= IORESOURCE_UNSET;
221 }
222 }
223
224 /* The PCI Host bridge of MPC52xx has a prefetch memory resource
225 fixed to 1Gb. Doesn't fit in the resource system so we remove it */
226 if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
Sylvain Munaut5931c432006-03-26 13:37:07 +0200227 ( dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200
228 || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 struct resource *res = &dev->resource[1];
230 res->start = res->end = res->flags = 0;
231 }
232}
233
234void __init
235mpc52xx_find_bridges(void)
236{
237 struct mpc52xx_pci __iomem *pci_regs;
238 struct pci_controller *hose;
239
Paul Mackerras399fe2b2005-10-20 20:57:05 +1000240 pci_assign_all_buses = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241
242 pci_regs = ioremap(MPC52xx_PA(MPC52xx_PCI_OFFSET), MPC52xx_PCI_SIZE);
243 if (!pci_regs)
244 return;
245
246 hose = pcibios_alloc_controller();
247 if (!hose) {
248 iounmap(pci_regs);
249 return;
250 }
251
252 ppc_md.pci_swizzle = common_swizzle;
253 ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources;
254
255 hose->first_busno = 0;
256 hose->last_busno = 0xff;
257 hose->bus_offset = 0;
258 hose->ops = &mpc52xx_pci_ops;
259
260 mpc52xx_pci_setup(pci_regs);
261
262 hose->pci_mem_offset = MPC52xx_PCI_MEM_OFFSET;
263
Al Viro92a11f92005-04-25 07:55:57 -0700264 hose->io_base_virt = ioremap(MPC52xx_PCI_IO_BASE, MPC52xx_PCI_IO_SIZE);
265 isa_io_base = (unsigned long) hose->io_base_virt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
267 hose->cfg_addr = &pci_regs->car;
Al Viro92a11f92005-04-25 07:55:57 -0700268 hose->cfg_data = hose->io_base_virt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
270 /* Setup resources */
271 pci_init_resource(&hose->mem_resources[0],
272 MPC52xx_PCI_MEM_START,
273 MPC52xx_PCI_MEM_STOP,
274 IORESOURCE_MEM|IORESOURCE_PREFETCH,
275 "PCI prefetchable memory");
276
277 pci_init_resource(&hose->mem_resources[1],
278 MPC52xx_PCI_MMIO_START,
279 MPC52xx_PCI_MMIO_STOP,
280 IORESOURCE_MEM,
281 "PCI memory");
282
283 pci_init_resource(&hose->io_resource,
284 MPC52xx_PCI_IO_START,
285 MPC52xx_PCI_IO_STOP,
286 IORESOURCE_IO,
287 "PCI I/O");
288
289}