Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux...
[linux-2.6] / arch / ppc / syslib / mpc52xx_pci.c
1 /*
2  * 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
15 #include <asm/pci.h>
16
17 #include <asm/mpc52xx.h>
18 #include "mpc52xx_pci.h"
19
20 #include <asm/delay.h>
21 #include <asm/machdep.h>
22
23
24 /* 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
30 static int
31 mpc52xx_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));
46         mb();
47
48 #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;
57
58                         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                 }
73         }
74
75         *val = value;
76
77         out_be32(hose->cfg_addr, 0);
78         mb();
79
80         return PCIBIOS_SUCCESSFUL;
81 }
82
83 static int
84 mpc52xx_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));
99         mb();
100
101 #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;
112
113                         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                 }
120         }
121         else
122 #endif
123         {
124                 if (len != 4) {
125                         value = in_le32(hose->cfg_data);
126
127                         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();
138
139         out_be32(hose->cfg_addr, 0);
140         mb();
141
142         return PCIBIOS_SUCCESSFUL;
143 }
144
145 static struct pci_ops mpc52xx_pci_ops = {
146         .read  = mpc52xx_pci_read_config,
147         .write = mpc52xx_pci_write_config
148 };
149
150
151 static void __init
152 mpc52xx_pci_setup(struct mpc52xx_pci __iomem *pci_regs)
153 {
154         u32 tmp;
155
156         /* Setup control regs */
157         tmp = in_be32(&pci_regs->scr);
158         tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
159         out_be32(&pci_regs->scr, tmp);
160
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 */
200         tmp = in_be32(&pci_regs->gscr);
201 #if 0
202         out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR);
203         udelay(50);
204 #endif
205         out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR);
206 }
207
208 static void
209 mpc52xx_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) &&
227              (   dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200
228               || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) {
229                 struct resource *res = &dev->resource[1];
230                 res->start = res->end = res->flags = 0;
231         }
232 }
233
234 void __init
235 mpc52xx_find_bridges(void)
236 {
237         struct mpc52xx_pci __iomem *pci_regs;
238         struct pci_controller *hose;
239
240         pci_assign_all_buses = 1;
241
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
264         hose->io_base_virt = ioremap(MPC52xx_PCI_IO_BASE, MPC52xx_PCI_IO_SIZE);
265         isa_io_base = (unsigned long) hose->io_base_virt;
266
267         hose->cfg_addr = &pci_regs->car;
268         hose->cfg_data = hose->io_base_virt;
269
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 }