1bbd0abdaSPaul Mackerras /* 2bbd0abdaSPaul Mackerras * arch/ppc/platforms/chrp_time.c 3bbd0abdaSPaul Mackerras * 4bbd0abdaSPaul Mackerras * Copyright (C) 1991, 1992, 1995 Linus Torvalds 5bbd0abdaSPaul Mackerras * 6bbd0abdaSPaul Mackerras * Adapted for PowerPC (PReP) by Gary Thomas 7bbd0abdaSPaul Mackerras * Modified by Cort Dougan (cort@cs.nmt.edu). 8bbd0abdaSPaul Mackerras * Copied and modified from arch/i386/kernel/time.c 9bbd0abdaSPaul Mackerras * 10bbd0abdaSPaul Mackerras */ 11bbd0abdaSPaul Mackerras #include <linux/errno.h> 12bbd0abdaSPaul Mackerras #include <linux/sched.h> 13bbd0abdaSPaul Mackerras #include <linux/kernel.h> 14bbd0abdaSPaul Mackerras #include <linux/param.h> 15bbd0abdaSPaul Mackerras #include <linux/string.h> 16bbd0abdaSPaul Mackerras #include <linux/mm.h> 17bbd0abdaSPaul Mackerras #include <linux/interrupt.h> 18bbd0abdaSPaul Mackerras #include <linux/time.h> 19bbd0abdaSPaul Mackerras #include <linux/timex.h> 20bbd0abdaSPaul Mackerras #include <linux/kernel_stat.h> 21bbd0abdaSPaul Mackerras #include <linux/mc146818rtc.h> 22bbd0abdaSPaul Mackerras #include <linux/init.h> 23bbd0abdaSPaul Mackerras #include <linux/bcd.h> 24575e3216SDavid Woodhouse #include <linux/ioport.h> 25bbd0abdaSPaul Mackerras 26bbd0abdaSPaul Mackerras #include <asm/io.h> 27bbd0abdaSPaul Mackerras #include <asm/nvram.h> 28bbd0abdaSPaul Mackerras #include <asm/prom.h> 29bbd0abdaSPaul Mackerras #include <asm/sections.h> 30bbd0abdaSPaul Mackerras #include <asm/time.h> 31bbd0abdaSPaul Mackerras 32bbd0abdaSPaul Mackerras extern spinlock_t rtc_lock; 33bbd0abdaSPaul Mackerras 34bbd0abdaSPaul Mackerras static int nvram_as1 = NVRAM_AS1; 35bbd0abdaSPaul Mackerras static int nvram_as0 = NVRAM_AS0; 36bbd0abdaSPaul Mackerras static int nvram_data = NVRAM_DATA; 37bbd0abdaSPaul Mackerras 38bbd0abdaSPaul Mackerras long __init chrp_time_init(void) 39bbd0abdaSPaul Mackerras { 40bbd0abdaSPaul Mackerras struct device_node *rtcs; 41575e3216SDavid Woodhouse struct resource r; 42bbd0abdaSPaul Mackerras int base; 43bbd0abdaSPaul Mackerras 44bbd0abdaSPaul Mackerras rtcs = find_compatible_devices("rtc", "pnpPNP,b00"); 45bbd0abdaSPaul Mackerras if (rtcs == NULL) 46bbd0abdaSPaul Mackerras rtcs = find_compatible_devices("rtc", "ds1385-rtc"); 47575e3216SDavid Woodhouse if (rtcs == NULL || of_address_to_resource(rtcs, 0, &r)) 48bbd0abdaSPaul Mackerras return 0; 49575e3216SDavid Woodhouse 50575e3216SDavid Woodhouse base = r.start; 51bbd0abdaSPaul Mackerras nvram_as1 = 0; 52bbd0abdaSPaul Mackerras nvram_as0 = base; 53bbd0abdaSPaul Mackerras nvram_data = base + 1; 54bbd0abdaSPaul Mackerras 55bbd0abdaSPaul Mackerras return 0; 56bbd0abdaSPaul Mackerras } 57bbd0abdaSPaul Mackerras 58bbd0abdaSPaul Mackerras int chrp_cmos_clock_read(int addr) 59bbd0abdaSPaul Mackerras { 60bbd0abdaSPaul Mackerras if (nvram_as1 != 0) 61bbd0abdaSPaul Mackerras outb(addr>>8, nvram_as1); 62bbd0abdaSPaul Mackerras outb(addr, nvram_as0); 63bbd0abdaSPaul Mackerras return (inb(nvram_data)); 64bbd0abdaSPaul Mackerras } 65bbd0abdaSPaul Mackerras 66bbd0abdaSPaul Mackerras void chrp_cmos_clock_write(unsigned long val, int addr) 67bbd0abdaSPaul Mackerras { 68bbd0abdaSPaul Mackerras if (nvram_as1 != 0) 69bbd0abdaSPaul Mackerras outb(addr>>8, nvram_as1); 70bbd0abdaSPaul Mackerras outb(addr, nvram_as0); 71bbd0abdaSPaul Mackerras outb(val, nvram_data); 72bbd0abdaSPaul Mackerras return; 73bbd0abdaSPaul Mackerras } 74bbd0abdaSPaul Mackerras 75bbd0abdaSPaul Mackerras /* 76bbd0abdaSPaul Mackerras * Set the hardware clock. -- Cort 77bbd0abdaSPaul Mackerras */ 78bbd0abdaSPaul Mackerras int chrp_set_rtc_time(struct rtc_time *tmarg) 79bbd0abdaSPaul Mackerras { 80bbd0abdaSPaul Mackerras unsigned char save_control, save_freq_select; 81bbd0abdaSPaul Mackerras struct rtc_time tm = *tmarg; 82bbd0abdaSPaul Mackerras 83bbd0abdaSPaul Mackerras spin_lock(&rtc_lock); 84bbd0abdaSPaul Mackerras 85bbd0abdaSPaul Mackerras save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */ 86bbd0abdaSPaul Mackerras 87bbd0abdaSPaul Mackerras chrp_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL); 88bbd0abdaSPaul Mackerras 89bbd0abdaSPaul Mackerras save_freq_select = chrp_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */ 90bbd0abdaSPaul Mackerras 91bbd0abdaSPaul Mackerras chrp_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); 92bbd0abdaSPaul Mackerras 93bbd0abdaSPaul Mackerras if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { 94bbd0abdaSPaul Mackerras BIN_TO_BCD(tm.tm_sec); 95bbd0abdaSPaul Mackerras BIN_TO_BCD(tm.tm_min); 96bbd0abdaSPaul Mackerras BIN_TO_BCD(tm.tm_hour); 97bbd0abdaSPaul Mackerras BIN_TO_BCD(tm.tm_mon); 98bbd0abdaSPaul Mackerras BIN_TO_BCD(tm.tm_mday); 99bbd0abdaSPaul Mackerras BIN_TO_BCD(tm.tm_year); 100bbd0abdaSPaul Mackerras } 101bbd0abdaSPaul Mackerras chrp_cmos_clock_write(tm.tm_sec,RTC_SECONDS); 102bbd0abdaSPaul Mackerras chrp_cmos_clock_write(tm.tm_min,RTC_MINUTES); 103bbd0abdaSPaul Mackerras chrp_cmos_clock_write(tm.tm_hour,RTC_HOURS); 104bbd0abdaSPaul Mackerras chrp_cmos_clock_write(tm.tm_mon,RTC_MONTH); 105bbd0abdaSPaul Mackerras chrp_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH); 106bbd0abdaSPaul Mackerras chrp_cmos_clock_write(tm.tm_year,RTC_YEAR); 107bbd0abdaSPaul Mackerras 108bbd0abdaSPaul Mackerras /* The following flags have to be released exactly in this order, 109bbd0abdaSPaul Mackerras * otherwise the DS12887 (popular MC146818A clone with integrated 110bbd0abdaSPaul Mackerras * battery and quartz) will not reset the oscillator and will not 111bbd0abdaSPaul Mackerras * update precisely 500 ms later. You won't find this mentioned in 112bbd0abdaSPaul Mackerras * the Dallas Semiconductor data sheets, but who believes data 113bbd0abdaSPaul Mackerras * sheets anyway ... -- Markus Kuhn 114bbd0abdaSPaul Mackerras */ 115bbd0abdaSPaul Mackerras chrp_cmos_clock_write(save_control, RTC_CONTROL); 116bbd0abdaSPaul Mackerras chrp_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT); 117bbd0abdaSPaul Mackerras 118bbd0abdaSPaul Mackerras spin_unlock(&rtc_lock); 119bbd0abdaSPaul Mackerras return 0; 120bbd0abdaSPaul Mackerras } 121bbd0abdaSPaul Mackerras 122bbd0abdaSPaul Mackerras void chrp_get_rtc_time(struct rtc_time *tm) 123bbd0abdaSPaul Mackerras { 124bbd0abdaSPaul Mackerras unsigned int year, mon, day, hour, min, sec; 125bbd0abdaSPaul Mackerras int uip, i; 126bbd0abdaSPaul Mackerras 127bbd0abdaSPaul Mackerras /* The Linux interpretation of the CMOS clock register contents: 128bbd0abdaSPaul Mackerras * When the Update-In-Progress (UIP) flag goes from 1 to 0, the 129bbd0abdaSPaul Mackerras * RTC registers show the second which has precisely just started. 130bbd0abdaSPaul Mackerras * Let's hope other operating systems interpret the RTC the same way. 131bbd0abdaSPaul Mackerras */ 132bbd0abdaSPaul Mackerras 133bbd0abdaSPaul Mackerras /* Since the UIP flag is set for about 2.2 ms and the clock 134bbd0abdaSPaul Mackerras * is typically written with a precision of 1 jiffy, trying 135bbd0abdaSPaul Mackerras * to obtain a precision better than a few milliseconds is 136bbd0abdaSPaul Mackerras * an illusion. Only consistency is interesting, this also 137bbd0abdaSPaul Mackerras * allows to use the routine for /dev/rtc without a potential 138bbd0abdaSPaul Mackerras * 1 second kernel busy loop triggered by any reader of /dev/rtc. 139bbd0abdaSPaul Mackerras */ 140bbd0abdaSPaul Mackerras 141bbd0abdaSPaul Mackerras for ( i = 0; i<1000000; i++) { 142bbd0abdaSPaul Mackerras uip = chrp_cmos_clock_read(RTC_FREQ_SELECT); 143bbd0abdaSPaul Mackerras sec = chrp_cmos_clock_read(RTC_SECONDS); 144bbd0abdaSPaul Mackerras min = chrp_cmos_clock_read(RTC_MINUTES); 145bbd0abdaSPaul Mackerras hour = chrp_cmos_clock_read(RTC_HOURS); 146bbd0abdaSPaul Mackerras day = chrp_cmos_clock_read(RTC_DAY_OF_MONTH); 147bbd0abdaSPaul Mackerras mon = chrp_cmos_clock_read(RTC_MONTH); 148bbd0abdaSPaul Mackerras year = chrp_cmos_clock_read(RTC_YEAR); 149bbd0abdaSPaul Mackerras uip |= chrp_cmos_clock_read(RTC_FREQ_SELECT); 150bbd0abdaSPaul Mackerras if ((uip & RTC_UIP)==0) break; 151bbd0abdaSPaul Mackerras } 152bbd0abdaSPaul Mackerras 153bbd0abdaSPaul Mackerras if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { 154bbd0abdaSPaul Mackerras BCD_TO_BIN(sec); 155bbd0abdaSPaul Mackerras BCD_TO_BIN(min); 156bbd0abdaSPaul Mackerras BCD_TO_BIN(hour); 157bbd0abdaSPaul Mackerras BCD_TO_BIN(day); 158bbd0abdaSPaul Mackerras BCD_TO_BIN(mon); 159bbd0abdaSPaul Mackerras BCD_TO_BIN(year); 160bbd0abdaSPaul Mackerras } 16149e16b7bSPaul Mackerras if (year < 70) 162bbd0abdaSPaul Mackerras year += 100; 163bbd0abdaSPaul Mackerras tm->tm_sec = sec; 164bbd0abdaSPaul Mackerras tm->tm_min = min; 165bbd0abdaSPaul Mackerras tm->tm_hour = hour; 166bbd0abdaSPaul Mackerras tm->tm_mday = day; 167bbd0abdaSPaul Mackerras tm->tm_mon = mon; 168bbd0abdaSPaul Mackerras tm->tm_year = year; 169bbd0abdaSPaul Mackerras } 170bbd0abdaSPaul Mackerras 171bbd0abdaSPaul Mackerras 172bbd0abdaSPaul Mackerras void __init chrp_calibrate_decr(void) 173bbd0abdaSPaul Mackerras { 174bbd0abdaSPaul Mackerras struct device_node *cpu; 175bbd0abdaSPaul Mackerras unsigned int freq, *fp; 176bbd0abdaSPaul Mackerras 177bbd0abdaSPaul Mackerras /* 178bbd0abdaSPaul Mackerras * The cpu node should have a timebase-frequency property 179bbd0abdaSPaul Mackerras * to tell us the rate at which the decrementer counts. 180bbd0abdaSPaul Mackerras */ 181bbd0abdaSPaul Mackerras freq = 16666000; /* hardcoded default */ 182bbd0abdaSPaul Mackerras cpu = find_type_devices("cpu"); 183bbd0abdaSPaul Mackerras if (cpu != 0) { 184bbd0abdaSPaul Mackerras fp = (unsigned int *) 185bbd0abdaSPaul Mackerras get_property(cpu, "timebase-frequency", NULL); 186bbd0abdaSPaul Mackerras if (fp != 0) 187bbd0abdaSPaul Mackerras freq = *fp; 188bbd0abdaSPaul Mackerras } 189bbd0abdaSPaul Mackerras ppc_tb_freq = freq; 190bbd0abdaSPaul Mackerras } 191