patch-2.3.23 linux/arch/sh/kernel/time.c
Next file: linux/arch/sh/kernel/traps.c
Previous file: linux/arch/sh/kernel/test-img.c
Back to the patch index
Back to the overall index
- Lines: 268
- Date:
Mon Oct 18 11:16:13 1999
- Orig file:
v2.3.22/linux/arch/sh/kernel/time.c
- Orig date:
Tue Sep 7 12:14:06 1999
diff -u --recursive --new-file v2.3.22/linux/arch/sh/kernel/time.c linux/arch/sh/kernel/time.c
@@ -1,12 +1,15 @@
-/*
+/* $Id: time.c,v 1.2 1999/10/11 13:12:02 gniibe Exp $
+ *
* linux/arch/sh/kernel/time.c
*
- * Copyright (C) 1999 Niibe Yutaka
+ * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
*
* Some code taken from i386 version.
* Copyright (C) 1991, 1992, 1995 Linus Torvalds
*/
+#include <linux/config.h>
+
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -28,6 +31,11 @@
#include <linux/timex.h>
#include <linux/irq.h>
+#define TMU_TOCR_INIT 0x00
+#define TMU0_TCR_INIT 0x0020
+#define TMU_TSTR_INIT 1
+
+#if defined(__sh3__)
#define TMU_TOCR 0xfffffe90 /* Byte access */
#define TMU_TSTR 0xfffffe92 /* Byte access */
@@ -35,13 +43,63 @@
#define TMU0_TCNT 0xfffffe98 /* Long access */
#define TMU0_TCR 0xfffffe9c /* Word access */
-#define TMU_TOCR_INIT 0x00
-#define TMU0_TCR_INIT 0x0020
-#define TMU_TSTR_INIT 1
-
-#define CLOCK_MHZ (60/4)
#define INTERVAL 37500 /* (1000000*CLOCK_MHZ/HZ/2) ??? */
+/* SH-3 RTC */
+#define R64CNT 0xfffffec0
+#define RSECCNT 0xfffffec2
+#define RMINCNT 0xfffffec4
+#define RHRCNT 0xfffffec6
+#define RWKCNT 0xfffffec8
+#define RDAYCNT 0xfffffeca
+#define RMONCNT 0xfffffecc
+#define RYRCNT 0xfffffece
+#define RSECAR 0xfffffed0
+#define RMINAR 0xfffffed2
+#define RHRAR 0xfffffed4
+#define RWKAR 0xfffffed6
+#define RDAYAR 0xfffffed8
+#define RMONAR 0xfffffeda
+#define RCR1 0xfffffedc
+#define RCR2 0xfffffede
+
+#elif defined(__SH4__)
+#define TMU_TOCR 0xffd80000 /* Byte access */
+#define TMU_TSTR 0xffd80004 /* Byte access */
+
+#define TMU0_TCOR 0xffd80008 /* Long access */
+#define TMU0_TCNT 0xffd8000c /* Long access */
+#define TMU0_TCR 0xffd80010 /* Word access */
+
+#define INTERVAL 83333
+
+/* SH-4 RTC */
+#define R64CNT 0xffc80000
+#define RSECCNT 0xffc80004
+#define RMINCNT 0xffc80008
+#define RHRCNT 0xffc8000c
+#define RWKCNT 0xffc80010
+#define RDAYCNT 0xffc80014
+#define RMONCNT 0xffc80018
+#define RYRCNT 0xffc8001c /* 16bit */
+#define RSECAR 0xffc80020
+#define RMINAR 0xffc80024
+#define RHRAR 0xffc80028
+#define RWKAR 0xffc8002c
+#define RDAYAR 0xffc80030
+#define RMONAR 0xffc80034
+#define RCR1 0xffc80038
+#define RCR2 0xffc8003c
+#endif
+
+#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 rwlock_t xtime_lock;
#define TICK_SIZE tick
@@ -82,14 +140,48 @@
write_unlock_irq(&xtime_lock);
}
-/*
- */
static int set_rtc_time(unsigned long nowtime)
{
-/* XXX should be implemented XXXXXXXXXX */
- int retval = -1;
+#ifdef CONFIG_SH_CPU_RTC
+ int retval = 0;
+ int real_seconds, real_minutes, cmos_minutes;
+
+ ctrl_outb(2, RCR2); /* reset pre-scaler & stop RTC */
+
+ cmos_minutes = ctrl_inb(RMINCNT);
+ 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) {
+ BIN_TO_BCD(real_seconds);
+ BIN_TO_BCD(real_minutes);
+ ctrl_outb(real_seconds, RSECCNT);
+ ctrl_outb(real_minutes, RMINCNT);
+ } else {
+ printk(KERN_WARNING
+ "set_rtc_time: can't update from %d to %d\n",
+ cmos_minutes, real_minutes);
+ retval = -1;
+ }
+
+ ctrl_outb(2, RCR2); /* start RTC */
return retval;
+#else
+ /* XXX should support other clock devices? */
+ return -1;
+#endif
}
/* last time the RTC clock got updated */
@@ -131,14 +223,12 @@
*/
static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- unsigned long __dummy;
+ unsigned long timer_status;
/* Clear UNF bit */
- asm volatile("mov.w %1,%0\n\t"
- "and %2,%0\n\t"
- "mov.w %0,%1"
- : "=&z" (__dummy)
- : "m" (__m(TMU0_TCR)), "r" (~0x100));
+ timer_status = ctrl_inw(TMU0_TCR);
+ timer_status &= ~0x100;
+ ctrl_outw(timer_status, TMU0_TCR);
/*
* Here we are in the timer irq handler. We just have irqs locally
@@ -187,16 +277,67 @@
static unsigned long get_rtc_time(void)
{
-/* XXX not implemented yet */
+#ifdef CONFIG_SH_CPU_RTC
+ unsigned int sec, min, hr, wk, day, mon, yr, yr100;
+
+ again:
+ ctrl_outb(1, RCR1); /* clear CF bit */
+ do {
+ sec = ctrl_inb(RSECCNT);
+ min = ctrl_inb(RMINCNT);
+ hr = ctrl_inb(RHRCNT);
+ wk = ctrl_inb(RWKCNT);
+ day = ctrl_inb(RDAYCNT);
+ mon = ctrl_inb(RMONCNT);
+#if defined(__SH4__)
+ yr = ctrl_inw(RYRCNT);
+ yr100 = (yr >> 8);
+ yr &= 0xff;
+#else
+ yr = ctrl_inb(RYRCNT);
+ yr100 = (yr == 0x99) ? 0x19 : 0x20;
+#endif
+ } while ((ctrl_inb(RCR1) & 0x80) != 0);
+
+ BCD_TO_BIN(yr100);
+ BCD_TO_BIN(yr);
+ BCD_TO_BIN(mon);
+ BCD_TO_BIN(day);
+ BCD_TO_BIN(hr);
+ BCD_TO_BIN(min);
+ BCD_TO_BIN(sec);
+
+ if (yr > 99 || mon < 1 || mon > 12 || day > 31 || day < 1 ||
+ hr > 23 || min > 59 || sec > 59) {
+ printk(KERN_ERR
+ "SH RTC: invalid value, resetting to 1 Jan 2000\n");
+ ctrl_outb(2, RCR2); /* reset, stop */
+ ctrl_outb(0, RSECCNT);
+ ctrl_outb(0, RMINCNT);
+ ctrl_outb(0, RHRCNT);
+ ctrl_outb(6, RWKCNT);
+ ctrl_outb(1, RDAYCNT);
+ ctrl_outb(1, RMONCNT);
+#if defined(__SH4__)
+ ctrl_outw(0x2000, RYRCNT);
+#else
+ ctrl_outb(0, RYRCNT);
+#endif
+ ctrl_outb(1, RCR2); /* start */
+ goto again;
+ }
+
+ return mktime(yr100 * 100 + yr, mon, day, hr, min, sec);
+#else
+ /* XXX should support other clock devices? */
return 0;
+#endif
}
static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};
void __init time_init(void)
{
- unsigned long __dummy;
-
xtime.tv_sec = get_rtc_time();
xtime.tv_usec = 0;
@@ -204,19 +345,12 @@
setup_irq(TIMER_IRQ, &irq0);
/* Start TMU0 */
- asm volatile("mov %1,%0\n\t"
- "mov.b %0,%2 ! external clock input\n\t"
- "mov %3,%0\n\t"
- "mov.w %0,%4 ! enable timer0 interrupt\n\t"
- "mov.l %5,%6\n\t"
- "mov.l %5,%7\n\t"
- "mov %8,%0\n\t"
- "mov.b %0,%9"
- : "=&z" (__dummy)
- : "i" (TMU_TOCR_INIT), "m" (__m(TMU_TOCR)),
- "i" (TMU0_TCR_INIT), "m" (__m(TMU0_TCR)),
- "r" (INTERVAL), "m" (__m(TMU0_TCOR)), "m" (__m(TMU0_TCNT)),
- "i" (TMU_TSTR_INIT), "m" (__m(TMU_TSTR)));
+ ctrl_outb(TMU_TOCR_INIT,TMU_TOCR);
+ ctrl_outw(TMU0_TCR_INIT,TMU0_TCR);
+ ctrl_outl(INTERVAL,TMU0_TCOR);
+ ctrl_outl(INTERVAL,TMU0_TCNT);
+ ctrl_outb(TMU_TSTR_INIT,TMU_TSTR);
+
#if 0
/* Start RTC */
asm volatile("");
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)