xref: /linux/arch/mips/sgi-ip27/ip27-timer.c (revision cc25ab008633ffd6010f01003ad380f9c7dd5374)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Copytight (C) 1999, 2000, 05 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 extern volatile unsigned long wall_jiffies;
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds #if 0
481da177e4SLinus Torvalds static int set_rtc_mmss(unsigned long nowtime)
491da177e4SLinus Torvalds {
501da177e4SLinus Torvalds 	int retval = 0;
511da177e4SLinus Torvalds 	int real_seconds, real_minutes, cmos_minutes;
521da177e4SLinus Torvalds 	struct m48t35_rtc *rtc;
531da177e4SLinus Torvalds 	nasid_t nid;
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds 	nid = get_nasid();
561da177e4SLinus Torvalds 	rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base +
571da177e4SLinus Torvalds 							IOC3_BYTEBUS_DEV0);
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds 	rtc->control |= M48T35_RTC_READ;
601da177e4SLinus Torvalds 	cmos_minutes = BCD2BIN(rtc->min);
611da177e4SLinus Torvalds 	rtc->control &= ~M48T35_RTC_READ;
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds 	/*
641da177e4SLinus Torvalds 	 * Since we're only adjusting minutes and seconds, don't interfere with
651da177e4SLinus Torvalds 	 * hour overflow. This avoids messing with unknown time zones but
661da177e4SLinus Torvalds 	 * requires your RTC not to be off by more than 15 minutes
671da177e4SLinus Torvalds 	 */
681da177e4SLinus Torvalds 	real_seconds = nowtime % 60;
691da177e4SLinus Torvalds 	real_minutes = nowtime / 60;
701da177e4SLinus Torvalds 	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
711da177e4SLinus Torvalds 		real_minutes += 30;	/* correct for half hour time zone */
721da177e4SLinus Torvalds 	real_minutes %= 60;
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds 	if (abs(real_minutes - cmos_minutes) < 30) {
751da177e4SLinus Torvalds 		real_seconds = BIN2BCD(real_seconds);
761da177e4SLinus Torvalds 		real_minutes = BIN2BCD(real_minutes);
771da177e4SLinus Torvalds 		rtc->control |= M48T35_RTC_SET;
781da177e4SLinus Torvalds 		rtc->sec = real_seconds;
791da177e4SLinus Torvalds 		rtc->min = real_minutes;
801da177e4SLinus Torvalds 		rtc->control &= ~M48T35_RTC_SET;
811da177e4SLinus Torvalds 	} else {
821da177e4SLinus Torvalds 		printk(KERN_WARNING
831da177e4SLinus Torvalds 		       "set_rtc_mmss: can't update from %d to %d\n",
841da177e4SLinus Torvalds 		       cmos_minutes, real_minutes);
851da177e4SLinus Torvalds 		retval = -1;
861da177e4SLinus Torvalds 	}
871da177e4SLinus Torvalds 
881da177e4SLinus Torvalds 	return retval;
891da177e4SLinus Torvalds }
901da177e4SLinus Torvalds #endif
911da177e4SLinus Torvalds 
923c009442SRalf Baechle static unsigned int rt_timer_irq;
933c009442SRalf Baechle 
941da177e4SLinus Torvalds void ip27_rt_timer_interrupt(struct pt_regs *regs)
951da177e4SLinus Torvalds {
961da177e4SLinus Torvalds 	int cpu = smp_processor_id();
971da177e4SLinus Torvalds 	int cpuA = cputoslice(cpu) == 0;
983c009442SRalf Baechle 	unsigned int irq = rt_timer_irq;
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds 	irq_enter();
1011da177e4SLinus Torvalds 	write_seqlock(&xtime_lock);
1021da177e4SLinus Torvalds 
1031da177e4SLinus Torvalds again:
1041da177e4SLinus Torvalds 	LOCAL_HUB_S(cpuA ? PI_RT_PEND_A : PI_RT_PEND_B, 0);	/* Ack  */
1051da177e4SLinus Torvalds 	ct_cur[cpu] += CYCLES_PER_JIFFY;
1061da177e4SLinus Torvalds 	LOCAL_HUB_S(cpuA ? PI_RT_COMPARE_A : PI_RT_COMPARE_B, ct_cur[cpu]);
1071da177e4SLinus Torvalds 
1081da177e4SLinus Torvalds 	if (LOCAL_HUB_L(PI_RT_COUNT) >= ct_cur[cpu])
1091da177e4SLinus Torvalds 		goto again;
1101da177e4SLinus Torvalds 
1111da177e4SLinus Torvalds 	kstat_this_cpu.irqs[irq]++;		/* kstat only for bootcpu? */
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds 	if (cpu == 0)
1141da177e4SLinus Torvalds 		do_timer(regs);
1151da177e4SLinus Torvalds 
1161da177e4SLinus Torvalds 	update_process_times(user_mode(regs));
1171da177e4SLinus Torvalds 
1181da177e4SLinus Torvalds 	/*
1191da177e4SLinus Torvalds 	 * If we have an externally synchronized Linux clock, then update
1201da177e4SLinus Torvalds 	 * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
1211da177e4SLinus Torvalds 	 * called as close as possible to when a second starts.
1221da177e4SLinus Torvalds 	 */
123b149ee22Sjohn stultz 	if (ntp_synced() &&
1241da177e4SLinus Torvalds 	    xtime.tv_sec > last_rtc_update + 660 &&
1251da177e4SLinus Torvalds 	    (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
1261da177e4SLinus Torvalds 	    (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
127c0858d82SAtsushi Nemoto 		if (rtc_mips_set_time(xtime.tv_sec) == 0) {
1281da177e4SLinus Torvalds 			last_rtc_update = xtime.tv_sec;
1291da177e4SLinus Torvalds 		} else {
1301da177e4SLinus Torvalds 			last_rtc_update = xtime.tv_sec - 600;
1311da177e4SLinus Torvalds 			/* do it again in 60 s */
1321da177e4SLinus Torvalds 		}
1331da177e4SLinus Torvalds 	}
1341da177e4SLinus Torvalds 
1351da177e4SLinus Torvalds 	write_sequnlock(&xtime_lock);
1361da177e4SLinus Torvalds 	irq_exit();
1371da177e4SLinus Torvalds }
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds unsigned long ip27_do_gettimeoffset(void)
1401da177e4SLinus Torvalds {
1411da177e4SLinus Torvalds 	unsigned long ct_cur1;
1421da177e4SLinus Torvalds 	ct_cur1 = REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT) + CYCLES_PER_JIFFY;
1431da177e4SLinus Torvalds 	return (ct_cur1 - ct_cur[0]) * NSEC_PER_CYCLE / 1000;
1441da177e4SLinus Torvalds }
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds /* Includes for ioc3_init().  */
1471da177e4SLinus Torvalds #include <asm/sn/types.h>
1481da177e4SLinus Torvalds #include <asm/sn/sn0/addrs.h>
1491da177e4SLinus Torvalds #include <asm/sn/sn0/hubni.h>
1501da177e4SLinus Torvalds #include <asm/sn/sn0/hubio.h>
1511da177e4SLinus Torvalds #include <asm/pci/bridge.h>
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds static __init unsigned long get_m48t35_time(void)
1541da177e4SLinus Torvalds {
1551da177e4SLinus Torvalds         unsigned int year, month, date, hour, min, sec;
1561da177e4SLinus Torvalds 	struct m48t35_rtc *rtc;
1571da177e4SLinus Torvalds 	nasid_t nid;
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds 	nid = get_nasid();
1601da177e4SLinus Torvalds 	rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base +
1611da177e4SLinus Torvalds 							IOC3_BYTEBUS_DEV0);
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds 	rtc->control |= M48T35_RTC_READ;
1641da177e4SLinus Torvalds 	sec = rtc->sec;
1651da177e4SLinus Torvalds 	min = rtc->min;
1661da177e4SLinus Torvalds 	hour = rtc->hour;
1671da177e4SLinus Torvalds 	date = rtc->date;
1681da177e4SLinus Torvalds 	month = rtc->month;
1691da177e4SLinus Torvalds 	year = rtc->year;
1701da177e4SLinus Torvalds 	rtc->control &= ~M48T35_RTC_READ;
1711da177e4SLinus Torvalds 
1721da177e4SLinus Torvalds         sec = BCD2BIN(sec);
1731da177e4SLinus Torvalds         min = BCD2BIN(min);
1741da177e4SLinus Torvalds         hour = BCD2BIN(hour);
1751da177e4SLinus Torvalds         date = BCD2BIN(date);
1761da177e4SLinus Torvalds         month = BCD2BIN(month);
1771da177e4SLinus Torvalds         year = BCD2BIN(year);
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds         year += 1970;
1801da177e4SLinus Torvalds 
1811da177e4SLinus Torvalds         return mktime(year, month, date, hour, min, sec);
1821da177e4SLinus Torvalds }
1831da177e4SLinus Torvalds 
184*cc25ab00SRalf Baechle static unsigned int startup_rt_irq(unsigned int irq)
1853c009442SRalf Baechle {
186*cc25ab00SRalf Baechle 	return 0;
1873c009442SRalf Baechle }
1883c009442SRalf Baechle 
1893c009442SRalf Baechle static void shutdown_rt_irq(unsigned int irq)
1903c009442SRalf Baechle {
1913c009442SRalf Baechle }
1923c009442SRalf Baechle 
1933c009442SRalf Baechle static void enable_rt_irq(unsigned int irq)
1943c009442SRalf Baechle {
1953c009442SRalf Baechle }
1963c009442SRalf Baechle 
1973c009442SRalf Baechle static void disable_rt_irq(unsigned int irq)
1983c009442SRalf Baechle {
1993c009442SRalf Baechle }
2003c009442SRalf Baechle 
2013c009442SRalf Baechle static void mask_and_ack_rt(unsigned int irq)
2023c009442SRalf Baechle {
2033c009442SRalf Baechle }
2043c009442SRalf Baechle 
2053c009442SRalf Baechle static void end_rt_irq(unsigned int irq)
2063c009442SRalf Baechle {
2073c009442SRalf Baechle }
2083c009442SRalf Baechle 
20994dee171SRalf Baechle static struct irq_chip rt_irq_type = {
2103c009442SRalf Baechle 	.typename	= "SN HUB RT timer",
2113c009442SRalf Baechle 	.startup	= startup_rt_irq,
2123c009442SRalf Baechle 	.shutdown	= shutdown_rt_irq,
2133c009442SRalf Baechle 	.enable		= enable_rt_irq,
2143c009442SRalf Baechle 	.disable	= disable_rt_irq,
2153c009442SRalf Baechle 	.ack		= mask_and_ack_rt,
2163c009442SRalf Baechle 	.end		= end_rt_irq,
2173c009442SRalf Baechle };
2183c009442SRalf Baechle 
2193c009442SRalf Baechle static struct irqaction rt_irqaction = {
2203c009442SRalf Baechle 	.handler	= ip27_rt_timer_interrupt,
221f40298fdSThomas Gleixner 	.flags		= IRQF_DISABLED,
2223c009442SRalf Baechle 	.mask		= CPU_MASK_NONE,
2233c009442SRalf Baechle 	.name		= "timer"
2243c009442SRalf Baechle };
2253c009442SRalf Baechle 
2263c009442SRalf Baechle extern int allocate_irqno(void);
2273c009442SRalf Baechle 
2281da177e4SLinus Torvalds static void ip27_timer_setup(struct irqaction *irq)
2291da177e4SLinus Torvalds {
2303c009442SRalf Baechle 	int irqno  = allocate_irqno();
2313c009442SRalf Baechle 
2323c009442SRalf Baechle 	if (irqno < 0)
2333c009442SRalf Baechle 		panic("Can't allocate interrupt number for timer interrupt");
2343c009442SRalf Baechle 
2353c009442SRalf Baechle 	irq_desc[irqno].status = IRQ_DISABLED;
2363c009442SRalf Baechle 	irq_desc[irqno].action = NULL;
2373c009442SRalf Baechle 	irq_desc[irqno].depth = 1;
238a365e53fSRalf Baechle 	irq_desc[irqno].chip = &rt_irq_type;
2393c009442SRalf Baechle 
2401da177e4SLinus Torvalds 	/* over-write the handler, we use our own way */
2411da177e4SLinus Torvalds 	irq->handler = no_action;
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds 	/* setup irqaction */
2443c009442SRalf Baechle 	irq_desc[irqno].status |= IRQ_PER_CPU;
2453c009442SRalf Baechle 
2463c009442SRalf Baechle 	rt_timer_irq = irqno;
2471da177e4SLinus Torvalds }
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds void __init ip27_time_init(void)
2501da177e4SLinus Torvalds {
2511da177e4SLinus Torvalds 	xtime.tv_sec = get_m48t35_time();
2521da177e4SLinus Torvalds 	xtime.tv_nsec = 0;
2531da177e4SLinus Torvalds 
2541da177e4SLinus Torvalds 	do_gettimeoffset = ip27_do_gettimeoffset;
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds 	board_timer_setup = ip27_timer_setup;
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