Pull novell-bugzilla-156426 into release branch
[pandora-kernel.git] / arch / powerpc / platforms / powermac / time.c
index a6d2d23..890758a 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/machdep.h>
 #include <asm/time.h>
 #include <asm/nvram.h>
+#include <asm/smu.h>
 
 #undef DEBUG
 
@@ -68,8 +69,8 @@
 
 long __init pmac_time_init(void)
 {
-#ifdef CONFIG_NVRAM
        s32 delta = 0;
+#ifdef CONFIG_NVRAM
        int dst;
        
        delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16;
@@ -80,124 +81,197 @@ long __init pmac_time_init(void)
        dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0);
        printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60,
                dst ? "on" : "off");
+#endif
        return delta;
-#else
+}
+
+static void to_rtc_time(unsigned long now, struct rtc_time *tm)
+{
+       to_tm(now, tm);
+       tm->tm_year -= 1900;
+       tm->tm_mon -= 1;
+}
+
+static unsigned long from_rtc_time(struct rtc_time *tm)
+{
+       return mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
+                     tm->tm_hour, tm->tm_min, tm->tm_sec);
+}
+
+#ifdef CONFIG_ADB_CUDA
+static unsigned long cuda_get_time(void)
+{
+       struct adb_request req;
+       unsigned int now;
+
+       if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
+               return 0;
+       while (!req.complete)
+               cuda_poll();
+       if (req.reply_len != 7)
+               printk(KERN_ERR "cuda_get_time: got %d byte reply\n",
+                      req.reply_len);
+       now = (req.reply[3] << 24) + (req.reply[4] << 16)
+               + (req.reply[5] << 8) + req.reply[6];
+       return ((unsigned long)now) - RTC_OFFSET;
+}
+
+#define cuda_get_rtc_time(tm)  to_rtc_time(cuda_get_time(), (tm))
+
+static int cuda_set_rtc_time(struct rtc_time *tm)
+{
+       unsigned int nowtime;
+       struct adb_request req;
+
+       nowtime = from_rtc_time(tm) + RTC_OFFSET;
+       if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
+                        nowtime >> 24, nowtime >> 16, nowtime >> 8,
+                        nowtime) < 0)
+               return -ENXIO;
+       while (!req.complete)
+               cuda_poll();
+       if ((req.reply_len != 3) && (req.reply_len != 7))
+               printk(KERN_ERR "cuda_set_rtc_time: got %d byte reply\n",
+                      req.reply_len);
        return 0;
+}
+
+#else
+#define cuda_get_time()                0
+#define cuda_get_rtc_time(tm)
+#define cuda_set_rtc_time(tm)  0
 #endif
+
+#ifdef CONFIG_ADB_PMU
+static unsigned long pmu_get_time(void)
+{
+       struct adb_request req;
+       unsigned int now;
+
+       if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
+               return 0;
+       pmu_wait_complete(&req);
+       if (req.reply_len != 4)
+               printk(KERN_ERR "pmu_get_time: got %d byte reply from PMU\n",
+                      req.reply_len);
+       now = (req.reply[0] << 24) + (req.reply[1] << 16)
+               + (req.reply[2] << 8) + req.reply[3];
+       return ((unsigned long)now) - RTC_OFFSET;
 }
 
