162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2015 Numascale AS. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/clockchips.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <asm/irq.h> 1062306a36Sopenharmony_ci#include <asm/numachip/numachip.h> 1162306a36Sopenharmony_ci#include <asm/numachip/numachip_csr.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct clock_event_device, numachip2_ced); 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic cycles_t numachip2_timer_read(struct clocksource *cs) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci return numachip2_read64_lcsr(NUMACHIP2_TIMER_NOW); 1862306a36Sopenharmony_ci} 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic struct clocksource numachip2_clocksource = { 2162306a36Sopenharmony_ci .name = "numachip2", 2262306a36Sopenharmony_ci .rating = 295, 2362306a36Sopenharmony_ci .read = numachip2_timer_read, 2462306a36Sopenharmony_ci .mask = CLOCKSOURCE_MASK(64), 2562306a36Sopenharmony_ci .flags = CLOCK_SOURCE_IS_CONTINUOUS, 2662306a36Sopenharmony_ci .mult = 1, 2762306a36Sopenharmony_ci .shift = 0, 2862306a36Sopenharmony_ci}; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic int numachip2_set_next_event(unsigned long delta, struct clock_event_device *ced) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci numachip2_write64_lcsr(NUMACHIP2_TIMER_DEADLINE + numachip2_timer(), 3362306a36Sopenharmony_ci delta); 3462306a36Sopenharmony_ci return 0; 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic const struct clock_event_device numachip2_clockevent __initconst = { 3862306a36Sopenharmony_ci .name = "numachip2", 3962306a36Sopenharmony_ci .rating = 400, 4062306a36Sopenharmony_ci .set_next_event = numachip2_set_next_event, 4162306a36Sopenharmony_ci .features = CLOCK_EVT_FEAT_ONESHOT, 4262306a36Sopenharmony_ci .mult = 1, 4362306a36Sopenharmony_ci .shift = 0, 4462306a36Sopenharmony_ci .min_delta_ns = 1250, 4562306a36Sopenharmony_ci .min_delta_ticks = 1250, 4662306a36Sopenharmony_ci .max_delta_ns = LONG_MAX, 4762306a36Sopenharmony_ci .max_delta_ticks = LONG_MAX, 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic void numachip_timer_interrupt(void) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci struct clock_event_device *ced = this_cpu_ptr(&numachip2_ced); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci ced->event_handler(ced); 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic __init void numachip_timer_each(struct work_struct *work) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci unsigned local_apicid = __this_cpu_read(x86_cpu_to_apicid) & 0xff; 6062306a36Sopenharmony_ci struct clock_event_device *ced = this_cpu_ptr(&numachip2_ced); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci /* Setup IPI vector to local core and relative timing mode */ 6362306a36Sopenharmony_ci numachip2_write64_lcsr(NUMACHIP2_TIMER_INT + numachip2_timer(), 6462306a36Sopenharmony_ci (3 << 22) | (X86_PLATFORM_IPI_VECTOR << 14) | 6562306a36Sopenharmony_ci (local_apicid << 6)); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci *ced = numachip2_clockevent; 6862306a36Sopenharmony_ci ced->cpumask = cpumask_of(smp_processor_id()); 6962306a36Sopenharmony_ci clockevents_register_device(ced); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic int __init numachip_timer_init(void) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci if (numachip_system != 2) 7562306a36Sopenharmony_ci return -ENODEV; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* Reset timer */ 7862306a36Sopenharmony_ci numachip2_write64_lcsr(NUMACHIP2_TIMER_RESET, 0); 7962306a36Sopenharmony_ci clocksource_register_hz(&numachip2_clocksource, NSEC_PER_SEC); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci /* Setup per-cpu clockevents */ 8262306a36Sopenharmony_ci x86_platform_ipi_callback = numachip_timer_interrupt; 8362306a36Sopenharmony_ci schedule_on_each_cpu(&numachip_timer_each); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci return 0; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ciarch_initcall(numachip_timer_init); 89