|
From: Andy P. <at...@us...> - 2002-04-25 08:46:24
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel
In directory usw-pr-cvs1:/tmp/cvs-serv20812/arch/vax/kernel
Modified Files:
Makefile cpu_ka410.c cpu_ka42.c cpu_ka43.c cpu_ka46.c
cpu_ka55.c cpu_ka630.c cpu_ka640.c cpu_ka650.c cpu_ka660.c
cpu_vxt.c time.c
Added Files:
clock.c
Log Message:
Real time clock driver for vaxstations with dallas chip
--- NEW FILE ---
/* arch/vax/kernel/clock.c
*
* Copyright atp 2002. license; GPL
*
* routines to manipulate the real time clock on vaxes
*
* There are two sorts of battery backed hardware clock. There is the
* TODR (time of day register) found on big vaxes, and the familiar
* Dallas CMOS clock on the desktop vaxes
*
* The init routines are called through the machine vector. See
* cpu_kaxx.c for details of that. The callers are time_init() and
* the rtc clock driver (drivers/char/rtc.c), using macros defined
* in asm/mc146818rtc.h
*
* Prototypes for some of these functions are in asm/mc146818rtc.h
* and some in asm/clock.h. (The ones that are used in the mv
* initialisation are in clock.h, and the ones used in mc146818rtc.h
* are in that file)
*
*/
#include <linux/config.h>
#include <asm/io.h> /* For ioremap() */
#include <asm/mtpr.h>
#include <asm/mv.h>
#include <asm/clock.h> /* for TODR, if anyone feels like implementing it */
#include <asm/vsa.h>
#include <linux/mc146818rtc.h> /* includes asm/mc146818rtc.h */
/* - needed for offsets in debug output */
/* this does nothing, and is a placeholder */
void generic_clock_init(void)
{
return;
}
/* map the ROM clock page, and put address in mv */
void ka4x_clock_init(void)
{
mv->clock_base = ioremap(VSA_CLOCK_BASE,1); /* 1 page */
printk("Mapped RTC clock page (v %8lx p %8lx )\n",mv->clock_base,VSA_CLOCK_BASE);
printk("RTC date is %2.2d:%2.2d:%4.4d %2.2d:%2.2d:%2.2d\n",
CMOS_READ(RTC_DAY_OF_MONTH), CMOS_READ(RTC_MONTH), CMOS_READ(RTC_YEAR),
CMOS_READ(RTC_HOURS), CMOS_READ(RTC_MINUTES), CMOS_READ(RTC_SECONDS));
return;
}
unsigned char ka4x_clock_read(unsigned long offset)
{
if (mv->clock_base)
return ( mv->clock_base[offset] >> 2 );
return 0;
}
void ka4x_clock_write(unsigned char val, unsigned long offset)
{
if (mv->clock_base)
mv->clock_base[offset] = (val<<2);
return;
}
Index: Makefile
===================================================================
RCS file: /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel/Makefile,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- Makefile 15 Nov 2001 00:27:00 -0000 1.9
+++ Makefile 25 Apr 2002 08:46:20 -0000 1.10
@@ -18,7 +18,7 @@
init_task.o reboot.o cpu_generic.o \
cpu_ka630.o cpu_ka640.o cpu_ka650.o cpu_ka660.o \
cpu_ka410.o cpu_ka42.o cpu_ka43.o cpu_ka46.o cpu_ka55.o \
- cpu_vxt.o
+ cpu_vxt.o clock.o
OX_OBJS :=
MX_OBJS :=
Index: cpu_ka410.c
===================================================================
RCS file: /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel/cpu_ka410.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- cpu_ka410.c 26 Jun 2001 18:59:00 -0000 1.2
+++ cpu_ka410.c 25 Apr 2002 08:46:20 -0000 1.3
@@ -14,6 +14,8 @@
#include <asm/mtpr.h>
#include <asm/mv.h>
#include <asm/vaxcpu.h>
+#include <asm/clock.h> /* for clock_init routines */
+
void ka410_pre_vm_init(void);
void ka410_post_vm_init(void);
@@ -43,7 +45,9 @@
NULL, /* init_devices */
- ka410_cpu_type_str
+ ka410_cpu_type_str,
+ ka4x_clock_init, /* dallas rtc init */
+ NULL /* clock base */
}
};
Index: cpu_ka42.c
===================================================================
RCS file: /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel/cpu_ka42.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- cpu_ka42.c 31 Jul 2001 17:28:26 -0000 1.6
+++ cpu_ka42.c 25 Apr 2002 08:46:20 -0000 1.7
@@ -17,7 +17,8 @@
#include <asm/mv.h>
#include <asm/vaxcpu.h>
#include <asm/vsa.h>
-
+#include <asm/clock.h> /* for clock_init routines */
+
void ka42_init_devices(void);
void ka42_pre_vm_init(void);
void ka42_post_vm_init(void);
@@ -48,7 +49,9 @@
ka42_init_devices, /* init_devices */
- ka42_cpu_type_str
+ ka42_cpu_type_str,
+ ka4x_clock_init, /* dallas rtc init */
+ NULL /* clock base */
},
0 /* System ID Extension from ROM */
};
Index: cpu_ka43.c
===================================================================
RCS file: /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel/cpu_ka43.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- cpu_ka43.c 31 Jul 2001 17:28:26 -0000 1.7
+++ cpu_ka43.c 25 Apr 2002 08:46:20 -0000 1.8
@@ -26,6 +26,8 @@
#include <asm/mm/tlb.h>
#include <asm/ka43.h>
+#include <asm/clock.h> /* for clock_init routines */
+
void ka43_pre_vm_init(void);
void ka43_post_vm_init(void);
void ka43_cache_disable(volatile unsigned int *creg_addr);
@@ -72,7 +74,10 @@
ka43_init_devices,
- ka43_cpu_type_str
+ ka43_cpu_type_str,
+ ka4x_clock_init, /* dallas rtc init */
+ NULL /* clock base */
+
},
0 /* System ID Extension from ROM */
};
Index: cpu_ka46.c
===================================================================
RCS file: /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel/cpu_ka46.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- cpu_ka46.c 5 Mar 2002 22:40:47 -0000 1.10
+++ cpu_ka46.c 25 Apr 2002 08:46:20 -0000 1.11
@@ -19,6 +19,8 @@
#include <asm/vsa.h>
#include <asm/ka46.h>
+#include <asm/clock.h> /* for clock_init routines */
+
void ka46_pre_vm_init(void);
void ka46_post_vm_init(void);
void ka46_cache_disable(void);
@@ -53,8 +55,9 @@
NULL, /* mcheck - machine check */
ka46_init_devices, /* init_devices */
-
- ka46_cpu_type_str
+ ka46_cpu_type_str,
+ ka4x_clock_init, /* dallas rtc init */
+ NULL /* clock base */
},
0 /* System ID Extension from ROM */
};
Index: cpu_ka55.c
===================================================================
RCS file: /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel/cpu_ka55.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- cpu_ka55.c 4 Sep 2001 03:11:38 -0000 1.5
+++ cpu_ka55.c 25 Apr 2002 08:46:20 -0000 1.6
@@ -18,6 +18,8 @@
#include <asm/vaxcpu.h>
#include <asm/vsa.h>
+#include <asm/clock.h> /* for clock_init routines */
+
void ka55_pre_vm_init(void);
void ka55_post_vm_init(void);
void ka55_prom_putchar(int);
@@ -50,7 +52,9 @@
NULL, /* mcheck - machine check */
ka55_init_devices, /* init_devices */
- ka55_cpu_type_str
+ ka55_cpu_type_str,
+ generic_clock_init,
+ NULL,
},
0 /* System ID Extension from ROM */
};
Index: cpu_ka630.c
===================================================================
RCS file: /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel/cpu_ka630.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- cpu_ka630.c 26 Jun 2001 18:59:00 -0000 1.2
+++ cpu_ka630.c 25 Apr 2002 08:46:20 -0000 1.3
@@ -15,7 +15,8 @@
#include <asm/mv.h>
#include <asm/simple_io.h>
#include <asm/vaxcpu.h>
-
+#include <asm/clock.h> /* for clock_init routines */
+
void ka630_pre_vm_init(void);
void ka630_post_vm_init(void);
const char *ka630_cpu_type_str(void);
@@ -43,7 +44,9 @@
NULL, /* init_devices */
- ka630_cpu_type_str
+ ka630_cpu_type_str,
+ generic_clock_init,
+ NULL
}
};
Index: cpu_ka640.c
===================================================================
RCS file: /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel/cpu_ka640.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- cpu_ka640.c 26 Jun 2001 18:59:00 -0000 1.2
+++ cpu_ka640.c 25 Apr 2002 08:46:20 -0000 1.3
@@ -15,6 +15,7 @@
#include <asm/mv.h>
#include <asm/simple_io.h>
#include <asm/vaxcpu.h>
+#include <asm/clock.h> /* for clock_init routines */
void ka640_pre_vm_init(void);
void ka640_post_vm_init(void);
@@ -44,7 +45,10 @@
NULL, /* init_devices */
- ka640_cpu_type_str
+ ka640_cpu_type_str,
+ generic_clock_init,
+ NULL
+
},
0 /* System ID Extension from ROM */
};
Index: cpu_ka650.c
===================================================================
RCS file: /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel/cpu_ka650.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- cpu_ka650.c 20 Apr 2002 12:28:40 -0000 1.3
+++ cpu_ka650.c 25 Apr 2002 08:46:20 -0000 1.4
@@ -15,7 +15,8 @@
#include <asm/mv.h>
#include <asm/simple_io.h>
#include <asm/vaxcpu.h>
-
+#include <asm/clock.h> /* for clock_init routines */
+
void ka650_pre_vm_init(void);
void ka650_post_vm_init(void);
const char *ka650_cpu_type_str(void);
@@ -44,7 +45,9 @@
NULL, /* init_devices */
- ka650_cpu_type_str
+ ka650_cpu_type_str,
+ generic_clock_init,
+ NULL
},
0 /* System ID Extension from ROM */
};
@@ -99,6 +102,6 @@
const char *ka650_cpu_type_str(void)
{
- return "KA650/5";
+ return "KA650";
}
Index: cpu_ka660.c
===================================================================
RCS file: /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel/cpu_ka660.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- cpu_ka660.c 26 Jun 2001 18:59:00 -0000 1.2
+++ cpu_ka660.c 25 Apr 2002 08:46:20 -0000 1.3
@@ -17,7 +17,8 @@
#include <asm/mv.h>
#include <asm/simple_io.h>
#include <asm/vaxcpu.h>
-
+#include <asm/clock.h> /* for clock_init routines */
+
void ka660_pre_vm_init(void);
void ka660_post_vm_init(void);
const char *ka660_cpu_type_str(void);
@@ -48,7 +49,9 @@
NULL, /* init_devices */
- ka660_cpu_type_str
+ ka660_cpu_type_str,
+ generic_clock_init,
+ NULL
}
};
Index: cpu_vxt.c
===================================================================
RCS file: /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel/cpu_vxt.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- cpu_vxt.c 15 Nov 2001 00:27:00 -0000 1.1
+++ cpu_vxt.c 25 Apr 2002 08:46:20 -0000 1.2
@@ -12,6 +12,7 @@
#include <asm/mv.h>
#include <asm/simple_io.h>
#include <asm/vaxcpu.h>
+#include <asm/clock.h> /* for clock_init routines */
void vxt_pre_vm_init(void);
void vxt_post_vm_init(void);
@@ -43,7 +44,9 @@
NULL, /* init_devices */
- vxt_cpu_type_str
+ vxt_cpu_type_str,
+ generic_clock_init,
+ NULL
}
};
Index: time.c
===================================================================
RCS file: /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel/time.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- time.c 26 Jan 2001 00:27:00 -0000 1.2
+++ time.c 25 Apr 2002 08:46:20 -0000 1.3
@@ -8,6 +8,9 @@
* 22-oct-2000: Erik Mouw
* Added some simple do_gettimeofday() and do_settimeofday()
* functions. Not tested due to lack of disk space.
+ *
+ * 24 Apr 2002: atp. Finally got round to doing this properly.
+ * We now use the CMOS clock.
*
*/
@@ -18,17 +21,35 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
+#include <linux/time.h>
#include <asm/irq.h>
#include <asm/mtpr.h>
#include <asm/clock.h>
+#include <linux/mc146818rtc.h>
+spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+extern rwlock_t xtime_lock;
+/* last time the cmos clock got updated */
+static long last_rtc_update;
+
+/* protos */
+static int set_rtc_mmss(unsigned long nowtime);
static void do_timer_interrupt(int vec_num, void *dev_id, struct pt_regs *regs);
+static unsigned long do_gettimeoffset(void);
+void time_init(void);
+void do_gettimeofday(struct timeval *tv);
+void do_settimeofday(struct timeval *tv);
+unsigned long get_cmos_time(void);
void __init time_init(void)
{
- xtime.tv_usec = 0;
- xtime.tv_sec = 0;
+ /* initialise the hardware clock */
+ mv->clock_init();
+
+ /* read cmos time */
+ xtime.tv_usec = 0;
+ xtime.tv_sec = get_cmos_time();
if (request_irq(0x30, do_timer_interrupt, 0, "timer", NULL)) {
printk("Panic: unable to register timer interrupt handler\n");
@@ -42,13 +63,91 @@
PR_ICCS);
}
-/* This is the interrupt service routine for the timer interrupt */
+/*
+ * 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;
+}
+
+
+/* This is the interrupt service routine for the timer interrupt */
static void do_timer_interrupt(int vec_num, void *dev_id, struct pt_regs *regs)
{
unsigned int iccs;
- iccs = __mfpr(PR_ICCS);
+ /*
+ * Here we are in the timer irq handler. We just have irqs locally
+ * disabled but we don't know if the timer_bh is running on the other
+ * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
+ * the irq version of write_lock because as just said we have irq
+ * locally disabled. -arca
+ */
+ write_lock(&xtime_lock);
+
+ iccs = __mfpr(PR_ICCS);
if (iccs & ICCS_ERROR) {
printk("Clock overrun\n");
@@ -56,6 +155,21 @@
do_timer(regs);
+ /*
+ * If we have an externally synchronized Linux clock, then update
+ * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+ * called as close as possible to 500 ms before the new second starts.
+ */
+ if ((time_status & STA_UNSYNC) == 0 &&
+ xtime.tv_sec > last_rtc_update + 660 &&
+ xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 &&
+ xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) {
+ if (set_rtc_mmss(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+ else
+ last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+ }
+
/* The ARM says we should do this in the clock ISR. It isn't
actually required on the KA650, as the ICCS register is
not fully implemented. But I don't know about the other
@@ -66,13 +180,11 @@
ICCS_TRANSFER | /* Reload ICR from NICR */
ICCS_RUN, /* ... and go again */
PR_ICCS);
-
+
+ write_unlock(&xtime_lock);
+
}
-
-
-
-
/*
* Function to compensate the time offset caused by calling this
* function (I think so, yes). This function definatively needs a real
@@ -84,9 +196,6 @@
return 0;
}
-
-
-
/*
* do_gettimeofday() and do_settimeofday()
*
@@ -112,9 +221,6 @@
}
}
-
-
-
void do_settimeofday(struct timeval *tv)
{
unsigned long flags;
@@ -142,3 +248,46 @@
restore_flags(flags);
}
+
+/* nicked from the i386 port, but we use the same chip, hee hee */
+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);
+}
+
|