1*aaf9128aSKuninori Morimoto // SPDX-License-Identifier: GPL-2.0 2da2014a2SPaul Mundt /* 3da2014a2SPaul Mundt * arch/sh/boards/dreamcast/rtc.c 4da2014a2SPaul Mundt * 5da2014a2SPaul Mundt * Dreamcast AICA RTC routines. 6da2014a2SPaul Mundt * 7da2014a2SPaul Mundt * Copyright (c) 2001, 2002 M. R. Brown <mrbrown@0xd6.org> 8da2014a2SPaul Mundt * Copyright (c) 2002 Paul Mundt <lethal@chaoticdreams.org> 9da2014a2SPaul Mundt */ 10da2014a2SPaul Mundt 11da2014a2SPaul Mundt #include <linux/time.h> 12da2014a2SPaul Mundt #include <asm/rtc.h> 13da2014a2SPaul Mundt #include <asm/io.h> 14da2014a2SPaul Mundt 15da2014a2SPaul Mundt /* The AICA RTC has an Epoch of 1/1/1950, so we must subtract 20 years (in 16da2014a2SPaul Mundt seconds) to get the standard Unix Epoch when getting the time, and add 17da2014a2SPaul Mundt 20 years when setting the time. */ 18da2014a2SPaul Mundt #define TWENTY_YEARS ((20 * 365LU + 5) * 86400) 19da2014a2SPaul Mundt 20da2014a2SPaul Mundt /* The AICA RTC is represented by a 32-bit seconds counter stored in 2 16-bit 21da2014a2SPaul Mundt registers.*/ 22da2014a2SPaul Mundt #define AICA_RTC_SECS_H 0xa0710000 23da2014a2SPaul Mundt #define AICA_RTC_SECS_L 0xa0710004 24da2014a2SPaul Mundt 25da2014a2SPaul Mundt /** 26da2014a2SPaul Mundt * aica_rtc_gettimeofday - Get the time from the AICA RTC 27da2014a2SPaul Mundt * @ts: pointer to resulting timespec 28da2014a2SPaul Mundt * 29da2014a2SPaul Mundt * Grabs the current RTC seconds counter and adjusts it to the Unix Epoch. 30da2014a2SPaul Mundt */ 31da2014a2SPaul Mundt static void aica_rtc_gettimeofday(struct timespec *ts) 32da2014a2SPaul Mundt { 33da2014a2SPaul Mundt unsigned long val1, val2; 34da2014a2SPaul Mundt 35da2014a2SPaul Mundt do { 369d56dd3bSPaul Mundt val1 = ((__raw_readl(AICA_RTC_SECS_H) & 0xffff) << 16) | 379d56dd3bSPaul Mundt (__raw_readl(AICA_RTC_SECS_L) & 0xffff); 38da2014a2SPaul Mundt 399d56dd3bSPaul Mundt val2 = ((__raw_readl(AICA_RTC_SECS_H) & 0xffff) << 16) | 409d56dd3bSPaul Mundt (__raw_readl(AICA_RTC_SECS_L) & 0xffff); 41da2014a2SPaul Mundt } while (val1 != val2); 42da2014a2SPaul Mundt 43da2014a2SPaul Mundt ts->tv_sec = val1 - TWENTY_YEARS; 44da2014a2SPaul Mundt 45da2014a2SPaul Mundt /* Can't get nanoseconds with just a seconds counter. */ 46da2014a2SPaul Mundt ts->tv_nsec = 0; 47da2014a2SPaul Mundt } 48da2014a2SPaul Mundt 49da2014a2SPaul Mundt /** 50da2014a2SPaul Mundt * aica_rtc_settimeofday - Set the AICA RTC to the current time 51da2014a2SPaul Mundt * @secs: contains the time_t to set 52da2014a2SPaul Mundt * 53da2014a2SPaul Mundt * Adjusts the given @tv to the AICA Epoch and sets the RTC seconds counter. 54da2014a2SPaul Mundt */ 55da2014a2SPaul Mundt static int aica_rtc_settimeofday(const time_t secs) 56da2014a2SPaul Mundt { 57da2014a2SPaul Mundt unsigned long val1, val2; 58da2014a2SPaul Mundt unsigned long adj = secs + TWENTY_YEARS; 59da2014a2SPaul Mundt 60da2014a2SPaul Mundt do { 619d56dd3bSPaul Mundt __raw_writel((adj & 0xffff0000) >> 16, AICA_RTC_SECS_H); 629d56dd3bSPaul Mundt __raw_writel((adj & 0xffff), AICA_RTC_SECS_L); 63da2014a2SPaul Mundt 649d56dd3bSPaul Mundt val1 = ((__raw_readl(AICA_RTC_SECS_H) & 0xffff) << 16) | 659d56dd3bSPaul Mundt (__raw_readl(AICA_RTC_SECS_L) & 0xffff); 66da2014a2SPaul Mundt 679d56dd3bSPaul Mundt val2 = ((__raw_readl(AICA_RTC_SECS_H) & 0xffff) << 16) | 689d56dd3bSPaul Mundt (__raw_readl(AICA_RTC_SECS_L) & 0xffff); 69da2014a2SPaul Mundt } while (val1 != val2); 70da2014a2SPaul Mundt 71da2014a2SPaul Mundt return 0; 72da2014a2SPaul Mundt } 73da2014a2SPaul Mundt 74da2014a2SPaul Mundt void aica_time_init(void) 75da2014a2SPaul Mundt { 76da2014a2SPaul Mundt rtc_sh_get_time = aica_rtc_gettimeofday; 77da2014a2SPaul Mundt rtc_sh_set_time = aica_rtc_settimeofday; 78da2014a2SPaul Mundt } 79da2014a2SPaul Mundt 80