-unsigned long pmac_get_boot_time(void)
+#define pmu_get_rtc_time(tm)   to_rtc_time(pmu_get_time(), (tm))
+
+static int pmu_set_rtc_time(struct rtc_time *tm)
 {
-#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
+       unsigned int nowtime;
        struct adb_request req;
-       unsigned long now;
+
+       nowtime = from_rtc_time(tm) + RTC_OFFSET;
+       if (pmu_request(&req, NULL, 5, PMU_SET_RTC, nowtime >> 24,
+                       nowtime >> 16, nowtime >> 8, nowtime) < 0)
+               return -ENXIO;
+       pmu_wait_complete(&req);
+       if (req.reply_len != 0)
+               printk(KERN_ERR "pmu_set_rtc_time: %d byte reply from PMU\n",
+                      req.reply_len);
+       return 0;
+}
+
+#else
+#define pmu_get_time()         0
+#define pmu_get_rtc_time(tm)
+#define pmu_set_rtc_time(tm)   0
+#endif
+
+#ifdef CONFIG_PMAC_SMU
+static unsigned long smu_get_time(void)
+{
+       struct rtc_time tm;
+
+       if (smu_get_rtc_time(&tm, 1))
+               return 0;
+       return from_rtc_time(&tm);
+}
+
+#else
+#define smu_get_time()                 0
+#define smu_get_rtc_time(tm, spin)
+#define smu_set_rtc_time(tm, spin)     0
 #endif
 
-       /* Get the time from the RTC */
+/* Can't be __init, it's called when suspending and resuming */
+unsigned long pmac_get_boot_time(void)
+{
+       /* Get the time from the RTC, used only at boot time */
        switch (sys_ctrler) {
-#ifdef CONFIG_ADB_CUDA
        case SYS_CTRLER_CUDA:
-               if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0)
-                       return 0;
-               while (!req.complete)
-                       cuda_poll();
-               if (req.reply_len != 7)
-                       printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
-                              req.reply_len);
-               now = (req.reply[3] << 24) + (req.reply[4] << 16)
-                       + (req.reply[5] << 8) + req.reply[6];
-               return now - RTC_OFFSET;
-#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU
+               return cuda_get_time();
        case SYS_CTRLER_PMU:
-               if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
-                       return 0;
-               while (!req.complete)
-                       pmu_poll();
-               if (req.reply_len != 4)
-                       printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
-                              req.reply_len);
-               now = (req.reply[0] << 24) + (req.reply[1] << 16)
-                       + (req.reply[2] << 8) + req.reply[3];
-               return now - RTC_OFFSET;
-#endif /* CONFIG_ADB_PMU */
-       default: ;
+               return pmu_get_time();
+       case SYS_CTRLER_SMU:
+               return smu_get_time();
+       default:
+               return 0;
        }
-       return 0;
 }
 
 void pmac_get_rtc_time(struct rtc_time *tm)
 {
-       unsigned long now;
-
-       now = pmac_get_boot_time();
-       to_tm(now, tm);
-       tm->tm_year -= 1900;
-       tm->tm_mon -= 1;                /* month is 0-based */
+       /* Get the time from the RTC, used only at boot time */
+       switch (sys_ctrler) {
+       case SYS_CTRLER_CUDA:
+               cuda_get_rtc_time(tm);
+               break;
+       case SYS_CTRLER_PMU:
+               pmu_get_rtc_time(tm);
+               break;
+       case SYS_CTRLER_SMU:
+               smu_get_rtc_time(tm, 1);
+               break;
+       default:
+               ;
+       }
 }
 
 int pmac_set_rtc_time(struct rtc_time *tm)
 {
-       unsigned long nowtime;
-#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU)
-       struct adb_request req;
-#endif
-
-       nowtime = mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
-                        tm->tm_hour, tm->tm_min, tm->tm_sec);
-       nowtime += RTC_OFFSET;
-
        switch (sys_ctrler) {
-#ifdef CONFIG_ADB_CUDA
        case SYS_CTRLER_CUDA:
-               if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME,
-                                nowtime >> 24, nowtime >> 16, nowtime >> 8,
-                                nowtime) < 0)
-                       return 0;
-               while (!req.complete)
-                       cuda_poll();
-               if ((req.reply_len != 3) && (req.reply_len != 7))
-                       printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
-                              req.reply_len);
-               return 1;
-#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU
+               return cuda_set_rtc_time(tm);
        case SYS_CTRLER_PMU:
