cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

time.c (4344B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  (c) Copyright 2004 Benjamin Herrenschmidt (benh@kernel.crashing.org),
      4 *                     IBM Corp. 
      5 */
      6
      7#undef DEBUG
      8
      9#include <linux/errno.h>
     10#include <linux/sched.h>
     11#include <linux/kernel.h>
     12#include <linux/param.h>
     13#include <linux/string.h>
     14#include <linux/mm.h>
     15#include <linux/init.h>
     16#include <linux/time.h>
     17#include <linux/adb.h>
     18#include <linux/pmu.h>
     19#include <linux/interrupt.h>
     20#include <linux/mc146818rtc.h>
     21#include <linux/bcd.h>
     22#include <linux/of_address.h>
     23
     24#include <asm/sections.h>
     25#include <asm/io.h>
     26#include <asm/machdep.h>
     27#include <asm/time.h>
     28
     29#include "maple.h"
     30
     31#ifdef DEBUG
     32#define DBG(x...) printk(x)
     33#else
     34#define DBG(x...)
     35#endif
     36
     37static int maple_rtc_addr;
     38
     39static int maple_clock_read(int addr)
     40{
     41	outb_p(addr, maple_rtc_addr);
     42	return inb_p(maple_rtc_addr+1);
     43}
     44
     45static void maple_clock_write(unsigned long val, int addr)
     46{
     47	outb_p(addr, maple_rtc_addr);
     48	outb_p(val, maple_rtc_addr+1);
     49}
     50
     51void maple_get_rtc_time(struct rtc_time *tm)
     52{
     53	do {
     54		tm->tm_sec = maple_clock_read(RTC_SECONDS);
     55		tm->tm_min = maple_clock_read(RTC_MINUTES);
     56		tm->tm_hour = maple_clock_read(RTC_HOURS);
     57		tm->tm_mday = maple_clock_read(RTC_DAY_OF_MONTH);
     58		tm->tm_mon = maple_clock_read(RTC_MONTH);
     59		tm->tm_year = maple_clock_read(RTC_YEAR);
     60	} while (tm->tm_sec != maple_clock_read(RTC_SECONDS));
     61
     62	if (!(maple_clock_read(RTC_CONTROL) & RTC_DM_BINARY)
     63	    || RTC_ALWAYS_BCD) {
     64		tm->tm_sec = bcd2bin(tm->tm_sec);
     65		tm->tm_min = bcd2bin(tm->tm_min);
     66		tm->tm_hour = bcd2bin(tm->tm_hour);
     67		tm->tm_mday = bcd2bin(tm->tm_mday);
     68		tm->tm_mon = bcd2bin(tm->tm_mon);
     69		tm->tm_year = bcd2bin(tm->tm_year);
     70	  }
     71	if ((tm->tm_year + 1900) < 1970)
     72		tm->tm_year += 100;
     73
     74	tm->tm_wday = -1;
     75}
     76
     77int maple_set_rtc_time(struct rtc_time *tm)
     78{
     79	unsigned char save_control, save_freq_select;
     80	int sec, min, hour, mon, mday, year;
     81
     82	spin_lock(&rtc_lock);
     83
     84	save_control = maple_clock_read(RTC_CONTROL); /* tell the clock it's being set */
     85
     86	maple_clock_write((save_control|RTC_SET), RTC_CONTROL);
     87
     88	save_freq_select = maple_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
     89
     90	maple_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
     91
     92	sec = tm->tm_sec;
     93	min = tm->tm_min;
     94	hour = tm->tm_hour;
     95	mon = tm->tm_mon;
     96	mday = tm->tm_mday;
     97	year = tm->tm_year;
     98
     99	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
    100		sec = bin2bcd(sec);
    101		min = bin2bcd(min);
    102		hour = bin2bcd(hour);
    103		mon = bin2bcd(mon);
    104		mday = bin2bcd(mday);
    105		year = bin2bcd(year);
    106	}
    107	maple_clock_write(sec, RTC_SECONDS);
    108	maple_clock_write(min, RTC_MINUTES);
    109	maple_clock_write(hour, RTC_HOURS);
    110	maple_clock_write(mon, RTC_MONTH);
    111	maple_clock_write(mday, RTC_DAY_OF_MONTH);
    112	maple_clock_write(year, RTC_YEAR);
    113
    114	/* The following flags have to be released exactly in this order,
    115	 * otherwise the DS12887 (popular MC146818A clone with integrated
    116	 * battery and quartz) will not reset the oscillator and will not
    117	 * update precisely 500 ms later. You won't find this mentioned in
    118	 * the Dallas Semiconductor data sheets, but who believes data
    119	 * sheets anyway ...                           -- Markus Kuhn
    120	 */
    121	maple_clock_write(save_control, RTC_CONTROL);
    122	maple_clock_write(save_freq_select, RTC_FREQ_SELECT);
    123
    124	spin_unlock(&rtc_lock);
    125
    126	return 0;
    127}
    128
    129static struct resource rtc_iores = {
    130	.name = "rtc",
    131	.flags = IORESOURCE_IO | IORESOURCE_BUSY,
    132};
    133
    134time64_t __init maple_get_boot_time(void)
    135{
    136	struct rtc_time tm;
    137	struct device_node *rtcs;
    138
    139	rtcs = of_find_compatible_node(NULL, "rtc", "pnpPNP,b00");
    140	if (rtcs) {
    141		struct resource r;
    142		if (of_address_to_resource(rtcs, 0, &r)) {
    143			printk(KERN_EMERG "Maple: Unable to translate RTC"
    144			       " address\n");
    145			goto bail;
    146		}
    147		if (!(r.flags & IORESOURCE_IO)) {
    148			printk(KERN_EMERG "Maple: RTC address isn't PIO!\n");
    149			goto bail;
    150		}
    151		maple_rtc_addr = r.start;
    152		printk(KERN_INFO "Maple: Found RTC at IO 0x%x\n",
    153		       maple_rtc_addr);
    154	}
    155 bail:
    156	if (maple_rtc_addr == 0) {
    157		maple_rtc_addr = RTC_PORT(0); /* legacy address */
    158		printk(KERN_INFO "Maple: No device node for RTC, assuming "
    159		       "legacy address (0x%x)\n", maple_rtc_addr);
    160	}
    161
    162	rtc_iores.start = maple_rtc_addr;
    163	rtc_iores.end = maple_rtc_addr + 7;
    164	request_resource(&ioport_resource, &rtc_iores);
    165
    166	maple_get_rtc_time(&tm);
    167	return rtc_tm_to_time64(&tm);
    168}
    169