blob: 5a5a7a9cd248620528e34bbee408203d57e2480c [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
14#include <linux/config.h>
15
16#include <asm/pci.h>
17
18#include <asm/mpc52xx.h>
19#include "mpc52xx_pci.h"
20
21#include <asm/delay.h>
Paul Mackerrasfd582ec2005-10-11 22:08:12 +100022#include <asm/machdep.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
24
Sylvain Munautdb674ed2006-01-06 00:11:36 -080025/* This macro is defined to activate the workaround for the bug
26 435 of the MPC5200 (L25R). With it activated, we don't do any
27 32 bits configuration access during type-1 cycles */
28#define MPC5200_BUG_435_WORKAROUND
29
30
Linus Torvalds1da177e2005-04-16 15:20:36 -070031static int
32mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
33 int offset, int len, u32 *val)
34{
35 struct pci_controller *hose = bus->sysdata;
36 u32 value;
37
38 if (ppc_md.pci_exclude_device)
39 if (ppc_md.pci_exclude_device(bus->number, devfn))
40 return PCIBIOS_DEVICE_NOT_FOUND;
41
42 out_be32(hose->cfg_addr,
43 (1 << 31) |
44 ((bus->number - hose->bus_offset) << 16) |
45 (devfn << 8) |
46 (offset & 0xfc));
Sylvain Munautdb674ed2006-01-06 00:11:36 -080047 mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
Sylvain Munautdb674ed2006-01-06 00:11:36 -080049#ifdef MPC5200_BUG_435_WORKAROUND
50 if (bus->number != hose->bus_offset) {
51 switch (len) {
52 case 1:
53 value = in_8(((u8 __iomem *)hose->cfg_data) + (offset & 3));
54 break;
55 case 2:
56 value = in_le16(((u16 __iomem *)hose->cfg_data) + ((offset>>1) & 1));
57 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Sylvain Munautdb674ed2006-01-06 00:11:36 -080059 default:
60 value = in_le16((u16 __iomem *)hose->cfg_data) |
61 (in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16);
62 break;
63 }
64 }
65 else
66#endif
67 {
68 value = in_le32(hose->cfg_data);
69
70 if (len != 4) {
71 value >>= ((offset & 0x3) << 3);
72 value &= 0xffffffff >> (32 - (len << 3));
73 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 }
75
76 *val = value;
77
78 out_be32(hose->cfg_addr, 0);
Sylvain Munautdb674ed2006-01-06 00:11:36 -080079 mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
81 return PCIBIOS_SUCCESSFUL;
82}
83
84static int
85mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
86 int offset, int len, u32 val)
87{
88 struct pci_controller *hose = bus->sysdata;
89 u32 value, mask;
90
91 if (ppc_md.pci_exclude_device)
92 if (ppc_md.pci_exclude_device(bus->number, devfn))
93 return PCIBIOS_DEVICE_NOT_FOUND;
94
95 out_be32(hose->cfg_addr,
96 (1 << 31) |
97 ((bus->number - hose->bus_offset) << 16) |
98 (devfn << 8) |
99 (offset & 0xfc));
Sylvain Munautdb674ed2006-01-06 00:11:36 -0800100 mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
Sylvain Munautdb674ed2006-01-06 00:11:36 -0800102#ifdef MPC5200_BUG_435_WORKAROUND
103 if (bus->number != hose->bus_offset) {
104 switch (len) {
105 case 1:
106 out_8(((u8 __iomem *)hose->cfg_data) +
107 (offset & 3), val);
108 break;
109 case 2:
110 out_le16(((u16 __iomem *)hose->cfg_data) +
111 ((offset>>1) & 1), val);
112 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113
Sylvain Munautdb674ed2006-01-06 00:11:36 -0800114 default:
115 out_le16((u16 __iomem *)hose->cfg_data,
116 (u16)val);
117 out_le16(((u16 __iomem *)hose->cfg_data) + 1,
118 (u16)(val>>16));
119 break;
120 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 }
Sylvain Munautdb674ed2006-01-06 00:11:36 -0800122 else
123#endif
124 {
125 if (len != 4) {
126 value = in_le32(hose->cfg_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
Sylvain Munautdb674ed2006-01-06 00:11:36 -0800128 offset = (offset & 0x3) << 3;
129 mask = (0xffffffff >> (32 - (len << 3)));
130 mask <<= offset;
131
132 value &= ~mask;
133 val = value | ((val << offset) & mask);
134 }
135
136 out_le32(hose->cfg_data, val);
137 }
138 mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140 out_be32(hose->cfg_addr, 0);
Sylvain Munautdb674ed2006-01-06 00:11:36 -0800141 mb();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
143 return PCIBIOS_SUCCESSFUL;
144}
145
146static struct pci_ops mpc52xx_pci_ops = {
147 .read = mpc52xx_pci_read_config,
148 .write = mpc52xx_pci_write_config
149};
150
151
152static void __init
153mpc52xx_pci_setup(struct mpc52xx_pci __iomem *pci_regs)
154{
Sylvain Munaut041cb622006-01-06 00:11:37 -0800155 u32 tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
157 /* Setup control regs */
Sylvain Munaut041cb622006-01-06 00:11:37 -0800158 tmp = in_be32(&pci_regs->scr);
159 tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
160 out_be32(&pci_regs->scr, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
162 /* Setup windows */
163 out_be32(&pci_regs->iw0btar, MPC52xx_PCI_IWBTAR_TRANSLATION(
164 MPC52xx_PCI_MEM_START + MPC52xx_PCI_MEM_OFFSET,
165 MPC52xx_PCI_MEM_START,
166 MPC52xx_PCI_MEM_SIZE ));
167
168 out_be32(&pci_regs->iw1btar, MPC52xx_PCI_IWBTAR_TRANSLATION(
169 MPC52xx_PCI_MMIO_START + MPC52xx_PCI_MEM_OFFSET,
170 MPC52xx_PCI_MMIO_START,
171 MPC52xx_PCI_MMIO_SIZE ));
172
173 out_be32(&pci_regs->iw2btar, MPC52xx_PCI_IWBTAR_TRANSLATION(
174 MPC52xx_PCI_IO_BASE,
175 MPC52xx_PCI_IO_START,
176 MPC52xx_PCI_IO_SIZE ));
177
178 out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(
179 ( MPC52xx_PCI_IWCR_ENABLE | /* iw0btar */
180 MPC52xx_PCI_IWCR_READ_MULTI |
181 MPC52xx_PCI_IWCR_MEM ),
182 ( MPC52xx_PCI_IWCR_ENABLE | /* iw1btar */
183 MPC52xx_PCI_IWCR_READ |
184 MPC52xx_PCI_IWCR_MEM ),
185 ( MPC52xx_PCI_IWCR_ENABLE | /* iw2btar */
186 MPC52xx_PCI_IWCR_IO )
187 ));
188
189
190 out_be32(&pci_regs->tbatr0,
191 MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO );
192 out_be32(&pci_regs->tbatr1,
193 MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM );
194
195 out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD);
196
197 /* Reset the exteral bus ( internal PCI controller is NOT resetted ) */
198 /* Not necessary and can be a bad thing if for example the bootloader
199 is displaying a splash screen or ... Just left here for
200 documentation purpose if anyone need it */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 tmp = in_be32(&pci_regs->gscr);
Sylvain Munaut041cb622006-01-06 00:11:37 -0800202#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR);
204 udelay(50);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205#endif
Sylvain Munaut041cb622006-01-06 00:11:37 -0800206 out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207}
208
Sylvain Munautdbeb1982006-01-06 00:11:35 -0800209static void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210mpc52xx_pci_fixup_resources(struct pci_dev *dev)
211{
212 int i;
213
214 /* We don't rely on boot loader for PCI and resets all
215 devices */
216 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
217 struct resource *res = &dev->resource[i];
218 if (res->end > res->start) { /* Only valid resources */
219 res->end -= res->start;
220 res->start = 0;
221 res->flags |= IORESOURCE_UNSET;
222 }
223 }
224
225 /* The PCI Host bridge of MPC52xx has a prefetch memory resource
226 fixed to 1Gb. Doesn't fit in the resource system so we remove it */
227 if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
Sylvain Munaut5931c432006-03-26 13:37:07 +0200228 ( dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200
229 || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 struct resource *res = &dev->resource[1];
231 res->start = res->end = res->flags = 0;
232 }
233}
234
235void __init
236mpc52xx_find_bridges(void)
237{
238 struct mpc52xx_pci __iomem *pci_regs;
239 struct pci_controller *hose;
240
Paul Mackerras399fe2b2005-10-20 20:57:05 +1000241 pci_assign_all_buses = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
243 pci_regs = ioremap(MPC52xx_PA(MPC52xx_PCI_OFFSET), MPC52xx_PCI_SIZE);
244 if (!pci_regs)
245 return;
246
247 hose = pcibios_alloc_controller();
248 if (!hose) {
249 iounmap(pci_regs);
250 return;
251 }
252
253 ppc_md.pci_swizzle = common_swizzle;
254 ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources;
255
256 hose->first_busno = 0;
257 hose->last_busno = 0xff;
258 hose->bus_offset = 0;
259 hose->ops = &mpc52xx_pci_ops;
260
261 mpc52xx_pci_setup(pci_regs);
262
263 hose->pci_mem_offset = MPC52xx_PCI_MEM_OFFSET;
264
Al Viro92a11f92005-04-25 07:55:57 -0700265 hose->io_base_virt = ioremap(MPC52xx_PCI_IO_BASE, MPC52xx_PCI_IO_SIZE);
266 isa_io_base = (unsigned long) hose->io_base_virt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
268 hose->cfg_addr = &pci_regs->car;
Al Viro92a11f92005-04-25 07:55:57 -0700269 hose->cfg_data = hose->io_base_virt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
271 /* Setup resources */
272 pci_init_resource(&hose->mem_resources[0],
273 MPC52xx_PCI_MEM_START,
274 MPC52xx_PCI_MEM_STOP,
275 IORESOURCE_MEM|IORESOURCE_PREFETCH,
276 "PCI prefetchable memory");
277
278 pci_init_resource(&hose->mem_resources[1],
279 MPC52xx_PCI_MMIO_START,
280 MPC52xx_PCI_MMIO_STOP,
281 IORESOURCE_MEM,
282 "PCI memory");
283
284 pci_init_resource(&hose->io_resource,
285 MPC52xx_PCI_IO_START,
286 MPC52xx_PCI_IO_STOP,
287 IORESOURCE_IO,
288 "PCI I/O");
289
290}