[ARM] 3617/1: ep93xx: fix slightly incorrect timer tick rate
[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 #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>
22 #include <asm/machdep.h>
23
24
25 /* 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
31 static int
32 mpc52xx_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));
47         mb();
48
49 #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;
58
59                         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                 }
74         }
75
76         *val = value;
77
78         out_be32(hose->cfg_addr, 0);
79         mb();
80
81         return PCIBIOS_SUCCESSFUL;
82 }
83
84 static int
85 mpc52xx_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));
100         mb();
101
102 #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;
113
114                         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                 }
121         }
122         else
123 #endif
124         {
125                 if (len != 4) {
126                         value = in_le32(hose->cfg_data);
127
128                         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();
139
140         out_be32(hose->cfg_addr, 0);
141         mb();
142
143         return PCIBIOS_SUCCESSFUL;
144 }
145
146 static struct pci_ops mpc52xx_pci_ops = {
147         .read  = mpc52xx_pci_read_config,
148         .write = mpc52xx_pci_write_config
149 };
150
151
152 static void __init
153 mpc52xx_pci_setup(struct mpc52xx_pci __iomem *pci_regs)
154 {
155         u32 tmp;
156
157         /* Setup control regs */
158         tmp = in_be32(&pci_regs->scr);
159         tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
160         out_be32(&pci_regs->scr, tmp);
161
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 */
201         tmp = in_be32(&pci_regs->gscr);
202 #if 0
203         out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR);
204         udelay(50);
205 #endif
206         out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR);
207 }
208
209 static void
210 mpc52xx_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) &&
228              (   dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200
229               || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) {
230                 struct resource *res = &dev->resource[1];
231                 res->start = res->end = res->flags = 0;
232         }
233 }
234
235 void __init
236 mpc52xx_find_bridges(void)
237 {
238         struct mpc52xx_pci __iomem *pci_regs;
239         struct pci_controller *hose;
240
241         pci_assign_all_buses = 1;
242
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
265         hose->io_base_virt = ioremap(MPC52xx_PCI_IO_BASE, MPC52xx_PCI_IO_SIZE);
266         isa_io_base = (unsigned long) hose->io_base_virt;
267
268         hose->cfg_addr = &pci_regs->car;
269         hose->cfg_data = hose->io_base_virt;
270
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 }