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