summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-ns9xxx
diff options
context:
space:
mode:
authorUwe Kleine-König <ukleinek@informatik.uni-freiburg.de>2007-02-16 15:36:55 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2007-02-17 20:05:45 +0000
commit9918cda52368ec3df5bb6bc1630ba8c070ad9fdd (patch)
tree4b0a6b5df2c8d5f27b3c945eaec0966d8bcf67d8 /arch/arm/mach-ns9xxx
parentae0a846e411dc0b568e8ccda584896310ee5f369 (diff)
downloadlinux-9918cda52368ec3df5bb6bc1630ba8c070ad9fdd.tar.gz
linux-9918cda52368ec3df5bb6bc1630ba8c070ad9fdd.tar.bz2
linux-9918cda52368ec3df5bb6bc1630ba8c070ad9fdd.zip
[ARM] 4210/1: base for new machine type "NetSilicon NS9360"
Signed-off-by: Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-ns9xxx')
-rw-r--r--arch/arm/mach-ns9xxx/Kconfig21
-rw-r--r--arch/arm/mach-ns9xxx/Makefile5
-rw-r--r--arch/arm/mach-ns9xxx/Makefile.boot2
-rw-r--r--arch/arm/mach-ns9xxx/board-a9m9750dev.c199
-rw-r--r--arch/arm/mach-ns9xxx/board-a9m9750dev.h15
-rw-r--r--arch/arm/mach-ns9xxx/generic.c42
-rw-r--r--arch/arm/mach-ns9xxx/generic.h19
-rw-r--r--arch/arm/mach-ns9xxx/irq.c94
-rw-r--r--arch/arm/mach-ns9xxx/mach-cc9p9360dev.c41
-rw-r--r--arch/arm/mach-ns9xxx/time.c88
10 files changed, 526 insertions, 0 deletions
diff --git a/arch/arm/mach-ns9xxx/Kconfig b/arch/arm/mach-ns9xxx/Kconfig
new file mode 100644
index 000000000000..8175ba92a2fa
--- /dev/null
+++ b/arch/arm/mach-ns9xxx/Kconfig
@@ -0,0 +1,21 @@
+if ARCH_NS9XXX
+
+menu "NS9xxx Implementations"
+
+config MACH_CC9P9360DEV
+ bool "Connect Core 9P 9360 on an A9M9750 Devboard"
+ select PROCESSOR_NS9360
+ select BOARD_A9M9750DEV
+ help
+ Say Y here if you are using the Digi Connect Core 9P 9360
+ on an A9M9750 Development Board.
+
+config PROCESSOR_NS9360
+ bool
+
+config BOARD_A9M9750DEV
+ bool
+
+endmenu
+
+endif
diff --git a/arch/arm/mach-ns9xxx/Makefile b/arch/arm/mach-ns9xxx/Makefile
new file mode 100644
index 000000000000..91e945f5e16d
--- /dev/null
+++ b/arch/arm/mach-ns9xxx/Makefile
@@ -0,0 +1,5 @@
+obj-y := irq.o time.o generic.o
+
+obj-$(CONFIG_MACH_CC9P9360DEV) += mach-cc9p9360dev.o
+
+obj-$(CONFIG_BOARD_A9M9750DEV) += board-a9m9750dev.o
diff --git a/arch/arm/mach-ns9xxx/Makefile.boot b/arch/arm/mach-ns9xxx/Makefile.boot
new file mode 100644
index 000000000000..75ed64e90fa4
--- /dev/null
+++ b/arch/arm/mach-ns9xxx/Makefile.boot
@@ -0,0 +1,2 @@
+zreladdr-y := 0x108000
+params_phys-y := 0x100
diff --git a/arch/arm/mach-ns9xxx/board-a9m9750dev.c b/arch/arm/mach-ns9xxx/board-a9m9750dev.c
new file mode 100644
index 000000000000..25289884a607
--- /dev/null
+++ b/arch/arm/mach-ns9xxx/board-a9m9750dev.c
@@ -0,0 +1,199 @@
+/*
+ * arch/arm/mach-ns9xxx/board-a9m9750dev.c
+ *
+ * Copyright (C) 2006,2007 by Digi International Inc.
+ * All rights reserved.
+ *
+ * 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/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/irq.h>
+
+#include <asm/mach/map.h>
+
+#include <asm/arch-ns9xxx/board.h>
+#include <asm/arch-ns9xxx/regs-sys.h>
+#include <asm/arch-ns9xxx/regs-mem.h>
+#include <asm/arch-ns9xxx/regs-bbu.h>
+#include <asm/arch-ns9xxx/regs-board-a9m9750dev.h>
+
+#include "board-a9m9750dev.h"
+
+static struct map_desc board_a9m9750dev_io_desc[] __initdata = {
+ { /* FPGA on CS0 */
+ .virtual = io_p2v(NS9XXX_CSxSTAT_PHYS(0)),
+ .pfn = __phys_to_pfn(NS9XXX_CSxSTAT_PHYS(0)),
+ .length = NS9XXX_CS0STAT_LENGTH,
+ .type = MT_DEVICE,
+ },
+};
+
+void __init board_a9m9750dev_map_io(void)
+{
+ iotable_init(board_a9m9750dev_io_desc,
+ ARRAY_SIZE(board_a9m9750dev_io_desc));
+}
+
+static void a9m9750dev_fpga_ack_irq(unsigned int irq)
+{
+ /* nothing */
+}
+
+static void a9m9750dev_fpga_mask_irq(unsigned int irq)
+{
+ FPGA_IER &= ~(1 << (irq - FPGA_IRQ(0)));
+}
+
+static void a9m9750dev_fpga_maskack_irq(unsigned int irq)
+{
+ a9m9750dev_fpga_mask_irq(irq);
+ a9m9750dev_fpga_ack_irq(irq);
+}
+
+static void a9m9750dev_fpga_unmask_irq(unsigned int irq)
+{
+ FPGA_IER |= 1 << (irq - FPGA_IRQ(0));
+}
+
+static struct irq_chip a9m9750dev_fpga_chip = {
+ .ack = a9m9750dev_fpga_ack_irq,
+ .mask = a9m9750dev_fpga_mask_irq,
+ .mask_ack = a9m9750dev_fpga_maskack_irq,
+ .unmask = a9m9750dev_fpga_unmask_irq,
+};
+
+static void a9m9750dev_fpga_demux_handler(unsigned int irq,
+ struct irq_desc *desc)
+{
+ int stat = FPGA_ISR;
+
+ while (stat != 0) {
+ int irqno = fls(stat) - 1;
+
+ stat &= ~(1 << irqno);
+
+ desc = irq_desc + FPGA_IRQ(irqno);
+
+ desc_handle_irq(irqno, desc);
+ }
+}
+
+void __init board_a9m9750dev_init_irq(void)
+{
+ u32 reg;
+ int i;
+
+ /*
+ * configure gpio for IRQ_EXT2
+ * use GPIO 11, because GPIO 32 is used for the LCD
+ */
+ /* XXX: proper GPIO handling */
+ BBU_GC(2) &= ~0x2000;
+
+ for (i = FPGA_IRQ(0); i <= FPGA_IRQ(7); ++i) {
+ set_irq_chip(i, &a9m9750dev_fpga_chip);
+ set_irq_handler(i, handle_level_irq);
+ set_irq_flags(i, IRQF_VALID);
+ }
+
+ /* IRQ_EXT2: level sensitive + active low */
+ reg = SYS_EIC(2);
+ REGSET(reg, SYS_EIC, PLTY, AL);
+ REGSET(reg, SYS_EIC, LVEDG, LEVEL);
+ SYS_EIC(2) = reg;
+
+ set_irq_chained_handler(IRQ_EXT2,
+ a9m9750dev_fpga_demux_handler);
+}
+
+static struct plat_serial8250_port board_a9m9750dev_serial8250_port[] = {
+ {
+ .iobase = FPGA_UARTA_BASE,
+ .membase = (unsigned char*)FPGA_UARTA_BASE,
+ .mapbase = FPGA_UARTA_BASE,
+ .irq = IRQ_FPGA_UARTA,
+ .iotype = UPIO_MEM,
+ .uartclk = 18432000,
+ .regshift = 0,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ,
+ }, {
+ .iobase = FPGA_UARTB_BASE,
+ .membase = (unsigned char*)FPGA_UARTB_BASE,
+ .mapbase = FPGA_UARTB_BASE,
+ .irq = IRQ_FPGA_UARTB,
+ .iotype = UPIO_MEM,
+ .uartclk = 18432000,
+ .regshift = 0,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ,
+ }, {
+ .iobase = FPGA_UARTC_BASE,
+ .membase = (unsigned char*)FPGA_UARTC_BASE,
+ .mapbase = FPGA_UARTC_BASE,
+ .irq = IRQ_FPGA_UARTC,
+ .iotype = UPIO_MEM,
+ .uartclk = 18432000,
+ .regshift = 0,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ,
+ }, {
+ .iobase = FPGA_UARTD_BASE,
+ .membase = (unsigned char*)FPGA_UARTD_BASE,
+ .mapbase = FPGA_UARTD_BASE,
+ .irq = IRQ_FPGA_UARTD,
+ .iotype = UPIO_MEM,
+ .uartclk = 18432000,
+ .regshift = 0,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ,
+ }, {
+ /* end marker */
+ },
+};
+
+static struct platform_device board_a9m9750dev_serial_device = {
+ .name = "serial8250",
+ .dev = {
+ .platform_data = board_a9m9750dev_serial8250_port,
+ },
+};
+
+static struct platform_device *board_a9m9750dev_devices[] __initdata = {
+ &board_a9m9750dev_serial_device,
+};
+
+void __init board_a9m9750dev_init_machine(void)
+{
+ u32 reg;
+
+ /* setup static CS0: memory base ... */
+ REGSETIM(SYS_SMCSSMB(0), SYS_SMCSSMB, CSxB,
+ NS9XXX_CSxSTAT_PHYS(0) >> 12);
+
+ /* ... and mask */
+ reg = SYS_SMCSSMM(0);
+ REGSETIM(reg, SYS_SMCSSMM, CSxM, 0xfffff);
+ REGSET(reg, SYS_SMCSSMM, CSEx, EN);
+ SYS_SMCSSMM(0) = reg;
+
+ /* setup static CS0: memory configuration */
+ reg = MEM_SMC(0);
+ REGSET(reg, MEM_SMC, WSMC, OFF);
+ REGSET(reg, MEM_SMC, BSMC, OFF);
+ REGSET(reg, MEM_SMC, EW, OFF);
+ REGSET(reg, MEM_SMC, PB, 1);
+ REGSET(reg, MEM_SMC, PC, AL);
+ REGSET(reg, MEM_SMC, PM, DIS);
+ REGSET(reg, MEM_SMC, MW, 8);
+ MEM_SMC(0) = reg;
+
+ /* setup static CS0: timing */
+ MEM_SMWED(0) = 0x2;
+ MEM_SMOED(0) = 0x2;
+ MEM_SMRD(0) = 0x6;
+ MEM_SMWD(0) = 0x6;
+
+ platform_add_devices(board_a9m9750dev_devices,
+ ARRAY_SIZE(board_a9m9750dev_devices));
+}
+
diff --git a/arch/arm/mach-ns9xxx/board-a9m9750dev.h b/arch/arm/mach-ns9xxx/board-a9m9750dev.h
new file mode 100644
index 000000000000..edc75abbc5dd
--- /dev/null
+++ b/arch/arm/mach-ns9xxx/board-a9m9750dev.h
@@ -0,0 +1,15 @@
+/*
+ * arch/arm/mach-ns9xxx/board-a9m9750dev.h
+ *
+ * Copyright (C) 2006 by Digi International Inc.
+ * All rights reserved.
+ *
+ * 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>
+
+void __init board_a9m9750dev_map_io(void);
+void __init board_a9m9750dev_init_machine(void);
+void __init board_a9m9750dev_init_irq(void);
diff --git a/arch/arm/mach-ns9xxx/generic.c b/arch/arm/mach-ns9xxx/generic.c
new file mode 100644
index 000000000000..83e2b6532b22
--- /dev/null
+++ b/arch/arm/mach-ns9xxx/generic.c
@@ -0,0 +1,42 @@
+/*
+ * arch/arm/mach-ns9xxx/generic.c
+ *
+ * Copyright (C) 2006 by Digi International Inc.
+ * All rights reserved.
+ *
+ * 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/init.h>
+#include <asm/memory.h>
+#include <asm/page.h>
+#include <asm/mach-types.h>
+#include <asm/mach/map.h>
+#include <asm/arch-ns9xxx/regs-sys.h>
+#include <asm/arch-ns9xxx/regs-mem.h>
+#include <asm/arch-ns9xxx/board.h>
+
+static struct map_desc standard_io_desc[] __initdata = {
+ { /* BBus */
+ .virtual = io_p2v(0x90000000),
+ .pfn = __phys_to_pfn(0x90000000),
+ .length = 0x00700000,
+ .type = MT_DEVICE,
+ }, { /* AHB */
+ .virtual = io_p2v(0xa0100000),
+ .pfn = __phys_to_pfn(0xa0100000),
+ .length = 0x00900000,
+ .type = MT_DEVICE,
+ },
+};
+
+void __init ns9xxx_map_io(void)
+{
+ iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
+}
+
+void __init ns9xxx_init_machine(void)
+{
+}
diff --git a/arch/arm/mach-ns9xxx/generic.h b/arch/arm/mach-ns9xxx/generic.h
new file mode 100644
index 000000000000..687e291773f4
--- /dev/null
+++ b/arch/arm/mach-ns9xxx/generic.h
@@ -0,0 +1,19 @@
+/*
+ * arch/arm/mach-ns9xxx/generic.h
+ *
+ * Copyright (C) 2006 by Digi International Inc.
+ * All rights reserved.
+ *
+ * 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/time.h>
+#include <asm/mach/time.h>
+#include <linux/init.h>
+
+void __init ns9xxx_init_irq(void);
+void __init ns9xxx_map_io(void);
+void __init ns9xxx_init_machine(void);
+
+extern struct sys_timer ns9xxx_timer;
diff --git a/arch/arm/mach-ns9xxx/irq.c b/arch/arm/mach-ns9xxx/irq.c
new file mode 100644
index 000000000000..83d92724a971
--- /dev/null
+++ b/arch/arm/mach-ns9xxx/irq.c
@@ -0,0 +1,94 @@
+/*
+ * arch/arm/mach-ns9xxx/irq.c
+ *
+ * Copyright (C) 2006,2007 by Digi International Inc.
+ * All rights reserved.
+ *
+ * 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/interrupt.h>
+#include <asm/mach/irq.h>
+#include <asm/mach-types.h>
+#include <asm/arch-ns9xxx/regs-sys.h>
+#include <asm/arch-ns9xxx/irqs.h>
+#include <asm/arch-ns9xxx/board.h>
+
+#include "generic.h"
+
+static void ns9xxx_ack_irq_timer(unsigned int irq)
+{
+ u32 tc = SYS_TC(irq - IRQ_TIMER0);
+
+ REGSET(tc, SYS_TCx, INTC, SET);
+ SYS_TC(irq - IRQ_TIMER0) = tc;
+
+ REGSET(tc, SYS_TCx, INTC, UNSET);
+ SYS_TC(irq - IRQ_TIMER0) = tc;
+}
+
+void (*ns9xxx_ack_irq_functions[NR_IRQS])(unsigned int) = {
+ [IRQ_TIMER0] = ns9xxx_ack_irq_timer,
+ [IRQ_TIMER1] = ns9xxx_ack_irq_timer,
+ [IRQ_TIMER2] = ns9xxx_ack_irq_timer,
+ [IRQ_TIMER3] = ns9xxx_ack_irq_timer,
+};
+
+static void ns9xxx_mask_irq(unsigned int irq)
+{
+ /* XXX: better use cpp symbols */
+ SYS_IC(irq / 4) &= ~(1 << (7 + 8 * (3 - (irq & 3))));
+}
+
+static void ns9xxx_ack_irq(unsigned int irq)
+{
+ if (!ns9xxx_ack_irq_functions[irq]) {
+ printk(KERN_ERR "no ack function for irq %u\n", irq);
+ BUG();
+ }
+
+ ns9xxx_ack_irq_functions[irq](irq);
+ SYS_ISRADDR = 0;
+}
+
+static void ns9xxx_maskack_irq(unsigned int irq)
+{
+ ns9xxx_mask_irq(irq);
+ ns9xxx_ack_irq(irq);
+}
+
+static void ns9xxx_unmask_irq(unsigned int irq)
+{
+ /* XXX: better use cpp symbols */
+ SYS_IC(irq / 4) |= 1 << (7 + 8 * (3 - (irq & 3)));
+}
+
+static struct irq_chip ns9xxx_chip = {
+ .ack = ns9xxx_ack_irq,
+ .mask = ns9xxx_mask_irq,
+ .mask_ack = ns9xxx_maskack_irq,
+ .unmask = ns9xxx_unmask_irq,
+};
+
+void __init ns9xxx_init_irq(void)
+{
+ int i;
+
+ /* disable all IRQs */
+ for (i = 0; i < 8; ++i)
+ SYS_IC(i) = (4 * i) << 24 | (4 * i + 1) << 16 |
+ (4 * i + 2) << 8 | (4 * i + 3);
+
+ /* simple interrupt prio table:
+ * prio(x) < prio(y) <=> x < y
+ */
+ for (i = 0; i < 32; ++i)
+ SYS_IVA(i) = i;
+
+ for (i = IRQ_WATCHDOG; i <= IRQ_EXT3; ++i) {
+ set_irq_chip(i, &ns9xxx_chip);
+ set_irq_handler(i, handle_level_irq);
+ set_irq_flags(i, IRQF_VALID);
+ }
+}
diff --git a/arch/arm/mach-ns9xxx/mach-cc9p9360dev.c b/arch/arm/mach-ns9xxx/mach-cc9p9360dev.c
new file mode 100644
index 000000000000..a193dd931512
--- /dev/null
+++ b/arch/arm/mach-ns9xxx/mach-cc9p9360dev.c
@@ -0,0 +1,41 @@
+/*
+ * arch/arm/mach-ns9xxx/mach-cc9p9360dev.c
+ *
+ * Copyright (C) 2006 by Digi International Inc.
+ * All rights reserved.
+ *
+ * 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 <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include "board-a9m9750dev.h"
+#include "generic.h"
+
+static void __init mach_cc9p9360dev_map_io(void)
+{
+ ns9xxx_map_io();
+ board_a9m9750dev_map_io();
+}
+
+static void __init mach_cc9p9360dev_init_irq(void)
+{
+ ns9xxx_init_irq();
+ board_a9m9750dev_init_irq();
+}
+
+static void __init mach_cc9p9360dev_init_machine(void)
+{
+ ns9xxx_init_machine();
+ board_a9m9750dev_init_machine();
+}
+
+MACHINE_START(CC9P9360DEV, "Connect Core 9P 9360 on an A9M9750 Devboard")
+ .map_io = mach_cc9p9360dev_map_io,
+ .init_irq = mach_cc9p9360dev_init_irq,
+ .init_machine = mach_cc9p9360dev_init_machine,
+ .timer = &ns9xxx_timer,
+ .boot_params = 0x100,
+MACHINE_END
diff --git a/arch/arm/mach-ns9xxx/time.c b/arch/arm/mach-ns9xxx/time.c
new file mode 100644
index 000000000000..eec05f18714a
--- /dev/null
+++ b/arch/arm/mach-ns9xxx/time.c
@@ -0,0 +1,88 @@
+/*
+ * arch/arm/mach-ns9xxx/time.c
+ *
+ * Copyright (C) 2006 by Digi International Inc.
+ * All rights reserved.
+ *
+ * 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/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <asm/arch-ns9xxx/regs-sys.h>
+#include <asm/arch-ns9xxx/clock.h>
+#include <asm/arch-ns9xxx/irqs.h>
+#include <asm/arch/system.h>
+#include "generic.h"
+
+#define TIMERCLOCKSELECT 64
+
+static u32 usecs_per_tick;
+
+static irqreturn_t
+ns9xxx_timer_interrupt(int irq, void *dev_id)
+{
+ write_seqlock(&xtime_lock);
+ timer_tick();
+ write_sequnlock(&xtime_lock);
+
+ return IRQ_HANDLED;
+}
+
+static unsigned long ns9xxx_timer_gettimeoffset(void)
+{
+ /* return the microseconds which have passed since the last interrupt
+ * was _serviced_. That is, if an interrupt is pending or the counter
+ * reloads, return one periode more. */
+
+ u32 counter1 = SYS_TR(0);
+ int pending = SYS_ISR & (1 << IRQ_TIMER0);
+ u32 counter2 = SYS_TR(0);
+ u32 elapsed;
+
+ if (pending || counter2 > counter1)
+ elapsed = 2 * SYS_TRC(0) - counter2;
+ else
+ elapsed = SYS_TRC(0) - counter1;
+
+ return (elapsed * usecs_per_tick) >> 16;
+
+}
+
+static struct irqaction ns9xxx_timer_irq = {
+ .name = "NS9xxx Timer Tick",
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .handler = ns9xxx_timer_interrupt,
+};
+
+static void __init ns9xxx_timer_init(void)
+{
+ int tc;
+
+ usecs_per_tick =
+ SH_DIV(1000000 * TIMERCLOCKSELECT, ns9xxx_cpuclock(), 16);
+
+ /* disable timer */
+ if ((tc = SYS_TC(0)) & SYS_TCx_TEN)
+ SYS_TC(0) = tc & ~SYS_TCx_TEN;
+
+ SYS_TRC(0) = SH_DIV(ns9xxx_cpuclock(), (TIMERCLOCKSELECT * HZ), 0);
+
+ REGSET(tc, SYS_TCx, TEN, EN);
+ REGSET(tc, SYS_TCx, TLCS, DIV64); /* This must match TIMERCLOCKSELECT */
+ REGSET(tc, SYS_TCx, INTS, EN);
+ REGSET(tc, SYS_TCx, UDS, DOWN);
+ REGSET(tc, SYS_TCx, TDBG, STOP);
+ REGSET(tc, SYS_TCx, TSZ, 32);
+ REGSET(tc, SYS_TCx, REN, EN);
+ SYS_TC(0) = tc;
+
+ setup_irq(IRQ_TIMER0, &ns9xxx_timer_irq);
+}
+
+struct sys_timer ns9xxx_timer = {
+ .init = ns9xxx_timer_init,
+ .offset = ns9xxx_timer_gettimeoffset,
+};