Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
0004  *  Copyright (C) 2000, 2003  Maciej W. Rozycki
0005  *
0006  * This file contains the time handling details for PC-style clocks as
0007  * found in some MIPS systems.
0008  *
0009  */
0010 #include <linux/bcd.h>
0011 #include <linux/init.h>
0012 #include <linux/mc146818rtc.h>
0013 #include <linux/param.h>
0014 
0015 #include <asm/cpu-features.h>
0016 #include <asm/ds1287.h>
0017 #include <asm/time.h>
0018 #include <asm/dec/interrupts.h>
0019 #include <asm/dec/ioasic.h>
0020 #include <asm/dec/machtype.h>
0021 
0022 void read_persistent_clock64(struct timespec64 *ts)
0023 {
0024     unsigned int year, mon, day, hour, min, sec, real_year;
0025     unsigned long flags;
0026 
0027     spin_lock_irqsave(&rtc_lock, flags);
0028 
0029     do {
0030         sec = CMOS_READ(RTC_SECONDS);
0031         min = CMOS_READ(RTC_MINUTES);
0032         hour = CMOS_READ(RTC_HOURS);
0033         day = CMOS_READ(RTC_DAY_OF_MONTH);
0034         mon = CMOS_READ(RTC_MONTH);
0035         year = CMOS_READ(RTC_YEAR);
0036         /*
0037          * The PROM will reset the year to either '72 or '73.
0038          * Therefore we store the real year separately, in one
0039          * of unused BBU RAM locations.
0040          */
0041         real_year = CMOS_READ(RTC_DEC_YEAR);
0042     } while (sec != CMOS_READ(RTC_SECONDS));
0043 
0044     spin_unlock_irqrestore(&rtc_lock, flags);
0045 
0046     if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
0047         sec = bcd2bin(sec);
0048         min = bcd2bin(min);
0049         hour = bcd2bin(hour);
0050         day = bcd2bin(day);
0051         mon = bcd2bin(mon);
0052         year = bcd2bin(year);
0053     }
0054 
0055     year += real_year - 72 + 2000;
0056 
0057     ts->tv_sec = mktime64(year, mon, day, hour, min, sec);
0058     ts->tv_nsec = 0;
0059 }
0060 
0061 /*
0062  * In order to set the CMOS clock precisely, update_persistent_clock64 has to
0063  * be called 500 ms after the second nowtime has started, because when
0064  * nowtime is written into the registers of the CMOS clock, it will
0065  * jump to the next second precisely 500 ms later.  Check the Dallas
0066  * DS1287 data sheet for details.
0067  */
0068 int update_persistent_clock64(struct timespec64 now)
0069 {
0070     time64_t nowtime = now.tv_sec;
0071     int retval = 0;
0072     int real_seconds, real_minutes, cmos_minutes;
0073     unsigned char save_control, save_freq_select;
0074 
0075     /* irq are locally disabled here */
0076     spin_lock(&rtc_lock);
0077     /* tell the clock it's being set */
0078     save_control = CMOS_READ(RTC_CONTROL);
0079     CMOS_WRITE((save_control | RTC_SET), RTC_CONTROL);
0080 
0081     /* stop and reset prescaler */
0082     save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
0083     CMOS_WRITE((save_freq_select | RTC_DIV_RESET2), RTC_FREQ_SELECT);
0084 
0085     cmos_minutes = CMOS_READ(RTC_MINUTES);
0086     if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
0087         cmos_minutes = bcd2bin(cmos_minutes);
0088 
0089     /*
0090      * since we're only adjusting minutes and seconds,
0091      * don't interfere with hour overflow. This avoids
0092      * messing with unknown time zones but requires your
0093      * RTC not to be off by more than 15 minutes
0094      */
0095     real_minutes = div_s64_rem(nowtime, 60, &real_seconds);
0096     if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1)
0097         real_minutes += 30; /* correct for half hour time zone */
0098     real_minutes %= 60;
0099 
0100     if (abs(real_minutes - cmos_minutes) < 30) {
0101         if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
0102             real_seconds = bin2bcd(real_seconds);
0103             real_minutes = bin2bcd(real_minutes);
0104         }
0105         CMOS_WRITE(real_seconds, RTC_SECONDS);
0106         CMOS_WRITE(real_minutes, RTC_MINUTES);
0107     } else {
0108         printk_once(KERN_NOTICE
0109                "set_rtc_mmss: can't update from %d to %d\n",
0110                cmos_minutes, real_minutes);
0111         retval = -1;
0112     }
0113 
0114     /* The following flags have to be released exactly in this order,
0115      * otherwise the DS1287 will not reset the oscillator and will not
0116      * update precisely 500 ms later.  You won't find this mentioned
0117      * in the Dallas Semiconductor data sheets, but who believes data
0118      * sheets anyway ...                           -- Markus Kuhn
0119      */
0120     CMOS_WRITE(save_control, RTC_CONTROL);
0121     CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
0122     spin_unlock(&rtc_lock);
0123 
0124     return retval;
0125 }
0126 
0127 void __init plat_time_init(void)
0128 {
0129     int ioasic_clock = 0;
0130     u32 start, end;
0131     int i = HZ / 8;
0132 
0133     /* Set up the rate of periodic DS1287 interrupts. */
0134     ds1287_set_base_clock(HZ);
0135 
0136     /* On some I/O ASIC systems we have the I/O ASIC's counter.  */
0137     if (IOASIC)
0138         ioasic_clock = dec_ioasic_clocksource_init() == 0;
0139     if (cpu_has_counter) {
0140         ds1287_timer_state();
0141         while (!ds1287_timer_state())
0142             ;
0143 
0144         start = read_c0_count();
0145 
0146         while (i--)
0147             while (!ds1287_timer_state())
0148                 ;
0149 
0150         end = read_c0_count();
0151 
0152         mips_hpt_frequency = (end - start) * 8;
0153         printk(KERN_INFO "MIPS counter frequency %dHz\n",
0154             mips_hpt_frequency);
0155 
0156         /*
0157          * All R4k DECstations suffer from the CP0 Count erratum,
0158          * so we can't use the timer as a clock source, and a clock
0159          * event both at a time.  An accurate wall clock is more
0160          * important than a high-precision interval timer so only
0161          * use the timer as a clock source, and not a clock event
0162          * if there's no I/O ASIC counter available to serve as a
0163          * clock source.
0164          */
0165         if (!ioasic_clock) {
0166             init_r4k_clocksource();
0167             mips_hpt_frequency = 0;
0168         }
0169     }
0170 
0171     ds1287_clockevent_init(dec_interrupt[DEC_IRQ_RTC]);
0172 }