2005-04-16 15:20:36 -07:00
/*
* Copyright ( C ) 1991 , 1992 , 1995 Linus Torvalds
* Copyright ( C ) 2000 , 2003 Maciej W . Rozycki
*
* This file contains the time handling details for PC - style clocks as
* found in some MIPS systems .
*
*/
# include <linux/bcd.h>
# include <linux/init.h>
# include <linux/mc146818rtc.h>
# include <linux/param.h>
2008-04-25 12:11:44 +09:00
# include <asm/cpu-features.h>
# include <asm/ds1287.h>
# include <asm/time.h>
2005-04-16 15:20:36 -07:00
# include <asm/dec/interrupts.h>
# include <asm/dec/ioasic.h>
# include <asm/dec/machtype.h>
2009-08-14 15:47:31 +02:00
void read_persistent_clock ( struct timespec * ts )
2005-04-16 15:20:36 -07:00
{
unsigned int year , mon , day , hour , min , sec , real_year ;
2005-11-03 01:01:15 +09:00
unsigned long flags ;
2005-04-16 15:20:36 -07:00
2005-11-03 01:01:15 +09:00
spin_lock_irqsave ( & rtc_lock , flags ) ;
2006-03-28 01:56:06 -08:00
2005-04-16 15:20:36 -07:00
do {
sec = CMOS_READ ( RTC_SECONDS ) ;
min = CMOS_READ ( RTC_MINUTES ) ;
hour = CMOS_READ ( RTC_HOURS ) ;
day = CMOS_READ ( RTC_DAY_OF_MONTH ) ;
mon = CMOS_READ ( RTC_MONTH ) ;
year = CMOS_READ ( RTC_YEAR ) ;
2006-03-28 01:56:06 -08:00
/*
* The PROM will reset the year to either ' 72 or ' 73.
* Therefore we store the real year separately , in one
* of unused BBU RAM locations .
*/
real_year = CMOS_READ ( RTC_DEC_YEAR ) ;
2005-04-16 15:20:36 -07:00
} while ( sec ! = CMOS_READ ( RTC_SECONDS ) ) ;
2006-03-28 01:56:06 -08:00
spin_unlock_irqrestore ( & rtc_lock , flags ) ;
2005-04-16 15:20:36 -07:00
if ( ! ( CMOS_READ ( RTC_CONTROL ) & RTC_DM_BINARY ) | | RTC_ALWAYS_BCD ) {
2008-10-18 20:28:44 -07:00
sec = bcd2bin ( sec ) ;
min = bcd2bin ( min ) ;
hour = bcd2bin ( hour ) ;
day = bcd2bin ( day ) ;
mon = bcd2bin ( mon ) ;
year = bcd2bin ( year ) ;
2005-04-16 15:20:36 -07:00
}
2006-03-28 01:56:06 -08:00
2005-04-16 15:20:36 -07:00
year + = real_year - 72 + 2000 ;
2009-08-14 15:47:31 +02:00
ts - > tv_sec = mktime ( year , mon , day , hour , min , sec ) ;
ts - > tv_nsec = 0 ;
2005-04-16 15:20:36 -07:00
}
/*
2007-10-11 23:46:08 +01:00
* In order to set the CMOS clock precisely , rtc_mips_set_mmss has to
2005-04-16 15:20:36 -07:00
* be called 500 ms after the second nowtime has started , because when
* nowtime is written into the registers of the CMOS clock , it will
* jump to the next second precisely 500 ms later . Check the Dallas
* DS1287 data sheet for details .
*/
2007-10-11 23:46:08 +01:00
int rtc_mips_set_mmss ( unsigned long nowtime )
2005-04-16 15:20:36 -07:00
{
int retval = 0 ;
int real_seconds , real_minutes , cmos_minutes ;
unsigned char save_control , save_freq_select ;
2005-11-03 01:01:15 +09:00
/* irq are locally disabled here */
spin_lock ( & rtc_lock ) ;
2005-04-16 15:20:36 -07:00
/* tell the clock it's being set */
save_control = CMOS_READ ( RTC_CONTROL ) ;
CMOS_WRITE ( ( save_control | RTC_SET ) , RTC_CONTROL ) ;
/* stop and reset prescaler */
save_freq_select = CMOS_READ ( RTC_FREQ_SELECT ) ;
CMOS_WRITE ( ( save_freq_select | RTC_DIV_RESET2 ) , RTC_FREQ_SELECT ) ;
cmos_minutes = CMOS_READ ( RTC_MINUTES ) ;
if ( ! ( save_control & RTC_DM_BINARY ) | | RTC_ALWAYS_BCD )
2008-10-18 20:28:44 -07:00
cmos_minutes = bcd2bin ( cmos_minutes ) ;
2005-04-16 15:20:36 -07:00
/*
* since we ' re only adjusting minutes and seconds ,
* don ' t interfere with hour overflow . This avoids
* messing with unknown time zones but requires your
* RTC not to be off by more than 15 minutes
*/
real_seconds = nowtime % 60 ;
real_minutes = nowtime / 60 ;
if ( ( ( abs ( real_minutes - cmos_minutes ) + 15 ) / 30 ) & 1 )
real_minutes + = 30 ; /* correct for half hour time zone */
real_minutes % = 60 ;
if ( abs ( real_minutes - cmos_minutes ) < 30 ) {
if ( ! ( save_control & RTC_DM_BINARY ) | | RTC_ALWAYS_BCD ) {
2008-10-18 20:28:44 -07:00
real_seconds = bin2bcd ( real_seconds ) ;
real_minutes = bin2bcd ( real_minutes ) ;
2005-04-16 15:20:36 -07:00
}
CMOS_WRITE ( real_seconds , RTC_SECONDS ) ;
CMOS_WRITE ( real_minutes , RTC_MINUTES ) ;
} else {
2011-01-12 16:59:31 -08:00
printk_once ( KERN_NOTICE
2005-04-16 15:20:36 -07:00
" set_rtc_mmss: can't update from %d to %d \n " ,
cmos_minutes , real_minutes ) ;
retval = - 1 ;
}
/* The following flags have to be released exactly in this order,
* otherwise the DS1287 will not reset the oscillator and will not
* update precisely 500 ms later . You won ' t find this mentioned
* in the Dallas Semiconductor data sheets , but who believes data
* sheets anyway . . . - - Markus Kuhn
*/
CMOS_WRITE ( save_control , RTC_CONTROL ) ;
CMOS_WRITE ( save_freq_select , RTC_FREQ_SELECT ) ;
2005-11-03 01:01:15 +09:00
spin_unlock ( & rtc_lock ) ;
2005-04-16 15:20:36 -07:00
return retval ;
}
2008-04-25 12:11:44 +09:00
void __init plat_time_init ( void )
2005-04-16 15:20:36 -07:00
{
2008-04-25 12:11:44 +09:00
u32 start , end ;
int i = HZ / 10 ;
2005-04-16 15:20:36 -07:00
2008-04-25 12:11:44 +09:00
/* Set up the rate of periodic DS1287 interrupts. */
ds1287_set_base_clock ( HZ ) ;
2005-04-16 15:20:36 -07:00
2008-04-25 12:11:44 +09:00
if ( cpu_has_counter ) {
while ( ! ds1287_timer_state ( ) )
;
2005-04-16 15:20:36 -07:00
2008-04-25 12:11:44 +09:00
start = read_c0_count ( ) ;
2005-04-16 15:20:36 -07:00
2008-04-25 12:11:44 +09:00
while ( i - - )
while ( ! ds1287_timer_state ( ) )
;
end = read_c0_count ( ) ;
2005-04-16 15:20:36 -07:00
2008-04-25 12:11:44 +09:00
mips_hpt_frequency = ( end - start ) * 10 ;
printk ( KERN_INFO " MIPS counter frequency %dHz \n " ,
mips_hpt_frequency ) ;
} else if ( IOASIC )
2005-04-16 15:20:36 -07:00
/* For pre-R4k systems we use the I/O ASIC's counter. */
2008-04-24 09:48:40 +09:00
dec_ioasic_clocksource_init ( ) ;
2005-04-16 15:20:36 -07:00
2008-04-25 12:11:44 +09:00
ds1287_clockevent_init ( dec_interrupt [ DEC_IRQ_RTC ] ) ;
2005-04-16 15:20:36 -07:00
}