patch-2.1.51 linux/arch/ppc/kernel/prep_time.c

Next file: linux/arch/ppc/kernel/process.c
Previous file: linux/arch/ppc/kernel/prep_setup.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/prep_time.c linux/arch/ppc/kernel/prep_time.c
@@ -23,18 +23,72 @@
 #include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/processor.h>
+#include <asm/nvram.h>
 
-/* last time the cmos clock got updated */
-static long last_rtc_update = 0;
-static int set_rtc_mmss(unsigned long nowtime);
-unsigned long get_cmos_time(void);
-static inline unsigned long mktime(unsigned int, unsigned int,unsigned int,
+#include "time.h"
+
+inline unsigned long mktime(unsigned int, unsigned int,unsigned int,
 				   unsigned int, unsigned int, unsigned int);
-#define TIMER_IRQ 0
 
-/* Cycle counter value at the previous timer interrupt.. */
-static unsigned long long last_timer_cc = 0;
-static unsigned long long init_timer_cc = 0;
+/*
+ * The motorola uses the m48t18 rtc (includes DS1643) whose registers
+ * are at a higher end of nvram (1ff8-1fff) than the ibm mc146818
+ * rtc (ds1386) which has regs at addr 0-d).  The intel gets
+ * past this because the bios emulates the mc146818.
+ *
+ * Why in the world did they have to use different clocks?
+ *
+ * Right now things are hacked to check which machine we're on then
+ * use the appropriate macro.  This is very very ugly and I should
+ * probably have a function that checks which machine we're on then
+ * does things correctly transparently or a function pointer which
+ * is setup at boot time to use the correct addresses.
+ * -- Cort
+ */
+/*
+ * translate from mc146818 to m48t18  addresses
+ */
+unsigned int clock_transl[] = { MOTO_RTC_SECONDS,0 /* alarm */,
+		       MOTO_RTC_MINUTES,0 /* alarm */,
+		       MOTO_RTC_HOURS,0 /* alarm */,                 /*  4,5 */
+		       MOTO_RTC_DAY_OF_WEEK,
+		       MOTO_RTC_DAY_OF_MONTH,
+		       MOTO_RTC_MONTH,
+		       MOTO_RTC_YEAR,                    /* 9 */
+		       MOTO_RTC_CONTROLA, MOTO_RTC_CONTROLB /* 10,11 */
+};
+
+int prep_cmos_clock_read(int addr)
+{
+	if ( _machine == _MACH_IBM )
+		return CMOS_READ(addr);
+	else if ( _machine == _MACH_Motorola )
+	{
+		outb(clock_transl[addr]>>8, NVRAM_AS1);
+		outb(clock_transl[addr], NVRAM_AS0);
+		return (inb(NVRAM_DATA));
+	}
+
+	printk("Unknown machine in prep_cmos_clock_read()!\n");
+	return -1;
+}
+
+void prep_cmos_clock_write(unsigned long val, int addr)
+{
+	if ( _machine == _MACH_IBM )
+	{
+		CMOS_WRITE(val,addr);
+		return;
+	}
+	else if ( _machine == _MACH_Motorola )
+	{
+		outb(clock_transl[addr]>>8, NVRAM_AS1);
+		outb(clock_transl[addr], NVRAM_AS0);
+		outb(val,NVRAM_DATA);
+		return;
+	}
+	printk("Unknown machine in prep_cmos_clock_write()!\n");
+}
 
 #define TICK_SIZE tick
 #define FEBRUARY	2
@@ -49,6 +103,7 @@
 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
 };
 
+#if 0
 static unsigned long do_slow_gettimeoffset(void)
 {
 	int count;
@@ -69,7 +124,6 @@
 	count = (count + LATCH/2) / LATCH;
 	return offset + count;
 }
-
 static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
 
 /*
@@ -106,6 +160,8 @@
 	sti();
 }
 
+#endif
+
 void to_tm(int tim, struct rtc_time * tm)
 {
 	register int    i;
@@ -139,20 +195,20 @@
 /*
  * Set the hardware clock. -- Cort
  */
-static int set_rtc_mmss(unsigned long nowtime)
+int prep_set_rtc_time(unsigned long nowtime)
 {
-	int retval = 0;
-	int real_seconds, real_minutes, cmos_minutes;
 	unsigned char save_control, save_freq_select;
 	struct rtc_time tm;
 
 	to_tm(nowtime, &tm);
 
-	save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
-	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+	save_control = prep_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
 
-	save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
-	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+	prep_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL);
+
+	save_freq_select = prep_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
+	
+	prep_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
 
         tm.tm_year -= 1900;
 	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
@@ -163,12 +219,12 @@
 		BIN_TO_BCD(tm.tm_mday);
 		BIN_TO_BCD(tm.tm_year);
 	}
