NT4/private/ntos/nthals/halfire/ppc/fpds1385.c
2020-09-30 17:12:29 +02:00

373 lines
9.7 KiB
C

/*
* Copyright (c) 1995 FirePower Systems, Inc.
* DO NOT DISTRIBUTE without permission
*
* $RCSfile: fpds1385.c $
* $Revision: 1.14 $
* $Date: 1996/05/20 22:35:57 $
* $Locker: $
*
* fpds1385.c: set of routines to init, and maintain the DS1385
*
*/
#include "fpdebug.h"
#include "halp.h"
#include "phsystem.h"
#include "fpreg.h"
#include "fpio.h" // pick up the io space register access macros
#include "fpds1385.h" // defines specific to the dallas 1385
#define DS1385_BAILOUT_COUNT 10
UCHAR OriginalA; // storage location for rtc data in control reg a
UCHAR OriginalB; // storage location for rtc data in control reg b
BOOLEAN RtcBinaryMode = FALSE;
// Flag to indicate if RTC is programmed in BINHEX or
// BCD format
BOOLEAN RtcFailure = FALSE;
// Flag to indicate if the RTC was read correctly
BOOLEAN NvramFailure = FALSE;
// Flag to indicate if the NVRAM was read correctly
ULONG TotalDs1385Failures = 0;
// Keep track of failures to read the DS1385
/*
* HalpInitFireRTC:
*
* Make sure the dallas 1385 chip is correctly setup. This means that
* all the configuration bits are in place. If the chip is not correctly
* setup, save the time off, fix the bits, recalculate the time if needed,
* and restore the time. Particularly, if the "DataMode" or "24/12 hour"
* bits are changed the time will need to be recalculated.
*/
BOOLEAN
HalpInitFirePowerRTC( VOID )
{
TIME_FIELDS TimeFields;
UCHAR tval;
BOOLEAN Status = FALSE;
UCHAR ds1385Data;
HDBG(DBG_INTERNAL, HalpDebugPrint("HalpInitFirePowerRTC: begin \n"););
if ( !(HalQueryRealTimeClock( &TimeFields )) ) {
HalDisplayString("Not sure RTC is initted \n");
}
//
// Make sure the time is valid before worrying about any of the bits.
//
ds1385Data = HalpDS1385ReadReg(RTC_CONTROL_REGISTERD);
if ( ds1385Data & RTC_VRT ) {
//
// Verify that the DataMode is BCD
// the time style is 24 hour,
// that Daylight Savings is NOT enabled,
// that the square wave output is enabled.
//
tval = HalpDS1385ReadReg(RTC_CONTROL_REGISTERB);
OriginalB = tval;
HDBG(DBG_GENERAL,
HalpDebugPrint("HalpInitFirePowerRTC: register b is %x \n",
OriginalB););
HalpDS1385WriteReg(RTC_CONTROL_REGISTERB,
RTC_24_HR |
//
// for consistency with firmware, setup the RTC
// to maintain the time in BCD format rather
// than binary
//
// RTC_BIN_MODE |
RTC_SQWE|
RTC_UIE |
RTC_PIE);
RtcBinaryMode = FALSE;
tval = HalpDS1385ReadReg(RTC_CONTROL_REGISTERA);
OriginalA = tval;
HDBG(DBG_GENERAL,
HalpDebugPrint("HalpInitFirePowerRTC: register a is %x\n",
OriginalA););
//
// Ensure the Oscillator is running and updating, not either
// stopped or counting but not updating.
//
if ((tval & ( RTC_DV1 | RTC_DV2 | RTC_DV0 )) != RTC_DV1 ) {
tval = RTC_DV1;
}
HalpDS1385WriteReg(RTC_CONTROL_REGISTERA, (UCHAR)(tval | RTC_4096_HZ));
//
// Clear the interrupt flag bits
//
tval = HalpDS1385ReadReg(RTC_CONTROL_REGISTERC);
//
// Finally, restore the time: HalSetRealTimeClock will take
// care of any BCD=BIN conversion necessary.
//
if ( HalSetRealTimeClock ( &TimeFields)) {
Status=TRUE;
}
} else {
HalDisplayString("RTC Time is invalid: battery is dead?\n");
}
HDBG(DBG_INTERNAL,
HalpDebugPrint("HalpInitFirePowerRTC: end \n"););
return(Status);
}
//
// write a byte to the specified DS1385 register.
// First acquire the spin lock to make sure something else is not
// trying to access the DS1385 (RTC or NVRAM). Then do the write
// Finally, release the spinlock.
//
VOID
HalpDS1385WriteReg(UCHAR reg, UCHAR value)
{
KIRQL OldIrql;
UCHAR data0, data1, data2;
ULONG failureCount = 0;
KeAcquireSpinLock(&HalpDS1385Lock, &OldIrql);
// We have a problem accessing the DS1385 correctly. To get around this,
// we use the Dave Stewart method; after writing the DS1385 regiser, we
// read it back 3 times - if
// one of the three values compares with the value written, we are
// done. If we do not get a comparison, throw all three values away and
// try the write
// again. If, after 10 interations we cannot read a consistent pair,
// we assert a failure flag; the routine calling us must decide what
// to do with the flag.
while (failureCount < DS1385_BAILOUT_COUNT) {
// Write the register
rIndexRTC = reg;
FireSyncRegister();
rDataRTC = value;
// make sure access to the chip is complete before releasing
// the spin lock
FireSyncRegister();
// Read it three times
rIndexRTC = reg;
FireSyncRegister();
data0 = rDataRTC;
rIndexRTC = reg;
FireSyncRegister();
data1 = rDataRTC;
rIndexRTC = reg;
FireSyncRegister();
data2 = rDataRTC;
if ((data0 == value) || (data1 == value) || (data2 == value)) {
break;
}
failureCount++;
}
if (failureCount == DS1385_BAILOUT_COUNT) {
RtcFailure = TRUE;
}
TotalDs1385Failures += failureCount;
KeReleaseSpinLock(&HalpDS1385Lock, OldIrql);
}
//
// read a byte from the specified DS1385 register.
// First acquire the spin lock to make sure something else is not
// trying to access the DS1385 (RTC or NVRAM). Then do the read
// Finally, release the spinlock.
//
UCHAR
HalpDS1385ReadReg(UCHAR reg)
{
KIRQL OldIrql;
UCHAR result = 0xff;
UCHAR data0, data1, data2;
ULONG failureCount = 0;
KeAcquireSpinLock(&HalpDS1385Lock, &OldIrql);
// We have a problem accessing the DS1385 correctly. To get around this,
// we use the Dave Stewart method; read the DS1385 register 3 times - if
// one of the three values compares with either of the other two, return
// it. If we do not get a comparison, throw all three values away and try
// again. If, after 10 interations we cannot read a consistent pair,
// we assert a failure flag; the routine calling us must decide what
// to do with the flag.
while (failureCount < DS1385_BAILOUT_COUNT) {
rIndexRTC = reg;
FireSyncRegister();
data0 = rDataRTC;
rIndexRTC = reg;
FireSyncRegister();
data1 = rDataRTC;
rIndexRTC = reg;
FireSyncRegister();
data2 = rDataRTC;
if ((data0 == data1) || (data0 == data2)) {
result = data0;
break;
}
if (data1 == data2) {
result = data1;
break;
}
failureCount++;
}
if (failureCount == DS1385_BAILOUT_COUNT) {
RtcFailure = TRUE;
}
TotalDs1385Failures += failureCount;
KeReleaseSpinLock(&HalpDS1385Lock, OldIrql);
return result;
}
//
// write a byte to the specified address in the DS1385 NVRAM.
// First acquire the spin lock to make sure something else is not
// trying to access the DS1385 (RTC or NVRAM). Then do the write
// Finally, release the spinlock.
//
VOID
HalpDS1385WriteNVRAM(USHORT addr, UCHAR value)
{
KIRQL OldIrql;
UCHAR data0, data1, data2;
ULONG failureCount = 0;
KeAcquireSpinLock(&HalpDS1385Lock, &OldIrql);
// We have a problem accessing the DS1385 correctly. To get around this,
// we use the Dave Stewart method; after writing the DS1385 regiser, we
// read it back 3 times - if
// one of the three values compares with the value written, we are
// done. If we do not get a comparison, throw all three values away and
// try the write
// again. If, after 10 interations we cannot read a consistent pair,
// we assert a failure flag; the routine calling us must decide what
// to do with the flag.
while (failureCount < DS1385_BAILOUT_COUNT) {
// Write the register
rNvramAddr0 = addr & 0xff;
FireSyncRegister();
rNvramAddr1 = addr >> 8;
FireSyncRegister();
rNvramData = value;
// make sure access to the chip is complete before releasing
// the spin lock
FireSyncRegister();
// Read the register three times
rNvramAddr0 = addr & 0xff;
FireSyncRegister();
rNvramAddr1 = addr >> 8;
FireSyncRegister();
data0 = rNvramData;
rNvramAddr0 = addr & 0xff;
FireSyncRegister();
rNvramAddr1 = addr >> 8;
FireSyncRegister();
data1 = rNvramData;
rNvramAddr0 = addr & 0xff;
FireSyncRegister();
rNvramAddr1 = addr >> 8;
FireSyncRegister();
data2 = rNvramData;
if ((data0 == value) || (data1 == value) || (data2 == value)) {
break;
}
failureCount++;
}
if (failureCount == DS1385_BAILOUT_COUNT) {
NvramFailure = TRUE;
}
TotalDs1385Failures += failureCount;
KeReleaseSpinLock(&HalpDS1385Lock, OldIrql);
}
//
// read a byte from the specified address in the DS1385 NVRAM.
// First acquire the spin lock to make sure something else is not
// trying to access the DS1385 (RTC or NVRAM). Then do the read
// Finally, release the spinlock.
//
UCHAR
HalpDS1385ReadNVRAM(USHORT addr)
{
KIRQL OldIrql;
UCHAR data0, data1, data2;
UCHAR result = 0xff;
ULONG failureCount = 0;
KeAcquireSpinLock(&HalpDS1385Lock, &OldIrql);
// We have a problem accessing the DS1385 correctly. To get around this,
// we use the Dave Stewart method; read the DS1385 register 3 times - if
// one of the three values compares with either of the other two, return
// it. If we do not get a comparison, throw all three values away and try
// again. If, after 10 interations we cannot read a consistent pair,
// we assert a failure flag; the routine calling us must decide what
// to do with the flag.
while (failureCount < DS1385_BAILOUT_COUNT) {
rNvramAddr0 = addr & 0xff;
FireSyncRegister();
rNvramAddr1 = addr >> 8;
FireSyncRegister();
data0 = rNvramData;
rNvramAddr0 = addr & 0xff;
FireSyncRegister();
rNvramAddr1 = addr >> 8;
FireSyncRegister();
data1 = rNvramData;
rNvramAddr0 = addr & 0xff;
FireSyncRegister();
rNvramAddr1 = addr >> 8;
FireSyncRegister();
data2 = rNvramData;
if ((data0 == data1) || (data0 == data2)) {
result = data0;
break;
}
if (data1 == data2) {
result = data1;
break;
}
failureCount++;
}
if (failureCount == DS1385_BAILOUT_COUNT) {
NvramFailure = TRUE;
}
TotalDs1385Failures += failureCount;
KeReleaseSpinLock(&HalpDS1385Lock, OldIrql);
return result;
}