432 lines
10 KiB
C
432 lines
10 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991 Microsoft Corporation
|
|||
|
|
|||
|
Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file
|
|||
|
contains copyrighted material. Use of this file is restricted
|
|||
|
by the provisions of a Motorola Software License Agreement.
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
mk48time.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements the HAL set/query realtime clock routines for
|
|||
|
a PowerPC system using the MK48T18 Clock Chip.
|
|||
|
|
|||
|
Original Author:
|
|||
|
|
|||
|
David N. Cutler (davec) 5-May-1991
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
Who When What
|
|||
|
--- -------- -----------------------------------------------
|
|||
|
dgh 07/20/94 Created from pxtime.c and modified for MK48T18 chip.
|
|||
|
dgh 07/22/94 Fixed typo of HalpReadRawClockRegister.
|
|||
|
dgh 07/29/94 Don't run the day-of-week value through the BCD
|
|||
|
conversion when reading the clock. Also mask it
|
|||
|
to 3-bits.
|
|||
|
dgh 08/08/94 Compute RTC location from HalpNvramBaseAddr and the
|
|||
|
RTC offset.
|
|||
|
dgh 08/09/94 HalQueryRealTimeClock: Forgot to restart the clock
|
|||
|
after reading it.
|
|||
|
kjr 10/18/94 Changes for Revision B Comet Mother Board. Remove
|
|||
|
HalpNvramBaseAddr and use new NVRAM address and data
|
|||
|
port.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "halp.h"
|
|||
|
#include "mk48tdc.h"
|
|||
|
#include "eisa.h"
|
|||
|
|
|||
|
#define WRITE 0x80 // Stop update while writing control bit
|
|||
|
#define READ 0x40 // Stop updating while reading control bit
|
|||
|
#define STOP 0x80 // Clock is stopped bit
|
|||
|
|
|||
|
extern PVOID HalpIoControlBase;
|
|||
|
#define RTC_BASE (TODC_OFFSET)
|
|||
|
#define NVRAM ((PNVRAM_CONTROL) HalpIoControlBase)
|
|||
|
|
|||
|
//***************************************************************************
|
|||
|
// Time of Day Clock registers for the MK48T18 chip can be viewed as an
|
|||
|
// array of bytes (UCHARs) where:
|
|||
|
//
|
|||
|
// Address of Real Time Clock Register bitmap of registers
|
|||
|
// -----------------------------------------------------------------------
|
|||
|
// TODC_OFFSET + 0: clock control/calibration reg. [W R S - - - - -]
|
|||
|
// TODC_OFFSET + 1: seconds register (00-59) [P - - - - - - -]
|
|||
|
// TODC_OFFSET + 2: minutes register (00-59) [0 - - - - - - -]
|
|||
|
// TODC_OFFSET + 3: hours register (00-23) [0 0 - - - - - -]
|
|||
|
// TODC_OFFSET + 4: day-of-week register (01-07) [0 F 0 0 0 - - -]
|
|||
|
// TODC_OFFSET + 5: day-of-month register (01-31) [0 0 - - - - - -]
|
|||
|
// TODC_OFFSET + 6: month register (01-12) [0 0 0 - - - - -]
|
|||
|
// TODC_OFFSET + 7: year register (00-99) [- - - - - - - -]
|
|||
|
// W=write, R=read, S=sign, P=stop
|
|||
|
// F=frequency test.
|
|||
|
//
|
|||
|
// NOTE: Values in the TODC registers are in BCD format
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Define forward referenced procedure prototypes.
|
|||
|
//
|
|||
|
|
|||
|
static UCHAR
|
|||
|
HalpReadRawClockRegister (
|
|||
|
UCHAR Register
|
|||
|
);
|
|||
|
|
|||
|
static VOID
|
|||
|
HalpWriteRawClockRegister (
|
|||
|
UCHAR Register,
|
|||
|
UCHAR Value
|
|||
|
);
|
|||
|
|
|||
|
static UCHAR
|
|||
|
HalpReadClockRegister (
|
|||
|
UCHAR Register
|
|||
|
);
|
|||
|
|
|||
|
static VOID
|
|||
|
HalpWriteClockRegister (
|
|||
|
UCHAR Register,
|
|||
|
UCHAR Value
|
|||
|
);
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HalQueryRealTimeClockMk (
|
|||
|
OUT PTIME_FIELDS TimeFields
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine queries the realtime clock.
|
|||
|
|
|||
|
N.B. This routine is required to provide any synchronization necessary
|
|||
|
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.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
UCHAR DataByte;
|
|||
|
KIRQL OldIrql;
|
|||
|
|
|||
|
//
|
|||
|
// If the realtime clock battery is still functioning, then read
|
|||
|
// the realtime clock values, and return a function value of TRUE.
|
|||
|
// Otherwise, return a function value of FALSE.
|
|||
|
//
|
|||
|
// NOTE: It isn't possible to test this clock chip to determine if
|
|||
|
// the battery is still running or not. So we check the STOP
|
|||
|
// bit and if set, then we return FALSE.
|
|||
|
//
|
|||
|
|
|||
|
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
|||
|
|
|||
|
DataByte = HalpReadRawClockRegister(TODC_SECOND);
|
|||
|
if (!(DataByte & STOP)) {
|
|||
|
|
|||
|
//
|
|||
|
// Clock is running.
|
|||
|
// Wait until the realtime clock is not being updated.
|
|||
|
//
|
|||
|
|
|||
|
do {
|
|||
|
DataByte = HalpReadRawClockRegister(TODC_CONTROL);
|
|||
|
} while (DataByte & WRITE);
|
|||
|
|
|||
|
//
|
|||
|
// First stop the clock from being updated while we read it.
|
|||
|
//
|
|||
|
DataByte = HalpReadRawClockRegister(TODC_CONTROL);
|
|||
|
DataByte |= READ;
|
|||
|
HalpWriteRawClockRegister(TODC_CONTROL, DataByte);
|
|||
|
|
|||
|
//
|
|||
|
// Read the realtime clock values.
|
|||
|
//
|
|||
|
|
|||
|
TimeFields->Year = 1900 + (CSHORT)HalpReadClockRegister(TODC_YEAR);
|
|||
|
if (TimeFields->Year < 1980) TimeFields->Year += 100;
|
|||
|
|
|||
|
TimeFields->Month = (CSHORT)HalpReadClockRegister(TODC_MONTH);
|
|||
|
TimeFields->Day = (CSHORT)HalpReadClockRegister(TODC_DAY_OF_MONTH);
|
|||
|
TimeFields->Weekday = (CSHORT)HalpReadClockRegister(TODC_DAY_OF_WEEK) - 1;
|
|||
|
TimeFields->Hour = (CSHORT)HalpReadClockRegister(TODC_HOUR);
|
|||
|
TimeFields->Minute = (CSHORT)HalpReadClockRegister(TODC_MINUTE);
|
|||
|
TimeFields->Second = (CSHORT)HalpReadClockRegister(TODC_SECOND);
|
|||
|
TimeFields->Milliseconds = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Now restart the clock
|
|||
|
//
|
|||
|
DataByte = HalpReadRawClockRegister(TODC_CONTROL);
|
|||
|
DataByte &= ~READ;
|
|||
|
HalpWriteRawClockRegister(TODC_CONTROL, DataByte);
|
|||
|
|
|||
|
KeLowerIrql(OldIrql);
|
|||
|
return TRUE;
|
|||
|
|
|||
|
} else {
|
|||
|
KeLowerIrql(OldIrql);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HalSetRealTimeClockMk (
|
|||
|
IN PTIME_FIELDS TimeFields
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine sets the realtime clock.
|
|||
|
|
|||
|
N.B. This routine is required to provide any synchronization necessary
|
|||
|
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.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
UCHAR DataByte;
|
|||
|
KIRQL OldIrql;
|
|||
|
|
|||
|
//
|
|||
|
// If the realtime clock battery is still functioning, then write
|
|||
|
// the realtime clock values, and return a function value of TRUE.
|
|||
|
// Otherwise, return a function value of FALSE.
|
|||
|
//
|
|||
|
// NOTE: We can't determine if the battery is running or not on
|
|||
|
// this clock chip. So, instead we check the STOP bit and
|
|||
|
// if set, then we treat this as the same condition and
|
|||
|
// return FALSE.
|
|||
|
//
|
|||
|
|
|||
|
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
|||
|
DataByte = HalpReadRawClockRegister(TODC_SECOND);
|
|||
|
if (!(DataByte & STOP)) {
|
|||
|
|
|||
|
//
|
|||
|
// Clock is running.
|
|||
|
// Set the realtime clock to stop updating while we set
|
|||
|
// the time.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
DataByte = HalpReadRawClockRegister(TODC_CONTROL);
|
|||
|
DataByte |= WRITE;
|
|||
|
HalpWriteRawClockRegister(TODC_CONTROL, DataByte);
|
|||
|
|
|||
|
//
|
|||
|
// Write the realtime clock values.
|
|||
|
//
|
|||
|
|
|||
|
if (TimeFields->Year > 1999)
|
|||
|
HalpWriteClockRegister(TODC_YEAR, (UCHAR)(TimeFields->Year - 2000));
|
|||
|
else
|
|||
|
HalpWriteClockRegister(TODC_YEAR, (UCHAR)(TimeFields->Year - 1900));
|
|||
|
|
|||
|
HalpWriteClockRegister(TODC_MONTH, (UCHAR)TimeFields->Month);
|
|||
|
HalpWriteClockRegister(TODC_DAY_OF_MONTH, (UCHAR)TimeFields->Day);
|
|||
|
HalpWriteClockRegister(TODC_DAY_OF_WEEK, (UCHAR)(TimeFields->Weekday + 1));
|
|||
|
HalpWriteClockRegister(TODC_HOUR, (UCHAR)TimeFields->Hour);
|
|||
|
HalpWriteClockRegister(TODC_MINUTE, (UCHAR)TimeFields->Minute);
|
|||
|
HalpWriteClockRegister(TODC_SECOND, (UCHAR)TimeFields->Second);
|
|||
|
|
|||
|
//
|
|||
|
// Set the realtime clock control to resume updating the time.
|
|||
|
//
|
|||
|
|
|||
|
DataByte = HalpReadRawClockRegister(TODC_CONTROL);
|
|||
|
DataByte &= ~WRITE;
|
|||
|
HalpWriteRawClockRegister(TODC_CONTROL, DataByte);
|
|||
|
|
|||
|
|
|||
|
KeLowerIrql(OldIrql);
|
|||
|
return TRUE;
|
|||
|
|
|||
|
} else {
|
|||
|
KeLowerIrql(OldIrql);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static UCHAR
|
|||
|
HalpReadRawClockRegister (
|
|||
|
UCHAR Register
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine reads the specified realtime clock register.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Register - Supplies the number of the register whose value is read.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The value of the register is returned as the function value.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
//
|
|||
|
// Read the specified Register from the Real Time Clock.
|
|||
|
//
|
|||
|
WRITE_REGISTER_UCHAR (&NVRAM->NvramIndexLo, (RTC_BASE + Register) & 0xFF);
|
|||
|
WRITE_REGISTER_UCHAR (&NVRAM->NvramIndexHi, (RTC_BASE + Register) >> 8);
|
|||
|
return(READ_REGISTER_UCHAR (&NVRAM->NvramData));
|
|||
|
}
|
|||
|
|
|||
|
static UCHAR
|
|||
|
HalpReadClockRegister (
|
|||
|
UCHAR Register
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine reads the specified realtime clock register.
|
|||
|
change return value from BCD to binary integer. I think the chip
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Register - Supplies the number of the register whose value is read.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The value of the register is returned as the function value.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UCHAR BcdValue;
|
|||
|
|
|||
|
|
|||
|
BcdValue = HalpReadRawClockRegister(Register);
|
|||
|
//
|
|||
|
// If this is NOT the day-of-week register, then
|
|||
|
// convert from BCD. If it is day-of-week, then
|
|||
|
// mask off to 3-bits.
|
|||
|
//
|
|||
|
if (Register != TODC_DAY_OF_WEEK)
|
|||
|
{
|
|||
|
BcdValue = ((BcdValue >> 4) & 0xf) * 10 + (BcdValue & 0xf);
|
|||
|
}
|
|||
|
else
|
|||
|
BcdValue &= 0x07;
|
|||
|
|
|||
|
return BcdValue;
|
|||
|
}
|
|||
|
|
|||
|
static VOID
|
|||
|
HalpWriteRawClockRegister (
|
|||
|
UCHAR Register,
|
|||
|
UCHAR Value
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine writes the specified value to the specified realtime
|
|||
|
clock register.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Register - Supplies the number of the register whose value is written.
|
|||
|
|
|||
|
Value - Supplies the value that is written to the specified register.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
//
|
|||
|
// Write the realtime clock register value.
|
|||
|
//
|
|||
|
WRITE_REGISTER_UCHAR (&NVRAM->NvramIndexLo, (RTC_BASE + Register) & 0xFF);
|
|||
|
WRITE_REGISTER_UCHAR (&NVRAM->NvramIndexHi, (RTC_BASE + Register) >> 8);
|
|||
|
WRITE_REGISTER_UCHAR (&NVRAM->NvramData, Value);
|
|||
|
}
|
|||
|
|
|||
|
static VOID
|
|||
|
HalpWriteClockRegister (
|
|||
|
UCHAR Register,
|
|||
|
UCHAR Value
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine writes the specified value to the specified realtime
|
|||
|
clock register.
|
|||
|
|
|||
|
The value is first converted to BCD format before being written to
|
|||
|
the clock register.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Register - Supplies the number of the register whose value is written.
|
|||
|
|
|||
|
Value - Supplies the value that is written to the specified register.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UCHAR BcdValue;
|
|||
|
|
|||
|
//
|
|||
|
// First ensure that the value is in range 0 - 99
|
|||
|
//
|
|||
|
BcdValue = (((Value % 100) / 10) << 4) | (Value % 10);
|
|||
|
HalpWriteRawClockRegister(Register, BcdValue);
|
|||
|
}
|