282 lines
6.6 KiB
C
282 lines
6.6 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
Copyright (c) 1992 Silicon Graphics, Inc.
|
||
|
||
Module Name:
|
||
|
||
s3time.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the HAL set/query realtime clock routines for
|
||
the SGI Indigo system.
|
||
|
||
Author:
|
||
|
||
David N. Cutler (davec) 5-May-1991
|
||
Kevin Meier (o-kevinm) 21-Jan-1992
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "halp.h"
|
||
|
||
struct dp8573_clk {
|
||
volatile unsigned int ck_status; /* main status reg */
|
||
union {
|
||
struct {
|
||
int fill[2];
|
||
volatile unsigned int ck_pflag; /* periodic flag */
|
||
volatile unsigned int ck_tsavctl; /* time save control */
|
||
} rs0;
|
||
struct {
|
||
volatile unsigned int ck_rtime; /* real time mode */
|
||
volatile unsigned int ck_outmode; /* output mode */
|
||
volatile unsigned int ck_int0ctl; /* interrupt control 0 */
|
||
volatile unsigned int ck_int1ctl; /* interrupt control 1 */
|
||
} rs1;
|
||
} rs;
|
||
volatile unsigned int ck_counter[10]; /* the counters */
|
||
int fill1[4];
|
||
volatile unsigned int ck_cmpram[6]; /* time compare ram */
|
||
volatile unsigned int ck_timsav[5]; /* time save ram */
|
||
volatile unsigned int ram[2]; /* ram */
|
||
};
|
||
|
||
#define ck_pflag0 rs.rs0.ck_pflag
|
||
#define ck_tsavctl0 rs.rs0.ck_tsavctl
|
||
#define ck_rtime1 rs.rs1.ck_rtime
|
||
#define ck_outmode1 rs.rs1.ck_outmode
|
||
#define ck_int0ctl1 rs.rs1.ck_int0ctl
|
||
#define ck_int1ctl1 rs.rs1.ck_int1ctl
|
||
|
||
#define RT_CLOCK_ADDR 0xbfb80e00
|
||
#define CLOCK_READ 0 /* _clock_func read command */
|
||
#define CLOCK_WRITE 1 /* _clock_func write command */
|
||
|
||
#define CLK_SHIFT 0 /* Indigo uses the LSB */
|
||
|
||
#define RTC_RUN (3 << (CLK_SHIFT + 3))
|
||
#define RTC_RS (1 << (CLK_SHIFT + 6))
|
||
#define RTC_TIMSAVON (1 << (CLK_SHIFT + 7))
|
||
#define RTC_TIMSAVOFF 0
|
||
#define RTC_STATINIT 0
|
||
#define RTC_INT1INIT (0x80 << CLK_SHIFT)
|
||
#define RTC_PFLAGINIT 0
|
||
#define RTC_OUTMODINIT 0
|
||
|
||
#define YRREF 1990
|
||
|
||
static void _clock_func(int, char *);
|
||
static int counter_not_moving (void);
|
||
int rtclock_ok = 0;
|
||
|
||
|
||
BOOLEAN
|
||
HalQueryRealTimeClock (
|
||
IN PTIME_FIELDS t
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine queries the realtime clock.
|
||
|
||
N.B. This routine assumes that the caller has provided any required
|
||
synchronization to query the realtime clock information.
|
||
|
||
Arguments:
|
||
|
||
TimeFields - Supplies a pointer to a time structure that receives
|
||
the realtime clock information.
|
||
|
||
Return Value:
|
||
|
||
If the power to the realtime clock has not failed, then the time
|
||
values are read from the realtime clock and a value of TRUE is
|
||
returned. Otherwise, a value of FALSE is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
char buf[8];
|
||
int tries = 0;
|
||
|
||
again:
|
||
_clock_func(CLOCK_READ, buf);
|
||
|
||
if (!(((int)buf[ 4 ] << CLK_SHIFT) & RTC_RUN) ||
|
||
(!rtclock_ok && counter_not_moving ())) {
|
||
//
|
||
// XXX Initialize to something that's not too unreasonable
|
||
// if the clock's out of whack. Currently the prom resets
|
||
// the clock to 0 when it powers on.
|
||
//
|
||
t->Second = 0;
|
||
t->Minute = 0;
|
||
t->Hour = 0;
|
||
t->Day = 1;
|
||
t->Month = 1;
|
||
t->Year = 1992;
|
||
t->Milliseconds = 0;
|
||
HalDisplayString ("Setting clock to 1/1/92, 00:00:00\n");
|
||
HalSetRealTimeClock (t);
|
||
if ( tries++ )
|
||
return FALSE;
|
||
goto again;
|
||
}
|
||
|
||
t->Second = (unsigned)(buf[ 0 ] & 0xf);
|
||
t->Second += (unsigned)(buf[ 0 ] >> 4) * 10;
|
||
|
||
t->Minute = (unsigned)(buf[ 1 ] & 0xf);
|
||
t->Minute += (unsigned)(buf[ 1 ] >> 4) * 10;
|
||
|
||
/*
|
||
** we use 24 hr mode, so bits 4 and 5 represent to 2 ten-hour
|
||
** bits
|
||
*/
|
||
t->Hour = (unsigned)( buf[ 2 ] & 0xf );
|
||
t->Hour += (unsigned)( ( buf[ 2 ] >> 4 ) & 0x3 ) * 10;
|
||
|
||
/*
|
||
** actually day of month
|
||
*/
|
||
t->Day = (unsigned)( buf[ 3 ] & 0xf );
|
||
t->Day += (unsigned)( buf[ 3 ] >> 4 ) * 10;
|
||
|
||
t->Month = (unsigned)( buf[ 5 ] & 0xf );
|
||
t->Month += (unsigned)( buf[ 5 ] >> 4 ) * 10;
|
||
|
||
t->Year = (unsigned)( buf[ 6 ] & 0xf );
|
||
t->Year += (unsigned)( buf[ 6 ] >> 4 ) * 10;
|
||
t->Year += YRREF;
|
||
|
||
t->Milliseconds = 0;
|
||
|
||
/*
|
||
** if the year is set to zero, then the clock must have stopped
|
||
*/
|
||
if (!buf[6])
|
||
return FALSE;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
HalSetRealTimeClock (
|
||
IN PTIME_FIELDS t
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets the realtime clock.
|
||
|
||
N.B. This routine assumes that the caller has provided any required
|
||
synchronization to set the realtime clock information.
|
||
|
||
Arguments:
|
||
|
||
TimeFields - Supplies a pointer to a time structure that specifies the
|
||
realtime clock information.
|
||
|
||
Return Value:
|
||
|
||
If the power to the realtime clock has not failed, then the time
|
||
values are written to the realtime clock and a value of TRUE is
|
||
returned. Otherwise, a value of FALSE is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
char buf[ 8 ];
|
||
|
||
buf[0] = 0;
|
||
buf[1] = ((t->Second / 10) << 4) | (t->Second % 10);
|
||
buf[2] = ((t->Minute / 10) << 4) | (t->Minute % 10);
|
||
buf[3] = ((t->Hour / 10) << 4) | (t->Hour % 10);
|
||
buf[4] = 0;
|
||
buf[5] = ((t->Day / 10) << 4) | (t->Day % 10);
|
||
buf[6] = ((t->Month / 10) << 4) | (t->Month % 10);
|
||
buf[7] = (((t->Year-YRREF) / 10) << 4) | ((t->Year-YRREF) % 10);
|
||
_clock_func(CLOCK_WRITE, buf);
|
||
|
||
if (!rtclock_ok && counter_not_moving())
|
||
return FALSE;
|
||
return TRUE;
|
||
}
|
||
|
||
static void
|
||
_clock_func(int func, char *ptr)
|
||
{
|
||
register struct dp8573_clk *clock;
|
||
char *state;
|
||
int leap, i;
|
||
|
||
clock = (struct dp8573_clk *)RT_CLOCK_ADDR;
|
||
|
||
if (func == CLOCK_READ) {
|
||
/* clear the time save RAM */
|
||
for (i = 0; i < 5; i++)
|
||
clock->ck_timsav[i] = 0;
|
||
/* latch the Time Save RAM */
|
||
clock->ck_status = RTC_STATINIT;
|
||
clock->ck_tsavctl0 = RTC_TIMSAVON;
|
||
clock->ck_tsavctl0 = RTC_TIMSAVOFF;
|
||
for (i = 0; i < 5; i++) {
|
||
if (i == 4) /* keep the format the same */
|
||
state = ptr++; /* as for IP4 */
|
||
*ptr++ = (char) (clock->ck_timsav[i] >> CLK_SHIFT);
|
||
}
|
||
*ptr = (char) (clock->ck_counter[6] >> CLK_SHIFT);
|
||
clock->ck_status |= RTC_RS;
|
||
*state = (char) (clock->ck_rtime1 >> CLK_SHIFT);
|
||
} else {
|
||
clock->ck_status = RTC_STATINIT;
|
||
clock->ck_tsavctl0 = RTC_TIMSAVOFF;
|
||
clock->ck_pflag0 = RTC_PFLAGINIT;
|
||
clock->ck_status = RTC_RS;
|
||
clock->ck_int1ctl1 = RTC_INT1INIT;
|
||
clock->ck_outmode1 = RTC_OUTMODINIT;
|
||
|
||
clock->ck_rtime1 &= ~RTC_RUN;
|
||
for (i = 0; i < 7; i++) {
|
||
if (i == 4)
|
||
ptr++;
|
||
clock->ck_counter[i] = *ptr++ << CLK_SHIFT;
|
||
}
|
||
leap = clock->ck_counter[6] % 4;
|
||
clock->ck_rtime1 = RTC_RUN | (leap << CLK_SHIFT);
|
||
}
|
||
|
||
}
|
||
|
||
static int
|
||
counter_not_moving (void)
|
||
{
|
||
struct dp8573_clk *clock = (struct dp8573_clk *)RT_CLOCK_ADDR;
|
||
int delay_count = 1000000;
|
||
unsigned char initial;
|
||
|
||
rtclock_ok = 1;
|
||
clock->ck_status = RTC_STATINIT;
|
||
initial = (unsigned char)(clock->ck_counter[0] >> CLK_SHIFT);
|
||
|
||
while (delay_count--)
|
||
if ((unsigned char)(clock->ck_counter[0] >> CLK_SHIFT) != initial)
|
||
return (0);
|
||
|
||
rtclock_ok = 0;
|
||
return (1);
|
||
} /* counter_not_moving */
|