1f6d57916SPaul Mackerras /* 2f6d57916SPaul Mackerras * Support for periodic interrupts (100 per second) and for getting 3f6d57916SPaul Mackerras * the current time from the RTC on Power Macintoshes. 4f6d57916SPaul Mackerras * 5f6d57916SPaul Mackerras * We use the decrementer register for our periodic interrupts. 6f6d57916SPaul Mackerras * 7f6d57916SPaul Mackerras * Paul Mackerras August 1996. 8f6d57916SPaul Mackerras * Copyright (C) 1996 Paul Mackerras. 9f2783c15SPaul Mackerras * Copyright (C) 2003-2005 Benjamin Herrenschmidt. 10f2783c15SPaul Mackerras * 11f6d57916SPaul Mackerras */ 12f6d57916SPaul Mackerras #include <linux/config.h> 13f6d57916SPaul Mackerras #include <linux/errno.h> 14f6d57916SPaul Mackerras #include <linux/sched.h> 15f6d57916SPaul Mackerras #include <linux/kernel.h> 16f6d57916SPaul Mackerras #include <linux/param.h> 17f6d57916SPaul Mackerras #include <linux/string.h> 18f6d57916SPaul Mackerras #include <linux/mm.h> 19f6d57916SPaul Mackerras #include <linux/init.h> 20f6d57916SPaul Mackerras #include <linux/time.h> 21f6d57916SPaul Mackerras #include <linux/adb.h> 22f6d57916SPaul Mackerras #include <linux/cuda.h> 23f6d57916SPaul Mackerras #include <linux/pmu.h> 24f2783c15SPaul Mackerras #include <linux/interrupt.h> 25f6d57916SPaul Mackerras #include <linux/hardirq.h> 26f2783c15SPaul Mackerras #include <linux/rtc.h> 27f6d57916SPaul Mackerras 28f6d57916SPaul Mackerras #include <asm/sections.h> 29f6d57916SPaul Mackerras #include <asm/prom.h> 30f6d57916SPaul Mackerras #include <asm/system.h> 31f6d57916SPaul Mackerras #include <asm/io.h> 32f6d57916SPaul Mackerras #include <asm/pgtable.h> 33f6d57916SPaul Mackerras #include <asm/machdep.h> 34f6d57916SPaul Mackerras #include <asm/time.h> 35f6d57916SPaul Mackerras #include <asm/nvram.h> 3635499c01SPaul Mackerras #include <asm/smu.h> 37f6d57916SPaul Mackerras 38f2783c15SPaul Mackerras #undef DEBUG 39f2783c15SPaul Mackerras 40f2783c15SPaul Mackerras #ifdef DEBUG 41f2783c15SPaul Mackerras #define DBG(x...) printk(x) 42f2783c15SPaul Mackerras #else 43f2783c15SPaul Mackerras #define DBG(x...) 44f2783c15SPaul Mackerras #endif 45f2783c15SPaul Mackerras 46f6d57916SPaul Mackerras /* Apparently the RTC stores seconds since 1 Jan 1904 */ 47f6d57916SPaul Mackerras #define RTC_OFFSET 2082844800 48f6d57916SPaul Mackerras 49f6d57916SPaul Mackerras /* 50f6d57916SPaul Mackerras * Calibrate the decrementer frequency with the VIA timer 1. 51f6d57916SPaul Mackerras */ 52f6d57916SPaul Mackerras #define VIA_TIMER_FREQ_6 4700000 /* time 1 frequency * 6 */ 53f6d57916SPaul Mackerras 54f6d57916SPaul Mackerras /* VIA registers */ 55f6d57916SPaul Mackerras #define RS 0x200 /* skip between registers */ 56f6d57916SPaul Mackerras #define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */ 57f6d57916SPaul Mackerras #define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */ 58f6d57916SPaul Mackerras #define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */ 59f6d57916SPaul Mackerras #define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */ 60f6d57916SPaul Mackerras #define ACR (11*RS) /* Auxiliary control register */ 61f6d57916SPaul Mackerras #define IFR (13*RS) /* Interrupt flag register */ 62f6d57916SPaul Mackerras 63f6d57916SPaul Mackerras /* Bits in ACR */ 64f6d57916SPaul Mackerras #define T1MODE 0xc0 /* Timer 1 mode */ 65f6d57916SPaul Mackerras #define T1MODE_CONT 0x40 /* continuous interrupts */ 66f6d57916SPaul Mackerras 67f6d57916SPaul Mackerras /* Bits in IFR and IER */ 68f6d57916SPaul Mackerras #define T1_INT 0x40 /* Timer 1 interrupt */ 69f6d57916SPaul Mackerras 70f2783c15SPaul Mackerras long __init pmac_time_init(void) 71f6d57916SPaul Mackerras { 72f6d57916SPaul Mackerras s32 delta = 0; 7335499c01SPaul Mackerras #ifdef CONFIG_NVRAM 74f6d57916SPaul Mackerras int dst; 75f6d57916SPaul Mackerras 76f6d57916SPaul Mackerras delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16; 77f6d57916SPaul Mackerras delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8; 78f6d57916SPaul Mackerras delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb); 79f6d57916SPaul Mackerras if (delta & 0x00800000UL) 80f6d57916SPaul Mackerras delta |= 0xFF000000UL; 81f6d57916SPaul Mackerras dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0); 82f6d57916SPaul Mackerras printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60, 83f6d57916SPaul Mackerras dst ? "on" : "off"); 84f6d57916SPaul Mackerras #endif 8535499c01SPaul Mackerras return delta; 86f6d57916SPaul Mackerras } 87f6d57916SPaul Mackerras 8835499c01SPaul Mackerras static void to_rtc_time(unsigned long now, struct rtc_time *tm) 89f6d57916SPaul Mackerras { 9035499c01SPaul Mackerras to_tm(now, tm); 9135499c01SPaul Mackerras tm->tm_year -= 1900; 9235499c01SPaul Mackerras tm->tm_mon -= 1; 9335499c01SPaul Mackerras } 9435499c01SPaul Mackerras 9535499c01SPaul Mackerras static unsigned long from_rtc_time(struct rtc_time *tm) 9635499c01SPaul Mackerras { 9735499c01SPaul Mackerras return mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, 9835499c01SPaul Mackerras tm->tm_hour, tm->tm_min, tm->tm_sec); 9935499c01SPaul Mackerras } 10035499c01SPaul Mackerras 10135499c01SPaul Mackerras #ifdef CONFIG_ADB_CUDA 10235499c01SPaul Mackerras static unsigned long cuda_get_time(void) 10335499c01SPaul Mackerras { 104f6d57916SPaul Mackerras struct adb_request req; 1050c37ec2aSBenjamin Herrenschmidt unsigned int now; 106f6d57916SPaul Mackerras 107f6d57916SPaul Mackerras if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0) 108f6d57916SPaul Mackerras return 0; 109f6d57916SPaul Mackerras while (!req.complete) 110f6d57916SPaul Mackerras cuda_poll(); 111f6d57916SPaul Mackerras if (req.reply_len != 7) 11235499c01SPaul Mackerras printk(KERN_ERR "cuda_get_time: got %d byte reply\n", 113f6d57916SPaul Mackerras req.reply_len); 114f6d57916SPaul Mackerras now = (req.reply[3] << 24) + (req.reply[4] << 16) 115f6d57916SPaul Mackerras + (req.reply[5] << 8) + req.reply[6]; 1160c37ec2aSBenjamin Herrenschmidt return ((unsigned long)now) - RTC_OFFSET; 117f6d57916SPaul Mackerras } 118f6d57916SPaul Mackerras 11935499c01SPaul Mackerras #define cuda_get_rtc_time(tm) to_rtc_time(cuda_get_time(), (tm)) 12035499c01SPaul Mackerras 12135499c01SPaul Mackerras static int cuda_set_rtc_time(struct rtc_time *tm) 122f6d57916SPaul Mackerras { 12335499c01SPaul Mackerras unsigned int nowtime; 124f6d57916SPaul Mackerras struct adb_request req; 125f6d57916SPaul Mackerras 12635499c01SPaul Mackerras nowtime = from_rtc_time(tm) + RTC_OFFSET; 127f6d57916SPaul Mackerras if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME, 128143a1decSPaul Mackerras nowtime >> 24, nowtime >> 16, nowtime >> 8, 129143a1decSPaul Mackerras nowtime) < 0) 13035499c01SPaul Mackerras return -ENXIO; 131f6d57916SPaul Mackerras while (!req.complete) 132f6d57916SPaul Mackerras cuda_poll(); 133f6d57916SPaul Mackerras if ((req.reply_len != 3) && (req.reply_len != 7)) 13435499c01SPaul Mackerras printk(KERN_ERR "cuda_set_rtc_time: got %d byte reply\n", 135f6d57916SPaul Mackerras req.reply_len); 136f6d57916SPaul Mackerras return 0; 13735499c01SPaul Mackerras } 13835499c01SPaul Mackerras 13935499c01SPaul Mackerras #else 14035499c01SPaul Mackerras #define cuda_get_time() 0 14135499c01SPaul Mackerras #define cuda_get_rtc_time(tm) 14235499c01SPaul Mackerras #define cuda_set_rtc_time(tm) 0 14335499c01SPaul Mackerras #endif 14435499c01SPaul Mackerras 14535499c01SPaul Mackerras #ifdef CONFIG_ADB_PMU 14635499c01SPaul Mackerras static unsigned long pmu_get_time(void) 14735499c01SPaul Mackerras { 14835499c01SPaul Mackerras struct adb_request req; 1490c37ec2aSBenjamin Herrenschmidt unsigned int now; 15035499c01SPaul Mackerras 15135499c01SPaul Mackerras if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) 15235499c01SPaul Mackerras return 0; 15335499c01SPaul Mackerras pmu_wait_complete(&req); 15435499c01SPaul Mackerras if (req.reply_len != 4) 15535499c01SPaul Mackerras printk(KERN_ERR "pmu_get_time: got %d byte reply from PMU\n", 156f6d57916SPaul Mackerras req.reply_len); 15735499c01SPaul Mackerras now = (req.reply[0] << 24) + (req.reply[1] << 16) 15835499c01SPaul Mackerras + (req.reply[2] << 8) + req.reply[3]; 1590c37ec2aSBenjamin Herrenschmidt return ((unsigned long)now) - RTC_OFFSET; 16035499c01SPaul Mackerras } 16135499c01SPaul Mackerras 16235499c01SPaul Mackerras #define pmu_get_rtc_time(tm) to_rtc_time(pmu_get_time(), (tm)) 16335499c01SPaul Mackerras 16435499c01SPaul Mackerras static int pmu_set_rtc_time(struct rtc_time *tm) 16535499c01SPaul Mackerras { 16635499c01SPaul Mackerras unsigned int nowtime; 16735499c01SPaul Mackerras struct adb_request req; 16835499c01SPaul Mackerras 16935499c01SPaul Mackerras nowtime = from_rtc_time(tm) + RTC_OFFSET; 17035499c01SPaul Mackerras if (pmu_request(&req, NULL, 5, PMU_SET_RTC, nowtime >> 24, 17135499c01SPaul Mackerras nowtime >> 16, nowtime >> 8, nowtime) < 0) 17235499c01SPaul Mackerras return -ENXIO; 17335499c01SPaul Mackerras pmu_wait_complete(&req); 17435499c01SPaul Mackerras if (req.reply_len != 0) 17535499c01SPaul Mackerras printk(KERN_ERR "pmu_set_rtc_time: %d byte reply from PMU\n", 17635499c01SPaul Mackerras req.reply_len); 17735499c01SPaul Mackerras return 0; 17835499c01SPaul Mackerras } 17935499c01SPaul Mackerras 18035499c01SPaul Mackerras #else 18135499c01SPaul Mackerras #define pmu_get_time() 0 18235499c01SPaul Mackerras #define pmu_get_rtc_time(tm) 18335499c01SPaul Mackerras #define pmu_set_rtc_time(tm) 0 18435499c01SPaul Mackerras #endif 18535499c01SPaul Mackerras 18635499c01SPaul Mackerras #ifdef CONFIG_PMAC_SMU 18735499c01SPaul Mackerras static unsigned long smu_get_time(void) 18835499c01SPaul Mackerras { 18935499c01SPaul Mackerras struct rtc_time tm; 19035499c01SPaul Mackerras 19135499c01SPaul Mackerras if (smu_get_rtc_time(&tm, 1)) 19235499c01SPaul Mackerras return 0; 19335499c01SPaul Mackerras return from_rtc_time(&tm); 19435499c01SPaul Mackerras } 19535499c01SPaul Mackerras 19635499c01SPaul Mackerras #else 19735499c01SPaul Mackerras #define smu_get_time() 0 19835499c01SPaul Mackerras #define smu_get_rtc_time(tm, spin) 19935499c01SPaul Mackerras #define smu_set_rtc_time(tm, spin) 0 20035499c01SPaul Mackerras #endif 20135499c01SPaul Mackerras 202ba76cd57SPaul Mackerras /* Can't be __init, it's called when suspending and resuming */ 203ba76cd57SPaul Mackerras unsigned long pmac_get_boot_time(void) 20435499c01SPaul Mackerras { 20535499c01SPaul Mackerras /* Get the time from the RTC, used only at boot time */ 20635499c01SPaul Mackerras switch (sys_ctrler) { 20735499c01SPaul Mackerras case SYS_CTRLER_CUDA: 20835499c01SPaul Mackerras return cuda_get_time(); 20935499c01SPaul Mackerras case SYS_CTRLER_PMU: 21035499c01SPaul Mackerras return pmu_get_time(); 21135499c01SPaul Mackerras case SYS_CTRLER_SMU: 21235499c01SPaul Mackerras return smu_get_time(); 213f6d57916SPaul Mackerras default: 214f6d57916SPaul Mackerras return 0; 215f6d57916SPaul Mackerras } 216f6d57916SPaul Mackerras } 217f6d57916SPaul Mackerras 21835499c01SPaul Mackerras void pmac_get_rtc_time(struct rtc_time *tm) 21935499c01SPaul Mackerras { 22035499c01SPaul Mackerras /* Get the time from the RTC, used only at boot time */ 22135499c01SPaul Mackerras switch (sys_ctrler) { 22235499c01SPaul Mackerras case SYS_CTRLER_CUDA: 22335499c01SPaul Mackerras cuda_get_rtc_time(tm); 22435499c01SPaul Mackerras break; 22535499c01SPaul Mackerras case SYS_CTRLER_PMU: 22635499c01SPaul Mackerras pmu_get_rtc_time(tm); 22735499c01SPaul Mackerras break; 22835499c01SPaul Mackerras case SYS_CTRLER_SMU: 22935499c01SPaul Mackerras smu_get_rtc_time(tm, 1); 23035499c01SPaul Mackerras break; 23135499c01SPaul Mackerras default: 23235499c01SPaul Mackerras ; 23335499c01SPaul Mackerras } 23435499c01SPaul Mackerras } 23535499c01SPaul Mackerras 23635499c01SPaul Mackerras int pmac_set_rtc_time(struct rtc_time *tm) 23735499c01SPaul Mackerras { 23835499c01SPaul Mackerras switch (sys_ctrler) { 23935499c01SPaul Mackerras case SYS_CTRLER_CUDA: 24035499c01SPaul Mackerras return cuda_set_rtc_time(tm); 24135499c01SPaul Mackerras case SYS_CTRLER_PMU: 24235499c01SPaul Mackerras return pmu_set_rtc_time(tm); 24335499c01SPaul Mackerras case SYS_CTRLER_SMU: 24435499c01SPaul Mackerras return smu_set_rtc_time(tm, 1); 24535499c01SPaul Mackerras default: 24635499c01SPaul Mackerras return -ENODEV; 24735499c01SPaul Mackerras } 24835499c01SPaul Mackerras } 24935499c01SPaul Mackerras 25035499c01SPaul Mackerras #ifdef CONFIG_PPC32 251f6d57916SPaul Mackerras /* 252f6d57916SPaul Mackerras * Calibrate the decrementer register using VIA timer 1. 253f6d57916SPaul Mackerras * This is used both on powermacs and CHRP machines. 254f6d57916SPaul Mackerras */ 25535499c01SPaul Mackerras int __init via_calibrate_decr(void) 256f6d57916SPaul Mackerras { 257f6d57916SPaul Mackerras struct device_node *vias; 258f6d57916SPaul Mackerras volatile unsigned char __iomem *via; 259f6d57916SPaul Mackerras int count = VIA_TIMER_FREQ_6 / 100; 260f6d57916SPaul Mackerras unsigned int dstart, dend; 261cc5d0189SBenjamin Herrenschmidt struct resource rsrc; 262f6d57916SPaul Mackerras 263cc5d0189SBenjamin Herrenschmidt vias = of_find_node_by_name(NULL, "via-cuda"); 264f6d57916SPaul Mackerras if (vias == 0) 265cc5d0189SBenjamin Herrenschmidt vias = of_find_node_by_name(NULL, "via-pmu"); 266f6d57916SPaul Mackerras if (vias == 0) 267cc5d0189SBenjamin Herrenschmidt vias = of_find_node_by_name(NULL, "via"); 268cc5d0189SBenjamin Herrenschmidt if (vias == 0 || of_address_to_resource(vias, 0, &rsrc)) 269f6d57916SPaul Mackerras return 0; 270cc5d0189SBenjamin Herrenschmidt via = ioremap(rsrc.start, rsrc.end - rsrc.start + 1); 271cc5d0189SBenjamin Herrenschmidt if (via == NULL) { 272cc5d0189SBenjamin Herrenschmidt printk(KERN_ERR "Failed to map VIA for timer calibration !\n"); 273cc5d0189SBenjamin Herrenschmidt return 0; 274cc5d0189SBenjamin Herrenschmidt } 275f6d57916SPaul Mackerras 276f6d57916SPaul Mackerras /* set timer 1 for continuous interrupts */ 277f6d57916SPaul Mackerras out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT); 278f6d57916SPaul Mackerras /* set the counter to a small value */ 279f6d57916SPaul Mackerras out_8(&via[T1CH], 2); 280f6d57916SPaul Mackerras /* set the latch to `count' */ 281f6d57916SPaul Mackerras out_8(&via[T1LL], count); 282f6d57916SPaul Mackerras out_8(&via[T1LH], count >> 8); 283f6d57916SPaul Mackerras /* wait until it hits 0 */ 284f6d57916SPaul Mackerras while ((in_8(&via[IFR]) & T1_INT) == 0) 285f6d57916SPaul Mackerras ; 286f6d57916SPaul Mackerras dstart = get_dec(); 287f6d57916SPaul Mackerras /* clear the interrupt & wait until it hits 0 again */ 288f6d57916SPaul Mackerras in_8(&via[T1CL]); 289f6d57916SPaul Mackerras while ((in_8(&via[IFR]) & T1_INT) == 0) 290f6d57916SPaul Mackerras ; 291f6d57916SPaul Mackerras dend = get_dec(); 292f6d57916SPaul Mackerras 2935d14a18dSPaul Mackerras ppc_tb_freq = (dstart - dend) * 100 / 6; 294f6d57916SPaul Mackerras 295f6d57916SPaul Mackerras iounmap(via); 296f6d57916SPaul Mackerras 297f6d57916SPaul Mackerras return 1; 298f6d57916SPaul Mackerras } 29935499c01SPaul Mackerras #endif 300f6d57916SPaul Mackerras 301f6d57916SPaul Mackerras #ifdef CONFIG_PM 302f6d57916SPaul Mackerras /* 303f6d57916SPaul Mackerras * Reset the time after a sleep. 304f6d57916SPaul Mackerras */ 305f6d57916SPaul Mackerras static int 306f6d57916SPaul Mackerras time_sleep_notify(struct pmu_sleep_notifier *self, int when) 307f6d57916SPaul Mackerras { 308f6d57916SPaul Mackerras static unsigned long time_diff; 309f6d57916SPaul Mackerras unsigned long flags; 310f6d57916SPaul Mackerras unsigned long seq; 311f2783c15SPaul Mackerras struct timespec tv; 312f6d57916SPaul Mackerras 313f6d57916SPaul Mackerras switch (when) { 314f6d57916SPaul Mackerras case PBOOK_SLEEP_NOW: 315f6d57916SPaul Mackerras do { 316f6d57916SPaul Mackerras seq = read_seqbegin_irqsave(&xtime_lock, flags); 317143a1decSPaul Mackerras time_diff = xtime.tv_sec - pmac_get_boot_time(); 318f6d57916SPaul Mackerras } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); 319f6d57916SPaul Mackerras break; 320f6d57916SPaul Mackerras case PBOOK_WAKE: 321f2783c15SPaul Mackerras tv.tv_sec = pmac_get_boot_time() + time_diff; 322f2783c15SPaul Mackerras tv.tv_nsec = 0; 323f2783c15SPaul Mackerras do_settimeofday(&tv); 324f6d57916SPaul Mackerras break; 325f6d57916SPaul Mackerras } 326f6d57916SPaul Mackerras return PBOOK_SLEEP_OK; 327f6d57916SPaul Mackerras } 328f6d57916SPaul Mackerras 329f6d57916SPaul Mackerras static struct pmu_sleep_notifier time_sleep_notifier = { 330f6d57916SPaul Mackerras time_sleep_notify, SLEEP_LEVEL_MISC, 331f6d57916SPaul Mackerras }; 332f6d57916SPaul Mackerras #endif /* CONFIG_PM */ 333f6d57916SPaul Mackerras 334f6d57916SPaul Mackerras /* 335f6d57916SPaul Mackerras * Query the OF and get the decr frequency. 336f6d57916SPaul Mackerras */ 33735499c01SPaul Mackerras void __init pmac_calibrate_decr(void) 338f6d57916SPaul Mackerras { 339f6d57916SPaul Mackerras #ifdef CONFIG_PM 34035499c01SPaul Mackerras /* XXX why here? */ 341f6d57916SPaul Mackerras pmu_register_sleep_notifier(&time_sleep_notifier); 342f6d57916SPaul Mackerras #endif /* CONFIG_PM */ 343f6d57916SPaul Mackerras 34435499c01SPaul Mackerras generic_calibrate_decr(); 34535499c01SPaul Mackerras 34635499c01SPaul Mackerras #ifdef CONFIG_PPC32 347f6d57916SPaul Mackerras /* We assume MacRISC2 machines have correct device-tree 348f6d57916SPaul Mackerras * calibration. That's better since the VIA itself seems 349f6d57916SPaul Mackerras * to be slightly off. --BenH 350f6d57916SPaul Mackerras */ 351f6d57916SPaul Mackerras if (!machine_is_compatible("MacRISC2") && 352f6d57916SPaul Mackerras !machine_is_compatible("MacRISC3") && 353f6d57916SPaul Mackerras !machine_is_compatible("MacRISC4")) 354f6d57916SPaul Mackerras if (via_calibrate_decr()) 355f6d57916SPaul Mackerras return; 356f6d57916SPaul Mackerras 357f6d57916SPaul Mackerras /* Special case: QuickSilver G4s seem to have a badly calibrated 358f6d57916SPaul Mackerras * timebase-frequency in OF, VIA is much better on these. We should 359f6d57916SPaul Mackerras * probably implement calibration based on the KL timer on these 360f6d57916SPaul Mackerras * machines anyway... -BenH 361f6d57916SPaul Mackerras */ 362f6d57916SPaul Mackerras if (machine_is_compatible("PowerMac3,5")) 363f6d57916SPaul Mackerras if (via_calibrate_decr()) 364f6d57916SPaul Mackerras return; 36535499c01SPaul Mackerras #endif 366f6d57916SPaul Mackerras } 367