From 1306abec905df1ff5cf2b1d91ac0d94d18d96c5b Mon Sep 17 00:00:00 2001 From: Cliff Brake Date: Fri, 20 Jul 2007 19:00:07 -0400 Subject: [PATCH] cm-x270-it8152 --- arch/arm/common/Makefile | 1 + arch/arm/common/it8152.c | 272 +++++++++++++++++++++++++++++++++++++ arch/arm/kernel/bios32.c | 28 ++++- include/asm-arm/hardware/it8152.h | 104 ++++++++++++++ include/asm-arm/pci.h | 7 + include/linux/pci_ids.h | 1 + 6 files changed, 410 insertions(+), 3 deletions(-) create mode 100644 arch/arm/common/it8152.c create mode 100644 include/asm-arm/hardware/it8152.h diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile index e1289a2..3d0b9fa 100644 --- a/arch/arm/common/Makefile +++ b/arch/arm/common/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_SHARPSL_PM) += sharpsl_pm.o obj-$(CONFIG_SHARP_SCOOP) += scoop.o obj-$(CONFIG_ARCH_IXP2000) += uengine.o obj-$(CONFIG_ARCH_IXP23XX) += uengine.o +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 0000000..8563610 --- /dev/null +++ b/arch/arm/common/it8152.c @@ -0,0 +1,272 @@ +/* + * arch/arm/common/it8152.c: PCI functions for IT8152 + * + * Compulab Ltd, 2002-2006 + * + * The DMA bouncing is taken from arch/arm/mach-ixp4xx/common-pci.c + * (see this file for respective copyrights) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include + +#define MAX_SLOTS 21 + +static unsigned long +it8152_pci_dev_base_address(struct pci_bus *bus, unsigned int devfn) +{ + unsigned long addr = 0; + + if (bus->number == 0) { + if (devfn < PCI_DEVFN(MAX_SLOTS, 0)) + addr = (devfn << 8); + } else + addr = (bus->number << 16) | (devfn << 8); + + return addr; +} + +static int +it8152_pci_read_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *value) +{ + unsigned long addr = it8152_pci_dev_base_address(bus, devfn); + u32 v; + int shift; + +#ifdef CONFIG_MACH_ARMCORE + if(devfn!=0) IT8152_GPIO_GPLR=0x00; +#endif + shift = (where & 3); + + IT8152_PCI_CFG_ADDR = (addr + where); + v = (IT8152_PCI_CFG_DATA >> (8 * (shift))); + + *value = v; + +#ifdef CONFIG_MACH_ARMCORE + if(devfn!=0) IT8152_GPIO_GPLR=0x20; +#endif + + return PCIBIOS_SUCCESSFUL; +} + + +static int +it8152_pci_write_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 value) +{ + unsigned long addr = it8152_pci_dev_base_address(bus, devfn); + u32 v, vtemp, mask=0; + int shift; + +#ifdef CONFIG_MACH_ARMCORE + if(devfn!=0) IT8152_GPIO_GPLR=0x00; +#endif + + if(size==1) mask=0xff; + if(size==2) mask=0xffff; + + shift = (where & 3); + + IT8152_PCI_CFG_ADDR = addr + where; + vtemp = IT8152_PCI_CFG_DATA; + + if(mask) vtemp &= ~(mask << (8 * shift)); + else vtemp = 0; + + v = (value << (8 * shift)); + IT8152_PCI_CFG_ADDR = addr + where; + IT8152_PCI_CFG_DATA = (v | vtemp); + +#ifdef CONFIG_MACH_ARMCORE + if(devfn!=0) IT8152_GPIO_GPLR=0x20; +#endif + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops it8152_ops = { + .read = it8152_pci_read_config, + .write = it8152_pci_write_config, +}; + +static struct resource it8152_io = { + .name = "IT8152 PCI I/O region", + .flags = IORESOURCE_IO, +}; + +static struct resource it8152_mem1 = { + .name = "First IT8152 PCI memory region", + .start = 0x10000000, + .end = 0x13e00000, + .flags = IORESOURCE_MEM, +}; + +/* + * The following functions are needed for DMA bouncing. + * ITE8152 chip can addrees up to 64MByte, so all the devices + * connected to ITE8152 (PCI and USB) should have limited DMA window + */ + +/* + * Setup DMA mask to 64MB on devices connected to ITE8152. Ignore all + * other devices. + */ +static int it8152_pci_platform_notify(struct device *dev) +{ + if ( dev->bus == &pci_bus_type ) { + if ( dev->dma_mask ) + *dev->dma_mask = (SZ_64M - 1) | PHYS_OFFSET; + dev->coherent_dma_mask = (SZ_64M - 1) | PHYS_OFFSET; + dmabounce_register_dev(dev, 2048, 4096); + } + return 0; +} + +static int it8152_pci_platform_notify_remove(struct device *dev) +{ + if ( dev->bus == &pci_bus_type ) { + dmabounce_unregister_dev(dev); + } + return 0; +} + +int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size) +{ + dev_dbg(dev, "%s: dma_addr %08x, size %08x\n", + __FUNCTION__, dma_addr, size); + return (dev->bus == &pci_bus_type ) && + ((dma_addr + size - PHYS_OFFSET) >= SZ_64M); +} + +/* + * Only first 64MB of memory can be accessed via PCI. + * We use GFP_DMA to allocate safe buffers to do map/unmap. + * This is really ugly and we need a better way of specifying + * DMA-capable regions of memory. + */ +void __init it8152_adjust_zones(int node, unsigned long *zone_size, + unsigned long *zhole_size) +{ + unsigned int sz = SZ_64M >> PAGE_SHIFT; + + /* + * Only adjust if > 64M on current system + */ + if (node || (zone_size[0] <= sz)) + return; + + zone_size[1] = zone_size[0] - sz; + zone_size[0] = sz; + zhole_size[1] = zhole_size[0]; + zhole_size[0] = 0; +} + +/* + * We override these so we properly do dmabounce otherwise drivers + * are able to set the dma_mask to 0xffffffff and we can no longer + * trap bounces. :( + * + * We just return true on everyhing except for < 64MB in which case + * we will fail miseralby and die since we can't handle that case. + */ +int +pci_set_dma_mask(struct pci_dev *dev, u64 mask) +{ + printk(KERN_INFO "===> %s: %s %x\n", __FUNCTION__, dev->dev.bus_id, mask); + if (mask >= PHYS_OFFSET + SZ_64M - 1 ) + return 0; + + return -EIO; +} + +int +pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) +{ + printk(KERN_INFO "===> %s: %s %x\n", __FUNCTION__, dev->dev.bus_id, mask); + if (mask >= PHYS_OFFSET + SZ_64M - 1 ) + return 0; + + return -EIO; +} + +EXPORT_SYMBOL(pci_set_dma_mask); +EXPORT_SYMBOL(pci_set_consistent_dma_mask); + + +int __init it8152_pci_setup(int nr, struct pci_sys_data *sys) +{ + it8152_io.start = IT8152_IO_BASE + 0x12000; + it8152_io.end = IT8152_IO_BASE + 0x100000; + + if (request_resource(&ioport_resource, &it8152_io)) { + printk(KERN_ERR "PCI: unable to allocate IO region\n"); + return -EBUSY; + } + if (request_resource(&iomem_resource, &it8152_mem1)) { + printk(KERN_ERR "PCI: unable to allocate memory region\n"); + return -EBUSY; + } + + sys->resource[0] = &it8152_io; + sys->resource[1] = &it8152_mem1; + + if (platform_notify || platform_notify_remove) { + printk(KERN_ERR "PCI: Can't use platform_notify\n"); + return -EBUSY; + } + + platform_notify = it8152_pci_platform_notify; + platform_notify_remove = it8152_pci_platform_notify_remove; + + return 1; +} + +/* + * If we set up a device for bus mastering, we need to check the latency + * timer as we don't have even crappy BIOSes to set it properly. + * The implementation is from arch/i386/pci/i386.c + */ +unsigned int pcibios_max_latency = 255; + +void pcibios_set_master(struct pci_dev *dev) +{ + u8 lat; + + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); + if (lat < 16) + lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency; + else if (lat > pcibios_max_latency) + lat = pcibios_max_latency; + else + return; + printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); +} + + +struct pci_bus * __init it8152_pci_scan_bus(int nr, struct pci_sys_data *sys) +{ + return pci_scan_bus(nr, &it8152_ops, sys); +} + diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index 240c448..d8d2352 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) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, pci_fixup_cy82c693); +static void __init pci_fixup_it8152(struct pci_dev *dev) +{ + int i; + /* fixup for ITE 8152 devices */ + /* FIXME: add defines for class 0x68000 and 0x80103 */ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_HOST || + dev->class == 0x68000 || + dev->class == 0x80103) { + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + dev->resource[i].start = 0; + dev->resource[i].end = 0; + dev->resource[i].flags = 0; + } + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8152, pci_fixup_it8152); + + + void __devinit pcibios_update_irq(struct pci_dev *dev, int irq) { if (debug_pci) @@ -292,9 +311,12 @@ void __devinit pcibios_update_irq(struct pci_dev *dev, int irq) */ static inline int pdev_bad_for_parity(struct pci_dev *dev) { - return (dev->vendor == PCI_VENDOR_ID_INTERG && - (dev->device == PCI_DEVICE_ID_INTERG_2000 || - dev->device == PCI_DEVICE_ID_INTERG_2010)); + return ((dev->vendor == PCI_VENDOR_ID_INTERG && + (dev->device == PCI_DEVICE_ID_INTERG_2000 || + dev->device == PCI_DEVICE_ID_INTERG_2010)) || + (dev->vendor == PCI_VENDOR_ID_ITE && + dev->device == PCI_DEVICE_ID_ITE_8152)); + } /* diff --git a/include/asm-arm/hardware/it8152.h b/include/asm-arm/hardware/it8152.h new file mode 100644 index 0000000..d28210d --- /dev/null +++ b/include/asm-arm/hardware/it8152.h @@ -0,0 +1,104 @@ +/* + * arch/arm/mach-pxa/it8152.h + * + * Compulab Ltd., 2006 + * + * ITE 8152 companion chip definitions + */ + + +/* #define CMX270_IT8152_VIRT (CMX270_VIRT_BASE) */ + + +extern unsigned long it8152_base_address; + +#define IT8152_IO_BASE (it8152_base_address + 0x03e00000) +#define IT8152_CFGREG_BASE (it8152_base_address + 0x03f00000) + +/* #define IRQ_GPIO_IT8152_IRQ IRQ_GPIO(GPIO_IT8152_IRQ) */ + +#define IT8152_SHORT_IO(x) (*((volatile unsigned short *)(IT8152_CFGREG_BASE+(x)))) +#define IT8152_LONG_IO(x) (*((volatile unsigned long *)(IT8152_CFGREG_BASE+(x)))) + + +#define IT8152_PCI_MEMBASE (*((volatile unsigned long *)(it8152_base_address))) +/* #define IT8152_PCI_IOBASE (*((volatile unsigned long *)(it8152_base_address + 0x3e00000))) */ + +#define IT8152_PCI_IACK (*((volatile unsigned long *)(it8152_base_address + 0x3f00808))) +#define IT8152_PCI_CFG_ADDR (*((volatile unsigned long *)(it8152_base_address + 0x3f00800))) +#define IT8152_PCI_CFG_DATA (*((volatile unsigned long *)(it8152_base_address + 0x3f00804))) + +#define IT_BUSNUM_SHF 16 +#define IT_DEVNUM_SHF 11 +#define IT_FUNCNUM_SHF 8 +#define IT_REGNUM_SHF 2 + +/* Power management & PLL registers */ +#define IT8152_PMPLL_DSR IT8152_LONG_IO(0x00) +#define IT8152_PMPLL_DSSR IT8152_LONG_IO(0x04) +#define IT8152_PMPLL_PLLCR IT8152_LONG_IO(0x20) +#define IT8152_PMPLL_MFSR IT8152_LONG_IO(0x24) + +/* Memory controller */ +#define IT8152_MC_REG_OFFSET 0x100 + +#define IT8152_MC_SDCR IT8152_LONG_IO(IT8152_MC_REG_OFFSET + 0x00) +#define IT8152_MC_PCICR IT8152_LONG_IO(IT8152_MC_REG_OFFSET + 0x04) + +/* Interrupt related definitions */ +#define IT8152_INTC_REG_OFFSET 0x300 + +#define IT8152_INTC_LDCNIRR IT8152_LONG_IO(IT8152_INTC_REG_OFFSET + 0x00) +#define IT8152_INTC_LDPNIRR IT8152_LONG_IO(IT8152_INTC_REG_OFFSET + 0x04) +#define IT8152_INTC_LDCNIMR IT8152_LONG_IO(IT8152_INTC_REG_OFFSET + 0x08) +#define IT8152_INTC_LDPNIMR IT8152_LONG_IO(IT8152_INTC_REG_OFFSET + 0x0C) +#define IT8152_INTC_LDNITR IT8152_LONG_IO(IT8152_INTC_REG_OFFSET + 0x10) +#define IT8152_INTC_LDNIAR IT8152_LONG_IO(IT8152_INTC_REG_OFFSET + 0x14) +#define IT8152_INTC_LPCNIRR IT8152_LONG_IO(IT8152_INTC_REG_OFFSET + 0x20) +#define IT8152_INTC_LPPNIRR IT8152_LONG_IO(IT8152_INTC_REG_OFFSET + 0x24) +#define IT8152_INTC_LPCNIMR IT8152_LONG_IO(IT8152_INTC_REG_OFFSET + 0x28) +#define IT8152_INTC_LPPNIMR IT8152_LONG_IO(IT8152_INTC_REG_OFFSET + 0x2C) +#define IT8152_INTC_LPNITR IT8152_LONG_IO(IT8152_INTC_REG_OFFSET + 0x30) +#define IT8152_INTC_LPNIAR IT8152_LONG_IO(IT8152_INTC_REG_OFFSET + 0x34) +#define IT8152_INTC_PDCNIRR IT8152_LONG_IO(IT8152_INTC_REG_OFFSET + 0x40) +#define IT8152_INTC_PDPNIRR IT8152_LONG_IO(IT8152_INTC_REG_OFFSET + 0x44) +#define IT8152_INTC_PDCNIMR IT8152_LONG_IO(IT8152_INTC_REG_OFFSET + 0x48) +#define IT8152_INTC_PDPNIMR IT8152_LONG_IO(IT8152_INTC_REG_OFFSET + 0x4C) +#define IT8152_INTC_PDNITR IT8152_LONG_IO(IT8152_INTC_REG_OFFSET + 0x50) +#define IT8152_INTC_PDNIAR IT8152_LONG_IO(IT8152_INTC_REG_OFFSET + 0x54) +#define IT8152_INTC_INTC_TYPER IT8152_LONG_IO(IT8152_INTC_REG_OFFSET + 0xFC) + +#define IT8152_UART_BASE IT8152_LONG_IO(0x200) + +#define IT8152_GPIO_REG_OFFSET 0x500 + +#define IT8152_GPIO_GPLR IT8152_LONG_IO(IT8152_GPIO_REG_OFFSET) +#define IT8152_GPIO_GPCR12 IT8152_LONG_IO(IT8152_GPIO_REG_OFFSET + 0x04) +#define IT8152_GPIO_GPCR34 IT8152_LONG_IO(IT8152_GPIO_REG_OFFSET + 0x08) + + +/* Interrupt bit definitions */ +#define PCISERR_BIT (1<<14) +#define H2PTADR_BIT (1<<13) +#define H2PMAR_BIT (1<<12) +#define PCI_INTD_BIT (1<<11) +#define PCI_INTC_BIT (1<<10) +#define PCI_INTB_BIT (1<<9) +#define PCI_INTA_BIT (1<<8) +#define CDMA_INT_BIT (1<<2) +#define USB_INT_BIT (1<<1) +#define AUDIO_INT_BIT (1<<0) + +/* IT8152 UART */ +#define ITESER_BIT (1<<5) + + + + + + + + + + + diff --git a/include/asm-arm/pci.h b/include/asm-arm/pci.h index f21abd4..2cf30bf 100644 --- a/include/asm-arm/pci.h +++ b/include/asm-arm/pci.h @@ -8,10 +8,17 @@ #define pcibios_scan_all_fns(a, b) 0 +#ifdef CONFIG_PCI_HOST_ITE8152 +/* ITE bridge requires setting latency timer to avoid early bus access + termination by PIC bus mater devices +*/ +extern void pcibios_set_master(struct pci_dev *dev); +#else static inline void pcibios_set_master(struct pci_dev *dev) { /* No special bus mastering setup handling */ } +#endif static inline void pcibios_penalize_isa_irq(int irq, int active) { diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 5b1c999..b4c81d5 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1650,6 +1650,7 @@ #define PCI_DEVICE_ID_ITE_8211 0x8211 #define PCI_DEVICE_ID_ITE_8212 0x8212 #define PCI_DEVICE_ID_ITE_8213 0x8213 +#define PCI_DEVICE_ID_ITE_8152 0x8152 #define PCI_DEVICE_ID_ITE_8872 0x8872 #define PCI_DEVICE_ID_ITE_IT8330G_0 0xe886 -- 1.5.1.6