2019-05-27 08:55:01 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2011-09-19 17:45:01 +00:00
/*
* PowerNV Real Time Clock .
*
* Copyright 2011 IBM Corp .
*/
# include <linux/kernel.h>
# include <linux/time.h>
# include <linux/bcd.h>
# include <linux/rtc.h>
# include <linux/delay.h>
2014-10-14 14:08:36 +05:30
# include <linux/platform_device.h>
# include <linux/of_platform.h>
2011-09-19 17:45:01 +00:00
# include <asm/opal.h>
# include <asm/firmware.h>
2013-11-29 14:22:48 +11:00
# include <asm/machdep.h>
2011-09-19 17:45:01 +00:00
static void opal_to_tm ( u32 y_m_d , u64 h_m_s_ms , struct rtc_time * tm )
{
tm - > tm_year = ( ( bcd2bin ( y_m_d > > 24 ) * 100 ) +
bcd2bin ( ( y_m_d > > 16 ) & 0xff ) ) - 1900 ;
tm - > tm_mon = bcd2bin ( ( y_m_d > > 8 ) & 0xff ) - 1 ;
tm - > tm_mday = bcd2bin ( y_m_d & 0xff ) ;
tm - > tm_hour = bcd2bin ( ( h_m_s_ms > > 56 ) & 0xff ) ;
tm - > tm_min = bcd2bin ( ( h_m_s_ms > > 48 ) & 0xff ) ;
tm - > tm_sec = bcd2bin ( ( h_m_s_ms > > 40 ) & 0xff ) ;
2015-12-15 18:09:14 +11:00
tm - > tm_wday = - 1 ;
2011-09-19 17:45:01 +00:00
}
2018-04-23 10:36:40 +02:00
time64_t __init opal_get_boot_time ( void )
2011-09-19 17:45:01 +00:00
{
struct rtc_time tm ;
u32 y_m_d ;
u64 h_m_s_ms ;
2013-09-23 12:05:05 +10:00
__be32 __y_m_d ;
__be64 __h_m_s_ms ;
2011-09-19 17:45:01 +00:00
long rc = OPAL_BUSY ;
2014-08-19 14:48:00 +10:00
if ( ! opal_check_token ( OPAL_RTC_READ ) )
2014-10-14 14:08:36 +05:30
return 0 ;
2014-08-19 14:48:00 +10:00
2011-09-19 17:45:01 +00:00
while ( rc = = OPAL_BUSY | | rc = = OPAL_BUSY_EVENT ) {
2013-09-23 12:05:05 +10:00
rc = opal_rtc_read ( & __y_m_d , & __h_m_s_ms ) ;
2018-04-10 21:49:32 +10:00
if ( rc = = OPAL_BUSY_EVENT ) {
mdelay ( OPAL_BUSY_DELAY_MS ) ;
2011-09-19 17:45:01 +00:00
opal_poll_events ( NULL ) ;
2018-04-10 21:49:32 +10:00
} else if ( rc = = OPAL_BUSY ) {
mdelay ( OPAL_BUSY_DELAY_MS ) ;
}
2011-09-19 17:45:01 +00:00
}
2014-08-19 14:48:00 +10:00
if ( rc ! = OPAL_SUCCESS )
2014-10-14 14:08:36 +05:30
return 0 ;
2014-08-19 14:48:00 +10:00
2013-09-23 12:05:05 +10:00
y_m_d = be32_to_cpu ( __y_m_d ) ;
h_m_s_ms = be64_to_cpu ( __h_m_s_ms ) ;
2011-09-19 17:45:01 +00:00
opal_to_tm ( y_m_d , h_m_s_ms , & tm ) ;
2018-04-23 10:36:40 +02:00
return rtc_tm_to_time64 ( & tm ) ;
2011-09-19 17:45:01 +00:00
}
2014-10-14 14:08:36 +05:30
static __init int opal_time_init ( void )
2011-09-19 17:45:01 +00:00
{
2014-10-14 14:08:36 +05:30
struct platform_device * pdev ;
struct device_node * rtc ;
2011-09-19 17:45:01 +00:00
2014-10-14 14:08:36 +05:30
rtc = of_find_node_by_path ( " /ibm,opal/rtc " ) ;
if ( rtc ) {
pdev = of_platform_device_create ( rtc , " opal-rtc " , NULL ) ;
of_node_put ( rtc ) ;
} else {
if ( opal_check_token ( OPAL_RTC_READ ) | |
opal_check_token ( OPAL_READ_TPO ) )
pdev = platform_device_register_simple ( " opal-rtc " , - 1 ,
NULL , 0 ) ;
2011-09-19 17:45:01 +00:00
else
2014-10-14 14:08:36 +05:30
return - ENODEV ;
2011-09-19 17:45:01 +00:00
}
2014-10-14 14:08:36 +05:30
return PTR_ERR_OR_ZERO ( pdev ) ;
2011-09-19 17:45:01 +00:00
}
2014-10-14 14:08:36 +05:30
machine_subsys_initcall ( powernv , opal_time_init ) ;