-               if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
-                               nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
-                       return 0;
-               while (!req.complete)
-                       pmu_poll();
-               if (req.reply_len != 0)
-                       printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
-                              req.reply_len);
-               return 1;
-#endif /* CONFIG_ADB_PMU */
+               return pmu_set_rtc_time(tm);
+       case SYS_CTRLER_SMU:
+               return smu_set_rtc_time(tm, 1);
        default:
-               return 0;
+               return -ENODEV;
        }
 }
 
+#ifdef CONFIG_PPC32
 /*
  * Calibrate the decrementer register using VIA timer 1.
  * This is used both on powermacs and CHRP machines.
  */
-int __init
-via_calibrate_decr(void)
+int __init via_calibrate_decr(void)
 {
        struct device_node *vias;
        volatile unsigned char __iomem *via;
        int count = VIA_TIMER_FREQ_6 / 100;
        unsigned int dstart, dend;
+       struct resource rsrc;
 
-       vias = find_devices("via-cuda");
+       vias = of_find_node_by_name(NULL, "via-cuda");
        if (vias == 0)
-               vias = find_devices("via-pmu");
+               vias = of_find_node_by_name(NULL, "via-pmu");
        if (vias == 0)
-               vias = find_devices("via");
-       if (vias == 0 || vias->n_addrs == 0)
+               vias = of_find_node_by_name(NULL, "via");
+       if (vias == 0 || of_address_to_resource(vias, 0, &rsrc))
+               return 0;
+       via = ioremap(rsrc.start, rsrc.end - rsrc.start + 1);
+       if (via == NULL) {
+               printk(KERN_ERR "Failed to map VIA for timer calibration !\n");
                return 0;
-       via = ioremap(vias->addrs[0].address, vias->addrs[0].size);
+       }
 
        /* set timer 1 for continuous interrupts */
        out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT);
@@ -217,15 +291,12 @@ via_calibrate_decr(void)
        dend = get_dec();
 
        ppc_tb_freq = (dstart - dend) * 100 / 6;
-       tb_ticks_per_jiffy = (dstart - dend) / ((6 * HZ)/100);
-
-       printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %lu (%u ticks)\n",
-              tb_ticks_per_jiffy, dstart - dend);
 
        iounmap(via);
        
        return 1;
 }
+#endif
 
 #ifdef CONFIG_PM
 /*
@@ -262,19 +333,17 @@ static struct pmu_sleep_notifier time_sleep_notifier = {
 
 /*
  * Query the OF and get the decr frequency.
- * This was taken from the pmac time_init() when merging the prep/pmac
- * time functions.
  */
-void __init
-pmac_calibrate_decr(void)
+void __init pmac_calibrate_decr(void)
 {
-       struct device_node *cpu;
-       unsigned int freq, *fp;
-
-#ifdef CONFIG_PM
+#if defined(CONFIG_PM) && defined(CONFIG_ADB_PMU)
+       /* XXX why here? */
        pmu_register_sleep_notifier(&time_sleep_notifier);
-#endif /* CONFIG_PM */
+#endif
+
+       generic_calibrate_decr();
 
+#ifdef CONFIG_PPC32
        /* We assume MacRISC2 machines have correct device-tree
         * calibration. That's better since the VIA itself seems
         * to be slightly off. --BenH
@@ -293,18 +362,5 @@ pmac_calibrate_decr(void)
        if (machine_is_compatible("PowerMac3,5"))
                if (via_calibrate_decr())
                        return;
-       /*
-        * The cpu node should have a timebase-frequency property
-        * to tell us the rate at which the decrementer counts.
-        */
-       cpu = find_type_devices("cpu");
-       if (cpu == 0)
-               panic("can't find cpu node in time_init");
-       fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL);
-       if (fp == 0)
-               panic("can't get cpu timebase frequency");
-       freq = *fp;
-       printk("time_init: decrementer frequency = %u.%.6u MHz\n",
-              freq/1000000, freq%1000000);
-       ppc_tb_freq = freq;
+#endif
 }