xref: /openbmc/linux/arch/mips/sgi-ip27/ip27-timer.c (revision 547840bd)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copytight (C) 1999, 2000, 05, 06 Ralf Baechle (ralf@linux-mips.org)
4  * Copytight (C) 1999, 2000 Silicon Graphics, Inc.
5  */
6 #include <linux/bcd.h>
7 #include <linux/clockchips.h>
8 #include <linux/init.h>
9 #include <linux/kernel.h>
10 #include <linux/sched.h>
11 #include <linux/sched_clock.h>
12 #include <linux/interrupt.h>
13 #include <linux/kernel_stat.h>
14 #include <linux/param.h>
15 #include <linux/smp.h>
16 #include <linux/time.h>
17 #include <linux/timex.h>
18 #include <linux/mm.h>
19 #include <linux/platform_device.h>
20 
21 #include <asm/time.h>
22 #include <asm/pgtable.h>
23 #include <asm/sgialib.h>
24 #include <asm/sn/klconfig.h>
25 #include <asm/sn/arch.h>
26 #include <asm/sn/addrs.h>
27 #include <asm/sn/agent.h>
28 
29 #include "ip27-common.h"
30 
31 static int rt_next_event(unsigned long delta, struct clock_event_device *evt)
32 {
33 	unsigned int cpu = smp_processor_id();
34 	int slice = cputoslice(cpu);
35 	unsigned long cnt;
36 
37 	cnt = LOCAL_HUB_L(PI_RT_COUNT);
38 	cnt += delta;
39 	LOCAL_HUB_S(PI_RT_COMPARE_A + PI_COUNT_OFFSET * slice, cnt);
40 
41 	return LOCAL_HUB_L(PI_RT_COUNT) >= cnt ? -ETIME : 0;
42 }
43 
44 static DEFINE_PER_CPU(struct clock_event_device, hub_rt_clockevent);
45 static DEFINE_PER_CPU(char [11], hub_rt_name);
46 
47 static irqreturn_t hub_rt_counter_handler(int irq, void *dev_id)
48 {
49 	unsigned int cpu = smp_processor_id();
50 	struct clock_event_device *cd = &per_cpu(hub_rt_clockevent, cpu);
51 	int slice = cputoslice(cpu);
52 
53 	/*
54 	 * Ack
55 	 */
56 	LOCAL_HUB_S(PI_RT_PEND_A + PI_COUNT_OFFSET * slice, 0);
57 	cd->event_handler(cd);
58 
59 	return IRQ_HANDLED;
60 }
61 
62 struct irqaction hub_rt_irqaction = {
63 	.handler	= hub_rt_counter_handler,
64 	.percpu_dev_id	= &hub_rt_clockevent,
65 	.flags		= IRQF_PERCPU | IRQF_TIMER,
66 	.name		= "hub-rt",
67 };
68 
69 /*
70  * This is a hack; we really need to figure these values out dynamically
71  *
72  * Since 800 ns works very well with various HUB frequencies, such as
73  * 360, 380, 390 and 400 MHZ, we use 800 ns rtc cycle time.
74  *
75  * Ralf: which clock rate is used to feed the counter?
76  */
77 #define NSEC_PER_CYCLE		800
78 #define CYCLES_PER_SEC		(NSEC_PER_SEC / NSEC_PER_CYCLE)
79 
80 void hub_rt_clock_event_init(void)
81 {
82 	unsigned int cpu = smp_processor_id();
83 	struct clock_event_device *cd = &per_cpu(hub_rt_clockevent, cpu);
84 	unsigned char *name = per_cpu(hub_rt_name, cpu);
85 
86 	sprintf(name, "hub-rt %d", cpu);
87 	cd->name		= name;
88 	cd->features		= CLOCK_EVT_FEAT_ONESHOT;
89 	clockevent_set_clock(cd, CYCLES_PER_SEC);
90 	cd->max_delta_ns	= clockevent_delta2ns(0xfffffffffffff, cd);
91 	cd->max_delta_ticks	= 0xfffffffffffff;
92 	cd->min_delta_ns	= clockevent_delta2ns(0x300, cd);
93 	cd->min_delta_ticks	= 0x300;
94 	cd->rating		= 200;
95 	cd->irq			= IP27_RT_TIMER_IRQ;
96 	cd->cpumask		= cpumask_of(cpu);
97 	cd->set_next_event	= rt_next_event;
98 	clockevents_register_device(cd);
99 
100 	enable_percpu_irq(IP27_RT_TIMER_IRQ, IRQ_TYPE_NONE);
101 }
102 
103 static void __init hub_rt_clock_event_global_init(void)
104 {
105 	irq_set_handler(IP27_RT_TIMER_IRQ, handle_percpu_devid_irq);
106 	irq_set_percpu_devid(IP27_RT_TIMER_IRQ);
107 	setup_percpu_irq(IP27_RT_TIMER_IRQ, &hub_rt_irqaction);
108 }
109 
110 static u64 hub_rt_read(struct clocksource *cs)
111 {
112 	return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT);
113 }
114 
115 struct clocksource hub_rt_clocksource = {
116 	.name	= "HUB-RT",
117 	.rating = 200,
118 	.read	= hub_rt_read,
119 	.mask	= CLOCKSOURCE_MASK(52),
120 	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
121 };
122 
123 static u64 notrace hub_rt_read_sched_clock(void)
124 {
125 	return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT);
126 }
127 
128 static void __init hub_rt_clocksource_init(void)
129 {
130 	struct clocksource *cs = &hub_rt_clocksource;
131 
132 	clocksource_register_hz(cs, CYCLES_PER_SEC);
133 
134 	sched_clock_register(hub_rt_read_sched_clock, 52, CYCLES_PER_SEC);
135 }
136 
137 void __init plat_time_init(void)
138 {
139 	hub_rt_clocksource_init();
140 	hub_rt_clock_event_global_init();
141 	hub_rt_clock_event_init();
142 }
143 
144 void hub_rtc_init(nasid_t nasid)
145 {
146 
147 	/*
148 	 * We only need to initialize the current node.
149 	 * If this is not the current node then it is a cpuless
150 	 * node and timeouts will not happen there.
151 	 */
152 	if (get_nasid() == nasid) {
153 		LOCAL_HUB_S(PI_RT_EN_A, 1);
154 		LOCAL_HUB_S(PI_RT_EN_B, 1);
155 		LOCAL_HUB_S(PI_PROF_EN_A, 0);
156 		LOCAL_HUB_S(PI_PROF_EN_B, 0);
157 		LOCAL_HUB_S(PI_RT_COUNT, 0);
158 		LOCAL_HUB_S(PI_RT_PEND_A, 0);
159 		LOCAL_HUB_S(PI_RT_PEND_B, 0);
160 	}
161 }
162