aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/time.c')
-rw-r--r--arch/sparc64/kernel/time.c389
1 files changed, 349 insertions, 40 deletions
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index a22930d62adf..e55b5c6ece02 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -30,6 +30,8 @@
30#include <linux/cpufreq.h> 30#include <linux/cpufreq.h>
31#include <linux/percpu.h> 31#include <linux/percpu.h>
32#include <linux/profile.h> 32#include <linux/profile.h>
33#include <linux/miscdevice.h>
34#include <linux/rtc.h>
33 35
34#include <asm/oplib.h> 36#include <asm/oplib.h>
35#include <asm/mostek.h> 37#include <asm/mostek.h>
@@ -45,6 +47,7 @@
45#include <asm/smp.h> 47#include <asm/smp.h>
46#include <asm/sections.h> 48#include <asm/sections.h>
47#include <asm/cpudata.h> 49#include <asm/cpudata.h>
50#include <asm/uaccess.h>
48 51
49DEFINE_SPINLOCK(mostek_lock); 52DEFINE_SPINLOCK(mostek_lock);
50DEFINE_SPINLOCK(rtc_lock); 53DEFINE_SPINLOCK(rtc_lock);
@@ -193,16 +196,22 @@ struct sparc64_tick_ops *tick_ops __read_mostly = &tick_operations;
193 196
194static void stick_init_tick(unsigned long offset) 197static void stick_init_tick(unsigned long offset)
195{ 198{
196 tick_disable_protection(); 199 /* Writes to the %tick and %stick register are not
197 200 * allowed on sun4v. The Hypervisor controls that
198 /* Let the user get at STICK too. */ 201 * bit, per-strand.
199 __asm__ __volatile__( 202 */
200 " rd %%asr24, %%g2\n" 203 if (tlb_type != hypervisor) {
201 " andn %%g2, %0, %%g2\n" 204 tick_disable_protection();
202 " wr %%g2, 0, %%asr24" 205
203 : /* no outputs */ 206 /* Let the user get at STICK too. */
204 : "r" (TICK_PRIV_BIT) 207 __asm__ __volatile__(
205 : "g1", "g2"); 208 " rd %%asr24, %%g2\n"
209 " andn %%g2, %0, %%g2\n"
210 " wr %%g2, 0, %%asr24"
211 : /* no outputs */
212 : "r" (TICK_PRIV_BIT)
213 : "g1", "g2");
214 }
206 215
207 __asm__ __volatile__( 216 __asm__ __volatile__(
208 " rd %%asr24, %%g1\n" 217 " rd %%asr24, %%g1\n"
@@ -632,23 +641,8 @@ static void __init set_system_time(void)
632 mon = MSTK_REG_MONTH(mregs); 641 mon = MSTK_REG_MONTH(mregs);
633 year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) ); 642 year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
634 } else { 643 } else {
635 int i;
636
637 /* Dallas 12887 RTC chip. */ 644 /* Dallas 12887 RTC chip. */
638 645
639 /* Stolen from arch/i386/kernel/time.c, see there for
640 * credits and descriptive comments.
641 */
642 for (i = 0; i < 1000000; i++) {
643 if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
644 break;
645 udelay(10);
646 }
647 for (i = 0; i < 1000000; i++) {
648 if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
649 break;
650 udelay(10);
651 }
652 do { 646 do {
653 sec = CMOS_READ(RTC_SECONDS); 647 sec = CMOS_READ(RTC_SECONDS);
654 min = CMOS_READ(RTC_MINUTES); 648 min = CMOS_READ(RTC_MINUTES);
@@ -657,6 +651,7 @@ static void __init set_system_time(void)
657 mon = CMOS_READ(RTC_MONTH); 651 mon = CMOS_READ(RTC_MONTH);
658 year = CMOS_READ(RTC_YEAR); 652 year = CMOS_READ(RTC_YEAR);
659 } while (sec != CMOS_READ(RTC_SECONDS)); 653 } while (sec != CMOS_READ(RTC_SECONDS));
654
660 if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { 655 if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
661 BCD_TO_BIN(sec); 656 BCD_TO_BIN(sec);
662 BCD_TO_BIN(min); 657 BCD_TO_BIN(min);
@@ -683,6 +678,83 @@ static void __init set_system_time(void)
683 } 678 }
684} 679}
685 680
681/* davem suggests we keep this within the 4M locked kernel image */
682static u32 starfire_get_time(void)
683{
684 static char obp_gettod[32];
685 static u32 unix_tod;
686
687 sprintf(obp_gettod, "h# %08x unix-gettod",
688 (unsigned int) (long) &unix_tod);
689 prom_feval(obp_gettod);
690
691 return unix_tod;
692}
693
694static int starfire_set_time(u32 val)
695{
696 /* Do nothing, time is set using the service processor
697 * console on this platform.
698 */
699 return 0;
700}
701
702static u32 hypervisor_get_time(void)
703{
704 register unsigned long func asm("%o5");
705 register unsigned long arg0 asm("%o0");
706 register unsigned long arg1 asm("%o1");
707 int retries = 10000;
708
709retry:
710 func = HV_FAST_TOD_GET;
711 arg0 = 0;
712 arg1 = 0;
713 __asm__ __volatile__("ta %6"
714 : "=&r" (func), "=&r" (arg0), "=&r" (arg1)
715 : "0" (func), "1" (arg0), "2" (arg1),
716 "i" (HV_FAST_TRAP));
717 if (arg0 == HV_EOK)
718 return arg1;
719 if (arg0 == HV_EWOULDBLOCK) {
720 if (--retries > 0) {
721 udelay(100);
722 goto retry;
723 }
724 printk(KERN_WARNING "SUN4V: tod_get() timed out.\n");
725 return 0;
726 }
727 printk(KERN_WARNING "SUN4V: tod_get() not supported.\n");
728 return 0;
729}
730
731static int hypervisor_set_time(u32 secs)
732{
733 register unsigned long func asm("%o5");
734 register unsigned long arg0 asm("%o0");
735 int retries = 10000;
736
737retry:
738 func = HV_FAST_TOD_SET;
739 arg0 = secs;
740 __asm__ __volatile__("ta %4"
741 : "=&r" (func), "=&r" (arg0)
742 : "0" (func), "1" (arg0),
743 "i" (HV_FAST_TRAP));
744 if (arg0 == HV_EOK)
745 return 0;
746 if (arg0 == HV_EWOULDBLOCK) {
747 if (--retries > 0) {
748 udelay(100);
749 goto retry;
750 }
751 printk(KERN_WARNING "SUN4V: tod_set() timed out.\n");
752 return -EAGAIN;
753 }
754 printk(KERN_WARNING "SUN4V: tod_set() not supported.\n");
755 return -EOPNOTSUPP;
756}
757
686void __init clock_probe(void) 758void __init clock_probe(void)
687{ 759{
688 struct linux_prom_registers clk_reg[2]; 760 struct linux_prom_registers clk_reg[2];
@@ -702,14 +774,14 @@ void __init clock_probe(void)
702 774
703 775
704 if (this_is_starfire) { 776 if (this_is_starfire) {
705 /* davem suggests we keep this within the 4M locked kernel image */ 777 xtime.tv_sec = starfire_get_time();
706 static char obp_gettod[256]; 778 xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
707 static u32 unix_tod; 779 set_normalized_timespec(&wall_to_monotonic,
708 780 -xtime.tv_sec, -xtime.tv_nsec);
709 sprintf(obp_gettod, "h# %08x unix-gettod", 781 return;
710 (unsigned int) (long) &unix_tod); 782 }
711 prom_feval(obp_gettod); 783 if (tlb_type == hypervisor) {
712 xtime.tv_sec = unix_tod; 784 xtime.tv_sec = hypervisor_get_time();
713 xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); 785 xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
714 set_normalized_timespec(&wall_to_monotonic, 786 set_normalized_timespec(&wall_to_monotonic,
715 -xtime.tv_sec, -xtime.tv_nsec); 787 -xtime.tv_sec, -xtime.tv_nsec);
@@ -981,11 +1053,10 @@ static void sparc64_start_timers(irqreturn_t (*cfunc)(int, void *, struct pt_reg
981} 1053}
982 1054
983struct freq_table { 1055struct freq_table {
984 unsigned long udelay_val_ref;
985 unsigned long clock_tick_ref; 1056 unsigned long clock_tick_ref;
986 unsigned int ref_freq; 1057 unsigned int ref_freq;
987}; 1058};
988static DEFINE_PER_CPU(struct freq_table, sparc64_freq_table) = { 0, 0, 0 }; 1059static DEFINE_PER_CPU(struct freq_table, sparc64_freq_table) = { 0, 0 };
989 1060
990unsigned long sparc64_get_clock_tick(unsigned int cpu) 1061unsigned long sparc64_get_clock_tick(unsigned int cpu)
991{ 1062{
@@ -1007,16 +1078,11 @@ static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val
1007 1078
1008 if (!ft->ref_freq) { 1079 if (!ft->ref_freq) {
1009 ft->ref_freq = freq->old; 1080 ft->ref_freq = freq->old;
1010 ft->udelay_val_ref = cpu_data(cpu).udelay_val;
1011 ft->clock_tick_ref = cpu_data(cpu).clock_tick; 1081 ft->clock_tick_ref = cpu_data(cpu).clock_tick;
1012 } 1082 }
1013 if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || 1083 if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
1014 (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) || 1084 (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
1015 (val == CPUFREQ_RESUMECHANGE)) { 1085 (val == CPUFREQ_RESUMECHANGE)) {
1016 cpu_data(cpu).udelay_val =
1017 cpufreq_scale(ft->udelay_val_ref,
1018 ft->ref_freq,
1019 freq->new);
1020 cpu_data(cpu).clock_tick = 1086 cpu_data(cpu).clock_tick =
1021 cpufreq_scale(ft->clock_tick_ref, 1087 cpufreq_scale(ft->clock_tick_ref,
1022 ft->ref_freq, 1088 ft->ref_freq,
@@ -1179,3 +1245,246 @@ static int set_rtc_mmss(unsigned long nowtime)
1179 return retval; 1245 return retval;
1180 } 1246 }
1181} 1247}
1248
1249#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */
1250static unsigned char mini_rtc_status; /* bitmapped status byte. */
1251
1252/* months start at 0 now */
1253static unsigned char days_in_mo[] =
1254{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1255
1256#define FEBRUARY 2
1257#define STARTOFTIME 1970
1258#define SECDAY 86400L
1259#define SECYR (SECDAY * 365)
1260#define leapyear(year) ((year) % 4 == 0 && \
1261 ((year) % 100 != 0 || (year) % 400 == 0))
1262#define days_in_year(a) (leapyear(a) ? 366 : 365)
1263#define days_in_month(a) (month_days[(a) - 1])
1264
1265static int month_days[12] = {
1266 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
1267};
1268
1269/*
1270 * This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
1271 */
1272static void GregorianDay(struct rtc_time * tm)
1273{
1274 int leapsToDate;
1275 int lastYear;
1276 int day;
1277 int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
1278
1279 lastYear = tm->tm_year - 1;
1280
1281 /*
1282 * Number of leap corrections to apply up to end of last year
1283 */
1284 leapsToDate = lastYear / 4 - lastYear / 100 + lastYear / 400;
1285
1286 /*
1287 * This year is a leap year if it is divisible by 4 except when it is
1288 * divisible by 100 unless it is divisible by 400
1289 *
1290 * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 was
1291 */
1292 day = tm->tm_mon > 2 && leapyear(tm->tm_year);
1293
1294 day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] +
1295 tm->tm_mday;
1296
1297 tm->tm_wday = day % 7;
1298}
1299
1300static void to_tm(int tim, struct rtc_time *tm)
1301{
1302 register int i;
1303 register long hms, day;
1304
1305 day = tim / SECDAY;
1306 hms = tim % SECDAY;
1307
1308 /* Hours, minutes, seconds are easy */
1309 tm->tm_hour = hms / 3600;
1310 tm->tm_min = (hms % 3600) / 60;
1311 tm->tm_sec = (hms % 3600) % 60;
1312
1313 /* Number of years in days */
1314 for (i = STARTOFTIME; day >= days_in_year(i); i++)
1315 day -= days_in_year(i);
1316 tm->tm_year = i;
1317
1318 /* Number of months in days left */
1319 if (leapyear(tm->tm_year))
1320 days_in_month(FEBRUARY) = 29;
1321 for (i = 1; day >= days_in_month(i); i++)
1322 day -= days_in_month(i);
1323 days_in_month(FEBRUARY) = 28;
1324 tm->tm_mon = i;
1325
1326 /* Days are what is left over (+1) from all that. */
1327 tm->tm_mday = day + 1;
1328
1329 /*
1330 * Determine the day of week
1331 */
1332 GregorianDay(tm);
1333}
1334
1335/* Both Starfire and SUN4V give us seconds since Jan 1st, 1970,
1336 * aka Unix time. So we have to convert to/from rtc_time.
1337 */
1338static inline void mini_get_rtc_time(struct rtc_time *time)
1339{
1340 unsigned long flags;
1341 u32 seconds;
1342
1343 spin_lock_irqsave(&rtc_lock, flags);
1344 seconds = 0;
1345 if (this_is_starfire)
1346 seconds = starfire_get_time();
1347 else if (tlb_type == hypervisor)
1348 seconds = hypervisor_get_time();
1349 spin_unlock_irqrestore(&rtc_lock, flags);
1350
1351 to_tm(seconds, time);
1352 time->tm_year -= 1900;
1353 time->tm_mon -= 1;
1354}
1355
1356static inline int mini_set_rtc_time(struct rtc_time *time)
1357{
1358 u32 seconds = mktime(time->tm_year + 1900, time->tm_mon + 1,
1359 time->tm_mday, time->tm_hour,
1360 time->tm_min, time->tm_sec);
1361 unsigned long flags;
1362 int err;
1363
1364 spin_lock_irqsave(&rtc_lock, flags);
1365 err = -ENODEV;
1366 if (this_is_starfire)
1367 err = starfire_set_time(seconds);
1368 else if (tlb_type == hypervisor)
1369 err = hypervisor_set_time(seconds);
1370 spin_unlock_irqrestore(&rtc_lock, flags);
1371
1372 return err;
1373}
1374
1375static int mini_rtc_ioctl(struct inode *inode, struct file *file,
1376 unsigned int cmd, unsigned long arg)
1377{
1378 struct rtc_time wtime;
1379 void __user *argp = (void __user *)arg;
1380
1381 switch (cmd) {
1382
1383 case RTC_PLL_GET:
1384 return -EINVAL;
1385
1386 case RTC_PLL_SET:
1387 return -EINVAL;
1388
1389 case RTC_UIE_OFF: /* disable ints from RTC updates. */
1390 return 0;
1391
1392 case RTC_UIE_ON: /* enable ints for RTC updates. */
1393 return -EINVAL;
1394
1395 case RTC_RD_TIME: /* Read the time/date from RTC */
1396 /* this doesn't get week-day, who cares */
1397 memset(&wtime, 0, sizeof(wtime));
1398 mini_get_rtc_time(&wtime);
1399
1400 return copy_to_user(argp, &wtime, sizeof(wtime)) ? -EFAULT : 0;
1401
1402 case RTC_SET_TIME: /* Set the RTC */
1403 {
1404 int year;
1405 unsigned char leap_yr;
1406
1407 if (!capable(CAP_SYS_TIME))
1408 return -EACCES;
1409
1410 if (copy_from_user(&wtime, argp, sizeof(wtime)))
1411 return -EFAULT;
1412
1413 year = wtime.tm_year + 1900;
1414 leap_yr = ((!(year % 4) && (year % 100)) ||
1415 !(year % 400));
1416
1417 if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) || (wtime.tm_mday < 1))
1418 return -EINVAL;
1419
1420 if (wtime.tm_mday < 0 || wtime.tm_mday >
1421 (days_in_mo[wtime.tm_mon] + ((wtime.tm_mon == 1) && leap_yr)))
1422 return -EINVAL;
1423
1424 if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 ||
1425 wtime.tm_min < 0 || wtime.tm_min >= 60 ||
1426 wtime.tm_sec < 0 || wtime.tm_sec >= 60)
1427 return -EINVAL;
1428
1429 return mini_set_rtc_time(&wtime);
1430 }
1431 }
1432
1433 return -EINVAL;
1434}
1435
1436static int mini_rtc_open(struct inode *inode, struct file *file)
1437{
1438 if (mini_rtc_status & RTC_IS_OPEN)
1439 return -EBUSY;
1440
1441 mini_rtc_status |= RTC_IS_OPEN;
1442
1443 return 0;
1444}
1445
1446static int mini_rtc_release(struct inode *inode, struct file *file)
1447{
1448 mini_rtc_status &= ~RTC_IS_OPEN;
1449 return 0;
1450}
1451
1452
1453static struct file_operations mini_rtc_fops = {
1454 .owner = THIS_MODULE,
1455 .ioctl = mini_rtc_ioctl,
1456 .open = mini_rtc_open,
1457 .release = mini_rtc_release,
1458};
1459
1460static struct miscdevice rtc_mini_dev =
1461{
1462 .minor = RTC_MINOR,
1463 .name = "rtc",
1464 .fops = &mini_rtc_fops,
1465};
1466
1467static int __init rtc_mini_init(void)
1468{
1469 int retval;
1470
1471 if (tlb_type != hypervisor && !this_is_starfire)
1472 return -ENODEV;
1473
1474 printk(KERN_INFO "Mini RTC Driver\n");
1475
1476 retval = misc_register(&rtc_mini_dev);
1477 if (retval < 0)
1478 return retval;
1479
1480 return 0;
1481}
1482
1483static void __exit rtc_mini_exit(void)
1484{
1485 misc_deregister(&rtc_mini_dev);
1486}
1487
1488
1489module_init(rtc_mini_init);
1490module_exit(rtc_mini_exit);