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