-	CMOS_WRITE(tm.tm_sec,RTC_SECONDS);
-	CMOS_WRITE(tm.tm_min,RTC_MINUTES);
-	CMOS_WRITE(tm.tm_hour,RTC_HOURS);
-	CMOS_WRITE(tm.tm_mon,RTC_MONTH);
-	CMOS_WRITE(tm.tm_mday,RTC_DAY_OF_MONTH);
-	CMOS_WRITE(tm.tm_year,RTC_YEAR);
+	prep_cmos_clock_write(tm.tm_sec,RTC_SECONDS);
+	prep_cmos_clock_write(tm.tm_min,RTC_MINUTES);
+	prep_cmos_clock_write(tm.tm_hour,RTC_HOURS);
+	prep_cmos_clock_write(tm.tm_mon,RTC_MONTH);
+	prep_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH);
+	prep_cmos_clock_write(tm.tm_year,RTC_YEAR);
 	
 	/* The following flags have to be released exactly in this order,
 	 * otherwise the DS12887 (popular MC146818A clone with integrated
@@ -177,15 +233,15 @@
 	 * 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);
+	prep_cmos_clock_write(save_control, RTC_CONTROL);
+	prep_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT);
 
 	if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
 		time_state = TIME_OK;
 	return 0;
 }
 
-unsigned long get_cmos_time(void)
+unsigned long prep_get_rtc_time(void)
 {
 	unsigned int year, mon, day, hour, min, sec;
 	int i;
@@ -197,20 +253,20 @@
 	 */
 	/* 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)
+		if (prep_cmos_clock_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))
+		if (!(prep_cmos_clock_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)
+		sec = prep_cmos_clock_read(RTC_SECONDS);
+		min = prep_cmos_clock_read(RTC_MINUTES);
+		hour = prep_cmos_clock_read(RTC_HOURS);
+		day = prep_cmos_clock_read(RTC_DAY_OF_MONTH);
+		mon = prep_cmos_clock_read(RTC_MONTH);
+		year = prep_cmos_clock_read(RTC_YEAR);
+	} while (sec != prep_cmos_clock_read(RTC_SECONDS));
+	if (!(prep_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
 	  {
 	    BCD_TO_BIN(sec);
 	    BCD_TO_BIN(min);
@@ -224,19 +280,68 @@
 	return mktime(year, mon, day, hour, min, sec);
 }
 
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+inline unsigned long mktime(unsigned int year, unsigned int mon,
+				   unsigned int day, unsigned int hour,
+				   unsigned int min, unsigned int sec)
+{
+	
+	if (0 >= (int) (mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
+		mon += 12;	/* Puts Feb last since it has leap day */
+		year -= 1;
+	}
+	return (((
+		(unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+		year*365 - 719499
+		)*24 + hour /* now have hours */
+		)*60 + min /* now have minutes */
+		)*60 + sec; /* finally seconds */
+}
+
+#if 0
+void time_init(void)
+{
+	void (*irq_handler)(int, void *,struct pt_regs *);
+	
+	xtime.tv_sec = prep_get_rtc_time();
+	xtime.tv_usec = 0;
+	
+	prep_calibrate_decr();
+	
+	/* If we have the CPU hardware time counters, use them */
+	irq_handler = timer_interrupt;
+	if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL) != 0)
+		panic("Could not allocate timer IRQ!");
+}
+
 /*
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  */
 static inline void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
 {
+	prep_calibrate_decr_handler(irq,dev,regs);
 	do_timer(regs);
 
 	/* update the hw clock if:
 	 * the time is marked out of sync (TIME_ERROR)
 	 * or ~11 minutes have expired since the last update -- Cort
 	 * If we have an externally synchronized Linux clock, then update
-	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+	 * CMOS clock accordingly every ~11 minutes. prep_set_rtc_mmss() has to be
 	 * called as close as possible to 500 ms before the new second starts.
 	 */
 	if ( time_state == TIME_BAD ||
@@ -244,7 +349,7 @@
 	/*if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
 	    xtime.tv_usec > 500000 - (tick >> 1) &&
 	    xtime.tv_usec < 500000 + (tick >> 1))*/
-		if (set_rtc_mmss(xtime.tv_sec) == 0)
+		if (prep_set_rtc_time(xtime.tv_sec) == 0)
 			last_rtc_update = xtime.tv_sec;
 		else
 			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
@@ -269,47 +374,4 @@
 	}
 #endif
 }
-
-
-/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
- * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
- * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
- *
- * [For the Julian calendar (which was used in Russia before 1917,
- * Britain & colonies before 1752, anywhere else before 1582,
- * and is still in use by some communities) leave out the
- * -year/100+year/400 terms, and add 10.]
- *
- * This algorithm was first published by Gauss (I think).
- *
- * WARNING: this function will overflow on 2106-02-07 06:28:16 on
- * machines were long is 32-bit! (However, as time_t is signed, we
- * will already get problems at other places on 2038-01-19 03:14:08)
- */
-static inline unsigned long mktime(unsigned int year, unsigned int mon,
-				   unsigned int day, unsigned int hour,
-				   unsigned int min, unsigned int sec)
-{
-	if (0 >= (int) (mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
-		mon += 12;	/* Puts Feb last since it has leap day */
-		year -= 1;
-	}
-	return (((
-		(unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
-		year*365 - 719499
-		)*24 + hour /* now have hours */
-		)*60 + min /* now have minutes */
-		)*60 + sec; /* finally seconds */
-}
-
-void time_init(void)
-{
-	void (*irq_handler)(int, void *,struct pt_regs *);
-	xtime.tv_sec = get_cmos_time();
-	xtime.tv_usec = 0;
-
-	/* If we have the CPU hardware time counters, use them */
-	irq_handler = timer_interrupt;
-	if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL) != 0)
-		panic("Could not allocate timer IRQ!");
-}
+#endif

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov