patch-2.2.8 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.2.7/linux/arch/ppc/kernel/prep_time.c linux/arch/ppc/kernel/prep_time.c
@@ -22,7 +22,9 @@
 #include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/processor.h>
-#include <asm/nvram.h>
+#include <asm/machdep.h>
+#include <asm/prep_nvram.h>
+#include <asm/mk48t59.h>
 
 #include "time.h"
 
@@ -41,133 +43,44 @@
  * is setup at boot time to use the correct addresses.
  * -- Cort
  */
-/*
- * translate from mc146818 to m48t18  addresses
- */
-unsigned int clock_transl[] __prepdata = { 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 */
-};
-
-/*
- * The following struture is used to access the MK48T18
- */
-typedef volatile struct _MK48T18 {
-	unsigned char	ucNvRAM[0x3ff8]; /* NvRAM locations */
-	unsigned char	ucControl;
-	unsigned char	ucSecond;	/* 0-59 */
-	unsigned char	ucMinute;	/* 0-59 */
-	unsigned char	ucHour;		/* 0-23 */
-	unsigned char	ucDay;		/* 1-7 */
-	unsigned char	ucDate;		/* 1-31 */
-	unsigned char	ucMonth;	/* 1-12 */
-	unsigned char	ucYear;		/* 0-99 */
-} MK48T18, *PMK48T18;
-
-/*
- * The control register contains a 5 bit calibration value plus sign
- * and read/write enable bits
- */
-#define MK48T18_CTRL_CAL_MASK	0x1f
-#define MK48T18_CTRL_CAL_SIGN	0x20
-#define MK48T18_CTRL_READ	0x40
-#define MK48T18_CTRL_WRITE	0x80
-/*
- * The STOP bit is the most significant bit of the seconds location
- */
-#define MK48T18_SEC_MASK	0x7f
-#define MK48T18_SEC_STOP	0x80
-/*
- * The day location also contains the frequency test bit which should
- * be zero for normal operation
- */
-#define MK48T18_DAY_MASK	0x07
-#define MK48T18_DAY_FT		0x40
-
-__prep
-int prep_cmos_clock_read(int addr)
-{
-	if ( _prep_type == _PREP_IBM )
-		return CMOS_READ(addr);
-	else if ( _prep_type == _PREP_Motorola )
-	{
-		outb(clock_transl[addr]>>8, NVRAM_AS1);
-		outb(clock_transl[addr], NVRAM_AS0);
-		return (inb(NVRAM_DATA));
-	}
-        else if ( _prep_type == _PREP_Radstone )
-                return CMOS_READ(addr);
-
-	printk("Unknown machine in prep_cmos_clock_read()!\n");
-	return -1;
-}
-
-__prep
-void prep_cmos_clock_write(unsigned long val, int addr)
-{
-	if ( _prep_type == _PREP_IBM )
-	{
-		CMOS_WRITE(val,addr);
-		return;
-	}
-	else if ( _prep_type == _PREP_Motorola )
-	{
-		outb(clock_transl[addr]>>8, NVRAM_AS1);
-		outb(clock_transl[addr], NVRAM_AS0);
-		outb(val,NVRAM_DATA);
-		return;
-	}
-        else if ( _prep_type == _PREP_Radstone )
-        {
-                CMOS_WRITE(val,addr);
-                return;
-        }
-
-	printk("Unknown machine in prep_cmos_clock_write()!\n");
-}
 
 /*
  * Set the hardware clock. -- Cort
  */
 __prep
-int prep_set_rtc_time(unsigned long nowtime)
+int mc146818_set_rtc_time(unsigned long nowtime)
 {
 	unsigned char save_control, save_freq_select;
 	struct rtc_time tm;
 
 	to_tm(nowtime, &tm);
 
-	save_control = prep_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
-
-	prep_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL);
-
-	save_freq_select = prep_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
+	/* tell the clock it's being set */
+	save_control = CMOS_READ(RTC_CONTROL);
 	
-	prep_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
-        tm.tm_year -= 1900;
+	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+	
+	/* stop and reset prescaler */
+	save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
+	
+	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+	
+        tm.tm_year = (tm.tm_year - 1900) % 100;
 	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
 		BIN_TO_BCD(tm.tm_sec);
 		BIN_TO_BCD(tm.tm_min);
 		BIN_TO_BCD(tm.tm_hour);
 		BIN_TO_BCD(tm.tm_mon);
-		BIN_TO_BCD(tm.tm_wday);
 		BIN_TO_BCD(tm.tm_mday);
 		BIN_TO_BCD(tm.tm_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_wday+1,RTC_DAY_OF_WEEK);
-	prep_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH);
-	prep_cmos_clock_write(tm.tm_year,RTC_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);
+	
 	/* 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
@@ -175,52 +88,14 @@
 	 * the Dallas Semiconductor data sheets, but who believes data
 	 * sheets anyway ...                           -- Markus Kuhn
 	 */
-	prep_cmos_clock_write(save_control, RTC_CONTROL);
-	prep_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT);
+	CMOS_WRITE(save_control,     RTC_CONTROL);
+	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
 
