diff options
Diffstat (limited to 'arch/arm/mach-iop33x')
-rw-r--r-- | arch/arm/mach-iop33x/Kconfig | 27 | ||||
-rw-r--r-- | arch/arm/mach-iop33x/Makefile | 11 | ||||
-rw-r--r-- | arch/arm/mach-iop33x/Makefile.boot | 3 | ||||
-rw-r--r-- | arch/arm/mach-iop33x/common.c | 22 | ||||
-rw-r--r-- | arch/arm/mach-iop33x/iq80331-mm.c | 35 | ||||
-rw-r--r-- | arch/arm/mach-iop33x/iq80331-pci.c | 119 | ||||
-rw-r--r-- | arch/arm/mach-iop33x/iq80332-mm.c | 35 | ||||
-rw-r--r-- | arch/arm/mach-iop33x/iq80332-pci.c | 125 | ||||
-rw-r--r-- | arch/arm/mach-iop33x/irq.c | 129 | ||||
-rw-r--r-- | arch/arm/mach-iop33x/pci.c | 222 | ||||
-rw-r--r-- | arch/arm/mach-iop33x/setup.c | 221 | ||||
-rw-r--r-- | arch/arm/mach-iop33x/time.c | 106 |
12 files changed, 1055 insertions, 0 deletions
diff --git a/arch/arm/mach-iop33x/Kconfig b/arch/arm/mach-iop33x/Kconfig new file mode 100644 index 00000000000..410df546e95 --- /dev/null +++ b/arch/arm/mach-iop33x/Kconfig @@ -0,0 +1,27 @@ +if ARCH_IOP33X + +menu "IOP33x Implementation Options" + +comment "IOP33x Platform Types" + +config ARCH_IQ80331 + bool "Enable support for IQ80331" + help + Say Y here if you want to run your kernel on the Intel IQ80331 + evaluation kit for the IOP331 chipset. + +config MACH_IQ80332 + bool "Enable support for IQ80332" + help + Say Y here if you want to run your kernel on the Intel IQ80332 + evaluation kit for the IOP332 chipset. + +config IOP331_STEPD + bool "Chip stepping D of the IOP80331 processor or IOP80333" + help + Say Y here if you have StepD of the IOP80331 or IOP8033 + based platforms. + +endmenu + +endif diff --git a/arch/arm/mach-iop33x/Makefile b/arch/arm/mach-iop33x/Makefile new file mode 100644 index 00000000000..0f1a8fffe18 --- /dev/null +++ b/arch/arm/mach-iop33x/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for the linux kernel. +# + +obj-y := common.o setup.o irq.o pci.o time.o +obj-m := +obj-n := +obj- := + +obj-$(CONFIG_ARCH_IQ80331) += iq80331-mm.o iq80331-pci.o +obj-$(CONFIG_MACH_IQ80332) += iq80332-mm.o iq80332-pci.o diff --git a/arch/arm/mach-iop33x/Makefile.boot b/arch/arm/mach-iop33x/Makefile.boot new file mode 100644 index 00000000000..67039c3e0c4 --- /dev/null +++ b/arch/arm/mach-iop33x/Makefile.boot @@ -0,0 +1,3 @@ + zreladdr-y := 0x00008000 +params_phys-y := 0x00000100 +initrd_phys-y := 0x00800000 diff --git a/arch/arm/mach-iop33x/common.c b/arch/arm/mach-iop33x/common.c new file mode 100644 index 00000000000..dd75f2b8e74 --- /dev/null +++ b/arch/arm/mach-iop33x/common.c @@ -0,0 +1,22 @@ +/* + * arch/arm/mach-iop33x/common.c + * + * Common routines shared across all IOP3xx implementations + * + * Author: Deepak Saxena <dsaxena@mvista.com> + * + * Copyright 2003 (c) MontaVista, Software, Inc. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/delay.h> +#include <asm/hardware.h> + +/* + * Shared variables + */ +unsigned long iop3xx_pcibios_min_io = 0; +unsigned long iop3xx_pcibios_min_mem = 0; diff --git a/arch/arm/mach-iop33x/iq80331-mm.c b/arch/arm/mach-iop33x/iq80331-mm.c new file mode 100644 index 00000000000..eb59445a0fc --- /dev/null +++ b/arch/arm/mach-iop33x/iq80331-mm.c @@ -0,0 +1,35 @@ +/* + * linux/arch/arm/mach-iop33x/iq80331-mm.c + * + * Low level memory initialization for iq80331 platform + * + * Author: Dave Jiang <dave.jiang@intel.com> + * Copyright (C) 2003 Intel Corp. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/mm.h> +#include <linux/init.h> + +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/page.h> + +#include <asm/mach/map.h> + + +/* + * IQ80331 specific IO mappings + * + * We use RedBoot's setup for the onboard devices. + */ + +void __init iq80331_map_io(void) +{ + iop331_map_io(); +} diff --git a/arch/arm/mach-iop33x/iq80331-pci.c b/arch/arm/mach-iop33x/iq80331-pci.c new file mode 100644 index 00000000000..71adb12a942 --- /dev/null +++ b/arch/arm/mach-iop33x/iq80331-pci.c @@ -0,0 +1,119 @@ +/* + * arch/arm/mach-iop33x/iq80331-pci.c + * + * PCI support for the Intel IQ80331 reference board + * + * Author: Dave Jiang <dave.jiang@intel.com> + * Copyright (C) 2003, 2004 Intel Corp. + * + * 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 <linux/kernel.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/string.h> +#include <linux/slab.h> + +#include <asm/hardware.h> +#include <asm/irq.h> +#include <asm/mach/pci.h> +#include <asm/mach-types.h> + +/* + * The following macro is used to lookup irqs in a standard table + * format for those systems that do not already have PCI + * interrupts properly routed. We assume 1 <= pin <= 4 + */ +#define PCI_IRQ_TABLE_LOOKUP(minid,maxid) \ +({ int _ctl_ = -1; \ + unsigned int _idsel = idsel - minid; \ + if (_idsel <= maxid) \ + _ctl_ = pci_irq_table[_idsel][pin-1]; \ + _ctl_; }) + +#define INTA IRQ_IQ80331_INTA +#define INTB IRQ_IQ80331_INTB +#define INTC IRQ_IQ80331_INTC +#define INTD IRQ_IQ80331_INTD + +//#define INTE IRQ_IQ80331_I82544 + +static inline int __init +iq80331_map_irq(struct pci_dev *dev, u8 idsel, u8 pin) +{ + static int pci_irq_table[][4] = { + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + {INTB, INTC, INTD, INTA}, /* PCI-X Slot */ + {INTC, INTC, INTC, INTC}, /* GigE */ + }; + + BUG_ON(pin < 1 || pin > 4); + + return PCI_IRQ_TABLE_LOOKUP(1, 7); +} + +static int iq80331_setup(int nr, struct pci_sys_data *sys) +{ + struct resource *res; + + if(nr != 0) + return 0; + + res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL); + if (!res) + panic("PCI: unable to alloc resources"); + + res[0].start = IOP331_PCI_LOWER_IO_VA; + res[0].end = IOP331_PCI_UPPER_IO_VA; + res[0].name = "IQ80331 PCI I/O Space"; + res[0].flags = IORESOURCE_IO; + + res[1].start = IOP331_PCI_LOWER_MEM_PA; + res[1].end = IOP331_PCI_UPPER_MEM_PA; + res[1].name = "IQ80331 PCI Memory Space"; + res[1].flags = IORESOURCE_MEM; + + request_resource(&ioport_resource, &res[0]); + request_resource(&iomem_resource, &res[1]); + + sys->mem_offset = IOP331_PCI_MEM_OFFSET; + sys->io_offset = IOP331_PCI_IO_OFFSET; + + sys->resource[0] = &res[0]; + sys->resource[1] = &res[1]; + sys->resource[2] = NULL; + + return 1; +} + +static void iq80331_preinit(void) +{ + iop331_init(); +} + +static struct hw_pci iq80331_pci __initdata = { + .swizzle = pci_std_swizzle, + .nr_controllers = 1, + .setup = iq80331_setup, + .scan = iop331_scan_bus, + .preinit = iq80331_preinit, + .map_irq = iq80331_map_irq +}; + +static int __init iq80331_pci_init(void) +{ + if (machine_is_iq80331()) + pci_common_init(&iq80331_pci); + return 0; +} + +subsys_initcall(iq80331_pci_init); + + + + diff --git a/arch/arm/mach-iop33x/iq80332-mm.c b/arch/arm/mach-iop33x/iq80332-mm.c new file mode 100644 index 00000000000..f7bc73113ea --- /dev/null +++ b/arch/arm/mach-iop33x/iq80332-mm.c @@ -0,0 +1,35 @@ +/* + * linux/arch/arm/mach-iop33x/iq80332-mm.c + * + * Low level memory initialization for iq80332 platform + * + * Author: Dave Jiang <dave.jiang@intel.com> + * Copyright (C) 2004 Intel Corp. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/mm.h> +#include <linux/init.h> + +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/page.h> + +#include <asm/mach/map.h> + + +/* + * IQ80332 specific IO mappings + * + * We use RedBoot's setup for the onboard devices. + */ + +void __init iq80332_map_io(void) +{ + iop331_map_io(); +} diff --git a/arch/arm/mach-iop33x/iq80332-pci.c b/arch/arm/mach-iop33x/iq80332-pci.c new file mode 100644 index 00000000000..f3010f85b1a --- /dev/null +++ b/arch/arm/mach-iop33x/iq80332-pci.c @@ -0,0 +1,125 @@ +/* + * arch/arm/mach-iop33x/iq80332-pci.c + * + * PCI support for the Intel IQ80332 reference board + * + * Author: Dave Jiang <dave.jiang@intel.com> + * Copyright (C) 2004 Intel Corp. + * + * 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 <linux/kernel.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/string.h> +#include <linux/slab.h> + +#include <asm/hardware.h> +#include <asm/irq.h> +#include <asm/mach/pci.h> +#include <asm/mach-types.h> + +/* + * The following macro is used to lookup irqs in a standard table + * format for those systems that do not already have PCI + * interrupts properly routed. We assume 1 <= pin <= 4 + */ +#define PCI_IRQ_TABLE_LOOKUP(minid,maxid) \ +({ int _ctl_ = -1; \ + unsigned int _idsel = idsel - minid; \ + if (_idsel <= maxid) \ + _ctl_ = pci_irq_table[_idsel][pin-1]; \ + _ctl_; }) + +#define INTA IRQ_IQ80332_INTA +#define INTB IRQ_IQ80332_INTB +#define INTC IRQ_IQ80332_INTC +#define INTD IRQ_IQ80332_INTD + +//#define INTE IRQ_IQ80332_I82544 + +static inline int __init +iq80332_map_irq(struct pci_dev *dev, u8 idsel, u8 pin) +{ + static int pci_irq_table[][8] = { + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + {-1, -1, -1, -1}, + {-1, -1, -1, -1}, + {-1, -1, -1, -1}, + {INTA, INTB, INTC, INTD}, /* PCI-X Slot */ + {-1, -1, -1, -1}, + {INTC, INTC, INTC, INTC}, /* GigE */ + {-1, -1, -1, -1}, + {-1, -1, -1, -1}, + }; + + BUG_ON(pin < 1 || pin > 4); + + return PCI_IRQ_TABLE_LOOKUP(1, 7); +} + +static int iq80332_setup(int nr, struct pci_sys_data *sys) +{ + struct resource *res; + + if(nr != 0) + return 0; + + res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL); + if (!res) + panic("PCI: unable to alloc resources"); + + res[0].start = IOP331_PCI_LOWER_IO_VA; + res[0].end = IOP331_PCI_UPPER_IO_VA; + res[0].name = "IQ80332 PCI I/O Space"; + res[0].flags = IORESOURCE_IO; + + res[1].start = IOP331_PCI_LOWER_MEM_PA; + res[1].end = IOP331_PCI_UPPER_MEM_PA; + res[1].name = "IQ80332 PCI Memory Space"; + res[1].flags = IORESOURCE_MEM; + + request_resource(&ioport_resource, &res[0]); + request_resource(&iomem_resource, &res[1]); + + sys->mem_offset = IOP331_PCI_MEM_OFFSET; + sys->io_offset = IOP331_PCI_IO_OFFSET; + + sys->resource[0] = &res[0]; + sys->resource[1] = &res[1]; + sys->resource[2] = NULL; + + return 1; +} + +static void iq80332_preinit(void) +{ + iop331_init(); +} + +static struct hw_pci iq80332_pci __initdata = { + .swizzle = pci_std_swizzle, + .nr_controllers = 1, + .setup = iq80332_setup, + .scan = iop331_scan_bus, + .preinit = iq80332_preinit, + .map_irq = iq80332_map_irq +}; + +static int __init iq80332_pci_init(void) +{ + if (machine_is_iq80332()) + pci_common_init(&iq80332_pci); + return 0; +} + +subsys_initcall(iq80332_pci_init); + + + + diff --git a/arch/arm/mach-iop33x/irq.c b/arch/arm/mach-iop33x/irq.c new file mode 100644 index 00000000000..029fa78876a --- /dev/null +++ b/arch/arm/mach-iop33x/irq.c @@ -0,0 +1,129 @@ +/* + * linux/arch/arm/mach-iop33x/irq.c + * + * Generic IOP331 IRQ handling functionality + * + * Author: Dave Jiang <dave.jiang@intel.com> + * Copyright (C) 2003 Intel Corp. + * + * 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 <linux/init.h> +#include <linux/interrupt.h> +#include <linux/list.h> + +#include <asm/mach/irq.h> +#include <asm/irq.h> +#include <asm/hardware.h> + +#include <asm/mach-types.h> + +static u32 iop331_mask0 = 0; +static u32 iop331_mask1 = 0; + +static inline void intctl_write0(u32 val) +{ + // INTCTL0 + asm volatile("mcr p6,0,%0,c0,c0,0"::"r" (val)); +} + +static inline void intctl_write1(u32 val) +{ + // INTCTL1 + asm volatile("mcr p6,0,%0,c1,c0,0"::"r" (val)); +} + +static inline void intstr_write0(u32 val) +{ + // INTSTR0 + asm volatile("mcr p6,0,%0,c2,c0,0"::"r" (val)); +} + +static inline void intstr_write1(u32 val) +{ + // INTSTR1 + asm volatile("mcr p6,0,%0,c3,c0,0"::"r" (val)); +} + +static void +iop331_irq_mask1 (unsigned int irq) +{ + iop331_mask0 &= ~(1 << (irq - IOP331_IRQ_OFS)); + intctl_write0(iop331_mask0); +} + +static void +iop331_irq_mask2 (unsigned int irq) +{ + iop331_mask1 &= ~(1 << (irq - IOP331_IRQ_OFS - 32)); + intctl_write1(iop331_mask1); +} + +static void +iop331_irq_unmask1(unsigned int irq) +{ + iop331_mask0 |= (1 << (irq - IOP331_IRQ_OFS)); + intctl_write0(iop331_mask0); +} + +static void +iop331_irq_unmask2(unsigned int irq) +{ + iop331_mask1 |= (1 << (irq - IOP331_IRQ_OFS - 32)); + intctl_write1(iop331_mask1); +} + +struct irq_chip iop331_irqchip1 = { + .name = "IOP-1", + .ack = iop331_irq_mask1, + .mask = iop331_irq_mask1, + .unmask = iop331_irq_unmask1, +}; + +struct irq_chip iop331_irqchip2 = { + .name = "IOP-2", + .ack = iop331_irq_mask2, + .mask = iop331_irq_mask2, + .unmask = iop331_irq_unmask2, +}; + +void __init iop331_init_irq(void) +{ + unsigned int i, tmp; + + /* Enable access to coprocessor 6 for dealing with IRQs. + * From RMK: + * Basically, the Intel documentation here is poor. It appears that + * you need to set the bit to be able to access the coprocessor from + * SVC mode. Whether that allows access from user space or not is + * unclear. + */ + asm volatile ( + "mrc p15, 0, %0, c15, c1, 0\n\t" + "orr %0, %0, %1\n\t" + "mcr p15, 0, %0, c15, c1, 0\n\t" + /* The action is delayed, so we have to do this: */ + "mrc p15, 0, %0, c15, c1, 0\n\t" + "mov %0, %0\n\t" + "sub pc, pc, #4" + : "=r" (tmp) : "i" (1 << 6) ); + + intctl_write0(0); // disable all interrupts + intctl_write1(0); + intstr_write0(0); // treat all as IRQ + intstr_write1(0); + if(machine_is_iq80331()) // all interrupts are inputs to chip + *IOP331_PCIIRSR = 0x0f; + + for(i = IOP331_IRQ_OFS; i < NR_IRQS; i++) + { + set_irq_chip(i, (i < 32) ? &iop331_irqchip1 : &iop331_irqchip2); + set_irq_handler(i, do_level_IRQ); + set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + } +} + diff --git a/arch/arm/mach-iop33x/pci.c b/arch/arm/mach-iop33x/pci.c new file mode 100644 index 00000000000..bf6aba91b47 --- /dev/null +++ b/arch/arm/mach-iop33x/pci.c @@ -0,0 +1,222 @@ +/* + * arch/arm/mach-iop33x/pci.c + * + * PCI support for the Intel IOP331 chipset + * + * Author: Dave Jiang (dave.jiang@intel.com) + * Copyright (C) 2003, 2004 Intel Corp. + * + * 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 <linux/kernel.h> +#include <linux/pci.h> +#include <linux/slab.h> +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/ioport.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/hardware.h> +#include <asm/mach/pci.h> + +#include <asm/arch/iop331.h> + +#undef DEBUG +#undef DEBUG1 + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) do { } while (0) +#endif + +#ifdef DEBUG1 +#define DBG1(x...) printk(x) +#else +#define DBG1(x...) do { } while (0) +#endif + +/* + * This routine builds either a type0 or type1 configuration command. If the + * bus is on the 80331 then a type0 made, else a type1 is created. + */ +static u32 iop331_cfg_address(struct pci_bus *bus, int devfn, int where) +{ + struct pci_sys_data *sys = bus->sysdata; + u32 addr; + + if (sys->busnr == bus->number) + addr = 1 << (PCI_SLOT(devfn) + 16) | (PCI_SLOT(devfn) << 11); + else + addr = bus->number << 16 | PCI_SLOT(devfn) << 11 | 1; + + addr |= PCI_FUNC(devfn) << 8 | (where & ~3); + + return addr; +} + +/* + * This routine checks the status of the last configuration cycle. If an error + * was detected it returns a 1, else it returns a 0. The errors being checked + * are parity, master abort, target abort (master and target). These types of + * errors occure during a config cycle where there is no device, like during + * the discovery stage. + */ +static int iop331_pci_status(void) +{ + unsigned int status; + int ret = 0; + + /* + * Check the status registers. + */ + status = *IOP331_ATUSR; + if (status & 0xf900) + { + DBG("\t\t\tPCI: P0 - status = 0x%08x\n", status); + *IOP331_ATUSR = status & 0xf900; + ret = 1; + } + status = *IOP331_ATUISR; + if (status & 0x679f) + { + DBG("\t\t\tPCI: P1 - status = 0x%08x\n", status); + *IOP331_ATUISR = status & 0x679f; + ret = 1; + } + return ret; +} + +/* + * Simply write the address register and read the configuration + * data. Note that the 4 nop's ensure that we are able to handle + * a delayed abort (in theory.) + */ +static inline u32 iop331_read(unsigned long addr) +{ + u32 val; + + __asm__ __volatile__( + "str %1, [%2]\n\t" + "ldr %0, [%3]\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + : "=r" (val) + : "r" (addr), "r" (IOP331_OCCAR), "r" (IOP331_OCCDR)); + + return val; +} + +/* + * The read routines must check the error status of the last configuration + * cycle. If there was an error, the routine returns all hex f's. + */ +static int +iop331_read_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 *value) +{ + unsigned long addr = iop331_cfg_address(bus, devfn, where); + u32 val = iop331_read(addr) >> ((where & 3) * 8); + + if( iop331_pci_status() ) + val = 0xffffffff; + + *value = val; + + return PCIBIOS_SUCCESSFUL; +} + +static int +iop331_write_config(struct pci_bus *bus, unsigned int devfn, int where, + int size, u32 value) +{ + unsigned long addr = iop331_cfg_address(bus, devfn, where); + u32 val; + + if (size != 4) { + val = iop331_read(addr); + if (!iop331_pci_status() == 0) + return PCIBIOS_SUCCESSFUL; + + where = (where & 3) * 8; + + if (size == 1) + val &= ~(0xff << where); + else + val &= ~(0xffff << where); + + *IOP331_OCCDR = val | value << where; + } else { + asm volatile( + "str %1, [%2]\n\t" + "str %0, [%3]\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + : + : "r" (value), "r" (addr), + "r" (IOP331_OCCAR), "r" (IOP331_OCCDR)); + } + + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops iop331_ops = { + .read = iop331_read_config, + .write = iop331_write_config, +}; + +/* + * When a PCI device does not exist during config cycles, the XScale gets a + * bus error instead of returning 0xffffffff. This handler simply returns. + */ +int +iop331_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) +{ + DBG("PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR = 0x%08lx\n", + addr, fsr, regs->ARM_pc, regs->ARM_lr); + + /* + * If it was an imprecise abort, then we need to correct the + * return address to be _after_ the instruction. + */ + if (fsr & (1 << 10)) + regs->ARM_pc += 4; + + return 0; +} + +/* + * Scan an IOP331 PCI bus. sys->bus defines which bus we scan. + */ +struct pci_bus *iop331_scan_bus(int nr, struct pci_sys_data *sys) +{ + return pci_scan_bus(sys->busnr, &iop331_ops, sys); +} + +void iop331_init(void) +{ + DBG1("PCI: Intel 80331 PCI init code.\n"); + DBG1("\tATU: IOP331_ATUCMD=0x%04x\n", *IOP331_ATUCMD); + DBG1("\tATU: IOP331_OMWTVR0=0x%04x, IOP331_OIOWTVR=0x%04x\n", + *IOP331_OMWTVR0, + *IOP331_OIOWTVR); + DBG1("\tATU: IOP331_OMWTVR1=0x%04x\n", *IOP331_OMWTVR1); + DBG1("\tATU: IOP331_ATUCR=0x%08x\n", *IOP331_ATUCR); + DBG1("\tATU: IOP331_IABAR0=0x%08x IOP331_IALR0=0x%08x IOP331_IATVR0=%08x\n", *IOP331_IABAR0, *IOP331_IALR0, *IOP331_IATVR0); + DBG1("\tATU: IOP31_IABAR1=0x%08x IOP331_IALR1=0x%08x\n", *IOP331_IABAR1, *IOP331_IALR1); + DBG1("\tATU: IOP331_ERBAR=0x%08x IOP331_ERLR=0x%08x IOP331_ERTVR=%08x\n", *IOP331_ERBAR, *IOP331_ERLR, *IOP331_ERTVR); + DBG1("\tATU: IOP331_IABAR2=0x%08x IOP331_IALR2=0x%08x IOP331_IATVR2=%08x\n", *IOP331_IABAR2, *IOP331_IALR2, *IOP331_IATVR2); + DBG1("\tATU: IOP331_IABAR3=0x%08x IOP331_IALR3=0x%08x IOP331_IATVR3=%08x\n", *IOP331_IABAR3, *IOP331_IALR3, *IOP331_IATVR3); + + hook_fault_code(16+6, iop331_pci_abort, SIGBUS, "imprecise external abort"); +} + diff --git a/arch/arm/mach-iop33x/setup.c b/arch/arm/mach-iop33x/setup.c new file mode 100644 index 00000000000..c14c7da5ec4 --- /dev/null +++ b/arch/arm/mach-iop33x/setup.c @@ -0,0 +1,221 @@ +/* + * linux/arch/arm/mach-iop33x/setup.c + * + * Author: Dave Jiang (dave.jiang@intel.com) + * Copyright (C) 2004 Intel Corporation. + * + * 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 <linux/mm.h> +#include <linux/init.h> +#include <linux/major.h> +#include <linux/fs.h> +#include <linux/platform_device.h> +#include <linux/serial.h> +#include <linux/tty.h> +#include <linux/serial_8250.h> + +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/mach/map.h> +#include <asm/setup.h> +#include <asm/system.h> +#include <asm/memory.h> +#include <asm/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> + +#define IOP331_UART_XTAL 33334000 + +/* + * Standard IO mapping for all IOP331 based systems + */ +static struct map_desc iop331_std_desc[] __initdata = { + { /* mem mapped registers */ + .virtual = IOP331_VIRT_MEM_BASE, + .pfn = __phys_to_pfn(IOP331_PHYS_MEM_BASE), + .length = 0x00002000, + .type = MT_DEVICE + }, { /* PCI IO space */ + .virtual = IOP331_PCI_LOWER_IO_VA, + .pfn = __phys_to_pfn(IOP331_PCI_LOWER_IO_PA), + .length = IOP331_PCI_IO_WINDOW_SIZE, + .type = MT_DEVICE + } +}; + +static struct resource iop33x_uart0_resources[] = { + [0] = { + .start = IOP331_UART0_PHYS, + .end = IOP331_UART0_PHYS + 0x3f, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_IOP331_UART0, + .end = IRQ_IOP331_UART0, + .flags = IORESOURCE_IRQ + } +}; + +static struct resource iop33x_uart1_resources[] = { + [0] = { + .start = IOP331_UART1_PHYS, + .end = IOP331_UART1_PHYS + 0x3f, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_IOP331_UART1, + .end = IRQ_IOP331_UART1, + .flags = IORESOURCE_IRQ + } +}; + +static struct plat_serial8250_port iop33x_uart0_data[] = { + { + .membase = (char*)(IOP331_UART0_VIRT), + .mapbase = (IOP331_UART0_PHYS), + .irq = IRQ_IOP331_UART0, + .uartclk = IOP331_UART_XTAL, + .regshift = 2, + .iotype = UPIO_MEM, + .flags = UPF_SKIP_TEST, + }, + { }, +}; + +static struct plat_serial8250_port iop33x_uart1_data[] = { + { + .membase = (char*)(IOP331_UART1_VIRT), + .mapbase = (IOP331_UART1_PHYS), + .irq = IRQ_IOP331_UART1, + .uartclk = IOP331_UART_XTAL, + .regshift = 2, + .iotype = UPIO_MEM, + .flags = UPF_SKIP_TEST, + }, + { }, +}; + +static struct platform_device iop33x_uart0 = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev.platform_data = iop33x_uart0_data, + .num_resources = 2, + .resource = iop33x_uart0_resources, +}; + +static struct platform_device iop33x_uart1 = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM1, + .dev.platform_data = iop33x_uart1_data, + .num_resources = 2, + .resource = iop33x_uart1_resources, +}; + +static struct resource iop33x_i2c_0_resources[] = { + [0] = { + .start = 0xfffff680, + .end = 0xfffff698, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_IOP331_I2C_0, + .end = IRQ_IOP331_I2C_0, + .flags = IORESOURCE_IRQ + } +}; + +static struct resource iop33x_i2c_1_resources[] = { + [0] = { + .start = 0xfffff6a0, + .end = 0xfffff6b8, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_IOP331_I2C_1, + .end = IRQ_IOP331_I2C_1, + .flags = IORESOURCE_IRQ + } +}; + +static struct platform_device iop33x_i2c_0_controller = { + .name = "IOP3xx-I2C", + .id = 0, + .num_resources = 2, + .resource = iop33x_i2c_0_resources +}; + +static struct platform_device iop33x_i2c_1_controller = { + .name = "IOP3xx-I2C", + .id = 1, + .num_resources = 2, + .resource = iop33x_i2c_1_resources +}; + +static struct platform_device *iop33x_devices[] __initdata = { + &iop33x_uart0, + &iop33x_uart1, + &iop33x_i2c_0_controller, + &iop33x_i2c_1_controller +}; + +void __init iop33x_init(void) +{ + if(iop_is_331()) + { + platform_add_devices(iop33x_devices, + ARRAY_SIZE(iop33x_devices)); + } +} + +void __init iop331_map_io(void) +{ + iotable_init(iop331_std_desc, ARRAY_SIZE(iop331_std_desc)); +} + +#ifdef CONFIG_ARCH_IOP33X +extern void iop331_init_irq(void); +extern struct sys_timer iop331_timer; +#endif + +#ifdef CONFIG_ARCH_IQ80331 +extern void iq80331_map_io(void); +#endif + +#ifdef CONFIG_MACH_IQ80332 +extern void iq80332_map_io(void); +#endif + +#if defined(CONFIG_ARCH_IQ80331) +MACHINE_START(IQ80331, "Intel IQ80331") + /* Maintainer: Intel Corp. */ + .phys_io = 0xfefff000, + .io_pg_offst = ((0xfffff000) >> 18) & 0xfffc, // virtual, physical + .map_io = iq80331_map_io, + .init_irq = iop331_init_irq, + .timer = &iop331_timer, + .boot_params = 0x0100, + .init_machine = iop33x_init, +MACHINE_END + +#elif defined(CONFIG_MACH_IQ80332) +MACHINE_START(IQ80332, "Intel IQ80332") + /* Maintainer: Intel Corp. */ + .phys_io = 0xfefff000, + .io_pg_offst = ((0xfffff000) >> 18) & 0xfffc, // virtual, physical + .map_io = iq80332_map_io, + .init_irq = iop331_init_irq, + .timer = &iop331_timer, + .boot_params = 0x0100, + .init_machine = iop33x_init, +MACHINE_END + +#else +#error No machine descriptor defined for this IOP3XX implementation +#endif + + diff --git a/arch/arm/mach-iop33x/time.c b/arch/arm/mach-iop33x/time.c new file mode 100644 index 00000000000..d839cd0d926 --- /dev/null +++ b/arch/arm/mach-iop33x/time.c @@ -0,0 +1,106 @@ +/* + * arch/arm/mach-iop33x/time.c + * + * Timer code for IOP331 based systems + * + * Author: Dave Jiang <dave.jiang@intel.com> + * + * Copyright 2003 Intel Corp. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/timex.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> +#include <asm/mach/irq.h> +#include <asm/mach/time.h> + +static inline unsigned long get_elapsed(void) +{ + return LATCH - *IOP331_TU_TCR0; +} + +static unsigned long iop331_gettimeoffset(void) +{ + unsigned long elapsed, usec; + u32 tisr1, tisr2; + + /* + * If an interrupt was pending before we read the timer, + * we've already wrapped. Factor this into the time. + * If an interrupt was pending after we read the timer, + * it may have wrapped between checking the interrupt + * status and reading the timer. Re-read the timer to + * be sure its value is after the wrap. + */ + + asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr1)); + elapsed = get_elapsed(); + asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr2)); + + if(tisr1 & 1) + elapsed += LATCH; + else if (tisr2 & 1) + elapsed = LATCH + get_elapsed(); + + /* + * Now convert them to usec. + */ + usec = (unsigned long)(elapsed / (CLOCK_TICK_RATE/1000000)); + + return usec; +} + +static irqreturn_t +iop331_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + u32 tisr; + + write_seqlock(&xtime_lock); + + asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr)); + tisr |= 1; + asm volatile("mcr p6, 0, %0, c6, c1, 0" : : "r" (tisr)); + + timer_tick(regs); + + write_sequnlock(&xtime_lock); + return IRQ_HANDLED; +} + +static struct irqaction iop331_timer_irq = { + .name = "IOP331 Timer Tick", + .handler = iop331_timer_interrupt, + .flags = IRQF_DISABLED | IRQF_TIMER, +}; + +static void __init iop331_timer_init(void) +{ + u32 timer_ctl; + + setup_irq(IRQ_IOP331_TIMER0, &iop331_timer_irq); + + timer_ctl = IOP331_TMR_EN | IOP331_TMR_PRIVILEGED | IOP331_TMR_RELOAD | + IOP331_TMR_RATIO_1_1; + + asm volatile("mcr p6, 0, %0, c4, c1, 0" : : "r" (LATCH)); + + asm volatile("mcr p6, 0, %0, c0, c1, 0" : : "r" (timer_ctl)); + +} + +struct sys_timer iop331_timer = { + .init = iop331_timer_init, + .offset = iop331_gettimeoffset, +}; |