sh: Add support for SH7206 and SH7619 CPU subtypes.

This implements initial support for the SH7206 (SH-2A) and SH7619
(SH-2) MMU-less CPUs.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
diff --git a/arch/sh/kernel/timers/timer-mtu2.c b/arch/sh/kernel/timers/timer-mtu2.c
new file mode 100644
index 0000000..73a5ef3
--- /dev/null
+++ b/arch/sh/kernel/timers/timer-mtu2.c
@@ -0,0 +1,260 @@
+/*
+ * arch/sh/kernel/timers/timer-mtu2.c - MTU2 Timer Support
+ *
+ *  Copyright (C) 2005  Paul Mundt
+ *
+ * Based off of arch/sh/kernel/timers/timer-tmu.c
+ *
+ * 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 <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/seqlock.h>
+#include <asm/timer.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/clock.h>
+
+/*
+ * We use channel 1 for our lowly system timer. Channel 2 would be the other
+ * likely candidate, but we leave it alone as it has higher divisors that
+ * would be of more use to other more interesting applications.
+ *
+ * TODO: Presently we only implement a 16-bit single-channel system timer.
+ * However, we can implement channel cascade if we go the overflow route and
+ * get away with using 2 MTU2 channels as a 32-bit timer.
+ */
+
+static DEFINE_SPINLOCK(mtu2_lock);
+
+#define MTU2_TSTR	0xfffe4280
+#define MTU2_TCR_1	0xfffe4380
+#define MTU2_TMDR_1	0xfffe4381
+#define MTU2_TIOR_1	0xfffe4382
+#define MTU2_TIER_1	0xfffe4384
+#define MTU2_TSR_1	0xfffe4385
+#define MTU2_TCNT_1	0xfffe4386	/* 16-bit counter */
+#define MTU2_TGRA_1	0xfffe438a
+
+#define STBCR3		0xfffe0408
+
+#define MTU2_TSTR_CST1	(1 << 1)	/* Counter Start 1 */
+
+#define MTU2_TSR_TGFA	(1 << 0)	/* GRA compare match */
+
+#define MTU2_TIER_TGIEA	(1 << 0)	/* GRA compare match  interrupt enable */
+
+#define MTU2_TCR_INIT	0x22
+
+#define MTU2_TCR_CALIB  0x00
+
+static unsigned long mtu2_timer_get_offset(void)
+{
+	int count;
+	unsigned long flags;
+
+	static int count_p = 0x7fff;	/* for the first call after boot */
+	static unsigned long jiffies_p = 0;
+
+	/*
+	 * cache volatile jiffies temporarily; we have IRQs turned off.
+	 */
+	unsigned long jiffies_t;
+
+	spin_lock_irqsave(&mtu2_lock, flags);
+	/* timer count may underflow right here */
+	count = ctrl_inw(MTU2_TCNT_1);	/* read the latched count */
+
+	jiffies_t = jiffies;
+
+	/*
+	 * avoiding timer inconsistencies (they are rare, but they happen)...
+	 * there is one kind of problem that must be avoided here:
+	 *  1. the timer counter underflows
+	 */
+
+	if (jiffies_t == jiffies_p) {
+		if (count > count_p) {
+			if (ctrl_inb(MTU2_TSR_1) & MTU2_TSR_TGFA) {
+				count -= LATCH;
+			} else {
+				printk("%s (): hardware timer problem?\n",
+				       __FUNCTION__);
+			}
+		}
+	} else
+		jiffies_p = jiffies_t;
+
+	count_p = count;
+	spin_unlock_irqrestore(&mtu2_lock, flags);
+
+	count = ((LATCH-1) - count) * TICK_SIZE;
+	count = (count + LATCH/2) / LATCH;
+
+	return count;
+}
+
+static irqreturn_t mtu2_timer_interrupt(int irq, void *dev_id,
+				       struct pt_regs *regs)
+{
+	unsigned long timer_status;
+
+	/* Clear TGFA bit */
+	timer_status = ctrl_inb(MTU2_TSR_1);
+	timer_status &= ~MTU2_TSR_TGFA;
+	ctrl_outb(timer_status, MTU2_TSR_1);
+
+	/* Do timer tick */
+	write_seqlock(&xtime_lock);
+	handle_timer_tick(regs);
+	write_sequnlock(&xtime_lock);
+
+	return IRQ_HANDLED;
+}
+
+static struct irqaction mtu2_irq = {
+	.name		= "timer",
+	.handler	= mtu2_timer_interrupt,
+	.flags		= SA_INTERRUPT,
+	.mask		= CPU_MASK_NONE,
+};
+
+/*
+ * Hah!  We'll see if this works (switching from usecs to nsecs).
+ */
+static unsigned long mtu2_timer_get_frequency(void)
+{
+	u32 freq;
+	struct timespec ts1, ts2;
+	unsigned long diff_nsec;
+	unsigned long factor;
+
+	/* Setup the timer:  We don't want to generate interrupts, just
+	 * have it count down at its natural rate.
+	 */
+	
+	ctrl_outb(ctrl_inb(MTU2_TSTR) & ~MTU2_TSTR_CST1, MTU2_TSTR);
+	ctrl_outb(MTU2_TCR_CALIB, MTU2_TCR_1);
+	ctrl_outb(ctrl_inb(MTU2_TIER_1) & ~MTU2_TIER_TGIEA, MTU2_TIER_1);
+	ctrl_outw(0, MTU2_TCNT_1);
+
+	rtc_get_time(&ts2);
+
+	do {
+		rtc_get_time(&ts1);
+	} while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec);
+
+	/* actually start the timer */
+	ctrl_outw(ctrl_inw(CMT_CMSTR) | 0x01, CMT_CMSTR);
+
+	do {
+		rtc_get_time(&ts2);
+	} while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec);
+
+	freq = ctrl_inw(MTU2_TCNT_0);
+	if (ts2.tv_nsec < ts1.tv_nsec) {
+		ts2.tv_nsec += 1000000000;
+		ts2.tv_sec--;
+	}
+
+	diff_nsec = (ts2.tv_sec - ts1.tv_sec) * 1000000000 + (ts2.tv_nsec - ts1.tv_nsec);
+
+	/* this should work well if the RTC has a precision of n Hz, where
+	 * n is an integer.  I don't think we have to worry about the other
+	 * cases. */
+	factor = (1000000000 + diff_nsec/2) / diff_nsec;
+
+	if (factor * diff_nsec > 1100000000 ||
+	    factor * diff_nsec <  900000000)
+		panic("weird RTC (diff_nsec %ld)", diff_nsec);
+
+	return freq * factor;
+}
+
+static unsigned int divisors[] = { 1, 4, 16, 64, 1, 1, 256 };
+
+static void mtu2_clk_init(struct clk *clk)
+{
+	u8 idx = MTU2_TCR_INIT & 0x7;
+
+	clk->rate = clk->parent->rate / divisors[idx];
+	/* Start TCNT counting */
+	ctrl_outb(ctrl_inb(MTU2_TSTR) | MTU2_TSTR_CST1, MTU2_TSTR);
+
+}
+
+static void mtu2_clk_recalc(struct clk *clk)
+{
+	u8 idx = ctrl_inb(MTU2_TCR_1) & 0x7;
+	clk->rate = clk->parent->rate / divisors[idx];
+}
+
+static struct clk_ops mtu2_clk_ops = {
+	.init		= mtu2_clk_init,
+	.recalc		= mtu2_clk_recalc,
+};
+
+static struct clk mtu2_clk1 = {
+	.name		= "mtu2_clk1",
+	.ops		= &mtu2_clk_ops,
+};
+
+static int mtu2_timer_start(void)
+{
+	ctrl_outb(ctrl_inb(MTU2_TSTR) | MTU2_TSTR_CST1, MTU2_TSTR);
+	return 0;
+}
+
+static int mtu2_timer_stop(void)
+{
+	ctrl_outb(ctrl_inb(MTU2_TSTR) & ~MTU2_TSTR_CST1, MTU2_TSTR);
+	return 0;
+}
+
+static int mtu2_timer_init(void)
+{
+	u8 tmp;
+	unsigned long interval;
+
+	setup_irq(TIMER_IRQ, &mtu2_irq);
+
+	mtu2_clk1.parent = clk_get("module_clk");
+
+	ctrl_outb(ctrl_inb(STBCR3) & (~0x20), STBCR3);
+
+	/* Normal operation */
+	ctrl_outb(0, MTU2_TMDR_1);
+	ctrl_outb(MTU2_TCR_INIT, MTU2_TCR_1);
+	ctrl_outb(0x01, MTU2_TIOR_1);
+
+	/* Enable underflow interrupt */
+	ctrl_outb(ctrl_inb(MTU2_TIER_1) | MTU2_TIER_TGIEA, MTU2_TIER_1);
+
+	interval = CONFIG_SH_PCLK_FREQ / 16 / HZ;
+	printk(KERN_INFO "Interval = %ld\n", interval);
+
+	ctrl_outw(interval, MTU2_TGRA_1);
+	ctrl_outw(0, MTU2_TCNT_1);
+
+	clk_register(&mtu2_clk1);
+	clk_enable(&mtu2_clk1);
+
+	return 0;
+}
+
+struct sys_timer_ops mtu2_timer_ops = {
+	.init		= mtu2_timer_init,
+	.start		= mtu2_timer_start,
+	.stop		= mtu2_timer_stop,
+	.get_frequency	= mtu2_timer_get_frequency,
+	.get_offset	= mtu2_timer_get_offset,
+};
+
+struct sys_timer mtu2_timer = {
+	.name	= "mtu2",
+	.ops	= &mtu2_timer_ops,
+};