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