summaryrefslogblamecommitdiffstats
path: root/c/src/lib/libbsp/powerpc/ppcn_60x/tod/tod.c
blob: 22c7090beccd33af4ec459a5facd0a0c18fd9b3d (plain) (tree)

























































































                                                                           
       




































                                                                             
                                 



                         

                                 










                                                                    










                                                                       
                                                          


                                                     
                                                      


               
       
                        
                                










                                                                    










                                                                       
                                   
 
                                                          


                                                     
                                                          




                          

                                 





















                                                                          
                                 





                                                    
       
                     
                                


















                                                                       
                                 
































                                                                       
                                   
















                                                                             
                                                                

                                   
                                                      



                                                                              
                                                           
                                                      
                                                         
                                                     
                                              

                                                               
                                                          
                                                
                                                            
                                                
                                                            






































                                                                           
                                   

















                                                                                 
                                     
                                                       
                                            






















































                                                                        
                                                             

                           
                                          

                                                         





                                                                
















































                                                                          
                                                                  
                                                                          




                                                             


































































































                                                                                  



                   
/*
 *  COPYRIGHT (c) 1998 by Radstone Technology
 *
 *
 * THIS FILE IS PROVIDED TO YOU, THE USER, "AS IS", WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
 * AS TO THE QUALITY AND PERFORMANCE OF ALL CODE IN THIS FILE IS WITH YOU.
 *
 * You are hereby granted permission to use, copy, modify, and distribute
 * this file, provided that this notice, plus the above copyright notice
 * and disclaimer, appears in all copies. Radstone Technology will provide
 * no support for this code.
 *
 */

#define MIN_YEAR 1996

#include <stdlib.h>
#include "bsp.h"
#include "cmos.h"
#include "../nvram/mk48t18.h"

#define Bin2BCD(Value) (((Value / 10) << 4) | (Value % 10))
#define BCD2Bin(BcdValue) ((BcdValue >> 4) * 10 + (BcdValue & 0x0f))

/*
 * Private types
 */
typedef
void
(*PTIMESET)
(
	rtems_time_of_day *pTOD
);

typedef
boolean
(*PTIMEGET)
(
	rtems_time_of_day *pTOD
);

typedef struct _TIME_ENTRY_TABLE
{
    PTIMESET	SetTime;
    PTIMEGET	GetTime;
} TIME_ENTRY_TABLE, *PTIME_ENTRY_TABLE;

/*
 * Private routines
 */

/*
 * DS1385 specific routines
 */
static void timeDsSet(rtems_time_of_day *pTOD);
static boolean timeDsGet(rtems_time_of_day *pTOD);

/*
 * MK48T18 specific routines
 */
static void timeMkSet(rtems_time_of_day *pTOD);
static boolean timeMkGet(rtems_time_of_day *pTOD);

TIME_ENTRY_TABLE timeDsTable =
{
	timeDsSet,
	timeDsGet
};

TIME_ENTRY_TABLE timeMkTable =
{
	timeMkSet,
	timeMkGet
};

/*
 * Private variables
 */
static PTIME_ENTRY_TABLE pTimeFunc;

/*
 * Mutual-exclusion semaphore
 */
static rtems_id	semRTC;

/*
 * This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
 */
uint8_t
GregorianDay(rtems_time_of_day *pTOD)
{
	boolean isLeap;
	unsigned long leapsToDate;
	unsigned long lastYear;
	unsigned long day;
	unsigned long MonthOffset[] = { 0, 31, 59, 90, 120, 151,
					181, 212, 243, 273, 304, 334 };

	lastYear=pTOD->year-1;

	/*
	 * Number of leap corrections to apply up to end of last year
	 */
	leapsToDate = lastYear/4 - lastYear/100 + lastYear/400;

	/*
	 * This year is a leap year if it is divisible by 4 except when it is
	 * divisible by 100 unless it is divisible by 400
	 *
	 * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be
	 */
	isLeap = (pTOD->year%4==0) &&
			 ((pTOD->year%100!=0) || (pTOD->year%400==0));

	if(isLeap && (pTOD->month>2))
	{
		day=1;
	}
	else
	{
		day=0;
	}

	day += lastYear*365 + leapsToDate + MonthOffset[pTOD->month-1] +
		   pTOD->day;

	return((uint8_t)(day%7));
}

void
DsWriteRawClockRegister (
	uint8_t         Register,
	uint8_t         Value
)

/*++

Routine Description:

    This routine reads the specified realtime clock register.

    This function was added to bridge the BCD format of the IBM roms
    and the binary formate of NT

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.

--*/

{
	outport_byte((uint8_t*)RTC_PORT, Register & 0x7f);

	/* Read the realtime clock register value. */

	outport_byte((uint8_t*)(RTC_PORT + 1), Value);
	return;
}

