aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/boards
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/boards')
-rw-r--r--arch/sh/boards/adx/Makefile6
-rw-r--r--arch/sh/boards/adx/irq.c31
-rw-r--r--arch/sh/boards/adx/irq_maskreg.c107
-rw-r--r--arch/sh/boards/adx/setup.c56
-rw-r--r--arch/sh/boards/bigsur/Makefile6
-rw-r--r--arch/sh/boards/bigsur/io.c125
-rw-r--r--arch/sh/boards/bigsur/irq.c348
-rw-r--r--arch/sh/boards/bigsur/led.c55
-rw-r--r--arch/sh/boards/bigsur/setup.c96
-rw-r--r--arch/sh/boards/cat68701/Makefile6
-rw-r--r--arch/sh/boards/cat68701/irq.c28
-rw-r--r--arch/sh/boards/cat68701/setup.c86
-rw-r--r--arch/sh/boards/cqreek/Makefile6
-rw-r--r--arch/sh/boards/cqreek/irq.c128
-rw-r--r--arch/sh/boards/cqreek/setup.c101
-rw-r--r--arch/sh/boards/dmida/Makefile7
-rw-r--r--arch/sh/boards/dmida/mach.c59
-rw-r--r--arch/sh/boards/dreamcast/Makefile6
-rw-r--r--arch/sh/boards/dreamcast/irq.c160
-rw-r--r--arch/sh/boards/dreamcast/rtc.c81
-rw-r--r--arch/sh/boards/dreamcast/setup.c83
-rw-r--r--arch/sh/boards/ec3104/Makefile6
-rw-r--r--arch/sh/boards/ec3104/io.c81
-rw-r--r--arch/sh/boards/ec3104/irq.c196
-rw-r--r--arch/sh/boards/ec3104/setup.c78
-rw-r--r--arch/sh/boards/harp/Makefile8
-rw-r--r--arch/sh/boards/harp/irq.c148
-rw-r--r--arch/sh/boards/harp/led.c52
-rw-r--r--arch/sh/boards/harp/mach.c62
-rw-r--r--arch/sh/boards/harp/pcidma.c42
-rw-r--r--arch/sh/boards/harp/setup.c91
-rw-r--r--arch/sh/boards/hp6xx/hp620/Makefile6
-rw-r--r--arch/sh/boards/hp6xx/hp620/mach.c52
-rw-r--r--arch/sh/boards/hp6xx/hp620/setup.c45
-rw-r--r--arch/sh/boards/hp6xx/hp680/Makefile6
-rw-r--r--arch/sh/boards/hp6xx/hp680/mach.c53
-rw-r--r--arch/sh/boards/hp6xx/hp680/setup.c41
-rw-r--r--arch/sh/boards/hp6xx/hp690/Makefile6
-rw-r--r--arch/sh/boards/hp6xx/hp690/mach.c48
-rw-r--r--arch/sh/boards/mpc1211/Makefile8
-rw-r--r--arch/sh/boards/mpc1211/led.c64
-rw-r--r--arch/sh/boards/mpc1211/pci.c296
-rw-r--r--arch/sh/boards/mpc1211/rtc.c152
-rw-r--r--arch/sh/boards/mpc1211/setup.c360
-rw-r--r--arch/sh/boards/overdrive/Makefile8
-rw-r--r--arch/sh/boards/overdrive/fpga.c134
-rw-r--r--arch/sh/boards/overdrive/galileo.c588
-rw-r--r--arch/sh/boards/overdrive/io.c173
-rw-r--r--arch/sh/boards/overdrive/irq.c192
-rw-r--r--arch/sh/boards/overdrive/led.c59
-rw-r--r--arch/sh/boards/overdrive/mach.c62
-rw-r--r--arch/sh/boards/overdrive/pcidma.c46
-rw-r--r--arch/sh/boards/overdrive/setup.c41
-rw-r--r--arch/sh/boards/overdrive/time.c119
-rw-r--r--arch/sh/boards/renesas/edosk7705/Makefile10
-rw-r--r--arch/sh/boards/renesas/edosk7705/io.c94
-rw-r--r--arch/sh/boards/renesas/edosk7705/setup.c60
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/Makefile12
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/io.c310
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/irq.c122
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/led.c27
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/mach.c55
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/pci.c150
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/setup.c89
-rw-r--r--arch/sh/boards/renesas/rts7751r2d/Makefile10
-rw-r--r--arch/sh/boards/renesas/rts7751r2d/io.c319
-rw-r--r--arch/sh/boards/renesas/rts7751r2d/irq.c135
-rw-r--r--arch/sh/boards/renesas/rts7751r2d/led.c67
-rw-r--r--arch/sh/boards/renesas/rts7751r2d/mach.c70
-rw-r--r--arch/sh/boards/renesas/rts7751r2d/setup.c31
-rw-r--r--arch/sh/boards/renesas/systemh/Makefile13
-rw-r--r--arch/sh/boards/renesas/systemh/io.c283
-rw-r--r--arch/sh/boards/renesas/systemh/irq.c111
-rw-r--r--arch/sh/boards/renesas/systemh/setup.c80
-rw-r--r--arch/sh/boards/saturn/Makefile8
-rw-r--r--arch/sh/boards/saturn/io.c26
-rw-r--r--arch/sh/boards/saturn/irq.c118
-rw-r--r--arch/sh/boards/saturn/setup.c43
-rw-r--r--arch/sh/boards/saturn/smp.c68
-rw-r--r--arch/sh/boards/se/7300/Makefile7
-rw-r--r--arch/sh/boards/se/7300/io.c265
-rw-r--r--arch/sh/boards/se/7300/irq.c37
-rw-r--r--arch/sh/boards/se/7300/led.c69
-rw-r--r--arch/sh/boards/se/7300/setup.c66
-rw-r--r--arch/sh/boards/se/73180/Makefile7
-rw-r--r--arch/sh/boards/se/73180/io.c265
-rw-r--r--arch/sh/boards/se/73180/irq.c137
-rw-r--r--arch/sh/boards/se/73180/led.c67
-rw-r--r--arch/sh/boards/se/73180/setup.c68
-rw-r--r--arch/sh/boards/se/770x/Makefile6
-rw-r--r--arch/sh/boards/se/770x/io.c226
-rw-r--r--arch/sh/boards/se/770x/irq.c80
-rw-r--r--arch/sh/boards/se/770x/led.c68
-rw-r--r--arch/sh/boards/se/770x/mach.c68
-rw-r--r--arch/sh/boards/se/770x/setup.c85
-rw-r--r--arch/sh/boards/se/7751/Makefile8
-rw-r--r--arch/sh/boards/se/7751/io.c244
-rw-r--r--arch/sh/boards/se/7751/irq.c67
-rw-r--r--arch/sh/boards/se/7751/led.c68
-rw-r--r--arch/sh/boards/se/7751/mach.c55
-rw-r--r--arch/sh/boards/se/7751/pci.c148
-rw-r--r--arch/sh/boards/se/7751/setup.c228
-rw-r--r--arch/sh/boards/sh03/Makefile6
-rw-r--r--arch/sh/boards/sh03/led.c49
-rw-r--r--arch/sh/boards/sh03/rtc.c144
-rw-r--r--arch/sh/boards/sh03/setup.c72
-rw-r--r--arch/sh/boards/sh2000/Makefile6
-rw-r--r--arch/sh/boards/sh2000/setup.c71
-rw-r--r--arch/sh/boards/snapgear/Makefile6
-rw-r--r--arch/sh/boards/snapgear/io.c226
-rw-r--r--arch/sh/boards/snapgear/rtc.c333
-rw-r--r--arch/sh/boards/snapgear/setup.c216
-rw-r--r--arch/sh/boards/superh/microdev/Makefile8
-rw-r--r--arch/sh/boards/superh/microdev/io.c370
-rw-r--r--arch/sh/boards/superh/microdev/irq.c200
-rw-r--r--arch/sh/boards/superh/microdev/led.c102
-rw-r--r--arch/sh/boards/superh/microdev/setup.c278
-rw-r--r--arch/sh/boards/unknown/Makefile6
-rw-r--r--arch/sh/boards/unknown/io.c46
-rw-r--r--arch/sh/boards/unknown/mach.c67
-rw-r--r--arch/sh/boards/unknown/setup.c23
121 files changed, 11783 insertions, 0 deletions
diff --git a/arch/sh/boards/adx/Makefile b/arch/sh/boards/adx/Makefile
new file mode 100644
index 000000000000..5b1c531b3991
--- /dev/null
+++ b/arch/sh/boards/adx/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for ADX boards
+#
+
+obj-y := setup.o irq.o irq_maskreq.o
+
diff --git a/arch/sh/boards/adx/irq.c b/arch/sh/boards/adx/irq.c
new file mode 100644
index 000000000000..c6ca409dff98
--- /dev/null
+++ b/arch/sh/boards/adx/irq.c
@@ -0,0 +1,31 @@
+/*
+ * linux/arch/sh/boards/adx/irq.c
+ *
+ * Copyright (C) 2001 A&D Co., Ltd.
+ *
+ * I/O routine and setup routines for A&D ADX Board
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <asm/irq.h>
+
+void init_adx_IRQ(void)
+{
+ int i;
+
+/* printk("init_adx_IRQ()\n");*/
+ /* setup irq_mask_register */
+ irq_mask_register = (unsigned short *)0xa6000008;
+
+ /* cover all external interrupt area by maskreg_irq_type
+ * (Actually, irq15 doesn't exist)
+ */
+ for (i = 0; i < 16; i++) {
+ make_maskreg_irq(i);
+ disable_irq(i);
+ }
+}
diff --git a/arch/sh/boards/adx/irq_maskreg.c b/arch/sh/boards/adx/irq_maskreg.c
new file mode 100644
index 000000000000..ca91bb0f1f5c
--- /dev/null
+++ b/arch/sh/boards/adx/irq_maskreg.c
@@ -0,0 +1,107 @@
+/*
+ * linux/arch/sh/kernel/irq_maskreg.c
+ *
+ * Copyright (C) 2001 A&D Co., Ltd. <http://www.aandd.co.jp>
+ *
+ * This file may be copied or modified under the terms of the GNU
+ * General Public License. See linux/COPYING for more information.
+ *
+ * Interrupt handling for Simple external interrupt mask register
+ *
+ * This is for the machine which have single 16 bit register
+ * for masking external IRQ individually.
+ * Each bit of the register is for masking each interrupt.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/machvec.h>
+
+/* address of external interrupt mask register
+ * address must be set prior to use these (maybe in init_XXX_irq())
+ * XXX : is it better to use .config than specifying it in code? */
+unsigned short *irq_mask_register = 0;
+
+/* forward declaration */
+static unsigned int startup_maskreg_irq(unsigned int irq);
+static void shutdown_maskreg_irq(unsigned int irq);
+static void enable_maskreg_irq(unsigned int irq);
+static void disable_maskreg_irq(unsigned int irq);
+static void mask_and_ack_maskreg(unsigned int);
+static void end_maskreg_irq(unsigned int irq);
+
+/* hw_interrupt_type */
+static struct hw_interrupt_type maskreg_irq_type = {
+ " Mask Register",
+ startup_maskreg_irq,
+ shutdown_maskreg_irq,
+ enable_maskreg_irq,
+ disable_maskreg_irq,
+ mask_and_ack_maskreg,
+ end_maskreg_irq
+};
+
+/* actual implementatin */
+static unsigned int startup_maskreg_irq(unsigned int irq)
+{
+ enable_maskreg_irq(irq);
+ return 0; /* never anything pending */
+}
+
+static void shutdown_maskreg_irq(unsigned int irq)
+{
+ disable_maskreg_irq(irq);
+}
+
+static void disable_maskreg_irq(unsigned int irq)
+{
+ if (irq_mask_register) {
+ unsigned long flags;
+ unsigned short val, mask = 0x01 << irq;
+
+ /* Set "irq"th bit */
+ local_irq_save(flags);
+ val = ctrl_inw((unsigned long)irq_mask_register);
+ val |= mask;
+ ctrl_outw(val, (unsigned long)irq_mask_register);
+ local_irq_restore(flags);
+ }
+}
+
+static void enable_maskreg_irq(unsigned int irq)
+{
+ if (irq_mask_register) {
+ unsigned long flags;
+ unsigned short val, mask = ~(0x01 << irq);
+
+ /* Clear "irq"th bit */
+ local_irq_save(flags);
+ val = ctrl_inw((unsigned long)irq_mask_register);
+ val &= mask;
+ ctrl_outw(val, (unsigned long)irq_mask_register);
+ local_irq_restore(flags);
+ }
+}
+
+static void mask_and_ack_maskreg(unsigned int irq)
+{
+ disable_maskreg_irq(irq);
+}
+
+static void end_maskreg_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ enable_maskreg_irq(irq);
+}
+
+void make_maskreg_irq(unsigned int irq)
+{
+ disable_irq_nosync(irq);
+ irq_desc[irq].handler = &maskreg_irq_type;
+ disable_maskreg_irq(irq);
+}
diff --git a/arch/sh/boards/adx/setup.c b/arch/sh/boards/adx/setup.c
new file mode 100644
index 000000000000..4938d9592343
--- /dev/null
+++ b/arch/sh/boards/adx/setup.c
@@ -0,0 +1,56 @@
+/*
+ * linux/arch/sh/board/adx/setup.c
+ *
+ * Copyright (C) 2001 A&D Co., Ltd.
+ *
+ * I/O routine and setup routines for A&D ADX Board
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <asm/machvec.h>
+#include <linux/module.h>
+
+extern void init_adx_IRQ(void);
+extern void *cf_io_base;
+
+const char *get_system_type(void)
+{
+ return "A&D ADX";
+}
+
+unsigned long adx_isa_port2addr(unsigned long offset)
+{
+ /* CompactFlash (IDE) */
+ if (((offset >= 0x1f0) && (offset <= 0x1f7)) || (offset == 0x3f6)) {
+ return (unsigned long)cf_io_base + offset;
+ }
+
+ /* eth0 */
+ if ((offset >= 0x300) && (offset <= 0x30f)) {
+ return 0xa5000000 + offset; /* COMM BOARD (AREA1) */
+ }
+
+ return offset + 0xb0000000; /* IOBUS (AREA 4)*/
+}
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_adx __initmv = {
+ .mv_nr_irqs = 48,
+ .mv_isa_port2addr = adx_isa_port2addr,
+ .mv_init_irq = init_adx_IRQ,
+};
+ALIAS_MV(adx)
+
+int __init platform_setup(void)
+{
+ /* Nothing to see here .. */
+ return 0;
+}
+
diff --git a/arch/sh/boards/bigsur/Makefile b/arch/sh/boards/bigsur/Makefile
new file mode 100644
index 000000000000..0ff9497ac58e
--- /dev/null
+++ b/arch/sh/boards/bigsur/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the BigSur specific parts of the kernel
+#
+
+obj-y := setup.o io.o irq.o led.o
+
diff --git a/arch/sh/boards/bigsur/io.c b/arch/sh/boards/bigsur/io.c
new file mode 100644
index 000000000000..697144de7419
--- /dev/null
+++ b/arch/sh/boards/bigsur/io.c
@@ -0,0 +1,125 @@
+/*
+ * include/asm-sh/io_bigsur.c
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+ * Derived from io_hd64465.h, which bore the message:
+ * By Greg Banks <gbanks@pocketpenguins.com>
+ * (c) 2000 PocketPenguins Inc.
+ * and from io_hd64461.h, which bore the message:
+ * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * IO functions for a Hitachi Big Sur Evaluation Board.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/machvec.h>
+#include <asm/io.h>
+#include <asm/bigsur/bigsur.h>
+
+/* Low iomap maps port 0-1K to addresses in 8byte chunks */
+#define BIGSUR_IOMAP_LO_THRESH 0x400
+#define BIGSUR_IOMAP_LO_SHIFT 3
+#define BIGSUR_IOMAP_LO_MASK ((1<<BIGSUR_IOMAP_LO_SHIFT)-1)
+#define BIGSUR_IOMAP_LO_NMAP (BIGSUR_IOMAP_LO_THRESH>>BIGSUR_IOMAP_LO_SHIFT)
+static u32 bigsur_iomap_lo[BIGSUR_IOMAP_LO_NMAP];
+static u8 bigsur_iomap_lo_shift[BIGSUR_IOMAP_LO_NMAP];
+
+/* High iomap maps port 1K-64K to addresses in 1K chunks */
+#define BIGSUR_IOMAP_HI_THRESH 0x10000
+#define BIGSUR_IOMAP_HI_SHIFT 10
+#define BIGSUR_IOMAP_HI_MASK ((1<<BIGSUR_IOMAP_HI_SHIFT)-1)
+#define BIGSUR_IOMAP_HI_NMAP (BIGSUR_IOMAP_HI_THRESH>>BIGSUR_IOMAP_HI_SHIFT)
+static u32 bigsur_iomap_hi[BIGSUR_IOMAP_HI_NMAP];
+static u8 bigsur_iomap_hi_shift[BIGSUR_IOMAP_HI_NMAP];
+
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+
+void bigsur_port_map(u32 baseport, u32 nports, u32 addr, u8 shift)
+{
+ u32 port, endport = baseport + nports;
+
+ pr_debug("bigsur_port_map(base=0x%0x, n=0x%0x, addr=0x%08x)\n",
+ baseport, nports, addr);
+
+ for (port = baseport ;
+ port < endport && port < BIGSUR_IOMAP_LO_THRESH ;
+ port += (1<<BIGSUR_IOMAP_LO_SHIFT)) {
+ pr_debug(" maplo[0x%x] = 0x%08x\n", port, addr);
+ bigsur_iomap_lo[port>>BIGSUR_IOMAP_LO_SHIFT] = addr;
+ bigsur_iomap_lo_shift[port>>BIGSUR_IOMAP_LO_SHIFT] = shift;
+ addr += (1<<(BIGSUR_IOMAP_LO_SHIFT));
+ }
+
+ for (port = MAX(baseport, BIGSUR_IOMAP_LO_THRESH) ;
+ port < endport && port < BIGSUR_IOMAP_HI_THRESH ;
+ port += (1<<BIGSUR_IOMAP_HI_SHIFT)) {
+ pr_debug(" maphi[0x%x] = 0x%08x\n", port, addr);
+ bigsur_iomap_hi[port>>BIGSUR_IOMAP_HI_SHIFT] = addr;
+ bigsur_iomap_hi_shift[port>>BIGSUR_IOMAP_HI_SHIFT] = shift;
+ addr += (1<<(BIGSUR_IOMAP_HI_SHIFT));
+ }
+}
+EXPORT_SYMBOL(bigsur_port_map);
+
+void bigsur_port_unmap(u32 baseport, u32 nports)
+{
+ u32 port, endport = baseport + nports;
+
+ pr_debug("bigsur_port_unmap(base=0x%0x, n=0x%0x)\n", baseport, nports);
+
+ for (port = baseport ;
+ port < endport && port < BIGSUR_IOMAP_LO_THRESH ;
+ port += (1<<BIGSUR_IOMAP_LO_SHIFT)) {
+ bigsur_iomap_lo[port>>BIGSUR_IOMAP_LO_SHIFT] = 0;
+ }
+
+ for (port = MAX(baseport, BIGSUR_IOMAP_LO_THRESH) ;
+ port < endport && port < BIGSUR_IOMAP_HI_THRESH ;
+ port += (1<<BIGSUR_IOMAP_HI_SHIFT)) {
+ bigsur_iomap_hi[port>>BIGSUR_IOMAP_HI_SHIFT] = 0;
+ }
+}
+EXPORT_SYMBOL(bigsur_port_unmap);
+
+unsigned long bigsur_isa_port2addr(unsigned long port)
+{
+ unsigned long addr = 0;
+ unsigned char shift;
+
+ /* Physical address not in P0, do nothing */
+ if (PXSEG(port)) {
+ addr = port;
+ /* physical address in P0, map to P2 */
+ } else if (port >= 0x30000) {
+ addr = P2SEGADDR(port);
+ /* Big Sur I/O + HD64465 registers 0x10000-0x30000 */
+ } else if (port >= BIGSUR_IOMAP_HI_THRESH) {
+ addr = BIGSUR_INTERNAL_BASE + (port - BIGSUR_IOMAP_HI_THRESH);
+ /* Handle remapping of high IO/PCI IO ports */
+ } else if (port >= BIGSUR_IOMAP_LO_THRESH) {
+ addr = bigsur_iomap_hi[port >> BIGSUR_IOMAP_HI_SHIFT];
+ shift = bigsur_iomap_hi_shift[port >> BIGSUR_IOMAP_HI_SHIFT];
+
+ if (addr != 0)
+ addr += (port & BIGSUR_IOMAP_HI_MASK) << shift;
+ } else {
+ /* Handle remapping of low IO ports */
+ addr = bigsur_iomap_lo[port >> BIGSUR_IOMAP_LO_SHIFT];
+ shift = bigsur_iomap_lo_shift[port >> BIGSUR_IOMAP_LO_SHIFT];
+
+ if (addr != 0)
+ addr += (port & BIGSUR_IOMAP_LO_MASK) << shift;
+ }
+
+ pr_debug("%s(0x%08lx) = 0x%08lx\n", __FUNCTION__, port, addr);
+
+ return addr;
+}
+
diff --git a/arch/sh/boards/bigsur/irq.c b/arch/sh/boards/bigsur/irq.c
new file mode 100644
index 000000000000..c188fc32dc9a
--- /dev/null
+++ b/arch/sh/boards/bigsur/irq.c
@@ -0,0 +1,348 @@
+/*
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+ *
+ * Setup and IRQ handling code for the HD64465 companion chip.
+ * by Greg Banks <gbanks@pocketpenguins.com>
+ * Copyright (c) 2000 PocketPenguins Inc
+ *
+ * Derived from setup_hd64465.c which bore the message:
+ * Greg Banks <gbanks@pocketpenguins.com>
+ * Copyright (c) 2000 PocketPenguins Inc and
+ * Copyright (C) 2000 YAEGASHI Takeshi
+ * and setup_cqreek.c which bore message:
+ * Copyright (C) 2000 Niibe Yutaka
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * IRQ functions for a Hitachi Big Sur Evaluation Board.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/bitops.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/bigsur/io.h>
+#include <asm/hd64465/hd64465.h>
+#include <asm/bigsur/bigsur.h>
+
+//#define BIGSUR_DEBUG 3
+#undef BIGSUR_DEBUG
+
+#ifdef BIGSUR_DEBUG
+#define DPRINTK(args...) printk(args)
+#define DIPRINTK(n, args...) if (BIGSUR_DEBUG>(n)) printk(args)
+#else
+#define DPRINTK(args...)
+#define DIPRINTK(n, args...)
+#endif /* BIGSUR_DEBUG */
+
+#ifdef CONFIG_HD64465
+extern int hd64465_irq_demux(int irq);
+#endif /* CONFIG_HD64465 */
+
+
+/*===========================================================*/
+// Big Sur CPLD IRQ Routines
+/*===========================================================*/
+
+/* Level 1 IRQ routines */
+static void disable_bigsur_l1irq(unsigned int irq)
+{
+ unsigned long flags;
+ unsigned char mask;
+ unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0;
+ unsigned char bit = (1 << ((irq - MGATE_IRQ_LOW)%8) );
+
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
+ DPRINTK("Disable L1 IRQ %d\n", irq);
+ DIPRINTK(2,"disable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n",
+ mask_port, bit);
+ local_irq_save(flags);
+
+ /* Disable IRQ - set mask bit */
+ mask = inb(mask_port) | bit;
+ outb(mask, mask_port);
+ local_irq_restore(flags);
+ return;
+ }
+ DPRINTK("disable_bigsur_l1irq: Invalid IRQ %d\n", irq);
+}
+
+static void enable_bigsur_l1irq(unsigned int irq)
+{
+ unsigned long flags;
+ unsigned char mask;
+ unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0;
+ unsigned char bit = (1 << ((irq - MGATE_IRQ_LOW)%8) );
+
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
+ DPRINTK("Enable L1 IRQ %d\n", irq);
+ DIPRINTK(2,"enable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n",
+ mask_port, bit);
+ local_irq_save(flags);
+ /* Enable L1 IRQ - clear mask bit */
+ mask = inb(mask_port) & ~bit;
+ outb(mask, mask_port);
+ local_irq_restore(flags);
+ return;
+ }
+ DPRINTK("enable_bigsur_l1irq: Invalid IRQ %d\n", irq);
+}
+
+
+/* Level 2 irq masks and registers for L2 decoding */
+/* Level2 bitmasks for each level 1 IRQ */
+const u32 bigsur_l2irq_mask[] =
+ {0x40,0x80,0x08,0x01,0x01,0x3C,0x3E,0xFF,0x40,0x80,0x06,0x03};
+/* Level2 to ISR[n] map for each level 1 IRQ */
+const u32 bigsur_l2irq_reg[] =
+ { 2, 2, 3, 3, 1, 2, 1, 0, 1, 1, 3, 2};
+/* Level2 to Level 1 IRQ map */
+const u32 bigsur_l2_l1_map[] =
+ {7,7,7,7,7,7,7,7, 4,6,6,6,6,6,8,9, 11,11,5,5,5,5,0,1, 3,10,10,2,-1,-1,-1,-1};
+/* IRQ inactive level (high or low) */
+const u32 bigsur_l2_inactv_state[] = {0x00, 0xBE, 0xFC, 0xF7};
+
+/* CPLD external status and mask registers base and offsets */
+static const u32 isr_base = BIGSUR_IRQ0;
+static const u32 isr_offset = BIGSUR_IRQ0 - BIGSUR_IRQ1;
+static const u32 imr_base = BIGSUR_IMR0;
+static const u32 imr_offset = BIGSUR_IMR0 - BIGSUR_IMR1;
+
+#define REG_NUM(irq) ((irq-BIGSUR_2NDLVL_IRQ_LOW)/8 )
+
+/* Level 2 IRQ routines */
+static void disable_bigsur_l2irq(unsigned int irq)
+{
+ unsigned long flags;
+ unsigned char mask;
+ unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8);
+ unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset;
+
+ if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
+ DPRINTK("Disable L2 IRQ %d\n", irq);
+ DIPRINTK(2,"disable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n",
+ mask_port, bit);
+ local_irq_save(flags);
+
+ /* Disable L2 IRQ - set mask bit */
+ mask = inb(mask_port) | bit;
+ outb(mask, mask_port);
+ local_irq_restore(flags);
+ return;
+ }
+ DPRINTK("disable_bigsur_l2irq: Invalid IRQ %d\n", irq);
+}
+
+static void enable_bigsur_l2irq(unsigned int irq)
+{
+ unsigned long flags;
+ unsigned char mask;
+ unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8);
+ unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset;
+
+ if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
+ DPRINTK("Enable L2 IRQ %d\n", irq);
+ DIPRINTK(2,"enable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n",
+ mask_port, bit);
+ local_irq_save(flags);
+
+ /* Enable L2 IRQ - clear mask bit */
+ mask = inb(mask_port) & ~bit;
+ outb(mask, mask_port);
+ local_irq_restore(flags);
+ return;
+ }
+ DPRINTK("enable_bigsur_l2irq: Invalid IRQ %d\n", irq);
+}
+
+static void mask_and_ack_bigsur(unsigned int irq)
+{
+ DPRINTK("mask_and_ack_bigsur IRQ %d\n", irq);
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
+ disable_bigsur_l1irq(irq);
+ else
+ disable_bigsur_l2irq(irq);
+}
+
+static void end_bigsur_irq(unsigned int irq)
+{
+ DPRINTK("end_bigsur_irq IRQ %d\n", irq);
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
+ enable_bigsur_l1irq(irq);
+ else
+ enable_bigsur_l2irq(irq);
+ }
+}
+
+static unsigned int startup_bigsur_irq(unsigned int irq)
+{
+ u8 mask;
+ u32 reg;
+
+ DPRINTK("startup_bigsur_irq IRQ %d\n", irq);
+
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
+ /* Enable the L1 IRQ */
+ enable_bigsur_l1irq(irq);
+ /* Enable all L2 IRQs in this L1 IRQ */
+ mask = ~(bigsur_l2irq_mask[irq-BIGSUR_IRQ_LOW]);
+ reg = imr_base - bigsur_l2irq_reg[irq-BIGSUR_IRQ_LOW] * imr_offset;
+ mask &= inb(reg);
+ outb(mask,reg);
+ DIPRINTK(2,"startup_bigsur_irq: IMR=0x%08x mask=0x%x\n",reg,inb(reg));
+ }
+ else {
+ /* Enable the L2 IRQ - clear mask bit */
+ enable_bigsur_l2irq(irq);
+ /* Enable the L1 bit masking this L2 IRQ */
+ enable_bigsur_l1irq(bigsur_l2_l1_map[irq-BIGSUR_2NDLVL_IRQ_LOW]);
+ DIPRINTK(2,"startup_bigsur_irq: L1=%d L2=%d\n",
+ bigsur_l2_l1_map[irq-BIGSUR_2NDLVL_IRQ_LOW],irq);
+ }
+ return 0;
+}
+
+static void shutdown_bigsur_irq(unsigned int irq)
+{
+ DPRINTK("shutdown_bigsur_irq IRQ %d\n", irq);
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
+ disable_bigsur_l1irq(irq);
+ else
+ disable_bigsur_l2irq(irq);
+}
+
+/* Define the IRQ structures for the L1 and L2 IRQ types */
+static struct hw_interrupt_type bigsur_l1irq_type = {
+ "BigSur-CPLD-Level1-IRQ",
+ startup_bigsur_irq,
+ shutdown_bigsur_irq,
+ enable_bigsur_l1irq,
+ disable_bigsur_l1irq,
+ mask_and_ack_bigsur,
+ end_bigsur_irq
+};
+
+static struct hw_interrupt_type bigsur_l2irq_type = {
+ "BigSur-CPLD-Level2-IRQ",
+ startup_bigsur_irq,
+ shutdown_bigsur_irq,
+ enable_bigsur_l2irq,
+ disable_bigsur_l2irq,
+ mask_and_ack_bigsur,
+ end_bigsur_irq
+};
+
+
+static void make_bigsur_l1isr(unsigned int irq) {
+
+ /* sanity check first */
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
+ /* save the handler in the main description table */
+ irq_desc[irq].handler = &bigsur_l1irq_type;
+ irq_desc[irq].status = IRQ_DISABLED;
+ irq_desc[irq].action = 0;
+ irq_desc[irq].depth = 1;
+
+ disable_bigsur_l1irq(irq);
+ return;
+ }
+ DPRINTK("make_bigsur_l1isr: bad irq, %d\n", irq);
+ return;
+}
+
+static void make_bigsur_l2isr(unsigned int irq) {
+
+ /* sanity check first */
+ if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
+ /* save the handler in the main description table */
+ irq_desc[irq].handler = &bigsur_l2irq_type;
+ irq_desc[irq].status = IRQ_DISABLED;
+ irq_desc[irq].action = 0;
+ irq_desc[irq].depth = 1;
+
+ disable_bigsur_l2irq(irq);
+ return;
+ }
+ DPRINTK("make_bigsur_l2isr: bad irq, %d\n", irq);
+ return;
+}
+
+/* The IRQ's will be decoded as follows:
+ * If a level 2 handler exists and there is an unmasked active
+ * IRQ, the 2nd level handler will be called.
+ * If a level 2 handler does not exist for the active IRQ
+ * the 1st level handler will be called.
+ */
+
+int bigsur_irq_demux(int irq)
+{
+ int dmux_irq = irq;
+ u8 mask, actv_irqs;
+ u32 reg_num;
+
+ DIPRINTK(3,"bigsur_irq_demux, irq=%d\n", irq);
+ /* decode the 1st level IRQ */
+ if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
+ /* Get corresponding L2 ISR bitmask and ISR number */
+ mask = bigsur_l2irq_mask[irq-BIGSUR_IRQ_LOW];
+ reg_num = bigsur_l2irq_reg[irq-BIGSUR_IRQ_LOW];
+ /* find the active IRQ's (XOR with inactive level)*/
+ actv_irqs = inb(isr_base-reg_num*isr_offset) ^
+ bigsur_l2_inactv_state[reg_num];
+ /* decode active IRQ's */
+ actv_irqs = actv_irqs & mask & ~(inb(imr_base-reg_num*imr_offset));
+ /* if NEZ then we have an active L2 IRQ */
+ if(actv_irqs) dmux_irq = ffz(~actv_irqs) + reg_num*8+BIGSUR_2NDLVL_IRQ_LOW;
+ /* if no 2nd level IRQ action, but has 1st level, use 1st level handler */
+ if(!irq_desc[dmux_irq].action && irq_desc[irq].action)
+ dmux_irq = irq;
+ DIPRINTK(1,"bigsur_irq_demux: irq=%d dmux_irq=%d mask=0x%04x reg=%d\n",
+ irq, dmux_irq, mask, reg_num);
+ }
+#ifdef CONFIG_HD64465
+ dmux_irq = hd64465_irq_demux(dmux_irq);
+#endif /* CONFIG_HD64465 */
+ DIPRINTK(3,"bigsur_irq_demux, demux_irq=%d\n", dmux_irq);
+
+ return dmux_irq;
+}
+
+/*===========================================================*/
+// Big Sur Init Routines
+/*===========================================================*/
+void __init init_bigsur_IRQ(void)
+{
+ int i;
+
+ if (!MACH_BIGSUR) return;
+
+ /* Create ISR's for Big Sur CPLD IRQ's */
+ /*==============================================================*/
+ for(i=BIGSUR_IRQ_LOW;i<BIGSUR_IRQ_HIGH;i++)
+ make_bigsur_l1isr(i);
+
+ printk(KERN_INFO "Big Sur CPLD L1 interrupts %d to %d.\n",
+ BIGSUR_IRQ_LOW,BIGSUR_IRQ_HIGH);
+
+ for(i=BIGSUR_2NDLVL_IRQ_LOW;i<BIGSUR_2NDLVL_IRQ_HIGH;i++)
+ make_bigsur_l2isr(i);
+
+ printk(KERN_INFO "Big Sur CPLD L2 interrupts %d to %d.\n",
+ BIGSUR_2NDLVL_IRQ_LOW,BIGSUR_2NDLVL_IRQ_HIGH);
+
+}
diff --git a/arch/sh/boards/bigsur/led.c b/arch/sh/boards/bigsur/led.c
new file mode 100644
index 000000000000..0a2339c69440
--- /dev/null
+++ b/arch/sh/boards/bigsur/led.c
@@ -0,0 +1,55 @@
+/*
+ * linux/arch/sh/kernel/led_bigsur.c
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+ * Derived from led_se.c and led.c, which bore the message:
+ * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * This file contains Big Sur specific LED code.
+ */
+
+#include <linux/config.h>
+#include <asm/io.h>
+#include <asm/bigsur/bigsur.h>
+
+static void mach_led(int position, int value)
+{
+ int word;
+
+ word = bigsur_inl(BIGSUR_CSLR);
+ if (value) {
+ bigsur_outl(word & ~BIGSUR_LED, BIGSUR_CSLR);
+ } else {
+ bigsur_outl(word | BIGSUR_LED, BIGSUR_CSLR);
+ }
+}
+
+#ifdef CONFIG_HEARTBEAT
+
+#include <linux/sched.h>
+
+/* Cycle the LED on/off */
+void heartbeat_bigsur(void)
+{
+ static unsigned cnt = 0, period = 0, dist = 0;
+
+ if (cnt == 0 || cnt == dist)
+ mach_led( -1, 1);
+ else if (cnt == 7 || cnt == dist+7)
+ mach_led( -1, 0);
+
+ if (++cnt > period) {
+ cnt = 0;
+ /* The hyperbolic function below modifies the heartbeat period
+ * length in dependency of the current (5min) load. It goes
+ * through the points f(0)=126, f(1)=86, f(5)=51,
+ * f(inf)->30. */
+ period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+ dist = period / 4;
+ }
+}
+#endif /* CONFIG_HEARTBEAT */
+
diff --git a/arch/sh/boards/bigsur/setup.c b/arch/sh/boards/bigsur/setup.c
new file mode 100644
index 000000000000..e69be05195f5
--- /dev/null
+++ b/arch/sh/boards/bigsur/setup.c
@@ -0,0 +1,96 @@
+/*
+ *
+ * By Dustin McIntire (dustin@sensoria.com) (c)2001
+ *
+ * Setup and IRQ handling code for the HD64465 companion chip.
+ * by Greg Banks <gbanks@pocketpenguins.com>
+ * Copyright (c) 2000 PocketPenguins Inc
+ *
+ * Derived from setup_hd64465.c which bore the message:
+ * Greg Banks <gbanks@pocketpenguins.com>
+ * Copyright (c) 2000 PocketPenguins Inc and
+ * Copyright (C) 2000 YAEGASHI Takeshi
+ * and setup_cqreek.c which bore message:
+ * Copyright (C) 2000 Niibe Yutaka
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Setup functions for a Hitachi Big Sur Evaluation Board.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/bitops.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/machvec.h>
+#include <asm/bigsur/io.h>
+#include <asm/hd64465/hd64465.h>
+#include <asm/bigsur/bigsur.h>
+
+/*===========================================================*/
+// Big Sur Init Routines
+/*===========================================================*/
+
+const char *get_system_type(void)
+{
+ return "Big Sur";
+}
+
+/*
+ * The Machine Vector
+ */
+extern void heartbeat_bigsur(void);
+extern void init_bigsur_IRQ(void);
+
+struct sh_machine_vector mv_bigsur __initmv = {
+ .mv_nr_irqs = NR_IRQS, // Defined in <asm/irq.h>
+
+ .mv_isa_port2addr = bigsur_isa_port2addr,
+ .mv_irq_demux = bigsur_irq_demux,
+
+ .mv_init_irq = init_bigsur_IRQ,
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_bigsur,
+#endif
+};
+ALIAS_MV(bigsur)
+
+int __init platform_setup(void)
+{
+ /* Mask all 2nd level IRQ's */
+ outb(-1,BIGSUR_IMR0);
+ outb(-1,BIGSUR_IMR1);
+ outb(-1,BIGSUR_IMR2);
+ outb(-1,BIGSUR_IMR3);
+
+ /* Mask 1st level interrupts */
+ outb(-1,BIGSUR_IRLMR0);
+ outb(-1,BIGSUR_IRLMR1);
+
+#if defined (CONFIG_HD64465) && defined (CONFIG_SERIAL)
+ /* remap IO ports for first ISA serial port to HD64465 UART */
+ bigsur_port_map(0x3f8, 8, CONFIG_HD64465_IOBASE + 0x8000, 1);
+#endif /* CONFIG_HD64465 && CONFIG_SERIAL */
+ /* TODO: setup IDE registers */
+ bigsur_port_map(BIGSUR_IDECTL_IOPORT, 2, BIGSUR_ICTL, 8);
+ /* Setup the Ethernet port to BIGSUR_ETHER_IOPORT */
+ bigsur_port_map(BIGSUR_ETHER_IOPORT, 16, BIGSUR_ETHR+BIGSUR_ETHER_IOPORT, 0);
+ /* set page to 1 */
+ outw(1, BIGSUR_ETHR+0xe);
+ /* set the IO port to BIGSUR_ETHER_IOPORT */
+ outw(BIGSUR_ETHER_IOPORT<<3, BIGSUR_ETHR+0x2);
+
+ return 0;
+}
+
diff --git a/arch/sh/boards/cat68701/Makefile b/arch/sh/boards/cat68701/Makefile
new file mode 100644
index 000000000000..52c1de0a6dfd
--- /dev/null
+++ b/arch/sh/boards/cat68701/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the CAT-68701 specific parts of the kernel
+#
+
+obj-y := setup.o irq.o
+
diff --git a/arch/sh/boards/cat68701/irq.c b/arch/sh/boards/cat68701/irq.c
new file mode 100644
index 000000000000..f9a6d185fb8b
--- /dev/null
+++ b/arch/sh/boards/cat68701/irq.c
@@ -0,0 +1,28 @@
+/*
+ * linux/arch/sh/boards/cat68701/irq.c
+ *
+ * Copyright (C) 2000 Niibe Yutaka
+ * 2001 Yutaro Ebihara
+ *
+ * Setup routines for A-ONE Corp CAT-68701 SH7708 Board
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <asm/irq.h>
+
+int cat68701_irq_demux(int irq)
+{
+ if(irq==13) return 14;
+ if(irq==7) return 10;
+ return irq;
+}
+
+void init_cat68701_IRQ()
+{
+ make_imask_irq(10);
+ make_imask_irq(14);
+}
diff --git a/arch/sh/boards/cat68701/setup.c b/arch/sh/boards/cat68701/setup.c
new file mode 100644
index 000000000000..ae8a350ade53
--- /dev/null
+++ b/arch/sh/boards/cat68701/setup.c
@@ -0,0 +1,86 @@
+/*
+ * linux/arch/sh/boards/cat68701/setup.c
+ *
+ * Copyright (C) 2000 Niibe Yutaka
+ * 2001 Yutaro Ebihara
+ *
+ * Setup routines for A-ONE Corp CAT-68701 SH7708 Board
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <asm/io.h>
+#include <asm/machvec.h>
+#include <asm/mach/io.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+
+const char *get_system_type(void)
+{
+ return "CAT-68701";
+}
+
+#ifdef CONFIG_HEARTBEAT
+void heartbeat_cat68701()
+{
+ static unsigned int cnt = 0, period = 0 , bit = 0;
+ cnt += 1;
+ if (cnt < period) {
+ return;
+ }
+ cnt = 0;
+
+ /* Go through the points (roughly!):
+ * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110
+ */
+ period = 110 - ( (300<<FSHIFT)/
+ ((avenrun[0]/5) + (3<<FSHIFT)) );
+
+ if(bit){ bit=0; }else{ bit=1; }
+ outw(bit<<15,0x3fe);
+}
+#endif /* CONFIG_HEARTBEAT */
+
+unsigned long cat68701_isa_port2addr(unsigned long offset)
+{
+ /* CompactFlash (IDE) */
+ if (((offset >= 0x1f0) && (offset <= 0x1f7)) || (offset==0x3f6))
+ return 0xba000000 + offset;
+
+ /* INPUT PORT */
+ if ((offset >= 0x3fc) && (offset <= 0x3fd))
+ return 0xb4007000 + offset;
+
+ /* OUTPUT PORT */
+ if ((offset >= 0x3fe) && (offset <= 0x3ff))
+ return 0xb4007400 + offset;
+
+ return offset + 0xb4000000; /* other I/O (EREA 5)*/
+}
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_cat68701 __initmv = {
+ .mv_nr_irqs = 32,
+ .mv_isa_port2addr = cat68701_isa_port2addr,
+ .mv_irq_demux = cat68701_irq_demux,
+
+ .mv_init_irq = init_cat68701_IRQ,
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_cat68701,
+#endif
+};
+ALIAS_MV(cat68701)
+
+int __init platform_setup(void)
+{
+ /* dummy read erea5 (CS8900A) */
+}
+
diff --git a/arch/sh/boards/cqreek/Makefile b/arch/sh/boards/cqreek/Makefile
new file mode 100644
index 000000000000..1a788a85eba3
--- /dev/null
+++ b/arch/sh/boards/cqreek/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the CqREEK specific parts of the kernel
+#
+
+obj-y := setup.o irq.o
+
diff --git a/arch/sh/boards/cqreek/irq.c b/arch/sh/boards/cqreek/irq.c
new file mode 100644
index 000000000000..fa6cfe5a20a7
--- /dev/null
+++ b/arch/sh/boards/cqreek/irq.c
@@ -0,0 +1,128 @@
+/* $Id: irq.c,v 1.1.2.4 2002/11/04 20:33:56 lethal Exp $
+ *
+ * arch/sh/boards/cqreek/irq.c
+ *
+ * Copyright (C) 2000 Niibe Yutaka
+ *
+ * CqREEK IDE/ISA Bridge Support.
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/init.h>
+
+#include <asm/cqreek/cqreek.h>
+#include <asm/io.h>
+#include <asm/io_generic.h>
+#include <asm/irq.h>
+#include <asm/machvec.h>
+#include <asm/machvec_init.h>
+#include <asm/rtc.h>
+
+struct cqreek_irq_data {
+ unsigned short mask_port; /* Port of Interrupt Mask Register */
+ unsigned short stat_port; /* Port of Interrupt Status Register */
+ unsigned short bit; /* Value of the bit */
+};
+static struct cqreek_irq_data cqreek_irq_data[NR_IRQS];
+
+static void disable_cqreek_irq(unsigned int irq)
+{
+ unsigned long flags;
+ unsigned short mask;
+ unsigned short mask_port = cqreek_irq_data[irq].mask_port;
+ unsigned short bit = cqreek_irq_data[irq].bit;
+
+ local_irq_save(flags);
+ /* Disable IRQ */
+ mask = inw(mask_port) & ~bit;
+ outw_p(mask, mask_port);
+ local_irq_restore(flags);
+}
+
+static void enable_cqreek_irq(unsigned int irq)
+{
+ unsigned long flags;
+ unsigned short mask;
+ unsigned short mask_port = cqreek_irq_data[irq].mask_port;
+ unsigned short bit = cqreek_irq_data[irq].bit;
+
+ local_irq_save(flags);
+ /* Enable IRQ */
+ mask = inw(mask_port) | bit;
+ outw_p(mask, mask_port);
+ local_irq_restore(flags);
+}
+
+static void mask_and_ack_cqreek(unsigned int irq)
+{
+ unsigned short stat_port = cqreek_irq_data[irq].stat_port;
+ unsigned short bit = cqreek_irq_data[irq].bit;
+
+ disable_cqreek_irq(irq);
+ /* Clear IRQ (it might be edge IRQ) */
+ inw(stat_port);
+ outw_p(bit, stat_port);
+}
+
+static void end_cqreek_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ enable_cqreek_irq(irq);
+}
+
+static unsigned int startup_cqreek_irq(unsigned int irq)
+{
+ enable_cqreek_irq(irq);
+ return 0;
+}
+
+static void shutdown_cqreek_irq(unsigned int irq)
+{
+ disable_cqreek_irq(irq);
+}
+
+static struct hw_interrupt_type cqreek_irq_type = {
+ "CqREEK-IRQ",
+ startup_cqreek_irq,
+ shutdown_cqreek_irq,
+ enable_cqreek_irq,
+ disable_cqreek_irq,
+ mask_and_ack_cqreek,
+ end_cqreek_irq
+};
+
+int cqreek_has_ide, cqreek_has_isa;
+
+/* XXX: This is just for test for my NE2000 ISA board
+ What we really need is virtualized IRQ and demultiplexer like HP600 port */
+void __init init_cqreek_IRQ(void)
+{
+ if (cqreek_has_ide) {
+ cqreek_irq_data[14].mask_port = BRIDGE_IDE_INTR_MASK;
+ cqreek_irq_data[14].stat_port = BRIDGE_IDE_INTR_STAT;
+ cqreek_irq_data[14].bit = 1;
+
+ irq_desc[14].handler = &cqreek_irq_type;
+ irq_desc[14].status = IRQ_DISABLED;
+ irq_desc[14].action = 0;
+ irq_desc[14].depth = 1;
+
+ disable_cqreek_irq(14);
+ }
+
+ if (cqreek_has_isa) {
+ cqreek_irq_data[10].mask_port = BRIDGE_ISA_INTR_MASK;
+ cqreek_irq_data[10].stat_port = BRIDGE_ISA_INTR_STAT;
+ cqreek_irq_data[10].bit = (1 << 10);
+
+ /* XXX: Err... we may need demultiplexer for ISA irq... */
+ irq_desc[10].handler = &cqreek_irq_type;
+ irq_desc[10].status = IRQ_DISABLED;
+ irq_desc[10].action = 0;
+ irq_desc[10].depth = 1;
+
+ disable_cqreek_irq(10);
+ }
+}
+
diff --git a/arch/sh/boards/cqreek/setup.c b/arch/sh/boards/cqreek/setup.c
new file mode 100644
index 000000000000..29b537cd6546
--- /dev/null
+++ b/arch/sh/boards/cqreek/setup.c
@@ -0,0 +1,101 @@
+/* $Id: setup.c,v 1.5 2003/08/04 01:51:58 lethal Exp $
+ *
+ * arch/sh/kernel/setup_cqreek.c
+ *
+ * Copyright (C) 2000 Niibe Yutaka
+ *
+ * CqREEK IDE/ISA Bridge Support.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/mach/cqreek.h>
+#include <asm/machvec.h>
+#include <asm/io.h>
+#include <asm/io_generic.h>
+#include <asm/irq.h>
+#include <asm/rtc.h>
+
+#define IDE_OFFSET 0xA4000000UL
+#define ISA_OFFSET 0xA4A00000UL
+
+const char *get_system_type(void)
+{
+ return "CqREEK";
+}
+
+static unsigned long cqreek_port2addr(unsigned long port)
+{
+ if (0x0000<=port && port<=0x0040)
+ return IDE_OFFSET + port;
+ if ((0x01f0<=port && port<=0x01f7) || port == 0x03f6)
+ return IDE_OFFSET + port;
+
+ return ISA_OFFSET + port;
+}
+
+/*
+ * The Machine Vector
+ */
+struct sh_machine_vector mv_cqreek __initmv = {
+#if defined(CONFIG_CPU_SH4)
+ .mv_nr_irqs = 48,
+#elif defined(CONFIG_CPU_SUBTYPE_SH7708)
+ .mv_nr_irqs = 32,
+#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
+ .mv_nr_irqs = 61,
+#endif
+
+ .mv_init_irq = init_cqreek_IRQ,
+
+ .mv_isa_port2addr = cqreek_port2addr,
+};
+ALIAS_MV(cqreek)
+
+/*
+ * Initialize the board
+ */
+void __init platform_setup(void)
+{
+ int i;
+/* udelay is not available at setup time yet... */
+#define DELAY() do {for (i=0; i<10000; i++) ctrl_inw(0xa0000000);} while(0)
+
+ if ((inw (BRIDGE_FEATURE) & 1)) { /* We have IDE interface */
+ outw_p(0, BRIDGE_IDE_INTR_LVL);
+ outw_p(0, BRIDGE_IDE_INTR_MASK);
+
+ outw_p(0, BRIDGE_IDE_CTRL);
+ DELAY();
+
+ outw_p(0x8000, BRIDGE_IDE_CTRL);
+ DELAY();
+
+ outw_p(0xffff, BRIDGE_IDE_INTR_STAT); /* Clear interrupt status */
+ outw_p(0x0f-14, BRIDGE_IDE_INTR_LVL); /* Use 14 IPR */
+ outw_p(1, BRIDGE_IDE_INTR_MASK); /* Enable interrupt */
+ cqreek_has_ide=1;
+ }
+
+ if ((inw (BRIDGE_FEATURE) & 2)) { /* We have ISA interface */
+ outw_p(0, BRIDGE_ISA_INTR_LVL);
+ outw_p(0, BRIDGE_ISA_INTR_MASK);
+
+ outw_p(0, BRIDGE_ISA_CTRL);
+ DELAY();
+ outw_p(0x8000, BRIDGE_ISA_CTRL);
+ DELAY();
+
+ outw_p(0xffff, BRIDGE_ISA_INTR_STAT); /* Clear interrupt status */
+ outw_p(0x0f-10, BRIDGE_ISA_INTR_LVL); /* Use 10 IPR */
+ outw_p(0xfff8, BRIDGE_ISA_INTR_MASK); /* Enable interrupt */
+ cqreek_has_isa=1;
+ }
+
+ printk(KERN_INFO "CqREEK Setup (IDE=%d, ISA=%d)...done\n", cqreek_has_ide, cqreek_has_isa);
+}
+
diff --git a/arch/sh/boards/dmida/Makefile b/arch/sh/boards/dmida/Makefile
new file mode 100644
index 000000000000..75999aa0a2d9
--- /dev/null
+++ b/arch/sh/boards/dmida/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the DataMyte Industrial Digital Assistant(tm) specific parts
+# of the kernel
+#
+
+obj-y := mach.o
+
diff --git a/arch/sh/boards/dmida/mach.c b/arch/sh/boards/dmida/mach.c
new file mode 100644
index 000000000000..d03a25f989c2
--- /dev/null
+++ b/arch/sh/boards/dmida/mach.c
@@ -0,0 +1,59 @@
+/*
+ * linux/arch/sh/boards/dmida/mach.c
+ *
+ * by Greg Banks <gbanks@pocketpenguins.com>
+ * (c) 2000 PocketPenguins Inc
+ *
+ * Derived from mach_hp600.c, which bore the message:
+ * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Machine vector for the DataMyte Industrial Digital Assistant(tm).
+ * See http://www.dmida.com
+ *
+ */
+
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/machvec_init.h>
+
+#include <asm/io.h>
+#include <asm/hd64465/hd64465.h>
+#include <asm/irq.h>
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_dmida __initmv = {
+ .mv_nr_irqs = HD64465_IRQ_BASE+HD64465_IRQ_NUM,
+
+ .mv_inb = hd64465_inb,
+ .mv_inw = hd64465_inw,
+ .mv_inl = hd64465_inl,
+ .mv_outb = hd64465_outb,
+ .mv_outw = hd64465_outw,
+ .mv_outl = hd64465_outl,
+
+ .mv_inb_p = hd64465_inb_p,
+ .mv_inw_p = hd64465_inw,
+ .mv_inl_p = hd64465_inl,
+ .mv_outb_p = hd64465_outb_p,
+ .mv_outw_p = hd64465_outw,
+ .mv_outl_p = hd64465_outl,
+
+ .mv_insb = hd64465_insb,
+ .mv_insw = hd64465_insw,
+ .mv_insl = hd64465_insl,
+ .mv_outsb = hd64465_outsb,
+ .mv_outsw = hd64465_outsw,
+ .mv_outsl = hd64465_outsl,
+
+ .mv_irq_demux = hd64465_irq_demux,
+};
+ALIAS_MV(dmida)
+
diff --git a/arch/sh/boards/dreamcast/Makefile b/arch/sh/boards/dreamcast/Makefile
new file mode 100644
index 000000000000..7b97546c7e5f
--- /dev/null
+++ b/arch/sh/boards/dreamcast/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Sega Dreamcast specific parts of the kernel
+#
+
+obj-y := setup.o irq.o rtc.o
+
diff --git a/arch/sh/boards/dreamcast/irq.c b/arch/sh/boards/dreamcast/irq.c
new file mode 100644
index 000000000000..b10a6b11c034
--- /dev/null
+++ b/arch/sh/boards/dreamcast/irq.c
@@ -0,0 +1,160 @@
+/*
+ * arch/sh/boards/dreamcast/irq.c
+ *
+ * Holly IRQ support for the Sega Dreamcast.
+ *
+ * Copyright (c) 2001, 2002 M. R. Brown <mrbrown@0xd6.org>
+ *
+ * This file is part of the LinuxDC project (www.linuxdc.org)
+ * Released under the terms of the GNU GPL v2.0
+ */
+
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dreamcast/sysasic.h>
+
+/* Dreamcast System ASIC Hardware Events -
+
+ The Dreamcast's System ASIC (a.k.a. Holly) is responsible for receiving
+ hardware events from system peripherals and triggering an SH7750 IRQ.
+ Hardware events can trigger IRQs 13, 11, or 9 depending on which bits are
+ set in the Event Mask Registers (EMRs). When a hardware event is
+ triggered, it's corresponding bit in the Event Status Registers (ESRs)
+ is set, and that bit should be rewritten to the ESR to acknowledge that
+ event.
+
+ There are three 32-bit ESRs located at 0xa05f8900 - 0xa05f6908. Event
+ types can be found in include/asm-sh/dc_sysasic.h. There are three groups
+ of EMRs that parallel the ESRs. Each EMR group corresponds to an IRQ, so
+ 0xa05f6910 - 0xa05f6918 triggers IRQ 13, 0xa05f6920 - 0xa05f6928 triggers
+ IRQ 11, and 0xa05f6930 - 0xa05f6938 triggers IRQ 9.
+
+ In the kernel, these events are mapped to virtual IRQs so that drivers can
+ respond to them as they would a normal interrupt. In order to keep this
+ mapping simple, the events are mapped as:
+
+ 6900/6910 - Events 0-31, IRQ 13
+ 6904/6924 - Events 32-63, IRQ 11
+ 6908/6938 - Events 64-95, IRQ 9
+
+*/
+
+#define ESR_BASE 0x005f6900 /* Base event status register */
+#define EMR_BASE 0x005f6910 /* Base event mask register */
+
+/* Helps us determine the EMR group that this event belongs to: 0 = 0x6910,
+ 1 = 0x6920, 2 = 0x6930; also determine the event offset */
+#define LEVEL(event) (((event) - HW_EVENT_IRQ_BASE) / 32)
+
+/* Return the hardware event's bit positon within the EMR/ESR */
+#define EVENT_BIT(event) (((event) - HW_EVENT_IRQ_BASE) & 31)
+
+/* For each of these *_irq routines, the IRQ passed in is the virtual IRQ
+ (logically mapped to the corresponding bit for the hardware event). */
+
+/* Disable the hardware event by masking its bit in its EMR */
+static inline void disable_systemasic_irq(unsigned int irq)
+{
+ unsigned long flags;
+ __u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
+ __u32 mask;
+
+ local_irq_save(flags);
+ mask = inl(emr);
+ mask &= ~(1 << EVENT_BIT(irq));
+ outl(mask, emr);
+ local_irq_restore(flags);
+}
+
+/* Enable the hardware event by setting its bit in its EMR */
+static inline void enable_systemasic_irq(unsigned int irq)
+{
+ unsigned long flags;
+ __u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
+ __u32 mask;
+
+ local_irq_save(flags);
+ mask = inl(emr);
+ mask |= (1 << EVENT_BIT(irq));
+ outl(mask, emr);
+ local_irq_restore(flags);
+}
+
+/* Acknowledge a hardware event by writing its bit back to its ESR */
+static void ack_systemasic_irq(unsigned int irq)
+{
+ __u32 esr = ESR_BASE + (LEVEL(irq) << 2);
+ disable_systemasic_irq(irq);
+ outl((1 << EVENT_BIT(irq)), esr);
+}
+
+/* After a IRQ has been ack'd and responded to, it needs to be renabled */
+static void end_systemasic_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ enable_systemasic_irq(irq);
+}
+
+static unsigned int startup_systemasic_irq(unsigned int irq)
+{
+ enable_systemasic_irq(irq);
+
+ return 0;
+}
+
+static void shutdown_systemasic_irq(unsigned int irq)
+{
+ disable_systemasic_irq(irq);
+}
+
+struct hw_interrupt_type systemasic_int = {
+ .typename = "System ASIC",
+ .startup = startup_systemasic_irq,
+ .shutdown = shutdown_systemasic_irq,
+ .enable = enable_systemasic_irq,
+ .disable = disable_systemasic_irq,
+ .ack = ack_systemasic_irq,
+ .end = end_systemasic_irq,
+};
+
+/*
+ * Map the hardware event indicated by the processor IRQ to a virtual IRQ.
+ */
+int systemasic_irq_demux(int irq)
+{
+ __u32 emr, esr, status, level;
+ __u32 j, bit;
+
+ switch (irq) {
+ case 13:
+ level = 0;
+ break;
+ case 11:
+ level = 1;
+ break;
+ case 9:
+ level = 2;
+ break;
+ default:
+ return irq;
+ }
+ emr = EMR_BASE + (level << 4) + (level << 2);
+ esr = ESR_BASE + (level << 2);
+
+ /* Mask the ESR to filter any spurious, unwanted interrtupts */
+ status = inl(esr);
+ status &= inl(emr);
+
+ /* Now scan and find the first set bit as the event to map */
+ for (bit = 1, j = 0; j < 32; bit <<= 1, j++) {
+ if (status & bit) {
+ irq = HW_EVENT_IRQ_BASE + j + (level << 5);
+ return irq;
+ }
+ }
+
+ /* Not reached */
+ return irq;
+}
diff --git a/arch/sh/boards/dreamcast/rtc.c b/arch/sh/boards/dreamcast/rtc.c
new file mode 100644
index 000000000000..379de1629134
--- /dev/null
+++ b/arch/sh/boards/dreamcast/rtc.c
@@ -0,0 +1,81 @@
+/* arch/sh/kernel/rtc-aica.c
+ *
+ * Dreamcast AICA RTC routines.
+ *
+ * Copyright (c) 2001, 2002 M. R. Brown <mrbrown@0xd6.org>
+ * Copyright (c) 2002 Paul Mundt <lethal@chaoticdreams.org>
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ */
+
+#include <linux/time.h>
+
+#include <asm/io.h>
+
+extern void (*rtc_get_time)(struct timespec *);
+extern int (*rtc_set_time)(const time_t);
+
+/* The AICA RTC has an Epoch of 1/1/1950, so we must subtract 20 years (in
+ seconds to get the standard Unix Epoch when getting the time, and add 20
+ years when setting the time. */
+#define TWENTY_YEARS ((20 * 365LU + 5) * 86400)
+
+/* The AICA RTC is represented by a 32-bit seconds counter stored in 2 16-bit
+ registers.*/
+#define AICA_RTC_SECS_H 0xa0710000
+#define AICA_RTC_SECS_L 0xa0710004
+
+/**
+ * aica_rtc_gettimeofday - Get the time from the AICA RTC
+ * @ts: pointer to resulting timespec
+ *
+ * Grabs the current RTC seconds counter and adjusts it to the Unix Epoch.
+ */
+void aica_rtc_gettimeofday(struct timespec *ts) {
+ unsigned long val1, val2;
+
+ do {
+ val1 = ((ctrl_inl(AICA_RTC_SECS_H) & 0xffff) << 16) |
+ (ctrl_inl(AICA_RTC_SECS_L) & 0xffff);
+
+ val2 = ((ctrl_inl(AICA_RTC_SECS_H) & 0xffff) << 16) |
+ (ctrl_inl(AICA_RTC_SECS_L) & 0xffff);
+ } while (val1 != val2);
+
+ ts->tv_sec = val1 - TWENTY_YEARS;
+
+ /* Can't get nanoseconds with just a seconds counter. */
+ ts->tv_nsec = 0;
+}
+
+/**
+ * aica_rtc_settimeofday - Set the AICA RTC to the current time
+ * @secs: contains the time_t to set
+ *
+ * Adjusts the given @tv to the AICA Epoch and sets the RTC seconds counter.
+ */
+int aica_rtc_settimeofday(const time_t secs) {
+ unsigned long val1, val2;
+ unsigned long adj = secs + TWENTY_YEARS;
+
+ do {
+ ctrl_outl((adj & 0xffff0000) >> 16, AICA_RTC_SECS_H);
+ ctrl_outl((adj & 0xffff), AICA_RTC_SECS_L);
+
+ val1 = ((ctrl_inl(AICA_RTC_SECS_H) & 0xffff) << 16) |
+ (ctrl_inl(AICA_RTC_SECS_L) & 0xffff);
+
+ val2 = ((ctrl_inl(AICA_RTC_SECS_H) & 0xffff) << 16) |
+ (ctrl_inl(AICA_RTC_SECS_L) & 0xffff);
+ } while (val1 != val2);
+
+ return 0;
+}
+
+void aica_time_init(void)
+{
+ rtc_get_time = aica_rtc_gettimeofday;
+ rtc_set_time = aica_rtc_settimeofday;
+}
+
diff --git a/arch/sh/boards/dreamcast/setup.c b/arch/sh/boards/dreamcast/setup.c
new file mode 100644
index 000000000000..55dece35cde5
--- /dev/null
+++ b/arch/sh/boards/dreamcast/setup.c
@@ -0,0 +1,83 @@
+/*
+ * arch/sh/boards/dreamcast/setup.c
+ *
+ * Hardware support for the Sega Dreamcast.
+ *
+ * Copyright (c) 2001, 2002 M. R. Brown <mrbrown@linuxdc.org>
+ * Copyright (c) 2002, 2003, 2004 Paul Mundt <lethal@linux-sh.org>
+ *
+ * This file is part of the LinuxDC project (www.linuxdc.org)
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * This file originally bore the message (with enclosed-$):
+ * Id: setup_dc.c,v 1.5 2001/05/24 05:09:16 mrbrown Exp
+ * SEGA Dreamcast support
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/device.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/machvec.h>
+#include <asm/machvec_init.h>
+#include <asm/mach/sysasic.h>
+
+extern struct hw_interrupt_type systemasic_int;
+/* XXX: Move this into it's proper header. */
+extern void (*board_time_init)(void);
+extern void aica_time_init(void);
+extern int gapspci_init(void);
+extern int systemasic_irq_demux(int);
+
+void *dreamcast_consistent_alloc(struct device *, size_t, dma_addr_t *, int);
+int dreamcast_consistent_free(struct device *, size_t, void *, dma_addr_t);
+
+const char *get_system_type(void)
+{
+ return "Sega Dreamcast";
+}
+
+struct sh_machine_vector mv_dreamcast __initmv = {
+ .mv_nr_irqs = NR_IRQS,
+
+ .mv_irq_demux = systemasic_irq_demux,
+
+#ifdef CONFIG_PCI
+ .mv_consistent_alloc = dreamcast_consistent_alloc,
+ .mv_consistent_free = dreamcast_consistent_free,
+#endif
+};
+ALIAS_MV(dreamcast)
+
+int __init platform_setup(void)
+{
+ int i;
+
+ /* Mask all hardware events */
+ /* XXX */
+
+ /* Acknowledge any previous events */
+ /* XXX */
+
+ __set_io_port_base(0xa0000000);
+
+ /* Assign all virtual IRQs to the System ASIC int. handler */
+ for (i = HW_EVENT_IRQ_BASE; i < HW_EVENT_IRQ_MAX; i++)
+ irq_desc[i].handler = &systemasic_int;
+
+ board_time_init = aica_time_init;
+
+#ifdef CONFIG_PCI
+ if (gapspci_init() < 0)
+ printk(KERN_WARNING "GAPSPCI was not detected.\n");
+#endif
+
+ return 0;
+}
diff --git a/arch/sh/boards/ec3104/Makefile b/arch/sh/boards/ec3104/Makefile
new file mode 100644
index 000000000000..178891534b67
--- /dev/null
+++ b/arch/sh/boards/ec3104/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the EC3104 specific parts of the kernel
+#
+
+obj-y := setup.o io.o irq.o
+
diff --git a/arch/sh/boards/ec3104/io.c b/arch/sh/boards/ec3104/io.c
new file mode 100644
index 000000000000..a70928c44753
--- /dev/null
+++ b/arch/sh/boards/ec3104/io.c
@@ -0,0 +1,81 @@
+/*
+ * linux/arch/sh/kernel/io_ec3104.c
+ * EC3104 companion chip support
+ *
+ * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *
+ */
+/* EC3104 note:
+ * This code was written without any documentation about the EC3104 chip. While
+ * I hope I got most of the basic functionality right, the register names I use
+ * are most likely completely different from those in the chip documentation.
+ *
+ * If you have any further information about the EC3104, please tell me
+ * (prumpf@tux.org).
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/ec3104/ec3104.h>
+
+/*
+ * EC3104 has a real ISA bus which we redirect low port accesses to (the
+ * actual device on mine is a ESS 1868, and I don't want to hack the driver
+ * more than strictly necessary). I am not going to duplicate the
+ * hard coding of PC addresses (for the 16550s aso) here though; it's just
+ * too ugly.
+ */
+
+#define low_port(port) ((port) < 0x10000)
+
+static inline unsigned long port2addr(unsigned long port)
+{
+ switch(port >> 16) {
+ case 0:
+ return EC3104_ISA_BASE + port * 2;
+
+ /* XXX hack. it's unclear what to do about the serial ports */
+ case 1:
+ return EC3104_BASE + (port&0xffff) * 4;
+
+ default:
+ /* XXX PCMCIA */
+ return 0;
+ }
+}
+
+unsigned char ec3104_inb(unsigned long port)
+{
+ u8 ret;
+
+ ret = *(volatile u8 *)port2addr(port);
+
+ return ret;
+}
+
+unsigned short ec3104_inw(unsigned long port)
+{
+ BUG();
+}
+
+unsigned long ec3104_inl(unsigned long port)
+{
+ BUG();
+}
+
+void ec3104_outb(unsigned char data, unsigned long port)
+{
+ *(volatile u8 *)port2addr(port) = data;
+}
+
+void ec3104_outw(unsigned short data, unsigned long port)
+{
+ BUG();
+}
+
+void ec3104_outl(unsigned long data, unsigned long port)
+{
+ BUG();
+}
diff --git a/arch/sh/boards/ec3104/irq.c b/arch/sh/boards/ec3104/irq.c
new file mode 100644
index 000000000000..ffa4ff1f090f
--- /dev/null
+++ b/arch/sh/boards/ec3104/irq.c
@@ -0,0 +1,196 @@
+/*
+ * linux/arch/sh/boards/ec3104/irq.c
+ * EC3104 companion chip support
+ *
+ * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *
+ */
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/ec3104/ec3104.h>
+
+/* This is for debugging mostly; here's the table that I intend to keep
+ * in here:
+ *
+ * index function base addr power interrupt bit
+ * 0 power b0ec0000 --- 00000001 (unused)
+ * 1 irqs b0ec1000 --- 00000002 (unused)
+ * 2 ?? b0ec2000 b0ec0008 00000004
+ * 3 PS2 (1) b0ec3000 b0ec000c 00000008
+ * 4 PS2 (2) b0ec4000 b0ec0010 00000010
+ * 5 ?? b0ec5000 b0ec0014 00000020
+ * 6 I2C b0ec6000 b0ec0018 00000040
+ * 7 serial (1) b0ec7000 b0ec001c 00000080
+ * 8 serial (2) b0ec8000 b0ec0020 00000100
+ * 9 serial (3) b0ec9000 b0ec0024 00000200
+ * 10 serial (4) b0eca000 b0ec0028 00000400
+ * 12 GPIO (1) b0ecc000 b0ec0030
+ * 13 GPIO (2) b0ecc000 b0ec0030
+ * 16 pcmcia (1) b0ed0000 b0ec0040 00010000
+ * 17 pcmcia (2) b0ed1000 b0ec0044 00020000
+ */
+
+/* I used the register names from another interrupt controller I worked with,
+ * since it seems to be identical to the ec3104 except that all bits are
+ * inverted:
+ *
+ * IRR: Interrupt Request Register (pending and enabled interrupts)
+ * IMR: Interrupt Mask Register (which interrupts are enabled)
+ * IPR: Interrupt Pending Register (pending interrupts, even disabled ones)
+ *
+ * 0 bits mean pending or enabled, 1 bits mean not pending or disabled. all
+ * IRQs seem to be level-triggered.
+ */
+
+#define EC3104_IRR (EC3104_BASE + 0x1000)
+#define EC3104_IMR (EC3104_BASE + 0x1004)
+#define EC3104_IPR (EC3104_BASE + 0x1008)
+
+#define ctrl_readl(addr) (*(volatile u32 *)(addr))
+#define ctrl_writel(data,addr) (*(volatile u32 *)(addr) = (data))
+#define ctrl_readb(addr) (*(volatile u8 *)(addr))
+
+static char *ec3104_name(unsigned index)
+{
+ switch(index) {
+ case 0:
+ return "power management";
+ case 1:
+ return "interrupts";
+ case 3:
+ return "PS2 (1)";
+ case 4:
+ return "PS2 (2)";
+ case 5:
+ return "I2C (1)";
+ case 6:
+ return "I2C (2)";
+ case 7:
+ return "serial (1)";
+ case 8:
+ return "serial (2)";
+ case 9:
+ return "serial (3)";
+ case 10:
+ return "serial (4)";
+ case 16:
+ return "pcmcia (1)";
+ case 17:
+ return "pcmcia (2)";
+ default: {
+ static char buf[32];
+
+ sprintf(buf, "unknown (%d)", index);
+
+ return buf;
+ }
+ }
+}
+
+int get_pending_interrupts(char *buf)
+{
+ u32 ipr;
+ u32 bit;
+ char *p = buf;
+
+ p += sprintf(p, "pending: (");
+
+ ipr = ctrl_inl(EC3104_IPR);
+
+ for (bit = 1; bit < 32; bit++)
+ if (!(ipr & (1<<bit)))
+ p += sprintf(p, "%s ", ec3104_name(bit));
+
+ p += sprintf(p, ")\n");
+
+ return p - buf;
+}
+
+static inline u32 ec3104_irq2mask(unsigned int irq)
+{
+ return (1 << (irq - EC3104_IRQBASE));
+}
+
+static inline void mask_ec3104_irq(unsigned int irq)
+{
+ u32 mask;
+
+ mask = ctrl_readl(EC3104_IMR);
+
+ mask |= ec3104_irq2mask(irq);
+
+ ctrl_writel(mask, EC3104_IMR);
+}
+
+static inline void unmask_ec3104_irq(unsigned int irq)
+{
+ u32 mask;
+
+ mask = ctrl_readl(EC3104_IMR);
+
+ mask &= ~ec3104_irq2mask(irq);
+
+ ctrl_writel(mask, EC3104_IMR);
+}
+
+static void disable_ec3104_irq(unsigned int irq)
+{
+ mask_ec3104_irq(irq);
+}
+
+static void enable_ec3104_irq(unsigned int irq)
+{
+ unmask_ec3104_irq(irq);
+}
+
+static void mask_and_ack_ec3104_irq(unsigned int irq)
+{
+ mask_ec3104_irq(irq);
+}
+
+static void end_ec3104_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ unmask_ec3104_irq(irq);
+}
+
+static unsigned int startup_ec3104_irq(unsigned int irq)
+{
+ unmask_ec3104_irq(irq);
+
+ return 0;
+}
+
+static void shutdown_ec3104_irq(unsigned int irq)
+{
+ mask_ec3104_irq(irq);
+
+}
+
+static struct hw_interrupt_type ec3104_int = {
+ .typename = "EC3104",
+ .enable = enable_ec3104_irq,
+ .disable = disable_ec3104_irq,
+ .ack = mask_and_ack_ec3104_irq,
+ .end = end_ec3104_irq,
+ .startup = startup_ec3104_irq,
+ .shutdown = shutdown_ec3104_irq,
+};
+
+/* Yuck. the _demux API is ugly */
+int ec3104_irq_demux(int irq)
+{
+ if (irq == EC3104_IRQ) {
+ unsigned int mask;
+
+ mask = ctrl_readl(EC3104_IRR);
+
+ if (mask == 0xffffffff)
+ return EC3104_IRQ;
+ else
+ return EC3104_IRQBASE + ffz(mask);
+ }
+
+ return irq;
+}
diff --git a/arch/sh/boards/ec3104/setup.c b/arch/sh/boards/ec3104/setup.c
new file mode 100644
index 000000000000..5130ba2b6ff1
--- /dev/null
+++ b/arch/sh/boards/ec3104/setup.c
@@ -0,0 +1,78 @@
+/*
+ * linux/arch/sh/boards/ec3104/setup.c
+ * EC3104 companion chip support
+ *
+ * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ *
+ */
+/* EC3104 note:
+ * This code was written without any documentation about the EC3104 chip. While
+ * I hope I got most of the basic functionality right, the register names I use
+ * are most likely completely different from those in the chip documentation.
+ *
+ * If you have any further information about the EC3104, please tell me
+ * (prumpf@tux.org).
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/types.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/machvec.h>
+#include <asm/mach/ec3104.h>
+
+const char *get_system_type(void)
+{
+ return "EC3104";
+}
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_ec3104 __initmv = {
+ .mv_nr_irqs = 96,
+
+ .mv_inb = ec3104_inb,
+ .mv_inw = ec3104_inw,
+ .mv_inl = ec3104_inl,
+ .mv_outb = ec3104_outb,
+ .mv_outw = ec3104_outw,
+ .mv_outl = ec3104_outl,
+
+ .mv_irq_demux = ec3104_irq_demux,
+};
+
+ALIAS_MV(ec3104)
+
+int __init platform_setup(void)
+{
+ char str[8];
+ int i;
+
+ if (0)
+ return 0;
+
+ for (i=0; i<8; i++)
+ str[i] = ctrl_readb(EC3104_BASE + i);
+
+ for (i = EC3104_IRQBASE; i < EC3104_IRQBASE + 32; i++)
+ irq_desc[i].handler = &ec3104_int;
+
+ printk("initializing EC3104 \"%.8s\" at %08x, IRQ %d, IRQ base %d\n",
+ str, EC3104_BASE, EC3104_IRQ, EC3104_IRQBASE);
+
+
+ /* mask all interrupts. this should have been done by the boot
+ * loader for us but we want to be sure ... */
+ ctrl_writel(0xffffffff, EC3104_IMR);
+
+ return 0;
+}
+
diff --git a/arch/sh/boards/harp/Makefile b/arch/sh/boards/harp/Makefile
new file mode 100644
index 000000000000..eb753d31812e
--- /dev/null
+++ b/arch/sh/boards/harp/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for STMicroelectronics board specific parts of the kernel
+#
+
+obj-y := irq.o setup.o mach.o led.o
+
+obj-$(CONFIG_PCI) += pcidma.o
+
diff --git a/arch/sh/boards/harp/irq.c b/arch/sh/boards/harp/irq.c
new file mode 100644
index 000000000000..acd58489970f
--- /dev/null
+++ b/arch/sh/boards/harp/irq.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Looks after interrupts on the HARP board.
+ *
+ * Bases on the IPR irq system
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/harp/harp.h>
+
+
+#define NUM_EXTERNAL_IRQS 16
+
+// Early versions of the STB1 Overdrive required this nasty frig
+//#define INVERT_INTMASK_WRITES
+
+static void enable_harp_irq(unsigned int irq);
+static void disable_harp_irq(unsigned int irq);
+
+/* shutdown is same as "disable" */
+#define shutdown_harp_irq disable_harp_irq
+
+static void mask_and_ack_harp(unsigned int);
+static void end_harp_irq(unsigned int irq);
+
+static unsigned int startup_harp_irq(unsigned int irq)
+{
+ enable_harp_irq(irq);
+ return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type harp_irq_type = {
+ "Harp-IRQ",
+ startup_harp_irq,
+ shutdown_harp_irq,
+ enable_harp_irq,
+ disable_harp_irq,
+ mask_and_ack_harp,
+ end_harp_irq
+};
+
+static void disable_harp_irq(unsigned int irq)
+{
+ unsigned val, flags;
+ unsigned maskReg;
+ unsigned mask;
+ int pri;
+
+ if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
+ return;
+
+ pri = 15 - irq;
+
+ if (pri < 8) {
+ maskReg = EPLD_INTMASK0;
+ } else {
+ maskReg = EPLD_INTMASK1;
+ pri -= 8;
+ }
+
+ local_irq_save(flags);
+ mask = ctrl_inl(maskReg);
+ mask &= (~(1 << pri));
+#if defined(INVERT_INTMASK_WRITES)
+ mask ^= 0xff;
+#endif
+ ctrl_outl(mask, maskReg);
+ local_irq_restore(flags);
+}
+
+static void enable_harp_irq(unsigned int irq)
+{
+ unsigned flags;
+ unsigned maskReg;
+ unsigned mask;
+ int pri;
+
+ if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
+ return;
+
+ pri = 15 - irq;
+
+ if (pri < 8) {
+ maskReg = EPLD_INTMASK0;
+ } else {
+ maskReg = EPLD_INTMASK1;
+ pri -= 8;
+ }
+
+ local_irq_save(flags);
+ mask = ctrl_inl(maskReg);
+
+
+ mask |= (1 << pri);
+
+#if defined(INVERT_INTMASK_WRITES)
+ mask ^= 0xff;
+#endif
+ ctrl_outl(mask, maskReg);
+
+ local_irq_restore(flags);
+}
+
+/* This functions sets the desired irq handler to be an overdrive type */
+static void __init make_harp_irq(unsigned int irq)
+{
+ disable_irq_nosync(irq);
+ irq_desc[irq].handler = &harp_irq_type;
+ disable_harp_irq(irq);
+}
+
+static void mask_and_ack_harp(unsigned int irq)
+{
+ disable_harp_irq(irq);
+}
+
+static void end_harp_irq(unsigned int irq)
+{
+ enable_harp_irq(irq);
+}
+
+void __init init_harp_irq(void)
+{
+ int i;
+
+#if !defined(INVERT_INTMASK_WRITES)
+ // On the harp these are set to enable an interrupt
+ ctrl_outl(0x00, EPLD_INTMASK0);
+ ctrl_outl(0x00, EPLD_INTMASK1);
+#else
+ // On the Overdrive the data is inverted before being stored in the reg
+ ctrl_outl(0xff, EPLD_INTMASK0);
+ ctrl_outl(0xff, EPLD_INTMASK1);
+#endif
+
+ for (i = 0; i < NUM_EXTERNAL_IRQS; i++) {
+ make_harp_irq(i);
+ }
+}
diff --git a/arch/sh/boards/harp/led.c b/arch/sh/boards/harp/led.c
new file mode 100644
index 000000000000..76ca4ccac703
--- /dev/null
+++ b/arch/sh/boards/harp/led.c
@@ -0,0 +1,52 @@
+/*
+ * linux/arch/sh/stboards/led.c
+ *
+ * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * This file contains ST40STB1 HARP and compatible code.
+ */
+
+#include <linux/config.h>
+#include <asm/io.h>
+#include <asm/harp/harp.h>
+
+/* Harp: Flash LD10 (front pannel) connected to EPLD (IC8) */
+/* Overdrive: Flash LD1 (front panel) connected to EPLD (IC4) */
+/* Works for HARP and overdrive */
+static void mach_led(int position, int value)
+{
+ if (value) {
+ ctrl_outl(EPLD_LED_ON, EPLD_LED);
+ } else {
+ ctrl_outl(EPLD_LED_OFF, EPLD_LED);
+ }
+}
+
+#ifdef CONFIG_HEARTBEAT
+
+#include <linux/sched.h>
+
+/* acts like an actual heart beat -- ie thump-thump-pause... */
+void heartbeat_harp(void)
+{
+ static unsigned cnt = 0, period = 0, dist = 0;
+
+ if (cnt == 0 || cnt == dist)
+ mach_led( -1, 1);
+ else if (cnt == 7 || cnt == dist+7)
+ mach_led( -1, 0);
+
+ if (++cnt > period) {
+ cnt = 0;
+ /* The hyperbolic function below modifies the heartbeat period
+ * length in dependency of the current (5min) load. It goes
+ * through the points f(0)=126, f(1)=86, f(5)=51,
+ * f(inf)->30. */
+ period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+ dist = period / 4;
+ }
+}
+#endif
diff --git a/arch/sh/boards/harp/mach.c b/arch/sh/boards/harp/mach.c
new file mode 100644
index 000000000000..a946dd1674ca
--- /dev/null
+++ b/arch/sh/boards/harp/mach.c
@@ -0,0 +1,62 @@
+/*
+ * linux/arch/sh/boards/harp/mach.c
+ *
+ * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Machine vector for the STMicroelectronics STB1 HARP and compatible boards
+ */
+
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/machvec_init.h>
+#include <asm/hd64465/io.h>
+#include <asm/hd64465/hd64465.h>
+
+void setup_harp(void);
+void init_harp_irq(void);
+void heartbeat_harp(void);
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_harp __initmv = {
+ .mv_nr_irqs = 89 + HD64465_IRQ_NUM,
+
+ .mv_inb = hd64465_inb,
+ .mv_inw = hd64465_inw,
+ .mv_inl = hd64465_inl,
+ .mv_outb = hd64465_outb,
+ .mv_outw = hd64465_outw,
+ .mv_outl = hd64465_outl,
+
+ .mv_inb_p = hd64465_inb_p,
+ .mv_inw_p = hd64465_inw,
+ .mv_inl_p = hd64465_inl,
+ .mv_outb_p = hd64465_outb_p,
+ .mv_outw_p = hd64465_outw,
+ .mv_outl_p = hd64465_outl,
+
+ .mv_insb = hd64465_insb,
+ .mv_insw = hd64465_insw,
+ .mv_insl = hd64465_insl,
+ .mv_outsb = hd64465_outsb,
+ .mv_outsw = hd64465_outsw,
+ .mv_outsl = hd64465_outsl,
+
+ .mv_isa_port2addr = hd64465_isa_port2addr,
+
+#ifdef CONFIG_PCI
+ .mv_init_irq = init_harp_irq,
+#endif
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_harp,
+#endif
+};
+
+ALIAS_MV(harp)
diff --git a/arch/sh/boards/harp/pcidma.c b/arch/sh/boards/harp/pcidma.c
new file mode 100644
index 000000000000..475311390fd6
--- /dev/null
+++ b/arch/sh/boards/harp/pcidma.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Dynamic DMA mapping support.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+
+
+void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+ dma_addr_t * dma_handle)
+{
+ void *ret;
+ int gfp = GFP_ATOMIC;
+
+ ret = (void *) __get_free_pages(gfp, get_order(size));
+
+ if (ret != NULL) {
+ /* Is it neccessary to do the memset? */
+ memset(ret, 0, size);
+ *dma_handle = virt_to_bus(ret);
+ }
+ /* We must flush the cache before we pass it on to the device */
+ flush_cache_all();
+ return P2SEGADDR(ret);
+}
+
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
+{
+ unsigned long p1addr=P1SEGADDR((unsigned long)vaddr);
+
+ free_pages(p1addr, get_order(size));
+}
diff --git a/arch/sh/boards/harp/setup.c b/arch/sh/boards/harp/setup.c
new file mode 100644
index 000000000000..05b01b8f40aa
--- /dev/null
+++ b/arch/sh/boards/harp/setup.c
@@ -0,0 +1,91 @@
+/*
+ * arch/sh/stboard/setup.c
+ *
+ * Copyright (C) 2001 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * STMicroelectronics ST40STB1 HARP and compatible support.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/harp/harp.h>
+
+const char *get_system_type(void)
+{
+ return "STB1 Harp";
+}
+
+/*
+ * Initialize the board
+ */
+int __init platform_setup(void)
+{
+#ifdef CONFIG_SH_STB1_HARP
+ unsigned long ic8_version, ic36_version;
+
+ ic8_version = ctrl_inl(EPLD_REVID2);
+ ic36_version = ctrl_inl(EPLD_REVID1);
+
+ printk("STMicroelectronics STB1 HARP initialisaton\n");
+ printk("EPLD versions: IC8: %d.%02d, IC36: %d.%02d\n",
+ (ic8_version >> 4) & 0xf, ic8_version & 0xf,
+ (ic36_version >> 4) & 0xf, ic36_version & 0xf);
+#elif defined(CONFIG_SH_STB1_OVERDRIVE)
+ unsigned long version;
+
+ version = ctrl_inl(EPLD_REVID);
+
+ printk("STMicroelectronics STB1 Overdrive initialisaton\n");
+ printk("EPLD version: %d.%02d\n",
+ (version >> 4) & 0xf, version & 0xf);
+#else
+#error Undefined machine
+#endif
+
+ /* Currently all STB1 chips have problems with the sleep instruction,
+ * so disable it here.
+ */
+ disable_hlt();
+
+ return 0;
+}
+
+/*
+ * pcibios_map_platform_irq
+ *
+ * This is board specific and returns the IRQ for a given PCI device.
+ * It is used by the PCI code (arch/sh/kernel/st40_pci*)
+ *
+ */
+
+#define HARP_PCI_IRQ 1
+#define HARP_BRIDGE_IRQ 2
+#define OVERDRIVE_SLOT0_IRQ 0
+
+
+int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ switch (slot) {
+#ifdef CONFIG_SH_STB1_HARP
+ case 2: /*This is the PCI slot on the */
+ return HARP_PCI_IRQ;
+ case 1: /* this is the bridge */
+ return HARP_BRIDGE_IRQ;
+#elif defined(CONFIG_SH_STB1_OVERDRIVE)
+ case 1:
+ case 2:
+ case 3:
+ return slot - 1;
+#else
+#error Unknown board
+#endif
+ default:
+ return -1;
+ }
+}
+
diff --git a/arch/sh/boards/hp6xx/hp620/Makefile b/arch/sh/boards/hp6xx/hp620/Makefile
new file mode 100644
index 000000000000..20691dbce347
--- /dev/null
+++ b/arch/sh/boards/hp6xx/hp620/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the HP620 specific parts of the kernel
+#
+
+obj-y := mach.o setup.o
+
diff --git a/arch/sh/boards/hp6xx/hp620/mach.c b/arch/sh/boards/hp6xx/hp620/mach.c
new file mode 100644
index 000000000000..0392d82b4a7b
--- /dev/null
+++ b/arch/sh/boards/hp6xx/hp620/mach.c
@@ -0,0 +1,52 @@
+/*
+ * linux/arch/sh/boards/hp6xx/hp620/mach.c
+ *
+ * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Machine vector for the HP620
+ */
+
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/machvec_init.h>
+
+#include <asm/io.h>
+#include <asm/hd64461/hd64461.h>
+#include <asm/irq.h>
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_hp620 __initmv = {
+ .mv_nr_irqs = HD64461_IRQBASE+HD64461_IRQ_NUM,
+
+ .mv_inb = hd64461_inb,
+ .mv_inw = hd64461_inw,
+ .mv_inl = hd64461_inl,
+ .mv_outb = hd64461_outb,
+ .mv_outw = hd64461_outw,
+ .mv_outl = hd64461_outl,
+
+ .mv_inb_p = hd64461_inb_p,
+ .mv_inw_p = hd64461_inw,
+ .mv_inl_p = hd64461_inl,
+ .mv_outb_p = hd64461_outb_p,
+ .mv_outw_p = hd64461_outw,
+ .mv_outl_p = hd64461_outl,
+
+ .mv_insb = hd64461_insb,
+ .mv_insw = hd64461_insw,
+ .mv_insl = hd64461_insl,
+ .mv_outsb = hd64461_outsb,
+ .mv_outsw = hd64461_outsw,
+ .mv_outsl = hd64461_outsl,
+
+ .mv_irq_demux = hd64461_irq_demux,
+};
+ALIAS_MV(hp620)
diff --git a/arch/sh/boards/hp6xx/hp620/setup.c b/arch/sh/boards/hp6xx/hp620/setup.c
new file mode 100644
index 000000000000..045fc5da7274
--- /dev/null
+++ b/arch/sh/boards/hp6xx/hp620/setup.c
@@ -0,0 +1,45 @@
+/*
+ * linux/arch/sh/boards/hp6xx/hp620/setup.c
+ *
+ * Copyright (C) 2002 Andriy Skulysh, 2005 Kristoffer Ericson
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See Linux/COPYING for more information.
+ *
+ * Setup code for an HP620.
+ * Due to similiarity with hp680/hp690 same inits are done (for now)
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/hd64461/hd64461.h>
+#include <asm/io.h>
+#include <asm/hp6xx/hp6xx.h>
+#include <asm/cpu/dac.h>
+
+const char *get_system_type(void)
+{
+ return "HP620";
+}
+
+int __init platform_setup(void)
+{
+ u16 v;
+
+ v = inw(HD64461_STBCR);
+ v |= HD64461_STBCR_SURTST | HD64461_STBCR_SIRST |
+ HD64461_STBCR_STM1ST | HD64461_STBCR_STM0ST |
+ HD64461_STBCR_SAFEST | HD64461_STBCR_SPC0ST |
+ HD64461_STBCR_SMIAST | HD64461_STBCR_SAFECKE_OST |
+ HD64461_STBCR_SAFECKE_IST;
+ outw(v, HD64461_STBCR);
+
+ v = inw(HD64461_GPADR);
+ v |= HD64461_GPADR_SPEAKER | HD64461_GPADR_PCMCIA0;
+ outw(v, HD64461_GPADR);
+
+ sh_dac_disable(DAC_SPEAKER_VOLUME);
+
+ return 0;
+}
+
diff --git a/arch/sh/boards/hp6xx/hp680/Makefile b/arch/sh/boards/hp6xx/hp680/Makefile
new file mode 100644
index 000000000000..0beef11d9b11
--- /dev/null
+++ b/arch/sh/boards/hp6xx/hp680/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the HP680 specific parts of the kernel
+#
+
+obj-y := mach.o setup.o
+
diff --git a/arch/sh/boards/hp6xx/hp680/mach.c b/arch/sh/boards/hp6xx/hp680/mach.c
new file mode 100644
index 000000000000..d73486136045
--- /dev/null
+++ b/arch/sh/boards/hp6xx/hp680/mach.c
@@ -0,0 +1,53 @@
+/*
+ * linux/arch/sh/boards/hp6xx/hp680/mach.c
+ *
+ * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Machine vector for the HP680
+ */
+
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/machvec_init.h>
+
+#include <asm/io.h>
+#include <asm/hd64461/hd64461.h>
+#include <asm/hp6xx/io.h>
+#include <asm/irq.h>
+
+struct sh_machine_vector mv_hp680 __initmv = {
+ .mv_nr_irqs = HD64461_IRQBASE + HD64461_IRQ_NUM,
+
+ .mv_inb = hd64461_inb,
+ .mv_inw = hd64461_inw,
+ .mv_inl = hd64461_inl,
+ .mv_outb = hd64461_outb,
+ .mv_outw = hd64461_outw,
+ .mv_outl = hd64461_outl,
+
+ .mv_inb_p = hd64461_inb_p,
+ .mv_inw_p = hd64461_inw,
+ .mv_inl_p = hd64461_inl,
+ .mv_outb_p = hd64461_outb_p,
+ .mv_outw_p = hd64461_outw,
+ .mv_outl_p = hd64461_outl,
+
+ .mv_insb = hd64461_insb,
+ .mv_insw = hd64461_insw,
+ .mv_insl = hd64461_insl,
+ .mv_outsb = hd64461_outsb,
+ .mv_outsw = hd64461_outsw,
+ .mv_outsl = hd64461_outsl,
+
+ .mv_readw = hd64461_readw,
+ .mv_writew = hd64461_writew,
+
+ .mv_irq_demux = hd64461_irq_demux,
+};
+
+ALIAS_MV(hp680)
diff --git a/arch/sh/boards/hp6xx/hp680/setup.c b/arch/sh/boards/hp6xx/hp680/setup.c
new file mode 100644
index 000000000000..4170190f2644
--- /dev/null
+++ b/arch/sh/boards/hp6xx/hp680/setup.c
@@ -0,0 +1,41 @@
+/*
+ * linux/arch/sh/boards/hp6xx/hp680/setup.c
+ *
+ * Copyright (C) 2002 Andriy Skulysh
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Setup code for an HP680 (internal peripherials only)
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/hd64461/hd64461.h>
+#include <asm/io.h>
+#include <asm/hp6xx/hp6xx.h>
+#include <asm/cpu/dac.h>
+
+const char *get_system_type(void)
+{
+ return "HP680";
+}
+
+int __init platform_setup(void)
+{
+ u16 v;
+ v = inw(HD64461_STBCR);
+ v |= HD64461_STBCR_SURTST | HD64461_STBCR_SIRST |
+ HD64461_STBCR_STM1ST | HD64461_STBCR_STM0ST |
+ HD64461_STBCR_SAFEST | HD64461_STBCR_SPC0ST |
+ HD64461_STBCR_SMIAST | HD64461_STBCR_SAFECKE_OST |
+ HD64461_STBCR_SAFECKE_IST;
+ outw(v, HD64461_STBCR);
+ v = inw(HD64461_GPADR);
+ v |= HD64461_GPADR_SPEAKER | HD64461_GPADR_PCMCIA0;
+ outw(v, HD64461_GPADR);
+
+ sh_dac_disable(DAC_SPEAKER_VOLUME);
+
+ return 0;
+}
diff --git a/arch/sh/boards/hp6xx/hp690/Makefile b/arch/sh/boards/hp6xx/hp690/Makefile
new file mode 100644
index 000000000000..fbbe95e75f83
--- /dev/null
+++ b/arch/sh/boards/hp6xx/hp690/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the HP690 specific parts of the kernel
+#
+
+obj-y := mach.o
+
diff --git a/arch/sh/boards/hp6xx/hp690/mach.c b/arch/sh/boards/hp6xx/hp690/mach.c
new file mode 100644
index 000000000000..2a4c68783cd6
--- /dev/null
+++ b/arch/sh/boards/hp6xx/hp690/mach.c
@@ -0,0 +1,48 @@
+/*
+ * linux/arch/sh/boards/hp6xx/hp690/mach.c
+ *
+ * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Machine vector for the HP690
+ */
+
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/machvec_init.h>
+
+#include <asm/io.h>
+#include <asm/hd64461/hd64461.h>
+#include <asm/irq.h>
+
+struct sh_machine_vector mv_hp690 __initmv = {
+ .mv_nr_irqs = HD64461_IRQBASE+HD64461_IRQ_NUM,
+
+ .mv_inb = hd64461_inb,
+ .mv_inw = hd64461_inw,
+ .mv_inl = hd64461_inl,
+ .mv_outb = hd64461_outb,
+ .mv_outw = hd64461_outw,
+ .mv_outl = hd64461_outl,
+
+ .mv_inb_p = hd64461_inb_p,
+ .mv_inw_p = hd64461_inw,
+ .mv_inl_p = hd64461_inl,
+ .mv_outb_p = hd64461_outb_p,
+ .mv_outw_p = hd64461_outw,
+ .mv_outl_p = hd64461_outl,
+
+ .mv_insb = hd64461_insb,
+ .mv_insw = hd64461_insw,
+ .mv_insl = hd64461_insl,
+ .mv_outsb = hd64461_outsb,
+ .mv_outsw = hd64461_outsw,
+ .mv_outsl = hd64461_outsl,
+
+ .mv_irq_demux = hd64461_irq_demux,
+};
+ALIAS_MV(hp690)
diff --git a/arch/sh/boards/mpc1211/Makefile b/arch/sh/boards/mpc1211/Makefile
new file mode 100644
index 000000000000..1644ebed78cb
--- /dev/null
+++ b/arch/sh/boards/mpc1211/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the Interface (CTP/PCI/MPC-SH02) specific parts of the kernel
+#
+
+obj-y := setup.o rtc.o led.o
+
+obj-$(CONFIG_PCI) += pci.o
+
diff --git a/arch/sh/boards/mpc1211/led.c b/arch/sh/boards/mpc1211/led.c
new file mode 100644
index 000000000000..0a31beec3465
--- /dev/null
+++ b/arch/sh/boards/mpc1211/led.c
@@ -0,0 +1,64 @@
+/*
+ * linux/arch/sh/kernel/led_mpc1211.c
+ *
+ * Copyright (C) 2001 Saito.K & Jeanne
+ *
+ * This file contains Interface MPC-1211 specific LED code.
+ */
+
+#include <linux/config.h>
+
+static void mach_led(int position, int value)
+{
+ volatile unsigned char* p = (volatile unsigned char*)0xa2000000;
+
+ if (value) {
+ *p |= 1;
+ } else {
+ *p &= ~1;
+ }
+}
+
+#ifdef CONFIG_HEARTBEAT
+
+#include <linux/sched.h>
+
+/* Cycle the LED's in the clasic Knightrider/Sun pattern */
+void heartbeat_mpc1211(void)
+{
+ static unsigned int cnt = 0, period = 0;
+ volatile unsigned char* p = (volatile unsigned char*)0xa2000000;
+ static unsigned bit = 0, up = 1;
+
+ cnt += 1;
+ if (cnt < period) {
+ return;
+ }
+
+ cnt = 0;
+
+ /* Go through the points (roughly!):
+ * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110
+ */
+ period = 110 - ( (300<<FSHIFT)/
+ ((avenrun[0]/5) + (3<<FSHIFT)) );
+
+ if (up) {
+ if (bit == 7) {
+ bit--;
+ up=0;
+ } else {
+ bit ++;
+ }
+ } else {
+ if (bit == 0) {
+ bit++;
+ up=1;
+ } else {
+ bit--;
+ }
+ }
+ *p = 1<<bit;
+
+}
+#endif /* CONFIG_HEARTBEAT */
diff --git a/arch/sh/boards/mpc1211/pci.c b/arch/sh/boards/mpc1211/pci.c
new file mode 100644
index 000000000000..ba3a65439752
--- /dev/null
+++ b/arch/sh/boards/mpc1211/pci.c
@@ -0,0 +1,296 @@
+/*
+ * Low-Level PCI Support for the MPC-1211(CTP/PCI/MPC-SH02)
+ *
+ * (c) 2002-2003 Saito.K & Jeanne
+ *
+ * Dustin McIntire (dustin@sensoria.com)
+ * Derived from arch/i386/kernel/pci-*.c which bore the message:
+ * (c) 1999--2000 Martin Mares <mj@ucw.cz>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+#include <asm/machvec.h>
+#include <asm/io.h>
+#include <asm/mpc1211/pci.h>
+
+static struct resource mpcpci_io_resource = {
+ "MPCPCI IO",
+ 0x00000000,
+ 0xffffffff,
+ IORESOURCE_IO
+};
+
+static struct resource mpcpci_mem_resource = {
+ "MPCPCI mem",
+ 0x00000000,
+ 0xffffffff,
+ IORESOURCE_MEM
+};
+
+static struct pci_ops pci_direct_conf1;
+struct pci_channel board_pci_channels[] = {
+ {&pci_direct_conf1, &mpcpci_io_resource, &mpcpci_mem_resource, 0, 256},
+ {NULL, NULL, NULL, 0, 0},
+};
+
+/*
+ * Direct access to PCI hardware...
+ */
+
+
+#define CONFIG_CMD(bus, devfn, where) (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
+
+/*
+ * Functions for accessing PCI configuration space with type 1 accesses
+ */
+static int pci_conf1_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
+{
+ u32 word;
+ unsigned long flags;
+
+ /*
+ * PCIPDR may only be accessed as 32 bit words,
+ * so we must do byte alignment by hand
+ */
+ local_irq_save(flags);
+ writel(CONFIG_CMD(bus,devfn,where), PCIPAR);
+ word = readl(PCIPDR);
+ local_irq_restore(flags);
+
+ switch (size) {
+ case 1:
+ switch (where & 0x3) {
+ case 3:
+ *value = (u8)(word >> 24);
+ break;
+ case 2:
+ *value = (u8)(word >> 16);
+ break;
+ case 1:
+ *value = (u8)(word >> 8);
+ break;
+ default:
+ *value = (u8)word;
+ break;
+ }
+ break;
+ case 2:
+ switch (where & 0x3) {
+ case 3:
+ *value = (u16)(word >> 24);
+ local_irq_save(flags);
+ writel(CONFIG_CMD(bus,devfn,(where+1)), PCIPAR);
+ word = readl(PCIPDR);
+ local_irq_restore(flags);
+ *value |= ((word & 0xff) << 8);
+ break;
+ case 2:
+ *value = (u16)(word >> 16);
+ break;
+ case 1:
+ *value = (u16)(word >> 8);
+ break;
+ default:
+ *value = (u16)word;
+ break;
+ }
+ break;
+ case 4:
+ *value = word;
+ break;
+ }
+ PCIDBG(4,"pci_conf1_read@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),*value);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+/*
+ * Since MPC-1211 only does 32bit access we'll have to do a read,mask,write operation.
+ * We'll allow an odd byte offset, though it should be illegal.
+ */
+static int pci_conf1_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
+{
+ u32 word,mask = 0;
+ unsigned long flags;
+ u32 shift = (where & 3) * 8;
+
+ if(size == 1) {
+ mask = ((1 << 8) - 1) << shift; // create the byte mask
+ } else if(size == 2){
+ if(shift == 24)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ mask = ((1 << 16) - 1) << shift; // create the word mask
+ }
+ local_irq_save(flags);
+ writel(CONFIG_CMD(bus,devfn,where), PCIPAR);
+ if(size == 4){
+ writel(value, PCIPDR);
+ local_irq_restore(flags);
+ PCIDBG(4,"pci_conf1_write@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),value);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ word = readl(PCIPDR);
+ word &= ~mask;
+ word |= ((value << shift) & mask);
+ writel(word, PCIPDR);
+ local_irq_restore(flags);
+ PCIDBG(4,"pci_conf1_write@0x%08x=0x%x\n", CONFIG_CMD(bus,devfn,where),word);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+#undef CONFIG_CMD
+
+static struct pci_ops pci_direct_conf1 = {
+ .read = pci_conf1_read,
+ .write = pci_conf1_write,
+};
+
+static void __devinit quirk_ali_ide_ports(struct pci_dev *dev)
+{
+ dev->resource[0].start = 0x1f0;
+ dev->resource[0].end = 0x1f7;
+ dev->resource[0].flags = IORESOURCE_IO;
+ dev->resource[1].start = 0x3f6;
+ dev->resource[1].end = 0x3f6;
+ dev->resource[1].flags = IORESOURCE_IO;
+ dev->resource[2].start = 0x170;
+ dev->resource[2].end = 0x177;
+ dev->resource[2].flags = IORESOURCE_IO;
+ dev->resource[3].start = 0x376;
+ dev->resource[3].end = 0x376;
+ dev->resource[3].flags = IORESOURCE_IO;
+ dev->resource[4].start = 0xf000;
+ dev->resource[4].end = 0xf00f;
+ dev->resource[4].flags = IORESOURCE_IO;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, quirk_ali_ide_ports);
+
+char * __devinit pcibios_setup(char *str)
+{
+ return str;
+}
+
+/*
+ * Called after each bus is probed, but before its children
+ * are examined.
+ */
+
+void __init pcibios_fixup_bus(struct pci_bus *b)
+{
+ pci_read_bridge_bases(b);
+}
+
+/*
+ * IRQ functions
+ */
+static inline u8 bridge_swizzle(u8 pin, u8 slot)
+{
+ return (((pin-1) + slot) % 4) + 1;
+}
+
+static inline u8 bridge_swizzle_pci_1(u8 pin, u8 slot)
+{
+ return (((pin-1) - slot) & 3) + 1;
+}
+
+static u8 __init mpc1211_swizzle(struct pci_dev *dev, u8 *pinp)
+{
+ unsigned long flags;
+ u8 pin = *pinp;
+ u32 word;
+
+ for ( ; dev->bus->self; dev = dev->bus->self) {
+ if (!pin)
+ continue;
+
+ if (dev->bus->number == 1) {
+ local_irq_save(flags);
+ writel(0x80000000 | 0x2c, PCIPAR);
+ word = readl(PCIPDR);
+ local_irq_restore(flags);
+ word >>= 16;
+
+ if (word == 0x0001)
+ pin = bridge_swizzle_pci_1(pin, PCI_SLOT(dev->devfn));
+ else
+ pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
+ } else
+ pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
+ }
+
+ *pinp = pin;
+
+ return PCI_SLOT(dev->devfn);
+}
+
+static int __init map_mpc1211_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int irq = -1;
+
+ /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */
+ if (dev->bus->number == 0) {
+ switch (slot) {
+ case 13: irq = 9; break; /* USB */
+ case 22: irq = 10; break; /* LAN */
+ default: irq = 0; break;
+ }
+ } else {
+ switch (pin) {
+ case 0: irq = 0; break;
+ case 1: irq = 7; break;
+ case 2: irq = 9; break;
+ case 3: irq = 10; break;
+ case 4: irq = 11; break;
+ }
+ }
+
+ if( irq < 0 ) {
+ PCIDBG(3, "PCI: Error mapping IRQ on device %s\n", pci_name(dev));
+ return irq;
+ }
+
+ PCIDBG(2, "Setting IRQ for slot %s to %d\n", pci_name(dev), irq);
+
+ return irq;
+}
+
+void __init pcibios_fixup_irqs(void)
+{
+ pci_fixup_irqs(mpc1211_swizzle, map_mpc1211_irq);
+}
+
+void pcibios_align_resource(void *data, struct resource *res,
+ unsigned long size, unsigned long align)
+{
+ unsigned long start = res->start;
+
+ if (res->flags & IORESOURCE_IO) {
+ if (start >= 0x10000UL) {
+ if ((start & 0xffffUL) < 0x4000UL) {
+ start = (start & 0xffff0000UL) + 0x4000UL;
+ } else if ((start & 0xffffUL) >= 0xf000UL) {
+ start = (start & 0xffff0000UL) + 0x10000UL;
+ }
+ res->start = start;
+ } else {
+ if (start & 0x300) {
+ start = (start + 0x3ff) & ~0x3ff;
+ res->start = start;
+ }
+ }
+ }
+}
+
diff --git a/arch/sh/boards/mpc1211/rtc.c b/arch/sh/boards/mpc1211/rtc.c
new file mode 100644
index 000000000000..4d100f048072
--- /dev/null
+++ b/arch/sh/boards/mpc1211/rtc.c
@@ -0,0 +1,152 @@
+/*
+ * linux/arch/sh/kernel/rtc-mpc1211.c -- MPC-1211 on-chip RTC support
+ *
+ * Copyright (C) 2002 Saito.K & Jeanne
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/mc146818rtc.h>
+
+#ifndef BCD_TO_BIN
+#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
+#endif
+
+#ifndef BIN_TO_BCD
+#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
+#endif
+
+/* arc/i386/kernel/time.c */
+unsigned long get_cmos_time(void)
+{
+ unsigned int year, mon, day, hour, min, sec;
+ int i;
+
+ spin_lock(&rtc_lock);
+ /* The Linux interpretation of the CMOS clock register contents:
+ * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+ * RTC registers show the second which has precisely just started.
+ * Let's hope other operating systems interpret the RTC the same way.
+ */
+ /* read RTC exactly on falling edge of update flag */
+ for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
+ if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
+ break;
+ for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
+ if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
+ break;
+ do { /* Isn't this overkill ? UIP above should guarantee consistency */
+ sec = CMOS_READ(RTC_SECONDS);
+ min = CMOS_READ(RTC_MINUTES);
+ hour = CMOS_READ(RTC_HOURS);
+ day = CMOS_READ(RTC_DAY_OF_MONTH);
+ mon = CMOS_READ(RTC_MONTH);
+ year = CMOS_READ(RTC_YEAR);
+ } while (sec != CMOS_READ(RTC_SECONDS));
+ if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ {
+ BCD_TO_BIN(sec);
+ BCD_TO_BIN(min);
+ BCD_TO_BIN(hour);
+ BCD_TO_BIN(day);
+ BCD_TO_BIN(mon);
+ BCD_TO_BIN(year);
+ }
+ spin_unlock(&rtc_lock);
+ if ((year += 1900) < 1970)
+ year += 100;
+ return mktime(year, mon, day, hour, min, sec);
+}
+
+void mpc1211_rtc_gettimeofday(struct timeval *tv)
+{
+
+ tv->tv_sec = get_cmos_time();
+ tv->tv_usec = 0;
+}
+
+/* arc/i386/kernel/time.c */
+/*
+ * In order to set the CMOS clock precisely, set_rtc_mmss has to be
+ * called 500 ms after the second nowtime has started, because when
+ * nowtime is written into the registers of the CMOS clock, it will
+ * jump to the next second precisely 500 ms later. Check the Motorola
+ * MC146818A or Dallas DS12887 data sheet for details.
+ *
+ * BUG: This routine does not handle hour overflow properly; it just
+ * sets the minutes. Usually you'll only notice that after reboot!
+ */
+static int set_rtc_mmss(unsigned long nowtime)
+{
+ int retval = 0;
+ int real_seconds, real_minutes, cmos_minutes;
+ unsigned char save_control, save_freq_select;
+
+ /* gets recalled with irq locally disabled */
+ spin_lock(&rtc_lock);
+ save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
+ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+
+ save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
+ CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+ cmos_minutes = CMOS_READ(RTC_MINUTES);
+ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ BCD_TO_BIN(cmos_minutes);
+
+ /*
+ * since we're only adjusting minutes and seconds,
+ * don't interfere with hour overflow. This avoids
+ * messing with unknown time zones but requires your
+ * RTC not to be off by more than 15 minutes
+ */
+ real_seconds = nowtime % 60;
+ real_minutes = nowtime / 60;
+ if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+ real_minutes += 30; /* correct for half hour time zone */
+ real_minutes %= 60;
+
+ if (abs(real_minutes - cmos_minutes) < 30) {
+ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BIN_TO_BCD(real_seconds);
+ BIN_TO_BCD(real_minutes);
+ }
+ CMOS_WRITE(real_seconds,RTC_SECONDS);
+ CMOS_WRITE(real_minutes,RTC_MINUTES);
+ } else {
+ printk(KERN_WARNING
+ "set_rtc_mmss: can't update from %d to %d\n",
+ cmos_minutes, real_minutes);
+ retval = -1;
+ }
+
+ /* The following flags have to be released exactly in this order,
+ * otherwise the DS12887 (popular MC146818A clone with integrated
+ * battery and quartz) will not reset the oscillator and will not
+ * update precisely 500 ms later. You won't find this mentioned in
+ * the Dallas Semiconductor data sheets, but who believes data
+ * sheets anyway ... -- Markus Kuhn
+ */
+ CMOS_WRITE(save_control, RTC_CONTROL);
+ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+ spin_unlock(&rtc_lock);
+
+ return retval;
+}
+
+int mpc1211_rtc_settimeofday(const struct timeval *tv)
+{
+ unsigned long nowtime = tv->tv_sec;
+
+ return set_rtc_mmss(nowtime);
+}
+
+void mpc1211_time_init(void)
+{
+ rtc_get_time = mpc1211_rtc_gettimeofday;
+ rtc_set_time = mpc1211_rtc_settimeofday;
+}
+
diff --git a/arch/sh/boards/mpc1211/setup.c b/arch/sh/boards/mpc1211/setup.c
new file mode 100644
index 000000000000..2bb581b91683
--- /dev/null
+++ b/arch/sh/boards/mpc1211/setup.c
@@ -0,0 +1,360 @@
+/*
+ * linux/arch/sh/board/mpc1211/setup.c
+ *
+ * Copyright (C) 2002 Saito.K & Jeanne, Fujii.Y
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/machvec.h>
+#include <asm/mpc1211/mpc1211.h>
+#include <asm/mpc1211/pci.h>
+#include <asm/mpc1211/m1543c.h>
+
+
+/* ALI15X3 SMBus address offsets */
+#define SMBHSTSTS (0 + 0x3100)
+#define SMBHSTCNT (1 + 0x3100)
+#define SMBHSTSTART (2 + 0x3100)
+#define SMBHSTCMD (7 + 0x3100)
+#define SMBHSTADD (3 + 0x3100)
+#define SMBHSTDAT0 (4 + 0x3100)
+#define SMBHSTDAT1 (5 + 0x3100)
+#define SMBBLKDAT (6 + 0x3100)
+
+/* Other settings */
+#define MAX_TIMEOUT 500 /* times 1/100 sec */
+
+/* ALI15X3 command constants */
+#define ALI15X3_ABORT 0x04
+#define ALI15X3_T_OUT 0x08
+#define ALI15X3_QUICK 0x00
+#define ALI15X3_BYTE 0x10
+#define ALI15X3_BYTE_DATA 0x20
+#define ALI15X3_WORD_DATA 0x30
+#define ALI15X3_BLOCK_DATA 0x40
+#define ALI15X3_BLOCK_CLR 0x80
+
+/* ALI15X3 status register bits */
+#define ALI15X3_STS_IDLE 0x04
+#define ALI15X3_STS_BUSY 0x08
+#define ALI15X3_STS_DONE 0x10
+#define ALI15X3_STS_DEV 0x20 /* device error */
+#define ALI15X3_STS_COLL 0x40 /* collision or no response */
+#define ALI15X3_STS_TERM 0x80 /* terminated by abort */
+#define ALI15X3_STS_ERR 0xE0 /* all the bad error bits */
+
+const char *get_system_type(void)
+{
+ return "Interface MPC-1211(CTP/PCI/MPC-SH02)";
+}
+
+static void __init pci_write_config(unsigned long busNo,
+ unsigned long devNo,
+ unsigned long fncNo,
+ unsigned long cnfAdd,
+ unsigned long cnfData)
+{
+ ctrl_outl((0x80000000
+ + ((busNo & 0xff) << 16)
+ + ((devNo & 0x1f) << 11)
+ + ((fncNo & 0x07) << 8)
+ + (cnfAdd & 0xfc)), PCIPAR);
+
+ ctrl_outl(cnfData, PCIPDR);
+}
+
+/*
+ Initialize IRQ setting
+*/
+
+static unsigned char m_irq_mask = 0xfb;
+static unsigned char s_irq_mask = 0xff;
+volatile unsigned long irq_err_count;
+
+static void disable_mpc1211_irq(unsigned int irq)
+{
+ unsigned long flags;
+
+ save_and_cli(flags);
+ if( irq < 8) {
+ m_irq_mask |= (1 << irq);
+ outb(m_irq_mask,I8259_M_MR);
+ } else {
+ s_irq_mask |= (1 << (irq - 8));
+ outb(s_irq_mask,I8259_S_MR);
+ }
+ restore_flags(flags);
+
+}
+
+static void enable_mpc1211_irq(unsigned int irq)
+{
+ unsigned long flags;
+
+ save_and_cli(flags);
+
+ if( irq < 8) {
+ m_irq_mask &= ~(1 << irq);
+ outb(m_irq_mask,I8259_M_MR);
+ } else {
+ s_irq_mask &= ~(1 << (irq - 8));
+ outb(s_irq_mask,I8259_S_MR);
+ }
+ restore_flags(flags);
+}
+
+static inline int mpc1211_irq_real(unsigned int irq)
+{
+ int value;
+ int irqmask;
+
+ if ( irq < 8) {
+ irqmask = 1<<irq;
+ outb(0x0b,I8259_M_CR); /* ISR register */
+ value = inb(I8259_M_CR) & irqmask;
+ outb(0x0a,I8259_M_CR); /* back ro the IPR reg */
+ return value;
+ }
+ irqmask = 1<<(irq - 8);
+ outb(0x0b,I8259_S_CR); /* ISR register */
+ value = inb(I8259_S_CR) & irqmask;
+ outb(0x0a,I8259_S_CR); /* back ro the IPR reg */
+ return value;
+}
+
+static void mask_and_ack_mpc1211(unsigned int irq)
+{
+ unsigned long flags;
+
+ save_and_cli(flags);
+
+ if(irq < 8) {
+ if(m_irq_mask & (1<<irq)){
+ if(!mpc1211_irq_real(irq)){
+ irq_err_count++;
+ printk("spurious 8259A interrupt: IRQ %x\n",irq);
+ }
+ } else {
+ m_irq_mask |= (1<<irq);
+ }
+ inb(I8259_M_MR); /* DUMMY */
+ outb(m_irq_mask,I8259_M_MR); /* disable */
+ outb(0x60+irq,I8259_M_CR); /* EOI */
+
+ } else {
+ if(s_irq_mask & (1<<(irq - 8))){
+ if(!mpc1211_irq_real(irq)){
+ irq_err_count++;
+ printk("spurious 8259A interrupt: IRQ %x\n",irq);
+ }
+ } else {
+ s_irq_mask |= (1<<(irq - 8));
+ }
+ inb(I8259_S_MR); /* DUMMY */
+ outb(s_irq_mask,I8259_S_MR); /* disable */
+ outb(0x60+(irq-8),I8259_S_CR); /* EOI */
+ outb(0x60+2,I8259_M_CR);
+ }
+ restore_flags(flags);
+}
+
+static void end_mpc1211_irq(unsigned int irq)
+{
+ enable_mpc1211_irq(irq);
+}
+
+static unsigned int startup_mpc1211_irq(unsigned int irq)
+{
+ enable_mpc1211_irq(irq);
+ return 0;
+}
+
+static void shutdown_mpc1211_irq(unsigned int irq)
+{
+ disable_mpc1211_irq(irq);
+}
+
+static struct hw_interrupt_type mpc1211_irq_type = {
+ .typename = "MPC1211-IRQ",
+ .startup = startup_mpc1211_irq,
+ .shutdown = shutdown_mpc1211_irq,
+ .enable = enable_mpc1211_irq,
+ .disable = disable_mpc1211_irq,
+ .ack = mask_and_ack_mpc1211,
+ .end = end_mpc1211_irq
+};
+
+static void make_mpc1211_irq(unsigned int irq)
+{
+ irq_desc[irq].handler = &mpc1211_irq_type;
+ irq_desc[irq].status = IRQ_DISABLED;
+ irq_desc[irq].action = 0;
+ irq_desc[irq].depth = 1;
+ disable_mpc1211_irq(irq);
+}
+
+int mpc1211_irq_demux(int irq)
+{
+ unsigned int poll;
+
+ if( irq == 2 ) {
+ outb(0x0c,I8259_M_CR);
+ poll = inb(I8259_M_CR);
+ if(poll & 0x80) {
+ irq = (poll & 0x07);
+ }
+ if( irq == 2) {
+ outb(0x0c,I8259_S_CR);
+ poll = inb(I8259_S_CR);
+ irq = (poll & 0x07) + 8;
+ }
+ }
+ return irq;
+}
+
+void __init init_mpc1211_IRQ(void)
+{
+ int i;
+ /*
+ * Super I/O (Just mimic PC):
+ * 1: keyboard
+ * 3: serial 1
+ * 4: serial 0
+ * 5: printer
+ * 6: floppy
+ * 8: rtc
+ * 10: lan
+ * 12: mouse
+ * 14: ide0
+ * 15: ide1
+ */
+
+ pci_write_config(0,0,0,0x54, 0xb0b0002d);
+ outb(0x11, I8259_M_CR); /* mater icw1 edge trigger */
+ outb(0x11, I8259_S_CR); /* slave icw1 edge trigger */
+ outb(0x20, I8259_M_MR); /* m icw2 base vec 0x08 */
+ outb(0x28, I8259_S_MR); /* s icw2 base vec 0x70 */
+ outb(0x04, I8259_M_MR); /* m icw3 slave irq2 */
+ outb(0x02, I8259_S_MR); /* s icw3 slave id */
+ outb(0x01, I8259_M_MR); /* m icw4 non buf normal eoi*/
+ outb(0x01, I8259_S_MR); /* s icw4 non buf normal eo1*/
+ outb(0xfb, I8259_M_MR); /* disable irq0--irq7 */
+ outb(0xff, I8259_S_MR); /* disable irq8--irq15 */
+
+ for ( i=0; i < 16; i++) {
+ if(i != 2) {
+ make_mpc1211_irq(i);
+ }
+ }
+}
+
+/*
+ Initialize the board
+*/
+
+
+static void delay (void)
+{
+ volatile unsigned short tmp;
+ tmp = *(volatile unsigned short *) 0xa0000000;
+}
+
+static void delay1000 (void)
+{
+ int i;
+
+ for (i=0; i<1000; i++)
+ delay ();
+}
+
+static int put_smb_blk(unsigned char *p, int address, int command, int no)
+{
+ int temp;
+ int timeout;
+ int i;
+
+ outb(0xff, SMBHSTSTS);
+ temp = inb(SMBHSTSTS);
+ for (timeout = 0; (timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE); timeout++) {
+ delay1000();
+ temp = inb(SMBHSTSTS);
+ }
+ if (timeout >= MAX_TIMEOUT){
+ return -1;
+ }
+
+ outb(((address & 0x7f) << 1), SMBHSTADD);
+ outb(0xc0, SMBHSTCNT);
+ outb(command & 0xff, SMBHSTCMD);
+ outb(no & 0x1f, SMBHSTDAT0);
+
+ for(i = 1; i <= no; i++) {
+ outb(*p++, SMBBLKDAT);
+ }
+ outb(0xff, SMBHSTSTART);
+
+ temp = inb(SMBHSTSTS);
+ for (timeout = 0; (timeout < MAX_TIMEOUT) && !(temp & (ALI15X3_STS_ERR | ALI15X3_STS_DONE)); timeout++) {
+ delay1000();
+ temp = inb(SMBHSTSTS);
+ }
+ if (timeout >= MAX_TIMEOUT) {
+ return -2;
+ }
+ if ( temp & ALI15X3_STS_ERR ){
+ return -3;
+ }
+ return 0;
+}
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_mpc1211 __initmv = {
+ .mv_nr_irqs = 48,
+ .mv_irq_demux = mpc1211_irq_demux,
+ .mv_init_irq = init_mpc1211_IRQ,
+
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_mpc1211,
+#endif
+};
+
+ALIAS_MV(mpc1211)
+
+/* arch/sh/boards/mpc1211/rtc.c */
+void mpc1211_time_init(void);
+
+int __init platform_setup(void)
+{
+ unsigned char spd_buf[128];
+
+ __set_io_port_base(PA_PCI_IO);
+
+ pci_write_config(0,0,0,0x54, 0xb0b00000);
+
+ do {
+ outb(ALI15X3_ABORT, SMBHSTCNT);
+ spd_buf[0] = 0x0c;
+ spd_buf[1] = 0x43;
+ spd_buf[2] = 0x7f;
+ spd_buf[3] = 0x03;
+ spd_buf[4] = 0x00;
+ spd_buf[5] = 0x03;
+ spd_buf[6] = 0x00;
+ } while (put_smb_blk(spd_buf, 0x69, 0, 7) < 0);
+
+ board_time_init = mpc1211_time_init;
+
+ return 0;
+}
+
diff --git a/arch/sh/boards/overdrive/Makefile b/arch/sh/boards/overdrive/Makefile
new file mode 100644
index 000000000000..1762b59e9279
--- /dev/null
+++ b/arch/sh/boards/overdrive/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the STMicroelectronics Overdrive specific parts of the kernel
+#
+
+obj-y := mach.o setup.o io.o irq.o led.o time.o
+
+obj-$(CONFIG_PCI) += fpga.o galileo.o pcidma.o
+
diff --git a/arch/sh/boards/overdrive/fpga.c b/arch/sh/boards/overdrive/fpga.c
new file mode 100644
index 000000000000..3a1ec9403441
--- /dev/null
+++ b/arch/sh/boards/overdrive/fpga.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * This file handles programming up the Altera Flex10K that interfaces to
+ * the Galileo, and does the PS/2 keyboard and mouse
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+
+#include <asm/overdriver/gt64111.h>
+#include <asm/overdrive/overdrive.h>
+#include <asm/overdrive/fpga.h>
+
+#define FPGA_NotConfigHigh() (*FPGA_ControlReg) = (*FPGA_ControlReg) | ENABLE_FPGA_BIT
+#define FPGA_NotConfigLow() (*FPGA_ControlReg) = (*FPGA_ControlReg) & RESET_FPGA_MASK
+
+/* I need to find out what (if any) the real delay factor here is */
+/* The delay is definately not critical */
+#define long_delay() {int i;for(i=0;i<10000;i++);}
+#define short_delay() {int i;for(i=0;i<100;i++);}
+
+static void __init program_overdrive_fpga(const unsigned char *fpgacode,
+ int size)
+{
+ int timeout = 0;
+ int i, j;
+ unsigned char b;
+ static volatile unsigned char *FPGA_ControlReg =
+ (volatile unsigned char *) (OVERDRIVE_CTRL);
+ static volatile unsigned char *FPGA_ProgramReg =
+ (volatile unsigned char *) (FPGA_DCLK_ADDRESS);
+
+ printk("FPGA: Commencing FPGA Programming\n");
+
+ /* The PCI reset but MUST be low when programming the FPGA !!! */
+ b = (*FPGA_ControlReg) & RESET_PCI_MASK;
+
+ (*FPGA_ControlReg) = b;
+
+ /* Prepare FPGA to program */
+
+ FPGA_NotConfigHigh();
+ long_delay();
+
+ FPGA_NotConfigLow();
+ short_delay();
+
+ while ((*FPGA_ProgramReg & FPGA_NOT_STATUS) != 0) {
+ printk("FPGA: Waiting for NotStatus to go Low ... \n");
+ }
+
+ FPGA_NotConfigHigh();
+
+ /* Wait for FPGA "ready to be programmed" signal */
+ printk("FPGA: Waiting for NotStatus to go high (FPGA ready)... \n");
+
+ for (timeout = 0;
+ (((*FPGA_ProgramReg & FPGA_NOT_STATUS) == 0)
+ && (timeout < FPGA_TIMEOUT)); timeout++);
+
+ /* Check if timeout condition occured - i.e. an error */
+
+ if (timeout == FPGA_TIMEOUT) {
+ printk
+ ("FPGA: Failed to program - Timeout waiting for notSTATUS to go high\n");
+ return;
+ }
+
+ printk("FPGA: Copying data to FPGA ... %d bytes\n", size);
+
+ /* Copy array to FPGA - bit at a time */
+
+ for (i = 0; i < size; i++) {
+ volatile unsigned w = 0;
+
+ for (j = 0; j < 8; j++) {
+ *FPGA_ProgramReg = (fpgacode[i] >> j) & 0x01;
+ short_delay();
+ }
+ if ((i & 0x3ff) == 0) {
+ printk(".");
+ }
+ }
+
+ /* Waiting for CONFDONE to go high - means the program is complete */
+
+ for (timeout = 0;
+ (((*FPGA_ProgramReg & FPGA_CONFDONE) == 0)
+ && (timeout < FPGA_TIMEOUT)); timeout++) {
+
+ *FPGA_ProgramReg = 0x0;
+ long_delay();
+ }
+
+ if (timeout == FPGA_TIMEOUT) {
+ printk
+ ("FPGA: Failed to program - Timeout waiting for CONFDONE to go high\n");
+ return;
+ } else { /* Clock another 10 times - gets the device into a working state */
+ for (i = 0; i < 10; i++) {
+ *FPGA_ProgramReg = 0x0;
+ short_delay();
+ }
+ }
+
+ printk("FPGA: Programming complete\n");
+}
+
+
+static const unsigned char __init fpgacode[] = {
+#include "./overdrive.ttf" /* Code from maxplus2 compiler */
+ , 0, 0
+};
+
+
+int __init init_overdrive_fpga(void)
+{
+ program_overdrive_fpga(fpgacode, sizeof(fpgacode));
+
+ return 0;
+}
diff --git a/arch/sh/boards/overdrive/galileo.c b/arch/sh/boards/overdrive/galileo.c
new file mode 100644
index 000000000000..276fa11ee4ce
--- /dev/null
+++ b/arch/sh/boards/overdrive/galileo.c
@@ -0,0 +1,588 @@
+/*
+ * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * This file contains the PCI routines required for the Galileo GT6411
+ * PCI bridge as used on the Orion and Overdrive boards.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+
+#include <asm/overdrive/overdrive.h>
+#include <asm/overdrive/gt64111.h>
+
+
+/* After boot, we shift the Galileo registers so that they appear
+ * in BANK6, along with IO space. This means we can have one contingous
+ * lump of PCI address space without these registers appearing in the
+ * middle of them
+ */
+
+#define GT64111_BASE_ADDRESS 0xbb000000
+#define GT64111_IO_BASE_ADDRESS 0x1000
+/* The GT64111 registers appear at this address to the SH4 after reset */
+#define RESET_GT64111_BASE_ADDRESS 0xb4000000
+
+/* Macros used to access the Galileo registers */
+#define RESET_GT64111_REG(x) (RESET_GT64111_BASE_ADDRESS+x)
+#define GT64111_REG(x) (GT64111_BASE_ADDRESS+x)
+
+#define RESET_GT_WRITE(x,v) writel((v),RESET_GT64111_REG(x))
+
+#define RESET_GT_READ(x) readl(RESET_GT64111_REG(x))
+
+#define GT_WRITE(x,v) writel((v),GT64111_REG(x))
+#define GT_WRITE_BYTE(x,v) writeb((v),GT64111_REG(x))
+#define GT_WRITE_SHORT(x,v) writew((v),GT64111_REG(x))
+
+#define GT_READ(x) readl(GT64111_REG(x))
+#define GT_READ_BYTE(x) readb(GT64111_REG(x))
+#define GT_READ_SHORT(x) readw(GT64111_REG(x))
+
+
+/* Where the various SH banks start at */
+#define SH_BANK4_ADR 0xb0000000
+#define SH_BANK5_ADR 0xb4000000
+#define SH_BANK6_ADR 0xb8000000
+
+/* Masks out everything but lines 28,27,26 */
+#define BANK_SELECT_MASK 0x1c000000
+
+#define SH4_TO_BANK(x) ( (x) & BANK_SELECT_MASK)
+
+/*
+ * Masks used for address conversaion. Bank 6 is used for IO and
+ * has all the address bits zeroed by the FPGA. Special case this
+ */
+#define MEMORY_BANK_MASK 0x1fffffff
+#define IO_BANK_MASK 0x03ffffff
+
+/* Mark bank 6 as the bank used for IO. You can change this in the FPGA code
+ * if you want
+ */
+#define IO_BANK_ADR PCI_GTIO_BASE
+
+/* Will select the correct mask to apply depending on the SH$ address */
+#define SELECT_BANK_MASK(x) \
+ ( (SH4_TO_BANK(x)==SH4_TO_BANK(IO_BANK_ADR)) ? IO_BANK_MASK : MEMORY_BANK_MASK)
+
+/* Converts between PCI space and P2 region */
+#define SH4_TO_PCI(x) ((x)&SELECT_BANK_MASK(x))
+
+/* Various macros for figuring out what to stick in the Galileo registers.
+ * You *really* don't want to figure this stuff out by hand, you always get
+ * it wrong
+ */
+#define GT_MEM_LO_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>21)&0x7ff)
+#define GT_MEM_HI_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>21)&0x7f)
+#define GT_MEM_SUB_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>20)&0xff)
+
+#define PROGRAM_HI_LO(block,a,s) \
+ GT_WRITE(block##_LO_DEC_ADR,GT_MEM_LO_ADR(a));\
+ GT_WRITE(block##_HI_DEC_ADR,GT_MEM_HI_ADR(a+s-1))
+
+#define PROGRAM_SUB_HI_LO(block,a,s) \
+ GT_WRITE(block##_LO_DEC_ADR,GT_MEM_SUB_ADR(a));\
+ GT_WRITE(block##_HI_DEC_ADR,GT_MEM_SUB_ADR(a+s-1))
+
+/* We need to set the size, and the offset register */
+
+#define GT_BAR_MASK(x) ((x)&~0xfff)
+
+/* Macro to set up the BAR in the Galileo. Essentially used for the DRAM */
+#define PROGRAM_GT_BAR(block,a,s) \
+ GT_WRITE(PCI_##block##_BANK_SIZE,GT_BAR_MASK((s-1)));\
+ write_config_to_galileo(PCI_CONFIG_##block##_BASE_ADR,\
+ GT_BAR_MASK(a))
+
+#define DISABLE_GT_BAR(block) \
+ GT_WRITE(PCI_##block##_BANK_SIZE,0),\
+ GT_CONFIG_WRITE(PCI_CONFIG_##block##_BASE_ADR,\
+ 0x80000000)
+
+/* Macros to disable things we are not going to use */
+#define DISABLE_DECODE(x) GT_WRITE(x##_LO_DEC_ADR,0x7ff);\
+ GT_WRITE(x##_HI_DEC_ADR,0x00)
+
+#define DISABLE_SUB_DECODE(x) GT_WRITE(x##_LO_DEC_ADR,0xff);\
+ GT_WRITE(x##_HI_DEC_ADR,0x00)
+
+static void __init reset_pci(void)
+{
+ /* Set RESET_PCI bit high */
+ writeb(readb(OVERDRIVE_CTRL) | ENABLE_PCI_BIT, OVERDRIVE_CTRL);
+ udelay(250);
+
+ /* Set RESET_PCI bit low */
+ writeb(readb(OVERDRIVE_CTRL) & RESET_PCI_MASK, OVERDRIVE_CTRL);
+ udelay(250);
+
+ writeb(readb(OVERDRIVE_CTRL) | ENABLE_PCI_BIT, OVERDRIVE_CTRL);
+ udelay(250);
+}
+
+static int write_config_to_galileo(int where, u32 val);
+#define GT_CONFIG_WRITE(where,val) write_config_to_galileo(where,val)
+
+#define ENABLE_PCI_DRAM
+
+
+#ifdef TEST_DRAM
+/* Test function to check out if the PCI DRAM is working OK */
+static int /* __init */ test_dram(unsigned *base, unsigned size)
+{
+ unsigned *p = base;
+ unsigned *end = (unsigned *) (((unsigned) base) + size);
+ unsigned w;
+
+ for (p = base; p < end; p++) {
+ *p = 0xffffffff;
+ if (*p != 0xffffffff) {
+ printk("AAARGH -write failed!!! at %p is %x\n", p,
+ *p);
+ return 0;
+ }
+ *p = 0x0;
+ if (*p != 0x0) {
+ printk("AAARGH -write failed!!!\n");
+ return 0;
+ }
+ }
+
+ for (p = base; p < end; p++) {
+ *p = (unsigned) p;
+ if (*p != (unsigned) p) {
+ printk("Failed at 0x%p, actually is 0x%x\n", p,
+ *p);
+ return 0;
+ }
+ }
+
+ for (p = base; p < end; p++) {
+ w = ((unsigned) p & 0xffff0000);
+ *p = w | (w >> 16);
+ }
+
+ for (p = base; p < end; p++) {
+ w = ((unsigned) p & 0xffff0000);
+ w |= (w >> 16);
+ if (*p != w) {
+ printk
+ ("Failed at 0x%p, should be 0x%x actually is 0x%x\n",
+ p, w, *p);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+#endif
+
+
+/* Function to set up and initialise the galileo. This sets up the BARS,
+ * maps the DRAM into the address space etc,etc
+ */
+int __init galileo_init(void)
+{
+ reset_pci();
+
+ /* Now shift the galileo regs into this block */
+ RESET_GT_WRITE(INTERNAL_SPACE_DEC,
+ GT_MEM_LO_ADR(GT64111_BASE_ADDRESS));
+
+ /* Should have a sanity check here, that you can read back at the new
+ * address what you just wrote
+ */
+
+ /* Disable decode for all regions */
+ DISABLE_DECODE(RAS10);
+ DISABLE_DECODE(RAS32);
+ DISABLE_DECODE(CS20);
+ DISABLE_DECODE(CS3);
+ DISABLE_DECODE(PCI_IO);
+ DISABLE_DECODE(PCI_MEM0);
+ DISABLE_DECODE(PCI_MEM1);
+
+ /* Disable all BARS */
+ GT_WRITE(BAR_ENABLE_ADR, 0x1ff);
+ DISABLE_GT_BAR(RAS10);
+ DISABLE_GT_BAR(RAS32);
+ DISABLE_GT_BAR(CS20);
+ DISABLE_GT_BAR(CS3);
+
+ /* Tell the BAR where the IO registers now are */
+ GT_CONFIG_WRITE(PCI_CONFIG_INT_REG_IO_ADR,GT_BAR_MASK(
+ (GT64111_IO_BASE_ADDRESS &
+ IO_BANK_MASK)));
+ /* set up a 112 Mb decode */
+ PROGRAM_HI_LO(PCI_MEM0, SH_BANK4_ADR, 112 * 1024 * 1024);
+
+ /* Set up a 32 MB io space decode */
+ PROGRAM_HI_LO(PCI_IO, IO_BANK_ADR, 32 * 1024 * 1024);
+
+#ifdef ENABLE_PCI_DRAM
+ /* Program up the DRAM configuration - there is DRAM only in bank 0 */
+ /* Now set up the DRAM decode */
+ PROGRAM_HI_LO(RAS10, PCI_DRAM_BASE, PCI_DRAM_SIZE);
+ /* And the sub decode */
+ PROGRAM_SUB_HI_LO(RAS0, PCI_DRAM_BASE, PCI_DRAM_SIZE);
+
+ DISABLE_SUB_DECODE(RAS1);
+
+ /* Set refresh rate */
+ GT_WRITE(DRAM_BANK0_PARMS, 0x3f);
+ GT_WRITE(DRAM_CFG, 0x100);
+
+ /* we have to lob off the top bits rememeber!! */
+ PROGRAM_GT_BAR(RAS10, SH4_TO_PCI(PCI_DRAM_BASE), PCI_DRAM_SIZE);
+
+#endif
+
+ /* We are only interested in decoding RAS10 and the Galileo's internal
+ * registers (as IO) on the PCI bus
+ */
+#ifdef ENABLE_PCI_DRAM
+ GT_WRITE(BAR_ENABLE_ADR, (~((1 << 8) | (1 << 3))) & 0x1ff);
+#else
+ GT_WRITE(BAR_ENABLE_ADR, (~(1 << 3)) & 0x1ff);
+#endif
+
+ /* Change the class code to host bridge, it actually powers up
+ * as a memory controller
+ */
+ GT_CONFIG_WRITE(8, 0x06000011);
+
+ /* Allow the galileo to master the PCI bus */
+ GT_CONFIG_WRITE(PCI_COMMAND,
+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+ PCI_COMMAND_IO);
+
+
+#if 0
+ printk("Testing PCI DRAM - ");
+ if(test_dram(PCI_DRAM_BASE,PCI_DRAM_SIZE)) {
+ printk("Passed\n");
+ }else {
+ printk("FAILED\n");
+ }
+#endif
+ return 0;
+
+}
+
+
+#define SET_CONFIG_BITS(bus,devfn,where)\
+ ((1<<31) | ((bus) << 16) | ((devfn) << 8) | ((where) & ~3))
+
+#define CONFIG_CMD(dev, where) SET_CONFIG_BITS((dev)->bus->number,(dev)->devfn,where)
+
+/* This write to the galileo config registers, unlike the functions below, can
+ * be used before the PCI subsystem has started up
+ */
+static int __init write_config_to_galileo(int where, u32 val)
+{
+ GT_WRITE(PCI_CFG_ADR, SET_CONFIG_BITS(0, 0, where));
+
+ GT_WRITE(PCI_CFG_DATA, val);
+ return 0;
+}
+
+/* We exclude the galileo and slot 31, the galileo because I don't know how to stop
+ * the setup code shagging up the setup I have done on it, and 31 because the whole
+ * thing locks up if you try to access that slot (which doesn't exist of course anyway
+ */
+
+#define EXCLUDED_DEV(dev) ((dev->bus->number==0) && ((PCI_SLOT(dev->devfn)==0) || (PCI_SLOT(dev->devfn) == 31)))
+
+static int galileo_read_config_byte(struct pci_dev *dev, int where,
+ u8 * val)
+{
+
+
+ /* I suspect this doesn't work because this drives a special cycle ? */
+ if (EXCLUDED_DEV(dev)) {
+ *val = 0xff;
+ return PCIBIOS_SUCCESSFUL;
+ }
+ /* Start the config cycle */
+ GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
+ /* Read back the result */
+ *val = GT_READ_BYTE(PCI_CFG_DATA + (where & 3));
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int galileo_read_config_word(struct pci_dev *dev, int where,
+ u16 * val)
+{
+
+ if (EXCLUDED_DEV(dev)) {
+ *val = 0xffff;
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
+ *val = GT_READ_SHORT(PCI_CFG_DATA + (where & 2));
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int galileo_read_config_dword(struct pci_dev *dev, int where,
+ u32 * val)
+{
+ if (EXCLUDED_DEV(dev)) {
+ *val = 0xffffffff;
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
+ *val = GT_READ(PCI_CFG_DATA);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int galileo_write_config_byte(struct pci_dev *dev, int where,
+ u8 val)
+{
+ GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
+
+ GT_WRITE_BYTE(PCI_CFG_DATA + (where & 3), val);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int galileo_write_config_word(struct pci_dev *dev, int where,
+ u16 val)
+{
+ GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
+
+ GT_WRITE_SHORT(PCI_CFG_DATA + (where & 2), val);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int galileo_write_config_dword(struct pci_dev *dev, int where,
+ u32 val)
+{
+ GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
+
+ GT_WRITE(PCI_CFG_DATA, val);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops pci_config_ops = {
+ galileo_read_config_byte,
+ galileo_read_config_word,
+ galileo_read_config_dword,
+ galileo_write_config_byte,
+ galileo_write_config_word,
+ galileo_write_config_dword
+};
+
+
+/* Everything hangs off this */
+static struct pci_bus *pci_root_bus;
+
+
+static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin)
+{
+ return PCI_SLOT(dev->devfn);
+}
+
+static int __init map_od_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ /* Slot 1: Galileo
+ * Slot 2: PCI Slot 1
+ * Slot 3: PCI Slot 2
+ * Slot 4: ESS
+ */
+ switch (slot) {
+ case 2:
+ return OVERDRIVE_PCI_IRQ1;
+ case 3:
+ /* Note this assumes you have a hacked card in slot 2 */
+ return OVERDRIVE_PCI_IRQ2;
+ case 4:
+ return OVERDRIVE_ESS_IRQ;
+ default:
+ /* printk("PCI: Unexpected IRQ mapping request for slot %d\n", slot); */
+ return -1;
+ }
+}
+
+
+
+void __init
+pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
+{
+ ranges->io_start -= bus->resource[0]->start;
+ ranges->io_end -= bus->resource[0]->start;
+ ranges->mem_start -= bus->resource[1]->start;
+ ranges->mem_end -= bus->resource[1]->start;
+}
+
+static void __init pci_fixup_ide_bases(struct pci_dev *d)
+{
+ int i;
+
+ /*
+ * PCI IDE controllers use non-standard I/O port decoding, respect it.
+ */
+ if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
+ return;
+ printk("PCI: IDE base address fixup for %s\n", pci_name(d));
+ for(i=0; i<4; i++) {
+ struct resource *r = &d->resource[i];
+ if ((r->start & ~0x80) == 0x374) {
+ r->start |= 2;
+ r->end = r->start;
+ }
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
+
+void __init pcibios_init(void)
+{
+ static struct resource galio,galmem;
+
+ /* Allocate the registers used by the Galileo */
+ galio.flags = IORESOURCE_IO;
+ galio.name = "Galileo GT64011";
+ galmem.flags = IORESOURCE_MEM|IORESOURCE_PREFETCH;
+ galmem.name = "Galileo GT64011 DRAM";
+
+ allocate_resource(&ioport_resource, &galio, 256,
+ GT64111_IO_BASE_ADDRESS,GT64111_IO_BASE_ADDRESS+256, 256, NULL, NULL);
+ allocate_resource(&iomem_resource, &galmem,PCI_DRAM_SIZE,
+ PHYSADDR(PCI_DRAM_BASE), PHYSADDR(PCI_DRAM_BASE)+PCI_DRAM_SIZE,
+ PCI_DRAM_SIZE, NULL, NULL);
+
+ /* ok, do the scan man */
+ pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL);
+
+ pci_assign_unassigned_resources();
+ pci_fixup_irqs(no_swizzle, map_od_irq);
+
+#ifdef TEST_DRAM
+ printk("Testing PCI DRAM - ");
+ if(test_dram(PCI_DRAM_BASE,PCI_DRAM_SIZE)) {
+ printk("Passed\n");
+ }else {
+ printk("FAILED\n");
+ }
+#endif
+
+}
+
+char * __init pcibios_setup(char *str)
+{
+ return str;
+}
+
+
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+
+ u16 cmd, old_cmd;
+ int idx;
+ struct resource *r;
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ old_cmd = cmd;
+ for (idx = 0; idx < 6; idx++) {
+ r = dev->resource + idx;
+ if (!r->start && r->end) {
+ printk(KERN_ERR
+ "PCI: Device %s not available because"
+ " of resource collisions\n",
+ pci_name(dev));
+ return -EINVAL;
+ }
+ if (r->flags & IORESOURCE_IO)
+ cmd |= PCI_COMMAND_IO;
+ if (r->flags & IORESOURCE_MEM)
+ cmd |= PCI_COMMAND_MEMORY;
+ }
+ if (cmd != old_cmd) {
+ printk("PCI: enabling device %s (%04x -> %04x)\n",
+ pci_name(dev), old_cmd, cmd);
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+ return 0;
+
+}
+
+/* We should do some optimisation work here I think. Ok for now though */
+void __init pcibios_fixup_bus(struct pci_bus *bus)
+{
+
+}
+
+void pcibios_align_resource(void *data, struct resource *res,
+ unsigned long size)
+{
+}
+
+void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+ struct resource *res, int resource)
+{
+
+ unsigned long where, size;
+ u32 reg;
+
+
+ printk("PCI: Assigning %3s %08lx to %s\n",
+ res->flags & IORESOURCE_IO ? "IO" : "MEM",
+ res->start, dev->name);
+
+ where = PCI_BASE_ADDRESS_0 + resource * 4;
+ size = res->end - res->start;
+
+ pci_read_config_dword(dev, where, &reg);
+ reg = (reg & size) | (((u32) (res->start - root->start)) & ~size);
+ pci_write_config_dword(dev, where, reg);
+}
+
+
+void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+ printk("PCI: Assigning IRQ %02d to %s\n", irq, dev->name);
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
+
+/*
+ * If we set up a device for bus mastering, we need to check the latency
+ * timer as certain crappy BIOSes forget to set it properly.
+ */
+unsigned int pcibios_max_latency = 255;
+
+void pcibios_set_master(struct pci_dev *dev)
+{
+ u8 lat;
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+ if (lat < 16)
+ lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
+ else if (lat > pcibios_max_latency)
+ lat = pcibios_max_latency;
+ else
+ return;
+ printk("PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
+}
diff --git a/arch/sh/boards/overdrive/io.c b/arch/sh/boards/overdrive/io.c
new file mode 100644
index 000000000000..65f3fd0563d3
--- /dev/null
+++ b/arch/sh/boards/overdrive/io.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * This file contains the I/O routines for use on the overdrive board
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+
+#include <asm/overdrive/overdrive.h>
+
+/*
+ * readX/writeX() are used to access memory mapped devices. On some
+ * architectures the memory mapped IO stuff needs to be accessed
+ * differently. On the SuperH architecture, we just read/write the
+ * memory location directly.
+ */
+
+#define dprintk(x...)
+
+/* Translates an IO address to where it is mapped in memory */
+
+#define io_addr(x) (((unsigned)(x))|PCI_GTIO_BASE)
+
+unsigned char od_inb(unsigned long port)
+{
+dprintk("od_inb(%x)\n", port);
+ return readb(io_addr(port)) & 0xff;
+}
+
+
+unsigned short od_inw(unsigned long port)
+{
+dprintk("od_inw(%x)\n", port);
+ return readw(io_addr(port)) & 0xffff;
+}
+
+unsigned int od_inl(unsigned long port)
+{
+dprintk("od_inl(%x)\n", port);
+ return readl(io_addr(port));
+}
+
+void od_outb(unsigned char value, unsigned long port)
+{
+dprintk("od_outb(%x, %x)\n", value, port);
+ writeb(value, io_addr(port));
+}
+
+void od_outw(unsigned short value, unsigned long port)
+{
+dprintk("od_outw(%x, %x)\n", value, port);
+ writew(value, io_addr(port));
+}
+
+void od_outl(unsigned int value, unsigned long port)
+{
+dprintk("od_outl(%x, %x)\n", value, port);
+ writel(value, io_addr(port));
+}
+
+/* This is horrible at the moment - needs more work to do something sensible */
+#define IO_DELAY() udelay(10)
+
+#define OUT_DELAY(x,type) \
+void od_out##x##_p(unsigned type value,unsigned long port){out##x(value,port);IO_DELAY();}
+
+#define IN_DELAY(x,type) \
+unsigned type od_in##x##_p(unsigned long port) {unsigned type tmp=in##x(port);IO_DELAY();return tmp;}
+
+
+OUT_DELAY(b,char)
+OUT_DELAY(w,short)
+OUT_DELAY(l,int)
+
+IN_DELAY(b,char)
+IN_DELAY(w,short)
+IN_DELAY(l,int)
+
+
+/* Now for the string version of these functions */
+void od_outsb(unsigned long port, const void *addr, unsigned long count)
+{
+ int i;
+ unsigned char *p = (unsigned char *) addr;
+
+ for (i = 0; i < count; i++, p++) {
+ outb(*p, port);
+ }
+}
+
+
+void od_insb(unsigned long port, void *addr, unsigned long count)
+{
+ int i;
+ unsigned char *p = (unsigned char *) addr;
+
+ for (i = 0; i < count; i++, p++) {
+ *p = inb(port);
+ }
+}
+
+/* For the 16 and 32 bit string functions, we have to worry about alignment.
+ * The SH does not do unaligned accesses, so we have to read as bytes and
+ * then write as a word or dword.
+ * This can be optimised a lot more, especially in the case where the data
+ * is aligned
+ */
+
+void od_outsw(unsigned long port, const void *addr, unsigned long count)
+{
+ int i;
+ unsigned short tmp;
+ unsigned char *p = (unsigned char *) addr;
+
+ for (i = 0; i < count; i++, p += 2) {
+ tmp = (*p) | ((*(p + 1)) << 8);
+ outw(tmp, port);
+ }
+}
+
+
+void od_insw(unsigned long port, void *addr, unsigned long count)
+{
+ int i;
+ unsigned short tmp;
+ unsigned char *p = (unsigned char *) addr;
+
+ for (i = 0; i < count; i++, p += 2) {
+ tmp = inw(port);
+ p[0] = tmp & 0xff;
+ p[1] = (tmp >> 8) & 0xff;
+ }
+}
+
+
+void od_outsl(unsigned long port, const void *addr, unsigned long count)
+{
+ int i;
+ unsigned tmp;
+ unsigned char *p = (unsigned char *) addr;
+
+ for (i = 0; i < count; i++, p += 4) {
+ tmp = (*p) | ((*(p + 1)) << 8) | ((*(p + 2)) << 16) |
+ ((*(p + 3)) << 24);
+ outl(tmp, port);
+ }
+}
+
+
+void od_insl(unsigned long port, void *addr, unsigned long count)
+{
+ int i;
+ unsigned tmp;
+ unsigned char *p = (unsigned char *) addr;
+
+ for (i = 0; i < count; i++, p += 4) {
+ tmp = inl(port);
+ p[0] = tmp & 0xff;
+ p[1] = (tmp >> 8) & 0xff;
+ p[2] = (tmp >> 16) & 0xff;
+ p[3] = (tmp >> 24) & 0xff;
+
+ }
+}
diff --git a/arch/sh/boards/overdrive/irq.c b/arch/sh/boards/overdrive/irq.c
new file mode 100644
index 000000000000..23adc6be71e7
--- /dev/null
+++ b/arch/sh/boards/overdrive/irq.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Looks after interrupts on the overdrive board.
+ *
+ * Bases on the IPR irq system
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include <asm/overdrive/overdrive.h>
+
+struct od_data {
+ int overdrive_irq;
+ int irq_mask;
+};
+
+#define NUM_EXTERNAL_IRQS 16
+#define EXTERNAL_IRQ_NOT_IN_USE (-1)
+#define EXTERNAL_IRQ_NOT_ASSIGNED (-1)
+
+/*
+ * This table is used to determine what to program into the FPGA's CT register
+ * for the specified Linux IRQ.
+ *
+ * The irq_mask gives the interrupt number from the PCI board (PCI_Int(6:0))
+ * but is one greater than that because the because the FPGA treats 0
+ * as disabled, a value of 1 asserts PCI_Int0, and so on.
+ *
+ * The overdrive_irq specifies which of the eight interrupt sources generates
+ * that interrupt, and but is multiplied by four to give the bit offset into
+ * the CT register.
+ *
+ * The seven interrupts levels (SH4 IRL's) we have available here is hardwired
+ * by the EPLD. The assignments here of which PCI interrupt generates each
+ * level is arbitary.
+ */
+static struct od_data od_data_table[NUM_EXTERNAL_IRQS] = {
+ /* overdrive_irq , irq_mask */
+ {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 0 */
+ {EXTERNAL_IRQ_NOT_ASSIGNED, 7}, /* 1 */
+ {EXTERNAL_IRQ_NOT_ASSIGNED, 6}, /* 2 */
+ {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 3 */
+ {EXTERNAL_IRQ_NOT_ASSIGNED, 5}, /* 4 */
+ {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 5 */
+ {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 6 */
+ {EXTERNAL_IRQ_NOT_ASSIGNED, 4}, /* 7 */
+ {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 8 */
+ {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 9 */
+ {EXTERNAL_IRQ_NOT_ASSIGNED, 3}, /* 10 */
+ {EXTERNAL_IRQ_NOT_ASSIGNED, 2}, /* 11 */
+ {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 12 */
+ {EXTERNAL_IRQ_NOT_ASSIGNED, 1}, /* 13 */
+ {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 14 */
+ {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE} /* 15 */
+};
+
+static void set_od_data(int overdrive_irq, int irq)
+{
+ if (irq >= NUM_EXTERNAL_IRQS || irq < 0)
+ return;
+ od_data_table[irq].overdrive_irq = overdrive_irq << 2;
+}
+
+static void enable_od_irq(unsigned int irq);
+void disable_od_irq(unsigned int irq);
+
+/* shutdown is same as "disable" */
+#define shutdown_od_irq disable_od_irq
+
+static void mask_and_ack_od(unsigned int);
+static void end_od_irq(unsigned int irq);
+
+static unsigned int startup_od_irq(unsigned int irq)
+{
+ enable_od_irq(irq);
+ return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type od_irq_type = {
+ "Overdrive-IRQ",
+ startup_od_irq,
+ shutdown_od_irq,
+ enable_od_irq,
+ disable_od_irq,
+ mask_and_ack_od,
+ end_od_irq
+};
+
+static void disable_od_irq(unsigned int irq)
+{
+ unsigned val, flags;
+ int overdrive_irq;
+ unsigned mask;
+
+ /* Not a valid interrupt */
+ if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
+ return;
+
+ /* Is is necessary to use a cli here? Would a spinlock not be
+ * mroe efficient?
+ */
+ local_irq_save(flags);
+ overdrive_irq = od_data_table[irq].overdrive_irq;
+ if (overdrive_irq != EXTERNAL_IRQ_NOT_ASSIGNED) {
+ mask = ~(0x7 << overdrive_irq);
+ val = ctrl_inl(OVERDRIVE_INT_CT);
+ val &= mask;
+ ctrl_outl(val, OVERDRIVE_INT_CT);
+ }
+ local_irq_restore(flags);
+}
+
+static void enable_od_irq(unsigned int irq)
+{
+ unsigned val, flags;
+ int overdrive_irq;
+ unsigned mask;
+
+ /* Not a valid interrupt */
+ if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
+ return;
+
+ /* Set priority in OD back to original value */
+ local_irq_save(flags);
+ /* This one is not in use currently */
+ overdrive_irq = od_data_table[irq].overdrive_irq;
+ if (overdrive_irq != EXTERNAL_IRQ_NOT_ASSIGNED) {
+ val = ctrl_inl(OVERDRIVE_INT_CT);
+ mask = ~(0x7 << overdrive_irq);
+ val &= mask;
+ mask = od_data_table[irq].irq_mask << overdrive_irq;
+ val |= mask;
+ ctrl_outl(val, OVERDRIVE_INT_CT);
+ }
+ local_irq_restore(flags);
+}
+
+
+
+/* this functions sets the desired irq handler to be an overdrive type */
+static void __init make_od_irq(unsigned int irq)
+{
+ disable_irq_nosync(irq);
+ irq_desc[irq].handler = &od_irq_type;
+ disable_od_irq(irq);
+}
+
+
+static void mask_and_ack_od(unsigned int irq)
+{
+ disable_od_irq(irq);
+}
+
+static void end_od_irq(unsigned int irq)
+{
+ enable_od_irq(irq);
+}
+
+void __init init_overdrive_irq(void)
+{
+ int i;
+
+ /* Disable all interrupts */
+ ctrl_outl(0, OVERDRIVE_INT_CT);
+
+ /* Update interrupt pin mode to use encoded interrupts */
+ i = ctrl_inw(INTC_ICR);
+ i &= ~INTC_ICR_IRLM;
+ ctrl_outw(i, INTC_ICR);
+
+ for (i = 0; i < NUM_EXTERNAL_IRQS; i++) {
+ if (od_data_table[i].irq_mask != EXTERNAL_IRQ_NOT_IN_USE) {
+ make_od_irq(i);
+ } else if (i != 15) { // Cannot use imask on level 15
+ make_imask_irq(i);
+ }
+ }
+
+ /* Set up the interrupts */
+ set_od_data(OVERDRIVE_PCI_INTA, OVERDRIVE_PCI_IRQ1);
+ set_od_data(OVERDRIVE_PCI_INTB, OVERDRIVE_PCI_IRQ2);
+ set_od_data(OVERDRIVE_AUDIO_INT, OVERDRIVE_ESS_IRQ);
+}
diff --git a/arch/sh/boards/overdrive/led.c b/arch/sh/boards/overdrive/led.c
new file mode 100644
index 000000000000..734742e92279
--- /dev/null
+++ b/arch/sh/boards/overdrive/led.c
@@ -0,0 +1,59 @@
+/*
+ * linux/arch/sh/overdrive/led.c
+ *
+ * Copyright (C) 1999 Stuart Menefy <stuart.menefy@st.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * This file contains an Overdrive specific LED feature.
+ */
+
+#include <linux/config.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/overdrive/overdrive.h>
+
+static void mach_led(int position, int value)
+{
+ unsigned long flags;
+ unsigned long reg;
+
+ local_irq_save(flags);
+
+ reg = readl(OVERDRIVE_CTRL);
+ if (value) {
+ reg |= (1<<3);
+ } else {
+ reg &= ~(1<<3);
+ }
+ writel(reg, OVERDRIVE_CTRL);
+
+ local_irq_restore(flags);
+}
+
+#ifdef CONFIG_HEARTBEAT
+
+#include <linux/sched.h>
+
+/* acts like an actual heart beat -- ie thump-thump-pause... */
+void heartbeat_od(void)
+{
+ static unsigned cnt = 0, period = 0, dist = 0;
+
+ if (cnt == 0 || cnt == dist)
+ mach_led( -1, 1);
+ else if (cnt == 7 || cnt == dist+7)
+ mach_led( -1, 0);
+
+ if (++cnt > period) {
+ cnt = 0;
+ /* The hyperbolic function below modifies the heartbeat period
+ * length in dependency of the current (5min) load. It goes
+ * through the points f(0)=126, f(1)=86, f(5)=51,
+ * f(inf)->30. */
+ period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+ dist = period / 4;
+ }
+}
+#endif /* CONFIG_HEARTBEAT */
diff --git a/arch/sh/boards/overdrive/mach.c b/arch/sh/boards/overdrive/mach.c
new file mode 100644
index 000000000000..2834a03ae477
--- /dev/null
+++ b/arch/sh/boards/overdrive/mach.c
@@ -0,0 +1,62 @@
+/*
+ * linux/arch/sh/overdrive/mach.c
+ *
+ * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Machine vector for the STMicroelectronics Overdrive
+ */
+
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/machvec_init.h>
+
+#include <asm/io_unknown.h>
+#include <asm/io_generic.h>
+#include <asm/overdrive/io.h>
+
+void heartbeat_od(void);
+void init_overdrive_irq(void);
+void galileo_pcibios_init(void);
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_od __initmv = {
+ .mv_nr_irqs = 48,
+
+ .mv_inb = od_inb,
+ .mv_inw = od_inw,
+ .mv_inl = od_inl,
+ .mv_outb = od_outb,
+ .mv_outw = od_outw,
+ .mv_outl = od_outl,
+
+ .mv_inb_p = od_inb_p,
+ .mv_inw_p = od_inw_p,
+ .mv_inl_p = od_inl_p,
+ .mv_outb_p = od_outb_p,
+ .mv_outw_p = od_outw_p,
+ .mv_outl_p = od_outl_p,
+
+ .mv_insb = od_insb,
+ .mv_insw = od_insw,
+ .mv_insl = od_insl,
+ .mv_outsb = od_outsb,
+ .mv_outsw = od_outsw,
+ .mv_outsl = od_outsl,
+
+#ifdef CONFIG_PCI
+ .mv_init_irq = init_overdrive_irq,
+#endif
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_od,
+#endif
+};
+
+ALIAS_MV(od)
diff --git a/arch/sh/boards/overdrive/pcidma.c b/arch/sh/boards/overdrive/pcidma.c
new file mode 100644
index 000000000000..1c9bfeda00b7
--- /dev/null
+++ b/arch/sh/boards/overdrive/pcidma.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Dynamic DMA mapping support.
+ *
+ * On the overdrive, we can only DMA from memory behind the PCI bus!
+ * this means that all DMA'able memory must come from there.
+ * this restriction will not apply to later boards.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+ dma_addr_t * dma_handle)
+{
+ void *ret;
+ int gfp = GFP_ATOMIC;
+
+ printk("BUG: pci_alloc_consistent() called - not yet supported\n");
+ /* We ALWAYS need DMA memory on the overdrive hardware,
+ * due to it's extreme weirdness
+ * Need to flush the cache here as well, since the memory
+ * can still be seen through the cache!
+ */
+ gfp |= GFP_DMA;
+ ret = (void *) __get_free_pages(gfp, get_order(size));
+
+ if (ret != NULL) {
+ memset(ret, 0, size);
+ *dma_handle = virt_to_bus(ret);
+ }
+ return ret;
+}
+
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
+{
+ free_pages((unsigned long) vaddr, get_order(size));
+}
diff --git a/arch/sh/boards/overdrive/setup.c b/arch/sh/boards/overdrive/setup.c
new file mode 100644
index 000000000000..a36ce0284ed3
--- /dev/null
+++ b/arch/sh/boards/overdrive/setup.c
@@ -0,0 +1,41 @@
+/*
+ * arch/sh/overdrive/setup.c
+ *
+ * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * STMicroelectronics Overdrive Support.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/io.h>
+
+#include <asm/overdrive/overdrive.h>
+#include <asm/overdrive/fpga.h>
+
+extern void od_time_init(void);
+
+const char *get_system_type(void)
+{
+ return "SH7750 Overdrive";
+}
+
+/*
+ * Initialize the board
+ */
+int __init platform_setup(void)
+{
+#ifdef CONFIG_PCI
+ init_overdrive_fpga();
+ galileo_init();
+#endif
+
+ board_time_init = od_time_init;
+
+ /* Enable RS232 receive buffers */
+ writel(0x1e, OVERDRIVE_CTRL);
+}
diff --git a/arch/sh/boards/overdrive/time.c b/arch/sh/boards/overdrive/time.c
new file mode 100644
index 000000000000..68533690e097
--- /dev/null
+++ b/arch/sh/boards/overdrive/time.c
@@ -0,0 +1,119 @@
+/*
+ * arch/sh/boards/overdrive/time.c
+ *
+ * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
+ * Copyright (C) 2002 Paul Mundt (lethal@chaoticdreams.org)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * STMicroelectronics Overdrive Support.
+ */
+
+void od_time_init(void)
+{
+ struct frqcr_data {
+ unsigned short frqcr;
+ struct {
+ unsigned char multiplier;
+ unsigned char divisor;
+ } factor[3];
+ };
+
+ static struct frqcr_data st40_frqcr_table[] = {
+ { 0x000, {{1,1}, {1,1}, {1,2}}},
+ { 0x002, {{1,1}, {1,1}, {1,4}}},
+ { 0x004, {{1,1}, {1,1}, {1,8}}},
+ { 0x008, {{1,1}, {1,2}, {1,2}}},
+ { 0x00A, {{1,1}, {1,2}, {1,4}}},
+ { 0x00C, {{1,1}, {1,2}, {1,8}}},
+ { 0x011, {{1,1}, {2,3}, {1,6}}},
+ { 0x013, {{1,1}, {2,3}, {1,3}}},
+ { 0x01A, {{1,1}, {1,2}, {1,4}}},
+ { 0x01C, {{1,1}, {1,2}, {1,8}}},
+ { 0x023, {{1,1}, {2,3}, {1,3}}},
+ { 0x02C, {{1,1}, {1,2}, {1,8}}},
+ { 0x048, {{1,2}, {1,2}, {1,4}}},
+ { 0x04A, {{1,2}, {1,2}, {1,6}}},
+ { 0x04C, {{1,2}, {1,2}, {1,8}}},
+ { 0x05A, {{1,2}, {1,3}, {1,6}}},
+ { 0x05C, {{1,2}, {1,3}, {1,6}}},
+ { 0x063, {{1,2}, {1,4}, {1,4}}},
+ { 0x06C, {{1,2}, {1,4}, {1,8}}},
+ { 0x091, {{1,3}, {1,3}, {1,6}}},
+ { 0x093, {{1,3}, {1,3}, {1,6}}},
+ { 0x0A3, {{1,3}, {1,6}, {1,6}}},
+ { 0x0DA, {{1,4}, {1,4}, {1,8}}},
+ { 0x0DC, {{1,4}, {1,4}, {1,8}}},
+ { 0x0EC, {{1,4}, {1,8}, {1,8}}},
+ { 0x123, {{1,4}, {1,4}, {1,8}}},
+ { 0x16C, {{1,4}, {1,8}, {1,8}}},
+ };
+
+ struct memclk_data {
+ unsigned char multiplier;
+ unsigned char divisor;
+ };
+ static struct memclk_data st40_memclk_table[8] = {
+ {1,1}, // 000
+ {1,2}, // 001
+ {1,3}, // 010
+ {2,3}, // 011
+ {1,4}, // 100
+ {1,6}, // 101
+ {1,8}, // 110
+ {1,8} // 111
+ };
+
+ unsigned long pvr;
+
+ /*
+ * This should probably be moved into the SH3 probing code, and then
+ * use the processor structure to determine which CPU we are running
+ * on.
+ */
+ pvr = ctrl_inl(CCN_PVR);
+ printk("PVR %08x\n", pvr);
+
+ if (((pvr >> CCN_PVR_CHIP_SHIFT) & CCN_PVR_CHIP_MASK) == CCN_PVR_CHIP_ST40STB1) {
+ /*
+ * Unfortunatly the STB1 FRQCR values are different from the
+ * 7750 ones.
+ */
+ struct frqcr_data *d;
+ int a;
+ unsigned long memclkcr;
+ struct memclk_data *e;
+
+ for (a=0; a<ARRAY_SIZE(st40_frqcr_table); a++) {
+ d = &st40_frqcr_table[a];
+ if (d->frqcr == (frqcr & 0x1ff))
+ break;
+ }
+ if (a == ARRAY_SIZE(st40_frqcr_table)) {
+ d = st40_frqcr_table;
+ printk("ERROR: Unrecognised FRQCR value, using default multipliers\n");
+ }
+
+ memclkcr = ctrl_inl(CLOCKGEN_MEMCLKCR);
+ e = &st40_memclk_table[memclkcr & MEMCLKCR_RATIO_MASK];
+
+ printk("Clock multipliers: CPU: %d/%d Bus: %d/%d Mem: %d/%d Periph: %d/%d\n",
+ d->factor[0].multiplier, d->factor[0].divisor,
+ d->factor[1].multiplier, d->factor[1].divisor,
+ e->multiplier, e->divisor,
+ d->factor[2].multiplier, d->factor[2].divisor);
+
+ current_cpu_data.master_clock = current_cpu_data.module_clock *
+ d->factor[2].divisor /
+ d->factor[2].multiplier;
+ current_cpu_data.bus_clock = current_cpu_data.master_clock *
+ d->factor[1].multiplier /
+ d->factor[1].divisor;
+ current_cpu_data.memory_clock = current_cpu_data.master_clock *
+ e->multiplier / e->divisor;
+ current_cpu_data.cpu_clock = current_cpu_data.master_clock *
+ d->factor[0].multiplier /
+ d->factor[0].divisor;
+}
+
diff --git a/arch/sh/boards/renesas/edosk7705/Makefile b/arch/sh/boards/renesas/edosk7705/Makefile
new file mode 100644
index 000000000000..7fccbf2e4a1d
--- /dev/null
+++ b/arch/sh/boards/renesas/edosk7705/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the EDOSK7705 specific parts of the kernel
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+obj-y := setup.o io.o
+
diff --git a/arch/sh/boards/renesas/edosk7705/io.c b/arch/sh/boards/renesas/edosk7705/io.c
new file mode 100644
index 000000000000..541cea2a652f
--- /dev/null
+++ b/arch/sh/boards/renesas/edosk7705/io.c
@@ -0,0 +1,94 @@
+/*
+ * arch/sh/boards/renesas/edosk7705/io.c
+ *
+ * Copyright (C) 2001 Ian da Silva, Jeremy Siegel
+ * Based largely on io_se.c.
+ *
+ * I/O routines for Hitachi EDOSK7705 board.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/edosk7705/io.h>
+#include <asm/addrspace.h>
+
+#define SMC_IOADDR 0xA2000000
+
+#define maybebadio(name,port) \
+ printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
+ #name, (port), (__u32) __builtin_return_address(0))
+
+/* Map the Ethernet addresses as if it is at 0x300 - 0x320 */
+unsigned long sh_edosk7705_isa_port2addr(unsigned long port)
+{
+ if (port >= 0x300 && port < 0x320) {
+ /* SMC91C96 registers are 4 byte aligned rather than the
+ * usual 2 byte!
+ */
+ return SMC_IOADDR + ( (port - 0x300) * 2);
+ }
+
+ maybebadio(sh_edosk7705_isa_port2addr, port);
+ return port;
+}
+
+/* Trying to read / write bytes on odd-byte boundaries to the Ethernet
+ * registers causes problems. So we bit-shift the value and read / write
+ * in 2 byte chunks. Setting the low byte to 0 does not cause problems
+ * now as odd byte writes are only made on the bit mask / interrupt
+ * register. This may not be the case in future Mar-2003 SJD
+ */
+unsigned char sh_edosk7705_inb(unsigned long port)
+{
+ if (port >= 0x300 && port < 0x320 && port & 0x01) {
+ return (volatile unsigned char)(generic_inw(port -1) >> 8);
+ }
+ return *(volatile unsigned char *)sh_edosk7705_isa_port2addr(port);
+}
+
+unsigned int sh_edosk7705_inl(unsigned long port)
+{
+ return *(volatile unsigned long *)port;
+}
+
+void sh_edosk7705_outb(unsigned char value, unsigned long port)
+{
+ if (port >= 0x300 && port < 0x320 && port & 0x01) {
+ generic_outw(((unsigned short)value << 8), port -1);
+ return;
+ }
+ *(volatile unsigned char *)sh_edosk7705_isa_port2addr(port) = value;
+}
+
+void sh_edosk7705_outl(unsigned int value, unsigned long port)
+{
+ *(volatile unsigned long *)port = value;
+}
+
+void sh_edosk7705_insb(unsigned long port, void *addr, unsigned long count)
+{
+ unsigned char *p = addr;
+ while (count--) *p++ = sh_edosk7705_inb(port);
+}
+
+void sh_edosk7705_insl(unsigned long port, void *addr, unsigned long count)
+{
+ unsigned long *p = (unsigned long*)addr;
+ while (count--)
+ *p++ = *(volatile unsigned long *)port;
+}
+
+void sh_edosk7705_outsb(unsigned long port, const void *addr, unsigned long count)
+{
+ unsigned char *p = (unsigned char*)addr;
+ while (count--) sh_edosk7705_outb(*p++, port);
+}
+
+void sh_edosk7705_outsl(unsigned long port, const void *addr, unsigned long count)
+{
+ unsigned long *p = (unsigned long*)addr;
+ while (count--) sh_edosk7705_outl(*p++, port);
+}
+
diff --git a/arch/sh/boards/renesas/edosk7705/setup.c b/arch/sh/boards/renesas/edosk7705/setup.c
new file mode 100644
index 000000000000..8b6f0c2af092
--- /dev/null
+++ b/arch/sh/boards/renesas/edosk7705/setup.c
@@ -0,0 +1,60 @@
+/*
+ * arch/sh/boards/renesas/edosk7705/setup.c
+ *
+ * Copyright (C) 2000 Kazumoto Kojima
+ *
+ * Hitachi SolutionEngine Support.
+ *
+ * Modified for edosk7705 development
+ * board by S. Dunn, 2003.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/machvec.h>
+#include <asm/machvec_init.h>
+#include <asm/edosk7705/io.h>
+
+static void init_edosk7705(void);
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_edosk7705 __initmv = {
+ .mv_nr_irqs = 80,
+
+ .mv_inb = sh_edosk7705_inb,
+ .mv_inl = sh_edosk7705_inl,
+ .mv_outb = sh_edosk7705_outb,
+ .mv_outl = sh_edosk7705_outl,
+
+ .mv_inl_p = sh_edosk7705_inl,
+ .mv_outl_p = sh_edosk7705_outl,
+
+ .mv_insb = sh_edosk7705_insb,
+ .mv_insl = sh_edosk7705_insl,
+ .mv_outsb = sh_edosk7705_outsb,
+ .mv_outsl = sh_edosk7705_outsl,
+
+ .mv_isa_port2addr = sh_edosk7705_isa_port2addr,
+ .mv_init_irq = init_edosk7705,
+};
+ALIAS_MV(edosk7705)
+
+static void __init init_edosk7705(void)
+{
+ /* This is the Ethernet interrupt */
+ make_imask_irq(0x09);
+}
+
+const char *get_system_type(void)
+{
+ return "EDOSK7705";
+}
+
+void __init platform_setup(void)
+{
+ /* Nothing .. */
+}
+
diff --git a/arch/sh/boards/renesas/hs7751rvoip/Makefile b/arch/sh/boards/renesas/hs7751rvoip/Makefile
new file mode 100644
index 000000000000..e8b4109ace11
--- /dev/null
+++ b/arch/sh/boards/renesas/hs7751rvoip/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for the HS7751RVoIP specific parts of the kernel
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+obj-y := mach.o setup.o io.o irq.o led.o
+
+obj-$(CONFIG_PCI) += pci.o
+
diff --git a/arch/sh/boards/renesas/hs7751rvoip/io.c b/arch/sh/boards/renesas/hs7751rvoip/io.c
new file mode 100644
index 000000000000..456753d2649c
--- /dev/null
+++ b/arch/sh/boards/renesas/hs7751rvoip/io.c
@@ -0,0 +1,310 @@
+/*
+ * linux/arch/sh/kernel/io_hs7751rvoip.c
+ *
+ * Copyright (C) 2001 Ian da Silva, Jeremy Siegel
+ * Based largely on io_se.c.
+ *
+ * I/O routine for Renesas Technology sales HS7751RVoIP
+ *
+ * Initial version only to support LAN access; some
+ * placeholder code from io_hs7751rvoip.c left in with the
+ * expectation of later SuperIO and PCMCIA access.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/hs7751rvoip/hs7751rvoip.h>
+#include <asm/addrspace.h>
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include "../../../drivers/pci/pci-sh7751.h"
+
+extern void *area5_io8_base; /* Area 5 8bit I/O Base address */
+extern void *area6_io8_base; /* Area 6 8bit I/O Base address */
+extern void *area5_io16_base; /* Area 5 16bit I/O Base address */
+extern void *area6_io16_base; /* Area 6 16bit I/O Base address */
+
+/*
+ * The 7751R HS7751RVoIP uses the built-in PCI controller (PCIC)
+ * of the 7751R processor, and has a SuperIO accessible via the PCI.
+ * The board also includes a PCMCIA controller on its memory bus,
+ * like the other Solution Engine boards.
+ */
+
+#define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR)
+#define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR)
+#define PCI_IO_AREA SH7751_PCI_IO_BASE
+#define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE
+
+#define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK))
+
+#if defined(CONFIG_HS7751RVOIP_CODEC)
+#define CODEC_IO_BASE 0x1000
+#endif
+
+#define maybebadio(name,port) \
+ printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
+ #name, (port), (__u32) __builtin_return_address(0))
+
+static inline void delay(void)
+{
+ ctrl_inw(0xa0000000);
+}
+
+static inline unsigned long port2adr(unsigned int port)
+{
+ if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
+ if (port == 0x3f6)
+ return ((unsigned long)area5_io16_base + 0x0c);
+ else
+ return ((unsigned long)area5_io16_base + 0x800 + ((port-0x1f0) << 1));
+ else
+ maybebadio(port2adr, (unsigned long)port);
+ return port;
+}
+
+/* The 7751R HS7751RVoIP seems to have everything hooked */
+/* up pretty normally (nothing on high-bytes only...) so this */
+/* shouldn't be needed */
+static inline int shifted_port(unsigned long port)
+{
+ /* For IDE registers, value is not shifted */
+ if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
+ return 0;
+ else
+ return 1;
+}
+
+#if defined(CONFIG_HS7751RVOIP_CODEC)
+static inline int
+codec_port(unsigned long port)
+{
+ if (CODEC_IO_BASE <= port && port < (CODEC_IO_BASE+0x20))
+ return 1;
+ else
+ return 0;
+}
+#endif
+
+/* In case someone configures the kernel w/o PCI support: in that */
+/* scenario, don't ever bother to check for PCI-window addresses */
+
+/* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */
+#if defined(CONFIG_PCI)
+#define CHECK_SH7751_PCIIO(port) \
+ ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
+#else
+#define CHECK_SH7751_PCIIO(port) (0)
+#endif
+
+/*
+ * General outline: remap really low stuff [eventually] to SuperIO,
+ * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
+ * is mapped through the PCI IO window. Stuff with high bits (PXSEG)
+ * should be way beyond the window, and is used w/o translation for
+ * compatibility.
+ */
+unsigned char hs7751rvoip_inb(unsigned long port)
+{
+ if (PXSEG(port))
+ return *(volatile unsigned char *)port;
+#if defined(CONFIG_HS7751RVOIP_CODEC)
+ else if (codec_port(port))
+ return *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE));
+#endif
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+ return *(volatile unsigned char *)PCI_IOMAP(port);
+ else
+ return (*(volatile unsigned short *)port2adr(port) & 0xff);
+}
+
+unsigned char hs7751rvoip_inb_p(unsigned long port)
+{
+ unsigned char v;
+
+ if (PXSEG(port))
+ v = *(volatile unsigned char *)port;
+#if defined(CONFIG_HS7751RVOIP_CODEC)
+ else if (codec_port(port))
+ v = *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE));
+#endif
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+ v = *(volatile unsigned char *)PCI_IOMAP(port);
+ else
+ v = (*(volatile unsigned short *)port2adr(port) & 0xff);
+ delay();
+ return v;
+}
+
+unsigned short hs7751rvoip_inw(unsigned long port)
+{
+ if (PXSEG(port))
+ return *(volatile unsigned short *)port;
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+ return *(volatile unsigned short *)PCI_IOMAP(port);
+ else
+ maybebadio(inw, port);
+ return 0;
+}
+
+unsigned int hs7751rvoip_inl(unsigned long port)
+{
+ if (PXSEG(port))
+ return *(volatile unsigned long *)port;
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+ return *(volatile unsigned long *)PCI_IOMAP(port);
+ else
+ maybebadio(inl, port);
+ return 0;
+}
+
+void hs7751rvoip_outb(unsigned char value, unsigned long port)
+{
+
+ if (PXSEG(port))
+ *(volatile unsigned char *)port = value;
+#if defined(CONFIG_HS7751RVOIP_CODEC)
+ else if (codec_port(port))
+ *(volatile unsigned cjar *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE)) = value;
+#endif
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+ *(unsigned char *)PCI_IOMAP(port) = value;
+ else
+ *(volatile unsigned short *)port2adr(port) = value;
+}
+
+void hs7751rvoip_outb_p(unsigned char value, unsigned long port)
+{
+ if (PXSEG(port))
+ *(volatile unsigned char *)port = value;
+#if defined(CONFIG_HS7751RVOIP_CODEC)
+ else if (codec_port(port))
+ *(volatile unsigned cjar *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE)) = value;
+#endif
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+ *(unsigned char *)PCI_IOMAP(port) = value;
+ else
+ *(volatile unsigned short *)port2adr(port) = value;
+ delay();
+}
+
+void hs7751rvoip_outw(unsigned short value, unsigned long port)
+{
+ if (PXSEG(port))
+ *(volatile unsigned short *)port = value;
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+ *(unsigned short *)PCI_IOMAP(port) = value;
+ else
+ maybebadio(outw, port);
+}
+
+void hs7751rvoip_outl(unsigned int value, unsigned long port)
+{
+ if (PXSEG(port))
+ *(volatile unsigned long *)port = value;
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+ *((unsigned long *)PCI_IOMAP(port)) = value;
+ else
+ maybebadio(outl, port);
+}
+
+void hs7751rvoip_insb(unsigned long port, void *addr, unsigned long count)
+{
+ if (PXSEG(port))
+ while (count--) *((unsigned char *) addr)++ = *(volatile unsigned char *)port;
+#if defined(CONFIG_HS7751RVOIP_CODEC)
+ else if (codec_port(port))
+ while (count--) *((unsigned char *) addr)++ = *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE));
+#endif
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
+ volatile __u8 *bp = (__u8 *)PCI_IOMAP(port);
+
+ while (count--) *((volatile unsigned char *) addr)++ = *bp;
+ } else {
+ volatile __u16 *p = (volatile unsigned short *)port2adr(port);
+
+ while (count--) *((unsigned char *) addr)++ = *p & 0xff;
+ }
+}
+
+void hs7751rvoip_insw(unsigned long port, void *addr, unsigned long count)
+{
+ volatile __u16 *p;
+
+ if (PXSEG(port))
+ p = (volatile unsigned short *)port;
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+ p = (volatile unsigned short *)PCI_IOMAP(port);
+ else
+ p = (volatile unsigned short *)port2adr(port);
+ while (count--) *((__u16 *) addr)++ = *p;
+}
+
+void hs7751rvoip_insl(unsigned long port, void *addr, unsigned long count)
+{
+ if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
+ volatile __u32 *p = (__u32 *)PCI_IOMAP(port);
+
+ while (count--) *((__u32 *) addr)++ = *p;
+ } else
+ maybebadio(insl, port);
+}
+
+void hs7751rvoip_outsb(unsigned long port, const void *addr, unsigned long count)
+{
+ if (PXSEG(port))
+ while (count--) *(volatile unsigned char *)port = *((unsigned char *) addr)++;
+#if defined(CONFIG_HS7751RVOIP_CODEC)
+ else if (codec_port(port))
+ while (count--) *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE)) = *((unsigned char *) addr)++;
+#endif
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
+ volatile __u8 *bp = (__u8 *)PCI_IOMAP(port);
+
+ while (count--) *bp = *((volatile unsigned char *) addr)++;
+ } else {
+ volatile __u16 *p = (volatile unsigned short *)port2adr(port);
+
+ while (count--) *p = *((unsigned char *) addr)++;
+ }
+}
+
+void hs7751rvoip_outsw(unsigned long port, const void *addr, unsigned long count)
+{
+ volatile __u16 *p;
+
+ if (PXSEG(port))
+ p = (volatile unsigned short *)port;
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+ p = (volatile unsigned short *)PCI_IOMAP(port);
+ else
+ p = (volatile unsigned short *)port2adr(port);
+ while (count--) *p = *((__u16 *) addr)++;
+}
+
+void hs7751rvoip_outsl(unsigned long port, const void *addr, unsigned long count)
+{
+ if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
+ volatile __u32 *p = (__u32 *)PCI_IOMAP(port);
+
+ while (count--) *p = *((__u32 *) addr)++;
+ } else
+ maybebadio(outsl, port);
+}
+
+void *hs7751rvoip_ioremap(unsigned long offset, unsigned long size)
+{
+ if (offset >= 0xfd000000)
+ return (void *)offset;
+ else
+ return (void *)P2SEGADDR(offset);
+}
+EXPORT_SYMBOL(hs7751rvoip_ioremap);
+
+unsigned long hs7751rvoip_isa_port2addr(unsigned long offset)
+{
+ return port2adr(offset);
+}
diff --git a/arch/sh/boards/renesas/hs7751rvoip/irq.c b/arch/sh/boards/renesas/hs7751rvoip/irq.c
new file mode 100644
index 000000000000..a7921f67a35f
--- /dev/null
+++ b/arch/sh/boards/renesas/hs7751rvoip/irq.c
@@ -0,0 +1,122 @@
+/*
+ * linux/arch/sh/boards/renesas/hs7751rvoip/irq.c
+ *
+ * Copyright (C) 2000 Kazumoto Kojima
+ *
+ * Renesas Technology Sales HS7751RVoIP Support.
+ *
+ * Modified for HS7751RVoIP by
+ * Atom Create Engineering Co., Ltd. 2002.
+ * Lineo uSolutions, Inc. 2003.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/hs7751rvoip/hs7751rvoip.h>
+
+static int mask_pos[] = {8, 9, 10, 11, 12, 13, 0, 1, 2, 3, 4, 5, 6, 7};
+
+static void enable_hs7751rvoip_irq(unsigned int irq);
+static void disable_hs7751rvoip_irq(unsigned int irq);
+
+/* shutdown is same as "disable" */
+#define shutdown_hs7751rvoip_irq disable_hs7751rvoip_irq
+
+static void ack_hs7751rvoip_irq(unsigned int irq);
+static void end_hs7751rvoip_irq(unsigned int irq);
+
+static unsigned int startup_hs7751rvoip_irq(unsigned int irq)
+{
+ enable_hs7751rvoip_irq(irq);
+ return 0; /* never anything pending */
+}
+
+static void disable_hs7751rvoip_irq(unsigned int irq)
+{
+ unsigned long flags;
+ unsigned short val;
+ unsigned short mask = 0xffff ^ (0x0001 << mask_pos[irq]);
+
+ /* Set the priority in IPR to 0 */
+ local_irq_save(flags);
+ val = ctrl_inw(IRLCNTR3);
+ val &= mask;
+ ctrl_outw(val, IRLCNTR3);
+ local_irq_restore(flags);
+}
+
+static void enable_hs7751rvoip_irq(unsigned int irq)
+{
+ unsigned long flags;
+ unsigned short val;
+ unsigned short value = (0x0001 << mask_pos[irq]);
+
+ /* Set priority in IPR back to original value */
+ local_irq_save(flags);
+ val = ctrl_inw(IRLCNTR3);
+ val |= value;
+ ctrl_outw(val, IRLCNTR3);
+ local_irq_restore(flags);
+}
+
+static void ack_hs7751rvoip_irq(unsigned int irq)
+{
+ disable_hs7751rvoip_irq(irq);
+}
+
+static void end_hs7751rvoip_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ enable_hs7751rvoip_irq(irq);
+}
+
+static struct hw_interrupt_type hs7751rvoip_irq_type = {
+ "HS7751RVoIP IRQ",
+ startup_hs7751rvoip_irq,
+ shutdown_hs7751rvoip_irq,
+ enable_hs7751rvoip_irq,
+ disable_hs7751rvoip_irq,
+ ack_hs7751rvoip_irq,
+ end_hs7751rvoip_irq,
+};
+
+static void make_hs7751rvoip_irq(unsigned int irq)
+{
+ disable_irq_nosync(irq);
+ irq_desc[irq].handler = &hs7751rvoip_irq_type;
+ disable_hs7751rvoip_irq(irq);
+}
+
+/*
+ * Initialize IRQ setting
+ */
+void __init init_hs7751rvoip_IRQ(void)
+{
+ int i;
+
+ /* IRL0=ON HOOK1
+ * IRL1=OFF HOOK1
+ * IRL2=ON HOOK2
+ * IRL3=OFF HOOK2
+ * IRL4=Ringing Detection
+ * IRL5=CODEC
+ * IRL6=Ethernet
+ * IRL7=Ethernet Hub
+ * IRL8=USB Communication
+ * IRL9=USB Connection
+ * IRL10=USB DMA
+ * IRL11=CF Card
+ * IRL12=PCMCIA
+ * IRL13=PCI Slot
+ */
+ ctrl_outw(0x9876, IRLCNTR1);
+ ctrl_outw(0xdcba, IRLCNTR2);
+ ctrl_outw(0x0050, IRLCNTR4);
+ ctrl_outw(0x4321, IRLCNTR5);
+
+ for (i=0; i<14; i++)
+ make_hs7751rvoip_irq(i);
+}
diff --git a/arch/sh/boards/renesas/hs7751rvoip/led.c b/arch/sh/boards/renesas/hs7751rvoip/led.c
new file mode 100644
index 000000000000..18a13c8da8a4
--- /dev/null
+++ b/arch/sh/boards/renesas/hs7751rvoip/led.c
@@ -0,0 +1,27 @@
+/*
+ * linux/arch/sh/kernel/setup_hs7751rvoip.c
+ *
+ * Copyright (C) 2000 Kazumoto Kojima
+ *
+ * Renesas Technology Sales HS7751RVoIP Support.
+ *
+ * Modified for HS7751RVoIP by
+ * Atom Create Engineering Co., Ltd. 2002.
+ * Lineo uSolutions, Inc. 2003.
+ */
+
+#include <linux/config.h>
+#include <asm/io.h>
+#include <asm/hs7751rvoip/hs7751rvoip.h>
+
+extern unsigned int debug_counter;
+
+void debug_led_disp(void)
+{
+ unsigned short value;
+
+ value = (unsigned char)debug_counter++;
+ ctrl_outb((0xf0|value), PA_OUTPORTR);
+ if (value == 0x0f)
+ debug_counter = 0;
+}
diff --git a/arch/sh/boards/renesas/hs7751rvoip/mach.c b/arch/sh/boards/renesas/hs7751rvoip/mach.c
new file mode 100644
index 000000000000..8bbed60220ca
--- /dev/null
+++ b/arch/sh/boards/renesas/hs7751rvoip/mach.c
@@ -0,0 +1,55 @@
+/*
+ * linux/arch/sh/kernel/mach_hs7751rvoip.c
+ *
+ * Minor tweak of mach_se.c file to reference hs7751rvoip-specific items.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Machine vector for the Renesas Technology sales HS7751RVoIP
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/irq.h>
+#include <asm/hs7751rvoip/io.h>
+
+extern void init_hs7751rvoip_IRQ(void);
+extern void *hs7751rvoip_ioremap(unsigned long, unsigned long);
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_hs7751rvoip __initmv = {
+ .mv_nr_irqs = 72,
+
+ .mv_inb = hs7751rvoip_inb,
+ .mv_inw = hs7751rvoip_inw,
+ .mv_inl = hs7751rvoip_inl,
+ .mv_outb = hs7751rvoip_outb,
+ .mv_outw = hs7751rvoip_outw,
+ .mv_outl = hs7751rvoip_outl,
+
+ .mv_inb_p = hs7751rvoip_inb_p,
+ .mv_inw_p = hs7751rvoip_inw,
+ .mv_inl_p = hs7751rvoip_inl,
+ .mv_outb_p = hs7751rvoip_outb_p,
+ .mv_outw_p = hs7751rvoip_outw,
+ .mv_outl_p = hs7751rvoip_outl,
+
+ .mv_insb = hs7751rvoip_insb,
+ .mv_insw = hs7751rvoip_insw,
+ .mv_insl = hs7751rvoip_insl,
+ .mv_outsb = hs7751rvoip_outsb,
+ .mv_outsw = hs7751rvoip_outsw,
+ .mv_outsl = hs7751rvoip_outsl,
+
+ .mv_ioremap = hs7751rvoip_ioremap,
+ .mv_isa_port2addr = hs7751rvoip_isa_port2addr,
+ .mv_init_irq = init_hs7751rvoip_IRQ,
+};
+ALIAS_MV(hs7751rvoip)
diff --git a/arch/sh/boards/renesas/hs7751rvoip/pci.c b/arch/sh/boards/renesas/hs7751rvoip/pci.c
new file mode 100644
index 000000000000..7a442d1eca46
--- /dev/null
+++ b/arch/sh/boards/renesas/hs7751rvoip/pci.c
@@ -0,0 +1,150 @@
+/*
+ * linux/arch/sh/kernel/pci-hs7751rvoip.c
+ *
+ * Author: Ian DaSilva (idasilva@mvista.com)
+ *
+ * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * PCI initialization for the Renesas SH7751R HS7751RVoIP board
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+
+#include <asm/io.h>
+#include "../../../drivers/pci/pci-sh7751.h"
+#include <asm/hs7751rvoip/hs7751rvoip.h>
+
+#define PCIMCR_MRSET_OFF 0xBFFFFFFF
+#define PCIMCR_RFSH_OFF 0xFFFFFFFB
+
+/*
+ * Only long word accesses of the PCIC's internal local registers and the
+ * configuration registers from the CPU is supported.
+ */
+#define PCIC_WRITE(x,v) writel((v), PCI_REG(x))
+#define PCIC_READ(x) readl(PCI_REG(x))
+
+/*
+ * Description: This function sets up and initializes the pcic, sets
+ * up the BARS, maps the DRAM into the address space etc, etc.
+ */
+int __init pcibios_init_platform(void)
+{
+ unsigned long bcr1, wcr1, wcr2, wcr3, mcr;
+ unsigned short bcr2, bcr3;
+
+ /*
+ * Initialize the slave bus controller on the pcic. The values used
+ * here should not be hardcoded, but they should be taken from the bsc
+ * on the processor, to make this function as generic as possible.
+ * (i.e. Another sbc may usr different SDRAM timing settings -- in order
+ * for the pcic to work, its settings need to be exactly the same.)
+ */
+ bcr1 = (*(volatile unsigned long *)(SH7751_BCR1));
+ bcr2 = (*(volatile unsigned short *)(SH7751_BCR2));
+ bcr3 = (*(volatile unsigned short *)(SH7751_BCR3));
+ wcr1 = (*(volatile unsigned long *)(SH7751_WCR1));
+ wcr2 = (*(volatile unsigned long *)(SH7751_WCR2));
+ wcr3 = (*(volatile unsigned long *)(SH7751_WCR3));
+ mcr = (*(volatile unsigned long *)(SH7751_MCR));
+
+ bcr1 = bcr1 | 0x00080000; /* Enable Bit 19, BREQEN */
+ (*(volatile unsigned long *)(SH7751_BCR1)) = bcr1;
+
+ bcr1 = bcr1 | 0x40080000; /* Enable Bit 19 BREQEN, set PCIC to slave */
+ PCIC_WRITE(SH7751_PCIBCR1, bcr1); /* PCIC BCR1 */
+ PCIC_WRITE(SH7751_PCIBCR2, bcr2); /* PCIC BCR2 */
+ PCIC_WRITE(SH7751_PCIBCR3, bcr3); /* PCIC BCR3 */
+ PCIC_WRITE(SH7751_PCIWCR1, wcr1); /* PCIC WCR1 */
+ PCIC_WRITE(SH7751_PCIWCR2, wcr2); /* PCIC WCR2 */
+ PCIC_WRITE(SH7751_PCIWCR3, wcr3); /* PCIC WCR3 */
+ mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF;
+ PCIC_WRITE(SH7751_PCIMCR, mcr); /* PCIC MCR */
+
+ /* Enable all interrupts, so we know what to fix */
+ PCIC_WRITE(SH7751_PCIINTM, 0x0000c3ff);
+ PCIC_WRITE(SH7751_PCIAINTM, 0x0000380f);
+
+ /* Set up standard PCI config registers */
+ PCIC_WRITE(SH7751_PCICONF1, 0xFB900047); /* Bus Master, Mem & I/O access */
+ PCIC_WRITE(SH7751_PCICONF2, 0x00000000); /* PCI Class code & Revision ID */
+ PCIC_WRITE(SH7751_PCICONF4, 0xab000001); /* PCI I/O address (local regs) */
+ PCIC_WRITE(SH7751_PCICONF5, 0x0c000000); /* PCI MEM address (local RAM) */
+ PCIC_WRITE(SH7751_PCICONF6, 0xd0000000); /* PCI MEM address (unused) */
+ PCIC_WRITE(SH7751_PCICONF11, 0x35051054); /* PCI Subsystem ID & Vendor ID */
+ PCIC_WRITE(SH7751_PCILSR0, 0x03f00000); /* MEM (full 64M exposed) */
+ PCIC_WRITE(SH7751_PCILSR1, 0x00000000); /* MEM (unused) */
+ PCIC_WRITE(SH7751_PCILAR0, 0x0c000000); /* MEM (direct map from PCI) */
+ PCIC_WRITE(SH7751_PCILAR1, 0x00000000); /* MEM (unused) */
+
+ /* Now turn it on... */
+ PCIC_WRITE(SH7751_PCICR, 0xa5000001);
+
+ /*
+ * Set PCIMBR and PCIIOBR here, assuming a single window
+ * (16M MEM, 256K IO) is enough. If a larger space is
+ * needed, the readx/writex and inx/outx functions will
+ * have to do more (e.g. setting registers for each call).
+ */
+
+ /*
+ * Set the MBR so PCI address is one-to-one with window,
+ * meaning all calls go straight through... use ifdef to
+ * catch erroneous assumption.
+ */
+ BUG_ON(PCIBIOS_MIN_MEM != SH7751_PCI_MEMORY_BASE);
+
+ PCIC_WRITE(SH7751_PCIMBR, PCIBIOS_MIN_MEM);
+
+ /* Set IOBR for window containing area specified in pci.h */
+ PCIC_WRITE(SH7751_PCIIOBR, (PCIBIOS_MIN_IO & SH7751_PCIIOBR_MASK));
+
+ /* All done, may as well say so... */
+ printk("SH7751R PCI: Finished initialization of the PCI controller\n");
+
+ return 1;
+}
+
+int __init pcibios_map_platform_irq(u8 slot, u8 pin)
+{
+ switch (slot) {
+ case 0: return IRQ_PCISLOT; /* PCI Extend slot */
+ case 1: return IRQ_PCMCIA; /* PCI Cardbus Bridge */
+ case 2: return IRQ_PCIETH; /* Realtek Ethernet controller */
+ case 3: return IRQ_PCIHUB; /* Realtek Ethernet Hub controller */
+ default:
+ printk("PCI: Bad IRQ mapping request for slot %d\n", slot);
+ return -1;
+ }
+}
+
+static struct resource sh7751_io_resource = {
+ .name = "SH7751_IO",
+ .start = 0x4000,
+ .end = 0x4000 + SH7751_PCI_IO_SIZE - 1,
+ .flags = IORESOURCE_IO
+};
+
+static struct resource sh7751_mem_resource = {
+ .name = "SH7751_mem",
+ .start = SH7751_PCI_MEMORY_BASE,
+ .end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
+ .flags = IORESOURCE_MEM
+};
+
+extern struct pci_ops sh7751_pci_ops;
+
+struct pci_channel board_pci_channels[] = {
+ { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
+ { NULL, NULL, NULL, 0, 0 },
+};
+EXPORT_SYMBOL(board_pci_channels);
diff --git a/arch/sh/boards/renesas/hs7751rvoip/setup.c b/arch/sh/boards/renesas/hs7751rvoip/setup.c
new file mode 100644
index 000000000000..f1a78b6c714c
--- /dev/null
+++ b/arch/sh/boards/renesas/hs7751rvoip/setup.c
@@ -0,0 +1,89 @@
+/*
+ * linux/arch/sh/kernel/setup_hs7751rvoip.c
+ *
+ * Copyright (C) 2000 Kazumoto Kojima
+ *
+ * Renesas Technology Sales HS7751RVoIP Support.
+ *
+ * Modified for HS7751RVoIP by
+ * Atom Create Engineering Co., Ltd. 2002.
+ * Lineo uSolutions, Inc. 2003.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+#include <asm/hs7751rvoip/hs7751rvoip.h>
+
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+
+/* defined in mm/ioremap.c */
+extern void * p3_ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags);
+
+unsigned int debug_counter;
+
+const char *get_system_type(void)
+{
+ return "HS7751RVoIP";
+}
+
+/*
+ * Initialize the board
+ */
+void __init platform_setup(void)
+{
+ printk(KERN_INFO "Renesas Technology Sales HS7751RVoIP-2 support.\n");
+ ctrl_outb(0xf0, PA_OUTPORTR);
+ debug_counter = 0;
+}
+
+void *area5_io8_base;
+void *area6_io8_base;
+void *area5_io16_base;
+void *area6_io16_base;
+
+int __init cf_init(void)
+{
+ pgprot_t prot;
+ unsigned long paddrbase, psize;
+
+ /* open I/O area window */
+ paddrbase = virt_to_phys((void *)(PA_AREA5_IO+0x00000800));
+ psize = PAGE_SIZE;
+ prot = PAGE_KERNEL_PCC(1, _PAGE_PCC_COM16);
+ area5_io16_base = p3_ioremap(paddrbase, psize, prot.pgprot);
+ if (!area5_io16_base) {
+ printk("allocate_cf_area : can't open CF I/O window!\n");
+ return -ENOMEM;
+ }
+
+ /* XXX : do we need attribute and common-memory area also? */
+
+ paddrbase = virt_to_phys((void *)PA_AREA6_IO);
+ psize = PAGE_SIZE;
+#if defined(CONFIG_HS7751RVOIP_CODEC)
+ prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_COM8);
+#else
+ prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_IO8);
+#endif
+ area6_io8_base = p3_ioremap(paddrbase, psize, prot.pgprot);
+ if (!area6_io8_base) {
+ printk("allocate_cf_area : can't open CODEC I/O 8bit window!\n");
+ return -ENOMEM;
+ }
+ prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_IO16);
+ area6_io16_base = p3_ioremap(paddrbase, psize, prot.pgprot);
+ if (!area6_io16_base) {
+ printk("allocate_cf_area : can't open CODEC I/O 16bit window!\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+__initcall (cf_init);
diff --git a/arch/sh/boards/renesas/rts7751r2d/Makefile b/arch/sh/boards/renesas/rts7751r2d/Makefile
new file mode 100644
index 000000000000..daa53334bdc3
--- /dev/null
+++ b/arch/sh/boards/renesas/rts7751r2d/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the RTS7751R2D specific parts of the kernel
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+obj-y := mach.o setup.o io.o irq.o led.o
+
diff --git a/arch/sh/boards/renesas/rts7751r2d/io.c b/arch/sh/boards/renesas/rts7751r2d/io.c
new file mode 100644
index 000000000000..c46f9154cfd5
--- /dev/null
+++ b/arch/sh/boards/renesas/rts7751r2d/io.c
@@ -0,0 +1,319 @@
+/*
+ * linux/arch/sh/kernel/io_rts7751r2d.c
+ *
+ * Copyright (C) 2001 Ian da Silva, Jeremy Siegel
+ * Based largely on io_se.c.
+ *
+ * I/O routine for Renesas Technology sales RTS7751R2D.
+ *
+ * Initial version only to support LAN access; some
+ * placeholder code from io_rts7751r2d.c left in with the
+ * expectation of later SuperIO and PCMCIA access.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/rts7751r2d/rts7751r2d.h>
+#include <asm/addrspace.h>
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include "../../../drivers/pci/pci-sh7751.h"
+
+/*
+ * The 7751R RTS7751R2D uses the built-in PCI controller (PCIC)
+ * of the 7751R processor, and has a SuperIO accessible via the PCI.
+ * The board also includes a PCMCIA controller on its memory bus,
+ * like the other Solution Engine boards.
+ */
+
+#define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR)
+#define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR)
+#define PCI_IO_AREA SH7751_PCI_IO_BASE
+#define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE
+
+#define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK))
+
+#define maybebadio(name,port) \
+ printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
+ #name, (port), (__u32) __builtin_return_address(0))
+
+static inline void delay(void)
+{
+ ctrl_inw(0xa0000000);
+}
+
+static inline unsigned long port2adr(unsigned int port)
+{
+ if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
+ if (port == 0x3f6)
+ return (PA_AREA5_IO + 0x80c);
+ else
+ return (PA_AREA5_IO + 0x1000 + ((port-0x1f0) << 1));
+ else
+ maybebadio(port2adr, (unsigned long)port);
+
+ return port;
+}
+
+static inline unsigned long port88796l(unsigned int port, int flag)
+{
+ unsigned long addr;
+
+ if (flag)
+ addr = PA_AX88796L + ((port - AX88796L_IO_BASE) << 1);
+ else
+ addr = PA_AX88796L + ((port - AX88796L_IO_BASE) << 1) + 0x1000;
+
+ return addr;
+}
+
+/* The 7751R RTS7751R2D seems to have everything hooked */
+/* up pretty normally (nothing on high-bytes only...) so this */
+/* shouldn't be needed */
+static inline int shifted_port(unsigned long port)
+{
+ /* For IDE registers, value is not shifted */
+ if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
+ return 0;
+ else
+ return 1;
+}
+
+/* In case someone configures the kernel w/o PCI support: in that */
+/* scenario, don't ever bother to check for PCI-window addresses */
+
+/* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */
+#if defined(CONFIG_PCI)
+#define CHECK_SH7751_PCIIO(port) \
+ ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
+#else
+#define CHECK_SH7751_PCIIO(port) (0)
+#endif
+
+#if defined(CONFIG_NE2000) || defined(CONFIG_NE2000_MODULE)
+#define CHECK_AX88796L_PORT(port) \
+ ((port >= AX88796L_IO_BASE) && (port < (AX88796L_IO_BASE+0x20)))
+#else
+#define CHECK_AX88796L_PORT(port) (0)
+#endif
+
+/*
+ * General outline: remap really low stuff [eventually] to SuperIO,
+ * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
+ * is mapped through the PCI IO window. Stuff with high bits (PXSEG)
+ * should be way beyond the window, and is used w/o translation for
+ * compatibility.
+ */
+unsigned char rts7751r2d_inb(unsigned long port)
+{
+ if (CHECK_AX88796L_PORT(port))
+ return (*(volatile unsigned short *)port88796l(port, 0)) & 0xff;
+ else if (PXSEG(port))
+ return *(volatile unsigned char *)port;
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+ return *(volatile unsigned char *)PCI_IOMAP(port);
+ else
+ return (*(volatile unsigned short *)port2adr(port) & 0xff);
+}
+
+unsigned char rts7751r2d_inb_p(unsigned long port)
+{
+ unsigned char v;
+
+ if (CHECK_AX88796L_PORT(port))
+ v = (*(volatile unsigned short *)port88796l(port, 0)) & 0xff;
+ else if (PXSEG(port))
+ v = *(volatile unsigned char *)port;
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+ v = *(volatile unsigned char *)PCI_IOMAP(port);
+ else
+ v = (*(volatile unsigned short *)port2adr(port) & 0xff);
+ delay();
+
+ return v;
+}
+
+unsigned short rts7751r2d_inw(unsigned long port)
+{
+ if (CHECK_AX88796L_PORT(port))
+ maybebadio(inw, port);
+ else if (PXSEG(port))
+ return *(volatile unsigned short *)port;
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+ return *(volatile unsigned short *)PCI_IOMAP(port);
+ else
+ maybebadio(inw, port);
+
+ return 0;
+}
+
+unsigned int rts7751r2d_inl(unsigned long port)
+{
+ if (CHECK_AX88796L_PORT(port))
+ maybebadio(inl, port);
+ else if (PXSEG(port))
+ return *(volatile unsigned long *)port;
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+ return *(volatile unsigned long *)PCI_IOMAP(port);
+ else
+ maybebadio(inl, port);
+
+ return 0;
+}
+
+void rts7751r2d_outb(unsigned char value, unsigned long port)
+{
+ if (CHECK_AX88796L_PORT(port))
+ *((volatile unsigned short *)port88796l(port, 0)) = value;
+ else if (PXSEG(port))
+ *(volatile unsigned char *)port = value;
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+ *(volatile unsigned char *)PCI_IOMAP(port) = value;
+ else
+ *(volatile unsigned short *)port2adr(port) = value;
+}
+
+void rts7751r2d_outb_p(unsigned char value, unsigned long port)
+{
+ if (CHECK_AX88796L_PORT(port))
+ *((volatile unsigned short *)port88796l(port, 0)) = value;
+ else if (PXSEG(port))
+ *(volatile unsigned char *)port = value;
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+ *(volatile unsigned char *)PCI_IOMAP(port) = value;
+ else
+ *(volatile unsigned short *)port2adr(port) = value;
+ delay();
+}
+
+void rts7751r2d_outw(unsigned short value, unsigned long port)
+{
+ if (CHECK_AX88796L_PORT(port))
+ maybebadio(outw, port);
+ else if (PXSEG(port))
+ *(volatile unsigned short *)port = value;
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+ *(volatile unsigned short *)PCI_IOMAP(port) = value;
+ else
+ maybebadio(outw, port);
+}
+
+void rts7751r2d_outl(unsigned int value, unsigned long port)
+{
+ if (CHECK_AX88796L_PORT(port))
+ maybebadio(outl, port);
+ else if (PXSEG(port))
+ *(volatile unsigned long *)port = value;
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+ *(volatile unsigned long *)PCI_IOMAP(port) = value;
+ else
+ maybebadio(outl, port);
+}
+
+void rts7751r2d_insb(unsigned long port, void *addr, unsigned long count)
+{
+ volatile __u8 *bp;
+ volatile __u16 *p;
+
+ if (CHECK_AX88796L_PORT(port)) {
+ p = (volatile unsigned short *)port88796l(port, 0);
+ while (count--) *((unsigned char *) addr)++ = *p & 0xff;
+ } else if (PXSEG(port))
+ while (count--) *((unsigned char *) addr)++ = *(volatile unsigned char *)port;
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
+ bp = (__u8 *)PCI_IOMAP(port);
+ while (count--) *((volatile unsigned char *) addr)++ = *bp;
+ } else {
+ p = (volatile unsigned short *)port2adr(port);
+ while (count--) *((unsigned char *) addr)++ = *p & 0xff;
+ }
+}
+
+void rts7751r2d_insw(unsigned long port, void *addr, unsigned long count)
+{
+ volatile __u16 *p;
+
+ if (CHECK_AX88796L_PORT(port))
+ p = (volatile unsigned short *)port88796l(port, 1);
+ else if (PXSEG(port))
+ p = (volatile unsigned short *)port;
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+ p = (volatile unsigned short *)PCI_IOMAP(port);
+ else
+ p = (volatile unsigned short *)port2adr(port);
+ while (count--) *((__u16 *) addr)++ = *p;
+}
+
+void rts7751r2d_insl(unsigned long port, void *addr, unsigned long count)
+{
+ if (CHECK_AX88796L_PORT(port))
+ maybebadio(insl, port);
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
+ volatile __u32 *p = (__u32 *)PCI_IOMAP(port);
+
+ while (count--) *((__u32 *) addr)++ = *p;
+ } else
+ maybebadio(insl, port);
+}
+
+void rts7751r2d_outsb(unsigned long port, const void *addr, unsigned long count)
+{
+ volatile __u8 *bp;
+ volatile __u16 *p;
+
+ if (CHECK_AX88796L_PORT(port)) {
+ p = (volatile unsigned short *)port88796l(port, 0);
+ while (count--) *p = *((unsigned char *) addr)++;
+ } else if (PXSEG(port))
+ while (count--) *(volatile unsigned char *)port = *((unsigned char *) addr)++;
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
+ bp = (__u8 *)PCI_IOMAP(port);
+ while (count--) *bp = *((volatile unsigned char *) addr)++;
+ } else {
+ p = (volatile unsigned short *)port2adr(port);
+ while (count--) *p = *((unsigned char *) addr)++;
+ }
+}
+
+void rts7751r2d_outsw(unsigned long port, const void *addr, unsigned long count)
+{
+ volatile __u16 *p;
+
+ if (CHECK_AX88796L_PORT(port))
+ p = (volatile unsigned short *)port88796l(port, 1);
+ else if (PXSEG(port))
+ p = (volatile unsigned short *)port;
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
+ p = (volatile unsigned short *)PCI_IOMAP(port);
+ else
+ p = (volatile unsigned short *)port2adr(port);
+ while (count--) *p = *((__u16 *) addr)++;
+}
+
+void rts7751r2d_outsl(unsigned long port, const void *addr, unsigned long count)
+{
+ if (CHECK_AX88796L_PORT(port))
+ maybebadio(outsl, port);
+ else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
+ volatile __u32 *p = (__u32 *)PCI_IOMAP(port);
+
+ while (count--) *p = *((__u32 *) addr)++;
+ } else
+ maybebadio(outsl, port);
+}
+
+void *rts7751r2d_ioremap(unsigned long offset, unsigned long size)
+{
+ if (offset >= 0xfd000000)
+ return (void *)offset;
+ else
+ return (void *)P2SEGADDR(offset);
+}
+EXPORT_SYMBOL(rts7751r2d_ioremap);
+
+unsigned long rts7751r2d_isa_port2addr(unsigned long offset)
+{
+ return port2adr(offset);
+}
diff --git a/arch/sh/boards/renesas/rts7751r2d/irq.c b/arch/sh/boards/renesas/rts7751r2d/irq.c
new file mode 100644
index 000000000000..95717f4f1e2d
--- /dev/null
+++ b/arch/sh/boards/renesas/rts7751r2d/irq.c
@@ -0,0 +1,135 @@
+/*
+ * linux/arch/sh/boards/renesas/rts7751r2d/irq.c
+ *
+ * Copyright (C) 2000 Kazumoto Kojima
+ *
+ * Renesas Technology Sales RTS7751R2D Support.
+ *
+ * Modified for RTS7751R2D by
+ * Atom Create Engineering Co., Ltd. 2002.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/rts7751r2d/rts7751r2d.h>
+
+#if defined(CONFIG_RTS7751R2D_REV11)
+static int mask_pos[] = {11, 9, 8, 12, 10, 6, 5, 4, 7, 14, 13, 0, 0, 0, 0};
+#else
+static int mask_pos[] = {6, 11, 9, 8, 12, 10, 5, 4, 7, 14, 13, 0, 0, 0, 0};
+#endif
+
+extern int voyagergx_irq_demux(int irq);
+extern void setup_voyagergx_irq(void);
+
+static void enable_rts7751r2d_irq(unsigned int irq);
+static void disable_rts7751r2d_irq(unsigned int irq);
+
+/* shutdown is same as "disable" */
+#define shutdown_rts7751r2d_irq disable_rts7751r2d_irq
+
+static void ack_rts7751r2d_irq(unsigned int irq);
+static void end_rts7751r2d_irq(unsigned int irq);
+
+static unsigned int startup_rts7751r2d_irq(unsigned int irq)
+{
+ enable_rts7751r2d_irq(irq);
+ return 0; /* never anything pending */
+}
+
+static void disable_rts7751r2d_irq(unsigned int irq)
+{
+ unsigned long flags;
+ unsigned short val;
+ unsigned short mask = 0xffff ^ (0x0001 << mask_pos[irq]);
+
+ /* Set the priority in IPR to 0 */
+ local_irq_save(flags);
+ val = ctrl_inw(IRLCNTR1);
+ val &= mask;
+ ctrl_outw(val, IRLCNTR1);
+ local_irq_restore(flags);
+}
+
+static void enable_rts7751r2d_irq(unsigned int irq)
+{
+ unsigned long flags;
+ unsigned short val;
+ unsigned short value = (0x0001 << mask_pos[irq]);
+
+ /* Set priority in IPR back to original value */
+ local_irq_save(flags);
+ val = ctrl_inw(IRLCNTR1);
+ val |= value;
+ ctrl_outw(val, IRLCNTR1);
+ local_irq_restore(flags);
+}
+
+int rts7751r2d_irq_demux(int irq)
+{
+ int demux_irq;
+
+ demux_irq = voyagergx_irq_demux(irq);
+ return demux_irq;
+}
+
+static void ack_rts7751r2d_irq(unsigned int irq)
+{
+ disable_rts7751r2d_irq(irq);
+}
+
+static void end_rts7751r2d_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ enable_rts7751r2d_irq(irq);
+}
+
+static struct hw_interrupt_type rts7751r2d_irq_type = {
+ "RTS7751R2D IRQ",
+ startup_rts7751r2d_irq,
+ shutdown_rts7751r2d_irq,
+ enable_rts7751r2d_irq,
+ disable_rts7751r2d_irq,
+ ack_rts7751r2d_irq,
+ end_rts7751r2d_irq,
+};
+
+static void make_rts7751r2d_irq(unsigned int irq)
+{
+ disable_irq_nosync(irq);
+ irq_desc[irq].handler = &rts7751r2d_irq_type;
+ disable_rts7751r2d_irq(irq);
+}
+
+/*
+ * Initialize IRQ setting
+ */
+void __init init_rts7751r2d_IRQ(void)
+{
+ int i;
+
+ /* IRL0=KEY Input
+ * IRL1=Ethernet
+ * IRL2=CF Card
+ * IRL3=CF Card Insert
+ * IRL4=PCMCIA
+ * IRL5=VOYAGER
+ * IRL6=RTC Alarm
+ * IRL7=RTC Timer
+ * IRL8=SD Card
+ * IRL9=PCI Slot #1
+ * IRL10=PCI Slot #2
+ * IRL11=Extention #0
+ * IRL12=Extention #1
+ * IRL13=Extention #2
+ * IRL14=Extention #3
+ */
+
+ for (i=0; i<15; i++)
+ make_rts7751r2d_irq(i);
+
+ setup_voyagergx_irq();
+}
diff --git a/arch/sh/boards/renesas/rts7751r2d/led.c b/arch/sh/boards/renesas/rts7751r2d/led.c
new file mode 100644
index 000000000000..9993259a894f
--- /dev/null
+++ b/arch/sh/boards/renesas/rts7751r2d/led.c
@@ -0,0 +1,67 @@
+/*
+ * linux/arch/sh/kernel/led_rts7751r2d.c
+ *
+ * Copyright (C) Atom Create Engineering Co., Ltd.
+ *
+ * May be copied or modified under the terms of GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * This file contains Renesas Technology Sales RTS7751R2D specific LED code.
+ */
+
+#include <linux/config.h>
+#include <asm/io.h>
+#include <asm/rts7751r2d/rts7751r2d.h>
+
+extern unsigned int debug_counter;
+
+#ifdef CONFIG_HEARTBEAT
+
+#include <linux/sched.h>
+
+/* Cycle the LED's in the clasic Knightriger/Sun pattern */
+void heartbeat_rts7751r2d(void)
+{
+ static unsigned int cnt = 0, period = 0;
+ volatile unsigned short *p = (volatile unsigned short *)PA_OUTPORT;
+ static unsigned bit = 0, up = 1;
+
+ cnt += 1;
+ if (cnt < period)
+ return;
+
+ cnt = 0;
+
+ /* Go through the points (roughly!):
+ * f(0)=10, f(1)=16, f(2)=20, f(5)=35, f(int)->110
+ */
+ period = 110 - ((300 << FSHIFT)/((avenrun[0]/5) + (3<<FSHIFT)));
+
+ *p = 1 << bit;
+ if (up)
+ if (bit == 7) {
+ bit--;
+ up = 0;
+ } else
+ bit++;
+ else if (bit == 0)
+ up = 1;
+ else
+ bit--;
+}
+#endif /* CONFIG_HEARTBEAT */
+
+void rts7751r2d_led(unsigned short value)
+{
+ ctrl_outw(value, PA_OUTPORT);
+}
+
+void debug_led_disp(void)
+{
+ unsigned short value;
+
+ value = (unsigned short)debug_counter++;
+ rts7751r2d_led(value);
+ if (value == 0xff)
+ debug_counter = 0;
+}
diff --git a/arch/sh/boards/renesas/rts7751r2d/mach.c b/arch/sh/boards/renesas/rts7751r2d/mach.c
new file mode 100644
index 000000000000..1efc18e786d5
--- /dev/null
+++ b/arch/sh/boards/renesas/rts7751r2d/mach.c
@@ -0,0 +1,70 @@
+/*
+ * linux/arch/sh/kernel/mach_rts7751r2d.c
+ *
+ * Minor tweak of mach_se.c file to reference rts7751r2d-specific items.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Machine vector for the Renesas Technology sales RTS7751R2D
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/irq.h>
+#include <asm/rts7751r2d/io.h>
+
+extern void heartbeat_rts7751r2d(void);
+extern void init_rts7751r2d_IRQ(void);
+extern void *rts7751r2d_ioremap(unsigned long, unsigned long);
+extern int rts7751r2d_irq_demux(int irq);
+
+extern void *voyagergx_consistent_alloc(struct device *, size_t, dma_addr_t *, int);
+extern int voyagergx_consistent_free(struct device *, size_t, void *, dma_addr_t);
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_rts7751r2d __initmv = {
+ .mv_nr_irqs = 72,
+
+ .mv_inb = rts7751r2d_inb,
+ .mv_inw = rts7751r2d_inw,
+ .mv_inl = rts7751r2d_inl,
+ .mv_outb = rts7751r2d_outb,
+ .mv_outw = rts7751r2d_outw,
+ .mv_outl = rts7751r2d_outl,
+
+ .mv_inb_p = rts7751r2d_inb_p,
+ .mv_inw_p = rts7751r2d_inw,
+ .mv_inl_p = rts7751r2d_inl,
+ .mv_outb_p = rts7751r2d_outb_p,
+ .mv_outw_p = rts7751r2d_outw,
+ .mv_outl_p = rts7751r2d_outl,
+
+ .mv_insb = rts7751r2d_insb,
+ .mv_insw = rts7751r2d_insw,
+ .mv_insl = rts7751r2d_insl,
+ .mv_outsb = rts7751r2d_outsb,
+ .mv_outsw = rts7751r2d_outsw,
+ .mv_outsl = rts7751r2d_outsl,
+
+ .mv_ioremap = rts7751r2d_ioremap,
+ .mv_isa_port2addr = rts7751r2d_isa_port2addr,
+ .mv_init_irq = init_rts7751r2d_IRQ,
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_rts7751r2d,
+#endif
+ .mv_irq_demux = rts7751r2d_irq_demux,
+
+#ifdef CONFIG_USB_OHCI_HCD
+ .mv_consistent_alloc = voyagergx_consistent_alloc,
+ .mv_consistent_free = voyagergx_consistent_free,
+#endif
+};
+ALIAS_MV(rts7751r2d)
diff --git a/arch/sh/boards/renesas/rts7751r2d/setup.c b/arch/sh/boards/renesas/rts7751r2d/setup.c
new file mode 100644
index 000000000000..2587fd1a0240
--- /dev/null
+++ b/arch/sh/boards/renesas/rts7751r2d/setup.c
@@ -0,0 +1,31 @@
+/*
+ * linux/arch/sh/kernel/setup_rts7751r2d.c
+ *
+ * Copyright (C) 2000 Kazumoto Kojima
+ *
+ * Renesas Technology Sales RTS7751R2D Support.
+ *
+ * Modified for RTS7751R2D by
+ * Atom Create Engineering Co., Ltd. 2002.
+ */
+
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/rts7751r2d/rts7751r2d.h>
+
+unsigned int debug_counter;
+
+const char *get_system_type(void)
+{
+ return "RTS7751R2D";
+}
+
+/*
+ * Initialize the board
+ */
+void __init platform_setup(void)
+{
+ printk(KERN_INFO "Renesas Technology Sales RTS7751R2D support.\n");
+ ctrl_outw(0x0000, PA_OUTPORT);
+ debug_counter = 0;
+}
diff --git a/arch/sh/boards/renesas/systemh/Makefile b/arch/sh/boards/renesas/systemh/Makefile
new file mode 100644
index 000000000000..2cc6a23d9d39
--- /dev/null
+++ b/arch/sh/boards/renesas/systemh/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for the SystemH specific parts of the kernel
+#
+
+obj-y := setup.o irq.o io.o
+
+# XXX: This wants to be consolidated in arch/sh/drivers/pci, and more
+# importantly, with the generic sh7751_pcic_init() code. For now, we'll
+# just abuse the hell out of kbuild, because we can..
+
+obj-$(CONFIG_PCI) += pci.o
+pci-y := ../../se/7751/pci.o
+
diff --git a/arch/sh/boards/renesas/systemh/io.c b/arch/sh/boards/renesas/systemh/io.c
new file mode 100644
index 000000000000..cf979011aa94
--- /dev/null
+++ b/arch/sh/boards/renesas/systemh/io.c
@@ -0,0 +1,283 @@
+/*
+ * linux/arch/sh/boards/systemh/io.c
+ *
+ * Copyright (C) 2001 Ian da Silva, Jeremy Siegel
+ * Based largely on io_se.c.
+ *
+ * I/O routine for Hitachi 7751 Systemh.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/systemh/7751systemh.h>
+#include <asm/addrspace.h>
+#include <asm/io.h>
+
+#include <linux/pci.h>
+#include "../../drivers/pci/pci-sh7751.h"
+
+/*
+ * The 7751 SystemH Engine uses the built-in PCI controller (PCIC)
+ * of the 7751 processor, and has a SuperIO accessible on its memory
+ * bus.
+ */
+
+#define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR)
+#define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR)
+#define PCI_IO_AREA SH7751_PCI_IO_BASE
+#define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE
+
+#define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK))
+#define ETHER_IOMAP(adr) (0xB3000000 + (adr)) /*map to 16bits access area
+ of smc lan chip*/
+
+#define maybebadio(name,port) \
+ printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
+ #name, (port), (__u32) __builtin_return_address(0))
+
+static inline void delay(void)
+{
+ ctrl_inw(0xa0000000);
+}
+
+static inline volatile __u16 *
+port2adr(unsigned int port)
+{
+ if (port >= 0x2000)
+ return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
+#if 0
+ else
+ return (volatile __u16 *) (PA_SUPERIO + (port << 1));
+#endif
+ maybebadio(name,(unsigned long)port);
+ return (volatile __u16*)port;
+}
+
+/* In case someone configures the kernel w/o PCI support: in that */
+/* scenario, don't ever bother to check for PCI-window addresses */
+
+/* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */
+#if defined(CONFIG_PCI)
+#define CHECK_SH7751_PCIIO(port) \
+ ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
+#else
+#define CHECK_SH7751_PCIIO(port) (0)
+#endif
+
+/*
+ * General outline: remap really low stuff [eventually] to SuperIO,
+ * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
+ * is mapped through the PCI IO window. Stuff with high bits (PXSEG)
+ * should be way beyond the window, and is used w/o translation for
+ * compatibility.
+ */
+unsigned char sh7751systemh_inb(unsigned long port)
+{
+ if (PXSEG(port))
+ return *(volatile unsigned char *)port;
+ else if (CHECK_SH7751_PCIIO(port))
+ return *(volatile unsigned char *)PCI_IOMAP(port);
+ else if (port <= 0x3F1)
+ return *(volatile unsigned char *)ETHER_IOMAP(port);
+ else
+ return (*port2adr(port))&0xff;
+}
+
+unsigned char sh7751systemh_inb_p(unsigned long port)
+{
+ unsigned char v;
+
+ if (PXSEG(port))
+ v = *(volatile unsigned char *)port;
+ else if (CHECK_SH7751_PCIIO(port))
+ v = *(volatile unsigned char *)PCI_IOMAP(port);
+ else if (port <= 0x3F1)
+ v = *(volatile unsigned char *)ETHER_IOMAP(port);
+ else
+ v = (*port2adr(port))&0xff;
+ delay();
+ return v;
+}
+
+unsigned short sh7751systemh_inw(unsigned long port)
+{
+ if (PXSEG(port))
+ return *(volatile unsigned short *)port;
+ else if (CHECK_SH7751_PCIIO(port))
+ return *(volatile unsigned short *)PCI_IOMAP(port);
+ else if (port >= 0x2000)
+ return *port2adr(port);
+ else if (port <= 0x3F1)
+ return *(volatile unsigned int *)ETHER_IOMAP(port);
+ else
+ maybebadio(inw, port);
+ return 0;
+}
+
+unsigned int sh7751systemh_inl(unsigned long port)
+{
+ if (PXSEG(port))
+ return *(volatile unsigned long *)port;
+ else if (CHECK_SH7751_PCIIO(port))
+ return *(volatile unsigned int *)PCI_IOMAP(port);
+ else if (port >= 0x2000)
+ return *port2adr(port);
+ else if (port <= 0x3F1)
+ return *(volatile unsigned int *)ETHER_IOMAP(port);
+ else
+ maybebadio(inl, port);
+ return 0;
+}
+
+void sh7751systemh_outb(unsigned char value, unsigned long port)
+{
+
+ if (PXSEG(port))
+ *(volatile unsigned char *)port = value;
+ else if (CHECK_SH7751_PCIIO(port))
+ *((unsigned char*)PCI_IOMAP(port)) = value;
+ else if (port <= 0x3F1)
+ *(volatile unsigned char *)ETHER_IOMAP(port) = value;
+ else
+ *(port2adr(port)) = value;
+}
+
+void sh7751systemh_outb_p(unsigned char value, unsigned long port)
+{
+ if (PXSEG(port))
+ *(volatile unsigned char *)port = value;
+ else if (CHECK_SH7751_PCIIO(port))
+ *((unsigned char*)PCI_IOMAP(port)) = value;
+ else if (port <= 0x3F1)
+ *(volatile unsigned char *)ETHER_IOMAP(port) = value;
+ else
+ *(port2adr(port)) = value;
+ delay();
+}
+
+void sh7751systemh_outw(unsigned short value, unsigned long port)
+{
+ if (PXSEG(port))
+ *(volatile unsigned short *)port = value;
+ else if (CHECK_SH7751_PCIIO(port))
+ *((unsigned short *)PCI_IOMAP(port)) = value;
+ else if (port >= 0x2000)
+ *port2adr(port) = value;
+ else if (port <= 0x3F1)
+ *(volatile unsigned short *)ETHER_IOMAP(port) = value;
+ else
+ maybebadio(outw, port);
+}
+
+void sh7751systemh_outl(unsigned int value, unsigned long port)
+{
+ if (PXSEG(port))
+ *(volatile unsigned long *)port = value;
+ else if (CHECK_SH7751_PCIIO(port))
+ *((unsigned long*)PCI_IOMAP(port)) = value;
+ else
+ maybebadio(outl, port);
+}
+
+void sh7751systemh_insb(unsigned long port, void *addr, unsigned long count)
+{
+ unsigned char *p = addr;
+ while (count--) *p++ = sh7751systemh_inb(port);
+}
+
+void sh7751systemh_insw(unsigned long port, void *addr, unsigned long count)
+{
+ unsigned short *p = addr;
+ while (count--) *p++ = sh7751systemh_inw(port);
+}
+
+void sh7751systemh_insl(unsigned long port, void *addr, unsigned long count)
+{
+ maybebadio(insl, port);
+}
+
+void sh7751systemh_outsb(unsigned long port, const void *addr, unsigned long count)
+{
+ unsigned char *p = (unsigned char*)addr;
+ while (count--) sh7751systemh_outb(*p++, port);
+}
+
+void sh7751systemh_outsw(unsigned long port, const void *addr, unsigned long count)
+{
+ unsigned short *p = (unsigned short*)addr;
+ while (count--) sh7751systemh_outw(*p++, port);
+}
+
+void sh7751systemh_outsl(unsigned long port, const void *addr, unsigned long count)
+{
+ maybebadio(outsw, port);
+}
+
+/* For read/write calls, just copy generic (pass-thru); PCIMBR is */
+/* already set up. For a larger memory space, these would need to */
+/* reset PCIMBR as needed on a per-call basis... */
+
+unsigned char sh7751systemh_readb(unsigned long addr)
+{
+ return *(volatile unsigned char*)addr;
+}
+
+unsigned short sh7751systemh_readw(unsigned long addr)
+{
+ return *(volatile unsigned short*)addr;
+}
+
+unsigned int sh7751systemh_readl(unsigned long addr)
+{
+ return *(volatile unsigned long*)addr;
+}
+
+void sh7751systemh_writeb(unsigned char b, unsigned long addr)
+{
+ *(volatile unsigned char*)addr = b;
+}
+
+void sh7751systemh_writew(unsigned short b, unsigned long addr)
+{
+ *(volatile unsigned short*)addr = b;
+}
+
+void sh7751systemh_writel(unsigned int b, unsigned long addr)
+{
+ *(volatile unsigned long*)addr = b;
+}
+
+
+
+/* Map ISA bus address to the real address. Only for PCMCIA. */
+
+/* ISA page descriptor. */
+static __u32 sh_isa_memmap[256];
+
+#if 0
+static int
+sh_isa_mmap(__u32 start, __u32 length, __u32 offset)
+{
+ int idx;
+
+ if (start >= 0x100000 || (start & 0xfff) || (length != 0x1000))
+ return -1;
+
+ idx = start >> 12;
+ sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff);
+ printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n",
+ start, length, offset, idx, sh_isa_memmap[idx]);
+ return 0;
+}
+#endif
+
+unsigned long
+sh7751systemh_isa_port2addr(unsigned long offset)
+{
+ int idx;
+
+ idx = (offset >> 12) & 0xff;
+ offset &= 0xfff;
+ return sh_isa_memmap[idx] + offset;
+}
diff --git a/arch/sh/boards/renesas/systemh/irq.c b/arch/sh/boards/renesas/systemh/irq.c
new file mode 100644
index 000000000000..5675a4134eee
--- /dev/null
+++ b/arch/sh/boards/renesas/systemh/irq.c
@@ -0,0 +1,111 @@
+/*
+ * linux/arch/sh/boards/systemh/irq.c
+ *
+ * Copyright (C) 2000 Kazumoto Kojima
+ *
+ * Hitachi SystemH Support.
+ *
+ * Modified for 7751 SystemH by
+ * Jonathan Short.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+#include <asm/mach/7751systemh.h>
+#include <asm/smc37c93x.h>
+
+/* address of external interrupt mask register
+ * address must be set prior to use these (maybe in init_XXX_irq())
+ * XXX : is it better to use .config than specifying it in code? */
+static unsigned long *systemh_irq_mask_register = (unsigned long *)0xB3F10004;
+static unsigned long *systemh_irq_request_register = (unsigned long *)0xB3F10000;
+
+/* forward declaration */
+static unsigned int startup_systemh_irq(unsigned int irq);
+static void shutdown_systemh_irq(unsigned int irq);
+static void enable_systemh_irq(unsigned int irq);
+static void disable_systemh_irq(unsigned int irq);
+static void mask_and_ack_systemh(unsigned int);
+static void end_systemh_irq(unsigned int irq);
+
+/* hw_interrupt_type */
+static struct hw_interrupt_type systemh_irq_type = {
+ " SystemH Register",
+ startup_systemh_irq,
+ shutdown_systemh_irq,
+ enable_systemh_irq,
+ disable_systemh_irq,
+ mask_and_ack_systemh,
+ end_systemh_irq
+};
+
+static unsigned int startup_systemh_irq(unsigned int irq)
+{
+ enable_systemh_irq(irq);
+ return 0; /* never anything pending */
+}
+
+static void shutdown_systemh_irq(unsigned int irq)
+{
+ disable_systemh_irq(irq);
+}
+
+static void disable_systemh_irq(unsigned int irq)
+{
+ if (systemh_irq_mask_register) {
+ unsigned long flags;
+ unsigned long val, mask = 0x01 << 1;
+
+ /* Clear the "irq"th bit in the mask and set it in the request */
+ local_irq_save(flags);
+
+ val = ctrl_inl((unsigned long)systemh_irq_mask_register);
+ val &= ~mask;
+ ctrl_outl(val, (unsigned long)systemh_irq_mask_register);
+
+ val = ctrl_inl((unsigned long)systemh_irq_request_register);
+ val |= mask;
+ ctrl_outl(val, (unsigned long)systemh_irq_request_register);
+
+ local_irq_restore(flags);
+ }
+}
+
+static void enable_systemh_irq(unsigned int irq)
+{
+ if (systemh_irq_mask_register) {
+ unsigned long flags;
+ unsigned long val, mask = 0x01 << 1;
+
+ /* Set "irq"th bit in the mask register */
+ local_irq_save(flags);
+ val = ctrl_inl((unsigned long)systemh_irq_mask_register);
+ val |= mask;
+ ctrl_outl(val, (unsigned long)systemh_irq_mask_register);
+ local_irq_restore(flags);
+ }
+}
+
+static void mask_and_ack_systemh(unsigned int irq)
+{
+ disable_systemh_irq(irq);
+}
+
+static void end_systemh_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ enable_systemh_irq(irq);
+}
+
+void make_systemh_irq(unsigned int irq)
+{
+ disable_irq_nosync(irq);
+ irq_desc[irq].handler = &systemh_irq_type;
+ disable_systemh_irq(irq);
+}
+
diff --git a/arch/sh/boards/renesas/systemh/setup.c b/arch/sh/boards/renesas/systemh/setup.c
new file mode 100644
index 000000000000..826fa3d7669c
--- /dev/null
+++ b/arch/sh/boards/renesas/systemh/setup.c
@@ -0,0 +1,80 @@
+/*
+ * linux/arch/sh/boards/systemh/setup.c
+ *
+ * Copyright (C) 2000 Kazumoto Kojima
+ * Copyright (C) 2003 Paul Mundt
+ *
+ * Hitachi SystemH Support.
+ *
+ * Modified for 7751 SystemH by Jonathan Short.
+ *
+ * Rewritten for 2.6 by Paul Mundt.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <asm/mach/7751systemh.h>
+#include <asm/mach/io.h>
+#include <asm/machvec.h>
+
+extern void make_systemh_irq(unsigned int irq);
+
+const char *get_system_type(void)
+{
+ return "7751 SystemH";
+}
+
+/*
+ * Initialize IRQ setting
+ */
+void __init init_7751systemh_IRQ(void)
+{
+/* make_ipr_irq(10, BCR_ILCRD, 1, 0x0f-10); LAN */
+/* make_ipr_irq(14, BCR_ILCRA, 2, 0x0f-4); */
+ make_systemh_irq(0xb); /* Ethernet interrupt */
+}
+
+struct sh_machine_vector mv_7751systemh __initmv = {
+ .mv_nr_irqs = 72,
+
+ .mv_inb = sh7751systemh_inb,
+ .mv_inw = sh7751systemh_inw,
+ .mv_inl = sh7751systemh_inl,
+ .mv_outb = sh7751systemh_outb,
+ .mv_outw = sh7751systemh_outw,
+ .mv_outl = sh7751systemh_outl,
+
+ .mv_inb_p = sh7751systemh_inb_p,
+ .mv_inw_p = sh7751systemh_inw,
+ .mv_inl_p = sh7751systemh_inl,
+ .mv_outb_p = sh7751systemh_outb_p,
+ .mv_outw_p = sh7751systemh_outw,
+ .mv_outl_p = sh7751systemh_outl,
+
+ .mv_insb = sh7751systemh_insb,
+ .mv_insw = sh7751systemh_insw,
+ .mv_insl = sh7751systemh_insl,
+ .mv_outsb = sh7751systemh_outsb,
+ .mv_outsw = sh7751systemh_outsw,
+ .mv_outsl = sh7751systemh_outsl,
+
+ .mv_readb = sh7751systemh_readb,
+ .mv_readw = sh7751systemh_readw,
+ .mv_readl = sh7751systemh_readl,
+ .mv_writeb = sh7751systemh_writeb,
+ .mv_writew = sh7751systemh_writew,
+ .mv_writel = sh7751systemh_writel,
+
+ .mv_isa_port2addr = sh7751systemh_isa_port2addr,
+
+ .mv_init_irq = init_7751systemh_IRQ,
+};
+ALIAS_MV(7751systemh)
+
+int __init platform_setup(void)
+{
+ return 0;
+}
+
diff --git a/arch/sh/boards/saturn/Makefile b/arch/sh/boards/saturn/Makefile
new file mode 100644
index 000000000000..75a3042e252e
--- /dev/null
+++ b/arch/sh/boards/saturn/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the Sega Saturn specific parts of the kernel
+#
+
+obj-y := setup.o io.o irq.o
+
+obj-$(CONFIG_SMP) += smp.o
+
diff --git a/arch/sh/boards/saturn/io.c b/arch/sh/boards/saturn/io.c
new file mode 100644
index 000000000000..c6e4f7f2e686
--- /dev/null
+++ b/arch/sh/boards/saturn/io.c
@@ -0,0 +1,26 @@
+/*
+ * arch/sh/boards/saturn/io.c
+ *
+ * I/O routines for the Sega Saturn.
+ *
+ * Copyright (C) 2002 Paul Mundt
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ */
+#include <asm/saturn/io.h>
+#include <asm/machvec.h>
+
+unsigned long saturn_isa_port2addr(unsigned long offset)
+{
+ return offset;
+}
+
+void *saturn_ioremap(unsigned long offset, unsigned long size)
+{
+ return (void *)offset;
+}
+
+void saturn_iounmap(void *addr)
+{
+}
+
diff --git a/arch/sh/boards/saturn/irq.c b/arch/sh/boards/saturn/irq.c
new file mode 100644
index 000000000000..15d1d3f0f787
--- /dev/null
+++ b/arch/sh/boards/saturn/irq.c
@@ -0,0 +1,118 @@
+/*
+ * arch/sh/boards/saturn/irq.c
+ *
+ * Copyright (C) 2002 Paul Mundt
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+/*
+ * Interrupts map out as follows:
+ *
+ * Vector Name Mask
+ *
+ * 64 VBLANKIN 0x0001
+ * 65 VBLANKOUT 0x0002
+ * 66 HBLANKIN 0x0004
+ * 67 TIMER0 0x0008
+ * 68 TIMER1 0x0010
+ * 69 DSPEND 0x0020
+ * 70 SOUNDREQUEST 0x0040
+ * 71 SYSTEMMANAGER 0x0080
+ * 72 PAD 0x0100
+ * 73 LEVEL2DMAEND 0x0200
+ * 74 LEVEL1DMAEND 0x0400
+ * 75 LEVEL0DMAEND 0x0800
+ * 76 DMAILLEGAL 0x1000
+ * 77 SRITEDRAWEND 0x2000
+ * 78 ABUS 0x8000
+ *
+ */
+#define SATURN_IRQ_MIN 64 /* VBLANKIN */
+#define SATURN_IRQ_MAX 78 /* ABUS */
+
+#define SATURN_IRQ_MASK 0xbfff
+
+static inline u32 saturn_irq_mask(unsigned int irq_nr)
+{
+ u32 mask;
+
+ mask = (1 << (irq_nr - SATURN_IRQ_MIN));
+ mask <<= (irq_nr == SATURN_IRQ_MAX);
+ mask &= SATURN_IRQ_MASK;
+
+ return mask;
+}
+
+static inline void mask_saturn_irq(unsigned int irq_nr)
+{
+ u32 mask;
+
+ mask = ctrl_inl(SATURN_IMR);
+ mask |= saturn_irq_mask(irq_nr);
+ ctrl_outl(mask, SATURN_IMR);
+}
+
+static inline void unmask_saturn_irq(unsigned int irq_nr)
+{
+ u32 mask;
+
+ mask = ctrl_inl(SATURN_IMR);
+ mask &= ~saturn_irq_mask(irq_nr);
+ ctrl_outl(mask, SATURN_IMR);
+}
+
+static void disable_saturn_irq(unsigned int irq_nr)
+{
+ mask_saturn_irq(irq_nr);
+}
+
+static void enable_saturn_irq(unsigned int irq_nr)
+{
+ unmask_saturn_irq(irq_nr);
+}
+
+static void mask_and_ack_saturn_irq(unsigned int irq_nr)
+{
+ mask_saturn_irq(irq_nr);
+}
+
+static void end_saturn_irq(unsigned int irq_nr)
+{
+ if (!(irq_desc[irq_nr].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+ unmask_saturn_irq(irq_nr);
+}
+
+static unsigned int startup_saturn_irq(unsigned int irq_nr)
+{
+ unmask_saturn_irq(irq_nr);
+
+ return 0;
+}
+
+static void shutdown_saturn_irq(unsigned int irq_nr)
+{
+ mask_saturn_irq(irq_nr);
+}
+
+static struct hw_interrupt_type saturn_int = {
+ .typename = "Saturn",
+ .enable = enable_saturn_irq,
+ .disable = disable_saturn_irq,
+ .ack = mask_and_ack_saturn_irq,
+ .end = end_saturn_irq,
+ .startup = startup_saturn_irq,
+ .shutdown = shutdown_saturn_irq,
+};
+
+int saturn_irq_demux(int irq_nr)
+{
+ /* FIXME */
+ return irq_nr;
+}
+
diff --git a/arch/sh/boards/saturn/setup.c b/arch/sh/boards/saturn/setup.c
new file mode 100644
index 000000000000..bea6c572ad82
--- /dev/null
+++ b/arch/sh/boards/saturn/setup.c
@@ -0,0 +1,43 @@
+/*
+ * arch/sh/boards/saturn/setup.c
+ *
+ * Hardware support for the Sega Saturn.
+ *
+ * Copyright (c) 2002 Paul Mundt
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/machvec.h>
+#include <asm/mach/io.h>
+
+extern int saturn_irq_demux(int irq_nr);
+
+const char *get_system_type(void)
+{
+ return "Sega Saturn";
+}
+
+/*
+ * The Machine Vector
+ */
+struct sh_machine_vector mv_saturn __initmv = {
+ .mv_nr_irqs = 80, /* Fix this later */
+
+ .mv_isa_port2addr = saturn_isa_port2addr,
+ .mv_irq_demux = saturn_irq_demux,
+
+ .mv_ioremap = saturn_ioremap,
+ .mv_iounmap = saturn_iounmap,
+};
+
+ALIAS_MV(saturn)
+
+int __init platform_setup(void)
+{
+ return 0;
+}
+
diff --git a/arch/sh/boards/saturn/smp.c b/arch/sh/boards/saturn/smp.c
new file mode 100644
index 000000000000..76460918c9cd
--- /dev/null
+++ b/arch/sh/boards/saturn/smp.c
@@ -0,0 +1,68 @@
+/*
+ * arch/sh/boards/saturn/smp.c
+ *
+ * SMP support for the Sega Saturn.
+ *
+ * Copyright (c) 2002 Paul Mundt
+ *
+ * Released under the terms of the GNU GPL v2.0.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+
+#include <asm/saturn/smpc.h>
+
+extern void start_secondary(void);
+
+void __smp_send_ipi(unsigned int cpu, unsigned int action)
+{
+ /* Nothing here yet .. */
+}
+
+unsigned int __smp_probe_cpus(void)
+{
+ /*
+ * This is just a straightforward master/slave configuration,
+ * and probing isn't really supported..
+ */
+ return 2;
+}
+
+/*
+ * We're only allowed to do byte-access to SMPC registers. In
+ * addition to which, we treat them as write-only, since
+ * reading from them will return undefined data.
+ */
+static inline void smpc_slave_stop(unsigned int cpu)
+{
+ smpc_barrier();
+ ctrl_outb(1, SMPC_STATUS);
+
+ ctrl_outb(SMPC_CMD_SSHOFF, SMPC_COMMAND);
+ smpc_barrier();
+}
+
+static inline void smpc_slave_start(unsigned int cpu)
+{
+ ctrl_outb(1, SMPC_STATUS);
+ ctrl_outb(SMPC_CMD_SSHON, SMPC_COMMAND);
+
+ smpc_barrier();
+}
+
+void __smp_slave_init(unsigned int cpu)
+{
+ register unsigned long vbr;
+ void **entry;
+
+ __asm__ __volatile__ ("stc vbr, %0\n\t" : "=r" (vbr));
+ entry = (void **)(vbr + 0x310 + 0x94);
+
+ smpc_slave_stop(cpu);
+
+ *(void **)entry = (void *)start_secondary;
+
+ smpc_slave_start(cpu);
+}
+
diff --git a/arch/sh/boards/se/7300/Makefile b/arch/sh/boards/se/7300/Makefile
new file mode 100644
index 000000000000..0fbd4f47815c
--- /dev/null
+++ b/arch/sh/boards/se/7300/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the 7300 SolutionEngine specific parts of the kernel
+#
+
+obj-y := setup.o io.o irq.o
+
+obj-$(CONFIG_HEARTBEAT) += led.o
diff --git a/arch/sh/boards/se/7300/io.c b/arch/sh/boards/se/7300/io.c
new file mode 100644
index 000000000000..3c89def46480
--- /dev/null
+++ b/arch/sh/boards/se/7300/io.c
@@ -0,0 +1,265 @@
+/*
+ * arch/sh/boards/se/7300/io.c
+ *
+ * Copyright (C) 2003 YOSHII Takashi <yoshii-takashi@hitachi-ul.co.jp>
+ * Based on arch/sh/kernel/io_shmse.c
+ *
+ * I/O routine for SH-Mobile3 73180 SolutionEngine.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <asm/mach/se7300.h>
+#include <asm/io.h>
+
+#define badio(fn, a) panic("bad i/o operation %s for %08lx.", #fn, a)
+
+struct iop {
+ unsigned long start, end;
+ unsigned long base;
+ struct iop *(*check) (struct iop * p, unsigned long port);
+ unsigned char (*inb) (struct iop * p, unsigned long port);
+ unsigned short (*inw) (struct iop * p, unsigned long port);
+ void (*outb) (struct iop * p, unsigned char value, unsigned long port);
+ void (*outw) (struct iop * p, unsigned short value, unsigned long port);
+};
+
+struct iop *
+simple_check(struct iop *p, unsigned long port)
+{
+ if ((p->start <= port) && (port <= p->end))
+ return p;
+ else
+ badio(check, port);
+}
+
+struct iop *
+ide_check(struct iop *p, unsigned long port)
+{
+ if (((0x1f0 <= port) && (port <= 0x1f7)) || (port == 0x3f7))
+ return p;
+ return NULL;
+}
+
+unsigned char
+simple_inb(struct iop *p, unsigned long port)
+{
+ return *(unsigned char *) (p->base + port);
+}
+
+unsigned short
+simple_inw(struct iop *p, unsigned long port)
+{
+ return *(unsigned short *) (p->base + port);
+}
+
+void
+simple_outb(struct iop *p, unsigned char value, unsigned long port)
+{
+ *(unsigned char *) (p->base + port) = value;
+}
+
+void
+simple_outw(struct iop *p, unsigned short value, unsigned long port)
+{
+ *(unsigned short *) (p->base + port) = value;
+}
+
+unsigned char
+pcc_inb(struct iop *p, unsigned long port)
+{
+ unsigned long addr = p->base + port + 0x40000;
+ unsigned long v;
+
+ if (port & 1)
+ addr += 0x00400000;
+ v = *(volatile unsigned char *) addr;
+ return v;
+}
+
+void
+pcc_outb(struct iop *p, unsigned char value, unsigned long port)
+{
+ unsigned long addr = p->base + port + 0x40000;
+
+ if (port & 1)
+ addr += 0x00400000;
+ *(volatile unsigned char *) addr = value;
+}
+
+unsigned char
+bad_inb(struct iop *p, unsigned long port)
+{
+ badio(inb, port);
+}
+
+void
+bad_outb(struct iop *p, unsigned char value, unsigned long port)
+{
+ badio(inw, port);
+}
+
+/* MSTLANEX01 LAN at 0xb400:0000 */
+static struct iop laniop = {
+ .start = 0x300,
+ .end = 0x30f,
+ .base = 0xb4000000,
+ .check = simple_check,
+ .inb = simple_inb,
+ .inw = simple_inw,
+ .outb = simple_outb,
+ .outw = simple_outw,
+};
+
+/* NE2000 pc card NIC */
+static struct iop neiop = {
+ .start = 0x280,
+ .end = 0x29f,
+ .base = 0xb0600000 + 0x80, /* soft 0x280 -> hard 0x300 */
+ .check = simple_check,
+ .inb = pcc_inb,
+ .inw = simple_inw,
+ .outb = pcc_outb,
+ .outw = simple_outw,
+};
+
+/* CF in CF slot */
+static struct iop cfiop = {
+ .base = 0xb0600000,
+ .check = ide_check,
+ .inb = pcc_inb,
+ .inw = simple_inw,
+ .outb = pcc_outb,
+ .outw = simple_outw,
+};
+
+static __inline__ struct iop *
+port2iop(unsigned long port)
+{
+ if (0) ;
+#if defined(CONFIG_SMC91111)
+ else if (laniop.check(&laniop, port))
+ return &laniop;
+#endif
+#if defined(CONFIG_NE2000)
+ else if (neiop.check(&neiop, port))
+ return &neiop;
+#endif
+#if defined(CONFIG_IDE)
+ else if (cfiop.check(&cfiop, port))
+ return &cfiop;
+#endif
+ else
+ return &neiop; /* fallback */
+}
+
+static inline void
+delay(void)
+{
+ ctrl_inw(0xac000000);
+ ctrl_inw(0xac000000);
+}
+
+unsigned char
+sh7300se_inb(unsigned long port)
+{
+ struct iop *p = port2iop(port);
+ return (p->inb) (p, port);
+}
+
+unsigned char
+sh7300se_inb_p(unsigned long port)
+{
+ unsigned char v = sh7300se_inb(port);
+ delay();
+ return v;
+}
+
+unsigned short
+sh7300se_inw(unsigned long port)
+{
+ struct iop *p = port2iop(port);
+ return (p->inw) (p, port);
+}
+
+unsigned int
+sh7300se_inl(unsigned long port)
+{
+ badio(inl, port);
+}
+
+void
+sh7300se_outb(unsigned char value, unsigned long port)
+{
+ struct iop *p = port2iop(port);
+ (p->outb) (p, value, port);
+}
+
+void
+sh7300se_outb_p(unsigned char value, unsigned long port)
+{
+ sh7300se_outb(value, port);
+ delay();
+}
+
+void
+sh7300se_outw(unsigned short value, unsigned long port)
+{
+ struct iop *p = port2iop(port);
+ (p->outw) (p, value, port);
+}
+
+void
+sh7300se_outl(unsigned int value, unsigned long port)
+{
+ badio(outl, port);
+}
+
+void
+sh7300se_insb(unsigned long port, void *addr, unsigned long count)
+{
+ unsigned char *a = addr;
+ struct iop *p = port2iop(port);
+ while (count--)
+ *a++ = (p->inb) (p, port);
+}
+
+void
+sh7300se_insw(unsigned long port, void *addr, unsigned long count)
+{
+ unsigned short *a = addr;
+ struct iop *p = port2iop(port);
+ while (count--)
+ *a++ = (p->inw) (p, port);
+}
+
+void
+sh7300se_insl(unsigned long port, void *addr, unsigned long count)
+{
+ badio(insl, port);
+}
+
+void
+sh7300se_outsb(unsigned long port, const void *addr, unsigned long count)
+{
+ unsigned char *a = (unsigned char *) addr;
+ struct iop *p = port2iop(port);
+ while (count--)
+ (p->outb) (p, *a++, port);
+}
+
+void
+sh7300se_outsw(unsigned long port, const void *addr, unsigned long count)
+{
+ unsigned short *a = (unsigned short *) addr;
+ struct iop *p = port2iop(port);
+ while (count--)
+ (p->outw) (p, *a++, port);
+}
+
+void
+sh7300se_outsl(unsigned long port, const void *addr, unsigned long count)
+{
+ badio(outsw, port);
+}
diff --git a/arch/sh/boards/se/7300/irq.c b/arch/sh/boards/se/7300/irq.c
new file mode 100644
index 000000000000..96c8c23d6c93
--- /dev/null
+++ b/arch/sh/boards/se/7300/irq.c
@@ -0,0 +1,37 @@
+/*
+ * linux/arch/sh/boards/se/7300/irq.c
+ *
+ * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
+ *
+ * SH-Mobile SolutionEngine 7300 Support.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mach/se7300.h>
+
+/*
+ * Initialize IRQ setting
+ */
+void __init
+init_7300se_IRQ(void)
+{
+ ctrl_outw(0x0028, PA_EPLD_MODESET); /* mode set IRQ0,1 active low. */
+ ctrl_outw(0xa000, INTC_ICR1); /* IRQ mode; IRQ0,1 enable. */
+ ctrl_outw(0x0000, PORT_PFCR); /* use F for IRQ[3:0] and SIU. */
+
+ /* PC_IRQ[0-3] -> IRQ0 (32) */
+ make_ipr_irq(IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, 0x0f - IRQ0_IRQ);
+ /* A_IRQ[0-3] -> IRQ1 (33) */
+ make_ipr_irq(IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, 0x0f - IRQ1_IRQ);
+ make_ipr_irq(SIOF0_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY);
+ make_ipr_irq(DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY);
+ make_ipr_irq(DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY);
+ make_ipr_irq(VIO_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY);
+
+ ctrl_outw(0x2000, PA_MRSHPC + 0x0c); /* mrshpc irq enable */
+}
diff --git a/arch/sh/boards/se/7300/led.c b/arch/sh/boards/se/7300/led.c
new file mode 100644
index 000000000000..02c7f846c84c
--- /dev/null
+++ b/arch/sh/boards/se/7300/led.c
@@ -0,0 +1,69 @@
+/*
+ * linux/arch/sh/boards/se/7300/led.c
+ *
+ * Derived from linux/arch/sh/boards/se/770x/led.c
+ *
+ * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * This file contains Solution Engine specific LED code.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <asm/mach/se7300.h>
+
+static void
+mach_led(int position, int value)
+{
+ volatile unsigned short *p = (volatile unsigned short *) PA_LED;
+
+ if (value) {
+ *p |= (1 << 8);
+ } else {
+ *p &= ~(1 << 8);
+ }
+}
+
+
+/* Cycle the LED's in the clasic Knightrider/Sun pattern */
+void
+heartbeat_7300se(void)
+{
+ static unsigned int cnt = 0, period = 0;
+ volatile unsigned short *p = (volatile unsigned short *) PA_LED;
+ static unsigned bit = 0, up = 1;
+
+ cnt += 1;
+ if (cnt < period) {
+ return;
+ }
+
+ cnt = 0;
+
+ /* Go through the points (roughly!):
+ * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110
+ */
+ period = 110 - ((300 << FSHIFT) / ((avenrun[0] / 5) + (3 << FSHIFT)));
+
+ if (up) {
+ if (bit == 7) {
+ bit--;
+ up = 0;
+ } else {
+ bit++;
+ }
+ } else {
+ if (bit == 0) {
+ bit++;
+ up = 1;
+ } else {
+ bit--;
+ }
+ }
+ *p = 1 << (bit + 8);
+
+}
+
diff --git a/arch/sh/boards/se/7300/setup.c b/arch/sh/boards/se/7300/setup.c
new file mode 100644
index 000000000000..08536bc224dc
--- /dev/null
+++ b/arch/sh/boards/se/7300/setup.c
@@ -0,0 +1,66 @@
+/*
+ * linux/arch/sh/boards/se/7300/setup.c
+ *
+ * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
+ *
+ * SH-Mobile SolutionEngine 7300 Support.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/machvec.h>
+#include <asm/machvec_init.h>
+#include <asm/mach/io.h>
+
+void heartbeat_7300se(void);
+void init_7300se_IRQ(void);
+
+const char *
+get_system_type(void)
+{
+ return "SolutionEngine 7300";
+}
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_7300se __initmv = {
+ .mv_nr_irqs = 109,
+ .mv_inb = sh7300se_inb,
+ .mv_inw = sh7300se_inw,
+ .mv_inl = sh7300se_inl,
+ .mv_outb = sh7300se_outb,
+ .mv_outw = sh7300se_outw,
+ .mv_outl = sh7300se_outl,
+
+ .mv_inb_p = sh7300se_inb_p,
+ .mv_inw_p = sh7300se_inw,
+ .mv_inl_p = sh7300se_inl,
+ .mv_outb_p = sh7300se_outb_p,
+ .mv_outw_p = sh7300se_outw,
+ .mv_outl_p = sh7300se_outl,
+
+ .mv_insb = sh7300se_insb,
+ .mv_insw = sh7300se_insw,
+ .mv_insl = sh7300se_insl,
+ .mv_outsb = sh7300se_outsb,
+ .mv_outsw = sh7300se_outsw,
+ .mv_outsl = sh7300se_outsl,
+
+ .mv_init_irq = init_7300se_IRQ,
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_7300se,
+#endif
+};
+
+ALIAS_MV(7300se)
+/*
+ * Initialize the board
+ */
+void __init
+platform_setup(void)
+{
+
+}
diff --git a/arch/sh/boards/se/73180/Makefile b/arch/sh/boards/se/73180/Makefile
new file mode 100644
index 000000000000..8f63886a0f3f
--- /dev/null
+++ b/arch/sh/boards/se/73180/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the 73180 SolutionEngine specific parts of the kernel
+#
+
+obj-y := setup.o io.o irq.o
+
+obj-$(CONFIG_HEARTBEAT) += led.o
diff --git a/arch/sh/boards/se/73180/io.c b/arch/sh/boards/se/73180/io.c
new file mode 100644
index 000000000000..73648cbe3678
--- /dev/null
+++ b/arch/sh/boards/se/73180/io.c
@@ -0,0 +1,265 @@
+/*
+ * arch/sh/boards/se/73180/io.c
+ *
+ * Copyright (C) 2003 YOSHII Takashi <yoshii-takashi@hitachi-ul.co.jp>
+ * Based on arch/sh/boards/se/7300/io.c
+ *
+ * I/O routine for SH-Mobile3 73180 SolutionEngine.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <asm/mach/se73180.h>
+#include <asm/io.h>
+
+#define badio(fn, a) panic("bad i/o operation %s for %08lx.", #fn, a)
+
+struct iop {
+ unsigned long start, end;
+ unsigned long base;
+ struct iop *(*check) (struct iop * p, unsigned long port);
+ unsigned char (*inb) (struct iop * p, unsigned long port);
+ unsigned short (*inw) (struct iop * p, unsigned long port);
+ void (*outb) (struct iop * p, unsigned char value, unsigned long port);
+ void (*outw) (struct iop * p, unsigned short value, unsigned long port);
+};
+
+struct iop *
+simple_check(struct iop *p, unsigned long port)
+{
+ if ((p->start <= port) && (port <= p->end))
+ return p;
+ else
+ badio(check, port);
+}
+
+struct iop *
+ide_check(struct iop *p, unsigned long port)
+{
+ if (((0x1f0 <= port) && (port <= 0x1f7)) || (port == 0x3f7))
+ return p;
+ return NULL;
+}
+
+unsigned char
+simple_inb(struct iop *p, unsigned long port)
+{
+ return *(unsigned char *) (p->base + port);
+}
+
+unsigned short
+simple_inw(struct iop *p, unsigned long port)
+{
+ return *(unsigned short *) (p->base + port);
+}
+
+void
+simple_outb(struct iop *p, unsigned char value, unsigned long port)
+{
+ *(unsigned char *) (p->base + port) = value;
+}
+
+void
+simple_outw(struct iop *p, unsigned short value, unsigned long port)
+{
+ *(unsigned short *) (p->base + port) = value;
+}
+
+unsigned char
+pcc_inb(struct iop *p, unsigned long port)
+{
+ unsigned long addr = p->base + port + 0x40000;
+ unsigned long v;
+
+ if (port & 1)
+ addr += 0x00400000;
+ v = *(volatile unsigned char *) addr;
+ return v;
+}
+
+void
+pcc_outb(struct iop *p, unsigned char value, unsigned long port)
+{
+ unsigned long addr = p->base + port + 0x40000;
+
+ if (port & 1)
+ addr += 0x00400000;
+ *(volatile unsigned char *) addr = value;
+}
+
+unsigned char
+bad_inb(struct iop *p, unsigned long port)
+{
+ badio(inb, port);
+}
+
+void
+bad_outb(struct iop *p, unsigned char value, unsigned long port)
+{
+ badio(inw, port);
+}
+
+/* MSTLANEX01 LAN at 0xb400:0000 */
+static struct iop laniop = {
+ .start = 0x300,
+ .end = 0x30f,
+ .base = 0xb4000000,
+ .check = simple_check,
+ .inb = simple_inb,
+ .inw = simple_inw,
+ .outb = simple_outb,
+ .outw = simple_outw,
+};
+
+/* NE2000 pc card NIC */
+static struct iop neiop = {
+ .start = 0x280,
+ .end = 0x29f,
+ .base = 0xb0600000 + 0x80, /* soft 0x280 -> hard 0x300 */
+ .check = simple_check,
+ .inb = pcc_inb,
+ .inw = simple_inw,
+ .outb = pcc_outb,
+ .outw = simple_outw,
+};
+
+/* CF in CF slot */
+static struct iop cfiop = {
+ .base = 0xb0600000,
+ .check = ide_check,
+ .inb = pcc_inb,
+ .inw = simple_inw,
+ .outb = pcc_outb,
+ .outw = simple_outw,
+};
+
+static __inline__ struct iop *
+port2iop(unsigned long port)
+{
+ if (0) ;
+#if defined(CONFIG_SMC91111)
+ else if (laniop.check(&laniop, port))
+ return &laniop;
+#endif
+#if defined(CONFIG_NE2000)
+ else if (neiop.check(&neiop, port))
+ return &neiop;
+#endif
+#if defined(CONFIG_IDE)
+ else if (cfiop.check(&cfiop, port))
+ return &cfiop;
+#endif
+ else
+ return &neiop; /* fallback */
+}
+
+static inline void
+delay(void)
+{
+ ctrl_inw(0xac000000);
+ ctrl_inw(0xac000000);
+}
+
+unsigned char
+sh73180se_inb(unsigned long port)
+{
+ struct iop *p = port2iop(port);
+ return (p->inb) (p, port);
+}
+
+unsigned char
+sh73180se_inb_p(unsigned long port)
+{
+ unsigned char v = sh73180se_inb(port);
+ delay();
+ return v;
+}
+
+unsigned short
+sh73180se_inw(unsigned long port)
+{
+ struct iop *p = port2iop(port);
+ return (p->inw) (p, port);
+}
+
+unsigned int
+sh73180se_inl(unsigned long port)
+{
+ badio(inl, port);
+}
+
+void
+sh73180se_outb(unsigned char value, unsigned long port)
+{
+ struct iop *p = port2iop(port);
+ (p->outb) (p, value, port);
+}
+
+void
+sh73180se_outb_p(unsigned char value, unsigned long port)
+{
+ sh73180se_outb(value, port);
+ delay();
+}
+
+void
+sh73180se_outw(unsigned short value, unsigned long port)
+{
+ struct iop *p = port2iop(port);
+ (p->outw) (p, value, port);
+}
+
+void
+sh73180se_outl(unsigned int value, unsigned long port)
+{
+ badio(outl, port);
+}
+
+void
+sh73180se_insb(unsigned long port, void *addr, unsigned long count)
+{
+ unsigned char *a = addr;
+ struct iop *p = port2iop(port);
+ while (count--)
+ *a++ = (p->inb) (p, port);
+}
+
+void
+sh73180se_insw(unsigned long port, void *addr, unsigned long count)
+{
+ unsigned short *a = addr;
+ struct iop *p = port2iop(port);
+ while (count--)
+ *a++ = (p->inw) (p, port);
+}
+
+void
+sh73180se_insl(unsigned long port, void *addr, unsigned long count)
+{
+ badio(insl, port);
+}
+
+void
+sh73180se_outsb(unsigned long port, const void *addr, unsigned long count)
+{
+ unsigned char *a = (unsigned char *) addr;
+ struct iop *p = port2iop(port);
+ while (count--)
+ (p->outb) (p, *a++, port);
+}
+
+void
+sh73180se_outsw(unsigned long port, const void *addr, unsigned long count)
+{
+ unsigned short *a = (unsigned short *) addr;
+ struct iop *p = port2iop(port);
+ while (count--)
+ (p->outw) (p, *a++, port);
+}
+
+void
+sh73180se_outsl(unsigned long port, const void *addr, unsigned long count)
+{
+ badio(outsw, port);
+}
diff --git a/arch/sh/boards/se/73180/irq.c b/arch/sh/boards/se/73180/irq.c
new file mode 100644
index 000000000000..70f04caad9a4
--- /dev/null
+++ b/arch/sh/boards/se/73180/irq.c
@@ -0,0 +1,137 @@
+/*
+ * arch/sh/boards/se/73180/irq.c
+ *
+ * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
+ * Based on arch/sh/boards/se/7300/irq.c
+ *
+ * Modified for SH-Mobile SolutionEngine 73180 Support
+ * by YOSHII Takashi <yoshii-takashi@hitachi-ul.co.jp>
+ *
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mach/se73180.h>
+
+static int
+intreq2irq(int i)
+{
+ if (i == 5)
+ return 10;
+ return 32 + 7 - i;
+}
+
+static int
+irq2intreq(int irq)
+{
+ if (irq == 10)
+ return 5;
+ return 7 - (irq - 32);
+}
+
+static void
+disable_intreq_irq(unsigned int irq)
+{
+ ctrl_outb(1 << (7 - irq2intreq(irq)), INTMSK0);
+}
+
+static void
+enable_intreq_irq(unsigned int irq)
+{
+ ctrl_outb(1 << (7 - irq2intreq(irq)), INTMSKCLR0);
+}
+
+static void
+mask_and_ack_intreq_irq(unsigned int irq)
+{
+ disable_intreq_irq(irq);
+}
+
+static unsigned int
+startup_intreq_irq(unsigned int irq)
+{
+ enable_intreq_irq(irq);
+ return 0;
+}
+
+static void
+shutdown_intreq_irq(unsigned int irq)
+{
+ disable_intreq_irq(irq);
+}
+
+static void
+end_intreq_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+ enable_intreq_irq(irq);
+}
+
+static struct hw_interrupt_type intreq_irq_type = {
+ .typename = "intreq",
+ .startup = startup_intreq_irq,
+ .shutdown = shutdown_intreq_irq,
+ .enable = enable_intreq_irq,
+ .disable = disable_intreq_irq,
+ .ack = mask_and_ack_intreq_irq,
+ .end = end_intreq_irq
+};
+
+void
+make_intreq_irq(unsigned int irq)
+{
+ disable_irq_nosync(irq);
+ irq_desc[irq].handler = &intreq_irq_type;
+ disable_intreq_irq(irq);
+}
+
+int
+shmse_irq_demux(int irq)
+{
+ if (irq == IRQ5_IRQ)
+ return 10;
+ return irq;
+}
+
+/*
+ * Initialize IRQ setting
+ */
+void __init
+init_73180se_IRQ(void)
+{
+ make_ipr_irq(SIOF0_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY);
+
+ ctrl_outw(0x2000, 0xb03fffec); /* mrshpc irq enable */
+ ctrl_outw(0x2000, 0xb07fffec); /* mrshpc irq enable */
+ ctrl_outl(3 << ((7 - 5) * 4), INTC_INTPRI0); /* irq5 pri=3 */
+ ctrl_outw(2 << ((7 - 5) * 2), INTC_ICR1); /* low-level irq */
+ make_intreq_irq(10);
+
+ make_ipr_irq(VPU_IRQ, VPU_IPR_ADDR, VPU_IPR_POS, 8);
+
+ ctrl_outb(0x0f, INTC_IMCR5); /* enable SCIF IRQ */
+
+ make_ipr_irq(DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY);
+ make_ipr_irq(DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY);
+ make_ipr_irq(DMTE4_IRQ, DMA2_IPR_ADDR, DMA2_IPR_POS, DMA2_PRIORITY);
+ make_ipr_irq(IIC0_ALI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS, IIC0_PRIORITY);
+ make_ipr_irq(IIC0_TACKI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS,
+ IIC0_PRIORITY);
+ make_ipr_irq(IIC0_WAITI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS,
+ IIC0_PRIORITY);
+ make_ipr_irq(IIC0_DTEI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS, IIC0_PRIORITY);
+ make_ipr_irq(SIOF0_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY);
+ make_ipr_irq(SIU_IRQ, SIU_IPR_ADDR, SIU_IPR_POS, SIU_PRIORITY);
+
+ /* VIO interrupt */
+ make_ipr_irq(CEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY);
+ make_ipr_irq(BEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY);
+ make_ipr_irq(VEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY);
+
+ make_ipr_irq(LCDC_IRQ, LCDC_IPR_ADDR, LCDC_IPR_POS, LCDC_PRIORITY);
+ ctrl_outw(0x2000, PA_MRSHPC + 0x0c); /* mrshpc irq enable */
+}
diff --git a/arch/sh/boards/se/73180/led.c b/arch/sh/boards/se/73180/led.c
new file mode 100644
index 000000000000..1e8f1cf3e10f
--- /dev/null
+++ b/arch/sh/boards/se/73180/led.c
@@ -0,0 +1,67 @@
+/*
+ * arch/sh/boards/se/73180/led.c
+ *
+ * Derived from arch/sh/boards/se/770x/led.c
+ *
+ * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * This file contains Solution Engine specific LED code.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <asm/mach/se73180.h>
+
+static void
+mach_led(int position, int value)
+{
+ volatile unsigned short *p = (volatile unsigned short *) PA_LED;
+
+ if (value) {
+ *p |= (1 << LED_SHIFT);
+ } else {
+ *p &= ~(1 << LED_SHIFT);
+ }
+}
+
+/* Cycle the LED's in the clasic Knightrider/Sun pattern */
+void
+heartbeat_73180se(void)
+{
+ static unsigned int cnt = 0, period = 0;
+ volatile unsigned short *p = (volatile unsigned short *) PA_LED;
+ static unsigned bit = 0, up = 1;
+
+ cnt += 1;
+ if (cnt < period) {
+ return;
+ }
+
+ cnt = 0;
+
+ /* Go through the points (roughly!):
+ * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110
+ */
+ period = 110 - ((300 << FSHIFT) / ((avenrun[0] / 5) + (3 << FSHIFT)));
+
+ if (up) {
+ if (bit == 7) {
+ bit--;
+ up = 0;
+ } else {
+ bit++;
+ }
+ } else {
+ if (bit == 0) {
+ bit++;
+ up = 1;
+ } else {
+ bit--;
+ }
+ }
+ *p = 1 << (bit + LED_SHIFT);
+
+}
diff --git a/arch/sh/boards/se/73180/setup.c b/arch/sh/boards/se/73180/setup.c
new file mode 100644
index 000000000000..07fa90c38a06
--- /dev/null
+++ b/arch/sh/boards/se/73180/setup.c
@@ -0,0 +1,68 @@
+/*
+ * arch/sh/boards/se/73180/setup.c
+ *
+ * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
+ * Based on arch/sh/setup_shmse.c
+ *
+ * Modified for 73180 SolutionEngine
+ * by YOSHII Takashi <yoshii-takashi@hitachi-ul.co.jp>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/machvec.h>
+#include <asm/machvec_init.h>
+#include <asm/mach/io.h>
+
+void heartbeat_73180se(void);
+void init_73180se_IRQ(void);
+
+const char *
+get_system_type(void)
+{
+ return "SolutionEngine 73180";
+}
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_73180se __initmv = {
+ .mv_nr_irqs = 108,
+ .mv_inb = sh73180se_inb,
+ .mv_inw = sh73180se_inw,
+ .mv_inl = sh73180se_inl,
+ .mv_outb = sh73180se_outb,
+ .mv_outw = sh73180se_outw,
+ .mv_outl = sh73180se_outl,
+
+ .mv_inb_p = sh73180se_inb_p,
+ .mv_inw_p = sh73180se_inw,
+ .mv_inl_p = sh73180se_inl,
+ .mv_outb_p = sh73180se_outb_p,
+ .mv_outw_p = sh73180se_outw,
+ .mv_outl_p = sh73180se_outl,
+
+ .mv_insb = sh73180se_insb,
+ .mv_insw = sh73180se_insw,
+ .mv_insl = sh73180se_insl,
+ .mv_outsb = sh73180se_outsb,
+ .mv_outsw = sh73180se_outsw,
+ .mv_outsl = sh73180se_outsl,
+
+ .mv_init_irq = init_73180se_IRQ,
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_73180se,
+#endif
+};
+
+ALIAS_MV(73180se)
+/*
+ * Initialize the board
+ */
+void __init
+platform_setup(void)
+{
+
+}
diff --git a/arch/sh/boards/se/770x/Makefile b/arch/sh/boards/se/770x/Makefile
new file mode 100644
index 000000000000..be89a73cc418
--- /dev/null
+++ b/arch/sh/boards/se/770x/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the 770x SolutionEngine specific parts of the kernel
+#
+
+obj-y := mach.o setup.o io.o irq.o led.o
+
diff --git a/arch/sh/boards/se/770x/io.c b/arch/sh/boards/se/770x/io.c
new file mode 100644
index 000000000000..9a39ee963143
--- /dev/null
+++ b/arch/sh/boards/se/770x/io.c
@@ -0,0 +1,226 @@
+/* $Id: io.c,v 1.5 2004/02/22 23:08:43 kkojima Exp $
+ *
+ * linux/arch/sh/kernel/io_se.c
+ *
+ * Copyright (C) 2000 Kazumoto Kojima
+ *
+ * I/O routine for Hitachi SolutionEngine.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/se/se.h>
+
+/* SH pcmcia io window base, start and end. */
+int sh_pcic_io_wbase = 0xb8400000;
+int sh_pcic_io_start;
+int sh_pcic_io_stop;
+int sh_pcic_io_type;
+int sh_pcic_io_dummy;
+
+static inline void delay(void)
+{
+ ctrl_inw(0xa0000000);
+}
+
+/* MS7750 requires special versions of in*, out* routines, since
+ PC-like io ports are located at upper half byte of 16-bit word which
+ can be accessed only with 16-bit wide. */
+
+static inline volatile __u16 *
+port2adr(unsigned int port)
+{
+ if (port >= 0x2000)
+ return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
+ else if (port >= 0x1000)
+ return (volatile __u16 *) (PA_83902 + (port << 1));
+ else if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)
+ return (volatile __u16 *) (sh_pcic_io_wbase + (port &~ 1));
+ else
+ return (volatile __u16 *) (PA_SUPERIO + (port << 1));
+}
+
+static inline int
+shifted_port(unsigned long port)
+{
+ /* For IDE registers, value is not shifted */
+ if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
+ return 0;
+ else
+ return 1;
+}
+
+#define maybebadio(name,port) \
+ printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
+ #name, (port), (__u32) __builtin_return_address(0))
+
+unsigned char se_inb(unsigned long port)
+{
+ if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)
+ return *(__u8 *) (sh_pcic_io_wbase + 0x40000 + port);
+ else if (shifted_port(port))
+ return (*port2adr(port) >> 8);
+ else
+ return (*port2adr(port))&0xff;
+}
+
+unsigned char se_inb_p(unsigned long port)
+{
+ unsigned long v;
+
+ if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)
+ v = *(__u8 *) (sh_pcic_io_wbase + 0x40000 + port);
+ else if (shifted_port(port))
+ v = (*port2adr(port) >> 8);
+ else
+ v = (*port2adr(port))&0xff;
+ delay();
+ return v;
+}
+
+unsigned short se_inw(unsigned long port)
+{
+ if (port >= 0x2000 ||
+ (sh_pcic_io_start <= port && port <= sh_pcic_io_stop))
+ return *port2adr(port);
+ else
+ maybebadio(inw, port);
+ return 0;
+}
+
+unsigned int se_inl(unsigned long port)
+{
+ maybebadio(inl, port);
+ return 0;
+}
+
+void se_outb(unsigned char value, unsigned long port)
+{
+ if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)
+ *(__u8 *)(sh_pcic_io_wbase + port) = value;
+ else if (shifted_port(port))
+ *(port2adr(port)) = value << 8;
+ else
+ *(port2adr(port)) = value;
+}
+
+void se_outb_p(unsigned char value, unsigned long port)
+{
+ if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)
+ *(__u8 *)(sh_pcic_io_wbase + port) = value;
+ else if (shifted_port(port))
+ *(port2adr(port)) = value << 8;
+ else
+ *(port2adr(port)) = value;
+ delay();
+}
+
+void se_outw(unsigned short value, unsigned long port)
+{
+ if (port >= 0x2000 ||
+ (sh_pcic_io_start <= port && port <= sh_pcic_io_stop))
+ *port2adr(port) = value;
+ else
+ maybebadio(outw, port);
+}
+
+void se_outl(unsigned int value, unsigned long port)
+{
+ maybebadio(outl, port);
+}
+
+void se_insb(unsigned long port, void *addr, unsigned long count)
+{
+ volatile __u16 *p = port2adr(port);
+ __u8 *ap = addr;
+
+ if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) {
+ volatile __u8 *bp = (__u8 *) (sh_pcic_io_wbase + 0x40000 + port);
+ while (count--)
+ *ap++ = *bp;
+ } else if (shifted_port(port)) {
+ while (count--)
+ *ap++ = *p >> 8;
+ } else {
+ while (count--)
+ *ap++ = *p;
+ }
+}
+
+void se_insw(unsigned long port, void *addr, unsigned long count)
+{
+ volatile __u16 *p = port2adr(port);
+ __u16 *ap = addr;
+ while (count--)
+ *ap++ = *p;
+}
+
+void se_insl(unsigned long port, void *addr, unsigned long count)
+{
+ maybebadio(insl, port);
+}
+
+void se_outsb(unsigned long port, const void *addr, unsigned long count)
+{
+ volatile __u16 *p = port2adr(port);
+ const __u8 *ap = addr;
+
+ if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) {
+ volatile __u8 *bp = (__u8 *) (sh_pcic_io_wbase + port);
+ while (count--)
+ *bp = *ap++;
+ } else if (shifted_port(port)) {
+ while (count--)
+ *p = *ap++ << 8;
+ } else {
+ while (count--)
+ *p = *ap++;
+ }
+}
+
+void se_outsw(unsigned long port, const void *addr, unsigned long count)
+{
+ volatile __u16 *p = port2adr(port);
+ const __u16 *ap = addr;
+ while (count--)
+ *p = *ap++;
+}
+
+void se_outsl(unsigned long port, const void *addr, unsigned long count)
+{
+ maybebadio(outsw, port);
+}
+
+/* Map ISA bus address to the real address. Only for PCMCIA. */
+
+/* ISA page descriptor. */
+static __u32 sh_isa_memmap[256];
+
+static int
+sh_isa_mmap(__u32 start, __u32 length, __u32 offset)
+{
+ int idx;
+
+ if (start >= 0x100000 || (start & 0xfff) || (length != 0x1000))
+ return -1;
+
+ idx = start >> 12;
+ sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff);
+#if 0
+ printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n",
+ start, length, offset, idx, sh_isa_memmap[idx]);
+#endif
+ return 0;
+}
+
+unsigned long
+se_isa_port2addr(unsigned long offset)
+{
+ int idx;
+
+ idx = (offset >> 12) & 0xff;
+ offset &= 0xfff;
+ return sh_isa_memmap[idx] + offset;
+}
diff --git a/arch/sh/boards/se/770x/irq.c b/arch/sh/boards/se/770x/irq.c
new file mode 100644
index 000000000000..210897b315f4
--- /dev/null
+++ b/arch/sh/boards/se/770x/irq.c
@@ -0,0 +1,80 @@
+/*
+ * linux/arch/sh/boards/se/770x/irq.c
+ *
+ * Copyright (C) 2000 Kazumoto Kojima
+ *
+ * Hitachi SolutionEngine Support.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/se/se.h>
+
+/*
+ * Initialize IRQ setting
+ */
+void __init init_se_IRQ(void)
+{
+ /*
+ * Super I/O (Just mimic PC):
+ * 1: keyboard
+ * 3: serial 0
+ * 4: serial 1
+ * 5: printer
+ * 6: floppy
+ * 8: rtc
+ * 12: mouse
+ * 14: ide0
+ */
+#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+ /* Disable all interrupts */
+ ctrl_outw(0, BCR_ILCRA);
+ ctrl_outw(0, BCR_ILCRB);
+ ctrl_outw(0, BCR_ILCRC);
+ ctrl_outw(0, BCR_ILCRD);
+ ctrl_outw(0, BCR_ILCRE);
+ ctrl_outw(0, BCR_ILCRF);
+ ctrl_outw(0, BCR_ILCRG);
+ /* This is default value */
+ make_ipr_irq(0xf-0x2, BCR_ILCRA, 2, 0x2);
+ make_ipr_irq(0xf-0xa, BCR_ILCRA, 1, 0xa);
+ make_ipr_irq(0xf-0x5, BCR_ILCRB, 0, 0x5);
+ make_ipr_irq(0xf-0x8, BCR_ILCRC, 1, 0x8);
+ make_ipr_irq(0xf-0xc, BCR_ILCRC, 0, 0xc);
+ make_ipr_irq(0xf-0xe, BCR_ILCRD, 3, 0xe);
+ make_ipr_irq(0xf-0x3, BCR_ILCRD, 1, 0x3); /* LAN */
+ make_ipr_irq(0xf-0xd, BCR_ILCRE, 2, 0xd);
+ make_ipr_irq(0xf-0x9, BCR_ILCRE, 1, 0x9);
+ make_ipr_irq(0xf-0x1, BCR_ILCRE, 0, 0x1);
+ make_ipr_irq(0xf-0xf, BCR_ILCRF, 3, 0xf);
+ make_ipr_irq(0xf-0xb, BCR_ILCRF, 1, 0xb);
+ make_ipr_irq(0xf-0x7, BCR_ILCRG, 3, 0x7);
+ make_ipr_irq(0xf-0x6, BCR_ILCRG, 2, 0x6);
+ make_ipr_irq(0xf-0x4, BCR_ILCRG, 1, 0x4);
+#else
+ make_ipr_irq(14, BCR_ILCRA, 2, 0x0f-14);
+ make_ipr_irq(12, BCR_ILCRA, 1, 0x0f-12);
+ make_ipr_irq( 8, BCR_ILCRB, 1, 0x0f- 8);
+ make_ipr_irq( 6, BCR_ILCRC, 3, 0x0f- 6);
+ make_ipr_irq( 5, BCR_ILCRC, 2, 0x0f- 5);
+ make_ipr_irq( 4, BCR_ILCRC, 1, 0x0f- 4);
+ make_ipr_irq( 3, BCR_ILCRC, 0, 0x0f- 3);
+ make_ipr_irq( 1, BCR_ILCRD, 3, 0x0f- 1);
+
+ make_ipr_irq(10, BCR_ILCRD, 1, 0x0f-10); /* LAN */
+
+ make_ipr_irq( 0, BCR_ILCRE, 3, 0x0f- 0); /* PCIRQ3 */
+ make_ipr_irq(11, BCR_ILCRE, 2, 0x0f-11); /* PCIRQ2 */
+ make_ipr_irq( 9, BCR_ILCRE, 1, 0x0f- 9); /* PCIRQ1 */
+ make_ipr_irq( 7, BCR_ILCRE, 0, 0x0f- 7); /* PCIRQ0 */
+
+ /* #2, #13 are allocated for SLOT IRQ #1 and #2 (for now) */
+ /* NOTE: #2 and #13 are not used on PC */
+ make_ipr_irq(13, BCR_ILCRG, 1, 0x0f-13); /* SLOTIRQ2 */
+ make_ipr_irq( 2, BCR_ILCRG, 0, 0x0f- 2); /* SLOTIRQ1 */
+#endif
+}
diff --git a/arch/sh/boards/se/770x/led.c b/arch/sh/boards/se/770x/led.c
new file mode 100644
index 000000000000..5c64e8ab2cfb
--- /dev/null
+++ b/arch/sh/boards/se/770x/led.c
@@ -0,0 +1,68 @@
+/*
+ * linux/arch/sh/kernel/led_se.c
+ *
+ * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * This file contains Solution Engine specific LED code.
+ */
+
+#include <linux/config.h>
+#include <asm/se/se.h>
+
+static void mach_led(int position, int value)
+{
+ volatile unsigned short* p = (volatile unsigned short*)PA_LED;
+
+ if (value) {
+ *p |= (1<<8);
+ } else {
+ *p &= ~(1<<8);
+ }
+}
+
+#ifdef CONFIG_HEARTBEAT
+
+#include <linux/sched.h>
+
+/* Cycle the LED's in the clasic Knightrider/Sun pattern */
+void heartbeat_se(void)
+{
+ static unsigned int cnt = 0, period = 0;
+ volatile unsigned short* p = (volatile unsigned short*)PA_LED;
+ static unsigned bit = 0, up = 1;
+
+ cnt += 1;
+ if (cnt < period) {
+ return;
+ }
+
+ cnt = 0;
+
+ /* Go through the points (roughly!):
+ * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110
+ */
+ period = 110 - ( (300<<FSHIFT)/
+ ((avenrun[0]/5) + (3<<FSHIFT)) );
+
+ if (up) {
+ if (bit == 7) {
+ bit--;
+ up=0;
+ } else {
+ bit ++;
+ }
+ } else {
+ if (bit == 0) {
+ bit++;
+ up=1;
+ } else {
+ bit--;
+ }
+ }
+ *p = 1<<(bit+8);
+
+}
+#endif /* CONFIG_HEARTBEAT */
diff --git a/arch/sh/boards/se/770x/mach.c b/arch/sh/boards/se/770x/mach.c
new file mode 100644
index 000000000000..f9b4c56cc47e
--- /dev/null
+++ b/arch/sh/boards/se/770x/mach.c
@@ -0,0 +1,68 @@
+/*
+ * linux/arch/sh/kernel/mach_se.c
+ *
+ * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Machine vector for the Hitachi SolutionEngine
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/machvec_init.h>
+
+#include <asm/se/io.h>
+
+void heartbeat_se(void);
+void setup_se(void);
+void init_se_IRQ(void);
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_se __initmv = {
+#if defined(CONFIG_CPU_SH4)
+ .mv_nr_irqs = 48,
+#elif defined(CONFIG_CPU_SUBTYPE_SH7708)
+ .mv_nr_irqs = 32,
+#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
+ .mv_nr_irqs = 61,
+#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
+ .mv_nr_irqs = 86,
+#endif
+
+ .mv_inb = se_inb,
+ .mv_inw = se_inw,
+ .mv_inl = se_inl,
+ .mv_outb = se_outb,
+ .mv_outw = se_outw,
+ .mv_outl = se_outl,
+
+ .mv_inb_p = se_inb_p,
+ .mv_inw_p = se_inw,
+ .mv_inl_p = se_inl,
+ .mv_outb_p = se_outb_p,
+ .mv_outw_p = se_outw,
+ .mv_outl_p = se_outl,
+
+ .mv_insb = se_insb,
+ .mv_insw = se_insw,
+ .mv_insl = se_insl,
+ .mv_outsb = se_outsb,
+ .mv_outsw = se_outsw,
+ .mv_outsl = se_outsl,
+
+ .mv_isa_port2addr = se_isa_port2addr,
+
+ .mv_init_irq = init_se_IRQ,
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_se,
+#endif
+};
+ALIAS_MV(se)
diff --git a/arch/sh/boards/se/770x/setup.c b/arch/sh/boards/se/770x/setup.c
new file mode 100644
index 000000000000..2bed46fb607d
--- /dev/null
+++ b/arch/sh/boards/se/770x/setup.c
@@ -0,0 +1,85 @@
+/* $Id: setup.c,v 1.1.2.4 2002/03/02 21:57:07 lethal Exp $
+ *
+ * linux/arch/sh/boards/se/770x/setup.c
+ *
+ * Copyright (C) 2000 Kazumoto Kojima
+ *
+ * Hitachi SolutionEngine Support.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+#include <asm/se/se.h>
+#include <asm/se/smc37c93x.h>
+
+/*
+ * Configure the Super I/O chip
+ */
+static void __init smsc_config(int index, int data)
+{
+ outb_p(index, INDEX_PORT);
+ outb_p(data, DATA_PORT);
+}
+
+static void __init init_smsc(void)
+{
+ outb_p(CONFIG_ENTER, CONFIG_PORT);
+ outb_p(CONFIG_ENTER, CONFIG_PORT);
+
+ /* FDC */
+ smsc_config(CURRENT_LDN_INDEX, LDN_FDC);
+ smsc_config(ACTIVATE_INDEX, 0x01);
+ smsc_config(IRQ_SELECT_INDEX, 6); /* IRQ6 */
+
+ /* IDE1 */
+ smsc_config(CURRENT_LDN_INDEX, LDN_IDE1);
+ smsc_config(ACTIVATE_INDEX, 0x01);
+ smsc_config(IRQ_SELECT_INDEX, 14); /* IRQ14 */
+
+ /* AUXIO (GPIO): to use IDE1 */
+ smsc_config(CURRENT_LDN_INDEX, LDN_AUXIO);
+ smsc_config(GPIO46_INDEX, 0x00); /* nIOROP */
+ smsc_config(GPIO47_INDEX, 0x00); /* nIOWOP */
+
+ /* COM1 */
+ smsc_config(CURRENT_LDN_INDEX, LDN_COM1);
+ smsc_config(ACTIVATE_INDEX, 0x01);
+ smsc_config(IO_BASE_HI_INDEX, 0x03);
+ smsc_config(IO_BASE_LO_INDEX, 0xf8);
+ smsc_config(IRQ_SELECT_INDEX, 4); /* IRQ4 */
+
+ /* COM2 */
+ smsc_config(CURRENT_LDN_INDEX, LDN_COM2);
+ smsc_config(ACTIVATE_INDEX, 0x01);
+ smsc_config(IO_BASE_HI_INDEX, 0x02);
+ smsc_config(IO_BASE_LO_INDEX, 0xf8);
+ smsc_config(IRQ_SELECT_INDEX, 3); /* IRQ3 */
+
+ /* RTC */
+ smsc_config(CURRENT_LDN_INDEX, LDN_RTC);
+ smsc_config(ACTIVATE_INDEX, 0x01);
+ smsc_config(IRQ_SELECT_INDEX, 8); /* IRQ8 */
+
+ /* XXX: PARPORT, KBD, and MOUSE will come here... */
+ outb_p(CONFIG_EXIT, CONFIG_PORT);
+}
+
+const char *get_system_type(void)
+{
+ return "SolutionEngine";
+}
+
+/*
+ * Initialize the board
+ */
+void __init platform_setup(void)
+{
+ init_smsc();
+ /* XXX: RTC setting comes here */
+}
diff --git a/arch/sh/boards/se/7751/Makefile b/arch/sh/boards/se/7751/Makefile
new file mode 100644
index 000000000000..ce7ca247f84d
--- /dev/null
+++ b/arch/sh/boards/se/7751/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the 7751 SolutionEngine specific parts of the kernel
+#
+
+obj-y := mach.o setup.o io.o irq.o led.o
+
+obj-$(CONFIG_PCI) += pci.o
+
diff --git a/arch/sh/boards/se/7751/io.c b/arch/sh/boards/se/7751/io.c
new file mode 100644
index 000000000000..99041b269261
--- /dev/null
+++ b/arch/sh/boards/se/7751/io.c
@@ -0,0 +1,244 @@
+/*
+ * linux/arch/sh/kernel/io_7751se.c
+ *
+ * Copyright (C) 2001 Ian da Silva, Jeremy Siegel
+ * Based largely on io_se.c.
+ *
+ * I/O routine for Hitachi 7751 SolutionEngine.
+ *
+ * Initial version only to support LAN access; some
+ * placeholder code from io_se.c left in with the
+ * expectation of later SuperIO and PCMCIA access.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/se7751/se7751.h>
+#include <asm/addrspace.h>
+
+#include <linux/pci.h>
+#include "../../../drivers/pci/pci-sh7751.h"
+
+#if 0
+/******************************************************************
+ * Variables from io_se.c, related to PCMCIA (not PCI); we're not
+ * compiling them in, and have removed references from functions
+ * which follow. [Many checked for IO ports in the range bounded
+ * by sh_pcic_io_start/stop, and used sh_pcic_io_wbase as offset.
+ * As start/stop are uninitialized, only port 0x0 would match?]
+ * When used, remember to adjust names to avoid clash with io_se?
+ *****************************************************************/
+/* SH pcmcia io window base, start and end. */
+int sh_pcic_io_wbase = 0xb8400000;
+int sh_pcic_io_start;
+int sh_pcic_io_stop;
+int sh_pcic_io_type;
+int sh_pcic_io_dummy;
+/*************************************************************/
+#endif
+
+/*
+ * The 7751 Solution Engine uses the built-in PCI controller (PCIC)
+ * of the 7751 processor, and has a SuperIO accessible via the PCI.
+ * The board also includes a PCMCIA controller on its memory bus,
+ * like the other Solution Engine boards.
+ */
+
+#define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR)
+#define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR)
+#define PCI_IO_AREA SH7751_PCI_IO_BASE
+#define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE
+
+#define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK))
+
+#define maybebadio(name,port) \
+ printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
+ #name, (port), (__u32) __builtin_return_address(0))
+
+static inline void delay(void)
+{
+ ctrl_inw(0xa0000000);
+}
+
+static inline volatile __u16 *
+port2adr(unsigned int port)
+{
+ if (port >= 0x2000)
+ return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
+#if 0
+ else
+ return (volatile __u16 *) (PA_SUPERIO + (port << 1));
+#endif
+ maybebadio(name,(unsigned long)port);
+ return (volatile __u16*)port;
+}
+
+#if 0
+/* The 7751 Solution Engine seems to have everything hooked */
+/* up pretty normally (nothing on high-bytes only...) so this */
+/* shouldn't be needed */
+static inline int
+shifted_port(unsigned long port)
+{
+ /* For IDE registers, value is not shifted */
+ if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
+ return 0;
+ else
+ return 1;
+}
+#endif
+
+/* In case someone configures the kernel w/o PCI support: in that */
+/* scenario, don't ever bother to check for PCI-window addresses */
+
+/* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */
+#if defined(CONFIG_PCI)
+#define CHECK_SH7751_PCIIO(port) \
+ ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
+#else
+#define CHECK_SH7751_PCIIO(port) (0)
+#endif
+
+/*
+ * General outline: remap really low stuff [eventually] to SuperIO,
+ * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
+ * is mapped through the PCI IO window. Stuff with high bits (PXSEG)
+ * should be way beyond the window, and is used w/o translation for
+ * compatibility.
+ */
+unsigned char sh7751se_inb(unsigned long port)
+{
+ if (PXSEG(port))
+ return *(volatile unsigned char *)port;
+ else if (CHECK_SH7751_PCIIO(port))
+ return *(volatile unsigned char *)PCI_IOMAP(port);
+ else
+ return (*port2adr(port))&0xff;
+}
+
+unsigned char sh7751se_inb_p(unsigned long port)
+{
+ unsigned char v;
+
+ if (PXSEG(port))
+ v = *(volatile unsigned char *)port;
+ else if (CHECK_SH7751_PCIIO(port))
+ v = *(volatile unsigned char *)PCI_IOMAP(port);
+ else
+ v = (*port2adr(port))&0xff;
+ delay();
+ return v;
+}
+
+unsigned short sh7751se_inw(unsigned long port)
+{
+ if (PXSEG(port))
+ return *(volatile unsigned short *)port;
+ else if (CHECK_SH7751_PCIIO(port))
+ return *(volatile unsigned short *)PCI_IOMAP(port);
+ else if (port >= 0x2000)
+ return *port2adr(port);
+ else
+ maybebadio(inw, port);
+ return 0;
+}
+
+unsigned int sh7751se_inl(unsigned long port)
+{
+ if (PXSEG(port))
+ return *(volatile unsigned long *)port;
+ else if (CHECK_SH7751_PCIIO(port))
+ return *(volatile unsigned int *)PCI_IOMAP(port);
+ else if (port >= 0x2000)
+ return *port2adr(port);
+ else
+ maybebadio(inl, port);
+ return 0;
+}
+
+void sh7751se_outb(unsigned char value, unsigned long port)
+{
+
+ if (PXSEG(port))
+ *(volatile unsigned char *)port = value;
+ else if (CHECK_SH7751_PCIIO(port))
+ *((unsigned char*)PCI_IOMAP(port)) = value;
+ else
+ *(port2adr(port)) = value;
+}
+
+void sh7751se_outb_p(unsigned char value, unsigned long port)
+{
+ if (PXSEG(port))
+ *(volatile unsigned char *)port = value;
+ else if (CHECK_SH7751_PCIIO(port))
+ *((unsigned char*)PCI_IOMAP(port)) = value;
+ else
+ *(port2adr(port)) = value;
+ delay();
+}
+
+void sh7751se_outw(unsigned short value, unsigned long port)
+{
+ if (PXSEG(port))
+ *(volatile unsigned short *)port = value;
+ else if (CHECK_SH7751_PCIIO(port))
+ *((unsigned short *)PCI_IOMAP(port)) = value;
+ else if (port >= 0x2000)
+ *port2adr(port) = value;
+ else
+ maybebadio(outw, port);
+}
+
+void sh7751se_outl(unsigned int value, unsigned long port)
+{
+ if (PXSEG(port))
+ *(volatile unsigned long *)port = value;
+ else if (CHECK_SH7751_PCIIO(port))
+ *((unsigned long*)PCI_IOMAP(port)) = value;
+ else
+ maybebadio(outl, port);
+}
+
+void sh7751se_insl(unsigned long port, void *addr, unsigned long count)
+{
+ maybebadio(insl, port);
+}
+
+void sh7751se_outsl(unsigned long port, const void *addr, unsigned long count)
+{
+ maybebadio(outsw, port);
+}
+
+/* Map ISA bus address to the real address. Only for PCMCIA. */
+
+/* ISA page descriptor. */
+static __u32 sh_isa_memmap[256];
+
+#if 0
+static int
+sh_isa_mmap(__u32 start, __u32 length, __u32 offset)
+{
+ int idx;
+
+ if (start >= 0x100000 || (start & 0xfff) || (length != 0x1000))
+ return -1;
+
+ idx = start >> 12;
+ sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff);
+ printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n",
+ start, length, offset, idx, sh_isa_memmap[idx]);
+ return 0;
+}
+#endif
+
+unsigned long
+sh7751se_isa_port2addr(unsigned long offset)
+{
+ int idx;
+
+ idx = (offset >> 12) & 0xff;
+ offset &= 0xfff;
+ return sh_isa_memmap[idx] + offset;
+}
diff --git a/arch/sh/boards/se/7751/irq.c b/arch/sh/boards/se/7751/irq.c
new file mode 100644
index 000000000000..ad71f3e66c11
--- /dev/null
+++ b/arch/sh/boards/se/7751/irq.c
@@ -0,0 +1,67 @@
+/*
+ * linux/arch/sh/boards/se/7751/irq.c
+ *
+ * Copyright (C) 2000 Kazumoto Kojima
+ *
+ * Hitachi SolutionEngine Support.
+ *
+ * Modified for 7751 Solution Engine by
+ * Ian da Silva and Jeremy Siegel, 2001.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <asm/irq.h>
+#include <asm/se7751/se7751.h>
+
+/*
+ * Initialize IRQ setting
+ */
+void __init init_7751se_IRQ(void)
+{
+
+ /* Leave old Solution Engine code in for reference. */
+#if defined(CONFIG_SH_SOLUTION_ENGINE)
+ /*
+ * Super I/O (Just mimic PC):
+ * 1: keyboard
+ * 3: serial 0
+ * 4: serial 1
+ * 5: printer
+ * 6: floppy
+ * 8: rtc
+ * 12: mouse
+ * 14: ide0
+ */
+ make_ipr_irq(14, BCR_ILCRA, 2, 0x0f-14);
+ make_ipr_irq(12, BCR_ILCRA, 1, 0x0f-12);
+ make_ipr_irq( 8, BCR_ILCRB, 1, 0x0f- 8);
+ make_ipr_irq( 6, BCR_ILCRC, 3, 0x0f- 6);
+ make_ipr_irq( 5, BCR_ILCRC, 2, 0x0f- 5);
+ make_ipr_irq( 4, BCR_ILCRC, 1, 0x0f- 4);
+ make_ipr_irq( 3, BCR_ILCRC, 0, 0x0f- 3);
+ make_ipr_irq( 1, BCR_ILCRD, 3, 0x0f- 1);
+
+ make_ipr_irq(10, BCR_ILCRD, 1, 0x0f-10); /* LAN */
+
+ make_ipr_irq( 0, BCR_ILCRE, 3, 0x0f- 0); /* PCIRQ3 */
+ make_ipr_irq(11, BCR_ILCRE, 2, 0x0f-11); /* PCIRQ2 */
+ make_ipr_irq( 9, BCR_ILCRE, 1, 0x0f- 9); /* PCIRQ1 */
+ make_ipr_irq( 7, BCR_ILCRE, 0, 0x0f- 7); /* PCIRQ0 */
+
+ /* #2, #13 are allocated for SLOT IRQ #1 and #2 (for now) */
+ /* NOTE: #2 and #13 are not used on PC */
+ make_ipr_irq(13, BCR_ILCRG, 1, 0x0f-13); /* SLOTIRQ2 */
+ make_ipr_irq( 2, BCR_ILCRG, 0, 0x0f- 2); /* SLOTIRQ1 */
+
+#elif defined(CONFIG_SH_7751_SOLUTION_ENGINE)
+
+ make_ipr_irq(13, BCR_ILCRD, 3, 2);
+
+ /* Add additional calls to make_ipr_irq() as drivers are added
+ * and tested.
+ */
+#endif
+
+}
diff --git a/arch/sh/boards/se/7751/led.c b/arch/sh/boards/se/7751/led.c
new file mode 100644
index 000000000000..0c788230cf8f
--- /dev/null
+++ b/arch/sh/boards/se/7751/led.c
@@ -0,0 +1,68 @@
+/*
+ * linux/arch/sh/kernel/led_se.c
+ *
+ * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * This file contains Solution Engine specific LED code.
+ */
+
+#include <linux/config.h>
+#include <asm/se7751/se7751.h>
+
+static void mach_led(int position, int value)
+{
+ volatile unsigned short* p = (volatile unsigned short*)PA_LED;
+
+ if (value) {
+ *p |= (1<<8);
+ } else {
+ *p &= ~(1<<8);
+ }
+}
+
+#ifdef CONFIG_HEARTBEAT
+
+#include <linux/sched.h>
+
+/* Cycle the LED's in the clasic Knightrider/Sun pattern */
+void heartbeat_7751se(void)
+{
+ static unsigned int cnt = 0, period = 0;
+ volatile unsigned short* p = (volatile unsigned short*)PA_LED;
+ static unsigned bit = 0, up = 1;
+
+ cnt += 1;
+ if (cnt < period) {
+ return;
+ }
+
+ cnt = 0;
+
+ /* Go through the points (roughly!):
+ * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110
+ */
+ period = 110 - ( (300<<FSHIFT)/
+ ((avenrun[0]/5) + (3<<FSHIFT)) );
+
+ if (up) {
+ if (bit == 7) {
+ bit--;
+ up=0;
+ } else {
+ bit ++;
+ }
+ } else {
+ if (bit == 0) {
+ bit++;
+ up=1;
+ } else {
+ bit--;
+ }
+ }
+ *p = 1<<(bit+8);
+
+}
+#endif /* CONFIG_HEARTBEAT */
diff --git a/arch/sh/boards/se/7751/mach.c b/arch/sh/boards/se/7751/mach.c
new file mode 100644
index 000000000000..16d386b7e3bf
--- /dev/null
+++ b/arch/sh/boards/se/7751/mach.c
@@ -0,0 +1,55 @@
+/*
+ * linux/arch/sh/kernel/mach_7751se.c
+ *
+ * Minor tweak of mach_se.c file to reference 7751se-specific items.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Machine vector for the Hitachi 7751 SolutionEngine
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/machvec_init.h>
+
+#include <asm/se7751/io.h>
+
+void heartbeat_7751se(void);
+void init_7751se_IRQ(void);
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_7751se __initmv = {
+ .mv_nr_irqs = 72,
+
+ .mv_inb = sh7751se_inb,
+ .mv_inw = sh7751se_inw,
+ .mv_inl = sh7751se_inl,
+ .mv_outb = sh7751se_outb,
+ .mv_outw = sh7751se_outw,
+ .mv_outl = sh7751se_outl,
+
+ .mv_inb_p = sh7751se_inb_p,
+ .mv_inw_p = sh7751se_inw,
+ .mv_inl_p = sh7751se_inl,
+ .mv_outb_p = sh7751se_outb_p,
+ .mv_outw_p = sh7751se_outw,
+ .mv_outl_p = sh7751se_outl,
+
+ .mv_insl = sh7751se_insl,
+ .mv_outsl = sh7751se_outsl,
+
+ .mv_isa_port2addr = sh7751se_isa_port2addr,
+
+ .mv_init_irq = init_7751se_IRQ,
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_7751se,
+#endif
+};
+ALIAS_MV(7751se)
diff --git a/arch/sh/boards/se/7751/pci.c b/arch/sh/boards/se/7751/pci.c
new file mode 100644
index 000000000000..1f273efd2cf5
--- /dev/null
+++ b/arch/sh/boards/se/7751/pci.c
@@ -0,0 +1,148 @@
+/*
+ * linux/arch/sh/kernel/pci-7751se.c
+ *
+ * Author: Ian DaSilva (idasilva@mvista.com)
+ *
+ * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * PCI initialization for the Hitachi SH7751 Solution Engine board (MS7751SE01)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include "../../../drivers/pci/pci-sh7751.h"
+
+#define PCIMCR_MRSET_OFF 0xBFFFFFFF
+#define PCIMCR_RFSH_OFF 0xFFFFFFFB
+
+/*
+ * Only long word accesses of the PCIC's internal local registers and the
+ * configuration registers from the CPU is supported.
+ */
+#define PCIC_WRITE(x,v) writel((v), PCI_REG(x))
+#define PCIC_READ(x) readl(PCI_REG(x))
+
+/*
+ * Description: This function sets up and initializes the pcic, sets
+ * up the BARS, maps the DRAM into the address space etc, etc.
+ */
+int __init pcibios_init_platform(void)
+{
+ unsigned long bcr1, wcr1, wcr2, wcr3, mcr;
+ unsigned short bcr2;
+
+ /*
+ * Initialize the slave bus controller on the pcic. The values used
+ * here should not be hardcoded, but they should be taken from the bsc
+ * on the processor, to make this function as generic as possible.
+ * (i.e. Another sbc may usr different SDRAM timing settings -- in order
+ * for the pcic to work, its settings need to be exactly the same.)
+ */
+ bcr1 = (*(volatile unsigned long*)(SH7751_BCR1));
+ bcr2 = (*(volatile unsigned short*)(SH7751_BCR2));
+ wcr1 = (*(volatile unsigned long*)(SH7751_WCR1));
+ wcr2 = (*(volatile unsigned long*)(SH7751_WCR2));
+ wcr3 = (*(volatile unsigned long*)(SH7751_WCR3));
+ mcr = (*(volatile unsigned long*)(SH7751_MCR));
+
+ bcr1 = bcr1 | 0x00080000; /* Enable Bit 19, BREQEN */
+ (*(volatile unsigned long*)(SH7751_BCR1)) = bcr1;
+
+ bcr1 = bcr1 | 0x40080000; /* Enable Bit 19 BREQEN, set PCIC to slave */
+ PCIC_WRITE(SH7751_PCIBCR1, bcr1); /* PCIC BCR1 */
+ PCIC_WRITE(SH7751_PCIBCR2, bcr2); /* PCIC BCR2 */
+ PCIC_WRITE(SH7751_PCIWCR1, wcr1); /* PCIC WCR1 */
+ PCIC_WRITE(SH7751_PCIWCR2, wcr2); /* PCIC WCR2 */
+ PCIC_WRITE(SH7751_PCIWCR3, wcr3); /* PCIC WCR3 */
+ mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF;
+ PCIC_WRITE(SH7751_PCIMCR, mcr); /* PCIC MCR */
+
+
+ /* Enable all interrupts, so we know what to fix */
+ PCIC_WRITE(SH7751_PCIINTM, 0x0000c3ff);
+ PCIC_WRITE(SH7751_PCIAINTM, 0x0000380f);
+
+ /* Set up standard PCI config registers */
+ PCIC_WRITE(SH7751_PCICONF1, 0xF39000C7); /* Bus Master, Mem & I/O access */
+ PCIC_WRITE(SH7751_PCICONF2, 0x00000000); /* PCI Class code & Revision ID */
+ PCIC_WRITE(SH7751_PCICONF4, 0xab000001); /* PCI I/O address (local regs) */
+ PCIC_WRITE(SH7751_PCICONF5, 0x0c000000); /* PCI MEM address (local RAM) */
+ PCIC_WRITE(SH7751_PCICONF6, 0xd0000000); /* PCI MEM address (unused) */
+ PCIC_WRITE(SH7751_PCICONF11, 0x35051054); /* PCI Subsystem ID & Vendor ID */
+ PCIC_WRITE(SH7751_PCILSR0, 0x03f00000); /* MEM (full 64M exposed) */
+ PCIC_WRITE(SH7751_PCILSR1, 0x00000000); /* MEM (unused) */
+ PCIC_WRITE(SH7751_PCILAR0, 0x0c000000); /* MEM (direct map from PCI) */
+ PCIC_WRITE(SH7751_PCILAR1, 0x00000000); /* MEM (unused) */
+
+ /* Now turn it on... */
+ PCIC_WRITE(SH7751_PCICR, 0xa5000001);
+
+ /*
+ * Set PCIMBR and PCIIOBR here, assuming a single window
+ * (16M MEM, 256K IO) is enough. If a larger space is
+ * needed, the readx/writex and inx/outx functions will
+ * have to do more (e.g. setting registers for each call).
+ */
+
+ /*
+ * Set the MBR so PCI address is one-to-one with window,
+ * meaning all calls go straight through... use BUG_ON to
+ * catch erroneous assumption.
+ */
+ BUG_ON(PCIBIOS_MIN_MEM != SH7751_PCI_MEMORY_BASE);
+
+ PCIC_WRITE(SH7751_PCIMBR, PCIBIOS_MIN_MEM);
+
+ /* Set IOBR for window containing area specified in pci.h */
+ PCIC_WRITE(SH7751_PCIIOBR, (PCIBIOS_MIN_IO & SH7751_PCIIOBR_MASK));
+
+ /* All done, may as well say so... */
+ printk("SH7751 PCI: Finished initialization of the PCI controller\n");
+
+ return 1;
+}
+
+int __init pcibios_map_platform_irq(u8 slot, u8 pin)
+{
+ switch (slot) {
+ case 0: return 13;
+ case 1: return 13; /* AMD Ethernet controller */
+ case 2: return -1;
+ case 3: return -1;
+ case 4: return -1;
+ default:
+ printk("PCI: Bad IRQ mapping request for slot %d\n", slot);
+ return -1;
+ }
+}
+
+static struct resource sh7751_io_resource = {
+ .name = "SH7751 IO",
+ .start = SH7751_PCI_IO_BASE,
+ .end = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1,
+ .flags = IORESOURCE_IO
+};
+
+static struct resource sh7751_mem_resource = {
+ .name = "SH7751 mem",
+ .start = SH7751_PCI_MEMORY_BASE,
+ .end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
+ .flags = IORESOURCE_MEM
+};
+
+extern struct pci_ops sh7751_pci_ops;
+
+struct pci_channel board_pci_channels[] = {
+ { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
+ { NULL, NULL, NULL, 0, 0 },
+};
+
diff --git a/arch/sh/boards/se/7751/setup.c b/arch/sh/boards/se/7751/setup.c
new file mode 100644
index 000000000000..9d111bb884f9
--- /dev/null
+++ b/arch/sh/boards/se/7751/setup.c
@@ -0,0 +1,228 @@
+/*
+ * linux/arch/sh/kernel/setup_7751se.c
+ *
+ * Copyright (C) 2000 Kazumoto Kojima
+ *
+ * Hitachi SolutionEngine Support.
+ *
+ * Modified for 7751 Solution Engine by
+ * Ian da Silva and Jeremy Siegel, 2001.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+#include <asm/se7751/se7751.h>
+
+#ifdef CONFIG_SH_KGDB
+#include <asm/kgdb.h>
+#endif
+
+/*
+ * Configure the Super I/O chip
+ */
+#if 0
+/* Leftover code from regular Solution Engine, for reference. */
+/* The SH7751 Solution Engine has a different SuperIO. */
+static void __init smsc_config(int index, int data)
+{
+ outb_p(index, INDEX_PORT);
+ outb_p(data, DATA_PORT);
+}
+
+static void __init init_smsc(void)
+{
+ outb_p(CONFIG_ENTER, CONFIG_PORT);
+ outb_p(CONFIG_ENTER, CONFIG_PORT);
+
+ /* FDC */
+ smsc_config(CURRENT_LDN_INDEX, LDN_FDC);
+ smsc_config(ACTIVATE_INDEX, 0x01);
+ smsc_config(IRQ_SELECT_INDEX, 6); /* IRQ6 */
+
+ /* IDE1 */
+ smsc_config(CURRENT_LDN_INDEX, LDN_IDE1);
+ smsc_config(ACTIVATE_INDEX, 0x01);
+ smsc_config(IRQ_SELECT_INDEX, 14); /* IRQ14 */
+
+ /* AUXIO (GPIO): to use IDE1 */
+ smsc_config(CURRENT_LDN_INDEX, LDN_AUXIO);
+ smsc_config(GPIO46_INDEX, 0x00); /* nIOROP */
+ smsc_config(GPIO47_INDEX, 0x00); /* nIOWOP */
+
+ /* COM1 */
+ smsc_config(CURRENT_LDN_INDEX, LDN_COM1);
+ smsc_config(ACTIVATE_INDEX, 0x01);
+ smsc_config(IO_BASE_HI_INDEX, 0x03);
+ smsc_config(IO_BASE_LO_INDEX, 0xf8);
+ smsc_config(IRQ_SELECT_INDEX, 4); /* IRQ4 */
+
+ /* COM2 */
+ smsc_config(CURRENT_LDN_INDEX, LDN_COM2);
+ smsc_config(ACTIVATE_INDEX, 0x01);
+ smsc_config(IO_BASE_HI_INDEX, 0x02);
+ smsc_config(IO_BASE_LO_INDEX, 0xf8);
+ smsc_config(IRQ_SELECT_INDEX, 3); /* IRQ3 */
+
+ /* RTC */
+ smsc_config(CURRENT_LDN_INDEX, LDN_RTC);
+ smsc_config(ACTIVATE_INDEX, 0x01);
+ smsc_config(IRQ_SELECT_INDEX, 8); /* IRQ8 */
+
+ /* XXX: PARPORT, KBD, and MOUSE will come here... */
+ outb_p(CONFIG_EXIT, CONFIG_PORT);
+}
+#endif
+
+const char *get_system_type(void)
+{
+ return "7751 SolutionEngine";
+}
+
+#ifdef CONFIG_SH_KGDB
+static int kgdb_uart_setup(void);
+static struct kgdb_sermap kgdb_uart_sermap =
+{ "ttyS", 0, kgdb_uart_setup, NULL };
+#endif
+
+/*
+ * Initialize the board
+ */
+void __init platform_setup(void)
+{
+ /* Call init_smsc() replacement to set up SuperIO. */
+ /* XXX: RTC setting comes here */
+#ifdef CONFIG_SH_KGDB
+ kgdb_register_sermap(&kgdb_uart_sermap);
+#endif
+}
+
+/*********************************************************************
+ * Currently a hack (e.g. does not interact well w/serial.c, lots of *
+ * hardcoded stuff) but may be useful if SCI/F needs debugging. *
+ * Mostly copied from x86 code (see files asm-i386/kgdb_local.h and *
+ * arch/i386/lib/kgdb_serial.c). *
+ *********************************************************************/
+
+#ifdef CONFIG_SH_KGDB
+#include <linux/types.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/serial_reg.h>
+
+#define COM1_PORT 0x3f8 /* Base I/O address */
+#define COM1_IRQ 4 /* IRQ not used yet */
+#define COM2_PORT 0x2f8 /* Base I/O address */
+#define COM2_IRQ 3 /* IRQ not used yet */
+
+#define SB_CLOCK 1843200 /* Serial baud clock */
+#define SB_BASE (SB_CLOCK/16)
+#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
+
+struct uart_port {
+ int base;
+};
+#define UART_NPORTS 2
+struct uart_port uart_ports[] = {
+ { COM1_PORT },
+ { COM2_PORT },
+};
+struct uart_port *kgdb_uart_port;
+
+#define UART_IN(reg) inb_p(kgdb_uart_port->base + reg)
+#define UART_OUT(reg,v) outb_p((v), kgdb_uart_port->base + reg)
+
+/* Basic read/write functions for the UART */
+#define UART_LSR_RXCERR (UART_LSR_BI | UART_LSR_FE | UART_LSR_PE)
+static int kgdb_uart_getchar(void)
+{
+ int lsr;
+ int c = -1;
+
+ while (c == -1) {
+ lsr = UART_IN(UART_LSR);
+ if (lsr & UART_LSR_DR)
+ c = UART_IN(UART_RX);
+ if ((lsr & UART_LSR_RXCERR))
+ c = -1;
+ }
+ return c;
+}
+
+static void kgdb_uart_putchar(int c)
+{
+ while ((UART_IN(UART_LSR) & UART_LSR_THRE) == 0)
+ ;
+ UART_OUT(UART_TX, c);
+}
+
+/*
+ * Initialize UART to configured/requested values.
+ * (But we don't interrupts yet, or interact w/serial.c)
+ */
+static int kgdb_uart_setup(void)
+{
+ int port;
+ int lcr = 0;
+ int bdiv = 0;
+
+ if (kgdb_portnum >= UART_NPORTS) {
+ KGDB_PRINTK("uart port %d invalid.\n", kgdb_portnum);
+ return -1;
+ }
+
+ kgdb_uart_port = &uart_ports[kgdb_portnum];
+
+ /* Init sequence from gdb_hook_interrupt */
+ UART_IN(UART_RX);
+ UART_OUT(UART_IER, 0);
+
+ UART_IN(UART_RX); /* Serial driver comments say */
+ UART_IN(UART_IIR); /* this clears interrupt regs */
+ UART_IN(UART_MSR);
+
+ /* Figure basic LCR values */
+ switch (kgdb_bits) {
+ case '7':
+ lcr |= UART_LCR_WLEN7;
+ break;
+ default: case '8':
+ lcr |= UART_LCR_WLEN8;
+ break;
+ }
+ switch (kgdb_parity) {
+ case 'O':
+ lcr |= UART_LCR_PARITY;
+ break;
+ case 'E':
+ lcr |= (UART_LCR_PARITY | UART_LCR_EPAR);
+ break;
+ default: break;
+ }
+
+ /* Figure the baud rate divisor */
+ bdiv = (SB_BASE/kgdb_baud);
+
+ /* Set the baud rate and LCR values */
+ UART_OUT(UART_LCR, (lcr | UART_LCR_DLAB));
+ UART_OUT(UART_DLL, (bdiv & 0xff));
+ UART_OUT(UART_DLM, ((bdiv >> 8) & 0xff));
+ UART_OUT(UART_LCR, lcr);
+
+ /* Set the MCR */
+ UART_OUT(UART_MCR, SB_MCR);
+
+ /* Turn off FIFOs for now */
+ UART_OUT(UART_FCR, 0);
+
+ /* Setup complete: initialize function pointers */
+ kgdb_getchar = kgdb_uart_getchar;
+ kgdb_putchar = kgdb_uart_putchar;
+
+ return 0;
+}
+#endif /* CONFIG_SH_KGDB */
diff --git a/arch/sh/boards/sh03/Makefile b/arch/sh/boards/sh03/Makefile
new file mode 100644
index 000000000000..321be50e36a5
--- /dev/null
+++ b/arch/sh/boards/sh03/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Interface (CTP/PCI-SH03) specific parts of the kernel
+#
+
+obj-y := setup.o rtc.o
+obj-$(CONFIG_HEARTBEAT) += led.o
diff --git a/arch/sh/boards/sh03/led.c b/arch/sh/boards/sh03/led.c
new file mode 100644
index 000000000000..c851b0bec80f
--- /dev/null
+++ b/arch/sh/boards/sh03/led.c
@@ -0,0 +1,49 @@
+/*
+ * linux/arch/sh/boards/sh03/led.c
+ *
+ * Copyright (C) 2004 Saito.K Interface Corporation.
+ *
+ * This file contains Interface CTP/PCI-SH03 specific LED code.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+
+/* Cycle the LED's in the clasic Knightrider/Sun pattern */
+void heartbeat_sh03(void)
+{
+ static unsigned int cnt = 0, period = 0;
+ volatile unsigned char* p = (volatile unsigned char*)0xa0800000;
+ static unsigned bit = 0, up = 1;
+
+ cnt += 1;
+ if (cnt < period) {
+ return;
+ }
+
+ cnt = 0;
+
+ /* Go through the points (roughly!):
+ * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110
+ */
+ period = 110 - ( (300<<FSHIFT)/
+ ((avenrun[0]/5) + (3<<FSHIFT)) );
+
+ if (up) {
+ if (bit == 7) {
+ bit--;
+ up=0;
+ } else {
+ bit ++;
+ }
+ } else {
+ if (bit == 0) {
+ bit++;
+ up=1;
+ } else {
+ bit--;
+ }
+ }
+ *p = 1<<bit;
+
+}
diff --git a/arch/sh/boards/sh03/rtc.c b/arch/sh/boards/sh03/rtc.c
new file mode 100644
index 000000000000..cbeca7037ba5
--- /dev/null
+++ b/arch/sh/boards/sh03/rtc.c
@@ -0,0 +1,144 @@
+/*
+ * linux/arch/sh/boards/sh03/rtc.c -- CTP/PCI-SH03 on-chip RTC support
+ *
+ * Copyright (C) 2004 Saito.K & Jeanne(ksaito@interface.co.jp)
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <asm/io.h>
+#include <linux/rtc.h>
+#include <linux/spinlock.h>
+
+#define RTC_BASE 0xb0000000
+#define RTC_SEC1 (RTC_BASE + 0)
+#define RTC_SEC10 (RTC_BASE + 1)
+#define RTC_MIN1 (RTC_BASE + 2)
+#define RTC_MIN10 (RTC_BASE + 3)
+#define RTC_HOU1 (RTC_BASE + 4)
+#define RTC_HOU10 (RTC_BASE + 5)
+#define RTC_WEE1 (RTC_BASE + 6)
+#define RTC_DAY1 (RTC_BASE + 7)
+#define RTC_DAY10 (RTC_BASE + 8)
+#define RTC_MON1 (RTC_BASE + 9)
+#define RTC_MON10 (RTC_BASE + 10)
+#define RTC_YEA1 (RTC_BASE + 11)
+#define RTC_YEA10 (RTC_BASE + 12)
+#define RTC_YEA100 (RTC_BASE + 13)
+#define RTC_YEA1000 (RTC_BASE + 14)
+#define RTC_CTL (RTC_BASE + 15)
+#define RTC_BUSY 1
+#define RTC_STOP 2
+
+#ifndef BCD_TO_BIN
+#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
+#endif
+
+#ifndef BIN_TO_BCD
+#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
+#endif
+
+extern void (*rtc_get_time)(struct timespec *);
+extern int (*rtc_set_time)(const time_t);
+extern spinlock_t rtc_lock;
+
+unsigned long get_cmos_time(void)
+{
+ unsigned int year, mon, day, hour, min, sec;
+ int i;
+
+ spin_lock(&rtc_lock);
+ again:
+ for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
+ if (!(ctrl_inb(RTC_CTL) & RTC_BUSY))
+ break;
+ do {
+ sec = (ctrl_inb(RTC_SEC1) & 0xf) + (ctrl_inb(RTC_SEC10) & 0x7) * 10;
+ min = (ctrl_inb(RTC_MIN1) & 0xf) + (ctrl_inb(RTC_MIN10) & 0xf) * 10;
+ hour = (ctrl_inb(RTC_HOU1) & 0xf) + (ctrl_inb(RTC_HOU10) & 0xf) * 10;
+ day = (ctrl_inb(RTC_DAY1) & 0xf) + (ctrl_inb(RTC_DAY10) & 0xf) * 10;
+ mon = (ctrl_inb(RTC_MON1) & 0xf) + (ctrl_inb(RTC_MON10) & 0xf) * 10;
+ year = (ctrl_inb(RTC_YEA1) & 0xf) + (ctrl_inb(RTC_YEA10) & 0xf) * 10
+ + (ctrl_inb(RTC_YEA100 ) & 0xf) * 100
+ + (ctrl_inb(RTC_YEA1000) & 0xf) * 1000;
+ } while (sec != (ctrl_inb(RTC_SEC1) & 0xf) + (ctrl_inb(RTC_SEC10) & 0x7) * 10);
+ if (year == 0 || mon < 1 || mon > 12 || day > 31 || day < 1 ||
+ hour > 23 || min > 59 || sec > 59) {
+ printk(KERN_ERR
+ "SH-03 RTC: invalid value, resetting to 1 Jan 2000\n");
+ printk("year=%d, mon=%d, day=%d, hour=%d, min=%d, sec=%d\n",
+ year, mon, day, hour, min, sec);
+
+ ctrl_outb(0, RTC_SEC1); ctrl_outb(0, RTC_SEC10);
+ ctrl_outb(0, RTC_MIN1); ctrl_outb(0, RTC_MIN10);
+ ctrl_outb(0, RTC_HOU1); ctrl_outb(0, RTC_HOU10);
+ ctrl_outb(6, RTC_WEE1);
+ ctrl_outb(1, RTC_DAY1); ctrl_outb(0, RTC_DAY10);
+ ctrl_outb(1, RTC_MON1); ctrl_outb(0, RTC_MON10);
+ ctrl_outb(0, RTC_YEA1); ctrl_outb(0, RTC_YEA10);
+ ctrl_outb(0, RTC_YEA100);
+ ctrl_outb(2, RTC_YEA1000);
+ ctrl_outb(0, RTC_CTL);
+ goto again;
+ }
+
+ spin_unlock(&rtc_lock);
+ return mktime(year, mon, day, hour, min, sec);
+}
+
+void sh03_rtc_gettimeofday(struct timespec *tv)
+{
+
+ tv->tv_sec = get_cmos_time();
+ tv->tv_nsec = 0;
+}
+
+static int set_rtc_mmss(unsigned long nowtime)
+{
+ int retval = 0;
+ int real_seconds, real_minutes, cmos_minutes;
+ int i;
+
+ /* gets recalled with irq locally disabled */
+ spin_lock(&rtc_lock);
+ for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
+ if (!(ctrl_inb(RTC_CTL) & RTC_BUSY))
+ break;
+ cmos_minutes = (ctrl_inb(RTC_MIN1) & 0xf) + (ctrl_inb(RTC_MIN10) & 0xf) * 10;
+ real_seconds = nowtime % 60;
+ real_minutes = nowtime / 60;
+ if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+ real_minutes += 30; /* correct for half hour time zone */
+ real_minutes %= 60;
+
+ if (abs(real_minutes - cmos_minutes) < 30) {
+ ctrl_outb(real_seconds % 10, RTC_SEC1);
+ ctrl_outb(real_seconds / 10, RTC_SEC10);
+ ctrl_outb(real_minutes % 10, RTC_MIN1);
+ ctrl_outb(real_minutes / 10, RTC_MIN10);
+ } else {
+ printk(KERN_WARNING
+ "set_rtc_mmss: can't update from %d to %d\n",
+ cmos_minutes, real_minutes);
+ retval = -1;
+ }
+ spin_unlock(&rtc_lock);
+
+ return retval;
+}
+
+int sh03_rtc_settimeofday(const time_t secs)
+{
+ unsigned long nowtime = secs;
+
+ return set_rtc_mmss(nowtime);
+}
+
+void sh03_time_init(void)
+{
+ rtc_get_time = sh03_rtc_gettimeofday;
+ rtc_set_time = sh03_rtc_settimeofday;
+}
diff --git a/arch/sh/boards/sh03/setup.c b/arch/sh/boards/sh03/setup.c
new file mode 100644
index 000000000000..d2a08ca5eb85
--- /dev/null
+++ b/arch/sh/boards/sh03/setup.c
@@ -0,0 +1,72 @@
+/*
+ * linux/arch/sh/boards/sh03/setup.c
+ *
+ * Copyright (C) 2004 Interface Co.,Ltd. Saito.K
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+#include <asm/sh03/io.h>
+#include <asm/sh03/sh03.h>
+#include <asm/addrspace.h>
+#include "../../drivers/pci/pci-sh7751.h"
+
+extern void (*board_time_init)(void);
+
+const char *get_system_type(void)
+{
+ return "Interface CTP/PCI-SH03)";
+}
+
+void init_sh03_IRQ(void)
+{
+ ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
+
+ make_ipr_irq(IRL0_IRQ, IRL0_IPR_ADDR, IRL0_IPR_POS, IRL0_PRIORITY);
+ make_ipr_irq(IRL1_IRQ, IRL1_IPR_ADDR, IRL1_IPR_POS, IRL1_PRIORITY);
+ make_ipr_irq(IRL2_IRQ, IRL2_IPR_ADDR, IRL2_IPR_POS, IRL2_PRIORITY);
+ make_ipr_irq(IRL3_IRQ, IRL3_IPR_ADDR, IRL3_IPR_POS, IRL3_PRIORITY);
+}
+
+extern void *cf_io_base;
+
+unsigned long sh03_isa_port2addr(unsigned long port)
+{
+ if (PXSEG(port))
+ return port;
+ /* CompactFlash (IDE) */
+ if (((port >= 0x1f0) && (port <= 0x1f7)) || (port == 0x3f6)) {
+ return (unsigned long)cf_io_base + port;
+ }
+ return port + SH7751_PCI_IO_BASE;
+}
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_sh03 __initmv = {
+ .mv_nr_irqs = 48,
+ .mv_isa_port2addr = sh03_isa_port2addr,
+ .mv_init_irq = init_sh03_IRQ,
+
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_sh03,
+#endif
+};
+
+ALIAS_MV(sh03)
+
+/* arch/sh/boards/sh03/rtc.c */
+void sh03_time_init(void);
+
+int __init platform_setup(void)
+{
+ board_time_init = sh03_time_init;
+ return 0;
+}
diff --git a/arch/sh/boards/sh2000/Makefile b/arch/sh/boards/sh2000/Makefile
new file mode 100644
index 000000000000..05d390c3599c
--- /dev/null
+++ b/arch/sh/boards/sh2000/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the SH2000 specific parts of the kernel
+#
+
+obj-y := setup.o
+
diff --git a/arch/sh/boards/sh2000/setup.c b/arch/sh/boards/sh2000/setup.c
new file mode 100644
index 000000000000..a290b1d09fb2
--- /dev/null
+++ b/arch/sh/boards/sh2000/setup.c
@@ -0,0 +1,71 @@
+/*
+ * linux/arch/sh/kernel/setup_sh2000.c
+ *
+ * Copyright (C) 2001 SUGIOKA Tochinobu
+ *
+ * SH-2000 Support.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/machvec.h>
+#include <asm/mach/sh2000.h>
+
+#define CF_CIS_BASE 0xb4200000
+
+#define PORT_PECR 0xa4000108
+#define PORT_PHCR 0xa400010E
+#define PORT_ICR1 0xa4000010
+#define PORT_IRR0 0xa4000004
+
+#define IDE_OFFSET 0xb6200000
+#define NIC_OFFSET 0xb6000000
+#define EXTBUS_OFFSET 0xba000000
+
+
+const char *get_system_type(void)
+{
+ return "sh2000";
+}
+
+static unsigned long sh2000_isa_port2addr(unsigned long offset)
+{
+ if((offset & ~7) == 0x1f0 || offset == 0x3f6)
+ return IDE_OFFSET + offset;
+ else if((offset & ~0x1f) == 0x300)
+ return NIC_OFFSET + offset;
+ return EXTBUS_OFFSET + offset;
+}
+
+/*
+ * The Machine Vector
+ */
+struct sh_machine_vector mv_sh2000 __initmv = {
+ .mv_nr_irqs = 80,
+ .mv_isa_port2addr = sh2000_isa_port2addr,
+};
+ALIAS_MV(sh2000)
+
+/*
+ * Initialize the board
+ */
+int __init platform_setup(void)
+{
+ /* XXX: RTC setting comes here */
+
+ /* These should be done by BIOS/IPL ... */
+ /* Enable nCE2A, nCE2B output */
+ ctrl_outw(ctrl_inw(PORT_PECR) & ~0xf00, PORT_PECR);
+ /* Enable the Compact Flash card, and set the level interrupt */
+ ctrl_outw(0x0042, CF_CIS_BASE+0x0200);
+ /* Enable interrupt */
+ ctrl_outw(ctrl_inw(PORT_PHCR) & ~0x03f3, PORT_PHCR);
+ ctrl_outw(1, PORT_ICR1);
+ ctrl_outw(ctrl_inw(PORT_IRR0) & ~0xff3f, PORT_IRR0);
+ printk(KERN_INFO "SH-2000 Setup...done\n");
+ return 0;
+}
diff --git a/arch/sh/boards/snapgear/Makefile b/arch/sh/boards/snapgear/Makefile
new file mode 100644
index 000000000000..59fc976bfc2f
--- /dev/null
+++ b/arch/sh/boards/snapgear/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the SnapGear specific parts of the kernel
+#
+
+obj-y := setup.o io.o rtc.o
+
diff --git a/arch/sh/boards/snapgear/io.c b/arch/sh/boards/snapgear/io.c
new file mode 100644
index 000000000000..e2eb78fc381d
--- /dev/null
+++ b/arch/sh/boards/snapgear/io.c
@@ -0,0 +1,226 @@
+/*
+ * linux/arch/sh/kernel/io_7751se.c
+ *
+ * Copyright (C) 2002 David McCullough <davidm@snapgear.com>
+ * Copyright (C) 2001 Ian da Silva, Jeremy Siegel
+ * Based largely on io_se.c.
+ *
+ * I/O routine for Hitachi 7751 SolutionEngine.
+ *
+ * Initial version only to support LAN access; some
+ * placeholder code from io_se.c left in with the
+ * expectation of later SuperIO and PCMCIA access.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+
+#include <asm/pci.h>
+#include "../../drivers/pci/pci-sh7751.h"
+
+#ifdef CONFIG_SH_SECUREEDGE5410
+unsigned short secureedge5410_ioport;
+#endif
+
+/*
+ * The SnapGear uses the built-in PCI controller (PCIC)
+ * of the 7751 processor
+ */
+
+#define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR)
+#define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR)
+#define PCI_IO_AREA SH7751_PCI_IO_BASE
+#define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE
+
+
+#define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK))
+
+
+#define maybebadio(name,port) \
+ printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
+ #name, (port), (__u32) __builtin_return_address(0))
+
+
+static inline void delay(void)
+{
+ ctrl_inw(0xa0000000);
+}
+
+
+static inline volatile __u16 *port2adr(unsigned int port)
+{
+#if 0
+ if (port >= 0x2000)
+ return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
+#endif
+ maybebadio(name,(unsigned long)port);
+ return (volatile __u16*)port;
+}
+
+
+/* In case someone configures the kernel w/o PCI support: in that */
+/* scenario, don't ever bother to check for PCI-window addresses */
+
+/* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */
+#if defined(CONFIG_PCI)
+#define CHECK_SH7751_PCIIO(port) \
+ ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
+#else
+#define CHECK_SH7751_PCIIO(port) (0)
+#endif
+
+/*
+ * General outline: remap really low stuff [eventually] to SuperIO,
+ * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
+ * is mapped through the PCI IO window. Stuff with high bits (PXSEG)
+ * should be way beyond the window, and is used w/o translation for
+ * compatibility.
+ */
+
+unsigned char snapgear_inb(unsigned long port)
+{
+ if (PXSEG(port))
+ return *(volatile unsigned char *)port;
+ else if (CHECK_SH7751_PCIIO(port))
+ return *(volatile unsigned char *)PCI_IOMAP(port);
+ else
+ return (*port2adr(port))&0xff;
+}
+
+
+unsigned char snapgear_inb_p(unsigned long port)
+{
+ unsigned char v;
+
+ if (PXSEG(port))
+ v = *(volatile unsigned char *)port;
+ else if (CHECK_SH7751_PCIIO(port))
+ v = *(volatile unsigned char *)PCI_IOMAP(port);
+ else
+ v = (*port2adr(port))&0xff;
+ delay();
+ return v;
+}
+
+
+unsigned short snapgear_inw(unsigned long port)
+{
+ if (PXSEG(port))
+ return *(volatile unsigned short *)port;
+ else if (CHECK_SH7751_PCIIO(port))
+ return *(volatile unsigned short *)PCI_IOMAP(port);
+ else if (port >= 0x2000)
+ return *port2adr(port);
+ else
+ maybebadio(inw, port);
+ return 0;
+}
+
+
+unsigned int snapgear_inl(unsigned long port)
+{
+ if (PXSEG(port))
+ return *(volatile unsigned long *)port;
+ else if (CHECK_SH7751_PCIIO(port))
+ return *(volatile unsigned int *)PCI_IOMAP(port);
+ else if (port >= 0x2000)
+ return *port2adr(port);
+ else
+ maybebadio(inl, port);
+ return 0;
+}
+
+
+void snapgear_outb(unsigned char value, unsigned long port)
+{
+
+ if (PXSEG(port))
+ *(volatile unsigned char *)port = value;
+ else if (CHECK_SH7751_PCIIO(port))
+ *((unsigned char*)PCI_IOMAP(port)) = value;
+ else
+ *(port2adr(port)) = value;
+}
+
+
+void snapgear_outb_p(unsigned char value, unsigned long port)
+{
+ if (PXSEG(port))
+ *(volatile unsigned char *)port = value;
+ else if (CHECK_SH7751_PCIIO(port))
+ *((unsigned char*)PCI_IOMAP(port)) = value;
+ else
+ *(port2adr(port)) = value;
+ delay();
+}
+
+
+void snapgear_outw(unsigned short value, unsigned long port)
+{
+ if (PXSEG(port))
+ *(volatile unsigned short *)port = value;
+ else if (CHECK_SH7751_PCIIO(port))
+ *((unsigned short *)PCI_IOMAP(port)) = value;
+ else if (port >= 0x2000)
+ *port2adr(port) = value;
+ else
+ maybebadio(outw, port);
+}
+
+
+void snapgear_outl(unsigned int value, unsigned long port)
+{
+ if (PXSEG(port))
+ *(volatile unsigned long *)port = value;
+ else if (CHECK_SH7751_PCIIO(port))
+ *((unsigned long*)PCI_IOMAP(port)) = value;
+ else
+ maybebadio(outl, port);
+}
+
+void snapgear_insl(unsigned long port, void *addr, unsigned long count)
+{
+ maybebadio(insl, port);
+}
+
+void snapgear_outsl(unsigned long port, const void *addr, unsigned long count)
+{
+ maybebadio(outsw, port);
+}
+
+/* Map ISA bus address to the real address. Only for PCMCIA. */
+
+
+/* ISA page descriptor. */
+static __u32 sh_isa_memmap[256];
+
+
+#if 0
+static int sh_isa_mmap(__u32 start, __u32 length, __u32 offset)
+{
+ int idx;
+
+ if (start >= 0x100000 || (start & 0xfff) || (length != 0x1000))
+ return -1;
+
+ idx = start >> 12;
+ sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff);
+#if 0
+ printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n",
+ start, length, offset, idx, sh_isa_memmap[idx]);
+#endif
+ return 0;
+}
+#endif
+
+unsigned long snapgear_isa_port2addr(unsigned long offset)
+{
+ int idx;
+
+ idx = (offset >> 12) & 0xff;
+ offset &= 0xfff;
+ return sh_isa_memmap[idx] + offset;
+}
diff --git a/arch/sh/boards/snapgear/rtc.c b/arch/sh/boards/snapgear/rtc.c
new file mode 100644
index 000000000000..b71e009da35c
--- /dev/null
+++ b/arch/sh/boards/snapgear/rtc.c
@@ -0,0 +1,333 @@
+/****************************************************************************/
+/*
+ * linux/arch/sh/boards/snapgear/rtc.c -- Secureedge5410 RTC code
+ *
+ * Copyright (C) 2002 David McCullough <davidm@snapgear.com>
+ * Copyright (C) 2003 Paul Mundt <lethal@linux-sh.org>
+ *
+ * The SecureEdge5410 can have one of 2 real time clocks, the SH
+ * built in version or the preferred external DS1302. Here we work out
+ * each to see what we have and then run with it.
+ */
+/****************************************************************************/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/io.h>
+#include <asm/rtc.h>
+#include <asm/mc146818rtc.h>
+
+/****************************************************************************/
+
+static int use_ds1302 = 0;
+
+/****************************************************************************/
+/*
+ * we need to implement a DS1302 driver here that can operate in
+ * conjunction with the builtin rtc driver which is already quite friendly
+ */
+/*****************************************************************************/
+
+#define RTC_CMD_READ 0x81 /* Read command */
+#define RTC_CMD_WRITE 0x80 /* Write command */
+
+#define RTC_ADDR_YEAR 0x06 /* Address of year register */
+#define RTC_ADDR_DAY 0x05 /* Address of day of week register */
+#define RTC_ADDR_MON 0x04 /* Address of month register */
+#define RTC_ADDR_DATE 0x03 /* Address of day of month register */
+#define RTC_ADDR_HOUR 0x02 /* Address of hour register */
+#define RTC_ADDR_MIN 0x01 /* Address of minute register */
+#define RTC_ADDR_SEC 0x00 /* Address of second register */
+
+#define RTC_RESET 0x1000
+#define RTC_IODATA 0x0800
+#define RTC_SCLK 0x0400
+
+#define set_dirp(x)
+#define get_dirp(x) 0
+#define set_dp(x) SECUREEDGE_WRITE_IOPORT(x, 0x1c00)
+#define get_dp(x) SECUREEDGE_READ_IOPORT()
+
+static void ds1302_sendbits(unsigned int val)
+{
+ int i;
+
+ for (i = 8; (i); i--, val >>= 1) {
+ set_dp((get_dp() & ~RTC_IODATA) | ((val & 0x1) ? RTC_IODATA : 0));
+ set_dp(get_dp() | RTC_SCLK); // clock high
+ set_dp(get_dp() & ~RTC_SCLK); // clock low
+ }
+}
+
+static unsigned int ds1302_recvbits(void)
+{
+ unsigned int val;
+ int i;
+
+ for (i = 0, val = 0; (i < 8); i++) {
+ val |= (((get_dp() & RTC_IODATA) ? 1 : 0) << i);
+ set_dp(get_dp() | RTC_SCLK); // clock high
+ set_dp(get_dp() & ~RTC_SCLK); // clock low
+ }
+ return(val);
+}
+
+static unsigned int ds1302_readbyte(unsigned int addr)
+{
+ unsigned int val;
+ unsigned long flags;
+
+#if 0
+ printk("SnapGear RTC: ds1302_readbyte(addr=%x)\n", addr);
+#endif
+
+ local_irq_save(flags);
+ set_dirp(get_dirp() | RTC_RESET | RTC_IODATA | RTC_SCLK);
+ set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+
+ set_dp(get_dp() | RTC_RESET);
+ ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_READ);
+ set_dirp(get_dirp() & ~RTC_IODATA);
+ val = ds1302_recvbits();
+ set_dp(get_dp() & ~RTC_RESET);
+ local_irq_restore(flags);
+
+ return(val);
+}
+
+static void ds1302_writebyte(unsigned int addr, unsigned int val)
+{
+ unsigned long flags;
+
+#if 0
+ printk("SnapGear RTC: ds1302_writebyte(addr=%x)\n", addr);
+#endif
+
+ local_irq_save(flags);
+ set_dirp(get_dirp() | RTC_RESET | RTC_IODATA | RTC_SCLK);
+ set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+ set_dp(get_dp() | RTC_RESET);
+ ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_WRITE);
+ ds1302_sendbits(val);
+ set_dp(get_dp() & ~RTC_RESET);
+ local_irq_restore(flags);
+}
+
+static void ds1302_reset(void)
+{
+ unsigned long flags;
+ /* Hardware dependant reset/init */
+ local_irq_save(flags);
+ set_dirp(get_dirp() | RTC_RESET | RTC_IODATA | RTC_SCLK);
+ set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
+ local_irq_restore(flags);
+}
+
+/*****************************************************************************/
+
+static inline int bcd2int(int val)
+{
+ return((((val & 0xf0) >> 4) * 10) + (val & 0xf));
+}
+
+static inline int int2bcd(int val)
+{
+ return(((val / 10) << 4) + (val % 10));
+}
+
+/*****************************************************************************/
+/*
+ * Write and Read some RAM in the DS1302, if it works assume it's there
+ * Otherwise use the SH4 internal RTC
+ */
+
+void snapgear_rtc_gettimeofday(struct timespec *);
+int snapgear_rtc_settimeofday(const time_t);
+
+void __init secureedge5410_rtc_init(void)
+{
+ unsigned char *test = "snapgear";
+ int i;
+
+ ds1302_reset();
+
+ use_ds1302 = 1;
+
+ for (i = 0; test[i]; i++)
+ ds1302_writebyte(32 + i, test[i]);
+
+ for (i = 0; test[i]; i++)
+ if (ds1302_readbyte(32 + i) != test[i]) {
+ use_ds1302 = 0;
+ break;
+ }
+
+ if (use_ds1302) {
+ rtc_get_time = snapgear_rtc_gettimeofday;
+ rtc_set_time = snapgear_rtc_settimeofday;
+ } else {
+ rtc_get_time = sh_rtc_gettimeofday;
+ rtc_set_time = sh_rtc_settimeofday;
+ }
+
+ printk("SnapGear RTC: using %s rtc.\n", use_ds1302 ? "ds1302" : "internal");
+}
+
+/****************************************************************************/
+/*
+ * our generic interface that chooses the correct code to use
+ */
+
+void snapgear_rtc_gettimeofday(struct timespec *ts)
+{
+ unsigned int sec, min, hr, day, mon, yr;
+
+ if (!use_ds1302) {
+ sh_rtc_gettimeofday(ts);
+ return;
+ }
+
+ sec = bcd2int(ds1302_readbyte(RTC_ADDR_SEC));
+ min = bcd2int(ds1302_readbyte(RTC_ADDR_MIN));
+ hr = bcd2int(ds1302_readbyte(RTC_ADDR_HOUR));
+ day = bcd2int(ds1302_readbyte(RTC_ADDR_DATE));
+ mon = bcd2int(ds1302_readbyte(RTC_ADDR_MON));
+ yr = bcd2int(ds1302_readbyte(RTC_ADDR_YEAR));
+
+bad_time:
+ if (yr > 99 || mon < 1 || mon > 12 || day > 31 || day < 1 ||
+ hr > 23 || min > 59 || sec > 59) {
+ printk(KERN_ERR
+ "SnapGear RTC: invalid value, resetting to 1 Jan 2000\n");
+ ds1302_writebyte(RTC_ADDR_MIN, min = 0);
+ ds1302_writebyte(RTC_ADDR_HOUR, hr = 0);
+ ds1302_writebyte(RTC_ADDR_DAY, 7);
+ ds1302_writebyte(RTC_ADDR_DATE, day = 1);
+ ds1302_writebyte(RTC_ADDR_MON, mon = 1);
+ ds1302_writebyte(RTC_ADDR_YEAR, yr = 0);
+ ds1302_writebyte(RTC_ADDR_SEC, sec = 0);
+ }
+
+ ts->tv_sec = mktime(2000 + yr, mon, day, hr, min, sec);
+ if (ts->tv_sec < 0) {
+#if 0
+ printk("BAD TIME %d %d %d %d %d %d\n", yr, mon, day, hr, min, sec);
+#endif
+ yr = 100;
+ goto bad_time;
+ }
+ ts->tv_nsec = 0;
+}
+
+int snapgear_rtc_settimeofday(const time_t secs)
+{
+ int retval = 0;
+ int real_seconds, real_minutes, cmos_minutes;
+ unsigned long nowtime;
+
+ if (!use_ds1302)
+ return sh_rtc_settimeofday(secs);
+
+/*
+ * This is called direct from the kernel timer handling code.
+ * It is supposed to synchronize the kernel clock to the RTC.
+ */
+
+ nowtime = secs;
+
+#if 1
+ printk("SnapGear RTC: snapgear_rtc_settimeofday(nowtime=%ld)\n", nowtime);
+#endif
+
+ /* STOP RTC */
+ ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) | 0x80);
+
+ cmos_minutes = bcd2int(ds1302_readbyte(RTC_ADDR_MIN));
+
+ /*
+ * since we're only adjusting minutes and seconds,
+ * don't interfere with hour overflow. This avoids
+ * messing with unknown time zones but requires your
+ * RTC not to be off by more than 15 minutes
+ */
+ real_seconds = nowtime % 60;
+ real_minutes = nowtime / 60;
+ if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+ real_minutes += 30; /* correct for half hour time zone */
+ real_minutes %= 60;
+
+ if (abs(real_minutes - cmos_minutes) < 30) {
+ ds1302_writebyte(RTC_ADDR_MIN, int2bcd(real_minutes));
+ ds1302_writebyte(RTC_ADDR_SEC, int2bcd(real_seconds));
+ } else {
+ printk(KERN_WARNING
+ "SnapGear RTC: can't update from %d to %d\n",
+ cmos_minutes, real_minutes);
+ retval = -1;
+ }
+
+ /* START RTC */
+ ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) & ~0x80);
+ return(0);
+}
+
+unsigned char secureedge5410_cmos_read(int addr)
+{
+ unsigned char val = 0;
+
+ if (!use_ds1302)
+ return(__CMOS_READ(addr, w));
+
+ switch(addr) {
+ case RTC_SECONDS: val = ds1302_readbyte(RTC_ADDR_SEC); break;
+ case RTC_SECONDS_ALARM: break;
+ case RTC_MINUTES: val = ds1302_readbyte(RTC_ADDR_MIN); break;
+ case RTC_MINUTES_ALARM: break;
+ case RTC_HOURS: val = ds1302_readbyte(RTC_ADDR_HOUR); break;
+ case RTC_HOURS_ALARM: break;
+ case RTC_DAY_OF_WEEK: val = ds1302_readbyte(RTC_ADDR_DAY); break;
+ case RTC_DAY_OF_MONTH: val = ds1302_readbyte(RTC_ADDR_DATE); break;
+ case RTC_MONTH: val = ds1302_readbyte(RTC_ADDR_MON); break;
+ case RTC_YEAR: val = ds1302_readbyte(RTC_ADDR_YEAR); break;
+ case RTC_REG_A: /* RTC_FREQ_SELECT */ break;
+ case RTC_REG_B: /* RTC_CONTROL */ break;
+ case RTC_REG_C: /* RTC_INTR_FLAGS */ break;
+ case RTC_REG_D: val = RTC_VRT /* RTC_VALID */; break;
+ default: break;
+ }
+
+ return(val);
+}
+
+void secureedge5410_cmos_write(unsigned char val, int addr)
+{
+ if (!use_ds1302) {
+ __CMOS_WRITE(val, addr, w);
+ return;
+ }
+
+ switch(addr) {
+ case RTC_SECONDS: ds1302_writebyte(RTC_ADDR_SEC, val); break;
+ case RTC_SECONDS_ALARM: break;
+ case RTC_MINUTES: ds1302_writebyte(RTC_ADDR_MIN, val); break;
+ case RTC_MINUTES_ALARM: break;
+ case RTC_HOURS: ds1302_writebyte(RTC_ADDR_HOUR, val); break;
+ case RTC_HOURS_ALARM: break;
+ case RTC_DAY_OF_WEEK: ds1302_writebyte(RTC_ADDR_DAY, val); break;
+ case RTC_DAY_OF_MONTH: ds1302_writebyte(RTC_ADDR_DATE, val); break;
+ case RTC_MONTH: ds1302_writebyte(RTC_ADDR_MON, val); break;
+ case RTC_YEAR: ds1302_writebyte(RTC_ADDR_YEAR, val); break;
+ case RTC_REG_A: /* RTC_FREQ_SELECT */ break;
+ case RTC_REG_B: /* RTC_CONTROL */ break;
+ case RTC_REG_C: /* RTC_INTR_FLAGS */ break;
+ case RTC_REG_D: /* RTC_VALID */ break;
+ default: break;
+ }
+}
+
+/****************************************************************************/
diff --git a/arch/sh/boards/snapgear/setup.c b/arch/sh/boards/snapgear/setup.c
new file mode 100644
index 000000000000..08fc98342a0b
--- /dev/null
+++ b/arch/sh/boards/snapgear/setup.c
@@ -0,0 +1,216 @@
+/****************************************************************************/
+/*
+ * linux/arch/sh/boards/snapgear/setup.c
+ *
+ * Copyright (C) 2002 David McCullough <davidm@snapgear.com>
+ * Copyright (C) 2003 Paul Mundt <lethal@linux-sh.org>
+ *
+ * Based on files with the following comments:
+ *
+ * Copyright (C) 2000 Kazumoto Kojima
+ *
+ * Modified for 7751 Solution Engine by
+ * Ian da Silva and Jeremy Siegel, 2001.
+ */
+/****************************************************************************/
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+
+#include <asm/machvec.h>
+#include <asm/mach/io.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/cpu/timer.h>
+
+extern void (*board_time_init)(void);
+extern void secureedge5410_rtc_init(void);
+extern void pcibios_init(void);
+
+/****************************************************************************/
+/*
+ * EraseConfig handling functions
+ */
+
+static irqreturn_t eraseconfig_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ volatile char dummy __attribute__((unused)) = * (volatile char *) 0xb8000000;
+
+ printk("SnapGear: erase switch interrupt!\n");
+
+ return IRQ_HANDLED;
+}
+
+static int __init eraseconfig_init(void)
+{
+ printk("SnapGear: EraseConfig init\n");
+ /* Setup "EraseConfig" switch on external IRQ 0 */
+ if (request_irq(IRL0_IRQ, eraseconfig_interrupt, SA_INTERRUPT,
+ "Erase Config", NULL))
+ printk("SnapGear: failed to register IRQ%d for Reset witch\n",
+ IRL0_IRQ);
+ else
+ printk("SnapGear: registered EraseConfig switch on IRQ%d\n",
+ IRL0_IRQ);
+ return(0);
+}
+
+module_init(eraseconfig_init);
+
+/****************************************************************************/
+/*
+ * Initialize IRQ setting
+ *
+ * IRL0 = erase switch
+ * IRL1 = eth0
+ * IRL2 = eth1
+ * IRL3 = crypto
+ */
+
+static void __init init_snapgear_IRQ(void)
+{
+ /* enable individual interrupt mode for externals */
+ ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
+
+ printk("Setup SnapGear IRQ/IPR ...\n");
+
+ make_ipr_irq(IRL0_IRQ, IRL0_IPR_ADDR, IRL0_IPR_POS, IRL0_PRIORITY);
+ make_ipr_irq(IRL1_IRQ, IRL1_IPR_ADDR, IRL1_IPR_POS, IRL1_PRIORITY);
+ make_ipr_irq(IRL2_IRQ, IRL2_IPR_ADDR, IRL2_IPR_POS, IRL2_PRIORITY);
+ make_ipr_irq(IRL3_IRQ, IRL3_IPR_ADDR, IRL3_IPR_POS, IRL3_PRIORITY);
+}
+
+/****************************************************************************/
+/*
+ * Fast poll interrupt simulator.
+ */
+
+/*
+ * Leave all of the fast timer/fast poll stuff commented out for now, since
+ * it's not clear whether it actually works or not. Since it wasn't being used
+ * at all in 2.4, we'll assume it's not sane for 2.6 either.. -- PFM
+ */
+#if 0
+#define FAST_POLL 1000
+//#define FAST_POLL_INTR
+
+#define FASTTIMER_IRQ 17
+#define FASTTIMER_IPR_ADDR INTC_IPRA
+#define FASTTIMER_IPR_POS 2
+#define FASTTIMER_PRIORITY 3
+
+#ifdef FAST_POLL_INTR
+#define TMU1_TCR_INIT 0x0020
+#else
+#define TMU1_TCR_INIT 0
+#endif
+#define TMU_TSTR_INIT 1
+#define TMU1_TCR_CALIB 0x0000
+
+
+#ifdef FAST_POLL_INTR
+static void fast_timer_irq(int irq, void *dev_instance, struct pt_regs *regs)
+{
+ unsigned long timer_status;
+ timer_status = ctrl_inw(TMU1_TCR);
+ timer_status &= ~0x100;
+ ctrl_outw(timer_status, TMU1_TCR);
+}
+#endif
+
+/*
+ * return the current ticks on the fast timer
+ */
+
+unsigned long fast_timer_count(void)
+{
+ return(ctrl_inl(TMU1_TCNT));
+}
+
+/*
+ * setup a fast timer for profiling etc etc
+ */
+
+static void setup_fast_timer()
+{
+ unsigned long interval;
+
+#ifdef FAST_POLL_INTR
+ interval = (current_cpu_data.module_clock/4 + FAST_POLL/2) / FAST_POLL;
+
+ make_ipr_irq(FASTTIMER_IRQ, FASTTIMER_IPR_ADDR, FASTTIMER_IPR_POS,
+ FASTTIMER_PRIORITY);
+
+ printk("SnapGear: %dHz fast timer on IRQ %d\n",FAST_POLL,FASTTIMER_IRQ);
+
+ if (request_irq(FASTTIMER_IRQ, fast_timer_irq, 0, "SnapGear fast timer",
+ NULL) != 0)
+ printk("%s(%d): request_irq() failed?\n", __FILE__, __LINE__);
+#else
+ printk("SnapGear: fast timer running\n",FAST_POLL,FASTTIMER_IRQ);
+ interval = 0xffffffff;
+#endif
+
+ ctrl_outb(ctrl_inb(TMU_TSTR) & ~0x2, TMU_TSTR); /* disable timer 1 */
+ ctrl_outw(TMU1_TCR_INIT, TMU1_TCR);
+ ctrl_outl(interval, TMU1_TCOR);
+ ctrl_outl(interval, TMU1_TCNT);
+ ctrl_outb(ctrl_inb(TMU_TSTR) | 0x2, TMU_TSTR); /* enable timer 1 */
+
+ printk("Timer count 1 = 0x%x\n", fast_timer_count());
+ udelay(1000);
+ printk("Timer count 2 = 0x%x\n", fast_timer_count());
+}
+#endif
+
+/****************************************************************************/
+
+const char *get_system_type(void)
+{
+ return "SnapGear SecureEdge5410";
+}
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_snapgear __initmv = {
+ .mv_nr_irqs = 72,
+
+ .mv_inb = snapgear_inb,
+ .mv_inw = snapgear_inw,
+ .mv_inl = snapgear_inl,
+ .mv_outb = snapgear_outb,
+ .mv_outw = snapgear_outw,
+ .mv_outl = snapgear_outl,
+
+ .mv_inb_p = snapgear_inb_p,
+ .mv_inw_p = snapgear_inw,
+ .mv_inl_p = snapgear_inl,
+ .mv_outb_p = snapgear_outb_p,
+ .mv_outw_p = snapgear_outw,
+ .mv_outl_p = snapgear_outl,
+
+ .mv_isa_port2addr = snapgear_isa_port2addr,
+
+ .mv_init_irq = init_snapgear_IRQ,
+};
+ALIAS_MV(snapgear)
+
+/*
+ * Initialize the board
+ */
+
+int __init platform_setup(void)
+{
+ board_time_init = secureedge5410_rtc_init;
+
+ return 0;
+}
+
diff --git a/arch/sh/boards/superh/microdev/Makefile b/arch/sh/boards/superh/microdev/Makefile
new file mode 100644
index 000000000000..1387dd6c85eb
--- /dev/null
+++ b/arch/sh/boards/superh/microdev/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the SuperH MicroDev specific parts of the kernel
+#
+
+obj-y := setup.o irq.o io.o
+
+obj-$(CONFIG_HEARTBEAT) += led.o
+
diff --git a/arch/sh/boards/superh/microdev/io.c b/arch/sh/boards/superh/microdev/io.c
new file mode 100644
index 000000000000..fe83b2c03076
--- /dev/null
+++ b/arch/sh/boards/superh/microdev/io.c
@@ -0,0 +1,370 @@
+/*
+ * linux/arch/sh/kernel/io_microdev.c
+ *
+ * Copyright (C) 2003 Sean McGoogan (Sean.McGoogan@superh.com)
+ * Copyright (C) 2003, 2004 SuperH, Inc.
+ * Copyright (C) 2004 Paul Mundt
+ *
+ * SuperH SH4-202 MicroDev board support.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/wait.h>
+#include <asm/io.h>
+#include <asm/mach/io.h>
+
+ /*
+ * we need to have a 'safe' address to re-direct all I/O requests
+ * that we do not explicitly wish to handle. This safe address
+ * must have the following properies:
+ *
+ * * writes are ignored (no exception)
+ * * reads are benign (no side-effects)
+ * * accesses of width 1, 2 and 4-bytes are all valid.
+ *
+ * The Processor Version Register (PVR) has these properties.
+ */
+#define PVR 0xff000030 /* Processor Version Register */
+
+
+#define IO_IDE2_BASE 0x170ul /* I/O base for SMSC FDC37C93xAPM IDE #2 */
+#define IO_IDE1_BASE 0x1f0ul /* I/O base for SMSC FDC37C93xAPM IDE #1 */
+#define IO_ISP1161_BASE 0x290ul /* I/O port for Philips ISP1161x USB chip */
+#define IO_SERIAL2_BASE 0x2f8ul /* I/O base for SMSC FDC37C93xAPM Serial #2 */
+#define IO_LAN91C111_BASE 0x300ul /* I/O base for SMSC LAN91C111 Ethernet chip */
+#define IO_IDE2_MISC 0x376ul /* I/O misc for SMSC FDC37C93xAPM IDE #2 */
+#define IO_SUPERIO_BASE 0x3f0ul /* I/O base for SMSC FDC37C93xAPM SuperIO chip */
+#define IO_IDE1_MISC 0x3f6ul /* I/O misc for SMSC FDC37C93xAPM IDE #1 */
+#define IO_SERIAL1_BASE 0x3f8ul /* I/O base for SMSC FDC37C93xAPM Serial #1 */
+
+#define IO_ISP1161_EXTENT 0x04ul /* I/O extent for Philips ISP1161x USB chip */
+#define IO_LAN91C111_EXTENT 0x10ul /* I/O extent for SMSC LAN91C111 Ethernet chip */
+#define IO_SUPERIO_EXTENT 0x02ul /* I/O extent for SMSC FDC37C93xAPM SuperIO chip */
+#define IO_IDE_EXTENT 0x08ul /* I/O extent for IDE Task Register set */
+#define IO_SERIAL_EXTENT 0x10ul
+
+#define IO_LAN91C111_PHYS 0xa7500000ul /* Physical address of SMSC LAN91C111 Ethernet chip */
+#define IO_ISP1161_PHYS 0xa7700000ul /* Physical address of Philips ISP1161x USB chip */
+#define IO_SUPERIO_PHYS 0xa7800000ul /* Physical address of SMSC FDC37C93xAPM SuperIO chip */
+
+#define PORT2ADDR(x) (microdev_isa_port2addr(x))
+
+
+static inline void delay(void)
+{
+#if defined(CONFIG_PCI)
+ /* System board present, just make a dummy SRAM access. (CS0 will be
+ mapped to PCI memory, probably good to avoid it.) */
+ ctrl_inw(0xa6800000);
+#else
+ /* CS0 will be mapped to flash, ROM etc so safe to access it. */
+ ctrl_inw(0xa0000000);
+#endif
+}
+
+unsigned char microdev_inb(unsigned long port)
+{
+#ifdef CONFIG_PCI
+ if (port >= PCIBIOS_MIN_IO)
+ return microdev_pci_inb(port);
+#endif
+ return *(volatile unsigned char*)PORT2ADDR(port);
+}
+
+unsigned short microdev_inw(unsigned long port)
+{
+#ifdef CONFIG_PCI
+ if (port >= PCIBIOS_MIN_IO)
+ return microdev_pci_inw(port);
+#endif
+ return *(volatile unsigned short*)PORT2ADDR(port);
+}
+
+unsigned int microdev_inl(unsigned long port)
+{
+#ifdef CONFIG_PCI
+ if (port >= PCIBIOS_MIN_IO)
+ return microdev_pci_inl(port);
+#endif
+ return *(volatile unsigned int*)PORT2ADDR(port);
+}
+
+void microdev_outb(unsigned char b, unsigned long port)
+{
+#ifdef CONFIG_PCI
+ if (port >= PCIBIOS_MIN_IO) {
+ microdev_pci_outb(b, port);
+ return;
+ }
+#endif
+
+ /*
+ * There is a board feature with the current SH4-202 MicroDev in
+ * that the 2 byte enables (nBE0 and nBE1) are tied together (and
+ * to the Chip Select Line (Ethernet_CS)). Due to this conectivity,
+ * it is not possible to safely perform 8-bit writes to the
+ * Ethernet registers, as 16-bits will be consumed from the Data
+ * lines (corrupting the other byte). Hence, this function is
+ * written to impliment 16-bit read/modify/write for all byte-wide
+ * acceses.
+ *
+ * Note: there is no problem with byte READS (even or odd).
+ *
+ * Sean McGoogan - 16th June 2003.
+ */
+ if ((port >= IO_LAN91C111_BASE) &&
+ (port < IO_LAN91C111_BASE + IO_LAN91C111_EXTENT)) {
+ /*
+ * Then are trying to perform a byte-write to the
+ * LAN91C111. This needs special care.
+ */
+ if (port % 2 == 1) { /* is the port odd ? */
+ /* unset bit-0, i.e. make even */
+ const unsigned long evenPort = port-1;
+ unsigned short word;
+
+ /*
+ * do a 16-bit read/write to write to 'port',
+ * preserving even byte.
+ *
+ * Even addresses are bits 0-7
+ * Odd addresses are bits 8-15
+ */
+ word = microdev_inw(evenPort);
+ word = (word & 0xffu) | (b << 8);
+ microdev_outw(word, evenPort);
+ } else {
+ /* else, we are trying to do an even byte write */
+ unsigned short word;
+
+ /*
+ * do a 16-bit read/write to write to 'port',
+ * preserving odd byte.
+ *
+ * Even addresses are bits 0-7
+ * Odd addresses are bits 8-15
+ */
+ word = microdev_inw(port);
+ word = (word & 0xff00u) | (b);
+ microdev_outw(word, port);
+ }
+ } else {
+ *(volatile unsigned char*)PORT2ADDR(port) = b;
+ }
+}
+
+void microdev_outw(unsigned short b, unsigned long port)
+{
+#ifdef CONFIG_PCI
+ if (port >= PCIBIOS_MIN_IO) {
+ microdev_pci_outw(b, port);
+ return;
+ }
+#endif
+ *(volatile unsigned short*)PORT2ADDR(port) = b;
+}
+
+void microdev_outl(unsigned int b, unsigned long port)
+{
+#ifdef CONFIG_PCI
+ if (port >= PCIBIOS_MIN_IO) {
+ microdev_pci_outl(b, port);
+ return;
+ }
+#endif
+ *(volatile unsigned int*)PORT2ADDR(port) = b;
+}
+
+unsigned char microdev_inb_p(unsigned long port)
+{
+ unsigned char v = microdev_inb(port);
+ delay();
+ return v;
+}
+
+unsigned short microdev_inw_p(unsigned long port)
+{
+ unsigned short v = microdev_inw(port);
+ delay();
+ return v;
+}
+
+unsigned int microdev_inl_p(unsigned long port)
+{
+ unsigned int v = microdev_inl(port);
+ delay();
+ return v;
+}
+
+void microdev_outb_p(unsigned char b, unsigned long port)
+{
+ microdev_outb(b, port);
+ delay();
+}
+
+void microdev_outw_p(unsigned short b, unsigned long port)
+{
+ microdev_outw(b, port);
+ delay();
+}
+
+void microdev_outl_p(unsigned int b, unsigned long port)
+{
+ microdev_outl(b, port);
+ delay();
+}
+
+void microdev_insb(unsigned long port, void *buffer, unsigned long count)
+{
+ volatile unsigned char *port_addr;
+ unsigned char *buf = buffer;
+
+ port_addr = (volatile unsigned char *)PORT2ADDR(port);
+
+ while (count--)
+ *buf++ = *port_addr;
+}
+
+void microdev_insw(unsigned long port, void *buffer, unsigned long count)
+{
+ volatile unsigned short *port_addr;
+ unsigned short *buf = buffer;
+
+ port_addr = (volatile unsigned short *)PORT2ADDR(port);
+
+ while (count--)
+ *buf++ = *port_addr;
+}
+
+void microdev_insl(unsigned long port, void *buffer, unsigned long count)
+{
+ volatile unsigned long *port_addr;
+ unsigned int *buf = buffer;
+
+ port_addr = (volatile unsigned long *)PORT2ADDR(port);
+
+ while (count--)
+ *buf++ = *port_addr;
+}
+
+void microdev_outsb(unsigned long port, const void *buffer, unsigned long count)
+{
+ volatile unsigned char *port_addr;
+ const unsigned char *buf = buffer;
+
+ port_addr = (volatile unsigned char *)PORT2ADDR(port);
+
+ while (count--)
+ *port_addr = *buf++;
+}
+
+void microdev_outsw(unsigned long port, const void *buffer, unsigned long count)
+{
+ volatile unsigned short *port_addr;
+ const unsigned short *buf = buffer;
+
+ port_addr = (volatile unsigned short *)PORT2ADDR(port);
+
+ while (count--)
+ *port_addr = *buf++;
+}
+
+void microdev_outsl(unsigned long port, const void *buffer, unsigned long count)
+{
+ volatile unsigned long *port_addr;
+ const unsigned int *buf = buffer;
+
+ port_addr = (volatile unsigned long *)PORT2ADDR(port);
+
+ while (count--)
+ *port_addr = *buf++;
+}
+
+/*
+ * map I/O ports to memory-mapped addresses
+ */
+unsigned long microdev_isa_port2addr(unsigned long offset)
+{
+ unsigned long result;
+
+ if ((offset >= IO_LAN91C111_BASE) &&
+ (offset < IO_LAN91C111_BASE + IO_LAN91C111_EXTENT)) {
+ /*
+ * SMSC LAN91C111 Ethernet chip
+ */
+ result = IO_LAN91C111_PHYS + offset - IO_LAN91C111_BASE;
+ } else if ((offset >= IO_SUPERIO_BASE) &&
+ (offset < IO_SUPERIO_BASE + IO_SUPERIO_EXTENT)) {
+ /*
+ * SMSC FDC37C93xAPM SuperIO chip
+ *
+ * Configuration Registers
+ */
+ result = IO_SUPERIO_PHYS + (offset << 1);
+#if 0
+ } else if (offset == KBD_DATA_REG || offset == KBD_CNTL_REG ||
+ offset == KBD_STATUS_REG) {
+ /*
+ * SMSC FDC37C93xAPM SuperIO chip
+ *
+ * PS/2 Keyboard + Mouse (ports 0x60 and 0x64).
+ */
+ result = IO_SUPERIO_PHYS + (offset << 1);
+#endif
+ } else if (((offset >= IO_IDE1_BASE) &&
+ (offset < IO_IDE1_BASE + IO_IDE_EXTENT)) ||
+ (offset == IO_IDE1_MISC)) {
+ /*
+ * SMSC FDC37C93xAPM SuperIO chip
+ *
+ * IDE #1
+ */
+ result = IO_SUPERIO_PHYS + (offset << 1);
+ } else if (((offset >= IO_IDE2_BASE) &&
+ (offset < IO_IDE2_BASE + IO_IDE_EXTENT)) ||
+ (offset == IO_IDE2_MISC)) {
+ /*
+ * SMSC FDC37C93xAPM SuperIO chip
+ *
+ * IDE #2
+ */
+ result = IO_SUPERIO_PHYS + (offset << 1);
+ } else if ((offset >= IO_SERIAL1_BASE) &&
+ (offset < IO_SERIAL1_BASE + IO_SERIAL_EXTENT)) {
+ /*
+ * SMSC FDC37C93xAPM SuperIO chip
+ *
+ * Serial #1
+ */
+ result = IO_SUPERIO_PHYS + (offset << 1);
+ } else if ((offset >= IO_SERIAL2_BASE) &&
+ (offset < IO_SERIAL2_BASE + IO_SERIAL_EXTENT)) {
+ /*
+ * SMSC FDC37C93xAPM SuperIO chip
+ *
+ * Serial #2
+ */
+ result = IO_SUPERIO_PHYS + (offset << 1);
+ } else if ((offset >= IO_ISP1161_BASE) &&
+ (offset < IO_ISP1161_BASE + IO_ISP1161_EXTENT)) {
+ /*
+ * Philips USB ISP1161x chip
+ */
+ result = IO_ISP1161_PHYS + offset - IO_ISP1161_BASE;
+ } else {
+ /*
+ * safe default.
+ */
+ printk("Warning: unexpected port in %s( offset = 0x%lx )\n",
+ __FUNCTION__, offset);
+ result = PVR;
+ }
+
+ return result;
+}
+
diff --git a/arch/sh/boards/superh/microdev/irq.c b/arch/sh/boards/superh/microdev/irq.c
new file mode 100644
index 000000000000..1298883eca4b
--- /dev/null
+++ b/arch/sh/boards/superh/microdev/irq.c
@@ -0,0 +1,200 @@
+/*
+ * arch/sh/boards/superh/microdev/irq.c
+ *
+ * Copyright (C) 2003 Sean McGoogan (Sean.McGoogan@superh.com)
+ *
+ * SuperH SH4-202 MicroDev board support.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/mach/irq.h>
+
+#define NUM_EXTERNAL_IRQS 16 /* IRL0 .. IRL15 */
+
+
+static const struct {
+ unsigned char fpgaIrq;
+ unsigned char mapped;
+ const char *name;
+} fpgaIrqTable[NUM_EXTERNAL_IRQS] = {
+ { 0, 0, "unused" }, /* IRQ #0 IRL=15 0x200 */
+ { MICRODEV_FPGA_IRQ_KEYBOARD, 1, "keyboard" }, /* IRQ #1 IRL=14 0x220 */
+ { MICRODEV_FPGA_IRQ_SERIAL1, 1, "Serial #1"}, /* IRQ #2 IRL=13 0x240 */
+ { MICRODEV_FPGA_IRQ_ETHERNET, 1, "Ethernet" }, /* IRQ #3 IRL=12 0x260 */
+ { MICRODEV_FPGA_IRQ_SERIAL2, 0, "Serial #2"}, /* IRQ #4 IRL=11 0x280 */
+ { 0, 0, "unused" }, /* IRQ #5 IRL=10 0x2a0 */
+ { 0, 0, "unused" }, /* IRQ #6 IRL=9 0x2c0 */
+ { MICRODEV_FPGA_IRQ_USB_HC, 1, "USB" }, /* IRQ #7 IRL=8 0x2e0 */
+ { MICRODEV_IRQ_PCI_INTA, 1, "PCI INTA" }, /* IRQ #8 IRL=7 0x300 */
+ { MICRODEV_IRQ_PCI_INTB, 1, "PCI INTB" }, /* IRQ #9 IRL=6 0x320 */
+ { MICRODEV_IRQ_PCI_INTC, 1, "PCI INTC" }, /* IRQ #10 IRL=5 0x340 */
+ { MICRODEV_IRQ_PCI_INTD, 1, "PCI INTD" }, /* IRQ #11 IRL=4 0x360 */
+ { MICRODEV_FPGA_IRQ_MOUSE, 1, "mouse" }, /* IRQ #12 IRL=3 0x380 */
+ { MICRODEV_FPGA_IRQ_IDE2, 1, "IDE #2" }, /* IRQ #13 IRL=2 0x3a0 */
+ { MICRODEV_FPGA_IRQ_IDE1, 1, "IDE #1" }, /* IRQ #14 IRL=1 0x3c0 */
+ { 0, 0, "unused" }, /* IRQ #15 IRL=0 0x3e0 */
+};
+
+#if (MICRODEV_LINUX_IRQ_KEYBOARD != 1)
+# error Inconsistancy in defining the IRQ# for Keyboard!
+#endif
+
+#if (MICRODEV_LINUX_IRQ_ETHERNET != 3)
+# error Inconsistancy in defining the IRQ# for Ethernet!
+#endif
+
+#if (MICRODEV_LINUX_IRQ_USB_HC != 7)
+# error Inconsistancy in defining the IRQ# for USB!
+#endif
+
+#if (MICRODEV_LINUX_IRQ_MOUSE != 12)
+# error Inconsistancy in defining the IRQ# for PS/2 Mouse!
+#endif
+
+#if (MICRODEV_LINUX_IRQ_IDE2 != 13)
+# error Inconsistancy in defining the IRQ# for secondary IDE!
+#endif
+
+#if (MICRODEV_LINUX_IRQ_IDE1 != 14)
+# error Inconsistancy in defining the IRQ# for primary IDE!
+#endif
+
+static void enable_microdev_irq(unsigned int irq);
+static void disable_microdev_irq(unsigned int irq);
+
+ /* shutdown is same as "disable" */
+#define shutdown_microdev_irq disable_microdev_irq
+
+static void mask_and_ack_microdev(unsigned int);
+static void end_microdev_irq(unsigned int irq);
+
+static unsigned int startup_microdev_irq(unsigned int irq)
+{
+ enable_microdev_irq(irq);
+ return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type microdev_irq_type = {
+ "MicroDev-IRQ",
+ startup_microdev_irq,
+ shutdown_microdev_irq,
+ enable_microdev_irq,
+ disable_microdev_irq,
+ mask_and_ack_microdev,
+ end_microdev_irq
+};
+
+static void disable_microdev_irq(unsigned int irq)
+{
+ unsigned int flags;
+ unsigned int fpgaIrq;
+
+ if (irq >= NUM_EXTERNAL_IRQS) return;
+ if (!fpgaIrqTable[irq].mapped) return;
+
+ fpgaIrq = fpgaIrqTable[irq].fpgaIrq;
+
+ /* disable interrupts */
+ local_irq_save(flags);
+
+ /* disable interupts on the FPGA INTC register */
+ ctrl_outl(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTDSB_REG);
+
+ /* restore interrupts */
+ local_irq_restore(flags);
+}
+
+static void enable_microdev_irq(unsigned int irq)
+{
+ unsigned long priorityReg, priorities, pri;
+ unsigned int flags;
+ unsigned int fpgaIrq;
+
+
+ if (irq >= NUM_EXTERNAL_IRQS) return;
+ if (!fpgaIrqTable[irq].mapped) return;
+
+ pri = 15 - irq;
+
+ fpgaIrq = fpgaIrqTable[irq].fpgaIrq;
+ priorityReg = MICRODEV_FPGA_INTPRI_REG(fpgaIrq);
+
+ /* disable interrupts */
+ local_irq_save(flags);
+
+ /* set priority for the interrupt */
+ priorities = ctrl_inl(priorityReg);
+ priorities &= ~MICRODEV_FPGA_INTPRI_MASK(fpgaIrq);
+ priorities |= MICRODEV_FPGA_INTPRI_LEVEL(fpgaIrq, pri);
+ ctrl_outl(priorities, priorityReg);
+
+ /* enable interupts on the FPGA INTC register */
+ ctrl_outl(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTENB_REG);
+
+ /* restore interrupts */
+ local_irq_restore(flags);
+}
+
+ /* This functions sets the desired irq handler to be a MicroDev type */
+static void __init make_microdev_irq(unsigned int irq)
+{
+ disable_irq_nosync(irq);
+ irq_desc[irq].handler = &microdev_irq_type;
+ disable_microdev_irq(irq);
+}
+
+static void mask_and_ack_microdev(unsigned int irq)
+{
+ disable_microdev_irq(irq);
+}
+
+static void end_microdev_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ {
+ enable_microdev_irq(irq);
+ }
+}
+
+extern void __init init_microdev_irq(void)
+{
+ int i;
+
+ /* disable interupts on the FPGA INTC register */
+ ctrl_outl(~0ul, MICRODEV_FPGA_INTDSB_REG);
+
+ for (i = 0; i < NUM_EXTERNAL_IRQS; i++)
+ {
+ make_microdev_irq(i);
+ }
+}
+
+extern void microdev_print_fpga_intc_status(void)
+{
+ volatile unsigned int * const intenb = (unsigned int*)MICRODEV_FPGA_INTENB_REG;
+ volatile unsigned int * const intdsb = (unsigned int*)MICRODEV_FPGA_INTDSB_REG;
+ volatile unsigned int * const intpria = (unsigned int*)MICRODEV_FPGA_INTPRI_REG(0);
+ volatile unsigned int * const intprib = (unsigned int*)MICRODEV_FPGA_INTPRI_REG(8);
+ volatile unsigned int * const intpric = (unsigned int*)MICRODEV_FPGA_INTPRI_REG(16);
+ volatile unsigned int * const intprid = (unsigned int*)MICRODEV_FPGA_INTPRI_REG(24);
+ volatile unsigned int * const intsrc = (unsigned int*)MICRODEV_FPGA_INTSRC_REG;
+ volatile unsigned int * const intreq = (unsigned int*)MICRODEV_FPGA_INTREQ_REG;
+
+ printk("-------------------------- microdev_print_fpga_intc_status() ------------------\n");
+ printk("FPGA_INTENB = 0x%08x\n", *intenb);
+ printk("FPGA_INTDSB = 0x%08x\n", *intdsb);
+ printk("FPGA_INTSRC = 0x%08x\n", *intsrc);
+ printk("FPGA_INTREQ = 0x%08x\n", *intreq);
+ printk("FPGA_INTPRI[3..0] = %08x:%08x:%08x:%08x\n", *intprid, *intpric, *intprib, *intpria);
+ printk("-------------------------------------------------------------------------------\n");
+}
+
+
diff --git a/arch/sh/boards/superh/microdev/led.c b/arch/sh/boards/superh/microdev/led.c
new file mode 100644
index 000000000000..52a98e69d3f0
--- /dev/null
+++ b/arch/sh/boards/superh/microdev/led.c
@@ -0,0 +1,102 @@
+/*
+ * linux/arch/sh/kernel/led_microdev.c
+ *
+ * Copyright (C) 2002 Stuart Menefy <stuart.menefy@st.com>
+ * Copyright (C) 2003 Richard Curnow (Richard.Curnow@superh.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ */
+
+#include <linux/config.h>
+#include <asm/io.h>
+
+#define LED_REGISTER 0xa6104d20
+
+static void mach_led_d9(int value)
+{
+ unsigned long reg;
+ reg = ctrl_inl(LED_REGISTER);
+ reg &= ~1;
+ reg |= (value & 1);
+ ctrl_outl(reg, LED_REGISTER);
+ return;
+}
+
+static void mach_led_d10(int value)
+{
+ unsigned long reg;
+ reg = ctrl_inl(LED_REGISTER);
+ reg &= ~2;
+ reg |= ((value & 1) << 1);
+ ctrl_outl(reg, LED_REGISTER);
+ return;
+}
+
+
+#ifdef CONFIG_HEARTBEAT
+#include <linux/sched.h>
+
+static unsigned char banner_table[] = {
+ 0x11, 0x01, 0x11, 0x01, 0x11, 0x03,
+ 0x11, 0x01, 0x11, 0x01, 0x13, 0x03,
+ 0x11, 0x01, 0x13, 0x01, 0x13, 0x01, 0x11, 0x03,
+ 0x11, 0x03,
+ 0x11, 0x01, 0x13, 0x01, 0x11, 0x03,
+ 0x11, 0x01, 0x11, 0x01, 0x11, 0x01, 0x11, 0x07,
+ 0x13, 0x01, 0x13, 0x03,
+ 0x11, 0x01, 0x11, 0x03,
+ 0x13, 0x01, 0x11, 0x01, 0x13, 0x01, 0x11, 0x03,
+ 0x11, 0x01, 0x13, 0x01, 0x11, 0x03,
+ 0x13, 0x01, 0x13, 0x01, 0x13, 0x03,
+ 0x13, 0x01, 0x11, 0x01, 0x11, 0x03,
+ 0x11, 0x03,
+ 0x11, 0x01, 0x11, 0x01, 0x11, 0x01, 0x13, 0x07,
+ 0xff
+};
+
+static void banner(void)
+{
+ static int pos = 0;
+ static int count = 0;
+
+ if (count) {
+ count--;
+ } else {
+ int val = banner_table[pos];
+ if (val == 0xff) {
+ pos = 0;
+ val = banner_table[pos];
+ }
+ pos++;
+ mach_led_d10((val >> 4) & 1);
+ count = 10 * (val & 0xf);
+ }
+}
+
+/* From heartbeat_harp in the stboards directory */
+/* acts like an actual heart beat -- ie thump-thump-pause... */
+void microdev_heartbeat(void)
+{
+ static unsigned cnt = 0, period = 0, dist = 0;
+
+ if (cnt == 0 || cnt == dist)
+ mach_led_d9(1);
+ else if (cnt == 7 || cnt == dist+7)
+ mach_led_d9(0);
+
+ if (++cnt > period) {
+ cnt = 0;
+ /* The hyperbolic function below modifies the heartbeat period
+ * length in dependency of the current (5min) load. It goes
+ * through the points f(0)=126, f(1)=86, f(5)=51,
+ * f(inf)->30. */
+ period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
+ dist = period / 4;
+ }
+
+ banner();
+}
+
+#endif
diff --git a/arch/sh/boards/superh/microdev/setup.c b/arch/sh/boards/superh/microdev/setup.c
new file mode 100644
index 000000000000..c18919941ec0
--- /dev/null
+++ b/arch/sh/boards/superh/microdev/setup.c
@@ -0,0 +1,278 @@
+/*
+ * arch/sh/boards/superh/microdev/setup.c
+ *
+ * Copyright (C) 2003 Sean McGoogan (Sean.McGoogan@superh.com)
+ * Copyright (C) 2003, 2004 SuperH, Inc.
+ * Copyright (C) 2004 Paul Mundt
+ *
+ * SuperH SH4-202 MicroDev board support.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/io.h>
+#include <asm/machvec.h>
+#include <asm/machvec_init.h>
+
+extern void microdev_heartbeat(void);
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_sh4202_microdev __initmv = {
+ .mv_nr_irqs = 72, /* QQQ need to check this - use the MACRO */
+
+ .mv_inb = microdev_inb,
+ .mv_inw = microdev_inw,
+ .mv_inl = microdev_inl,
+ .mv_outb = microdev_outb,
+ .mv_outw = microdev_outw,
+ .mv_outl = microdev_outl,
+
+ .mv_inb_p = microdev_inb_p,
+ .mv_inw_p = microdev_inw_p,
+ .mv_inl_p = microdev_inl_p,
+ .mv_outb_p = microdev_outb_p,
+ .mv_outw_p = microdev_outw_p,
+ .mv_outl_p = microdev_outl_p,
+
+ .mv_insb = microdev_insb,
+ .mv_insw = microdev_insw,
+ .mv_insl = microdev_insl,
+ .mv_outsb = microdev_outsb,
+ .mv_outsw = microdev_outsw,
+ .mv_outsl = microdev_outsl,
+
+ .mv_isa_port2addr = microdev_isa_port2addr,
+
+ .mv_init_irq = init_microdev_irq,
+
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = microdev_heartbeat,
+#endif
+};
+ALIAS_MV(sh4202_microdev)
+
+/****************************************************************************/
+
+
+ /*
+ * Setup for the SMSC FDC37C93xAPM
+ */
+#define SMSC_CONFIG_PORT_ADDR (0x3F0)
+#define SMSC_INDEX_PORT_ADDR SMSC_CONFIG_PORT_ADDR
+#define SMSC_DATA_PORT_ADDR (SMSC_INDEX_PORT_ADDR + 1)
+
+#define SMSC_ENTER_CONFIG_KEY 0x55
+#define SMSC_EXIT_CONFIG_KEY 0xaa
+
+#define SMCS_LOGICAL_DEV_INDEX 0x07 /* Logical Device Number */
+#define SMSC_DEVICE_ID_INDEX 0x20 /* Device ID */
+#define SMSC_DEVICE_REV_INDEX 0x21 /* Device Revision */
+#define SMSC_ACTIVATE_INDEX 0x30 /* Activate */
+#define SMSC_PRIMARY_BASE_INDEX 0x60 /* Primary Base Address */
+#define SMSC_SECONDARY_BASE_INDEX 0x62 /* Secondary Base Address */
+#define SMSC_PRIMARY_INT_INDEX 0x70 /* Primary Interrupt Select */
+#define SMSC_SECONDARY_INT_INDEX 0x72 /* Secondary Interrupt Select */
+#define SMSC_HDCS0_INDEX 0xf0 /* HDCS0 Address Decoder */
+#define SMSC_HDCS1_INDEX 0xf1 /* HDCS1 Address Decoder */
+
+#define SMSC_IDE1_DEVICE 1 /* IDE #1 logical device */
+#define SMSC_IDE2_DEVICE 2 /* IDE #2 logical device */
+#define SMSC_PARALLEL_DEVICE 3 /* Parallel Port logical device */
+#define SMSC_SERIAL1_DEVICE 4 /* Serial #1 logical device */
+#define SMSC_SERIAL2_DEVICE 5 /* Serial #2 logical device */
+#define SMSC_KEYBOARD_DEVICE 7 /* Keyboard logical device */
+#define SMSC_CONFIG_REGISTERS 8 /* Configuration Registers (Aux I/O) */
+
+#define SMSC_READ_INDEXED(index) ({ \
+ outb((index), SMSC_INDEX_PORT_ADDR); \
+ inb(SMSC_DATA_PORT_ADDR); })
+#define SMSC_WRITE_INDEXED(val, index) ({ \
+ outb((index), SMSC_INDEX_PORT_ADDR); \
+ outb((val), SMSC_DATA_PORT_ADDR); })
+
+#define IDE1_PRIMARY_BASE 0x01f0 /* Task File Registe base for IDE #1 */
+#define IDE1_SECONDARY_BASE 0x03f6 /* Miscellaneous AT registers for IDE #1 */
+#define IDE2_PRIMARY_BASE 0x0170 /* Task File Registe base for IDE #2 */
+#define IDE2_SECONDARY_BASE 0x0376 /* Miscellaneous AT registers for IDE #2 */
+
+#define SERIAL1_PRIMARY_BASE 0x03f8
+#define SERIAL2_PRIMARY_BASE 0x02f8
+
+#define MSB(x) ( (x) >> 8 )
+#define LSB(x) ( (x) & 0xff )
+
+ /* General-Purpose base address on CPU-board FPGA */
+#define MICRODEV_FPGA_GP_BASE 0xa6100000ul
+
+ /* assume a Keyboard Controller is present */
+int microdev_kbd_controller_present = 1;
+
+const char *get_system_type(void)
+{
+ return "SH4-202 MicroDev";
+}
+
+static struct resource smc91x_resources[] = {
+ [0] = {
+ .start = 0x300,
+ .end = 0x300 + 0x0001000 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = MICRODEV_LINUX_IRQ_ETHERNET,
+ .end = MICRODEV_LINUX_IRQ_ETHERNET,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+
+static int __init smc91x_setup(void)
+{
+ return platform_device_register(&smc91x_device);
+}
+
+__initcall(smc91x_setup);
+
+ /*
+ * Initialize the board
+ */
+void __init platform_setup(void)
+{
+ int * const fpgaRevisionRegister = (int*)(MICRODEV_FPGA_GP_BASE + 0x8ul);
+ const int fpgaRevision = *fpgaRevisionRegister;
+ int * const CacheControlRegister = (int*)CCR;
+
+ printk("SuperH %s board (FPGA rev: 0x%0x, CCR: 0x%0x)\n",
+ get_system_type(), fpgaRevision, *CacheControlRegister);
+}
+
+
+/****************************************************************************/
+
+
+ /*
+ * Setup for the SMSC FDC37C93xAPM
+ */
+static int __init smsc_superio_setup(void)
+{
+
+ unsigned char devid, devrev;
+
+ /* Initially the chip is in run state */
+ /* Put it into configuration state */
+ outb(SMSC_ENTER_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
+
+ /* Read device ID info */
+ devid = SMSC_READ_INDEXED(SMSC_DEVICE_ID_INDEX);
+ devrev = SMSC_READ_INDEXED(SMSC_DEVICE_REV_INDEX);
+ if ( (devid==0x30) && (devrev==0x01) )
+ {
+ printk("SMSC FDC37C93xAPM SuperIO device detected\n");
+ }
+ else
+ { /* not the device identity we expected */
+ printk("Not detected a SMSC FDC37C93xAPM SuperIO device (devid=0x%02x, rev=0x%02x)\n",
+ devid, devrev);
+ /* inform the keyboard driver that we have no keyboard controller */
+ microdev_kbd_controller_present = 0;
+ /* little point in doing anything else in this functon */
+ return 0;
+ }
+
+ /* Select the keyboard device */
+ SMSC_WRITE_INDEXED(SMSC_KEYBOARD_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+ /* enable it */
+ SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
+ /* enable the interrupts */
+ SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_KEYBOARD, SMSC_PRIMARY_INT_INDEX);
+ SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_MOUSE, SMSC_SECONDARY_INT_INDEX);
+
+ /* Select the Serial #1 device */
+ SMSC_WRITE_INDEXED(SMSC_SERIAL1_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+ /* enable it */
+ SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
+ /* program with port addresses */
+ SMSC_WRITE_INDEXED(MSB(SERIAL1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0);
+ SMSC_WRITE_INDEXED(LSB(SERIAL1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1);
+ SMSC_WRITE_INDEXED(0x00, SMSC_HDCS0_INDEX);
+ /* enable the interrupts */
+ SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_SERIAL1, SMSC_PRIMARY_INT_INDEX);
+
+ /* Select the Serial #2 device */
+ SMSC_WRITE_INDEXED(SMSC_SERIAL2_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+ /* enable it */
+ SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
+ /* program with port addresses */
+ SMSC_WRITE_INDEXED(MSB(SERIAL2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0);
+ SMSC_WRITE_INDEXED(LSB(SERIAL2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1);
+ SMSC_WRITE_INDEXED(0x00, SMSC_HDCS0_INDEX);
+ /* enable the interrupts */
+ SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_SERIAL2, SMSC_PRIMARY_INT_INDEX);
+
+ /* Select the IDE#1 device */
+ SMSC_WRITE_INDEXED(SMSC_IDE1_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+ /* enable it */
+ SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
+ /* program with port addresses */
+ SMSC_WRITE_INDEXED(MSB(IDE1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0);
+ SMSC_WRITE_INDEXED(LSB(IDE1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1);
+ SMSC_WRITE_INDEXED(MSB(IDE1_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+0);
+ SMSC_WRITE_INDEXED(LSB(IDE1_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+1);
+ SMSC_WRITE_INDEXED(0x0c, SMSC_HDCS0_INDEX);
+ SMSC_WRITE_INDEXED(0x00, SMSC_HDCS1_INDEX);
+ /* select the interrupt */
+ SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_IDE1, SMSC_PRIMARY_INT_INDEX);
+
+ /* Select the IDE#2 device */
+ SMSC_WRITE_INDEXED(SMSC_IDE2_DEVICE, SMCS_LOGICAL_DEV_INDEX);
+ /* enable it */
+ SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
+ /* program with port addresses */
+ SMSC_WRITE_INDEXED(MSB(IDE2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0);
+ SMSC_WRITE_INDEXED(LSB(IDE2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1);
+ SMSC_WRITE_INDEXED(MSB(IDE2_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+0);
+ SMSC_WRITE_INDEXED(LSB(IDE2_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+1);
+ /* select the interrupt */
+ SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_IDE2, SMSC_PRIMARY_INT_INDEX);
+
+ /* Select the configuration registers */
+ SMSC_WRITE_INDEXED(SMSC_CONFIG_REGISTERS, SMCS_LOGICAL_DEV_INDEX);
+ /* enable the appropriate GPIO pins for IDE functionality:
+ * bit[0] In/Out 1==input; 0==output
+ * bit[1] Polarity 1==invert; 0==no invert
+ * bit[2] Int Enb #1 1==Enable Combined IRQ #1; 0==disable
+ * bit[3:4] Function Select 00==original; 01==Alternate Function #1
+ */
+ SMSC_WRITE_INDEXED(0x00, 0xc2); /* GP42 = nIDE1_OE */
+ SMSC_WRITE_INDEXED(0x01, 0xc5); /* GP45 = IDE1_IRQ */
+ SMSC_WRITE_INDEXED(0x00, 0xc6); /* GP46 = nIOROP */
+ SMSC_WRITE_INDEXED(0x00, 0xc7); /* GP47 = nIOWOP */
+ SMSC_WRITE_INDEXED(0x08, 0xe8); /* GP20 = nIDE2_OE */
+
+ /* Exit the configuraton state */
+ outb(SMSC_EXIT_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
+
+ return 0;
+}
+
+
+/* This is grotty, but, because kernel is always referenced on the link line
+ * before any devices, this is safe.
+ */
+__initcall(smsc_superio_setup);
diff --git a/arch/sh/boards/unknown/Makefile b/arch/sh/boards/unknown/Makefile
new file mode 100644
index 000000000000..cffc21031e71
--- /dev/null
+++ b/arch/sh/boards/unknown/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for unknown SH boards
+#
+
+obj-y := mach.o io.o setup.o
+
diff --git a/arch/sh/boards/unknown/io.c b/arch/sh/boards/unknown/io.c
new file mode 100644
index 000000000000..8f3f17267bd9
--- /dev/null
+++ b/arch/sh/boards/unknown/io.c
@@ -0,0 +1,46 @@
+/*
+ * linux/arch/sh/kernel/io_unknown.c
+ *
+ * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * I/O routine for unknown hardware.
+ */
+
+static unsigned int unknown_handler(void)
+{
+ return 0;
+}
+
+#define UNKNOWN_ALIAS(fn) \
+ void unknown_##fn(void) __attribute__ ((alias ("unknown_handler")));
+
+UNKNOWN_ALIAS(inb)
+UNKNOWN_ALIAS(inw)
+UNKNOWN_ALIAS(inl)
+UNKNOWN_ALIAS(outb)
+UNKNOWN_ALIAS(outw)
+UNKNOWN_ALIAS(outl)
+UNKNOWN_ALIAS(inb_p)
+UNKNOWN_ALIAS(inw_p)
+UNKNOWN_ALIAS(inl_p)
+UNKNOWN_ALIAS(outb_p)
+UNKNOWN_ALIAS(outw_p)
+UNKNOWN_ALIAS(outl_p)
+UNKNOWN_ALIAS(insb)
+UNKNOWN_ALIAS(insw)
+UNKNOWN_ALIAS(insl)
+UNKNOWN_ALIAS(outsb)
+UNKNOWN_ALIAS(outsw)
+UNKNOWN_ALIAS(outsl)
+UNKNOWN_ALIAS(readb)
+UNKNOWN_ALIAS(readw)
+UNKNOWN_ALIAS(readl)
+UNKNOWN_ALIAS(writeb)
+UNKNOWN_ALIAS(writew)
+UNKNOWN_ALIAS(writel)
+UNKNOWN_ALIAS(isa_port2addr)
+UNKNOWN_ALIAS(ioremap)
+UNKNOWN_ALIAS(iounmap)
diff --git a/arch/sh/boards/unknown/mach.c b/arch/sh/boards/unknown/mach.c
new file mode 100644
index 000000000000..ad0bcc60a640
--- /dev/null
+++ b/arch/sh/boards/unknown/mach.c
@@ -0,0 +1,67 @@
+/*
+ * linux/arch/sh/kernel/mach_unknown.c
+ *
+ * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Machine specific code for an unknown machine (internal peripherials only)
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <asm/machvec.h>
+#include <asm/machvec_init.h>
+
+#include <asm/io_unknown.h>
+
+#include <asm/rtc.h>
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_unknown __initmv = {
+#if defined(CONFIG_CPU_SH4)
+ .mv_nr_irqs = 48,
+#elif defined(CONFIG_CPU_SUBTYPE_SH7708)
+ .mv_nr_irqs = 32,
+#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
+ .mv_nr_irqs = 61,
+#endif
+
+ .mv_inb = unknown_inb,
+ .mv_inw = unknown_inw,
+ .mv_inl = unknown_inl,
+ .mv_outb = unknown_outb,
+ .mv_outw = unknown_outw,
+ .mv_outl = unknown_outl,
+
+ .mv_inb_p = unknown_inb_p,
+ .mv_inw_p = unknown_inw_p,
+ .mv_inl_p = unknown_inl_p,
+ .mv_outb_p = unknown_outb_p,
+ .mv_outw_p = unknown_outw_p,
+ .mv_outl_p = unknown_outl_p,
+
+ .mv_insb = unknown_insb,
+ .mv_insw = unknown_insw,
+ .mv_insl = unknown_insl,
+ .mv_outsb = unknown_outsb,
+ .mv_outsw = unknown_outsw,
+ .mv_outsl = unknown_outsl,
+
+ .mv_readb = unknown_readb,
+ .mv_readw = unknown_readw,
+ .mv_readl = unknown_readl,
+ .mv_writeb = unknown_writeb,
+ .mv_writew = unknown_writew,
+ .mv_writel = unknown_writel,
+
+ .mv_ioremap = unknown_ioremap,
+ .mv_iounmap = unknown_iounmap,
+
+ .mv_isa_port2addr = unknown_isa_port2addr,
+};
+ALIAS_MV(unknown)
diff --git a/arch/sh/boards/unknown/setup.c b/arch/sh/boards/unknown/setup.c
new file mode 100644
index 000000000000..7d772a6f8865
--- /dev/null
+++ b/arch/sh/boards/unknown/setup.c
@@ -0,0 +1,23 @@
+/*
+ * linux/arch/sh/boards/unknown/setup.c
+ *
+ * Copyright (C) 2002 Paul Mundt
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * Setup code for an unknown machine (internal peripherials only)
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+const char *get_system_type(void)
+{
+ return "Unknown";
+}
+
+void __init platform_setup(void)
+{
+}
+