aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-iop33x
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-iop33x')
-rw-r--r--arch/arm/mach-iop33x/Kconfig27
-rw-r--r--arch/arm/mach-iop33x/Makefile11
-rw-r--r--arch/arm/mach-iop33x/Makefile.boot3
-rw-r--r--arch/arm/mach-iop33x/common.c22
-rw-r--r--arch/arm/mach-iop33x/iq80331-mm.c35
-rw-r--r--arch/arm/mach-iop33x/iq80331-pci.c119
-rw-r--r--arch/arm/mach-iop33x/iq80332-mm.c35
-rw-r--r--arch/arm/mach-iop33x/iq80332-pci.c125
-rw-r--r--arch/arm/mach-iop33x/irq.c129
-rw-r--r--arch/arm/mach-iop33x/pci.c222
-rw-r--r--arch/arm/mach-iop33x/setup.c221
-rw-r--r--arch/arm/mach-iop33x/time.c106
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,
+};