uint8_t
DsReadRawClockRegister (
	uint8_t         Register
)

/*++

Routine Description:

    This routine reads the specified realtime clock register.

    This function was added to bridge the BCD format of the IBM roms
    and the binary formate of NT

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.

--*/

{
	uint8_t         ucDataByte;

	outport_byte((uint8_t*)RTC_PORT, Register & 0x7f);

	/* Read the realtime clock register value. */

	inport_byte((uint8_t*)(RTC_PORT + 1), ucDataByte);
	return ucDataByte;
}

void
DsWriteClockRegister (
	uint8_t         Register,
	uint8_t         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:

    The value of the register is returned as the function value.

--*/

{
	uint8_t         BcdValue;

	BcdValue = Bin2BCD(Value);
	DsWriteRawClockRegister(Register, BcdValue);
	return;
}

uint8_t
DsReadClockRegister (
	uint8_t         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.

--*/

{
	uint8_t         BcdValue;

	BcdValue =  DsReadRawClockRegister(Register);
	return BCD2Bin(BcdValue);
}

void
timeDsSet (
    rtems_time_of_day *pTOD
    )

/*++

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:

    pTOD - 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.

--*/

{
	uint8_t         ucDataByte;
	PCMOS_MAP pCMOS = (PCMOS_MAP)0;

	/* 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. */

	ucDataByte = DsReadRawClockRegister(RTC_CONTROL_REGISTERD);
	if (ucDataByte&DS1385_REGD_VALID)
	{
		/* Set the realtime clock control to set the time. */

		ucDataByte = DS1385_REGB_HOURS_FMT | DS1385_REGB_SET_TIME;
		DsWriteRawClockRegister(RTC_CONTROL_REGISTERB, ucDataByte);

		/* Write the realtime clock values. */

		DsWriteClockRegister(RTC_YEAR,
				     (uint8_t)(pTOD->year%100));
		if(pTOD->year>=100)
		{
			DsWriteClockRegister((uint8_t)
					     ((unsigned long)&pCMOS->Century),
					     pTOD->year/100);
		}
		DsWriteClockRegister(RTC_MONTH,
				     (uint8_t)pTOD->month);
		DsWriteClockRegister(RTC_DAY_OF_MONTH,
				     (uint8_t)pTOD->day);
		DsWriteClockRegister(RTC_DAY_OF_WEEK,
				     (uint8_t)
				     (GregorianDay(pTOD) + 1));
		DsWriteClockRegister(RTC_HOUR,
				     (uint8_t)pTOD->hour);
		DsWriteClockRegister(RTC_MINUTE,
				     (uint8_t)pTOD->minute);
		DsWriteClockRegister(RTC_SECOND,
				     (uint8_t)pTOD->second);

		/* Set the realtime clock control to update the time. */

		ucDataByte &= ~DS1385_REGB_SET_TIME;
		DsWriteRawClockRegister(RTC_CONTROL_REGISTERB, ucDataByte);
		return;

	}
	else
	{
		return;
	}
}

boolean
timeDsGet (
    rtems_time_of_day *pTOD
    )

/*++

Routine Description:

    This routine queries the realtime clock.

Arguments:

    pTOD - 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.

--*/

{
	uint8_t         ucDataByte;
	PCMOS_MAP pCMOS = (PCMOS_MAP)0;

	/* 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. */

	ucDataByte = DsReadRawClockRegister(RTC_CONTROL_REGISTERD);
	if(ucDataByte&DS1385_REGD_VALID)
	{
		/* Wait until the realtime clock is not being updated. */

		do
		{
			ucDataByte=DsReadRawClockRegister(RTC_CONTROL_REGISTERA);
		} while (ucDataByte&DS1385_REGA_UIP);

		/* Read the realtime clock values. */

		pTOD->year=(uint16_t)
				  (DsReadClockRegister(
				   (uint8_t)
				   (unsigned long)&pCMOS->Century)
				  *100 + DsReadClockRegister(RTC_YEAR));
		pTOD->month=DsReadClockRegister(RTC_MONTH);
		pTOD->day=DsReadClockRegister(RTC_DAY_OF_MONTH);
		pTOD->hour=DsReadClockRegister(RTC_HOUR);
		pTOD->minute=DsReadClockRegister(RTC_MINUTE);
		pTOD->second=DsReadClockRegister(RTC_SECOND);
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

void
timeMkSet (
    rtems_time_of_day *pTOD
    )

/*++

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:

    pTOD - 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.

--*/

{
	PMK48T18_NVRAM_MAP pNvRAM = MK48T18_BASE;

	/*
	 * Set the RTC into write mode
	 */
	pNvRAM->CMOS.Control|=MK48T18_CTRL_WRITE;
	EIEIO;

	/*
	 * Write the realtime clock values.
	 */

	pNvRAM->CMOS.Year = (uint8_t)Bin2BCD(pTOD->year%100);
	if(pTOD->year>=100)
	{
	    pNvRAM->CMOS.Century=(uint8_t)
	    			 Bin2BCD(pTOD->year/100);
	}
	pNvRAM->CMOS.Month  = (uint8_t)Bin2BCD(pTOD->month);
	pNvRAM->CMOS.Date   = (uint8_t)Bin2BCD(pTOD->day);
	pNvRAM->CMOS.Day    = (uint8_t)(GregorianDay(pTOD) + 1);
	pNvRAM->CMOS.Hour   = (uint8_t)Bin2BCD(pTOD->hour);
	pNvRAM->CMOS.Minute = (uint8_t)Bin2BCD(pTOD->minute);
	pNvRAM->CMOS.Second = (uint8_t)Bin2BCD(pTOD->second);

	/*
	 * Set the realtime clock control to update the time.
	 */

	EIEIO;
	pNvRAM->CMOS.Control&=~MK48T18_CTRL_WRITE;
}

boolean
timeMkGet (
    rtems_time_of_day *pTOD
    )

/*++

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:

    pTOD - 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.

--*/

{
	PMK48T18_NVRAM_MAP pNvRAM = MK48T18_BASE;

	/*
	 * Set the RTC into read mode
	 */
	pNvRAM->CMOS.Control|=MK48T18_CTRL_READ;
	EIEIO;

	/*
	 * Read the realtime clock values.
	 */

	pTOD->year = (uint16_t)(100*BCD2Bin(pNvRAM->CMOS.Century)+
					      BCD2Bin(pNvRAM->CMOS.Year));
	pTOD->month = (uint8_t)BCD2Bin(pNvRAM->CMOS.Month);
	pTOD->day = (uint8_t)BCD2Bin(pNvRAM->CMOS.Date);
	pTOD->hour = (uint8_t)BCD2Bin(pNvRAM->CMOS.Hour);
	pTOD->minute = (uint8_t)BCD2Bin(pNvRAM->CMOS.Minute);
	pTOD->second = (uint8_t)BCD2Bin(pNvRAM->CMOS.Second);

	/*
	 * Set the realtime clock control to normal mode.
	 */
	EIEIO;
	pNvRAM->CMOS.Control&=~MK48T18_CTRL_READ;

	return TRUE;
}

/*
 * Set up entry table
 */
void
InitializeRTC(void)
{
	rtems_status_code sc;

	switch(ucSystemType)
	{
		case SYS_TYPE_PPC1:
		{
			if(ucBoardRevMaj<5)
			{
				pTimeFunc=&timeDsTable;
				break;
			}
			/*
			 * For the 005 and later drop through to the PPC1a support
			 */
		}

		case SYS_TYPE_PPC1a:
		{
			pTimeFunc=&timeMkTable;
			break;
		}

		default:
		{
			pTimeFunc=&timeDsTable;
			break;
		}
	}

	/*
	 * Set up mutex semaphore
	 */
	sc = rtems_semaphore_create (
		rtems_build_name ('R', 'T', 'C', 's'),
		1,
		RTEMS_BINARY_SEMAPHORE |
		RTEMS_INHERIT_PRIORITY |
		RTEMS_PRIORITY,
		RTEMS_NO_PRIORITY,
		&semRTC);
	if (sc != RTEMS_SUCCESSFUL)
	{
		rtems_fatal_error_occurred (sc);
	}
}

void setRealTimeToRTEMS()
{
	rtems_time_of_day rtc_tod;

	rtems_semaphore_obtain(semRTC, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
	(pTimeFunc->GetTime)(&rtc_tod);
	rtems_semaphore_release(semRTC);

	/*
	 * Millenium fix...
	 *
	 * If year is earlier than MIN_YEAR then assume the clock has wrapped from
	 * 1999 to 1900 so advance by a century
	 */
	if(rtc_tod.year<MIN_YEAR)
	{
		rtc_tod.year+=100;
		rtems_semaphore_obtain(semRTC, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
		(pTimeFunc->SetTime)(&rtc_tod);
		rtems_semaphore_release(semRTC);
	}

	rtc_tod.ticks=0;

	rtems_clock_set( &rtc_tod );
}

void setRealTimeFromRTEMS()
{
	rtems_time_of_day rtems_tod;

	rtems_clock_get( RTEMS_CLOCK_GET_TOD, &rtems_tod );
	rtems_semaphore_obtain(semRTC, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
	(pTimeFunc->SetTime)(&rtems_tod);
	rtems_semaphore_release(semRTC);
}

int checkRealTime()
{
  return 0;
}