Merge with /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
[linux-2.6] / 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 static int
28 mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
29                                 int offset, int len, u32 *val)
30 {
31         struct pci_controller *hose = bus->sysdata;
32         u32 value;
33
34         if (ppc_md.pci_exclude_device)
35                 if (ppc_md.pci_exclude_device(bus->number, devfn))
36                         return PCIBIOS_DEVICE_NOT_FOUND;
37
38         out_be32(hose->cfg_addr,
39                 (1 << 31) |
40                 ((bus->number - hose->bus_offset) << 16) |
41                 (devfn << 8) |
42                 (offset & 0xfc));
43
44         value = in_le32(hose->cfg_data);
45
46         if (len != 4) {
47                 value >>= ((offset & 0x3) << 3);
48                 value &= 0xffffffff >> (32 - (len << 3));
49         }
50
51         *val = value;
52
53         out_be32(hose->cfg_addr, 0);
54
55         return PCIBIOS_SUCCESSFUL;
56 }
57
58 static int
59 mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
60                                 int offset, int len, u32 val)
61 {
62         struct pci_controller *hose = bus->sysdata;
63         u32 value, mask;
64
65         if (ppc_md.pci_exclude_device)
66                 if (ppc_md.pci_exclude_device(bus->number, devfn))
67                         return PCIBIOS_DEVICE_NOT_FOUND;
68
69         out_be32(hose->cfg_addr,
70                 (1 << 31) |
71                 ((bus->number - hose->bus_offset) << 16) |
72                 (devfn << 8) |
73                 (offset & 0xfc));
74
75         if (len != 4) {
76                 value = in_le32(hose->cfg_data);
77
78                 offset = (offset & 0x3) << 3;
79                 mask = (0xffffffff >> (32 - (len << 3)));
80                 mask <<= offset;
81
82                 value &= ~mask;
83                 val = value | ((val << offset) & mask);
84         }
85
86         out_le32(hose->cfg_data, val);
87
88         out_be32(hose->cfg_addr, 0);
89
90         return PCIBIOS_SUCCESSFUL;
91 }
92
93 static struct pci_ops mpc52xx_pci_ops = {
94         .read  = mpc52xx_pci_read_config,
95         .write = mpc52xx_pci_write_config
96 };
97
98
99 static void __init
100 mpc52xx_pci_setup(struct mpc52xx_pci __iomem *pci_regs)
101 {
102
103         /* Setup control regs */
104                 /* Nothing to do afaik */
105
106         /* Setup windows */
107         out_be32(&pci_regs->iw0btar, MPC52xx_PCI_IWBTAR_TRANSLATION(
108                 MPC52xx_PCI_MEM_START + MPC52xx_PCI_MEM_OFFSET,
109                 MPC52xx_PCI_MEM_START,
110                 MPC52xx_PCI_MEM_SIZE ));
111
112         out_be32(&pci_regs->iw1btar, MPC52xx_PCI_IWBTAR_TRANSLATION(
113                 MPC52xx_PCI_MMIO_START + MPC52xx_PCI_MEM_OFFSET,
114                 MPC52xx_PCI_MMIO_START,
115                 MPC52xx_PCI_MMIO_SIZE ));
116
117         out_be32(&pci_regs->iw2btar, MPC52xx_PCI_IWBTAR_TRANSLATION(
118                 MPC52xx_PCI_IO_BASE,
119                 MPC52xx_PCI_IO_START,
120                 MPC52xx_PCI_IO_SIZE ));
121
122         out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(
123                 ( MPC52xx_PCI_IWCR_ENABLE |             /* iw0btar */
124                   MPC52xx_PCI_IWCR_READ_MULTI |
125                   MPC52xx_PCI_IWCR_MEM ),
126                 ( MPC52xx_PCI_IWCR_ENABLE |             /* iw1btar */
127                   MPC52xx_PCI_IWCR_READ |
128                   MPC52xx_PCI_IWCR_MEM ),
129                 ( MPC52xx_PCI_IWCR_ENABLE |             /* iw2btar */
130                   MPC52xx_PCI_IWCR_IO )
131         ));
132
133
134         out_be32(&pci_regs->tbatr0,
135                 MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO );
136         out_be32(&pci_regs->tbatr1,
137                 MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM );
138
139         out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD);
140
141         /* Reset the exteral bus ( internal PCI controller is NOT resetted ) */
142         /* Not necessary and can be a bad thing if for example the bootloader
143            is displaying a splash screen or ... Just left here for
144            documentation purpose if anyone need it */
145 #if 0
146         u32 tmp;
147         tmp = in_be32(&pci_regs->gscr);
148         out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR);
149         udelay(50);
150         out_be32(&pci_regs->gscr, tmp);
151 #endif
152 }
153
154 static void __init
155 mpc52xx_pci_fixup_resources(struct pci_dev *dev)
156 {
157         int i;
158
159         /* We don't rely on boot loader for PCI and resets all
160            devices */
161         for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
162                 struct resource *res = &dev->resource[i];
163                 if (res->end > res->start) {    /* Only valid resources */
164                         res->end -= res->start;
165                         res->start = 0;
166                         res->flags |= IORESOURCE_UNSET;
167                 }
168         }
169
170         /* The PCI Host bridge of MPC52xx has a prefetch memory resource
171            fixed to 1Gb. Doesn't fit in the resource system so we remove it */
172         if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
173              (dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200) ) {
174                 struct resource *res = &dev->resource[1];
175                 res->start = res->end = res->flags = 0;
176         }
177 }
178
179 void __init
180 mpc52xx_find_bridges(void)
181 {
182         struct mpc52xx_pci __iomem *pci_regs;
183         struct pci_controller *hose;
184
185         pci_assign_all_buses = 1;
186
187         pci_regs = ioremap(MPC52xx_PA(MPC52xx_PCI_OFFSET), MPC52xx_PCI_SIZE);
188         if (!pci_regs)
189                 return;
190
191         hose = pcibios_alloc_controller();
192         if (!hose) {
193                 iounmap(pci_regs);
194                 return;
195         }
196
197         ppc_md.pci_swizzle = common_swizzle;
198         ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources;
199
200         hose->first_busno = 0;
201         hose->last_busno = 0xff;
202         hose->bus_offset = 0;
203         hose->ops = &mpc52xx_pci_ops;
204
205         mpc52xx_pci_setup(pci_regs);
206
207         hose->pci_mem_offset = MPC52xx_PCI_MEM_OFFSET;
208
209         hose->io_base_virt = ioremap(MPC52xx_PCI_IO_BASE, MPC52xx_PCI_IO_SIZE);
210         isa_io_base = (unsigned long) hose->io_base_virt;
211
212         hose->cfg_addr = &pci_regs->car;
213         hose->cfg_data = hose->io_base_virt;
214
215         /* Setup resources */
216         pci_init_resource(&hose->mem_resources[0],
217                         MPC52xx_PCI_MEM_START,
218                         MPC52xx_PCI_MEM_STOP,
219                         IORESOURCE_MEM|IORESOURCE_PREFETCH,
220                         "PCI prefetchable memory");
221
222         pci_init_resource(&hose->mem_resources[1],
223                         MPC52xx_PCI_MMIO_START,
224                         MPC52xx_PCI_MMIO_STOP,
225                         IORESOURCE_MEM,
226                         "PCI memory");
227
228         pci_init_resource(&hose->io_resource,
229                         MPC52xx_PCI_IO_START,
230                         MPC52xx_PCI_IO_STOP,
231                         IORESOURCE_IO,
232                         "PCI I/O");
233
234 }