diff options
Diffstat (limited to 'arch/arm/common/it8152.c')
| -rw-r--r-- | arch/arm/common/it8152.c | 387 |
1 files changed, 387 insertions, 0 deletions
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 | |||
