1 // SPDX-License-Identifier: GPL-2.0
3 * Common time service routines for LoongArch machines.
5 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
7 #include <linux/clockchips.h>
8 #include <linux/delay.h>
9 #include <linux/export.h>
10 #include <linux/init.h>
11 #include <linux/interrupt.h>
12 #include <linux/kernel.h>
13 #include <linux/sched_clock.h>
14 #include <linux/spinlock.h>
16 #include <asm/cpu-features.h>
17 #include <asm/loongarch.h>
21 EXPORT_SYMBOL(cpu_clock_freq
);
23 EXPORT_SYMBOL(const_clock_freq
);
25 static DEFINE_RAW_SPINLOCK(state_lock
);
26 static DEFINE_PER_CPU(struct clock_event_device
, constant_clockevent_device
);
28 static void constant_event_handler(struct clock_event_device
*dev
)
32 static irqreturn_t
constant_timer_interrupt(int irq
, void *data
)
34 int cpu
= smp_processor_id();
35 struct clock_event_device
*cd
;
37 /* Clear Timer Interrupt */
38 write_csr_tintclear(CSR_TINTCLR_TI
);
39 cd
= &per_cpu(constant_clockevent_device
, cpu
);
40 cd
->event_handler(cd
);
45 static int constant_set_state_oneshot(struct clock_event_device
*evt
)
47 unsigned long timer_config
;
49 raw_spin_lock(&state_lock
);
51 timer_config
= csr_read64(LOONGARCH_CSR_TCFG
);
52 timer_config
|= CSR_TCFG_EN
;
53 timer_config
&= ~CSR_TCFG_PERIOD
;
54 csr_write64(timer_config
, LOONGARCH_CSR_TCFG
);
56 raw_spin_unlock(&state_lock
);
61 static int constant_set_state_periodic(struct clock_event_device
*evt
)
64 unsigned long timer_config
;
66 raw_spin_lock(&state_lock
);
68 period
= const_clock_freq
/ HZ
;
69 timer_config
= period
& CSR_TCFG_VAL
;
70 timer_config
|= (CSR_TCFG_PERIOD
| CSR_TCFG_EN
);
71 csr_write64(timer_config
, LOONGARCH_CSR_TCFG
);
73 raw_spin_unlock(&state_lock
);
78 static int constant_set_state_shutdown(struct clock_event_device
*evt
)
80 unsigned long timer_config
;
82 raw_spin_lock(&state_lock
);
84 timer_config
= csr_read64(LOONGARCH_CSR_TCFG
);
85 timer_config
&= ~CSR_TCFG_EN
;
86 csr_write64(timer_config
, LOONGARCH_CSR_TCFG
);
88 raw_spin_unlock(&state_lock
);
93 static int constant_timer_next_event(unsigned long delta
, struct clock_event_device
*evt
)
95 unsigned long timer_config
;
97 delta
&= CSR_TCFG_VAL
;
98 timer_config
= delta
| CSR_TCFG_EN
;
99 csr_write64(timer_config
, LOONGARCH_CSR_TCFG
);
104 static unsigned long __init
get_loops_per_jiffy(void)
106 unsigned long lpj
= (unsigned long)const_clock_freq
;
113 static long init_offset __nosavedata
;
115 void save_counter(void)
117 init_offset
= drdtime();
120 void sync_counter(void)
122 /* Ensure counter begin at 0 */
123 csr_write64(init_offset
, LOONGARCH_CSR_CNTC
);
126 static int get_timer_irq(void)
128 struct irq_domain
*d
= irq_find_matching_fwnode(cpuintc_handle
, DOMAIN_BUS_ANY
);
131 return irq_create_mapping(d
, INT_TI
);
136 int constant_clockevent_init(void)
138 unsigned int cpu
= smp_processor_id();
139 unsigned long min_delta
= 0x600;
140 unsigned long max_delta
= (1UL << 48) - 1;
141 struct clock_event_device
*cd
;
142 static int irq
= 0, timer_irq_installed
= 0;
144 if (!timer_irq_installed
) {
145 irq
= get_timer_irq();
147 pr_err("Failed to map irq %d (timer)\n", irq
);
150 cd
= &per_cpu(constant_clockevent_device
, cpu
);
152 cd
->name
= "Constant";
153 cd
->features
= CLOCK_EVT_FEAT_ONESHOT
| CLOCK_EVT_FEAT_PERIODIC
| CLOCK_EVT_FEAT_PERCPU
;
157 cd
->cpumask
= cpumask_of(cpu
);
158 cd
->set_state_oneshot
= constant_set_state_oneshot
;
159 cd
->set_state_oneshot_stopped
= constant_set_state_shutdown
;
160 cd
->set_state_periodic
= constant_set_state_periodic
;
161 cd
->set_state_shutdown
= constant_set_state_shutdown
;
162 cd
->set_next_event
= constant_timer_next_event
;
163 cd
->event_handler
= constant_event_handler
;
165 clockevents_config_and_register(cd
, const_clock_freq
, min_delta
, max_delta
);
167 if (timer_irq_installed
)
170 timer_irq_installed
= 1;
174 if (request_irq(irq
, constant_timer_interrupt
, IRQF_PERCPU
| IRQF_TIMER
, "timer", NULL
))
175 pr_err("Failed to request irq %d (timer)\n", irq
);
177 lpj_fine
= get_loops_per_jiffy();
178 pr_info("Constant clock event device register\n");
183 static u64
read_const_counter(struct clocksource
*clk
)
188 static noinstr u64
sched_clock_read(void)
193 static struct clocksource clocksource_const
= {
196 .read
= read_const_counter
,
197 .mask
= CLOCKSOURCE_MASK(64),
198 .flags
= CLOCK_SOURCE_IS_CONTINUOUS
,
199 .vdso_clock_mode
= VDSO_CLOCKMODE_CPU
,
202 int __init
constant_clocksource_init(void)
205 unsigned long freq
= const_clock_freq
;
207 res
= clocksource_register_hz(&clocksource_const
, freq
);
209 sched_clock_register(sched_clock_read
, 64, freq
);
211 pr_info("Constant clock source device register\n");
216 void __init
time_init(void)
219 const_clock_freq
= cpu_clock_freq
;
221 const_clock_freq
= calc_const_freq();
223 init_offset
= -(drdtime() - csr_read64(LOONGARCH_CSR_CNTC
));
225 constant_clockevent_init();
226 constant_clocksource_init();