1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Common time service routines for LoongArch machines. 4 * 5 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 6 */ 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> 15 16 #include <asm/cpu-features.h> 17 #include <asm/loongarch.h> 18 #include <asm/paravirt.h> 19 #include <asm/time.h> 20 21 u64 cpu_clock_freq; 22 EXPORT_SYMBOL(cpu_clock_freq); 23 u64 const_clock_freq; 24 EXPORT_SYMBOL(const_clock_freq); 25 26 static DEFINE_RAW_SPINLOCK(state_lock); 27 static DEFINE_PER_CPU(struct clock_event_device, constant_clockevent_device); 28 29 static void constant_event_handler(struct clock_event_device *dev) 30 { 31 } 32 33 static irqreturn_t constant_timer_interrupt(int irq, void *data) 34 { 35 int cpu = smp_processor_id(); 36 struct clock_event_device *cd; 37 38 /* Clear Timer Interrupt */ 39 write_csr_tintclear(CSR_TINTCLR_TI); 40 cd = &per_cpu(constant_clockevent_device, cpu); 41 cd->event_handler(cd); 42 43 return IRQ_HANDLED; 44 } 45 46 static int constant_set_state_oneshot(struct clock_event_device *evt) 47 { 48 unsigned long timer_config; 49 50 raw_spin_lock(&state_lock); 51 52 timer_config = csr_read64(LOONGARCH_CSR_TCFG); 53 timer_config |= CSR_TCFG_EN; 54 timer_config &= ~CSR_TCFG_PERIOD; 55 csr_write64(timer_config, LOONGARCH_CSR_TCFG); 56 57 raw_spin_unlock(&state_lock); 58 59 return 0; 60 } 61 62 static int constant_set_state_periodic(struct clock_event_device *evt) 63 { 64 unsigned long period; 65 unsigned long timer_config; 66 67 raw_spin_lock(&state_lock); 68 69 period = const_clock_freq / HZ; 70 timer_config = period & CSR_TCFG_VAL; 71 timer_config |= (CSR_TCFG_PERIOD | CSR_TCFG_EN); 72 csr_write64(timer_config, LOONGARCH_CSR_TCFG); 73 74 raw_spin_unlock(&state_lock); 75 76 return 0; 77 } 78 79 static int constant_set_state_shutdown(struct clock_event_device *evt) 80 { 81 unsigned long timer_config; 82 83 raw_spin_lock(&state_lock); 84 85 timer_config = csr_read64(LOONGARCH_CSR_TCFG); 86 timer_config &= ~CSR_TCFG_EN; 87 csr_write64(timer_config, LOONGARCH_CSR_TCFG); 88 89 raw_spin_unlock(&state_lock); 90 91 return 0; 92 } 93 94 static int constant_timer_next_event(unsigned long delta, struct clock_event_device *evt) 95 { 96 unsigned long timer_config; 97 98 delta &= CSR_TCFG_VAL; 99 timer_config = delta | CSR_TCFG_EN; 100 csr_write64(timer_config, LOONGARCH_CSR_TCFG); 101 102 return 0; 103 } 104 105 static unsigned long __init get_loops_per_jiffy(void) 106 { 107 unsigned long lpj = (unsigned long)const_clock_freq; 108 109 do_div(lpj, HZ); 110 111 return lpj; 112 } 113 114 static long init_offset __nosavedata; 115 116 void save_counter(void) 117 { 118 init_offset = drdtime(); 119 } 120 121 void sync_counter(void) 122 { 123 /* Ensure counter begin at 0 */ 124 csr_write64(init_offset, LOONGARCH_CSR_CNTC); 125 } 126 127 int constant_clockevent_init(void) 128 { 129 unsigned int cpu = smp_processor_id(); 130 #ifdef CONFIG_PREEMPT_RT 131 unsigned long min_delta = 100; 132 #else 133 unsigned long min_delta = 1000; 134 #endif 135 unsigned long max_delta = (1UL << 48) - 1; 136 struct clock_event_device *cd; 137 static int irq = 0, timer_irq_installed = 0; 138 139 if (!timer_irq_installed) { 140 irq = get_percpu_irq(INT_TI); 141 if (irq < 0) 142 pr_err("Failed to map irq %d (timer)\n", irq); 143 } 144 145 cd = &per_cpu(constant_clockevent_device, cpu); 146 147 cd->name = "Constant"; 148 cd->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_PERCPU; 149 150 cd->irq = irq; 151 cd->rating = 320; 152 cd->cpumask = cpumask_of(cpu); 153 cd->set_state_oneshot = constant_set_state_oneshot; 154 cd->set_state_oneshot_stopped = constant_set_state_shutdown; 155 cd->set_state_periodic = constant_set_state_periodic; 156 cd->set_state_shutdown = constant_set_state_shutdown; 157 cd->set_next_event = constant_timer_next_event; 158 cd->event_handler = constant_event_handler; 159 160 clockevents_config_and_register(cd, const_clock_freq, min_delta, max_delta); 161 162 if (timer_irq_installed) 163 return 0; 164 165 timer_irq_installed = 1; 166 167 sync_counter(); 168 169 if (request_irq(irq, constant_timer_interrupt, IRQF_PERCPU | IRQF_TIMER, "timer", NULL)) 170 pr_err("Failed to request irq %d (timer)\n", irq); 171 172 lpj_fine = get_loops_per_jiffy(); 173 pr_info("Constant clock event device register\n"); 174 175 return 0; 176 } 177 178 static u64 read_const_counter(struct clocksource *clk) 179 { 180 return drdtime(); 181 } 182 183 static noinstr u64 sched_clock_read(void) 184 { 185 return drdtime(); 186 } 187 188 static struct clocksource clocksource_const = { 189 .name = "Constant", 190 .rating = 400, 191 .read = read_const_counter, 192 .mask = CLOCKSOURCE_MASK(64), 193 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 194 .vdso_clock_mode = VDSO_CLOCKMODE_CPU, 195 }; 196 197 int __init constant_clocksource_init(void) 198 { 199 int res; 200 unsigned long freq = const_clock_freq; 201 202 res = clocksource_register_hz(&clocksource_const, freq); 203 204 sched_clock_register(sched_clock_read, 64, freq); 205 206 pr_info("Constant clock source device register\n"); 207 208 return res; 209 } 210 211 void __init time_init(void) 212 { 213 if (!cpu_has_cpucfg) 214 const_clock_freq = cpu_clock_freq; 215 else 216 const_clock_freq = calc_const_freq(); 217 218 init_offset = -(drdtime() - csr_read64(LOONGARCH_CSR_CNTC)); 219 220 constant_clockevent_init(); 221 constant_clocksource_init(); 222 pv_time_init(); 223 } 224