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