linux/arch/powerpc/platforms/powermac/time.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Support for periodic interrupts (100 per second) and for getting
   4 * the current time from the RTC on Power Macintoshes.
   5 *
   6 * We use the decrementer register for our periodic interrupts.
   7 *
   8 * Paul Mackerras       August 1996.
   9 * Copyright (C) 1996 Paul Mackerras.
  10 * Copyright (C) 2003-2005 Benjamin Herrenschmidt.
  11 *
  12 */
  13#include <linux/errno.h>
  14#include <linux/sched.h>
  15#include <linux/kernel.h>
  16#include <linux/param.h>
  17#include <linux/string.h>
  18#include <linux/mm.h>
  19#include <linux/init.h>
  20#include <linux/time.h>
  21#include <linux/adb.h>
  22#include <linux/cuda.h>
  23#include <linux/pmu.h>
  24#include <linux/interrupt.h>
  25#include <linux/hardirq.h>
  26#include <linux/rtc.h>
  27
  28#include <asm/sections.h>
  29#include <asm/prom.h>
  30#include <asm/io.h>
  31#include <asm/pgtable.h>
  32#include <asm/machdep.h>
  33#include <asm/time.h>
  34#include <asm/nvram.h>
  35#include <asm/smu.h>
  36
  37#undef DEBUG
  38
  39#ifdef DEBUG
  40#define DBG(x...) printk(x)
  41#else
  42#define DBG(x...)
  43#endif
  44
  45/* Apparently the RTC stores seconds since 1 Jan 1904 */
  46#define RTC_OFFSET      2082844800
  47
  48/*
  49 * Calibrate the decrementer frequency with the VIA timer 1.
  50 */
  51#define VIA_TIMER_FREQ_6        4700000 /* time 1 frequency * 6 */
  52
  53/* VIA registers */
  54#define RS              0x200           /* skip between registers */
  55#define T1CL            (4*RS)          /* Timer 1 ctr/latch (low 8 bits) */
  56#define T1CH            (5*RS)          /* Timer 1 counter (high 8 bits) */
  57#define T1LL            (6*RS)          /* Timer 1 latch (low 8 bits) */
  58#define T1LH            (7*RS)          /* Timer 1 latch (high 8 bits) */
  59#define ACR             (11*RS)         /* Auxiliary control register */
  60#define IFR             (13*RS)         /* Interrupt flag register */
  61
  62/* Bits in ACR */
  63#define T1MODE          0xc0            /* Timer 1 mode */
  64#define T1MODE_CONT     0x40            /*  continuous interrupts */
  65
  66/* Bits in IFR and IER */
  67#define T1_INT          0x40            /* Timer 1 interrupt */
  68
  69long __init pmac_time_init(void)
  70{
  71        s32 delta = 0;
  72#ifdef CONFIG_NVRAM
  73        int dst;
  74        
  75        delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16;
  76        delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8;
  77        delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb);
  78        if (delta & 0x00800000UL)
  79                delta |= 0xFF000000UL;
  80        dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0);
  81        printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60,
  82                dst ? "on" : "off");
  83#endif
  84        return delta;
  85}
  86
  87#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
  88static void to_rtc_time(unsigned long now, struct rtc_time *tm)
  89{
  90        to_tm(now, tm);
  91        tm->tm_year -= 1900;
  92        tm->tm_mon -= 1;
  93}
  94#endif
  95
  96#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) || \
  97    defined(CONFIG_PMAC_SMU)
  98static unsigned long from_rtc_time(struct rtc_time *tm)
  99{
 100        return mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
 101                      tm->tm_hour, tm->tm_min, tm->tm_sec);
 102}
 103#endif
 104
 105#ifdef CONFIG_ADB_CUDA
 106static unsigned long cuda_get_time(void)
 107{
 108        struct adb_request req;
 109        unsigned int now;
 110
 111        if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
 112                return 0;
 113        while (!req.complete)
 114                cuda_poll();
 115        if (req.reply_len != 7)
 116                printk(KERN_ERR "cuda_get_time: got %d byte reply\n",
 117                       req.reply_len);
 118        now = (req.reply[3] << 24) + (req.reply[4] << 16)
 119                + (req.reply[5] << 8) + req.reply[6];
 120        return ((unsigned long)now) - RTC_OFFSET;
 121}
 122
 123#define cuda_get_rtc_time(tm)   to_rtc_time(cuda_get_time(), (tm))
 124
 125static int cuda_set_rtc_time(struct rtc_time *tm)
 126{
 127        unsigned int nowtime;
 128        struct adb_request req;
 129
 130        nowtime = from_rtc_time(tm) + RTC_OFFSET;
 131        if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
 132                         nowtime >> 24, nowtime >> 16, nowtime >> 8,
 133                         nowtime) < 0)
 134                return -ENXIO;
 135        while (!req.complete)
 136                cuda_poll();
 137        if ((req.reply_len != 3) && (req.reply_len != 7))
 138                printk(KERN_ERR "cuda_set_rtc_time: got %d byte reply\n",
 139                       req.reply_len);
 140        return 0;
 141}
 142
 143#else
 144#define cuda_get_time()         0
 145#define cuda_get_rtc_time(tm)
 146#define cuda_set_rtc_time(tm)   0
 147#endif
 148
 149#ifdef CONFIG_ADB_PMU
 150static unsigned long pmu_get_time(void)
 151{
 152        struct adb_request req;
 153        unsigned int now;
 154
 155        if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
 156                return 0;
 157        pmu_wait_complete(&req);
 158        if (req.reply_len != 4)
 159                printk(KERN_ERR "pmu_get_time: got %d byte reply from PMU\n",
 160                       req.reply_len);
 161        now = (req.reply[0] << 24) + (req.reply[1] << 16)
 162                + (req.reply[2] << 8) + req.reply[3];
 163        return ((unsigned long)now) - RTC_OFFSET;
 164}
 165
 166#define pmu_get_rtc_time(tm)    to_rtc_time(pmu_get_time(), (tm))
 167
 168static int pmu_set_rtc_time(struct rtc_time *tm)
 169{
 170        unsigned int nowtime;
 171        struct adb_request req;
 172
 173        nowtime = from_rtc_time(tm) + RTC_OFFSET;
 174        if (pmu_request(&req, NULL, 5, PMU_SET_RTC, nowtime >> 24,
 175                        nowtime >> 16, nowtime >> 8, nowtime) < 0)
 176                return -ENXIO;
 177        pmu_wait_complete(&req);
 178        if (req.reply_len != 0)
 179                printk(KERN_ERR "pmu_set_rtc_time: %d byte reply from PMU\n",
 180                       req.reply_len);
 181        return 0;
 182}
 183
 184#else
 185#define pmu_get_time()          0
 186#define pmu_get_rtc_time(tm)
 187#define pmu_set_rtc_time(tm)    0
 188#endif
 189
 190#ifdef CONFIG_PMAC_SMU
 191static unsigned long smu_get_time(void)
 192{
 193        struct rtc_time tm;
 194
 195        if (smu_get_rtc_time(&tm, 1))
 196                return 0;
 197        return from_rtc_time(&tm);
 198}
 199
 200#else
 201#define smu_get_time()                  0
 202#define smu_get_rtc_time(tm, spin)
 203#define smu_set_rtc_time(tm, spin)      0
 204#endif
 205
 206/* Can't be __init, it's called when suspending and resuming */
 207unsigned long pmac_get_boot_time(void)
 208{
 209        /* Get the time from the RTC, used only at boot time */
 210        switch (sys_ctrler) {
 211        case SYS_CTRLER_CUDA:
 212                return cuda_get_time();
 213        case SYS_CTRLER_PMU:
 214                return pmu_get_time();
 215        case SYS_CTRLER_SMU:
 216                return smu_get_time();
 217        default:
 218                return 0;
 219        }
 220}
 221
 222void pmac_get_rtc_time(struct rtc_time *tm)
 223{
 224        /* Get the time from the RTC, used only at boot time */
 225        switch (sys_ctrler) {
 226        case SYS_CTRLER_CUDA:
 227                cuda_get_rtc_time(tm);
 228                break;
 229        case SYS_CTRLER_PMU:
 230                pmu_get_rtc_time(tm);
 231                break;
 232        case SYS_CTRLER_SMU:
 233                smu_get_rtc_time(tm, 1);
 234                break;
 235        default:
 236                ;
 237        }
 238}
 239
 240int pmac_set_rtc_time(struct rtc_time *tm)
 241{
 242        switch (sys_ctrler) {
 243        case SYS_CTRLER_CUDA:
 244                return cuda_set_rtc_time(tm);
 245        case SYS_CTRLER_PMU:
 246                return pmu_set_rtc_time(tm);
 247        case SYS_CTRLER_SMU:
 248                return smu_set_rtc_time(tm, 1);
 249        default:
 250                return -ENODEV;
 251        }
 252}
 253
 254#ifdef CONFIG_PPC32
 255/*
 256 * Calibrate the decrementer register using VIA timer 1.
 257 * This is used both on powermacs and CHRP machines.
 258 */
 259int __init via_calibrate_decr(void)
 260{
 261        struct device_node *vias;
 262        volatile unsigned char __iomem *via;
 263        int count = VIA_TIMER_FREQ_6 / 100;
 264        unsigned int dstart, dend;
 265        struct resource rsrc;
 266
 267        vias = of_find_node_by_name(NULL, "via-cuda");
 268        if (vias == NULL)
 269                vias = of_find_node_by_name(NULL, "via-pmu");
 270        if (vias == NULL)
 271                vias = of_find_node_by_name(NULL, "via");
 272        if (vias == NULL || of_address_to_resource(vias, 0, &rsrc)) {
 273                of_node_put(vias);
 274                return 0;
 275        }
 276        of_node_put(vias);
 277        via = ioremap(rsrc.start, resource_size(&rsrc));
 278        if (via == NULL) {
 279                printk(KERN_ERR "Failed to map VIA for timer calibration !\n");
 280                return 0;
 281        }
 282
 283        /* set timer 1 for continuous interrupts */
 284        out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT);
 285        /* set the counter to a small value */
 286        out_8(&via[T1CH], 2);
 287        /* set the latch to `count' */
 288        out_8(&via[T1LL], count);
 289        out_8(&via[T1LH], count >> 8);
 290        /* wait until it hits 0 */
 291        while ((in_8(&via[IFR]) & T1_INT) == 0)
 292                ;
 293        dstart = get_dec();
 294        /* clear the interrupt & wait until it hits 0 again */
 295        in_8(&via[T1CL]);
 296        while ((in_8(&via[IFR]) & T1_INT) == 0)
 297                ;
 298        dend = get_dec();
 299
 300        ppc_tb_freq = (dstart - dend) * 100 / 6;
 301
 302        iounmap(via);
 303
 304        return 1;
 305}
 306#endif
 307
 308/*
 309 * Query the OF and get the decr frequency.
 310 */
 311void __init pmac_calibrate_decr(void)
 312{
 313        generic_calibrate_decr();
 314
 315#ifdef CONFIG_PPC32
 316        /* We assume MacRISC2 machines have correct device-tree
 317         * calibration. That's better since the VIA itself seems
 318         * to be slightly off. --BenH
 319         */
 320        if (!of_machine_is_compatible("MacRISC2") &&
 321            !of_machine_is_compatible("MacRISC3") &&
 322            !of_machine_is_compatible("MacRISC4"))
 323                if (via_calibrate_decr())
 324                        return;
 325
 326        /* Special case: QuickSilver G4s seem to have a badly calibrated
 327         * timebase-frequency in OF, VIA is much better on these. We should
 328         * probably implement calibration based on the KL timer on these
 329         * machines anyway... -BenH
 330         */
 331        if (of_machine_is_compatible("PowerMac3,5"))
 332                if (via_calibrate_decr())
 333                        return;
 334#endif
 335}
 336