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