diff options
author | Mike Rapoport <mike@compulab.co.il> | 2007-09-23 10:59:52 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2007-10-15 13:53:59 -0400 |
commit | a8fc0789558d81d2898b87473404b71b7f7cd0fc (patch) | |
tree | 90294fc683be115d5c7bae3c7aed5916d0ad7db7 /arch/arm | |
parent | 3696a8a426f8caebd97463e9b5cf9f06c1c36759 (diff) |
[ARM] 4577/1: ITE 8152 PCI bridge support
This patch provides driver for ITE 8152 PCI bridge.
Signed-off-by: Mike Rapoport <mike@compulab.co.il>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/common/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/common/it8152.c | 387 | ||||
-rw-r--r-- | arch/arm/kernel/bios32.c | 28 |
3 files changed, 413 insertions, 3 deletions
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index e1289a256ce5..3d0b9fa42f84 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile | |||
@@ -17,3 +17,4 @@ obj-$(CONFIG_SHARPSL_PM) += sharpsl_pm.o | |||
17 | obj-$(CONFIG_SHARP_SCOOP) += scoop.o | 17 | obj-$(CONFIG_SHARP_SCOOP) += scoop.o |
18 | obj-$(CONFIG_ARCH_IXP2000) += uengine.o | 18 | obj-$(CONFIG_ARCH_IXP2000) += uengine.o |
19 | obj-$(CONFIG_ARCH_IXP23XX) += uengine.o | 19 | obj-$(CONFIG_ARCH_IXP23XX) += uengine.o |
20 | obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o | ||
diff --git a/arch/arm/common/it8152.c b/arch/arm/common/it8152.c new file mode 100644 index 000000000000..c03de9bfd76b --- /dev/null +++ b/arch/arm/common/it8152.c | |||
@@ -0,0 +1,387 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/common/it8152.c | ||
3 | * | ||
4 | * Copyright Compulab Ltd, 2002-2007 | ||
5 | * Mike Rapoport <mike@compulab.co.il> | ||
6 | * | ||
7 | * The DMA bouncing part is taken from arch/arm/mach-ixp4xx/common-pci.c | ||
8 | * (see this file for respective copyrights) | ||
9 | * | ||
10 | * Thanks to Guennadi Liakhovetski <gl@dsa-ac.de> for IRQ enumberation | ||
11 | * and demux code. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License version 2 as | ||
15 | * published by the Free Software Foundation. | ||
16 | */ | ||
17 | |||
18 | #include <linux/sched.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/pci.h> | ||
21 | #include <linux/ptrace.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/mm.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/ioport.h> | ||
27 | #include <linux/irq.h> | ||
28 | #include <linux/io.h> | ||
29 | |||
30 | #include <asm/mach/pci.h> | ||
31 | #include <asm/hardware/it8152.h> | ||
32 | |||
33 | #define MAX_SLOTS 21 | ||
34 | |||
35 | static void it8152_mask_irq(unsigned int irq) | ||
36 | { | ||
37 | if (irq >= IT8152_LD_IRQ(0)) { | ||
38 | __raw_writel((__raw_readl(IT8152_INTC_LDCNIMR) | | ||
39 | (1 << (irq - IT8152_LD_IRQ(0)))), | ||
40 | IT8152_INTC_LDCNIMR); | ||
41 | } else if (irq >= IT8152_LP_IRQ(0)) { | ||
42 | __raw_writel((__raw_readl(IT8152_INTC_LPCNIMR) | | ||
43 | (1 << (irq - IT8152_LP_IRQ(0)))), | ||
44 | IT8152_INTC_LPCNIMR); | ||
45 | } else if (irq >= IT8152_PD_IRQ(0)) { | ||
46 | __raw_writel((__raw_readl(IT8152_INTC_PDCNIMR) | | ||
47 | (1 << (irq - IT8152_PD_IRQ(0)))), | ||
48 | IT8152_INTC_PDCNIMR); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | static void it8152_unmask_irq(unsigned int irq) | ||
53 | { | ||
54 | if (irq >= IT8152_LD_IRQ(0)) { | ||
55 | __raw_writel((__raw_readl(IT8152_INTC_LDCNIMR) & | ||
56 | ~(1 << (irq - IT8152_LD_IRQ(0)))), | ||
57 | IT8152_INTC_LDCNIMR); | ||
58 | } else if (irq >= IT8152_LP_IRQ(0)) { | ||
59 | __raw_writel((__raw_readl(IT8152_INTC_LPCNIMR) & | ||
60 | ~(1 << (irq - IT8152_LP_IRQ(0)))), | ||
61 | IT8152_INTC_LPCNIMR); | ||
62 | } else if (irq >= IT8152_PD_IRQ(0)) { | ||
63 | __raw_writel((__raw_readl(IT8152_INTC_PDCNIMR) & | ||
64 | ~(1 << (irq - IT8152_PD_IRQ(0)))), | ||
65 | IT8152_INTC_PDCNIMR); | ||
66 | } | ||
67 | } | ||
68 | |||
69 | static inline void it8152_irq(int irq) | ||
70 | { | ||
71 | struct irq_desc *desc; | ||
72 | |||
73 | printk(KERN_DEBUG "===> %s: irq=%d\n", __FUNCTION__, irq); | ||
74 | |||
75 | desc = irq_desc + irq; | ||
76 | desc_handle_irq(irq, desc); | ||
77 | } | ||
78 | |||
79 | static struct irq_chip it8152_irq_chip = { | ||
80 | .name = "it8152", | ||
81 | .ack = it8152_mask_irq, | ||
82 | .mask = it8152_mask_irq, | ||
83 | .unmask = it8152_unmask_irq, | ||
84 | }; | ||
85 | |||
86 | void it8152_init_irq(void) | ||
87 | { | ||
88 | int irq; | ||
89 | |||
90 | __raw_writel((0xffff), IT8152_INTC_PDCNIMR); | ||
91 | __raw_writel((0), IT8152_INTC_PDCNIRR); | ||
92 | __raw_writel((0xffff), IT8152_INTC_LPCNIMR); | ||
93 | __raw_writel((0), IT8152_INTC_LPCNIRR); | ||
94 | __raw_writel((0xffff), IT8152_INTC_LDCNIMR); | ||
95 | __raw_writel((0), IT8152_INTC_LDCNIRR); | ||
96 | |||
97 | for (irq = IT8152_IRQ(0); irq <= IT8152_LAST_IRQ; irq++) { | ||
98 | set_irq_chip(irq, &it8152_irq_chip); | ||
99 | set_irq_handler(irq, handle_level_irq); | ||
100 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | ||
101 | } | ||
102 | } | ||
103 | |||
104 | void it8152_irq_demux(unsigned int irq, struct irq_desc *desc) | ||
105 | { | ||
106 | int bits_pd, bits_lp, bits_ld; | ||
107 | int i; | ||
108 | |||
109 | printk(KERN_DEBUG "=> %s: irq = %d\n", __FUNCTION__, irq); | ||
110 | |||
111 | while (1) { | ||
112 | /* Read all */ | ||
113 | bits_pd = __raw_readl(IT8152_INTC_PDCNIRR); | ||
114 | bits_lp = __raw_readl(IT8152_INTC_LPCNIRR); | ||
115 | bits_ld = __raw_readl(IT8152_INTC_LDCNIRR); | ||
116 | |||
117 | /* Ack */ | ||
118 | __raw_writel((~bits_pd), IT8152_INTC_PDCNIRR); | ||
119 | __raw_writel((~bits_lp), IT8152_INTC_LPCNIRR); | ||
120 | __raw_writel((~bits_ld), IT8152_INTC_LDCNIRR); | ||
121 | |||
122 | if (!(bits_ld | bits_lp | bits_pd)) { | ||
123 | /* Re-read to guarantee, that there was a moment of | ||
124 | time, when they all three were 0. */ | ||
125 | bits_pd = __raw_readl(IT8152_INTC_PDCNIRR); | ||
126 | bits_lp = __raw_readl(IT8152_INTC_LPCNIRR); | ||
127 | if (!(bits_ld | bits_lp | bits_pd)) | ||
128 | return; | ||
129 | } | ||
130 | |||
131 | bits_pd &= ((1 << IT8152_PD_IRQ_COUNT) - 1); | ||
132 | while (bits_pd) { | ||
133 | i = __ffs(bits_pd); | ||
134 | it8152_irq(IT8152_PD_IRQ(i)); | ||
135 | bits_pd &= ~(1 << i); | ||
136 | } | ||
137 | |||
138 | bits_lp &= ((1 << IT8152_LP_IRQ_COUNT) - 1); | ||
139 | while (bits_lp) { | ||
140 | i = __ffs(bits_pd); | ||
141 | it8152_irq(IT8152_LP_IRQ(i)); | ||
142 | bits_lp &= ~(1 << i); | ||
143 | } | ||
144 | |||
145 | bits_ld &= ((1 << IT8152_LD_IRQ_COUNT) - 1); | ||
146 | while (bits_ld) { | ||
147 | i = __ffs(bits_pd); | ||
148 | it8152_irq(IT8152_LD_IRQ(i)); | ||
149 | bits_ld &= ~(1 << i); | ||
150 | } | ||
151 | } | ||
152 | } | ||
153 | |||
154 | /* mapping for on-chip devices */ | ||
155 | int __init it8152_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
156 | { | ||
157 | if ((dev->vendor == PCI_VENDOR_ID_ITE) && | ||
158 | (dev->device == PCI_DEVICE_ID_ITE_8152)) { | ||
159 | if ((dev->class >> 8) == PCI_CLASS_MULTIMEDIA_AUDIO) | ||
160 | return IT8152_AUDIO_INT; | ||
161 | if ((dev->class >> 8) == PCI_CLASS_SERIAL_USB) | ||
162 | return IT8152_USB_INT; | ||
163 | if ((dev->class >> 8) == PCI_CLASS_SYSTEM_DMA) | ||
164 | return IT8152_CDMA_INT; | ||
165 | } | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static unsigned long it8152_pci_dev_base_address(struct pci_bus *bus, | ||
171 | unsigned int devfn) | ||
172 | { | ||
173 | unsigned long addr = 0; | ||
174 | |||
175 | if (bus->number == 0) { | ||
176 | if (devfn < PCI_DEVFN(MAX_SLOTS, 0)) | ||
177 | addr = (devfn << 8); | ||
178 | } else | ||
179 | addr = (bus->number << 16) | (devfn << 8); | ||
180 | |||
181 | return addr; | ||
182 | } | ||
183 | |||
184 | static int it8152_pci_read_config(struct pci_bus *bus, | ||
185 | unsigned int devfn, int where, | ||
186 | int size, u32 *value) | ||
187 | { | ||
188 | unsigned long addr = it8152_pci_dev_base_address(bus, devfn); | ||
189 | u32 v; | ||
190 | int shift; | ||
191 | |||
192 | shift = (where & 3); | ||
193 | |||
194 | __raw_writel((addr + where), IT8152_PCI_CFG_ADDR); | ||
195 | v = (__raw_readl(IT8152_PCI_CFG_DATA) >> (8 * (shift))); | ||
196 | |||
197 | *value = v; | ||
198 | |||
199 | return PCIBIOS_SUCCESSFUL; | ||
200 | } | ||
201 | |||
202 | static int it8152_pci_write_config(struct pci_bus *bus, | ||
203 | unsigned int devfn, int where, | ||
204 | int size, u32 value) | ||
205 | { | ||
206 | unsigned long addr = it8152_pci_dev_base_address(bus, devfn); | ||
207 | u32 v, vtemp, mask = 0; | ||
208 | int shift; | ||
209 | |||
210 | if (size == 1) | ||
211 | mask = 0xff; | ||
212 | if (size == 2) | ||
213 | mask = 0xffff; | ||
214 | |||
215 | shift = (where & 3); | ||
216 | |||
217 | __raw_writel((addr + where), IT8152_PCI_CFG_ADDR); | ||
218 | vtemp = __raw_readl(IT8152_PCI_CFG_DATA); | ||
219 | |||
220 | if (mask) | ||
221 | vtemp &= ~(mask << (8 * shift)); | ||
222 | else | ||
223 | vtemp = 0; | ||
224 | |||
225 | v = (value << (8 * shift)); | ||
226 | __raw_writel((addr + where), IT8152_PCI_CFG_ADDR); | ||
227 | __raw_writel((v | vtemp), IT8152_PCI_CFG_DATA); | ||
228 | |||
229 | return PCIBIOS_SUCCESSFUL; | ||
230 | } | ||
231 | |||
232 | static struct pci_ops it8152_ops = { | ||
233 | .read = it8152_pci_read_config, | ||
234 | .write = it8152_pci_write_config, | ||
235 | }; | ||
236 | |||
237 | static struct resource it8152_io = { | ||
238 | .name = "IT8152 PCI I/O region", | ||
239 | .flags = IORESOURCE_IO, | ||
240 | }; | ||
241 | |||
242 | static struct resource it8152_mem = { | ||
243 | .name = "IT8152 PCI memory region", | ||
244 | .start = 0x10000000, | ||
245 | .end = 0x13e00000, | ||
246 | .flags = IORESOURCE_MEM, | ||
247 | }; | ||
248 | |||
249 | /* | ||
250 | * The following functions are needed for DMA bouncing. | ||
251 | * ITE8152 chip can addrees up to 64MByte, so all the devices | ||
252 | * connected to ITE8152 (PCI and USB) should have limited DMA window | ||
253 | */ | ||
254 | |||
255 | /* | ||
256 | * Setup DMA mask to 64MB on devices connected to ITE8152. Ignore all | ||
257 | * other devices. | ||
258 | */ | ||
259 | static int it8152_pci_platform_notify(struct device *dev) | ||
260 | { | ||
261 | if (dev->bus == &pci_bus_type) { | ||
262 | if (dev->dma_mask) | ||
263 | *dev->dma_mask = (SZ_64M - 1) | PHYS_OFFSET; | ||
264 | dev->coherent_dma_mask = (SZ_64M - 1) | PHYS_OFFSET; | ||
265 | dmabounce_register_dev(dev, 2048, 4096); | ||
266 | } | ||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int it8152_pci_platform_notify_remove(struct device *dev) | ||
271 | { | ||
272 | if (dev->bus == &pci_bus_type) | ||
273 | dmabounce_unregister_dev(dev); | ||
274 | |||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) | ||
279 | { | ||
280 | dev_dbg(dev, "%s: dma_addr %08x, size %08x\n", | ||
281 | __FUNCTION__, dma_addr, size); | ||
282 | return (dev->bus == &pci_bus_type) && | ||
283 | ((dma_addr + size - PHYS_OFFSET) >= SZ_64M); | ||
284 | } | ||
285 | |||
286 | /* | ||
287 | * We override these so we properly do dmabounce otherwise drivers | ||
288 | * are able to set the dma_mask to 0xffffffff and we can no longer | ||
289 | * trap bounces. :( | ||
290 | * | ||
291 | * We just return true on everyhing except for < 64MB in which case | ||
292 | * we will fail miseralby and die since we can't handle that case. | ||
293 | */ | ||
294 | int pci_set_dma_mask(struct pci_dev *dev, u64 mask) | ||
295 | { | ||
296 | printk(KERN_DEBUG "%s: %s %llx\n", | ||
297 | __FUNCTION__, dev->dev.bus_id, mask); | ||
298 | if (mask >= PHYS_OFFSET + SZ_64M - 1) | ||
299 | return 0; | ||
300 | |||
301 | return -EIO; | ||
302 | } | ||
303 | |||
304 | int | ||
305 | pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) | ||
306 | { | ||
307 | printk(KERN_DEBUG "%s: %s %llx\n", | ||
308 | __FUNCTION__, dev->dev.bus_id, mask); | ||
309 | if (mask >= PHYS_OFFSET + SZ_64M - 1) | ||
310 | return 0; | ||
311 | |||
312 | return -EIO; | ||
313 | } | ||
314 | |||
315 | int __init it8152_pci_setup(int nr, struct pci_sys_data *sys) | ||
316 | { | ||
317 | it8152_io.start = IT8152_IO_BASE + 0x12000; | ||
318 | it8152_io.end = IT8152_IO_BASE + 0x12000 + 0x100000; | ||
319 | |||
320 | sys->mem_offset = 0x10000000; | ||
321 | sys->io_offset = IT8152_IO_BASE; | ||
322 | |||
323 | if (request_resource(&ioport_resource, &it8152_io)) { | ||
324 | printk(KERN_ERR "PCI: unable to allocate IO region\n"); | ||
325 | goto err0; | ||
326 | } | ||
327 | if (request_resource(&iomem_resource, &it8152_mem)) { | ||
328 | printk(KERN_ERR "PCI: unable to allocate memory region\n"); | ||
329 | goto err1; | ||
330 | } | ||
331 | |||
332 | sys->resource[0] = &it8152_io; | ||
333 | sys->resource[1] = &it8152_mem; | ||
334 | |||
335 | if (platform_notify || platform_notify_remove) { | ||
336 | printk(KERN_ERR "PCI: Can't use platform_notify\n"); | ||
337 | goto err2; | ||
338 | } | ||
339 | |||
340 | platform_notify = it8152_pci_platform_notify; | ||
341 | platform_notify_remove = it8152_pci_platform_notify_remove; | ||
342 | |||
343 | return 1; | ||
344 | |||
345 | err2: | ||
346 | release_resource(&it8152_io); | ||
347 | err1: | ||
348 | release_resource(&it8152_mem); | ||
349 | err0: | ||
350 | return -EBUSY; | ||
351 | } | ||
352 | |||
353 | /* | ||
354 | * If we set up a device for bus mastering, we need to check the latency | ||
355 | * timer as we don't have even crappy BIOSes to set it properly. | ||
356 | * The implementation is from arch/i386/pci/i386.c | ||
357 | */ | ||
358 | unsigned int pcibios_max_latency = 255; | ||
359 | |||
360 | void pcibios_set_master(struct pci_dev *dev) | ||
361 | { | ||
362 | u8 lat; | ||
363 | |||
364 | /* no need to update on-chip OHCI controller */ | ||
365 | if ((dev->vendor == PCI_VENDOR_ID_ITE) && | ||
366 | (dev->device == PCI_DEVICE_ID_ITE_8152) && | ||
367 | ((dev->class >> 8) == PCI_CLASS_SERIAL_USB)) | ||
368 | return; | ||
369 | |||
370 | pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); | ||
371 | if (lat < 16) | ||
372 | lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; | ||
373 | else if (lat > pcibios_max_latency) | ||
374 | lat = pcibios_max_latency; | ||
375 | else | ||
376 | return; | ||
377 | printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", | ||
378 | pci_name(dev), lat); | ||
379 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); | ||
380 | } | ||
381 | |||
382 | |||
383 | struct pci_bus * __init it8152_pci_scan_bus(int nr, struct pci_sys_data *sys) | ||
384 | { | ||
385 | return pci_scan_bus(nr, &it8152_ops, sys); | ||
386 | } | ||
387 | |||
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index a2dd930d11ef..e5747547b44c 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c | |||
@@ -279,6 +279,25 @@ static void __devinit pci_fixup_cy82c693(struct pci_dev *dev) | |||
279 | } | 279 | } |
280 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, pci_fixup_cy82c693); | 280 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, pci_fixup_cy82c693); |
281 | 281 | ||
282 | static void __init pci_fixup_it8152(struct pci_dev *dev) | ||
283 | { | ||
284 | int i; | ||
285 | /* fixup for ITE 8152 devices */ | ||
286 | /* FIXME: add defines for class 0x68000 and 0x80103 */ | ||
287 | if ((dev->class >> 8) == PCI_CLASS_BRIDGE_HOST || | ||
288 | dev->class == 0x68000 || | ||
289 | dev->class == 0x80103) { | ||
290 | for (i = 0; i < PCI_NUM_RESOURCES; i++) { | ||
291 | dev->resource[i].start = 0; | ||
292 | dev->resource[i].end = 0; | ||
293 | dev->resource[i].flags = 0; | ||
294 | } | ||
295 | } | ||
296 | } | ||
297 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8152, pci_fixup_it8152); | ||
298 | |||
299 | |||
300 | |||
282 | void __devinit pcibios_update_irq(struct pci_dev *dev, int irq) | 301 | void __devinit pcibios_update_irq(struct pci_dev *dev, int irq) |
283 | { | 302 | { |
284 | if (debug_pci) | 303 | if (debug_pci) |
@@ -292,9 +311,12 @@ void __devinit pcibios_update_irq(struct pci_dev *dev, int irq) | |||
292 | */ | 311 | */ |
293 | static inline int pdev_bad_for_parity(struct pci_dev *dev) | 312 | static inline int pdev_bad_for_parity(struct pci_dev *dev) |
294 | { | 313 | { |
295 | return (dev->vendor == PCI_VENDOR_ID_INTERG && | 314 | return ((dev->vendor == PCI_VENDOR_ID_INTERG && |
296 | (dev->device == PCI_DEVICE_ID_INTERG_2000 || | 315 | (dev->device == PCI_DEVICE_ID_INTERG_2000 || |
297 | dev->device == PCI_DEVICE_ID_INTERG_2010)); | 316 | dev->device == PCI_DEVICE_ID_INTERG_2010)) || |
317 | (dev->vendor == PCI_VENDOR_ID_ITE && | ||
318 | dev->device == PCI_DEVICE_ID_ITE_8152)); | ||
319 | |||
298 | } | 320 | } |
299 | 321 | ||
300 | /* | 322 | /* |