linux/arch/alpha/kernel/rtc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 *  linux/arch/alpha/kernel/rtc.c
   4 *
   5 *  Copyright (C) 1991, 1992, 1995, 1999, 2000  Linus Torvalds
   6 *
   7 * This file contains date handling.
   8 */
   9#include <linux/errno.h>
  10#include <linux/init.h>
  11#include <linux/kernel.h>
  12#include <linux/param.h>
  13#include <linux/string.h>
  14#include <linux/mc146818rtc.h>
  15#include <linux/bcd.h>
  16#include <linux/rtc.h>
  17#include <linux/platform_device.h>
  18
  19#include "proto.h"
  20
  21
  22/*
  23 * Support for the RTC device.
  24 *
  25 * We don't want to use the rtc-cmos driver, because we don't want to support
  26 * alarms, as that would be indistinguishable from timer interrupts.
  27 *
  28 * Further, generic code is really, really tied to a 1900 epoch.  This is
  29 * true in __get_rtc_time as well as the users of struct rtc_time e.g.
  30 * rtc_tm_to_time.  Thankfully all of the other epochs in use are later
  31 * than 1900, and so it's easy to adjust.
  32 */
  33
  34static unsigned long rtc_epoch;
  35
  36static int __init
  37specifiy_epoch(char *str)
  38{
  39        unsigned long epoch = simple_strtoul(str, NULL, 0);
  40        if (epoch < 1900)
  41                printk("Ignoring invalid user specified epoch %lu\n", epoch);
  42        else
  43                rtc_epoch = epoch;
  44        return 1;
  45}
  46__setup("epoch=", specifiy_epoch);
  47
  48static void __init
  49init_rtc_epoch(void)
  50{
  51        int epoch, year, ctrl;
  52
  53        if (rtc_epoch != 0) {
  54                /* The epoch was specified on the command-line.  */
  55                return;
  56        }
  57
  58        /* Detect the epoch in use on this computer.  */
  59        ctrl = CMOS_READ(RTC_CONTROL);
  60        year = CMOS_READ(RTC_YEAR);
  61        if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
  62                year = bcd2bin(year);
  63
  64        /* PC-like is standard; used for year >= 70 */
  65        epoch = 1900;
  66        if (year < 20) {
  67                epoch = 2000;
  68        } else if (year >= 20 && year < 48) {
  69                /* NT epoch */
  70                epoch = 1980;
  71        } else if (year >= 48 && year < 70) {
  72                /* Digital UNIX epoch */
  73                epoch = 1952;
  74        }
  75        rtc_epoch = epoch;
  76
  77        printk(KERN_INFO "Using epoch %d for rtc year %d\n", epoch, year);
  78}
  79
  80static int
  81alpha_rtc_read_time(struct device *dev, struct rtc_time *tm)
  82{
  83        mc146818_get_time(tm);
  84
  85        /* Adjust for non-default epochs.  It's easier to depend on the
  86           generic __get_rtc_time and adjust the epoch here than create
  87           a copy of __get_rtc_time with the edits we need.  */
  88        if (rtc_epoch != 1900) {
  89                int year = tm->tm_year;
  90                /* Undo the century adjustment made in __get_rtc_time.  */
  91                if (year >= 100)
  92                        year -= 100;
  93                year += rtc_epoch - 1900;
  94                /* Redo the century adjustment with the epoch in place.  */
  95                if (year <= 69)
  96                        year += 100;
  97                tm->tm_year = year;
  98        }
  99
 100        return 0;
 101}
 102
 103static int
 104alpha_rtc_set_time(struct device *dev, struct rtc_time *tm)
 105{
 106        struct rtc_time xtm;
 107
 108        if (rtc_epoch != 1900) {
 109                xtm = *tm;
 110                xtm.tm_year -= rtc_epoch - 1900;
 111                tm = &xtm;
 112        }
 113
 114        return mc146818_set_time(tm);
 115}
 116
 117static int
 118alpha_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
 119{
 120        switch (cmd) {
 121        case RTC_EPOCH_READ:
 122                return put_user(rtc_epoch, (unsigned long __user *)arg);
 123        case RTC_EPOCH_SET:
 124                if (arg < 1900)
 125                        return -EINVAL;
 126                rtc_epoch = arg;
 127                return 0;
 128        default:
 129                return -ENOIOCTLCMD;
 130        }
 131}
 132
 133static const struct rtc_class_ops alpha_rtc_ops = {
 134        .read_time = alpha_rtc_read_time,
 135        .set_time = alpha_rtc_set_time,
 136        .ioctl = alpha_rtc_ioctl,
 137};
 138
 139/*
 140 * Similarly, except do the actual CMOS access on the boot cpu only.
 141 * This requires marshalling the data across an interprocessor call.
 142 */
 143
 144#if defined(CONFIG_SMP) && \
 145    (defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_MARVEL))
 146# define HAVE_REMOTE_RTC 1
 147
 148union remote_data {
 149        struct rtc_time *tm;
 150        long retval;
 151};
 152
 153static void
 154do_remote_read(void *data)
 155{
 156        union remote_data *x = data;
 157        x->retval = alpha_rtc_read_time(NULL, x->tm);
 158}
 159
 160static int
 161remote_read_time(struct device *dev, struct rtc_time *tm)
 162{
 163        union remote_data x;
 164        if (smp_processor_id() != boot_cpuid) {
 165                x.tm = tm;
 166                smp_call_function_single(boot_cpuid, do_remote_read, &x, 1);
 167                return x.retval;
 168        }
 169        return alpha_rtc_read_time(NULL, tm);
 170}
 171
 172static void
 173do_remote_set(void *data)
 174{
 175        union remote_data *x = data;
 176        x->retval = alpha_rtc_set_time(NULL, x->tm);
 177}
 178
 179static int
 180remote_set_time(struct device *dev, struct rtc_time *tm)
 181{
 182        union remote_data x;
 183        if (smp_processor_id() != boot_cpuid) {
 184                x.tm = tm;
 185                smp_call_function_single(boot_cpuid, do_remote_set, &x, 1);
 186                return x.retval;
 187        }
 188        return alpha_rtc_set_time(NULL, tm);
 189}
 190
 191static const struct rtc_class_ops remote_rtc_ops = {
 192        .read_time = remote_read_time,
 193        .set_time = remote_set_time,
 194        .ioctl = alpha_rtc_ioctl,
 195};
 196#endif
 197
 198static int __init
 199alpha_rtc_init(void)
 200{
 201        struct platform_device *pdev;
 202        struct rtc_device *rtc;
 203
 204        init_rtc_epoch();
 205
 206        pdev = platform_device_register_simple("rtc-alpha", -1, NULL, 0);
 207        rtc = devm_rtc_allocate_device(&pdev->dev);
 208        if (IS_ERR(rtc))
 209                return PTR_ERR(rtc);
 210
 211        platform_set_drvdata(pdev, rtc);
 212        rtc->ops = &alpha_rtc_ops;
 213
 214#ifdef HAVE_REMOTE_RTC
 215        if (alpha_mv.rtc_boot_cpu_only)
 216                rtc->ops = &remote_rtc_ops;
 217#endif
 218
 219        return devm_rtc_register_device(rtc);
 220}
 221device_initcall(alpha_rtc_init);
 222