Commit | Line | Data |
---|---|---|
f8365ec4 GJ |
1 | /* |
2 | * Atheros AR71xx PCI host controller driver | |
3 | * | |
4 | * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org> | |
5 | * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> | |
6 | * | |
7 | * Parts of this file are based on Atheros' 2.6.15 BSP | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify it | |
10 | * under the terms of the GNU General Public License version 2 as published | |
11 | * by the Free Software Foundation. | |
12 | */ | |
13 | ||
14 | #include <linux/resource.h> | |
15 | #include <linux/types.h> | |
16 | #include <linux/delay.h> | |
17 | #include <linux/bitops.h> | |
18 | #include <linux/pci.h> | |
19 | #include <linux/pci_regs.h> | |
20 | #include <linux/interrupt.h> | |
fb167e89 GJ |
21 | #include <linux/module.h> |
22 | #include <linux/platform_device.h> | |
f8365ec4 GJ |
23 | |
24 | #include <asm/mach-ath79/ar71xx_regs.h> | |
25 | #include <asm/mach-ath79/ath79.h> | |
f8365ec4 | 26 | |
f8365ec4 GJ |
27 | #define AR71XX_PCI_REG_CRP_AD_CBE 0x00 |
28 | #define AR71XX_PCI_REG_CRP_WRDATA 0x04 | |
29 | #define AR71XX_PCI_REG_CRP_RDDATA 0x08 | |
30 | #define AR71XX_PCI_REG_CFG_AD 0x0c | |
31 | #define AR71XX_PCI_REG_CFG_CBE 0x10 | |
32 | #define AR71XX_PCI_REG_CFG_WRDATA 0x14 | |
33 | #define AR71XX_PCI_REG_CFG_RDDATA 0x18 | |
34 | #define AR71XX_PCI_REG_PCI_ERR 0x1c | |
35 | #define AR71XX_PCI_REG_PCI_ERR_ADDR 0x20 | |
36 | #define AR71XX_PCI_REG_AHB_ERR 0x24 | |
37 | #define AR71XX_PCI_REG_AHB_ERR_ADDR 0x28 | |
38 | ||
39 | #define AR71XX_PCI_CRP_CMD_WRITE 0x00010000 | |
40 | #define AR71XX_PCI_CRP_CMD_READ 0x00000000 | |
41 | #define AR71XX_PCI_CFG_CMD_READ 0x0000000a | |
42 | #define AR71XX_PCI_CFG_CMD_WRITE 0x0000000b | |
43 | ||
44 | #define AR71XX_PCI_INT_CORE BIT(4) | |
45 | #define AR71XX_PCI_INT_DEV2 BIT(2) | |
46 | #define AR71XX_PCI_INT_DEV1 BIT(1) | |
47 | #define AR71XX_PCI_INT_DEV0 BIT(0) | |
48 | ||
49 | #define AR71XX_PCI_IRQ_COUNT 5 | |
50 | ||
f18118a8 GJ |
51 | struct ar71xx_pci_controller { |
52 | void __iomem *cfg_base; | |
f18118a8 | 53 | int irq; |
326e8d17 | 54 | int irq_base; |
f18118a8 | 55 | struct pci_controller pci_ctrl; |
42cb60d1 GJ |
56 | struct resource io_res; |
57 | struct resource mem_res; | |
f18118a8 | 58 | }; |
f8365ec4 GJ |
59 | |
60 | /* Byte lane enable bits */ | |
61 | static const u8 ar71xx_pci_ble_table[4][4] = { | |
62 | {0x0, 0xf, 0xf, 0xf}, | |
63 | {0xe, 0xd, 0xb, 0x7}, | |
64 | {0xc, 0xf, 0x3, 0xf}, | |
65 | {0xf, 0xf, 0xf, 0xf}, | |
66 | }; | |
67 | ||
68 | static const u32 ar71xx_pci_read_mask[8] = { | |
69 | 0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0 | |
70 | }; | |
71 | ||
72 | static inline u32 ar71xx_pci_get_ble(int where, int size, int local) | |
73 | { | |
74 | u32 t; | |
75 | ||
76 | t = ar71xx_pci_ble_table[size & 3][where & 3]; | |
77 | BUG_ON(t == 0xf); | |
78 | t <<= (local) ? 20 : 4; | |
79 | ||
80 | return t; | |
81 | } | |
82 | ||
83 | static inline u32 ar71xx_pci_bus_addr(struct pci_bus *bus, unsigned int devfn, | |
84 | int where) | |
85 | { | |
86 | u32 ret; | |
87 | ||
88 | if (!bus->number) { | |
89 | /* type 0 */ | |
90 | ret = (1 << PCI_SLOT(devfn)) | (PCI_FUNC(devfn) << 8) | | |
91 | (where & ~3); | |
92 | } else { | |
93 | /* type 1 */ | |
94 | ret = (bus->number << 16) | (PCI_SLOT(devfn) << 11) | | |
95 | (PCI_FUNC(devfn) << 8) | (where & ~3) | 1; | |
96 | } | |
97 | ||
98 | return ret; | |
99 | } | |
100 | ||
f18118a8 GJ |
101 | static inline struct ar71xx_pci_controller * |
102 | pci_bus_to_ar71xx_controller(struct pci_bus *bus) | |
f8365ec4 | 103 | { |
f18118a8 GJ |
104 | struct pci_controller *hose; |
105 | ||
106 | hose = (struct pci_controller *) bus->sysdata; | |
107 | return container_of(hose, struct ar71xx_pci_controller, pci_ctrl); | |
108 | } | |
109 | ||
110 | static int ar71xx_pci_check_error(struct ar71xx_pci_controller *apc, int quiet) | |
111 | { | |
112 | void __iomem *base = apc->cfg_base; | |
f8365ec4 GJ |
113 | u32 pci_err; |
114 | u32 ahb_err; | |
115 | ||
116 | pci_err = __raw_readl(base + AR71XX_PCI_REG_PCI_ERR) & 3; | |
117 | if (pci_err) { | |
118 | if (!quiet) { | |
119 | u32 addr; | |
120 | ||
121 | addr = __raw_readl(base + AR71XX_PCI_REG_PCI_ERR_ADDR); | |
122 | pr_crit("ar71xx: %s bus error %d at addr 0x%x\n", | |
123 | "PCI", pci_err, addr); | |
124 | } | |
125 | ||
126 | /* clear PCI error status */ | |
127 | __raw_writel(pci_err, base + AR71XX_PCI_REG_PCI_ERR); | |
128 | } | |
129 | ||
130 | ahb_err = __raw_readl(base + AR71XX_PCI_REG_AHB_ERR) & 1; | |
131 | if (ahb_err) { | |
132 | if (!quiet) { | |
133 | u32 addr; | |
134 | ||
135 | addr = __raw_readl(base + AR71XX_PCI_REG_AHB_ERR_ADDR); | |
136 | pr_crit("ar71xx: %s bus error %d at addr 0x%x\n", | |
137 | "AHB", ahb_err, addr); | |
138 | } | |
139 | ||
140 | /* clear AHB error status */ | |
141 | __raw_writel(ahb_err, base + AR71XX_PCI_REG_AHB_ERR); | |
142 | } | |
143 | ||
144 | return !!(ahb_err | pci_err); | |
145 | } | |
146 | ||
f18118a8 GJ |
147 | static inline void ar71xx_pci_local_write(struct ar71xx_pci_controller *apc, |
148 | int where, int size, u32 value) | |
f8365ec4 | 149 | { |
f18118a8 | 150 | void __iomem *base = apc->cfg_base; |
f8365ec4 GJ |
151 | u32 ad_cbe; |
152 | ||
153 | value = value << (8 * (where & 3)); | |
154 | ||
155 | ad_cbe = AR71XX_PCI_CRP_CMD_WRITE | (where & ~3); | |
156 | ad_cbe |= ar71xx_pci_get_ble(where, size, 1); | |
157 | ||
158 | __raw_writel(ad_cbe, base + AR71XX_PCI_REG_CRP_AD_CBE); | |
159 | __raw_writel(value, base + AR71XX_PCI_REG_CRP_WRDATA); | |
160 | } | |
161 | ||
162 | static inline int ar71xx_pci_set_cfgaddr(struct pci_bus *bus, | |
163 | unsigned int devfn, | |
164 | int where, int size, u32 cmd) | |
165 | { | |
f18118a8 GJ |
166 | struct ar71xx_pci_controller *apc = pci_bus_to_ar71xx_controller(bus); |
167 | void __iomem *base = apc->cfg_base; | |
f8365ec4 GJ |
168 | u32 addr; |
169 | ||
170 | addr = ar71xx_pci_bus_addr(bus, devfn, where); | |
171 | ||
172 | __raw_writel(addr, base + AR71XX_PCI_REG_CFG_AD); | |
173 | __raw_writel(cmd | ar71xx_pci_get_ble(where, size, 0), | |
174 | base + AR71XX_PCI_REG_CFG_CBE); | |
175 | ||
f18118a8 | 176 | return ar71xx_pci_check_error(apc, 1); |
f8365ec4 GJ |
177 | } |
178 | ||
179 | static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, | |
180 | int where, int size, u32 *value) | |
181 | { | |
f18118a8 GJ |
182 | struct ar71xx_pci_controller *apc = pci_bus_to_ar71xx_controller(bus); |
183 | void __iomem *base = apc->cfg_base; | |
f8365ec4 GJ |
184 | u32 data; |
185 | int err; | |
186 | int ret; | |
187 | ||
188 | ret = PCIBIOS_SUCCESSFUL; | |
189 | data = ~0; | |
190 | ||
f8365ec4 GJ |
191 | err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size, |
192 | AR71XX_PCI_CFG_CMD_READ); | |
193 | if (err) | |
194 | ret = PCIBIOS_DEVICE_NOT_FOUND; | |
195 | else | |
196 | data = __raw_readl(base + AR71XX_PCI_REG_CFG_RDDATA); | |
197 | ||
f8365ec4 GJ |
198 | *value = (data >> (8 * (where & 3))) & ar71xx_pci_read_mask[size & 7]; |
199 | ||
200 | return ret; | |
201 | } | |
202 | ||
203 | static int ar71xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, | |
204 | int where, int size, u32 value) | |
205 | { | |
f18118a8 GJ |
206 | struct ar71xx_pci_controller *apc = pci_bus_to_ar71xx_controller(bus); |
207 | void __iomem *base = apc->cfg_base; | |
f8365ec4 GJ |
208 | int err; |
209 | int ret; | |
210 | ||
211 | value = value << (8 * (where & 3)); | |
212 | ret = PCIBIOS_SUCCESSFUL; | |
213 | ||
f8365ec4 GJ |
214 | err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size, |
215 | AR71XX_PCI_CFG_CMD_WRITE); | |
216 | if (err) | |
217 | ret = PCIBIOS_DEVICE_NOT_FOUND; | |
218 | else | |
219 | __raw_writel(value, base + AR71XX_PCI_REG_CFG_WRDATA); | |
220 | ||
f8365ec4 GJ |
221 | return ret; |
222 | } | |
223 | ||
224 | static struct pci_ops ar71xx_pci_ops = { | |
225 | .read = ar71xx_pci_read_config, | |
226 | .write = ar71xx_pci_write_config, | |
227 | }; | |
228 | ||
bd0b9ac4 | 229 | static void ar71xx_pci_irq_handler(struct irq_desc *desc) |
f8365ec4 | 230 | { |
326e8d17 | 231 | struct ar71xx_pci_controller *apc; |
f8365ec4 GJ |
232 | void __iomem *base = ath79_reset_base; |
233 | u32 pending; | |
234 | ||
25aae561 | 235 | apc = irq_desc_get_handler_data(desc); |
326e8d17 | 236 | |
f8365ec4 GJ |
237 | pending = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_STATUS) & |
238 | __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); | |
239 | ||
240 | if (pending & AR71XX_PCI_INT_DEV0) | |
326e8d17 | 241 | generic_handle_irq(apc->irq_base + 0); |
f8365ec4 GJ |
242 | |
243 | else if (pending & AR71XX_PCI_INT_DEV1) | |
326e8d17 | 244 | generic_handle_irq(apc->irq_base + 1); |
f8365ec4 GJ |
245 | |
246 | else if (pending & AR71XX_PCI_INT_DEV2) | |
326e8d17 | 247 | generic_handle_irq(apc->irq_base + 2); |
f8365ec4 GJ |
248 | |
249 | else if (pending & AR71XX_PCI_INT_CORE) | |
326e8d17 | 250 | generic_handle_irq(apc->irq_base + 4); |
f8365ec4 GJ |
251 | |
252 | else | |
253 | spurious_interrupt(); | |
254 | } | |
255 | ||
256 | static void ar71xx_pci_irq_unmask(struct irq_data *d) | |
257 | { | |
326e8d17 GJ |
258 | struct ar71xx_pci_controller *apc; |
259 | unsigned int irq; | |
f8365ec4 GJ |
260 | void __iomem *base = ath79_reset_base; |
261 | u32 t; | |
262 | ||
326e8d17 GJ |
263 | apc = irq_data_get_irq_chip_data(d); |
264 | irq = d->irq - apc->irq_base; | |
265 | ||
f8365ec4 GJ |
266 | t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); |
267 | __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE); | |
268 | ||
269 | /* flush write */ | |
270 | __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); | |
271 | } | |
272 | ||
273 | static void ar71xx_pci_irq_mask(struct irq_data *d) | |
274 | { | |
326e8d17 GJ |
275 | struct ar71xx_pci_controller *apc; |
276 | unsigned int irq; | |
f8365ec4 GJ |
277 | void __iomem *base = ath79_reset_base; |
278 | u32 t; | |
279 | ||
326e8d17 GJ |
280 | apc = irq_data_get_irq_chip_data(d); |
281 | irq = d->irq - apc->irq_base; | |
282 | ||
f8365ec4 GJ |
283 | t = __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); |
284 | __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_PCI_INT_ENABLE); | |
285 | ||
286 | /* flush write */ | |
287 | __raw_readl(base + AR71XX_RESET_REG_PCI_INT_ENABLE); | |
288 | } | |
289 | ||
290 | static struct irq_chip ar71xx_pci_irq_chip = { | |
291 | .name = "AR71XX PCI", | |
292 | .irq_mask = ar71xx_pci_irq_mask, | |
293 | .irq_unmask = ar71xx_pci_irq_unmask, | |
294 | .irq_mask_ack = ar71xx_pci_irq_mask, | |
295 | }; | |
296 | ||
f18118a8 | 297 | static void ar71xx_pci_irq_init(struct ar71xx_pci_controller *apc) |
f8365ec4 GJ |
298 | { |
299 | void __iomem *base = ath79_reset_base; | |
300 | int i; | |
301 | ||
302 | __raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_ENABLE); | |
303 | __raw_writel(0, base + AR71XX_RESET_REG_PCI_INT_STATUS); | |
304 | ||
305 | BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR71XX_PCI_IRQ_COUNT); | |
306 | ||
326e8d17 GJ |
307 | apc->irq_base = ATH79_PCI_IRQ_BASE; |
308 | for (i = apc->irq_base; | |
309 | i < apc->irq_base + AR71XX_PCI_IRQ_COUNT; i++) { | |
f8365ec4 GJ |
310 | irq_set_chip_and_handler(i, &ar71xx_pci_irq_chip, |
311 | handle_level_irq); | |
326e8d17 GJ |
312 | irq_set_chip_data(i, apc); |
313 | } | |
f8365ec4 | 314 | |
777fd18a TG |
315 | irq_set_chained_handler_and_data(apc->irq, ar71xx_pci_irq_handler, |
316 | apc); | |
f8365ec4 GJ |
317 | } |
318 | ||
fb167e89 | 319 | static void ar71xx_pci_reset(void) |
f8365ec4 | 320 | { |
f8365ec4 GJ |
321 | ath79_device_reset_set(AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE); |
322 | mdelay(100); | |
323 | ||
324 | ath79_device_reset_clear(AR71XX_RESET_PCI_BUS | AR71XX_RESET_PCI_CORE); | |
325 | mdelay(100); | |
326 | ||
24b0e3e8 | 327 | ath79_ddr_set_pci_windows(); |
f8365ec4 GJ |
328 | mdelay(100); |
329 | } | |
330 | ||
fb167e89 GJ |
331 | static int ar71xx_pci_probe(struct platform_device *pdev) |
332 | { | |
f18118a8 | 333 | struct ar71xx_pci_controller *apc; |
fb167e89 | 334 | struct resource *res; |
fb167e89 GJ |
335 | u32 t; |
336 | ||
f18118a8 GJ |
337 | apc = devm_kzalloc(&pdev->dev, sizeof(struct ar71xx_pci_controller), |
338 | GFP_KERNEL); | |
339 | if (!apc) | |
340 | return -ENOMEM; | |
341 | ||
fb167e89 | 342 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg_base"); |
f560fabd SMP |
343 | apc->cfg_base = devm_ioremap_resource(&pdev->dev, res); |
344 | if (IS_ERR(apc->cfg_base)) | |
345 | return PTR_ERR(apc->cfg_base); | |
fb167e89 | 346 | |
f18118a8 GJ |
347 | apc->irq = platform_get_irq(pdev, 0); |
348 | if (apc->irq < 0) | |
fb167e89 GJ |
349 | return -EINVAL; |
350 | ||
42cb60d1 GJ |
351 | res = platform_get_resource_byname(pdev, IORESOURCE_IO, "io_base"); |
352 | if (!res) | |
353 | return -EINVAL; | |
354 | ||
355 | apc->io_res.parent = res; | |
356 | apc->io_res.name = "PCI IO space"; | |
357 | apc->io_res.start = res->start; | |
358 | apc->io_res.end = res->end; | |
359 | apc->io_res.flags = IORESOURCE_IO; | |
360 | ||
361 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem_base"); | |
362 | if (!res) | |
363 | return -EINVAL; | |
364 | ||
365 | apc->mem_res.parent = res; | |
366 | apc->mem_res.name = "PCI memory space"; | |
367 | apc->mem_res.start = res->start; | |
368 | apc->mem_res.end = res->end; | |
369 | apc->mem_res.flags = IORESOURCE_MEM; | |
370 | ||
fb167e89 GJ |
371 | ar71xx_pci_reset(); |
372 | ||
373 | /* setup COMMAND register */ | |
374 | t = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | |
375 | | PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK; | |
f18118a8 | 376 | ar71xx_pci_local_write(apc, PCI_COMMAND, 4, t); |
fb167e89 GJ |
377 | |
378 | /* clear bus errors */ | |
f18118a8 GJ |
379 | ar71xx_pci_check_error(apc, 1); |
380 | ||
381 | ar71xx_pci_irq_init(apc); | |
fb167e89 | 382 | |
f18118a8 | 383 | apc->pci_ctrl.pci_ops = &ar71xx_pci_ops; |
42cb60d1 GJ |
384 | apc->pci_ctrl.mem_resource = &apc->mem_res; |
385 | apc->pci_ctrl.io_resource = &apc->io_res; | |
fb167e89 | 386 | |
f18118a8 | 387 | register_pci_controller(&apc->pci_ctrl); |
fb167e89 GJ |
388 | |
389 | return 0; | |
390 | } | |
391 | ||
392 | static struct platform_driver ar71xx_pci_driver = { | |
393 | .probe = ar71xx_pci_probe, | |
394 | .driver = { | |
395 | .name = "ar71xx-pci", | |
fb167e89 GJ |
396 | }, |
397 | }; | |
398 | ||
399 | static int __init ar71xx_pci_init(void) | |
400 | { | |
401 | return platform_driver_register(&ar71xx_pci_driver); | |
402 | } | |
403 | ||
404 | postcore_initcall(ar71xx_pci_init); |