-	/*
-	 * Radstone Technology PPC1a boards use an MK48T18 device
-	 * as the "master" RTC but also have a DS1287 equivalent incorporated
-	 * into the PCI-ISA bridge device. The DS1287 is initialised by the boot
-	 * firmware to reflect the value held in the MK48T18 and thus the
-	 * time may be read from this device both here and in the rtc driver.
-	 * Whenever we set the time, however, if it is to be preserved across
-	 * boots we must also update the "master" RTC.
-	 */
-	if((_prep_type==_PREP_Radstone) && (ucSystemType==RS_SYS_TYPE_PPC1a))
-	{
-		PMK48T18 pMk48t18=(PMK48T18)(_ISA_MEM_BASE+0x00800000);
-
-		/*
-		 * Set the write enable bit
-		 */
-		pMk48t18->ucControl|=MK48T18_CTRL_WRITE;
-		eieio();
-		/*
-		 * Update the clock
-		 */
-		pMk48t18->ucSecond=tm.tm_sec;
-		pMk48t18->ucMinute=tm.tm_min;
-		pMk48t18->ucHour=tm.tm_hour;
-		pMk48t18->ucMonth=tm.tm_mon;
-		pMk48t18->ucDay=tm.tm_wday+1;
-		pMk48t18->ucDate=tm.tm_mday;
-		pMk48t18->ucYear=tm.tm_year;
-
-		eieio();
-		/*
-		 * Clear the write enable bit
-		 */
-		pMk48t18->ucControl&=~MK48T18_CTRL_WRITE;
-	}
-
-	if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
-		time_state = TIME_OK;
 	return 0;
 }
 
 __prep
-unsigned long prep_get_rtc_time(void)
+unsigned long mc146818_get_rtc_time(void)
 {
 	unsigned int year, mon, day, hour, min, sec;
 	int i;
@@ -232,29 +107,123 @@
 	 */
 	/* read RTC exactly on falling edge of update flag */
 	for (i = 0 ; i < 1000000 ; i++)	/* may take up to 1 second... */
-		if (prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP)
+		if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
 			break;
 	for (i = 0 ; i < 1000000 ; i++)	/* must try at least 2.228 ms */
-		if (!(prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP))
+		if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
 			break;
 	do { /* Isn't this overkill ? UIP above should guarantee consistency */
-		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);
-	    BCD_TO_BIN(hour);
-	    BCD_TO_BIN(day);
-	    BCD_TO_BIN(mon);
-	    BCD_TO_BIN(year);
-	  }
+		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;
+	return mktime(year, mon, day, hour, min, sec);
+}
+
+__prep
+int mk48t59_set_rtc_time(unsigned long nowtime)
+{
+	unsigned char save_control;
+	struct rtc_time tm;
+
+
+	to_tm(nowtime, &tm);
+
+	/* tell the clock it's being written */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+	
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+			     (save_control | MK48T59_RTC_CA_WRITE));
+
+        tm.tm_year = (tm.tm_year - 1900) % 100;
+	BIN_TO_BCD(tm.tm_sec);
+	BIN_TO_BCD(tm.tm_min);
+	BIN_TO_BCD(tm.tm_hour);
+	BIN_TO_BCD(tm.tm_mon);
+	BIN_TO_BCD(tm.tm_mday);
+	BIN_TO_BCD(tm.tm_year);
+
+	ppc_md.nvram_write_val(MK48T59_RTC_SECONDS,      tm.tm_sec);
+	ppc_md.nvram_write_val(MK48T59_RTC_MINUTES,      tm.tm_min);
+	ppc_md.nvram_write_val(MK48T59_RTC_HOURS,        tm.tm_hour);
+	ppc_md.nvram_write_val(MK48T59_RTC_MONTH,        tm.tm_mon);
+	ppc_md.nvram_write_val(MK48T59_RTC_DAY_OF_MONTH, tm.tm_mday);
+	ppc_md.nvram_write_val(MK48T59_RTC_YEAR,         tm.tm_year);
+	
+	/* Turn off the write bit. */
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+	return 0;
+}
+
+__prep
+unsigned long mk48t59_get_rtc_time(void)
+{
+	unsigned char save_control;
+	unsigned int year, mon, day, hour, min, sec;
+	int i;
+
+	/* Make sure the time is not stopped. */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB);
+	
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+			     (save_control & (~MK48T59_RTC_CB_STOP)));
+
+	/* Now make sure the read bit is off so the value will change. */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+	save_control &= ~MK48T59_RTC_CA_READ;
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+	/* Read the seconds value to see when it changes. */
+	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+		
+	/* Wait until the seconds value changes, then read the value. */
+	for (i = 0 ; i < 1000000 ; i++)	{ /* may take up to 1 second... */
+	   if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) {
+	      break;
+	   }
+	}
+
+	/* Set the register to read the value. */
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+			     (save_control | MK48T59_RTC_CA_READ));
+
+	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+	min = ppc_md.nvram_read_val(MK48T59_RTC_MINUTES);
+	hour = ppc_md.nvram_read_val(MK48T59_RTC_HOURS);
+	day = ppc_md.nvram_read_val(MK48T59_RTC_DAY_OF_MONTH);
+	mon = ppc_md.nvram_read_val(MK48T59_RTC_MONTH);
+	year = ppc_md.nvram_read_val(MK48T59_RTC_YEAR);
+
+	/* Let the time values change again. */
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+	BCD_TO_BIN(sec);
+	BCD_TO_BIN(min);
+	BCD_TO_BIN(hour);
+	BCD_TO_BIN(day);
+	BCD_TO_BIN(mon);
+	BCD_TO_BIN(year);
+
+	year = year + 1900;
+	if (year < 1970) {
+		year += 100;
+	}
+
 	return mktime(year, mon, day, hour, min, sec);
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)