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