Update of /cvsroot/linux-vax/kernel-2.5/arch/vax/kernel In directory usw-pr-cvs1:/tmp/cvs-serv2801/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 entry.S interrupt.c interrupt.h process.c ptrace.c reboot.c regdump.c semaphore.c setup.c syscall.c time.c Added Files: clock.c Log Message: RTC clock driver for vaxstations, 2.5 branch. --- 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.5/arch/vax/kernel/Makefile,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- Makefile 24 Apr 2002 08:52:47 -0000 1.1.1.1 +++ Makefile 25 Apr 2002 09:43:48 -0000 1.2 @@ -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.5/arch/vax/kernel/cpu_ka410.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- cpu_ka410.c 24 Apr 2002 08:52:47 -0000 1.1.1.1 +++ cpu_ka410.c 25 Apr 2002 09:43:48 -0000 1.2 @@ -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.5/arch/vax/kernel/cpu_ka42.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- cpu_ka42.c 24 Apr 2002 08:52:47 -0000 1.1.1.1 +++ cpu_ka42.c 25 Apr 2002 09:43:48 -0000 1.2 @@ -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.5/arch/vax/kernel/cpu_ka43.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- cpu_ka43.c 24 Apr 2002 08:52:47 -0000 1.1.1.1 +++ cpu_ka43.c 25 Apr 2002 09:43:48 -0000 1.2 @@ -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.5/arch/vax/kernel/cpu_ka46.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- cpu_ka46.c 24 Apr 2002 08:52:47 -0000 1.1.1.1 +++ cpu_ka46.c 25 Apr 2002 09:43:48 -0000 1.2 @@ -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.5/arch/vax/kernel/cpu_ka55.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- cpu_ka55.c 24 Apr 2002 08:52:47 -0000 1.1.1.1 +++ cpu_ka55.c 25 Apr 2002 09:43:48 -0000 1.2 @@ -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.5/arch/vax/kernel/cpu_ka630.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- cpu_ka630.c 24 Apr 2002 08:52:47 -0000 1.1.1.1 +++ cpu_ka630.c 25 Apr 2002 09:43:48 -0000 1.2 @@ -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.5/arch/vax/kernel/cpu_ka640.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- cpu_ka640.c 24 Apr 2002 08:52:47 -0000 1.1.1.1 +++ cpu_ka640.c 25 Apr 2002 09:43:48 -0000 1.2 @@ -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.5/arch/vax/kernel/cpu_ka650.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- cpu_ka650.c 24 Apr 2002 08:52:47 -0000 1.1.1.1 +++ cpu_ka650.c 25 Apr 2002 09:43:48 -0000 1.2 @@ -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 */ }; Index: cpu_ka660.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/arch/vax/kernel/cpu_ka660.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- cpu_ka660.c 24 Apr 2002 08:52:47 -0000 1.1.1.1 +++ cpu_ka660.c 25 Apr 2002 09:43:48 -0000 1.2 @@ -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.5/arch/vax/kernel/cpu_vxt.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- cpu_vxt.c 24 Apr 2002 08:52:47 -0000 1.1.1.1 +++ cpu_vxt.c 25 Apr 2002 09:43:48 -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: entry.S =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/arch/vax/kernel/entry.S,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 Index: interrupt.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/arch/vax/kernel/interrupt.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 Index: interrupt.h =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/arch/vax/kernel/interrupt.h,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 Index: process.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/arch/vax/kernel/process.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 Index: ptrace.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/arch/vax/kernel/ptrace.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 Index: reboot.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/arch/vax/kernel/reboot.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 Index: regdump.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/arch/vax/kernel/regdump.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 Index: semaphore.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/arch/vax/kernel/semaphore.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 Index: setup.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/arch/vax/kernel/setup.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 Index: syscall.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/arch/vax/kernel/syscall.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 Index: time.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.5/arch/vax/kernel/time.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- time.c 24 Apr 2002 08:52:48 -0000 1.1.1.1 +++ time.c 25 Apr 2002 09:43:48 -0000 1.2 @@ -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); +} + |