1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2f6d57916SPaul Mackerras /* 3f6d57916SPaul Mackerras * Support for periodic interrupts (100 per second) and for getting 4f6d57916SPaul Mackerras * the current time from the RTC on Power Macintoshes. 5f6d57916SPaul Mackerras * 6f6d57916SPaul Mackerras * We use the decrementer register for our periodic interrupts. 7f6d57916SPaul Mackerras * 8f6d57916SPaul Mackerras * Paul Mackerras August 1996. 9f6d57916SPaul Mackerras * Copyright (C) 1996 Paul Mackerras. 10f2783c15SPaul Mackerras * Copyright (C) 2003-2005 Benjamin Herrenschmidt. 11f2783c15SPaul Mackerras * 12f6d57916SPaul Mackerras */ 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/io.h> 31f6d57916SPaul Mackerras #include <asm/pgtable.h> 32f6d57916SPaul Mackerras #include <asm/machdep.h> 33f6d57916SPaul Mackerras #include <asm/time.h> 34f6d57916SPaul Mackerras #include <asm/nvram.h> 3535499c01SPaul Mackerras #include <asm/smu.h> 36f6d57916SPaul Mackerras 372fff0f07SMathieu Malaterre #include "pmac.h" 382fff0f07SMathieu Malaterre 39f2783c15SPaul Mackerras #undef DEBUG 40f2783c15SPaul Mackerras 41f2783c15SPaul Mackerras #ifdef DEBUG 42f2783c15SPaul Mackerras #define DBG(x...) printk(x) 43f2783c15SPaul Mackerras #else 44f2783c15SPaul Mackerras #define DBG(x...) 45f2783c15SPaul Mackerras #endif 46f2783c15SPaul Mackerras 4722db552bSArnd Bergmann /* 48f6d57916SPaul Mackerras * Calibrate the decrementer frequency with the VIA timer 1. 49f6d57916SPaul Mackerras */ 50f6d57916SPaul Mackerras #define VIA_TIMER_FREQ_6 4700000 /* time 1 frequency * 6 */ 51f6d57916SPaul Mackerras 52f6d57916SPaul Mackerras /* VIA registers */ 53f6d57916SPaul Mackerras #define RS 0x200 /* skip between registers */ 54f6d57916SPaul Mackerras #define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */ 55f6d57916SPaul Mackerras #define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */ 56f6d57916SPaul Mackerras #define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */ 57f6d57916SPaul Mackerras #define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */ 58f6d57916SPaul Mackerras #define ACR (11*RS) /* Auxiliary control register */ 59f6d57916SPaul Mackerras #define IFR (13*RS) /* Interrupt flag register */ 60f6d57916SPaul Mackerras 61f6d57916SPaul Mackerras /* Bits in ACR */ 62f6d57916SPaul Mackerras #define T1MODE 0xc0 /* Timer 1 mode */ 63f6d57916SPaul Mackerras #define T1MODE_CONT 0x40 /* continuous interrupts */ 64f6d57916SPaul Mackerras 65f6d57916SPaul Mackerras /* Bits in IFR and IER */ 66f6d57916SPaul Mackerras #define T1_INT 0x40 /* Timer 1 interrupt */ 67f6d57916SPaul Mackerras 68f2783c15SPaul Mackerras long __init pmac_time_init(void) 69f6d57916SPaul Mackerras { 70f6d57916SPaul Mackerras s32 delta = 0; 7120e07af7SFinn Thain #if defined(CONFIG_NVRAM) && defined(CONFIG_PPC32) 72f6d57916SPaul Mackerras int dst; 73f6d57916SPaul Mackerras 74f6d57916SPaul Mackerras delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16; 75f6d57916SPaul Mackerras delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8; 76f6d57916SPaul Mackerras delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb); 77f6d57916SPaul Mackerras if (delta & 0x00800000UL) 78f6d57916SPaul Mackerras delta |= 0xFF000000UL; 79f6d57916SPaul Mackerras dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0); 80f6d57916SPaul Mackerras printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60, 81f6d57916SPaul Mackerras dst ? "on" : "off"); 82f6d57916SPaul Mackerras #endif 8335499c01SPaul Mackerras return delta; 84f6d57916SPaul Mackerras } 85f6d57916SPaul Mackerras 8635499c01SPaul Mackerras #ifdef CONFIG_PMAC_SMU 875bfd6435SArnd Bergmann static time64_t smu_get_time(void) 8835499c01SPaul Mackerras { 8935499c01SPaul Mackerras struct rtc_time tm; 9035499c01SPaul Mackerras 9135499c01SPaul Mackerras if (smu_get_rtc_time(&tm, 1)) 9235499c01SPaul Mackerras return 0; 935bfd6435SArnd Bergmann return rtc_tm_to_time64(&tm); 9435499c01SPaul Mackerras } 9535499c01SPaul Mackerras #endif 9635499c01SPaul Mackerras 97ba76cd57SPaul Mackerras /* Can't be __init, it's called when suspending and resuming */ 985bfd6435SArnd Bergmann time64_t pmac_get_boot_time(void) 9935499c01SPaul Mackerras { 10035499c01SPaul Mackerras /* Get the time from the RTC, used only at boot time */ 10135499c01SPaul Mackerras switch (sys_ctrler) { 1020792a2c8SFinn Thain #ifdef CONFIG_ADB_CUDA 10335499c01SPaul Mackerras case SYS_CTRLER_CUDA: 10435499c01SPaul Mackerras return cuda_get_time(); 1050792a2c8SFinn Thain #endif 1060792a2c8SFinn Thain #ifdef CONFIG_ADB_PMU 10735499c01SPaul Mackerras case SYS_CTRLER_PMU: 10835499c01SPaul Mackerras return pmu_get_time(); 1090792a2c8SFinn Thain #endif 1100792a2c8SFinn Thain #ifdef CONFIG_PMAC_SMU 11135499c01SPaul Mackerras case SYS_CTRLER_SMU: 11235499c01SPaul Mackerras return smu_get_time(); 1130792a2c8SFinn Thain #endif 114f6d57916SPaul Mackerras default: 115f6d57916SPaul Mackerras return 0; 116f6d57916SPaul Mackerras } 117f6d57916SPaul Mackerras } 118f6d57916SPaul Mackerras 11935499c01SPaul Mackerras void pmac_get_rtc_time(struct rtc_time *tm) 12035499c01SPaul Mackerras { 12135499c01SPaul Mackerras /* Get the time from the RTC, used only at boot time */ 12235499c01SPaul Mackerras switch (sys_ctrler) { 1230792a2c8SFinn Thain #ifdef CONFIG_ADB_CUDA 12435499c01SPaul Mackerras case SYS_CTRLER_CUDA: 1250792a2c8SFinn Thain rtc_time64_to_tm(cuda_get_time(), tm); 12635499c01SPaul Mackerras break; 1270792a2c8SFinn Thain #endif 1280792a2c8SFinn Thain #ifdef CONFIG_ADB_PMU 12935499c01SPaul Mackerras case SYS_CTRLER_PMU: 1300792a2c8SFinn Thain rtc_time64_to_tm(pmu_get_time(), tm); 13135499c01SPaul Mackerras break; 1320792a2c8SFinn Thain #endif 1330792a2c8SFinn Thain #ifdef CONFIG_PMAC_SMU 13435499c01SPaul Mackerras case SYS_CTRLER_SMU: 13535499c01SPaul Mackerras smu_get_rtc_time(tm, 1); 13635499c01SPaul Mackerras break; 1370792a2c8SFinn Thain #endif 13835499c01SPaul Mackerras default: 13935499c01SPaul Mackerras ; 14035499c01SPaul Mackerras } 14135499c01SPaul Mackerras } 14235499c01SPaul Mackerras 14335499c01SPaul Mackerras int pmac_set_rtc_time(struct rtc_time *tm) 14435499c01SPaul Mackerras { 14535499c01SPaul Mackerras switch (sys_ctrler) { 1460792a2c8SFinn Thain #ifdef CONFIG_ADB_CUDA 14735499c01SPaul Mackerras case SYS_CTRLER_CUDA: 14835499c01SPaul Mackerras return cuda_set_rtc_time(tm); 1490792a2c8SFinn Thain #endif 1500792a2c8SFinn Thain #ifdef CONFIG_ADB_PMU 15135499c01SPaul Mackerras case SYS_CTRLER_PMU: 15235499c01SPaul Mackerras return pmu_set_rtc_time(tm); 1530792a2c8SFinn Thain #endif 1540792a2c8SFinn Thain #ifdef CONFIG_PMAC_SMU 15535499c01SPaul Mackerras case SYS_CTRLER_SMU: 15635499c01SPaul Mackerras return smu_set_rtc_time(tm, 1); 1570792a2c8SFinn Thain #endif 15835499c01SPaul Mackerras default: 15935499c01SPaul Mackerras return -ENODEV; 16035499c01SPaul Mackerras } 16135499c01SPaul Mackerras } 16235499c01SPaul Mackerras 16335499c01SPaul Mackerras #ifdef CONFIG_PPC32 164f6d57916SPaul Mackerras /* 165f6d57916SPaul Mackerras * Calibrate the decrementer register using VIA timer 1. 166f6d57916SPaul Mackerras * This is used both on powermacs and CHRP machines. 167f6d57916SPaul Mackerras */ 1682fff0f07SMathieu Malaterre static int __init via_calibrate_decr(void) 169f6d57916SPaul Mackerras { 170f6d57916SPaul Mackerras struct device_node *vias; 171f6d57916SPaul Mackerras volatile unsigned char __iomem *via; 172f6d57916SPaul Mackerras int count = VIA_TIMER_FREQ_6 / 100; 173f6d57916SPaul Mackerras unsigned int dstart, dend; 174cc5d0189SBenjamin Herrenschmidt struct resource rsrc; 175f6d57916SPaul Mackerras 176cc5d0189SBenjamin Herrenschmidt vias = of_find_node_by_name(NULL, "via-cuda"); 177afcb0654SNicolas Palix if (vias == NULL) 178cc5d0189SBenjamin Herrenschmidt vias = of_find_node_by_name(NULL, "via-pmu"); 179afcb0654SNicolas Palix if (vias == NULL) 180cc5d0189SBenjamin Herrenschmidt vias = of_find_node_by_name(NULL, "via"); 181afcb0654SNicolas Palix if (vias == NULL || of_address_to_resource(vias, 0, &rsrc)) { 182afcb0654SNicolas Palix of_node_put(vias); 183f6d57916SPaul Mackerras return 0; 184afcb0654SNicolas Palix } 185afcb0654SNicolas Palix of_node_put(vias); 18628f65c11SJoe Perches via = ioremap(rsrc.start, resource_size(&rsrc)); 187cc5d0189SBenjamin Herrenschmidt if (via == NULL) { 188cc5d0189SBenjamin Herrenschmidt printk(KERN_ERR "Failed to map VIA for timer calibration !\n"); 189cc5d0189SBenjamin Herrenschmidt return 0; 190cc5d0189SBenjamin Herrenschmidt } 191f6d57916SPaul Mackerras 192f6d57916SPaul Mackerras /* set timer 1 for continuous interrupts */ 193f6d57916SPaul Mackerras out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT); 194f6d57916SPaul Mackerras /* set the counter to a small value */ 195f6d57916SPaul Mackerras out_8(&via[T1CH], 2); 196f6d57916SPaul Mackerras /* set the latch to `count' */ 197f6d57916SPaul Mackerras out_8(&via[T1LL], count); 198f6d57916SPaul Mackerras out_8(&via[T1LH], count >> 8); 199f6d57916SPaul Mackerras /* wait until it hits 0 */ 200f6d57916SPaul Mackerras while ((in_8(&via[IFR]) & T1_INT) == 0) 201f6d57916SPaul Mackerras ; 202f6d57916SPaul Mackerras dstart = get_dec(); 203f6d57916SPaul Mackerras /* clear the interrupt & wait until it hits 0 again */ 204f6d57916SPaul Mackerras in_8(&via[T1CL]); 205f6d57916SPaul Mackerras while ((in_8(&via[IFR]) & T1_INT) == 0) 206f6d57916SPaul Mackerras ; 207f6d57916SPaul Mackerras dend = get_dec(); 208f6d57916SPaul Mackerras 2095d14a18dSPaul Mackerras ppc_tb_freq = (dstart - dend) * 100 / 6; 210f6d57916SPaul Mackerras 211f6d57916SPaul Mackerras iounmap(via); 212f6d57916SPaul Mackerras 213f6d57916SPaul Mackerras return 1; 214f6d57916SPaul Mackerras } 21535499c01SPaul Mackerras #endif 216f6d57916SPaul Mackerras 217f6d57916SPaul Mackerras /* 218f6d57916SPaul Mackerras * Query the OF and get the decr frequency. 219f6d57916SPaul Mackerras */ 22035499c01SPaul Mackerras void __init pmac_calibrate_decr(void) 221f6d57916SPaul Mackerras { 22235499c01SPaul Mackerras generic_calibrate_decr(); 22335499c01SPaul Mackerras 22435499c01SPaul Mackerras #ifdef CONFIG_PPC32 225f6d57916SPaul Mackerras /* We assume MacRISC2 machines have correct device-tree 226f6d57916SPaul Mackerras * calibration. That's better since the VIA itself seems 227f6d57916SPaul Mackerras * to be slightly off. --BenH 228f6d57916SPaul Mackerras */ 22971a157e8SGrant Likely if (!of_machine_is_compatible("MacRISC2") && 23071a157e8SGrant Likely !of_machine_is_compatible("MacRISC3") && 23171a157e8SGrant Likely !of_machine_is_compatible("MacRISC4")) 232f6d57916SPaul Mackerras if (via_calibrate_decr()) 233f6d57916SPaul Mackerras return; 234f6d57916SPaul Mackerras 235f6d57916SPaul Mackerras /* Special case: QuickSilver G4s seem to have a badly calibrated 236f6d57916SPaul Mackerras * timebase-frequency in OF, VIA is much better on these. We should 237f6d57916SPaul Mackerras * probably implement calibration based on the KL timer on these 238f6d57916SPaul Mackerras * machines anyway... -BenH 239f6d57916SPaul Mackerras */ 24071a157e8SGrant Likely if (of_machine_is_compatible("PowerMac3,5")) 241f6d57916SPaul Mackerras if (via_calibrate_decr()) 242f6d57916SPaul Mackerras return; 24335499c01SPaul Mackerras #endif 244f6d57916SPaul Mackerras } 245