11da177e4SLinus Torvalds /* 254d0a216SRalf Baechle * Copytight (C) 1999, 2000, 05, 06 Ralf Baechle (ralf@linux-mips.org) 31da177e4SLinus Torvalds * Copytight (C) 1999, 2000 Silicon Graphics, Inc. 41da177e4SLinus Torvalds */ 51da177e4SLinus Torvalds #include <linux/bcd.h> 61da177e4SLinus Torvalds #include <linux/init.h> 71da177e4SLinus Torvalds #include <linux/kernel.h> 81da177e4SLinus Torvalds #include <linux/sched.h> 91da177e4SLinus Torvalds #include <linux/interrupt.h> 101da177e4SLinus Torvalds #include <linux/kernel_stat.h> 111da177e4SLinus Torvalds #include <linux/param.h> 121da177e4SLinus Torvalds #include <linux/time.h> 131da177e4SLinus Torvalds #include <linux/timex.h> 141da177e4SLinus Torvalds #include <linux/mm.h> 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds #include <asm/time.h> 171da177e4SLinus Torvalds #include <asm/pgtable.h> 181da177e4SLinus Torvalds #include <asm/sgialib.h> 191da177e4SLinus Torvalds #include <asm/sn/ioc3.h> 201da177e4SLinus Torvalds #include <asm/m48t35.h> 211da177e4SLinus Torvalds #include <asm/sn/klconfig.h> 221da177e4SLinus Torvalds #include <asm/sn/arch.h> 231da177e4SLinus Torvalds #include <asm/sn/addrs.h> 241da177e4SLinus Torvalds #include <asm/sn/sn_private.h> 251da177e4SLinus Torvalds #include <asm/sn/sn0/ip27.h> 261da177e4SLinus Torvalds #include <asm/sn/sn0/hub.h> 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds /* 291da177e4SLinus Torvalds * This is a hack; we really need to figure these values out dynamically 301da177e4SLinus Torvalds * 311da177e4SLinus Torvalds * Since 800 ns works very well with various HUB frequencies, such as 321da177e4SLinus Torvalds * 360, 380, 390 and 400 MHZ, we use 800 ns rtc cycle time. 331da177e4SLinus Torvalds * 341da177e4SLinus Torvalds * Ralf: which clock rate is used to feed the counter? 351da177e4SLinus Torvalds */ 361da177e4SLinus Torvalds #define NSEC_PER_CYCLE 800 371da177e4SLinus Torvalds #define CYCLES_PER_SEC (NSEC_PER_SEC/NSEC_PER_CYCLE) 381da177e4SLinus Torvalds #define CYCLES_PER_JIFFY (CYCLES_PER_SEC/HZ) 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds #define TICK_SIZE (tick_nsec / 1000) 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds static unsigned long ct_cur[NR_CPUS]; /* What counter should be at next timer irq */ 431da177e4SLinus Torvalds static long last_rtc_update; /* Last time the rtc clock got updated */ 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds #if 0 461da177e4SLinus Torvalds static int set_rtc_mmss(unsigned long nowtime) 471da177e4SLinus Torvalds { 481da177e4SLinus Torvalds int retval = 0; 491da177e4SLinus Torvalds int real_seconds, real_minutes, cmos_minutes; 501da177e4SLinus Torvalds struct m48t35_rtc *rtc; 511da177e4SLinus Torvalds nasid_t nid; 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds nid = get_nasid(); 541da177e4SLinus Torvalds rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base + 551da177e4SLinus Torvalds IOC3_BYTEBUS_DEV0); 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds rtc->control |= M48T35_RTC_READ; 581da177e4SLinus Torvalds cmos_minutes = BCD2BIN(rtc->min); 591da177e4SLinus Torvalds rtc->control &= ~M48T35_RTC_READ; 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds /* 621da177e4SLinus Torvalds * Since we're only adjusting minutes and seconds, don't interfere with 631da177e4SLinus Torvalds * hour overflow. This avoids messing with unknown time zones but 641da177e4SLinus Torvalds * requires your RTC not to be off by more than 15 minutes 651da177e4SLinus Torvalds */ 661da177e4SLinus Torvalds real_seconds = nowtime % 60; 671da177e4SLinus Torvalds real_minutes = nowtime / 60; 681da177e4SLinus Torvalds if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) 691da177e4SLinus Torvalds real_minutes += 30; /* correct for half hour time zone */ 701da177e4SLinus Torvalds real_minutes %= 60; 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds if (abs(real_minutes - cmos_minutes) < 30) { 731da177e4SLinus Torvalds real_seconds = BIN2BCD(real_seconds); 741da177e4SLinus Torvalds real_minutes = BIN2BCD(real_minutes); 751da177e4SLinus Torvalds rtc->control |= M48T35_RTC_SET; 761da177e4SLinus Torvalds rtc->sec = real_seconds; 771da177e4SLinus Torvalds rtc->min = real_minutes; 781da177e4SLinus Torvalds rtc->control &= ~M48T35_RTC_SET; 791da177e4SLinus Torvalds } else { 801da177e4SLinus Torvalds printk(KERN_WARNING 811da177e4SLinus Torvalds "set_rtc_mmss: can't update from %d to %d\n", 821da177e4SLinus Torvalds cmos_minutes, real_minutes); 831da177e4SLinus Torvalds retval = -1; 841da177e4SLinus Torvalds } 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds return retval; 871da177e4SLinus Torvalds } 881da177e4SLinus Torvalds #endif 891da177e4SLinus Torvalds 903c009442SRalf Baechle static unsigned int rt_timer_irq; 913c009442SRalf Baechle 92*937a8015SRalf Baechle void ip27_rt_timer_interrupt(void) 931da177e4SLinus Torvalds { 941da177e4SLinus Torvalds int cpu = smp_processor_id(); 951da177e4SLinus Torvalds int cpuA = cputoslice(cpu) == 0; 963c009442SRalf Baechle unsigned int irq = rt_timer_irq; 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds irq_enter(); 991da177e4SLinus Torvalds write_seqlock(&xtime_lock); 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds again: 1021da177e4SLinus Torvalds LOCAL_HUB_S(cpuA ? PI_RT_PEND_A : PI_RT_PEND_B, 0); /* Ack */ 1031da177e4SLinus Torvalds ct_cur[cpu] += CYCLES_PER_JIFFY; 1041da177e4SLinus Torvalds LOCAL_HUB_S(cpuA ? PI_RT_COMPARE_A : PI_RT_COMPARE_B, ct_cur[cpu]); 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds if (LOCAL_HUB_L(PI_RT_COUNT) >= ct_cur[cpu]) 1071da177e4SLinus Torvalds goto again; 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds kstat_this_cpu.irqs[irq]++; /* kstat only for bootcpu? */ 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds if (cpu == 0) 1123171a030SAtsushi Nemoto do_timer(1); 1131da177e4SLinus Torvalds 114*937a8015SRalf Baechle update_process_times(user_mode(get_irq_regs())); 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds /* 1171da177e4SLinus Torvalds * If we have an externally synchronized Linux clock, then update 1181da177e4SLinus Torvalds * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be 1191da177e4SLinus Torvalds * called as close as possible to when a second starts. 1201da177e4SLinus Torvalds */ 121b149ee22Sjohn stultz if (ntp_synced() && 1221da177e4SLinus Torvalds xtime.tv_sec > last_rtc_update + 660 && 1231da177e4SLinus Torvalds (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && 1241da177e4SLinus Torvalds (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { 125c0858d82SAtsushi Nemoto if (rtc_mips_set_time(xtime.tv_sec) == 0) { 1261da177e4SLinus Torvalds last_rtc_update = xtime.tv_sec; 1271da177e4SLinus Torvalds } else { 1281da177e4SLinus Torvalds last_rtc_update = xtime.tv_sec - 600; 1291da177e4SLinus Torvalds /* do it again in 60 s */ 1301da177e4SLinus Torvalds } 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds write_sequnlock(&xtime_lock); 1341da177e4SLinus Torvalds irq_exit(); 1351da177e4SLinus Torvalds } 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds unsigned long ip27_do_gettimeoffset(void) 1381da177e4SLinus Torvalds { 1391da177e4SLinus Torvalds unsigned long ct_cur1; 1401da177e4SLinus Torvalds ct_cur1 = REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT) + CYCLES_PER_JIFFY; 1411da177e4SLinus Torvalds return (ct_cur1 - ct_cur[0]) * NSEC_PER_CYCLE / 1000; 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds /* Includes for ioc3_init(). */ 1451da177e4SLinus Torvalds #include <asm/sn/types.h> 1461da177e4SLinus Torvalds #include <asm/sn/sn0/addrs.h> 1471da177e4SLinus Torvalds #include <asm/sn/sn0/hubni.h> 1481da177e4SLinus Torvalds #include <asm/sn/sn0/hubio.h> 1491da177e4SLinus Torvalds #include <asm/pci/bridge.h> 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds static __init unsigned long get_m48t35_time(void) 1521da177e4SLinus Torvalds { 1531da177e4SLinus Torvalds unsigned int year, month, date, hour, min, sec; 1541da177e4SLinus Torvalds struct m48t35_rtc *rtc; 1551da177e4SLinus Torvalds nasid_t nid; 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds nid = get_nasid(); 1581da177e4SLinus Torvalds rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base + 1591da177e4SLinus Torvalds IOC3_BYTEBUS_DEV0); 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds rtc->control |= M48T35_RTC_READ; 1621da177e4SLinus Torvalds sec = rtc->sec; 1631da177e4SLinus Torvalds min = rtc->min; 1641da177e4SLinus Torvalds hour = rtc->hour; 1651da177e4SLinus Torvalds date = rtc->date; 1661da177e4SLinus Torvalds month = rtc->month; 1671da177e4SLinus Torvalds year = rtc->year; 1681da177e4SLinus Torvalds rtc->control &= ~M48T35_RTC_READ; 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds sec = BCD2BIN(sec); 1711da177e4SLinus Torvalds min = BCD2BIN(min); 1721da177e4SLinus Torvalds hour = BCD2BIN(hour); 1731da177e4SLinus Torvalds date = BCD2BIN(date); 1741da177e4SLinus Torvalds month = BCD2BIN(month); 1751da177e4SLinus Torvalds year = BCD2BIN(year); 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds year += 1970; 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds return mktime(year, month, date, hour, min, sec); 1801da177e4SLinus Torvalds } 1811da177e4SLinus Torvalds 182cc25ab00SRalf Baechle static unsigned int startup_rt_irq(unsigned int irq) 1833c009442SRalf Baechle { 184cc25ab00SRalf Baechle return 0; 1853c009442SRalf Baechle } 1863c009442SRalf Baechle 1873c009442SRalf Baechle static void shutdown_rt_irq(unsigned int irq) 1883c009442SRalf Baechle { 1893c009442SRalf Baechle } 1903c009442SRalf Baechle 1913c009442SRalf Baechle static void enable_rt_irq(unsigned int irq) 1923c009442SRalf Baechle { 1933c009442SRalf Baechle } 1943c009442SRalf Baechle 1953c009442SRalf Baechle static void disable_rt_irq(unsigned int irq) 1963c009442SRalf Baechle { 1973c009442SRalf Baechle } 1983c009442SRalf Baechle 1993c009442SRalf Baechle static void mask_and_ack_rt(unsigned int irq) 2003c009442SRalf Baechle { 2013c009442SRalf Baechle } 2023c009442SRalf Baechle 2033c009442SRalf Baechle static void end_rt_irq(unsigned int irq) 2043c009442SRalf Baechle { 2053c009442SRalf Baechle } 2063c009442SRalf Baechle 20794dee171SRalf Baechle static struct irq_chip rt_irq_type = { 2083c009442SRalf Baechle .typename = "SN HUB RT timer", 2093c009442SRalf Baechle .startup = startup_rt_irq, 2103c009442SRalf Baechle .shutdown = shutdown_rt_irq, 2113c009442SRalf Baechle .enable = enable_rt_irq, 2123c009442SRalf Baechle .disable = disable_rt_irq, 2133c009442SRalf Baechle .ack = mask_and_ack_rt, 2143c009442SRalf Baechle .end = end_rt_irq, 2153c009442SRalf Baechle }; 2163c009442SRalf Baechle 2173c009442SRalf Baechle static struct irqaction rt_irqaction = { 2183c009442SRalf Baechle .handler = ip27_rt_timer_interrupt, 219f40298fdSThomas Gleixner .flags = IRQF_DISABLED, 2203c009442SRalf Baechle .mask = CPU_MASK_NONE, 2213c009442SRalf Baechle .name = "timer" 2223c009442SRalf Baechle }; 2233c009442SRalf Baechle 2243c009442SRalf Baechle extern int allocate_irqno(void); 2253c009442SRalf Baechle 22654d0a216SRalf Baechle void __init plat_timer_setup(struct irqaction *irq) 2271da177e4SLinus Torvalds { 2283c009442SRalf Baechle int irqno = allocate_irqno(); 2293c009442SRalf Baechle 2303c009442SRalf Baechle if (irqno < 0) 2313c009442SRalf Baechle panic("Can't allocate interrupt number for timer interrupt"); 2323c009442SRalf Baechle 2333c009442SRalf Baechle irq_desc[irqno].status = IRQ_DISABLED; 2343c009442SRalf Baechle irq_desc[irqno].action = NULL; 2353c009442SRalf Baechle irq_desc[irqno].depth = 1; 236a365e53fSRalf Baechle irq_desc[irqno].chip = &rt_irq_type; 2373c009442SRalf Baechle 2381da177e4SLinus Torvalds /* over-write the handler, we use our own way */ 2391da177e4SLinus Torvalds irq->handler = no_action; 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds /* setup irqaction */ 2423c009442SRalf Baechle irq_desc[irqno].status |= IRQ_PER_CPU; 2433c009442SRalf Baechle 2443c009442SRalf Baechle rt_timer_irq = irqno; 245bf283630SRalf Baechle /* 246bf283630SRalf Baechle * Only needed to get /proc/interrupt to display timer irq stats 247bf283630SRalf Baechle */ 248bf283630SRalf Baechle setup_irq(irqno, &rt_irqaction); 2491da177e4SLinus Torvalds } 2501da177e4SLinus Torvalds 2511da177e4SLinus Torvalds void __init ip27_time_init(void) 2521da177e4SLinus Torvalds { 2531da177e4SLinus Torvalds xtime.tv_sec = get_m48t35_time(); 2541da177e4SLinus Torvalds xtime.tv_nsec = 0; 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds do_gettimeoffset = ip27_do_gettimeoffset; 2571da177e4SLinus Torvalds } 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds void __init cpu_time_init(void) 2601da177e4SLinus Torvalds { 2611da177e4SLinus Torvalds lboard_t *board; 2621da177e4SLinus Torvalds klcpu_t *cpu; 2631da177e4SLinus Torvalds int cpuid; 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds /* Don't use ARCS. ARCS is fragile. Klconfig is simple and sane. */ 2661da177e4SLinus Torvalds board = find_lboard(KL_CONFIG_INFO(get_nasid()), KLTYPE_IP27); 2671da177e4SLinus Torvalds if (!board) 2681da177e4SLinus Torvalds panic("Can't find board info for myself."); 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds cpuid = LOCAL_HUB_L(PI_CPU_NUM) ? IP27_CPU0_INDEX : IP27_CPU1_INDEX; 2711da177e4SLinus Torvalds cpu = (klcpu_t *) KLCF_COMP(board, cpuid); 2721da177e4SLinus Torvalds if (!cpu) 2731da177e4SLinus Torvalds panic("No information about myself?"); 2741da177e4SLinus Torvalds 2751da177e4SLinus Torvalds printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed); 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds set_c0_status(SRB_TIMOCLK); 2781da177e4SLinus Torvalds } 2791da177e4SLinus Torvalds 2801da177e4SLinus Torvalds void __init hub_rtc_init(cnodeid_t cnode) 2811da177e4SLinus Torvalds { 2821da177e4SLinus Torvalds /* 2831da177e4SLinus Torvalds * We only need to initialize the current node. 2841da177e4SLinus Torvalds * If this is not the current node then it is a cpuless 2851da177e4SLinus Torvalds * node and timeouts will not happen there. 2861da177e4SLinus Torvalds */ 2871da177e4SLinus Torvalds if (get_compact_nodeid() == cnode) { 2881da177e4SLinus Torvalds int cpu = smp_processor_id(); 2891da177e4SLinus Torvalds LOCAL_HUB_S(PI_RT_EN_A, 1); 2901da177e4SLinus Torvalds LOCAL_HUB_S(PI_RT_EN_B, 1); 2911da177e4SLinus Torvalds LOCAL_HUB_S(PI_PROF_EN_A, 0); 2921da177e4SLinus Torvalds LOCAL_HUB_S(PI_PROF_EN_B, 0); 2931da177e4SLinus Torvalds ct_cur[cpu] = CYCLES_PER_JIFFY; 2941da177e4SLinus Torvalds LOCAL_HUB_S(PI_RT_COMPARE_A, ct_cur[cpu]); 2951da177e4SLinus Torvalds LOCAL_HUB_S(PI_RT_COUNT, 0); 2961da177e4SLinus Torvalds LOCAL_HUB_S(PI_RT_PEND_A, 0); 2971da177e4SLinus Torvalds LOCAL_HUB_S(PI_RT_COMPARE_B, ct_cur[cpu]); 2981da177e4SLinus Torvalds LOCAL_HUB_S(PI_RT_COUNT, 0); 2991da177e4SLinus Torvalds LOCAL_HUB_S(PI_RT_PEND_B, 0); 3001da177e4SLinus Torvalds } 3011da177e4SLinus Torvalds } 302