18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 1991, 1992, 1995 Linus Torvalds 48c2ecf20Sopenharmony_ci * Copyright (C) 2000, 2003 Maciej W. Rozycki 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This file contains the time handling details for PC-style clocks as 78c2ecf20Sopenharmony_ci * found in some MIPS systems. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#include <linux/bcd.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/mc146818rtc.h> 138c2ecf20Sopenharmony_ci#include <linux/param.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <asm/cpu-features.h> 168c2ecf20Sopenharmony_ci#include <asm/ds1287.h> 178c2ecf20Sopenharmony_ci#include <asm/time.h> 188c2ecf20Sopenharmony_ci#include <asm/dec/interrupts.h> 198c2ecf20Sopenharmony_ci#include <asm/dec/ioasic.h> 208c2ecf20Sopenharmony_ci#include <asm/dec/machtype.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_civoid read_persistent_clock64(struct timespec64 *ts) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci unsigned int year, mon, day, hour, min, sec, real_year; 258c2ecf20Sopenharmony_ci unsigned long flags; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci spin_lock_irqsave(&rtc_lock, flags); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci do { 308c2ecf20Sopenharmony_ci sec = CMOS_READ(RTC_SECONDS); 318c2ecf20Sopenharmony_ci min = CMOS_READ(RTC_MINUTES); 328c2ecf20Sopenharmony_ci hour = CMOS_READ(RTC_HOURS); 338c2ecf20Sopenharmony_ci day = CMOS_READ(RTC_DAY_OF_MONTH); 348c2ecf20Sopenharmony_ci mon = CMOS_READ(RTC_MONTH); 358c2ecf20Sopenharmony_ci year = CMOS_READ(RTC_YEAR); 368c2ecf20Sopenharmony_ci /* 378c2ecf20Sopenharmony_ci * The PROM will reset the year to either '72 or '73. 388c2ecf20Sopenharmony_ci * Therefore we store the real year separately, in one 398c2ecf20Sopenharmony_ci * of unused BBU RAM locations. 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci real_year = CMOS_READ(RTC_DEC_YEAR); 428c2ecf20Sopenharmony_ci } while (sec != CMOS_READ(RTC_SECONDS)); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rtc_lock, flags); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { 478c2ecf20Sopenharmony_ci sec = bcd2bin(sec); 488c2ecf20Sopenharmony_ci min = bcd2bin(min); 498c2ecf20Sopenharmony_ci hour = bcd2bin(hour); 508c2ecf20Sopenharmony_ci day = bcd2bin(day); 518c2ecf20Sopenharmony_ci mon = bcd2bin(mon); 528c2ecf20Sopenharmony_ci year = bcd2bin(year); 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci year += real_year - 72 + 2000; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci ts->tv_sec = mktime64(year, mon, day, hour, min, sec); 588c2ecf20Sopenharmony_ci ts->tv_nsec = 0; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * In order to set the CMOS clock precisely, update_persistent_clock64 has to 638c2ecf20Sopenharmony_ci * be called 500 ms after the second nowtime has started, because when 648c2ecf20Sopenharmony_ci * nowtime is written into the registers of the CMOS clock, it will 658c2ecf20Sopenharmony_ci * jump to the next second precisely 500 ms later. Check the Dallas 668c2ecf20Sopenharmony_ci * DS1287 data sheet for details. 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_ciint update_persistent_clock64(struct timespec64 now) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci time64_t nowtime = now.tv_sec; 718c2ecf20Sopenharmony_ci int retval = 0; 728c2ecf20Sopenharmony_ci int real_seconds, real_minutes, cmos_minutes; 738c2ecf20Sopenharmony_ci unsigned char save_control, save_freq_select; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* irq are locally disabled here */ 768c2ecf20Sopenharmony_ci spin_lock(&rtc_lock); 778c2ecf20Sopenharmony_ci /* tell the clock it's being set */ 788c2ecf20Sopenharmony_ci save_control = CMOS_READ(RTC_CONTROL); 798c2ecf20Sopenharmony_ci CMOS_WRITE((save_control | RTC_SET), RTC_CONTROL); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* stop and reset prescaler */ 828c2ecf20Sopenharmony_ci save_freq_select = CMOS_READ(RTC_FREQ_SELECT); 838c2ecf20Sopenharmony_ci CMOS_WRITE((save_freq_select | RTC_DIV_RESET2), RTC_FREQ_SELECT); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci cmos_minutes = CMOS_READ(RTC_MINUTES); 868c2ecf20Sopenharmony_ci if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) 878c2ecf20Sopenharmony_ci cmos_minutes = bcd2bin(cmos_minutes); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /* 908c2ecf20Sopenharmony_ci * since we're only adjusting minutes and seconds, 918c2ecf20Sopenharmony_ci * don't interfere with hour overflow. This avoids 928c2ecf20Sopenharmony_ci * messing with unknown time zones but requires your 938c2ecf20Sopenharmony_ci * RTC not to be off by more than 15 minutes 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_ci real_minutes = div_s64_rem(nowtime, 60, &real_seconds); 968c2ecf20Sopenharmony_ci if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1) 978c2ecf20Sopenharmony_ci real_minutes += 30; /* correct for half hour time zone */ 988c2ecf20Sopenharmony_ci real_minutes %= 60; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (abs(real_minutes - cmos_minutes) < 30) { 1018c2ecf20Sopenharmony_ci if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { 1028c2ecf20Sopenharmony_ci real_seconds = bin2bcd(real_seconds); 1038c2ecf20Sopenharmony_ci real_minutes = bin2bcd(real_minutes); 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci CMOS_WRITE(real_seconds, RTC_SECONDS); 1068c2ecf20Sopenharmony_ci CMOS_WRITE(real_minutes, RTC_MINUTES); 1078c2ecf20Sopenharmony_ci } else { 1088c2ecf20Sopenharmony_ci printk_once(KERN_NOTICE 1098c2ecf20Sopenharmony_ci "set_rtc_mmss: can't update from %d to %d\n", 1108c2ecf20Sopenharmony_ci cmos_minutes, real_minutes); 1118c2ecf20Sopenharmony_ci retval = -1; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* The following flags have to be released exactly in this order, 1158c2ecf20Sopenharmony_ci * otherwise the DS1287 will not reset the oscillator and will not 1168c2ecf20Sopenharmony_ci * update precisely 500 ms later. You won't find this mentioned 1178c2ecf20Sopenharmony_ci * in the Dallas Semiconductor data sheets, but who believes data 1188c2ecf20Sopenharmony_ci * sheets anyway ... -- Markus Kuhn 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci CMOS_WRITE(save_control, RTC_CONTROL); 1218c2ecf20Sopenharmony_ci CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); 1228c2ecf20Sopenharmony_ci spin_unlock(&rtc_lock); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci return retval; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_civoid __init plat_time_init(void) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci int ioasic_clock = 0; 1308c2ecf20Sopenharmony_ci u32 start, end; 1318c2ecf20Sopenharmony_ci int i = HZ / 8; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* Set up the rate of periodic DS1287 interrupts. */ 1348c2ecf20Sopenharmony_ci ds1287_set_base_clock(HZ); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* On some I/O ASIC systems we have the I/O ASIC's counter. */ 1378c2ecf20Sopenharmony_ci if (IOASIC) 1388c2ecf20Sopenharmony_ci ioasic_clock = dec_ioasic_clocksource_init() == 0; 1398c2ecf20Sopenharmony_ci if (cpu_has_counter) { 1408c2ecf20Sopenharmony_ci ds1287_timer_state(); 1418c2ecf20Sopenharmony_ci while (!ds1287_timer_state()) 1428c2ecf20Sopenharmony_ci ; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci start = read_c0_count(); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci while (i--) 1478c2ecf20Sopenharmony_ci while (!ds1287_timer_state()) 1488c2ecf20Sopenharmony_ci ; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci end = read_c0_count(); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci mips_hpt_frequency = (end - start) * 8; 1538c2ecf20Sopenharmony_ci printk(KERN_INFO "MIPS counter frequency %dHz\n", 1548c2ecf20Sopenharmony_ci mips_hpt_frequency); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* 1578c2ecf20Sopenharmony_ci * All R4k DECstations suffer from the CP0 Count erratum, 1588c2ecf20Sopenharmony_ci * so we can't use the timer as a clock source, and a clock 1598c2ecf20Sopenharmony_ci * event both at a time. An accurate wall clock is more 1608c2ecf20Sopenharmony_ci * important than a high-precision interval timer so only 1618c2ecf20Sopenharmony_ci * use the timer as a clock source, and not a clock event 1628c2ecf20Sopenharmony_ci * if there's no I/O ASIC counter available to serve as a 1638c2ecf20Sopenharmony_ci * clock source. 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_ci if (!ioasic_clock) { 1668c2ecf20Sopenharmony_ci init_r4k_clocksource(); 1678c2ecf20Sopenharmony_ci mips_hpt_frequency = 0; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci ds1287_clockevent_init(dec_interrupt[DEC_IRQ_RTC]); 1728c2ecf20Sopenharmony_ci} 173