patch-2.4.3 linux/arch/sparc64/kernel/time.c
Next file: linux/arch/sparc64/kernel/trampoline.S
Previous file: linux/arch/sparc64/kernel/sys_sunos32.c
Back to the patch index
Back to the overall index
- Lines: 463
- Date:
Sun Mar 25 18:14:21 2001
- Orig file:
v2.4.2/linux/arch/sparc64/kernel/time.c
- Orig date:
Sat Feb 3 19:51:25 2001
diff -u --recursive --new-file v2.4.2/linux/arch/sparc64/kernel/time.c linux/arch/sparc64/kernel/time.c
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.33 2001/01/11 15:07:09 davem Exp $
+/* $Id: time.c,v 1.36 2001/03/15 08:51:24 anton Exp $
* time.c: UltraSparc timer and TOD clock support.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -20,6 +20,8 @@
#include <linux/timex.h>
#include <linux/init.h>
#include <linux/ioport.h>
+#include <linux/mc146818rtc.h>
+#include <linux/delay.h>
#include <asm/oplib.h>
#include <asm/mostek.h>
@@ -35,7 +37,11 @@
extern rwlock_t xtime_lock;
spinlock_t mostek_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
unsigned long mstk48t02_regs = 0UL;
+#ifdef CONFIG_PCI
+unsigned long ds1287_regs = 0UL;
+#endif
static unsigned long mstk48t08_regs = 0UL;
static unsigned long mstk48t59_regs = 0UL;
@@ -77,6 +83,7 @@
extern int rwlock_impl_begin, rwlock_impl_end;
extern int atomic_impl_begin, atomic_impl_end;
extern int __memcpy_begin, __memcpy_end;
+ extern int __bzero_begin, __bzero_end;
extern int __bitops_begin, __bitops_end;
if ((pc >= (unsigned long) &atomic_impl_begin &&
@@ -85,6 +92,8 @@
pc < (unsigned long) &rwlock_impl_end) ||
(pc >= (unsigned long) &__memcpy_begin &&
pc < (unsigned long) &__memcpy_end) ||
+ (pc >= (unsigned long) &__bzero_begin &&
+ pc < (unsigned long) &__bzero_end) ||
(pc >= (unsigned long) &__bitops_begin &&
pc < (unsigned long) &__bitops_end))
pc = o7;
@@ -135,6 +144,7 @@
* that %tick is not prone to this bug, but I am not
* taking any chances.
*/
+ if (!SPARC64_USE_STICK) {
__asm__ __volatile__("
rd %%tick_cmpr, %0
ba,pt %%xcc, 1f
@@ -146,6 +156,15 @@
mov %1, %1"
: "=&r" (timer_tick_compare), "=r" (ticks)
: "r" (timer_tick_offset));
+ } else {
+ __asm__ __volatile__("
+ rd %%asr25, %0
+ add %0, %2, %0
+ wr %0, 0, %%asr25
+ rd %%asr24, %1"
+ : "=&r" (timer_tick_compare), "=r" (ticks)
+ : "r" (timer_tick_offset));
+ }
/* Restore PSTATE_IE. */
__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
@@ -168,11 +187,19 @@
/*
* Only keep timer_tick_offset uptodate, but don't set TICK_CMPR.
*/
+ if (!SPARC64_USE_STICK) {
__asm__ __volatile__("
rd %%tick_cmpr, %0
add %0, %1, %0"
: "=&r" (timer_tick_compare)
: "r" (timer_tick_offset));
+ } else {
+ __asm__ __volatile__("
+ rd %%asr25, %0
+ add %0, %1, %0"
+ : "=&r" (timer_tick_compare)
+ : "r" (timer_tick_offset));
+ }
timer_check_rtc();
@@ -282,41 +309,95 @@
return (data1 == data2); /* Was the write blocked? */
}
+#ifndef BCD_TO_BIN
+#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
+#endif
+
+#ifndef BIN_TO_BCD
+#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10)
+#endif
/* Probe for the real time clock chip. */
static void __init set_system_time(void)
{
unsigned int year, mon, day, hour, min, sec;
unsigned long mregs = mstk48t02_regs;
+#ifdef CONFIG_PCI
+ unsigned long dregs = ds1287_regs;
+#else
+ unsigned long dregs = 0UL;
+#endif
u8 tmp;
do_get_fast_time = do_gettimeofday;
- if(!mregs) {
+ if (!mregs && !dregs) {
prom_printf("Something wrong, clock regs not mapped yet.\n");
prom_halt();
}
- spin_lock_irq(&mostek_lock);
+ if (mregs) {
+ spin_lock_irq(&mostek_lock);
+
+ /* Traditional Mostek chip. */
+ tmp = mostek_read(mregs + MOSTEK_CREG);
+ tmp |= MSTK_CREG_READ;
+ mostek_write(mregs + MOSTEK_CREG, tmp);
+
+ sec = MSTK_REG_SEC(mregs);
+ min = MSTK_REG_MIN(mregs);
+ hour = MSTK_REG_HOUR(mregs);
+ day = MSTK_REG_DOM(mregs);
+ mon = MSTK_REG_MONTH(mregs);
+ year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
+ } else {
+ int i;
+
+ /* Dallas 12887 RTC chip. */
+
+ /* Stolen from arch/i386/kernel/time.c, see there for
+ * credits and descriptive comments.
+ */
+ for (i = 0; i < 1000000; i++) {
+ if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
+ break;
+ udelay(10);
+ }
+ for (i = 0; i < 1000000; i++) {
+ if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
+ break;
+ udelay(10);
+ }
+ do {
+ 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);
+ }
+ if ((year += 1900) < 1970)
+ year += 100;
+ }
- tmp = mostek_read(mregs + MOSTEK_CREG);
- tmp |= MSTK_CREG_READ;
- mostek_write(mregs + MOSTEK_CREG, tmp);
-
- sec = MSTK_REG_SEC(mregs);
- min = MSTK_REG_MIN(mregs);
- hour = MSTK_REG_HOUR(mregs);
- day = MSTK_REG_DOM(mregs);
- mon = MSTK_REG_MONTH(mregs);
- year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
xtime.tv_usec = 0;
- tmp = mostek_read(mregs + MOSTEK_CREG);
- tmp &= ~MSTK_CREG_READ;
- mostek_write(mregs + MOSTEK_CREG, tmp);
+ if (mregs) {
+ tmp = mostek_read(mregs + MOSTEK_CREG);
+ tmp &= ~MSTK_CREG_READ;
+ mostek_write(mregs + MOSTEK_CREG, tmp);
- spin_unlock_irq(&mostek_lock);
+ spin_unlock_irq(&mostek_lock);
+ }
}
void __init clock_probe(void)
@@ -358,21 +439,22 @@
busnd = sbus_root->prom_node;
}
- if(busnd == -1) {
+ if (busnd == -1) {
prom_printf("clock_probe: problem, cannot find bus to search.\n");
prom_halt();
}
node = prom_getchild(busnd);
- while(1) {
+ while (1) {
if (!node)
model[0] = 0;
else
prom_getstring(node, "model", model, sizeof(model));
- if(strcmp(model, "mk48t02") &&
- strcmp(model, "mk48t08") &&
- strcmp(model, "mk48t59")) {
+ if (strcmp(model, "mk48t02") &&
+ strcmp(model, "mk48t08") &&
+ strcmp(model, "mk48t59") &&
+ strcmp(model, "ds1287")) {
if (node)
node = prom_getsibling(node);
#ifdef CONFIG_PCI
@@ -384,7 +466,7 @@
}
}
#endif
- if(node == 0) {
+ if (node == 0) {
prom_printf("clock_probe: Cannot find timer chip\n");
prom_halt();
}
@@ -415,8 +497,12 @@
prom_halt();
}
- mstk48t59_regs = edev->resource[0].start;
- mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
+ if (!strcmp(model, "ds1287")) {
+ ds1287_regs = edev->resource[0].start;
+ } else {
+ mstk48t59_regs = edev->resource[0].start;
+ mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
+ }
break;
}
#endif
@@ -456,27 +542,21 @@
break;
}
- /* Report a low battery voltage condition. */
- if (has_low_battery())
- prom_printf("NVRAM: Low battery voltage!\n");
-
- /* Kick start the clock if it is completely stopped. */
- if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
- kick_start_clock();
+ if (mstk48t02_regs != 0UL) {
+ /* Report a low battery voltage condition. */
+ if (has_low_battery())
+ prom_printf("NVRAM: Low battery voltage!\n");
+
+ /* Kick start the clock if it is completely stopped. */
+ if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
+ kick_start_clock();
+ }
set_system_time();
__restore_flags(flags);
}
-#ifndef BCD_TO_BIN
-#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
-#endif
-
-#ifndef BIN_TO_BCD
-#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10)
-#endif
-
extern void init_timers(void (*func)(int, void *, struct pt_regs *),
unsigned long *);
@@ -497,6 +577,7 @@
{
unsigned long ticks;
+ if (!SPARC64_USE_STICK) {
__asm__ __volatile__("
rd %%tick, %%g1
add %1, %%g1, %0
@@ -505,6 +586,14 @@
: "=r" (ticks)
: "r" (timer_tick_offset), "r" (timer_tick_compare)
: "g1", "g2");
+ } else {
+ __asm__ __volatile__("rd %%asr24, %%g1\n\t"
+ "add %1, %%g1, %0\n\t"
+ "sub %0, %2, %0\n\t"
+ : "=&r" (ticks)
+ : "r" (timer_tick_offset), "r" (timer_tick_compare)
+ : "g1");
+ }
return (ticks * timer_ticks_per_usec_quotient) >> 32UL;
}
@@ -533,8 +622,13 @@
static int set_rtc_mmss(unsigned long nowtime)
{
- int real_seconds, real_minutes, mostek_minutes;
- unsigned long regs = mstk48t02_regs;
+ int real_seconds, real_minutes, chip_minutes;
+ unsigned long mregs = mstk48t02_regs;
+#ifdef CONFIG_PCI
+ unsigned long dregs = ds1287_regs;
+#else
+ unsigned long dregs = 0UL;
+#endif
unsigned long flags;
u8 tmp;
@@ -542,52 +636,96 @@
* Not having a register set can lead to trouble.
* Also starfire doesnt have a tod clock.
*/
- if (!regs)
+ if (!mregs && !dregs)
return -1;
- spin_lock_irqsave(&mostek_lock, flags);
-
- /* Read the current RTC minutes. */
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp |= MSTK_CREG_READ;
- mostek_write(regs + MOSTEK_CREG, tmp);
-
- mostek_minutes = MSTK_REG_MIN(regs);
+ if (mregs) {
+ spin_lock_irqsave(&mostek_lock, flags);
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp &= ~MSTK_CREG_READ;
- mostek_write(regs + MOSTEK_CREG, tmp);
-
- /*
- * 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 - mostek_minutes) + 15)/30) & 1)
- real_minutes += 30; /* correct for half hour time zone */
- real_minutes %= 60;
+ /* Read the current RTC minutes. */
+ tmp = mostek_read(mregs + MOSTEK_CREG);
+ tmp |= MSTK_CREG_READ;
+ mostek_write(mregs + MOSTEK_CREG, tmp);
+
+ chip_minutes = MSTK_REG_MIN(mregs);
+
+ tmp = mostek_read(mregs + MOSTEK_CREG);
+ tmp &= ~MSTK_CREG_READ;
+ mostek_write(mregs + MOSTEK_CREG, tmp);
+
+ /*
+ * 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 - chip_minutes) + 15)/30) & 1)
+ real_minutes += 30; /* correct for half hour time zone */
+ real_minutes %= 60;
+
+ if (abs(real_minutes - chip_minutes) < 30) {
+ tmp = mostek_read(mregs + MOSTEK_CREG);
+ tmp |= MSTK_CREG_WRITE;
+ mostek_write(mregs + MOSTEK_CREG, tmp);
+
+ MSTK_SET_REG_SEC(mregs,real_seconds);
+ MSTK_SET_REG_MIN(mregs,real_minutes);
+
+ tmp = mostek_read(mregs + MOSTEK_CREG);
+ tmp &= ~MSTK_CREG_WRITE;
+ mostek_write(mregs + MOSTEK_CREG, tmp);
- if (abs(real_minutes - mostek_minutes) < 30) {
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp |= MSTK_CREG_WRITE;
- mostek_write(regs + MOSTEK_CREG, tmp);
+ spin_unlock_irqrestore(&mostek_lock, flags);
- MSTK_SET_REG_SEC(regs,real_seconds);
- MSTK_SET_REG_MIN(regs,real_minutes);
+ return 0;
+ } else {
+ spin_unlock_irqrestore(&mostek_lock, flags);
- tmp = mostek_read(regs + MOSTEK_CREG);
- tmp &= ~MSTK_CREG_WRITE;
- mostek_write(regs + MOSTEK_CREG, tmp);
+ return -1;
+ }
+ } else {
+ int retval = 0;
+ unsigned char save_control, save_freq_select;
- spin_unlock_irqrestore(&mostek_lock, flags);
+ /* Stolen from arch/i386/kernel/time.c, see there for
+ * credits and descriptive comments.
+ */
+ spin_lock_irqsave(&rtc_lock, flags);
+ 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);
+
+ chip_minutes = CMOS_READ(RTC_MINUTES);
+ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ BCD_TO_BIN(chip_minutes);
+ real_seconds = nowtime % 60;
+ real_minutes = nowtime / 60;
+ if (((abs(real_minutes - chip_minutes) + 15)/30) & 1)
+ real_minutes += 30;
+ real_minutes %= 60;
+
+ if (abs(real_minutes - chip_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",
+ chip_minutes, real_minutes);
+ retval = -1;
+ }
- return 0;
- } else {
- spin_unlock_irqrestore(&mostek_lock, flags);
+ CMOS_WRITE(save_control, RTC_CONTROL);
+ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+ spin_unlock_irqrestore(&rtc_lock, flags);
- return -1;
+ return retval;
}
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)