root/arch/sparc/kernel/time.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. timer_interrupt
  2. mktime
  3. clock_probe
  4. time_init
  5. do_gettimeofday
  6. do_settimeofday
  7. set_rtc_mmss

   1 /* $Id: time.c,v 1.12 1996/04/04 16:30:30 tridge Exp $
   2  * linux/arch/sparc/kernel/time.c
   3  *
   4  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
   5  *
   6  * This file handles the Sparc specific time handling details.
   7  */
   8 #include <linux/config.h>
   9 #include <linux/errno.h>
  10 #include <linux/sched.h>
  11 #include <linux/kernel.h>
  12 #include <linux/param.h>
  13 #include <linux/string.h>
  14 #include <linux/mm.h>
  15 #include <linux/timex.h>
  16 
  17 #include <asm/oplib.h>
  18 #include <asm/segment.h>
  19 #include <asm/timer.h>
  20 #include <asm/mostek.h>
  21 #include <asm/system.h>
  22 #include <asm/irq.h>
  23 #include <asm/io.h>
  24 
  25 enum sparc_clock_type sp_clock_typ;
  26 struct mostek48t02 *mstk48t02_regs = 0;
  27 struct mostek48t08 *mstk48t08_regs = 0;
  28 static int set_rtc_mmss(unsigned long);
  29 
  30 /*
  31  * timer_interrupt() needs to keep up the real-time clock,
  32  * as well as call the "do_timer()" routine every clocktick
  33  */
  34 void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  35 {
  36         /* last time the cmos clock got updated */
  37         static long last_rtc_update=0;
  38 
  39         clear_clock_irq();
  40 
  41         do_timer(regs);
  42 
  43         /* XXX I don't know if this is right for the Sparc yet. XXX */
  44         if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
  45             xtime.tv_usec > 500000 - (tick >> 1) &&
  46             xtime.tv_usec < 500000 + (tick >> 1))
  47           if (set_rtc_mmss(xtime.tv_sec) == 0)
  48             last_rtc_update = xtime.tv_sec;
  49           else
  50             last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
  51 }
  52 
  53 /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
  54  * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
  55  * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
  56  *
  57  * [For the Julian calendar (which was used in Russia before 1917,
  58  * Britain & colonies before 1752, anywhere else before 1582,
  59  * and is still in use by some communities) leave out the
  60  * -year/100+year/400 terms, and add 10.]
  61  *
  62  * This algorithm was first published by Gauss (I think).
  63  *
  64  * WARNING: this function will overflow on 2106-02-07 06:28:16 on
  65  * machines were long is 32-bit! (However, as time_t is signed, we
  66  * will already get problems at other places on 2038-01-19 03:14:08)
  67  */
  68 static inline unsigned long mktime(unsigned int year, unsigned int mon,
     /* [previous][next][first][last][top][bottom][index][help] */
  69         unsigned int day, unsigned int hour,
  70         unsigned int min, unsigned int sec)
  71 {
  72         if (0 >= (int) (mon -= 2)) {    /* 1..12 -> 11,12,1..10 */
  73                 mon += 12;      /* Puts Feb last since it has leap day */
  74                 year -= 1;
  75         }
  76         return (((
  77             (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
  78               year*365 - 719499
  79             )*24 + hour /* now have hours */
  80            )*60 + min /* now have minutes */
  81           )*60 + sec; /* finally seconds */
  82 }
  83 
  84 /* Clock probing, we probe the timers here also. */
  85 volatile unsigned int foo_limit;
  86 
  87 static void clock_probe(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  88 {
  89         char node_str[128];
  90         register int node, type;
  91         struct linux_prom_registers clk_reg[2];
  92 
  93         /* This will basically traverse the node-tree of the prom to see
  94          * which timer chip is on this machine.
  95          */
  96         node = 0;
  97         if(sparc_cpu_model == sun4) {
  98                 printk("clock_probe: No SUN4 Clock/Timer support yet...\n");
  99                 return;
 100         }
 101         if(sparc_cpu_model == sun4c)
 102                 node = prom_getchild(prom_root_node);
 103         else
 104                 if(sparc_cpu_model == sun4m)
 105                         node=prom_getchild(prom_searchsiblings(prom_getchild(prom_root_node), "obio"));
 106         type = 0;
 107         sp_clock_typ = MSTK_INVALID;
 108         for(;;) {
 109                 prom_getstring(node, "model", node_str, sizeof(node_str));
 110                 if(strcmp(node_str, "mk48t02") == 0) {
 111                         sp_clock_typ = MSTK48T02;
 112                         if(prom_getproperty(node, "reg", (char *) clk_reg, sizeof(clk_reg)) == -1) {
 113                                 printk("clock_probe: FAILED!\n");
 114                                 halt();
 115                         }
 116                         prom_apply_obio_ranges(clk_reg, 1);
 117                         /* Map the clock register io area read-only */
 118                         mstk48t02_regs = (struct mostek48t02 *) 
 119                                 sparc_alloc_io((void *) clk_reg[0].phys_addr,
 120                                                (void *) 0, sizeof(*mstk48t02_regs),
 121                                                "clock", clk_reg[0].which_io, 0x0);
 122                         mstk48t08_regs = 0;  /* To catch weirdness */
 123                         break;
 124                 }
 125 
 126                 if(strcmp(node_str, "mk48t08") == 0) {
 127                         sp_clock_typ = MSTK48T08;
 128                         if(prom_getproperty(node, "reg", (char *) clk_reg,
 129                                             sizeof(clk_reg)) == -1) {
 130                                 printk("clock_probe: FAILED!\n");
 131                                 halt();
 132                         }
 133                         prom_apply_obio_ranges(clk_reg, 1);
 134                         /* Map the clock register io area read-only */
 135                         mstk48t08_regs = (struct mostek48t08 *)
 136                                 sparc_alloc_io((void *) clk_reg[0].phys_addr,
 137                                                (void *) 0, sizeof(*mstk48t08_regs),
 138                                                "clock", clk_reg[0].which_io, 0x0);
 139 
 140                         mstk48t02_regs = &mstk48t08_regs->regs;
 141                         break;
 142                 }
 143 
 144                 node = prom_getsibling(node);
 145                 if(node == 0) {
 146                         printk("Aieee, could not find timer chip type\n");
 147                         return;
 148                 }
 149         }
 150 }
 151 
 152 #ifndef BCD_TO_BIN
 153 #define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
 154 #endif
 155 
 156 #ifndef BIN_TO_BCD
 157 #define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10)
 158 #endif
 159 
 160 void time_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 161 {
 162         unsigned int year, mon, day, hour, min, sec;
 163         struct mostek48t02 *mregs;
 164 
 165 #if CONFIG_AP1000
 166         init_timers(timer_interrupt);
 167         return;
 168 #endif
 169 
 170         clock_probe();
 171         init_timers(timer_interrupt);
 172 
 173         mregs = mstk48t02_regs;
 174         if(!mregs) {
 175                 prom_printf("Something wrong, clock regs not mapped yet.\n");
 176                 prom_halt();
 177         }               
 178         mregs->creg |= MSTK_CREG_READ;
 179         sec = BCD_TO_BIN(mregs->sec);
 180         min = BCD_TO_BIN(mregs->min);
 181         hour = BCD_TO_BIN(mregs->hour);
 182         day = BCD_TO_BIN(mregs->dom);
 183         mon = BCD_TO_BIN(mregs->mnth);
 184         year = (BCD_TO_BIN(mregs->yr) + MSTK_YR_ZERO);
 185         xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
 186         xtime.tv_usec = 0;
 187         mregs->creg &= ~MSTK_CREG_READ;
 188         return;
 189 }
 190 
 191 /* Nothing fancy on the Sparc yet. */
 192 void do_gettimeofday(struct timeval *tv)
     /* [previous][next][first][last][top][bottom][index][help] */
 193 {
 194         unsigned long flags;
 195 
 196         save_flags(flags);
 197         cli();
 198 #if CONFIG_AP1000
 199         ap_gettimeofday(&xtime);
 200 #endif
 201         *tv = xtime;
 202         restore_flags(flags);
 203 }
 204 
 205 void do_settimeofday(struct timeval *tv)
     /* [previous][next][first][last][top][bottom][index][help] */
 206 {
 207         cli();
 208         xtime = *tv;
 209         time_state = TIME_BAD;
 210         time_maxerror = 0x70000000;
 211         time_esterror = 0x70000000;
 212         sti();
 213 }
 214 
 215 static int set_rtc_mmss(unsigned long nowtime)
     /* [previous][next][first][last][top][bottom][index][help] */
 216 {
 217         int retval = 0;
 218         int real_seconds, real_minutes, mostek_minutes;
 219         struct mostek48t02 *mregs = mstk48t02_regs;
 220 
 221         if(!mregs)
 222                 retval = -1;
 223         else {
 224                 mregs->creg |= MSTK_CREG_READ;
 225                 mostek_minutes = BCD_TO_BIN(mregs->min);
 226                 mregs->creg &= ~MSTK_CREG_READ;
 227 
 228                 real_seconds = nowtime % 60;
 229                 real_minutes = nowtime / 60;
 230                 if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
 231                         real_minutes += 30;
 232                 real_minutes %= 60;
 233                 if (abs(real_minutes - mostek_minutes) < 30) {
 234                         mregs->creg |= MSTK_CREG_WRITE;
 235                         mregs->sec = real_seconds;
 236                         mregs->min = real_minutes;
 237                         mregs->creg &= ~MSTK_CREG_WRITE;
 238                 } else
 239                         retval = -1;
 240         }
 241 
 242         return retval;
 243 }

/* [previous][next][first][last][top][bottom][index][help] */