xref: /openbmc/linux/arch/m68k/coldfire/pci.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1f86b9e03SGreg Ungerer /*
2f86b9e03SGreg Ungerer  * pci.c -- PCI bus support for ColdFire processors
3f86b9e03SGreg Ungerer  *
4f86b9e03SGreg Ungerer  * (C) Copyright 2012, Greg Ungerer <gerg@uclinux.com>
5f86b9e03SGreg Ungerer  *
6f86b9e03SGreg Ungerer  * This file is subject to the terms and conditions of the GNU General Public
7f86b9e03SGreg Ungerer  * License.  See the file COPYING in the main directory of this archive
8f86b9e03SGreg Ungerer  * for more details.
9f86b9e03SGreg Ungerer  */
10f86b9e03SGreg Ungerer 
11f86b9e03SGreg Ungerer #include <linux/types.h>
12f86b9e03SGreg Ungerer #include <linux/module.h>
13f86b9e03SGreg Ungerer #include <linux/init.h>
14f86b9e03SGreg Ungerer #include <linux/kernel.h>
15f86b9e03SGreg Ungerer #include <linux/interrupt.h>
16f86b9e03SGreg Ungerer #include <linux/irq.h>
17f86b9e03SGreg Ungerer #include <linux/io.h>
18f86b9e03SGreg Ungerer #include <linux/pci.h>
19f86b9e03SGreg Ungerer #include <linux/delay.h>
20f86b9e03SGreg Ungerer #include <asm/coldfire.h>
21f86b9e03SGreg Ungerer #include <asm/mcfsim.h>
22f86b9e03SGreg Ungerer #include <asm/m54xxpci.h>
23f86b9e03SGreg Ungerer 
24f86b9e03SGreg Ungerer /*
25f86b9e03SGreg Ungerer  * Memory and IO mappings. We use a 1:1 mapping for local host memory to
26de25cfcbSGreg Ungerer  * PCI bus memory (no reason not to really). IO space is mapped in its own
27de25cfcbSGreg Ungerer  * separate address region. The device configuration space is mapped over
28de25cfcbSGreg Ungerer  * the IO map space when we enable it in the PCICAR register.
29f86b9e03SGreg Ungerer  */
30f86b9e03SGreg Ungerer static struct pci_bus *rootbus;
31f86b9e03SGreg Ungerer static unsigned long iospace;
32f86b9e03SGreg Ungerer 
33f86b9e03SGreg Ungerer /*
34*968f0e1cSJulia Lawall  * We need to be careful probing on bus 0 (directly connected to host
3586a8280aSAndrea Gelmini  * bridge). We should only access the well defined possible devices in
36f86b9e03SGreg Ungerer  * use, ignore aliases and the like.
37f86b9e03SGreg Ungerer  */
38f86b9e03SGreg Ungerer static unsigned char mcf_host_slot2sid[32] = {
39f86b9e03SGreg Ungerer 	0, 0, 0, 0, 0, 0, 0, 0,
40f86b9e03SGreg Ungerer 	0, 0, 0, 0, 0, 0, 0, 0,
41f86b9e03SGreg Ungerer 	0, 1, 2, 0, 3, 4, 0, 0,
42f86b9e03SGreg Ungerer 	0, 0, 0, 0, 0, 0, 0, 0,
43f86b9e03SGreg Ungerer };
44f86b9e03SGreg Ungerer 
45f86b9e03SGreg Ungerer static unsigned char mcf_host_irq[] = {
46f86b9e03SGreg Ungerer 	0, 69, 69, 71, 71,
47f86b9e03SGreg Ungerer };
48f86b9e03SGreg Ungerer 
49f86b9e03SGreg Ungerer /*
50f86b9e03SGreg Ungerer  * Configuration space access functions. Configuration space access is
51f86b9e03SGreg Ungerer  * through the IO mapping window, enabling it via the PCICAR register.
52f86b9e03SGreg Ungerer  */
mcf_mk_pcicar(int bus,unsigned int devfn,int where)53f86b9e03SGreg Ungerer static unsigned long mcf_mk_pcicar(int bus, unsigned int devfn, int where)
54f86b9e03SGreg Ungerer {
55f86b9e03SGreg Ungerer 	return (bus << PCICAR_BUSN) | (devfn << PCICAR_DEVFNN) | (where & 0xfc);
56f86b9e03SGreg Ungerer }
57f86b9e03SGreg Ungerer 
mcf_pci_readconfig(struct pci_bus * bus,unsigned int devfn,int where,int size,u32 * value)58f86b9e03SGreg Ungerer static int mcf_pci_readconfig(struct pci_bus *bus, unsigned int devfn,
59f86b9e03SGreg Ungerer 	int where, int size, u32 *value)
60f86b9e03SGreg Ungerer {
61f86b9e03SGreg Ungerer 	unsigned long addr;
62f86b9e03SGreg Ungerer 
63f86b9e03SGreg Ungerer 	*value = 0xffffffff;
64f86b9e03SGreg Ungerer 
65f86b9e03SGreg Ungerer 	if (bus->number == 0) {
66f86b9e03SGreg Ungerer 		if (mcf_host_slot2sid[PCI_SLOT(devfn)] == 0)
67f86b9e03SGreg Ungerer 			return PCIBIOS_SUCCESSFUL;
68f86b9e03SGreg Ungerer 	}
69f86b9e03SGreg Ungerer 
70f86b9e03SGreg Ungerer 	addr = mcf_mk_pcicar(bus->number, devfn, where);
71f86b9e03SGreg Ungerer 	__raw_writel(PCICAR_E | addr, PCICAR);
72082f55c4SGreg Ungerer 	__raw_readl(PCICAR);
73f86b9e03SGreg Ungerer 	addr = iospace + (where & 0x3);
74f86b9e03SGreg Ungerer 
75f86b9e03SGreg Ungerer 	switch (size) {
76f86b9e03SGreg Ungerer 	case 1:
77f86b9e03SGreg Ungerer 		*value = __raw_readb(addr);
78f86b9e03SGreg Ungerer 		break;
79f86b9e03SGreg Ungerer 	case 2:
80f86b9e03SGreg Ungerer 		*value = le16_to_cpu(__raw_readw(addr));
81f86b9e03SGreg Ungerer 		break;
82f86b9e03SGreg Ungerer 	default:
83f86b9e03SGreg Ungerer 		*value = le32_to_cpu(__raw_readl(addr));
84f86b9e03SGreg Ungerer 		break;
85f86b9e03SGreg Ungerer 	}
86f86b9e03SGreg Ungerer 
87f86b9e03SGreg Ungerer 	__raw_writel(0, PCICAR);
88082f55c4SGreg Ungerer 	__raw_readl(PCICAR);
89f86b9e03SGreg Ungerer 	return PCIBIOS_SUCCESSFUL;
90f86b9e03SGreg Ungerer }
91f86b9e03SGreg Ungerer 
mcf_pci_writeconfig(struct pci_bus * bus,unsigned int devfn,int where,int size,u32 value)92f86b9e03SGreg Ungerer static int mcf_pci_writeconfig(struct pci_bus *bus, unsigned int devfn,
93f86b9e03SGreg Ungerer 	int where, int size, u32 value)
94f86b9e03SGreg Ungerer {
95f86b9e03SGreg Ungerer 	unsigned long addr;
96f86b9e03SGreg Ungerer 
97f86b9e03SGreg Ungerer 	if (bus->number == 0) {
98f86b9e03SGreg Ungerer 		if (mcf_host_slot2sid[PCI_SLOT(devfn)] == 0)
99f86b9e03SGreg Ungerer 			return PCIBIOS_SUCCESSFUL;
100f86b9e03SGreg Ungerer 	}
101f86b9e03SGreg Ungerer 
102f86b9e03SGreg Ungerer 	addr = mcf_mk_pcicar(bus->number, devfn, where);
103f86b9e03SGreg Ungerer 	__raw_writel(PCICAR_E | addr, PCICAR);
104082f55c4SGreg Ungerer 	__raw_readl(PCICAR);
105f86b9e03SGreg Ungerer 	addr = iospace + (where & 0x3);
106f86b9e03SGreg Ungerer 
107f86b9e03SGreg Ungerer 	switch (size) {
108f86b9e03SGreg Ungerer 	case 1:
109f86b9e03SGreg Ungerer 		 __raw_writeb(value, addr);
110f86b9e03SGreg Ungerer 		break;
111f86b9e03SGreg Ungerer 	case 2:
112f86b9e03SGreg Ungerer 		__raw_writew(cpu_to_le16(value), addr);
113f86b9e03SGreg Ungerer 		break;
114f86b9e03SGreg Ungerer 	default:
115f86b9e03SGreg Ungerer 		__raw_writel(cpu_to_le32(value), addr);
116f86b9e03SGreg Ungerer 		break;
117f86b9e03SGreg Ungerer 	}
118f86b9e03SGreg Ungerer 
119f86b9e03SGreg Ungerer 	__raw_writel(0, PCICAR);
120082f55c4SGreg Ungerer 	__raw_readl(PCICAR);
121f86b9e03SGreg Ungerer 	return PCIBIOS_SUCCESSFUL;
122f86b9e03SGreg Ungerer }
123f86b9e03SGreg Ungerer 
124f86b9e03SGreg Ungerer static struct pci_ops mcf_pci_ops = {
125f86b9e03SGreg Ungerer 	.read	= mcf_pci_readconfig,
126f86b9e03SGreg Ungerer 	.write	= mcf_pci_writeconfig,
127f86b9e03SGreg Ungerer };
128f86b9e03SGreg Ungerer 
129f86b9e03SGreg Ungerer /*
130f86b9e03SGreg Ungerer  * Initialize the PCI bus registers, and scan the bus.
131f86b9e03SGreg Ungerer  */
132f86b9e03SGreg Ungerer static struct resource mcf_pci_mem = {
133f86b9e03SGreg Ungerer 	.name	= "PCI Memory space",
134f86b9e03SGreg Ungerer 	.start	= PCI_MEM_PA,
135f86b9e03SGreg Ungerer 	.end	= PCI_MEM_PA + PCI_MEM_SIZE - 1,
136f86b9e03SGreg Ungerer 	.flags	= IORESOURCE_MEM,
137f86b9e03SGreg Ungerer };
138f86b9e03SGreg Ungerer 
139f86b9e03SGreg Ungerer static struct resource mcf_pci_io = {
140f86b9e03SGreg Ungerer 	.name	= "PCI IO space",
141f86b9e03SGreg Ungerer 	.start	= 0x400,
142f86b9e03SGreg Ungerer 	.end	= 0x10000 - 1,
143f86b9e03SGreg Ungerer 	.flags	= IORESOURCE_IO,
144f86b9e03SGreg Ungerer };
145f86b9e03SGreg Ungerer 
14619cc4c84SLorenzo Pieralisi static struct resource busn_resource = {
14719cc4c84SLorenzo Pieralisi 	.name	= "PCI busn",
14819cc4c84SLorenzo Pieralisi 	.start	= 0,
14919cc4c84SLorenzo Pieralisi 	.end	= 255,
15019cc4c84SLorenzo Pieralisi 	.flags	= IORESOURCE_BUS,
15119cc4c84SLorenzo Pieralisi };
15219cc4c84SLorenzo Pieralisi 
153f86b9e03SGreg Ungerer /*
154f86b9e03SGreg Ungerer  * Interrupt mapping and setting.
155f86b9e03SGreg Ungerer  */
mcf_pci_map_irq(const struct pci_dev * dev,u8 slot,u8 pin)156f86b9e03SGreg Ungerer static int mcf_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
157f86b9e03SGreg Ungerer {
158f86b9e03SGreg Ungerer 	int sid;
159f86b9e03SGreg Ungerer 
160f86b9e03SGreg Ungerer 	sid = mcf_host_slot2sid[slot];
161f86b9e03SGreg Ungerer 	if (sid)
162f86b9e03SGreg Ungerer 		return mcf_host_irq[sid];
163f86b9e03SGreg Ungerer 	return 0;
164f86b9e03SGreg Ungerer }
165f86b9e03SGreg Ungerer 
mcf_pci_init(void)166f86b9e03SGreg Ungerer static int __init mcf_pci_init(void)
167f86b9e03SGreg Ungerer {
16819cc4c84SLorenzo Pieralisi 	struct pci_host_bridge *bridge;
16919cc4c84SLorenzo Pieralisi 	int ret;
17019cc4c84SLorenzo Pieralisi 
17119cc4c84SLorenzo Pieralisi 	bridge = pci_alloc_host_bridge(0);
17219cc4c84SLorenzo Pieralisi 	if (!bridge)
17319cc4c84SLorenzo Pieralisi 		return -ENOMEM;
17419cc4c84SLorenzo Pieralisi 
175f86b9e03SGreg Ungerer 	pr_info("ColdFire: PCI bus initialization...\n");
176f86b9e03SGreg Ungerer 
177f86b9e03SGreg Ungerer 	/* Reset the external PCI bus */
178f86b9e03SGreg Ungerer 	__raw_writel(PCIGSCR_RESET, PCIGSCR);
179f86b9e03SGreg Ungerer 	__raw_writel(0, PCITCR);
180f86b9e03SGreg Ungerer 
181f86b9e03SGreg Ungerer 	request_resource(&iomem_resource, &mcf_pci_mem);
182f86b9e03SGreg Ungerer 	request_resource(&iomem_resource, &mcf_pci_io);
183f86b9e03SGreg Ungerer 
184f86b9e03SGreg Ungerer 	/* Configure PCI arbiter */
185f86b9e03SGreg Ungerer 	__raw_writel(PACR_INTMPRI | PACR_INTMINTE | PACR_EXTMPRI(0x1f) |
186f86b9e03SGreg Ungerer 		PACR_EXTMINTE(0x1f), PACR);
187f86b9e03SGreg Ungerer 
188f86b9e03SGreg Ungerer 	/* Set required multi-function pins for PCI bus use */
189f86b9e03SGreg Ungerer 	__raw_writew(0x3ff, MCFGPIO_PAR_PCIBG);
190f86b9e03SGreg Ungerer 	__raw_writew(0x3ff, MCFGPIO_PAR_PCIBR);
191f86b9e03SGreg Ungerer 
192f86b9e03SGreg Ungerer 	/* Set up config space for local host bus controller */
193f86b9e03SGreg Ungerer 	__raw_writel(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
194f86b9e03SGreg Ungerer 		PCI_COMMAND_INVALIDATE, PCISCR);
195f86b9e03SGreg Ungerer 	__raw_writel(PCICR1_LT(32) | PCICR1_CL(8), PCICR1);
196f86b9e03SGreg Ungerer 	__raw_writel(0, PCICR2);
197f86b9e03SGreg Ungerer 
198f86b9e03SGreg Ungerer 	/*
199f86b9e03SGreg Ungerer 	 * Set up the initiator windows for memory and IO mapping.
200f86b9e03SGreg Ungerer 	 * These give the CPU bus access onto the PCI bus. One for each of
201f86b9e03SGreg Ungerer 	 * PCI memory and IO address spaces.
202f86b9e03SGreg Ungerer 	 */
203f86b9e03SGreg Ungerer 	__raw_writel(WXBTAR(PCI_MEM_PA, PCI_MEM_BA, PCI_MEM_SIZE),
204f86b9e03SGreg Ungerer 		PCIIW0BTAR);
205f86b9e03SGreg Ungerer 	__raw_writel(WXBTAR(PCI_IO_PA, PCI_IO_BA, PCI_IO_SIZE),
206f86b9e03SGreg Ungerer 		PCIIW1BTAR);
207f86b9e03SGreg Ungerer 	__raw_writel(PCIIWCR_W0_MEM /*| PCIIWCR_W0_MRDL*/ | PCIIWCR_W0_E |
208f86b9e03SGreg Ungerer 		PCIIWCR_W1_IO | PCIIWCR_W1_E, PCIIWCR);
209f86b9e03SGreg Ungerer 
210f86b9e03SGreg Ungerer 	/*
211f86b9e03SGreg Ungerer 	 * Set up the target windows for access from the PCI bus back to the
212f86b9e03SGreg Ungerer 	 * CPU bus. All we need is access to system RAM (for mastering).
213f86b9e03SGreg Ungerer 	 */
214f86b9e03SGreg Ungerer 	__raw_writel(CONFIG_RAMBASE, PCIBAR1);
215f86b9e03SGreg Ungerer 	__raw_writel(CONFIG_RAMBASE | PCITBATR1_E, PCITBATR1);
216f86b9e03SGreg Ungerer 
217f86b9e03SGreg Ungerer 	/* Keep a virtual mapping to IO/config space active */
218f86b9e03SGreg Ungerer 	iospace = (unsigned long) ioremap(PCI_IO_PA, PCI_IO_SIZE);
219c3f4ec05SChristophe JAILLET 	if (iospace == 0) {
220c3f4ec05SChristophe JAILLET 		pci_free_host_bridge(bridge);
221f86b9e03SGreg Ungerer 		return -ENODEV;
222c3f4ec05SChristophe JAILLET 	}
223f86b9e03SGreg Ungerer 	pr_info("Coldfire: PCI IO/config window mapped to 0x%x\n",
224f86b9e03SGreg Ungerer 		(u32) iospace);
225f86b9e03SGreg Ungerer 
226f86b9e03SGreg Ungerer 	/* Turn of PCI reset, and wait for devices to settle */
227f86b9e03SGreg Ungerer 	__raw_writel(0, PCIGSCR);
228f86b9e03SGreg Ungerer 	set_current_state(TASK_UNINTERRUPTIBLE);
229f86b9e03SGreg Ungerer 	schedule_timeout(msecs_to_jiffies(200));
230f86b9e03SGreg Ungerer 
23119cc4c84SLorenzo Pieralisi 
23219cc4c84SLorenzo Pieralisi 	pci_add_resource(&bridge->windows, &ioport_resource);
23319cc4c84SLorenzo Pieralisi 	pci_add_resource(&bridge->windows, &iomem_resource);
23419cc4c84SLorenzo Pieralisi 	pci_add_resource(&bridge->windows, &busn_resource);
23519cc4c84SLorenzo Pieralisi 	bridge->dev.parent = NULL;
23619cc4c84SLorenzo Pieralisi 	bridge->sysdata = NULL;
23719cc4c84SLorenzo Pieralisi 	bridge->busnr = 0;
23819cc4c84SLorenzo Pieralisi 	bridge->ops = &mcf_pci_ops;
23919cc4c84SLorenzo Pieralisi 	bridge->swizzle_irq = pci_common_swizzle;
24019cc4c84SLorenzo Pieralisi 	bridge->map_irq = mcf_pci_map_irq;
24119cc4c84SLorenzo Pieralisi 
24219cc4c84SLorenzo Pieralisi 	ret = pci_scan_root_bus_bridge(bridge);
24319cc4c84SLorenzo Pieralisi 	if (ret) {
24419cc4c84SLorenzo Pieralisi 		pci_free_host_bridge(bridge);
24519cc4c84SLorenzo Pieralisi 		return ret;
24619cc4c84SLorenzo Pieralisi 	}
24719cc4c84SLorenzo Pieralisi 
24819cc4c84SLorenzo Pieralisi 	rootbus = bridge->bus;
249c90570d9SYijing Wang 
250f86b9e03SGreg Ungerer 	rootbus->resource[0] = &mcf_pci_io;
251f86b9e03SGreg Ungerer 	rootbus->resource[1] = &mcf_pci_mem;
252f86b9e03SGreg Ungerer 
253f86b9e03SGreg Ungerer 	pci_bus_size_bridges(rootbus);
254f86b9e03SGreg Ungerer 	pci_bus_assign_resources(rootbus);
255c90570d9SYijing Wang 	pci_bus_add_devices(rootbus);
256f86b9e03SGreg Ungerer 	return 0;
257f86b9e03SGreg Ungerer }
258f86b9e03SGreg Ungerer 
259f86b9e03SGreg Ungerer subsys_initcall(mcf_pci_init);
260