aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-rpc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-rpc')
-rw-r--r--arch/arm/mach-rpc/Makefile2
-rw-r--r--arch/arm/mach-rpc/Makefile.boot2
-rw-r--r--arch/arm/mach-rpc/dma.c2
-rw-r--r--arch/arm/mach-rpc/ecard.c1140
-rw-r--r--arch/arm/mach-rpc/ecard.h69
-rw-r--r--arch/arm/mach-rpc/fiq.S16
-rw-r--r--arch/arm/mach-rpc/include/mach/debug-macro.S23
-rw-r--r--arch/arm/mach-rpc/include/mach/entry-macro.S4
-rw-r--r--arch/arm/mach-rpc/include/mach/hardware.h31
-rw-r--r--arch/arm/mach-rpc/include/mach/io.h198
-rw-r--r--arch/arm/mach-rpc/include/mach/irqs.h2
-rw-r--r--arch/arm/mach-rpc/include/mach/memory.h2
-rw-r--r--arch/arm/mach-rpc/include/mach/system.h27
-rw-r--r--arch/arm/mach-rpc/include/mach/timex.h17
-rw-r--r--arch/arm/mach-rpc/include/mach/uncompress.h17
-rw-r--r--arch/arm/mach-rpc/include/mach/vmalloc.h10
-rw-r--r--arch/arm/mach-rpc/irq.c82
-rw-r--r--arch/arm/mach-rpc/riscpc.c67
-rw-r--r--arch/arm/mach-rpc/time.c92
19 files changed, 1424 insertions, 379 deletions
diff --git a/arch/arm/mach-rpc/Makefile b/arch/arm/mach-rpc/Makefile
index aa77bc9efbb..992e28b4ae9 100644
--- a/arch/arm/mach-rpc/Makefile
+++ b/arch/arm/mach-rpc/Makefile
@@ -4,7 +4,7 @@
# Object file lists.
-obj-y := dma.o irq.o riscpc.o
+obj-y := dma.o ecard.o fiq.o irq.o riscpc.o time.o
obj-m :=
obj-n :=
obj- :=
diff --git a/arch/arm/mach-rpc/Makefile.boot b/arch/arm/mach-rpc/Makefile.boot
index 9c9e7685ec7..ae2df0d7d03 100644
--- a/arch/arm/mach-rpc/Makefile.boot
+++ b/arch/arm/mach-rpc/Makefile.boot
@@ -1,4 +1,4 @@
- zreladdr-y := 0x10008000
+ zreladdr-y += 0x10008000
params_phys-y := 0x10000100
initrd_phys-y := 0x18000000
diff --git a/arch/arm/mach-rpc/dma.c b/arch/arm/mach-rpc/dma.c
index 85883b2e0e4..6d3517dc477 100644
--- a/arch/arm/mach-rpc/dma.c
+++ b/arch/arm/mach-rpc/dma.c
@@ -141,7 +141,7 @@ static int iomd_request_dma(unsigned int chan, dma_t *dma)
struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
return request_irq(idma->irq, iomd_dma_handle,
- IRQF_DISABLED, idma->dma.device_id, idma);
+ 0, idma->dma.device_id, idma);
}
static void iomd_free_dma(unsigned int chan, dma_t *dma)
diff --git a/arch/arm/mach-rpc/ecard.c b/arch/arm/mach-rpc/ecard.c
new file mode 100644
index 00000000000..fcb1d59f7ae
--- /dev/null
+++ b/arch/arm/mach-rpc/ecard.c
@@ -0,0 +1,1140 @@
+/*
+ * linux/arch/arm/kernel/ecard.c
+ *
+ * Copyright 1995-2001 Russell King
+ *
+ * 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.
+ *
+ * Find all installed expansion cards, and handle interrupts from them.
+ *
+ * Created from information from Acorns RiscOS3 PRMs
+ *
+ * 08-Dec-1996 RMK Added code for the 9'th expansion card - the ether
+ * podule slot.
+ * 06-May-1997 RMK Added blacklist for cards whose loader doesn't work.
+ * 12-Sep-1997 RMK Created new handling of interrupt enables/disables
+ * - cards can now register their own routine to control
+ * interrupts (recommended).
+ * 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled
+ * on reset from Linux. (Caused cards not to respond
+ * under RiscOS without hard reset).
+ * 15-Feb-1998 RMK Added DMA support
+ * 12-Sep-1998 RMK Added EASI support
+ * 10-Jan-1999 RMK Run loaders in a simulated RISC OS environment.
+ * 17-Apr-1999 RMK Support for EASI Type C cycles.
+ */
+#define ECARD_C
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/reboot.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <asm/dma.h>
+#include <asm/ecard.h>
+#include <mach/hardware.h>
+#include <asm/irq.h>
+#include <asm/mmu_context.h>
+#include <asm/mach/irq.h>
+#include <asm/tlbflush.h>
+
+#include "ecard.h"
+
+struct ecard_request {
+ void (*fn)(struct ecard_request *);
+ ecard_t *ec;
+ unsigned int address;
+ unsigned int length;
+ unsigned int use_loader;
+ void *buffer;
+ struct completion *complete;
+};
+
+struct expcard_blacklist {
+ unsigned short manufacturer;
+ unsigned short product;
+ const char *type;
+};
+
+static ecard_t *cards;
+static ecard_t *slot_to_expcard[MAX_ECARDS];
+static unsigned int ectcr;
+
+/* List of descriptions of cards which don't have an extended
+ * identification, or chunk directories containing a description.
+ */
+static struct expcard_blacklist __initdata blacklist[] = {
+ { MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" }
+};
+
+asmlinkage extern int
+ecard_loader_reset(unsigned long base, loader_t loader);
+asmlinkage extern int
+ecard_loader_read(int off, unsigned long base, loader_t loader);
+
+static inline unsigned short ecard_getu16(unsigned char *v)
+{
+ return v[0] | v[1] << 8;
+}
+
+static inline signed long ecard_gets24(unsigned char *v)
+{
+ return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0);
+}
+
+static inline ecard_t *slot_to_ecard(unsigned int slot)
+{
+ return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL;
+}
+
+/* ===================== Expansion card daemon ======================== */
+/*
+ * Since the loader programs on the expansion cards need to be run
+ * in a specific environment, create a separate task with this
+ * environment up, and pass requests to this task as and when we
+ * need to.
+ *
+ * This should allow 99% of loaders to be called from Linux.
+ *
+ * From a security standpoint, we trust the card vendors. This
+ * may be a misplaced trust.
+ */
+static void ecard_task_reset(struct ecard_request *req)
+{
+ struct expansion_card *ec = req->ec;
+ struct resource *res;
+
+ res = ec->slot_no == 8
+ ? &ec->resource[ECARD_RES_MEMC]
+ : ec->easi
+ ? &ec->resource[ECARD_RES_EASI]
+ : &ec->resource[ECARD_RES_IOCSYNC];
+
+ ecard_loader_reset(res->start, ec->loader);
+}
+
+static void ecard_task_readbytes(struct ecard_request *req)
+{
+ struct expansion_card *ec = req->ec;
+ unsigned char *buf = req->buffer;
+ unsigned int len = req->length;
+ unsigned int off = req->address;
+
+ if (ec->slot_no == 8) {
+ void __iomem *base = (void __iomem *)
+ ec->resource[ECARD_RES_MEMC].start;
+
+ /*
+ * The card maintains an index which increments the address
+ * into a 4096-byte page on each access. We need to keep
+ * track of the counter.
+ */
+ static unsigned int index;
+ unsigned int page;
+
+ page = (off >> 12) * 4;
+ if (page > 256 * 4)
+ return;
+
+ off &= 4095;
+
+ /*
+ * If we are reading offset 0, or our current index is
+ * greater than the offset, reset the hardware index counter.
+ */
+ if (off == 0 || index > off) {
+ writeb(0, base);
+ index = 0;
+ }
+
+ /*
+ * Increment the hardware index counter until we get to the
+ * required offset. The read bytes are discarded.
+ */
+ while (index < off) {
+ readb(base + page);
+ index += 1;
+ }
+
+ while (len--) {
+ *buf++ = readb(base + page);
+ index += 1;
+ }
+ } else {
+ unsigned long base = (ec->easi
+ ? &ec->resource[ECARD_RES_EASI]
+ : &ec->resource[ECARD_RES_IOCSYNC])->start;
+ void __iomem *pbase = (void __iomem *)base;
+
+ if (!req->use_loader || !ec->loader) {
+ off *= 4;
+ while (len--) {
+ *buf++ = readb(pbase + off);
+ off += 4;
+ }
+ } else {
+ while(len--) {
+ /*
+ * The following is required by some
+ * expansion card loader programs.
+ */
+ *(unsigned long *)0x108 = 0;
+ *buf++ = ecard_loader_read(off++, base,
+ ec->loader);
+ }
+ }
+ }
+
+}
+
+static DECLARE_WAIT_QUEUE_HEAD(ecard_wait);
+static struct ecard_request *ecard_req;
+static DEFINE_MUTEX(ecard_mutex);
+
+/*
+ * Set up the expansion card daemon's page tables.
+ */
+static void ecard_init_pgtables(struct mm_struct *mm)
+{
+ struct vm_area_struct vma;
+
+ /* We want to set up the page tables for the following mapping:
+ * Virtual Physical
+ * 0x03000000 0x03000000
+ * 0x03010000 unmapped
+ * 0x03210000 0x03210000
+ * 0x03400000 unmapped
+ * 0x08000000 0x08000000
+ * 0x10000000 unmapped
+ *
+ * FIXME: we don't follow this 100% yet.
+ */
+ pgd_t *src_pgd, *dst_pgd;
+
+ src_pgd = pgd_offset(mm, (unsigned long)IO_BASE);
+ dst_pgd = pgd_offset(mm, IO_START);
+
+ memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (IO_SIZE / PGDIR_SIZE));
+
+ src_pgd = pgd_offset(mm, (unsigned long)EASI_BASE);
+ dst_pgd = pgd_offset(mm, EASI_START);
+
+ memcpy(dst_pgd, src_pgd, sizeof(pgd_t) * (EASI_SIZE / PGDIR_SIZE));
+
+ vma.vm_flags = VM_EXEC;
+ vma.vm_mm = mm;
+
+ flush_tlb_range(&vma, IO_START, IO_START + IO_SIZE);
+ flush_tlb_range(&vma, EASI_START, EASI_START + EASI_SIZE);
+}
+
+static int ecard_init_mm(void)
+{
+ struct mm_struct * mm = mm_alloc();
+ struct mm_struct *active_mm = current->active_mm;
+
+ if (!mm)
+ return -ENOMEM;
+
+ current->mm = mm;
+ current->active_mm = mm;
+ activate_mm(active_mm, mm);
+ mmdrop(active_mm);
+ ecard_init_pgtables(mm);
+ return 0;
+}
+
+static int
+ecard_task(void * unused)
+{
+ /*
+ * Allocate a mm. We're not a lazy-TLB kernel task since we need
+ * to set page table entries where the user space would be. Note
+ * that this also creates the page tables. Failure is not an
+ * option here.
+ */
+ if (ecard_init_mm())
+ panic("kecardd: unable to alloc mm\n");
+
+ while (1) {
+ struct ecard_request *req;
+
+ wait_event_interruptible(ecard_wait, ecard_req != NULL);
+
+ req = xchg(&ecard_req, NULL);
+ if (req != NULL) {
+ req->fn(req);
+ complete(req->complete);
+ }
+ }
+}
+
+/*
+ * Wake the expansion card daemon to action our request.
+ *
+ * FIXME: The test here is not sufficient to detect if the
+ * kcardd is running.
+ */
+static void ecard_call(struct ecard_request *req)
+{
+ DECLARE_COMPLETION_ONSTACK(completion);
+
+ req->complete = &completion;
+
+ mutex_lock(&ecard_mutex);
+ ecard_req = req;
+ wake_up(&ecard_wait);
+
+ /*
+ * Now wait for kecardd to run.
+ */
+ wait_for_completion(&completion);
+ mutex_unlock(&ecard_mutex);
+}
+
+/* ======================= Mid-level card control ===================== */
+
+static void
+ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld)
+{
+ struct ecard_request req;
+
+ req.fn = ecard_task_readbytes;
+ req.ec = ec;
+ req.address = off;
+ req.length = len;
+ req.use_loader = useld;
+ req.buffer = addr;
+
+ ecard_call(&req);
+}
+
+int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num)
+{
+ struct ex_chunk_dir excd;
+ int index = 16;
+ int useld = 0;
+
+ if (!ec->cid.cd)
+ return 0;
+
+ while(1) {
+ ecard_readbytes(&excd, ec, index, 8, useld);
+ index += 8;
+ if (c_id(&excd) == 0) {
+ if (!useld && ec->loader) {
+ useld = 1;
+ index = 0;
+ continue;
+ }
+ return 0;
+ }
+ if (c_id(&excd) == 0xf0) { /* link */
+ index = c_start(&excd);
+ continue;
+ }
+ if (c_id(&excd) == 0x80) { /* loader */
+ if (!ec->loader) {
+ ec->loader = kmalloc(c_len(&excd),
+ GFP_KERNEL);
+ if (ec->loader)
+ ecard_readbytes(ec->loader, ec,
+ (int)c_start(&excd),
+ c_len(&excd), useld);
+ else
+ return 0;
+ }
+ continue;
+ }
+ if (c_id(&excd) == id && num-- == 0)
+ break;
+ }
+
+ if (c_id(&excd) & 0x80) {
+ switch (c_id(&excd) & 0x70) {
+ case 0x70:
+ ecard_readbytes((unsigned char *)excd.d.string, ec,
+ (int)c_start(&excd), c_len(&excd),
+ useld);
+ break;
+ case 0x00:
+ break;
+ }
+ }
+ cd->start_offset = c_start(&excd);
+ memcpy(cd->d.string, excd.d.string, 256);
+ return 1;
+}
+
+/* ======================= Interrupt control ============================ */
+
+static void ecard_def_irq_enable(ecard_t *ec, int irqnr)
+{
+}
+
+static void ecard_def_irq_disable(ecard_t *ec, int irqnr)
+{
+}
+
+static int ecard_def_irq_pending(ecard_t *ec)
+{
+ return !ec->irqmask || readb(ec->irqaddr) & ec->irqmask;
+}
+
+static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr)
+{
+ panic("ecard_def_fiq_enable called - impossible");
+}
+
+static void ecard_def_fiq_disable(ecard_t *ec, int fiqnr)
+{
+ panic("ecard_def_fiq_disable called - impossible");
+}
+
+static int ecard_def_fiq_pending(ecard_t *ec)
+{
+ return !ec->fiqmask || readb(ec->fiqaddr) & ec->fiqmask;
+}
+
+static expansioncard_ops_t ecard_default_ops = {
+ ecard_def_irq_enable,
+ ecard_def_irq_disable,
+ ecard_def_irq_pending,
+ ecard_def_fiq_enable,
+ ecard_def_fiq_disable,
+ ecard_def_fiq_pending
+};
+
+/*
+ * Enable and disable interrupts from expansion cards.
+ * (interrupts are disabled for these functions).
+ *
+ * They are not meant to be called directly, but via enable/disable_irq.
+ */
+static void ecard_irq_unmask(struct irq_data *d)
+{
+ ecard_t *ec = irq_data_get_irq_chip_data(d);
+
+ if (ec) {
+ if (!ec->ops)
+ ec->ops = &ecard_default_ops;
+
+ if (ec->claimed && ec->ops->irqenable)
+ ec->ops->irqenable(ec, d->irq);
+ else
+ printk(KERN_ERR "ecard: rejecting request to "
+ "enable IRQs for %d\n", d->irq);
+ }
+}
+
+static void ecard_irq_mask(struct irq_data *d)
+{
+ ecard_t *ec = irq_data_get_irq_chip_data(d);
+
+ if (ec) {
+ if (!ec->ops)
+ ec->ops = &ecard_default_ops;
+
+ if (ec->ops && ec->ops->irqdisable)
+ ec->ops->irqdisable(ec, d->irq);
+ }
+}
+
+static struct irq_chip ecard_chip = {
+ .name = "ECARD",
+ .irq_ack = ecard_irq_mask,
+ .irq_mask = ecard_irq_mask,
+ .irq_unmask = ecard_irq_unmask,
+};
+
+void ecard_enablefiq(unsigned int fiqnr)
+{
+ ecard_t *ec = slot_to_ecard(fiqnr);
+
+ if (ec) {
+ if (!ec->ops)
+ ec->ops = &ecard_default_ops;
+
+ if (ec->claimed && ec->ops->fiqenable)
+ ec->ops->fiqenable(ec, fiqnr);
+ else
+ printk(KERN_ERR "ecard: rejecting request to "
+ "enable FIQs for %d\n", fiqnr);
+ }
+}
+
+void ecard_disablefiq(unsigned int fiqnr)
+{
+ ecard_t *ec = slot_to_ecard(fiqnr);
+
+ if (ec) {
+ if (!ec->ops)
+ ec->ops = &ecard_default_ops;
+
+ if (ec->ops->fiqdisable)
+ ec->ops->fiqdisable(ec, fiqnr);
+ }
+}
+
+static void ecard_dump_irq_state(void)
+{
+ ecard_t *ec;
+
+ printk("Expansion card IRQ state:\n");
+
+ for (ec = cards; ec; ec = ec->next) {
+ if (ec->slot_no == 8)
+ continue;
+
+ printk(" %d: %sclaimed, ",
+ ec->slot_no, ec->claimed ? "" : "not ");
+
+ if (ec->ops && ec->ops->irqpending &&
+ ec->ops != &ecard_default_ops)
+ printk("irq %spending\n",
+ ec->ops->irqpending(ec) ? "" : "not ");
+ else
+ printk("irqaddr %p, mask = %02X, status = %02X\n",
+ ec->irqaddr, ec->irqmask, readb(ec->irqaddr));
+ }
+}
+
+static void ecard_check_lockup(struct irq_desc *desc)
+{
+ static unsigned long last;
+ static int lockup;
+
+ /*
+ * If the timer interrupt has not run since the last million
+ * unrecognised expansion card interrupts, then there is
+ * something seriously wrong. Disable the expansion card
+ * interrupts so at least we can continue.
+ *
+ * Maybe we ought to start a timer to re-enable them some time
+ * later?
+ */
+ if (last == jiffies) {
+ lockup += 1;
+ if (lockup > 1000000) {
+ printk(KERN_ERR "\nInterrupt lockup detected - "
+ "disabling all expansion card interrupts\n");
+
+ desc->irq_data.chip->irq_mask(&desc->irq_data);
+ ecard_dump_irq_state();
+ }
+ } else
+ lockup = 0;
+
+ /*
+ * If we did not recognise the source of this interrupt,
+ * warn the user, but don't flood the user with these messages.
+ */
+ if (!last || time_after(jiffies, last + 5*HZ)) {
+ last = jiffies;
+ printk(KERN_WARNING "Unrecognised interrupt from backplane\n");
+ ecard_dump_irq_state();
+ }
+}
+
+static void
+ecard_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ ecard_t *ec;
+ int called = 0;
+
+ desc->irq_data.chip->irq_mask(&desc->irq_data);
+ for (ec = cards; ec; ec = ec->next) {
+ int pending;
+
+ if (!ec->claimed || !ec->irq || ec->slot_no == 8)
+ continue;
+
+ if (ec->ops && ec->ops->irqpending)
+ pending = ec->ops->irqpending(ec);
+ else
+ pending = ecard_default_ops.irqpending(ec);
+
+ if (pending) {
+ generic_handle_irq(ec->irq);
+ called ++;
+ }
+ }
+ desc->irq_data.chip->irq_unmask(&desc->irq_data);
+
+ if (called == 0)
+ ecard_check_lockup(desc);
+}
+
+static void __iomem *__ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed)
+{
+ void __iomem *address = NULL;
+ int slot = ec->slot_no;
+
+ if (ec->slot_no == 8)
+ return ECARD_MEMC8_BASE;
+
+ ectcr &= ~(1 << slot);
+
+ switch (type) {
+ case ECARD_MEMC:
+ if (slot < 4)
+ address = ECARD_MEMC_BASE + (slot << 14);
+ break;
+
+ case ECARD_IOC:
+ if (slot < 4)
+ address = ECARD_IOC_BASE + (slot << 14);
+ else
+ address = ECARD_IOC4_BASE + ((slot - 4) << 14);
+ if (address)
+ address += speed << 19;
+ break;
+
+ case ECARD_EASI:
+ address = ECARD_EASI_BASE + (slot << 24);
+ if (speed == ECARD_FAST)
+ ectcr |= 1 << slot;
+ break;
+
+ default:
+ break;
+ }
+
+#ifdef IOMD_ECTCR
+ iomd_writeb(ectcr, IOMD_ECTCR);
+#endif
+ return address;
+}
+
+static int ecard_prints(struct seq_file *m, ecard_t *ec)
+{
+ seq_printf(m, " %d: %s ", ec->slot_no, ec->easi ? "EASI" : " ");
+
+ if (ec->cid.id == 0) {
+ struct in_chunk_dir incd;
+
+ seq_printf(m, "[%04X:%04X] ",
+ ec->cid.manufacturer, ec->cid.product);
+
+ if (!ec->card_desc && ec->cid.cd &&
+ ecard_readchunk(&incd, ec, 0xf5, 0)) {
+ ec->card_desc = kmalloc(strlen(incd.d.string)+1, GFP_KERNEL);
+
+ if (ec->card_desc)
+ strcpy((char *)ec->card_desc, incd.d.string);
+ }
+
+ seq_printf(m, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*");
+ } else
+ seq_printf(m, "Simple card %d\n", ec->cid.id);
+
+ return 0;
+}
+
+static int ecard_devices_proc_show(struct seq_file *m, void *v)
+{
+ ecard_t *ec = cards;
+
+ while (ec) {
+ ecard_prints(m, ec);
+ ec = ec->next;
+ }
+ return 0;
+}
+
+static int ecard_devices_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ecard_devices_proc_show, NULL);
+}
+
+static const struct file_operations bus_ecard_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = ecard_devices_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct proc_dir_entry *proc_bus_ecard_dir = NULL;
+
+static void ecard_proc_init(void)
+{
+ proc_bus_ecard_dir = proc_mkdir("bus/ecard", NULL);
+ proc_create("devices", 0, proc_bus_ecard_dir, &bus_ecard_proc_fops);
+}
+
+#define ec_set_resource(ec,nr,st,sz) \
+ do { \
+ (ec)->resource[nr].name = dev_name(&ec->dev); \
+ (ec)->resource[nr].start = st; \
+ (ec)->resource[nr].end = (st) + (sz) - 1; \
+ (ec)->resource[nr].flags = IORESOURCE_MEM; \
+ } while (0)
+
+static void __init ecard_free_card(struct expansion_card *ec)
+{
+ int i;
+
+ for (i = 0; i < ECARD_NUM_RESOURCES; i++)
+ if (ec->resource[i].flags)
+ release_resource(&ec->resource[i]);
+
+ kfree(ec);
+}
+
+static struct expansion_card *__init ecard_alloc_card(int type, int slot)
+{
+ struct expansion_card *ec;
+ unsigned long base;
+ int i;
+
+ ec = kzalloc(sizeof(ecard_t), GFP_KERNEL);
+ if (!ec) {
+ ec = ERR_PTR(-ENOMEM);
+ goto nomem;
+ }
+
+ ec->slot_no = slot;
+ ec->easi = type == ECARD_EASI;
+ ec->irq = 0;
+ ec->fiq = 0;
+ ec->dma = NO_DMA;
+ ec->ops = &ecard_default_ops;
+
+ dev_set_name(&ec->dev, "ecard%d", slot);
+ ec->dev.parent = NULL;
+ ec->dev.bus = &ecard_bus_type;
+ ec->dev.dma_mask = &ec->dma_mask;
+ ec->dma_mask = (u64)0xffffffff;
+ ec->dev.coherent_dma_mask = ec->dma_mask;
+
+ if (slot < 4) {
+ ec_set_resource(ec, ECARD_RES_MEMC,
+ PODSLOT_MEMC_BASE + (slot << 14),
+ PODSLOT_MEMC_SIZE);
+ base = PODSLOT_IOC0_BASE + (slot << 14);
+ } else
+ base = PODSLOT_IOC4_BASE + ((slot - 4) << 14);
+
+#ifdef CONFIG_ARCH_RPC
+ if (slot < 8) {
+ ec_set_resource(ec, ECARD_RES_EASI,
+ PODSLOT_EASI_BASE + (slot << 24),
+ PODSLOT_EASI_SIZE);
+ }
+
+ if (slot == 8) {
+ ec_set_resource(ec, ECARD_RES_MEMC, NETSLOT_BASE, NETSLOT_SIZE);
+ } else
+#endif
+
+ for (i = 0; i <= ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++)
+ ec_set_resource(ec, i + ECARD_RES_IOCSLOW,
+ base + (i << 19), PODSLOT_IOC_SIZE);
+
+ for (i = 0; i < ECARD_NUM_RESOURCES; i++) {
+ if (ec->resource[i].flags &&
+ request_resource(&iomem_resource, &ec->resource[i])) {
+ dev_err(&ec->dev, "resource(s) not available\n");
+ ec->resource[i].end -= ec->resource[i].start;
+ ec->resource[i].start = 0;
+ ec->resource[i].flags = 0;
+ }
+ }
+
+ nomem:
+ return ec;
+}
+
+static ssize_t ecard_show_irq(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct expansion_card *ec = ECARD_DEV(dev);
+ return sprintf(buf, "%u\n", ec->irq);
+}
+
+static ssize_t ecard_show_dma(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct expansion_card *ec = ECARD_DEV(dev);
+ return sprintf(buf, "%u\n", ec->dma);
+}
+
+static ssize_t ecard_show_resources(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct expansion_card *ec = ECARD_DEV(dev);
+ char *str = buf;
+ int i;
+
+ for (i = 0; i < ECARD_NUM_RESOURCES; i++)
+ str += sprintf(str, "%08x %08x %08lx\n",
+ ec->resource[i].start,
+ ec->resource[i].end,
+ ec->resource[i].flags);
+
+ return str - buf;
+}
+
+static ssize_t ecard_show_vendor(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct expansion_card *ec = ECARD_DEV(dev);
+ return sprintf(buf, "%u\n", ec->cid.manufacturer);
+}
+
+static ssize_t ecard_show_device(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct expansion_card *ec = ECARD_DEV(dev);
+ return sprintf(buf, "%u\n", ec->cid.product);
+}
+
+static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct expansion_card *ec = ECARD_DEV(dev);
+ return sprintf(buf, "%s\n", ec->easi ? "EASI" : "IOC");
+}
+
+static struct device_attribute ecard_dev_attrs[] = {
+ __ATTR(device, S_IRUGO, ecard_show_device, NULL),
+ __ATTR(dma, S_IRUGO, ecard_show_dma, NULL),
+ __ATTR(irq, S_IRUGO, ecard_show_irq, NULL),
+ __ATTR(resource, S_IRUGO, ecard_show_resources, NULL),
+ __ATTR(type, S_IRUGO, ecard_show_type, NULL),
+ __ATTR(vendor, S_IRUGO, ecard_show_vendor, NULL),
+ __ATTR_NULL,
+};
+
+
+int ecard_request_resources(struct expansion_card *ec)
+{
+ int i, err = 0;
+
+ for (i = 0; i < ECARD_NUM_RESOURCES; i++) {
+ if (ecard_resource_end(ec, i) &&
+ !request_mem_region(ecard_resource_start(ec, i),
+ ecard_resource_len(ec, i),
+ ec->dev.driver->name)) {
+ err = -EBUSY;
+ break;
+ }
+ }
+
+ if (err) {
+ while (i--)
+ if (ecard_resource_end(ec, i))
+ release_mem_region(ecard_resource_start(ec, i),
+ ecard_resource_len(ec, i));
+ }
+ return err;
+}
+EXPORT_SYMBOL(ecard_request_resources);
+
+void ecard_release_resources(struct expansion_card *ec)
+{
+ int i;
+
+ for (i = 0; i < ECARD_NUM_RESOURCES; i++)
+ if (ecard_resource_end(ec, i))
+ release_mem_region(ecard_resource_start(ec, i),
+ ecard_resource_len(ec, i));
+}
+EXPORT_SYMBOL(ecard_release_resources);
+
+void ecard_setirq(struct expansion_card *ec, const struct expansion_card_ops *ops, void *irq_data)
+{
+ ec->irq_data = irq_data;
+ barrier();
+ ec->ops = ops;
+}
+EXPORT_SYMBOL(ecard_setirq);
+
+void __iomem *ecardm_iomap(struct expansion_card *ec, unsigned int res,
+ unsigned long offset, unsigned long maxsize)
+{
+ unsigned long start = ecard_resource_start(ec, res);
+ unsigned long end = ecard_resource_end(ec, res);
+
+ if (offset > (end - start))
+ return NULL;
+
+ start += offset;
+ if (maxsize && end - start > maxsize)
+ end = start + maxsize;
+
+ return devm_ioremap(&ec->dev, start, end - start);
+}
+EXPORT_SYMBOL(ecardm_iomap);
+
+/*
+ * Probe for an expansion card.
+ *
+ * If bit 1 of the first byte of the card is set, then the
+ * card does not exist.
+ */
+static int __init ecard_probe(int slot, unsigned irq, card_type_t type)
+{
+ ecard_t **ecp;
+ ecard_t *ec;
+ struct ex_ecid cid;
+ void __iomem *addr;
+ int i, rc;
+
+ ec = ecard_alloc_card(type, slot);
+ if (IS_ERR(ec)) {
+ rc = PTR_ERR(ec);
+ goto nomem;
+ }
+
+ rc = -ENODEV;
+ if ((addr = __ecard_address(ec, type, ECARD_SYNC)) == NULL)
+ goto nodev;
+
+ cid.r_zero = 1;
+ ecard_readbytes(&cid, ec, 0, 16, 0);
+ if (cid.r_zero)
+ goto nodev;
+
+ ec->cid.id = cid.r_id;
+ ec->cid.cd = cid.r_cd;
+ ec->cid.is = cid.r_is;
+ ec->cid.w = cid.r_w;
+ ec->cid.manufacturer = ecard_getu16(cid.r_manu);
+ ec->cid.product = ecard_getu16(cid.r_prod);
+ ec->cid.country = cid.r_country;
+ ec->cid.irqmask = cid.r_irqmask;
+ ec->cid.irqoff = ecard_gets24(cid.r_irqoff);
+ ec->cid.fiqmask = cid.r_fiqmask;
+ ec->cid.fiqoff = ecard_gets24(cid.r_fiqoff);
+ ec->fiqaddr =
+ ec->irqaddr = addr;
+
+ if (ec->cid.is) {
+ ec->irqmask = ec->cid.irqmask;
+ ec->irqaddr += ec->cid.irqoff;
+ ec->fiqmask = ec->cid.fiqmask;
+ ec->fiqaddr += ec->cid.fiqoff;
+ } else {
+ ec->irqmask = 1;
+ ec->fiqmask = 4;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(blacklist); i++)
+ if (blacklist[i].manufacturer == ec->cid.manufacturer &&
+ blacklist[i].product == ec->cid.product) {
+ ec->card_desc = blacklist[i].type;
+ break;
+ }
+
+ ec->irq = irq;
+
+ /*
+ * hook the interrupt handlers
+ */
+ if (slot < 8) {
+ irq_set_chip_and_handler(ec->irq, &ecard_chip,
+ handle_level_irq);
+ irq_set_chip_data(ec->irq, ec);
+ set_irq_flags(ec->irq, IRQF_VALID);
+ }
+
+#ifdef CONFIG_ARCH_RPC
+ /* On RiscPC, only first two slots have DMA capability */
+ if (slot < 2)
+ ec->dma = 2 + slot;
+#endif
+
+ for (ecp = &cards; *ecp; ecp = &(*ecp)->next);
+
+ *ecp = ec;
+ slot_to_expcard[slot] = ec;
+
+ rc = device_register(&ec->dev);
+ if (rc)
+ goto nodev;
+
+ return 0;
+
+ nodev:
+ ecard_free_card(ec);
+ nomem:
+ return rc;
+}
+
+/*
+ * Initialise the expansion card system.
+ * Locate all hardware - interrupt management and
+ * actual cards.
+ */
+static int __init ecard_init(void)
+{
+ struct task_struct *task;
+ int slot, irqbase;
+
+ irqbase = irq_alloc_descs(-1, 0, 8, -1);
+ if (irqbase < 0)
+ return irqbase;
+
+ task = kthread_run(ecard_task, NULL, "kecardd");
+ if (IS_ERR(task)) {
+ printk(KERN_ERR "Ecard: unable to create kernel thread: %ld\n",
+ PTR_ERR(task));
+ irq_free_descs(irqbase, 8);
+ return PTR_ERR(task);
+ }
+
+ printk("Probing expansion cards\n");
+
+ for (slot = 0; slot < 8; slot ++) {
+ if (ecard_probe(slot, irqbase + slot, ECARD_EASI) == -ENODEV)
+ ecard_probe(slot, irqbase + slot, ECARD_IOC);
+ }
+
+ ecard_probe(8, 11, ECARD_IOC);
+
+ irq_set_chained_handler(IRQ_EXPANSIONCARD, ecard_irq_handler);
+
+ ecard_proc_init();
+
+ return 0;
+}
+
+subsys_initcall(ecard_init);
+
+/*
+ * ECARD "bus"
+ */
+static const struct ecard_id *
+ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec)
+{
+ int i;
+
+ for (i = 0; ids[i].manufacturer != 65535; i++)
+ if (ec->cid.manufacturer == ids[i].manufacturer &&
+ ec->cid.product == ids[i].product)
+ return ids + i;
+
+ return NULL;
+}
+
+static int ecard_drv_probe(struct device *dev)
+{
+ struct expansion_card *ec = ECARD_DEV(dev);
+ struct ecard_driver *drv = ECARD_DRV(dev->driver);
+ const struct ecard_id *id;
+ int ret;
+
+ id = ecard_match_device(drv->id_table, ec);
+
+ ec->claimed = 1;
+ ret = drv->probe(ec, id);
+ if (ret)
+ ec->claimed = 0;
+ return ret;
+}
+
+static int ecard_drv_remove(struct device *dev)
+{
+ struct expansion_card *ec = ECARD_DEV(dev);
+ struct ecard_driver *drv = ECARD_DRV(dev->driver);
+
+ drv->remove(ec);
+ ec->claimed = 0;
+
+ /*
+ * Restore the default operations. We ensure that the
+ * ops are set before we change the data.
+ */
+ ec->ops = &ecard_default_ops;
+ barrier();
+ ec->irq_data = NULL;
+
+ return 0;
+}
+
+/*
+ * Before rebooting, we must make sure that the expansion card is in a
+ * sensible state, so it can be re-detected. This means that the first
+ * page of the ROM must be visible. We call the expansion cards reset
+ * handler, if any.
+ */
+static void ecard_drv_shutdown(struct device *dev)
+{
+ struct expansion_card *ec = ECARD_DEV(dev);
+ struct ecard_driver *drv = ECARD_DRV(dev->driver);
+ struct ecard_request req;
+
+ if (dev->driver) {
+ if (drv->shutdown)
+ drv->shutdown(ec);
+ ec->claimed = 0;
+ }
+
+ /*
+ * If this card has a loader, call the reset handler.
+ */
+ if (ec->loader) {
+ req.fn = ecard_task_reset;
+ req.ec = ec;
+ ecard_call(&req);
+ }
+}
+
+int ecard_register_driver(struct ecard_driver *drv)
+{
+ drv->drv.bus = &ecard_bus_type;
+
+ return driver_register(&drv->drv);
+}
+
+void ecard_remove_driver(struct ecard_driver *drv)
+{
+ driver_unregister(&drv->drv);
+}
+
+static int ecard_match(struct device *_dev, struct device_driver *_drv)
+{
+ struct expansion_card *ec = ECARD_DEV(_dev);
+ struct ecard_driver *drv = ECARD_DRV(_drv);
+ int ret;
+
+ if (drv->id_table) {
+ ret = ecard_match_device(drv->id_table, ec) != NULL;
+ } else {
+ ret = ec->cid.id == drv->id;
+ }
+
+ return ret;
+}
+
+struct bus_type ecard_bus_type = {
+ .name = "ecard",
+ .dev_attrs = ecard_dev_attrs,
+ .match = ecard_match,
+ .probe = ecard_drv_probe,
+ .remove = ecard_drv_remove,
+ .shutdown = ecard_drv_shutdown,
+};
+
+static int ecard_bus_init(void)
+{
+ return bus_register(&ecard_bus_type);
+}
+
+postcore_initcall(ecard_bus_init);
+
+EXPORT_SYMBOL(ecard_readchunk);
+EXPORT_SYMBOL(ecard_register_driver);
+EXPORT_SYMBOL(ecard_remove_driver);
+EXPORT_SYMBOL(ecard_bus_type);
diff --git a/arch/arm/mach-rpc/ecard.h b/arch/arm/mach-rpc/ecard.h
new file mode 100644
index 00000000000..4642d436be2
--- /dev/null
+++ b/arch/arm/mach-rpc/ecard.h
@@ -0,0 +1,69 @@
+/*
+ * ecard.h
+ *
+ * Copyright 2007 Russell King
+ *
+ * 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.
+ */
+
+/* Definitions internal to ecard.c - for it's use only!!
+ *
+ * External expansion card header as read from the card
+ */
+struct ex_ecid {
+ unsigned char r_irq:1;
+ unsigned char r_zero:1;
+ unsigned char r_fiq:1;
+ unsigned char r_id:4;
+ unsigned char r_a:1;
+
+ unsigned char r_cd:1;
+ unsigned char r_is:1;
+ unsigned char r_w:2;
+ unsigned char r_r1:4;
+
+ unsigned char r_r2:8;
+
+ unsigned char r_prod[2];
+
+ unsigned char r_manu[2];
+
+ unsigned char r_country;
+
+ unsigned char r_fiqmask;
+ unsigned char r_fiqoff[3];
+
+ unsigned char r_irqmask;
+ unsigned char r_irqoff[3];
+};
+
+/*
+ * Chunk directory entry as read from the card
+ */
+struct ex_chunk_dir {
+ unsigned char r_id;
+ unsigned char r_len[3];
+ unsigned long r_start;
+ union {
+ char string[256];
+ char data[1];
+ } d;
+#define c_id(x) ((x)->r_id)
+#define c_len(x) ((x)->r_len[0]|((x)->r_len[1]<<8)|((x)->r_len[2]<<16))
+#define c_start(x) ((x)->r_start)
+};
+
+typedef enum ecard_type { /* Cards address space */
+ ECARD_IOC,
+ ECARD_MEMC,
+ ECARD_EASI
+} card_type_t;
+
+typedef enum { /* Speed for ECARD_IOC space */
+ ECARD_SLOW = 0,
+ ECARD_MEDIUM = 1,
+ ECARD_FAST = 2,
+ ECARD_SYNC = 3
+} card_speed_t;
diff --git a/arch/arm/mach-rpc/fiq.S b/arch/arm/mach-rpc/fiq.S
new file mode 100644
index 00000000000..48ddd57db16
--- /dev/null
+++ b/arch/arm/mach-rpc/fiq.S
@@ -0,0 +1,16 @@
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <mach/hardware.h>
+#include <mach/entry-macro.S>
+
+ .text
+
+ .global rpc_default_fiq_end
+ENTRY(rpc_default_fiq_start)
+ mov r12, #ioc_base_high
+ .if ioc_base_low
+ orr r12, r12, #ioc_base_low
+ .endif
+ strb r12, [r12, #0x38] @ Disable FIQ register
+ subs pc, lr, #4
+rpc_default_fiq_end:
diff --git a/arch/arm/mach-rpc/include/mach/debug-macro.S b/arch/arm/mach-rpc/include/mach/debug-macro.S
deleted file mode 100644
index 85effffdc2b..00000000000
--- a/arch/arm/mach-rpc/include/mach/debug-macro.S
+++ /dev/null
@@ -1,23 +0,0 @@
-/* arch/arm/mach-rpc/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- * Copyright (C) 1994-1999 Russell King
- * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * 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.
- *
-*/
-
- .macro addruart, rp, rv
- mov \rp, #0x00010000
- orr \rp, \rp, #0x00000fe0
- orr \rv, \rp, #0xe0000000 @ virtual
- orr \rp, \rp, #0x03000000 @ physical
- .endm
-
-#define UART_SHIFT 2
-#define FLOW_CONTROL
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-rpc/include/mach/entry-macro.S b/arch/arm/mach-rpc/include/mach/entry-macro.S
index 4e7e5414409..7178368d706 100644
--- a/arch/arm/mach-rpc/include/mach/entry-macro.S
+++ b/arch/arm/mach-rpc/include/mach/entry-macro.S
@@ -10,7 +10,3 @@
orr \base, \base, #ioc_base_low
.endif
.endm
-
- .macro arch_ret_to_user, tmp1, tmp2
- .endm
-
diff --git a/arch/arm/mach-rpc/include/mach/hardware.h b/arch/arm/mach-rpc/include/mach/hardware.h
index dde6b3c0e29..257166b21f3 100644
--- a/arch/arm/mach-rpc/include/mach/hardware.h
+++ b/arch/arm/mach-rpc/include/mach/hardware.h
@@ -14,12 +14,6 @@
#include <mach/memory.h>
-#ifndef __ASSEMBLY__
-#define IOMEM(x) ((void __iomem *)(unsigned long)(x))
-#else
-#define IOMEM(x) x
-#endif /* __ASSEMBLY__ */
-
/*
* What hardware must be present
*/
@@ -36,7 +30,7 @@
#define EASI_SIZE 0x08000000 /* EASI I/O */
#define EASI_START 0x08000000
-#define EASI_BASE 0xe5000000
+#define EASI_BASE IOMEM(0xe5000000)
#define IO_START 0x03000000 /* I/O */
#define IO_SIZE 0x01000000
@@ -51,21 +45,20 @@
/*
* IO Addresses
*/
-#define VIDC_BASE IOMEM(0xe0400000)
-#define EXPMASK_BASE 0xe0360000
-#define IOMD_BASE IOMEM(0xe0200000)
-#define IOC_BASE IOMEM(0xe0200000)
-#define PCIO_BASE IOMEM(0xe0010000)
-#define FLOPPYDMA_BASE IOMEM(0xe002a000)
+#define ECARD_EASI_BASE (EASI_BASE)
+#define VIDC_BASE (IO_BASE + 0x00400000)
+#define EXPMASK_BASE (IO_BASE + 0x00360000)
+#define ECARD_IOC4_BASE (IO_BASE + 0x00270000)
+#define ECARD_IOC_BASE (IO_BASE + 0x00240000)
+#define IOMD_BASE (IO_BASE + 0x00200000)
+#define IOC_BASE (IO_BASE + 0x00200000)
+#define ECARD_MEMC8_BASE (IO_BASE + 0x0002b000)
+#define FLOPPYDMA_BASE (IO_BASE + 0x0002a000)
+#define PCIO_BASE (IO_BASE + 0x00010000)
+#define ECARD_MEMC_BASE (IO_BASE + 0x00000000)
#define vidc_writel(val) __raw_writel(val, VIDC_BASE)
-#define IO_EC_EASI_BASE 0x81400000
-#define IO_EC_IOC4_BASE 0x8009c000
-#define IO_EC_IOC_BASE 0x80090000
-#define IO_EC_MEMC8_BASE 0x8000ac00
-#define IO_EC_MEMC_BASE 0x80000000
-
#define NETSLOT_BASE 0x0302b000
#define NETSLOT_SIZE 0x00001000
diff --git a/arch/arm/mach-rpc/include/mach/io.h b/arch/arm/mach-rpc/include/mach/io.h
index 20da7f486e5..707071a7ea4 100644
--- a/arch/arm/mach-rpc/include/mach/io.h
+++ b/arch/arm/mach-rpc/include/mach/io.h
@@ -15,199 +15,17 @@
#include <mach/hardware.h>
-#define IO_SPACE_LIMIT 0xffffffff
+#define IO_SPACE_LIMIT 0xffff
/*
- * We use two different types of addressing - PC style addresses, and ARM
- * addresses. PC style accesses the PC hardware with the normal PC IO
- * addresses, eg 0x3f8 for serial#1. ARM addresses are 0x80000000+
- * and are translated to the start of IO. Note that all addresses are
- * shifted left!
- */
-#define __PORT_PCIO(x) (!((x) & 0x80000000))
-
-/*
- * Dynamic IO functions.
- */
-static inline void __outb (unsigned int value, unsigned int port)
-{
- unsigned long temp;
- __asm__ __volatile__(
- "tst %2, #0x80000000\n\t"
- "mov %0, %4\n\t"
- "addeq %0, %0, %3\n\t"
- "strb %1, [%0, %2, lsl #2] @ outb"
- : "=&r" (temp)
- : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
- : "cc");
-}
-
-static inline void __outw (unsigned int value, unsigned int port)
-{
- unsigned long temp;
- __asm__ __volatile__(
- "tst %2, #0x80000000\n\t"
- "mov %0, %4\n\t"
- "addeq %0, %0, %3\n\t"
- "str %1, [%0, %2, lsl #2] @ outw"
- : "=&r" (temp)
- : "r" (value|value<<16), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
- : "cc");
-}
-
-static inline void __outl (unsigned int value, unsigned int port)
-{
- unsigned long temp;
- __asm__ __volatile__(
- "tst %2, #0x80000000\n\t"
- "mov %0, %4\n\t"
- "addeq %0, %0, %3\n\t"
- "str %1, [%0, %2, lsl #2] @ outl"
- : "=&r" (temp)
- : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE)
- : "cc");
-}
-
-#define DECLARE_DYN_IN(sz,fnsuffix,instr) \
-static inline unsigned sz __in##fnsuffix (unsigned int port) \
-{ \
- unsigned long temp, value; \
- __asm__ __volatile__( \
- "tst %2, #0x80000000\n\t" \
- "mov %0, %4\n\t" \
- "addeq %0, %0, %3\n\t" \
- "ldr" instr " %1, [%0, %2, lsl #2] @ in" #fnsuffix \
- : "=&r" (temp), "=r" (value) \
- : "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE) \
- : "cc"); \
- return (unsigned sz)value; \
-}
-
-static inline void __iomem *__deprecated __ioaddr(unsigned int port)
-{
- void __iomem *ret;
- if (__PORT_PCIO(port))
- ret = PCIO_BASE;
- else
- ret = IO_BASE;
- return ret + (port << 2);
-}
-
-#define DECLARE_IO(sz,fnsuffix,instr) \
- DECLARE_DYN_IN(sz,fnsuffix,instr)
-
-DECLARE_IO(char,b,"b")
-DECLARE_IO(short,w,"")
-DECLARE_IO(int,l,"")
-
-#undef DECLARE_IO
-#undef DECLARE_DYN_IN
-
-/*
- * Constant address IO functions
+ * We need PC style IO addressing for:
+ * - floppy (at 0x3f2,0x3f4,0x3f5,0x3f7)
+ * - parport (at 0x278-0x27a, 0x27b-0x27f, 0x778-0x77a)
+ * - 8250 serial (only for compile)
*
- * These have to be macros for the 'J' constraint to work -
- * +/-4096 immediate operand.
- */
-#define __outbc(value,port) \
-({ \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "strb %0, [%1, %2] @ outbc" \
- : : "r" (value), "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "strb %0, [%1, %2] @ outbc" \
- : : "r" (value), "r" (IO_BASE), "r" ((port) << 2)); \
-})
-
-#define __inbc(port) \
-({ \
- unsigned char result; \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "ldrb %0, [%1, %2] @ inbc" \
- : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "ldrb %0, [%1, %2] @ inbc" \
- : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \
- result; \
-})
-
-#define __outwc(value,port) \
-({ \
- unsigned long __v = value; \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "str %0, [%1, %2] @ outwc" \
- : : "r" (__v|__v<<16), "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "str %0, [%1, %2] @ outwc" \
- : : "r" (__v|__v<<16), "r" (IO_BASE), "r" ((port) << 2)); \
-})
-
-#define __inwc(port) \
-({ \
- unsigned short result; \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "ldr %0, [%1, %2] @ inwc" \
- : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "ldr %0, [%1, %2] @ inwc" \
- : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \
- result & 0xffff; \
-})
-
-#define __outlc(value,port) \
-({ \
- unsigned long __v = value; \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "str %0, [%1, %2] @ outlc" \
- : : "r" (__v), "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "str %0, [%1, %2] @ outlc" \
- : : "r" (__v), "r" (IO_BASE), "r" ((port) << 2)); \
-})
-
-#define __inlc(port) \
-({ \
- unsigned long result; \
- if (__PORT_PCIO((port))) \
- __asm__ __volatile__( \
- "ldr %0, [%1, %2] @ inlc" \
- : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \
- else \
- __asm__ __volatile__( \
- "ldr %0, [%1, %2] @ inlc" \
- : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \
- result; \
-})
-
-#define inb(p) (__builtin_constant_p((p)) ? __inbc(p) : __inb(p))
-#define inw(p) (__builtin_constant_p((p)) ? __inwc(p) : __inw(p))
-#define inl(p) (__builtin_constant_p((p)) ? __inlc(p) : __inl(p))
-#define outb(v,p) (__builtin_constant_p((p)) ? __outbc(v,p) : __outb(v,p))
-#define outw(v,p) (__builtin_constant_p((p)) ? __outwc(v,p) : __outw(v,p))
-#define outl(v,p) (__builtin_constant_p((p)) ? __outlc(v,p) : __outl(v,p))
-
-/* the following macro is deprecated */
-#define ioaddr(port) ((unsigned long)__ioaddr((port)))
-
-#define insb(p,d,l) __raw_readsb(__ioaddr(p),d,l)
-#define insw(p,d,l) __raw_readsw(__ioaddr(p),d,l)
-
-#define outsb(p,d,l) __raw_writesb(__ioaddr(p),d,l)
-#define outsw(p,d,l) __raw_writesw(__ioaddr(p),d,l)
-
-/*
- * 1:1 mapping for ioremapped regions.
+ * These peripherals are found in an area of MMIO which looks very much
+ * like an ISA bus, but with registers at the low byte of each word.
*/
-#define __mem_pci(x) (x)
+#define __io(a) (PCIO_BASE + ((a) << 2))
#endif
diff --git a/arch/arm/mach-rpc/include/mach/irqs.h b/arch/arm/mach-rpc/include/mach/irqs.h
index 3d2037496e3..6868e178274 100644
--- a/arch/arm/mach-rpc/include/mach/irqs.h
+++ b/arch/arm/mach-rpc/include/mach/irqs.h
@@ -42,6 +42,4 @@
*/
#define FIQ_START 64
-#define IRQ_TIMER IRQ_TIMER0
-
#define NR_IRQS 128
diff --git a/arch/arm/mach-rpc/include/mach/memory.h b/arch/arm/mach-rpc/include/mach/memory.h
index 78191bf2519..18a221093bf 100644
--- a/arch/arm/mach-rpc/include/mach/memory.h
+++ b/arch/arm/mach-rpc/include/mach/memory.h
@@ -21,7 +21,7 @@
/*
* Physical DRAM offset.
*/
-#define PHYS_OFFSET UL(0x10000000)
+#define PLAT_PHYS_OFFSET UL(0x10000000)
/*
* Cache flushing area - ROM
diff --git a/arch/arm/mach-rpc/include/mach/system.h b/arch/arm/mach-rpc/include/mach/system.h
deleted file mode 100644
index 45c7b935dc4..00000000000
--- a/arch/arm/mach-rpc/include/mach/system.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * arch/arm/mach-rpc/include/mach/system.h
- *
- * Copyright (C) 1996-1999 Russell King.
- *
- * 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/io.h>
-#include <mach/hardware.h>
-#include <asm/hardware/iomd.h>
-
-static inline void arch_idle(void)
-{
- cpu_do_idle();
-}
-
-static inline void arch_reset(char mode, const char *cmd)
-{
- iomd_writeb(0, IOMD_ROMCR0);
-
- /*
- * Jump into the ROM
- */
- cpu_reset(0);
-}
diff --git a/arch/arm/mach-rpc/include/mach/timex.h b/arch/arm/mach-rpc/include/mach/timex.h
deleted file mode 100644
index dd75e7387bb..00000000000
--- a/arch/arm/mach-rpc/include/mach/timex.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * arch/arm/mach-rpc/include/mach/timex.h
- *
- * Copyright (C) 1997, 1998 Russell King
- *
- * 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.
- *
- * RiscPC architecture timex specifications
- */
-
-/*
- * On the RiscPC, the clock ticks at 2MHz.
- */
-#define CLOCK_TICK_RATE 2000000
-
diff --git a/arch/arm/mach-rpc/include/mach/uncompress.h b/arch/arm/mach-rpc/include/mach/uncompress.h
index 8c9e2c7161c..0fd4b0b8ef2 100644
--- a/arch/arm/mach-rpc/include/mach/uncompress.h
+++ b/arch/arm/mach-rpc/include/mach/uncompress.h
@@ -66,12 +66,12 @@ extern __attribute__((pure)) struct param_struct *params(void);
#define params (params())
#ifndef STANDALONE_DEBUG
-static unsigned long video_num_cols;
-static unsigned long video_num_rows;
-static unsigned long video_x;
-static unsigned long video_y;
-static unsigned char bytes_per_char_v;
-static int white;
+unsigned long video_num_cols;
+unsigned long video_num_rows;
+unsigned long video_x;
+unsigned long video_y;
+unsigned char bytes_per_char_v;
+int white;
/*
* This does not append a newline
@@ -189,8 +189,3 @@ static void arch_decomp_setup(void)
if (nr_pages * page_size < 4096*1024) error("<4M of mem\n");
}
#endif
-
-/*
- * nothing to do
- */
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-rpc/include/mach/vmalloc.h b/arch/arm/mach-rpc/include/mach/vmalloc.h
deleted file mode 100644
index 3bcd86fadb8..00000000000
--- a/arch/arm/mach-rpc/include/mach/vmalloc.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * arch/arm/mach-rpc/include/mach/vmalloc.h
- *
- * Copyright (C) 1997 Russell King
- *
- * 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.
- */
-#define VMALLOC_END 0xdc000000
diff --git a/arch/arm/mach-rpc/irq.c b/arch/arm/mach-rpc/irq.c
index 9dd15d679c5..3e4fa849c64 100644
--- a/arch/arm/mach-rpc/irq.c
+++ b/arch/arm/mach-rpc/irq.c
@@ -5,113 +5,116 @@
#include <asm/mach/irq.h>
#include <asm/hardware/iomd.h>
#include <asm/irq.h>
+#include <asm/fiq.h>
-static void iomd_ack_irq_a(unsigned int irq)
+static void iomd_ack_irq_a(struct irq_data *d)
{
unsigned int val, mask;
- mask = 1 << irq;
+ mask = 1 << d->irq;
val = iomd_readb(IOMD_IRQMASKA);
iomd_writeb(val & ~mask, IOMD_IRQMASKA);
iomd_writeb(mask, IOMD_IRQCLRA);
}
-static void iomd_mask_irq_a(unsigned int irq)
+static void iomd_mask_irq_a(struct irq_data *d)
{
unsigned int val, mask;
- mask = 1 << irq;
+ mask = 1 << d->irq;
val = iomd_readb(IOMD_IRQMASKA);
iomd_writeb(val & ~mask, IOMD_IRQMASKA);
}
-static void iomd_unmask_irq_a(unsigned int irq)
+static void iomd_unmask_irq_a(struct irq_data *d)
{
unsigned int val, mask;
- mask = 1 << irq;
+ mask = 1 << d->irq;
val = iomd_readb(IOMD_IRQMASKA);
iomd_writeb(val | mask, IOMD_IRQMASKA);
}
static struct irq_chip iomd_a_chip = {
- .ack = iomd_ack_irq_a,
- .mask = iomd_mask_irq_a,
- .unmask = iomd_unmask_irq_a,
+ .irq_ack = iomd_ack_irq_a,
+ .irq_mask = iomd_mask_irq_a,
+ .irq_unmask = iomd_unmask_irq_a,
};
-static void iomd_mask_irq_b(unsigned int irq)
+static void iomd_mask_irq_b(struct irq_data *d)
{
unsigned int val, mask;
- mask = 1 << (irq & 7);
+ mask = 1 << (d->irq & 7);
val = iomd_readb(IOMD_IRQMASKB);
iomd_writeb(val & ~mask, IOMD_IRQMASKB);
}
-static void iomd_unmask_irq_b(unsigned int irq)
+static void iomd_unmask_irq_b(struct irq_data *d)
{
unsigned int val, mask;
- mask = 1 << (irq & 7);
+ mask = 1 << (d->irq & 7);
val = iomd_readb(IOMD_IRQMASKB);
iomd_writeb(val | mask, IOMD_IRQMASKB);
}
static struct irq_chip iomd_b_chip = {
- .ack = iomd_mask_irq_b,
- .mask = iomd_mask_irq_b,
- .unmask = iomd_unmask_irq_b,
+ .irq_ack = iomd_mask_irq_b,
+ .irq_mask = iomd_mask_irq_b,
+ .irq_unmask = iomd_unmask_irq_b,
};
-static void iomd_mask_irq_dma(unsigned int irq)
+static void iomd_mask_irq_dma(struct irq_data *d)
{
unsigned int val, mask;
- mask = 1 << (irq & 7);
+ mask = 1 << (d->irq & 7);
val = iomd_readb(IOMD_DMAMASK);
iomd_writeb(val & ~mask, IOMD_DMAMASK);
}
-static void iomd_unmask_irq_dma(unsigned int irq)
+static void iomd_unmask_irq_dma(struct irq_data *d)
{
unsigned int val, mask;
- mask = 1 << (irq & 7);
+ mask = 1 << (d->irq & 7);
val = iomd_readb(IOMD_DMAMASK);
iomd_writeb(val | mask, IOMD_DMAMASK);
}
static struct irq_chip iomd_dma_chip = {
- .ack = iomd_mask_irq_dma,
- .mask = iomd_mask_irq_dma,
- .unmask = iomd_unmask_irq_dma,
+ .irq_ack = iomd_mask_irq_dma,
+ .irq_mask = iomd_mask_irq_dma,
+ .irq_unmask = iomd_unmask_irq_dma,
};
-static void iomd_mask_irq_fiq(unsigned int irq)
+static void iomd_mask_irq_fiq(struct irq_data *d)
{
unsigned int val, mask;
- mask = 1 << (irq & 7);
+ mask = 1 << (d->irq & 7);
val = iomd_readb(IOMD_FIQMASK);
iomd_writeb(val & ~mask, IOMD_FIQMASK);
}
-static void iomd_unmask_irq_fiq(unsigned int irq)
+static void iomd_unmask_irq_fiq(struct irq_data *d)
{
unsigned int val, mask;
- mask = 1 << (irq & 7);
+ mask = 1 << (d->irq & 7);
val = iomd_readb(IOMD_FIQMASK);
iomd_writeb(val | mask, IOMD_FIQMASK);
}
static struct irq_chip iomd_fiq_chip = {
- .ack = iomd_mask_irq_fiq,
- .mask = iomd_mask_irq_fiq,
- .unmask = iomd_unmask_irq_fiq,
+ .irq_ack = iomd_mask_irq_fiq,
+ .irq_mask = iomd_mask_irq_fiq,
+ .irq_unmask = iomd_unmask_irq_fiq,
};
+extern unsigned char rpc_default_fiq_start, rpc_default_fiq_end;
+
void __init rpc_init_irq(void)
{
unsigned int irq, flags;
@@ -121,6 +124,9 @@ void __init rpc_init_irq(void)
iomd_writeb(0, IOMD_FIQMASK);
iomd_writeb(0, IOMD_DMAMASK);
+ set_fiq_handler(&rpc_default_fiq_start,
+ &rpc_default_fiq_end - &rpc_default_fiq_start);
+
for (irq = 0; irq < NR_IRQS; irq++) {
flags = IRQF_VALID;
@@ -133,30 +139,30 @@ void __init rpc_init_irq(void)
switch (irq) {
case 0 ... 7:
- set_irq_chip(irq, &iomd_a_chip);
- set_irq_handler(irq, handle_level_irq);
+ irq_set_chip_and_handler(irq, &iomd_a_chip,
+ handle_level_irq);
set_irq_flags(irq, flags);
break;
case 8 ... 15:
- set_irq_chip(irq, &iomd_b_chip);
- set_irq_handler(irq, handle_level_irq);
+ irq_set_chip_and_handler(irq, &iomd_b_chip,
+ handle_level_irq);
set_irq_flags(irq, flags);
break;
case 16 ... 21:
- set_irq_chip(irq, &iomd_dma_chip);
- set_irq_handler(irq, handle_level_irq);
+ irq_set_chip_and_handler(irq, &iomd_dma_chip,
+ handle_level_irq);
set_irq_flags(irq, flags);
break;
case 64 ... 71:
- set_irq_chip(irq, &iomd_fiq_chip);
+ irq_set_chip(irq, &iomd_fiq_chip);
set_irq_flags(irq, IRQF_VALID);
break;
}
}
- init_FIQ();
+ init_FIQ(FIQ_START);
}
diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c
index 580b3c73d2c..09d602b10d5 100644
--- a/arch/arm/mach-rpc/riscpc.c
+++ b/arch/arm/mach-rpc/riscpc.c
@@ -20,13 +20,16 @@
#include <linux/ata_platform.h>
#include <linux/io.h>
#include <linux/i2c.h>
+#include <linux/reboot.h>
#include <asm/elf.h>
#include <asm/mach-types.h>
#include <mach/hardware.h>
+#include <asm/hardware/iomd.h>
#include <asm/page.h>
#include <asm/domain.h>
#include <asm/setup.h>
+#include <asm/system_misc.h>
#include <asm/mach/map.h>
#include <asm/mach/arch.h>
@@ -74,7 +77,7 @@ static struct map_desc rpc_io_desc[] __initdata = {
.length = IO_SIZE ,
.type = MT_DEVICE
}, { /* EASI space */
- .virtual = EASI_BASE,
+ .virtual = (unsigned long)EASI_BASE,
.pfn = __phys_to_pfn(EASI_START),
.length = EASI_SIZE,
.type = MT_DEVICE
@@ -97,15 +100,9 @@ static void __init rpc_map_io(void)
}
static struct resource acornfb_resources[] = {
- { /* VIDC */
- .start = 0x03400000,
- .end = 0x035fffff,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_VSYNCPULSE,
- .end = IRQ_VSYNCPULSE,
- .flags = IORESOURCE_IRQ,
- },
+ /* VIDC */
+ DEFINE_RES_MEM(0x03400000, 0x00200000),
+ DEFINE_RES_IRQ(IRQ_VSYNCPULSE),
};
static struct platform_device acornfb_device = {
@@ -119,11 +116,7 @@ static struct platform_device acornfb_device = {
};
static struct resource iomd_resources[] = {
- {
- .start = 0x03200000,
- .end = 0x0320ffff,
- .flags = IORESOURCE_MEM,
- },
+ DEFINE_RES_MEM(0x03200000, 0x10000),
};
static struct platform_device iomd_device = {
@@ -133,18 +126,25 @@ static struct platform_device iomd_device = {
.resource = iomd_resources,
};
+static struct resource iomd_kart_resources[] = {
+ DEFINE_RES_IRQ(IRQ_KEYBOARDRX),
+ DEFINE_RES_IRQ(IRQ_KEYBOARDTX),
+};
+
static struct platform_device kbd_device = {
.name = "kart",
.id = -1,
.dev = {
.parent = &iomd_device.dev,
},
+ .num_resources = ARRAY_SIZE(iomd_kart_resources),
+ .resource = iomd_kart_resources,
};
static struct plat_serial8250_port serial_platform_data[] = {
{
.mapbase = 0x03010fe0,
- .irq = 10,
+ .irq = IRQ_SERIALPORT,
.uartclk = 1843200,
.regshift = 2,
.iotype = UPIO_MEM,
@@ -166,21 +166,9 @@ static struct pata_platform_info pata_platform_data = {
};
static struct resource pata_resources[] = {
- [0] = {
- .start = 0x030107c0,
- .end = 0x030107df,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = 0x03010fd8,
- .end = 0x03010fdb,
- .flags = IORESOURCE_MEM,
- },
- [2] = {
- .start = IRQ_HARDDISK,
- .end = IRQ_HARDDISK,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_MEM(0x030107c0, 0x20),
+ DEFINE_RES_MEM(0x03010fd8, 0x04),
+ DEFINE_RES_IRQ(IRQ_HARDDISK),
};
static struct platform_device pata_device = {
@@ -214,14 +202,25 @@ static int __init rpc_init(void)
arch_initcall(rpc_init);
-extern struct sys_timer ioc_timer;
+static void rpc_restart(enum reboot_mode mode, const char *cmd)
+{
+ iomd_writeb(0, IOMD_ROMCR0);
+
+ /*
+ * Jump into the ROM
+ */
+ soft_restart(0);
+}
+
+void ioc_timer_init(void);
MACHINE_START(RISCPC, "Acorn-RiscPC")
/* Maintainer: Russell King */
- .boot_params = 0x10000100,
+ .atag_offset = 0x100,
.reserve_lp0 = 1,
.reserve_lp1 = 1,
.map_io = rpc_map_io,
.init_irq = rpc_init_irq,
- .timer = &ioc_timer,
+ .init_time = ioc_timer_init,
+ .restart = rpc_restart,
MACHINE_END
diff --git a/arch/arm/mach-rpc/time.c b/arch/arm/mach-rpc/time.c
new file mode 100644
index 00000000000..2689771c1d3
--- /dev/null
+++ b/arch/arm/mach-rpc/time.c
@@ -0,0 +1,92 @@
+/*
+ * linux/arch/arm/common/time-acorn.c
+ *
+ * Copyright (c) 1996-2000 Russell King.
+ *
+ * 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.
+ *
+ * Changelog:
+ * 24-Sep-1996 RMK Created
+ * 10-Oct-1996 RMK Brought up to date with arch-sa110eval
+ * 04-Dec-1997 RMK Updated for new arch/arm/time.c
+ * 13=Jun-2004 DS Moved to arch/arm/common b/c shared w/CLPS7500
+ */
+#include <linux/timex.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/hardware/ioc.h>
+
+#include <asm/mach/time.h>
+
+#define RPC_CLOCK_FREQ 2000000
+#define RPC_LATCH DIV_ROUND_CLOSEST(RPC_CLOCK_FREQ, HZ)
+
+static u32 ioc_timer_gettimeoffset(void)
+{
+ unsigned int count1, count2, status;
+ long offset;
+
+ ioc_writeb (0, IOC_T0LATCH);
+ barrier ();
+ count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
+ barrier ();
+ status = ioc_readb(IOC_IRQREQA);
+ barrier ();
+ ioc_writeb (0, IOC_T0LATCH);
+ barrier ();
+ count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
+
+ offset = count2;
+ if (count2 < count1) {
+ /*
+ * We have not had an interrupt between reading count1
+ * and count2.
+ */
+ if (status & (1 << 5))
+ offset -= RPC_LATCH;
+ } else if (count2 > count1) {
+ /*
+ * We have just had another interrupt between reading
+ * count1 and count2.
+ */
+ offset -= RPC_LATCH;
+ }
+
+ offset = (RPC_LATCH - offset) * (tick_nsec / 1000);
+ return DIV_ROUND_CLOSEST(offset, RPC_LATCH) * 1000;
+}
+
+void __init ioctime_init(void)
+{
+ ioc_writeb(RPC_LATCH & 255, IOC_T0LTCHL);
+ ioc_writeb(RPC_LATCH >> 8, IOC_T0LTCHH);
+ ioc_writeb(0, IOC_T0GO);
+}
+
+static irqreturn_t
+ioc_timer_interrupt(int irq, void *dev_id)
+{
+ timer_tick();
+ return IRQ_HANDLED;
+}
+
+static struct irqaction ioc_timer_irq = {
+ .name = "timer",
+ .handler = ioc_timer_interrupt
+};
+
+/*
+ * Set up timer interrupt.
+ */
+void __init ioc_timer_init(void)
+{
+ arch_gettimeoffset = ioc_timer_gettimeoffset;
+ ioctime_init();
+ setup_irq(IRQ_TIMER0, &ioc_timer_irq);
+}