xref: /linux/arch/mips/sgi-ip27/ip27-timer.c (revision e887b24592c5ddf46d37e592b2ee6bd2188257e1)
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>
6*e887b245SRalf Baechle #include <linux/clockchips.h>
71da177e4SLinus Torvalds #include <linux/init.h>
81da177e4SLinus Torvalds #include <linux/kernel.h>
91da177e4SLinus Torvalds #include <linux/sched.h>
101da177e4SLinus Torvalds #include <linux/interrupt.h>
111da177e4SLinus Torvalds #include <linux/kernel_stat.h>
121da177e4SLinus Torvalds #include <linux/param.h>
131da177e4SLinus Torvalds #include <linux/time.h>
141da177e4SLinus Torvalds #include <linux/timex.h>
151da177e4SLinus Torvalds #include <linux/mm.h>
161da177e4SLinus Torvalds 
171da177e4SLinus Torvalds #include <asm/time.h>
181da177e4SLinus Torvalds #include <asm/pgtable.h>
191da177e4SLinus Torvalds #include <asm/sgialib.h>
201da177e4SLinus Torvalds #include <asm/sn/ioc3.h>
211da177e4SLinus Torvalds #include <asm/m48t35.h>
221da177e4SLinus Torvalds #include <asm/sn/klconfig.h>
231da177e4SLinus Torvalds #include <asm/sn/arch.h>
241da177e4SLinus Torvalds #include <asm/sn/addrs.h>
251da177e4SLinus Torvalds #include <asm/sn/sn_private.h>
261da177e4SLinus Torvalds #include <asm/sn/sn0/ip27.h>
271da177e4SLinus Torvalds #include <asm/sn/sn0/hub.h>
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds #define TICK_SIZE (tick_nsec / 1000)
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds #if 0
321da177e4SLinus Torvalds static int set_rtc_mmss(unsigned long nowtime)
331da177e4SLinus Torvalds {
341da177e4SLinus Torvalds 	int retval = 0;
351da177e4SLinus Torvalds 	int real_seconds, real_minutes, cmos_minutes;
361da177e4SLinus Torvalds 	struct m48t35_rtc *rtc;
371da177e4SLinus Torvalds 	nasid_t nid;
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds 	nid = get_nasid();
401da177e4SLinus Torvalds 	rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base +
411da177e4SLinus Torvalds 							IOC3_BYTEBUS_DEV0);
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds 	rtc->control |= M48T35_RTC_READ;
441da177e4SLinus Torvalds 	cmos_minutes = BCD2BIN(rtc->min);
451da177e4SLinus Torvalds 	rtc->control &= ~M48T35_RTC_READ;
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds 	/*
481da177e4SLinus Torvalds 	 * Since we're only adjusting minutes and seconds, don't interfere with
491da177e4SLinus Torvalds 	 * hour overflow. This avoids messing with unknown time zones but
501da177e4SLinus Torvalds 	 * requires your RTC not to be off by more than 15 minutes
511da177e4SLinus Torvalds 	 */
521da177e4SLinus Torvalds 	real_seconds = nowtime % 60;
531da177e4SLinus Torvalds 	real_minutes = nowtime / 60;
541da177e4SLinus Torvalds 	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
551da177e4SLinus Torvalds 		real_minutes += 30;	/* correct for half hour time zone */
561da177e4SLinus Torvalds 	real_minutes %= 60;
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds 	if (abs(real_minutes - cmos_minutes) < 30) {
591da177e4SLinus Torvalds 		real_seconds = BIN2BCD(real_seconds);
601da177e4SLinus Torvalds 		real_minutes = BIN2BCD(real_minutes);
611da177e4SLinus Torvalds 		rtc->control |= M48T35_RTC_SET;
621da177e4SLinus Torvalds 		rtc->sec = real_seconds;
631da177e4SLinus Torvalds 		rtc->min = real_minutes;
641da177e4SLinus Torvalds 		rtc->control &= ~M48T35_RTC_SET;
651da177e4SLinus Torvalds 	} else {
661da177e4SLinus Torvalds 		printk(KERN_WARNING
671da177e4SLinus Torvalds 		       "set_rtc_mmss: can't update from %d to %d\n",
681da177e4SLinus Torvalds 		       cmos_minutes, real_minutes);
691da177e4SLinus Torvalds 		retval = -1;
701da177e4SLinus Torvalds 	}
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds 	return retval;
731da177e4SLinus Torvalds }
741da177e4SLinus Torvalds #endif
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds /* Includes for ioc3_init().  */
771da177e4SLinus Torvalds #include <asm/sn/types.h>
781da177e4SLinus Torvalds #include <asm/sn/sn0/addrs.h>
791da177e4SLinus Torvalds #include <asm/sn/sn0/hubni.h>
801da177e4SLinus Torvalds #include <asm/sn/sn0/hubio.h>
811da177e4SLinus Torvalds #include <asm/pci/bridge.h>
821da177e4SLinus Torvalds 
834b550488SRalf Baechle unsigned long read_persistent_clock(void)
841da177e4SLinus Torvalds {
851da177e4SLinus Torvalds         unsigned int year, month, date, hour, min, sec;
861da177e4SLinus Torvalds 	struct m48t35_rtc *rtc;
871da177e4SLinus Torvalds 	nasid_t nid;
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds 	nid = get_nasid();
901da177e4SLinus Torvalds 	rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base +
911da177e4SLinus Torvalds 							IOC3_BYTEBUS_DEV0);
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds 	rtc->control |= M48T35_RTC_READ;
941da177e4SLinus Torvalds 	sec = rtc->sec;
951da177e4SLinus Torvalds 	min = rtc->min;
961da177e4SLinus Torvalds 	hour = rtc->hour;
971da177e4SLinus Torvalds 	date = rtc->date;
981da177e4SLinus Torvalds 	month = rtc->month;
991da177e4SLinus Torvalds 	year = rtc->year;
1001da177e4SLinus Torvalds 	rtc->control &= ~M48T35_RTC_READ;
1011da177e4SLinus Torvalds 
1021da177e4SLinus Torvalds         sec = BCD2BIN(sec);
1031da177e4SLinus Torvalds         min = BCD2BIN(min);
1041da177e4SLinus Torvalds         hour = BCD2BIN(hour);
1051da177e4SLinus Torvalds         date = BCD2BIN(date);
1061da177e4SLinus Torvalds         month = BCD2BIN(month);
1071da177e4SLinus Torvalds         year = BCD2BIN(year);
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds         year += 1970;
1101da177e4SLinus Torvalds 
1111da177e4SLinus Torvalds         return mktime(year, month, date, hour, min, sec);
1121da177e4SLinus Torvalds }
1131da177e4SLinus Torvalds 
114*e887b245SRalf Baechle static int rt_set_next_event(unsigned long delta,
115*e887b245SRalf Baechle 		struct clock_event_device *evt)
116*e887b245SRalf Baechle {
117*e887b245SRalf Baechle 	unsigned int cpu = smp_processor_id();
118*e887b245SRalf Baechle 	int slice = cputoslice(cpu) == 0;
119*e887b245SRalf Baechle 	unsigned long cnt;
120*e887b245SRalf Baechle 
121*e887b245SRalf Baechle 	cnt = LOCAL_HUB_L(PI_RT_COUNT);
122*e887b245SRalf Baechle 	cnt += delta;
123*e887b245SRalf Baechle 	LOCAL_HUB_S(slice ? PI_RT_COMPARE_A : PI_RT_COMPARE_B, cnt);
124*e887b245SRalf Baechle 
125*e887b245SRalf Baechle 	return LOCAL_HUB_L(PI_RT_COUNT) >= cnt ? -ETIME : 0;
126*e887b245SRalf Baechle }
127*e887b245SRalf Baechle 
128*e887b245SRalf Baechle static void rt_set_mode(enum clock_event_mode mode,
129*e887b245SRalf Baechle 		struct clock_event_device *evt)
130*e887b245SRalf Baechle {
131*e887b245SRalf Baechle 	switch (mode) {
132*e887b245SRalf Baechle 	case CLOCK_EVT_MODE_PERIODIC:
133*e887b245SRalf Baechle 		/* The only mode supported */
134*e887b245SRalf Baechle 		break;
135*e887b245SRalf Baechle 
136*e887b245SRalf Baechle 	case CLOCK_EVT_MODE_UNUSED:
137*e887b245SRalf Baechle 	case CLOCK_EVT_MODE_SHUTDOWN:
138*e887b245SRalf Baechle 	case CLOCK_EVT_MODE_ONESHOT:
139*e887b245SRalf Baechle 	case CLOCK_EVT_MODE_RESUME:
140*e887b245SRalf Baechle 		/* Nothing to do  */
141*e887b245SRalf Baechle 		break;
142*e887b245SRalf Baechle 	}
143*e887b245SRalf Baechle }
144*e887b245SRalf Baechle 
145*e887b245SRalf Baechle struct clock_event_device rt_clock_event_device = {
146*e887b245SRalf Baechle 	.name		= "HUB-RT",
147*e887b245SRalf Baechle 	.features	= CLOCK_EVT_FEAT_ONESHOT,
148*e887b245SRalf Baechle 
149*e887b245SRalf Baechle 	.rating		= 300,
150*e887b245SRalf Baechle 	.set_next_event	= rt_set_next_event,
151*e887b245SRalf Baechle 	.set_mode	= rt_set_mode,
152*e887b245SRalf Baechle };
153*e887b245SRalf Baechle 
1543c009442SRalf Baechle static void enable_rt_irq(unsigned int irq)
1553c009442SRalf Baechle {
1563c009442SRalf Baechle }
1573c009442SRalf Baechle 
1583c009442SRalf Baechle static void disable_rt_irq(unsigned int irq)
1593c009442SRalf Baechle {
1603c009442SRalf Baechle }
1613c009442SRalf Baechle 
16294dee171SRalf Baechle static struct irq_chip rt_irq_type = {
16370d21cdeSAtsushi Nemoto 	.name		= "SN HUB RT timer",
1641603b5acSAtsushi Nemoto 	.ack		= disable_rt_irq,
1651603b5acSAtsushi Nemoto 	.mask		= disable_rt_irq,
1661603b5acSAtsushi Nemoto 	.mask_ack	= disable_rt_irq,
1671603b5acSAtsushi Nemoto 	.unmask		= enable_rt_irq,
1681417836eSAtsushi Nemoto 	.eoi		= enable_rt_irq,
1693c009442SRalf Baechle };
1703c009442SRalf Baechle 
171*e887b245SRalf Baechle unsigned int rt_timer_irq;
172*e887b245SRalf Baechle 
173*e887b245SRalf Baechle static irqreturn_t ip27_rt_timer_interrupt(int irq, void *dev_id)
174*e887b245SRalf Baechle {
175*e887b245SRalf Baechle 	struct clock_event_device *cd = &rt_clock_event_device;
176*e887b245SRalf Baechle 	unsigned int cpu = smp_processor_id();
177*e887b245SRalf Baechle 	int slice = cputoslice(cpu) == 0;
178*e887b245SRalf Baechle 
179*e887b245SRalf Baechle 	LOCAL_HUB_S(slice ? PI_RT_PEND_A : PI_RT_PEND_B, 0);	/* Ack  */
180*e887b245SRalf Baechle 	cd->event_handler(cd);
181*e887b245SRalf Baechle 
182*e887b245SRalf Baechle 	return IRQ_HANDLED;
183*e887b245SRalf Baechle }
184*e887b245SRalf Baechle 
1853c009442SRalf Baechle static struct irqaction rt_irqaction = {
186f8aeb85fSRalf Baechle 	.handler	= (irq_handler_t) ip27_rt_timer_interrupt,
187f40298fdSThomas Gleixner 	.flags		= IRQF_DISABLED,
1883c009442SRalf Baechle 	.mask		= CPU_MASK_NONE,
1893c009442SRalf Baechle 	.name		= "timer"
1903c009442SRalf Baechle };
1913c009442SRalf Baechle 
192*e887b245SRalf Baechle /*
193*e887b245SRalf Baechle  * This is a hack; we really need to figure these values out dynamically
194*e887b245SRalf Baechle  *
195*e887b245SRalf Baechle  * Since 800 ns works very well with various HUB frequencies, such as
196*e887b245SRalf Baechle  * 360, 380, 390 and 400 MHZ, we use 800 ns rtc cycle time.
197*e887b245SRalf Baechle  *
198*e887b245SRalf Baechle  * Ralf: which clock rate is used to feed the counter?
199*e887b245SRalf Baechle  */
200*e887b245SRalf Baechle #define NSEC_PER_CYCLE		800
201*e887b245SRalf Baechle #define CYCLES_PER_SEC		(NSEC_PER_SEC / NSEC_PER_CYCLE)
2023c009442SRalf Baechle 
203*e887b245SRalf Baechle static void __init ip27_rt_clock_event_init(void)
204*e887b245SRalf Baechle {
205*e887b245SRalf Baechle 	struct clock_event_device *cd = &rt_clock_event_device;
206*e887b245SRalf Baechle 	unsigned int cpu = smp_processor_id();
207*e887b245SRalf Baechle 	int irq = allocate_irqno();
208*e887b245SRalf Baechle 
209*e887b245SRalf Baechle 	if (irq < 0)
2103c009442SRalf Baechle 		panic("Can't allocate interrupt number for timer interrupt");
2113c009442SRalf Baechle 
212*e887b245SRalf Baechle 	rt_timer_irq = irq;
2133c009442SRalf Baechle 
214*e887b245SRalf Baechle 	cd->irq			= irq,
215*e887b245SRalf Baechle 	cd->cpumask		= cpumask_of_cpu(cpu),
2161da177e4SLinus Torvalds 
217bf283630SRalf Baechle 	/*
218*e887b245SRalf Baechle 	 * Calculate the min / max delta
219bf283630SRalf Baechle 	 */
220*e887b245SRalf Baechle 	cd->mult        	=
221*e887b245SRalf Baechle 		div_sc((unsigned long) CYCLES_PER_SEC, NSEC_PER_SEC, 32);
222*e887b245SRalf Baechle 	cd->shift               = 32;
223*e887b245SRalf Baechle 	cd->max_delta_ns        = clockevent_delta2ns(0x7fffffff, cd);
224*e887b245SRalf Baechle 	cd->min_delta_ns        = clockevent_delta2ns(0x300, cd);
225*e887b245SRalf Baechle 	clockevents_register_device(cd);
226*e887b245SRalf Baechle 
227*e887b245SRalf Baechle 	set_irq_chip_and_handler(irq, &rt_irq_type, handle_percpu_irq);
228*e887b245SRalf Baechle 	setup_irq(irq, &rt_irqaction);
2291da177e4SLinus Torvalds }
2301da177e4SLinus Torvalds 
23187b2335dSRalf Baechle static cycle_t hub_rt_read(void)
23216b7b2acSAtsushi Nemoto {
23316b7b2acSAtsushi Nemoto 	return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT);
23416b7b2acSAtsushi Nemoto }
23516b7b2acSAtsushi Nemoto 
23687b2335dSRalf Baechle struct clocksource ht_rt_clocksource = {
237*e887b245SRalf Baechle 	.name	= "HUB-RT",
23887b2335dSRalf Baechle 	.rating	= 200,
23987b2335dSRalf Baechle 	.read	= hub_rt_read,
24087b2335dSRalf Baechle 	.mask	= CLOCKSOURCE_MASK(52),
24187b2335dSRalf Baechle 	.shift	= 32,
24287b2335dSRalf Baechle 	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
24387b2335dSRalf Baechle };
24487b2335dSRalf Baechle 
245*e887b245SRalf Baechle static void __init ip27_rt_clocksource_init(void)
2461da177e4SLinus Torvalds {
24787b2335dSRalf Baechle 	clocksource_register(&ht_rt_clocksource);
2481da177e4SLinus Torvalds }
2491da177e4SLinus Torvalds 
250*e887b245SRalf Baechle void __init plat_time_init(void)
251*e887b245SRalf Baechle {
252*e887b245SRalf Baechle 	ip27_rt_clock_event_init();
253*e887b245SRalf Baechle 	ip27_rt_clocksource_init();
254*e887b245SRalf Baechle }
255*e887b245SRalf Baechle 
2561da177e4SLinus Torvalds void __init cpu_time_init(void)
2571da177e4SLinus Torvalds {
2581da177e4SLinus Torvalds 	lboard_t *board;
2591da177e4SLinus Torvalds 	klcpu_t *cpu;
2601da177e4SLinus Torvalds 	int cpuid;
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds 	/* Don't use ARCS.  ARCS is fragile.  Klconfig is simple and sane.  */
2631da177e4SLinus Torvalds 	board = find_lboard(KL_CONFIG_INFO(get_nasid()), KLTYPE_IP27);
2641da177e4SLinus Torvalds 	if (!board)
2651da177e4SLinus Torvalds 		panic("Can't find board info for myself.");
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds 	cpuid = LOCAL_HUB_L(PI_CPU_NUM) ? IP27_CPU0_INDEX : IP27_CPU1_INDEX;
2681da177e4SLinus Torvalds 	cpu = (klcpu_t *) KLCF_COMP(board, cpuid);
2691da177e4SLinus Torvalds 	if (!cpu)
2701da177e4SLinus Torvalds 		panic("No information about myself?");
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds 	printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed);
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds 	set_c0_status(SRB_TIMOCLK);
2751da177e4SLinus Torvalds }
2761da177e4SLinus Torvalds 
2771da177e4SLinus Torvalds void __init hub_rtc_init(cnodeid_t cnode)
2781da177e4SLinus Torvalds {
2791da177e4SLinus Torvalds 	/*
2801da177e4SLinus Torvalds 	 * We only need to initialize the current node.
2811da177e4SLinus Torvalds 	 * If this is not the current node then it is a cpuless
2821da177e4SLinus Torvalds 	 * node and timeouts will not happen there.
2831da177e4SLinus Torvalds 	 */
2841da177e4SLinus Torvalds 	if (get_compact_nodeid() == cnode) {
2851da177e4SLinus Torvalds 		LOCAL_HUB_S(PI_RT_EN_A, 1);
2861da177e4SLinus Torvalds 		LOCAL_HUB_S(PI_RT_EN_B, 1);
2871da177e4SLinus Torvalds 		LOCAL_HUB_S(PI_PROF_EN_A, 0);
2881da177e4SLinus Torvalds 		LOCAL_HUB_S(PI_PROF_EN_B, 0);
2891da177e4SLinus Torvalds 		LOCAL_HUB_S(PI_RT_COUNT, 0);
2901da177e4SLinus Torvalds 		LOCAL_HUB_S(PI_RT_PEND_A, 0);
2911da177e4SLinus Torvalds 		LOCAL_HUB_S(PI_RT_PEND_B, 0);
2921da177e4SLinus Torvalds 	}
2931da177e4SLinus Torvalds }
294