1*9c92ab61SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2ce2e572cSDaniel J Blueman /* 3ce2e572cSDaniel J Blueman * 4ce2e572cSDaniel J Blueman * Copyright (C) 2015 Numascale AS. All rights reserved. 5ce2e572cSDaniel J Blueman */ 6ce2e572cSDaniel J Blueman 7ce2e572cSDaniel J Blueman #include <linux/clockchips.h> 8ce2e572cSDaniel J Blueman 9ce2e572cSDaniel J Blueman #include <asm/irq.h> 10ce2e572cSDaniel J Blueman #include <asm/numachip/numachip.h> 11ce2e572cSDaniel J Blueman #include <asm/numachip/numachip_csr.h> 12ce2e572cSDaniel J Blueman 13ef34cc34SDaniel J Blueman static DEFINE_PER_CPU(struct clock_event_device, numachip2_ced); 14ce2e572cSDaniel J Blueman 15ce2e572cSDaniel J Blueman static cycles_t numachip2_timer_read(struct clocksource *cs) 16ce2e572cSDaniel J Blueman { 17ce2e572cSDaniel J Blueman return numachip2_read64_lcsr(NUMACHIP2_TIMER_NOW); 18ce2e572cSDaniel J Blueman } 19ce2e572cSDaniel J Blueman 20ce2e572cSDaniel J Blueman static struct clocksource numachip2_clocksource = { 21ce2e572cSDaniel J Blueman .name = "numachip2", 22ce2e572cSDaniel J Blueman .rating = 295, 23ce2e572cSDaniel J Blueman .read = numachip2_timer_read, 24ce2e572cSDaniel J Blueman .mask = CLOCKSOURCE_MASK(64), 25ce2e572cSDaniel J Blueman .flags = CLOCK_SOURCE_IS_CONTINUOUS, 26ce2e572cSDaniel J Blueman .mult = 1, 27ce2e572cSDaniel J Blueman .shift = 0, 28ce2e572cSDaniel J Blueman }; 29ce2e572cSDaniel J Blueman 30ce2e572cSDaniel J Blueman static int numachip2_set_next_event(unsigned long delta, struct clock_event_device *ced) 31ce2e572cSDaniel J Blueman { 32ce2e572cSDaniel J Blueman numachip2_write64_lcsr(NUMACHIP2_TIMER_DEADLINE + numachip2_timer(), 33ce2e572cSDaniel J Blueman delta); 34ce2e572cSDaniel J Blueman return 0; 35ce2e572cSDaniel J Blueman } 36ce2e572cSDaniel J Blueman 3710430364SBhumika Goyal static const struct clock_event_device numachip2_clockevent __initconst = { 38ce2e572cSDaniel J Blueman .name = "numachip2", 39ce2e572cSDaniel J Blueman .rating = 400, 40ce2e572cSDaniel J Blueman .set_next_event = numachip2_set_next_event, 41ce2e572cSDaniel J Blueman .features = CLOCK_EVT_FEAT_ONESHOT, 42ce2e572cSDaniel J Blueman .mult = 1, 43ce2e572cSDaniel J Blueman .shift = 0, 44ce2e572cSDaniel J Blueman .min_delta_ns = 1250, 456cf57ae8SNicolai Stange .min_delta_ticks = 1250, 46ce2e572cSDaniel J Blueman .max_delta_ns = LONG_MAX, 476cf57ae8SNicolai Stange .max_delta_ticks = LONG_MAX, 48ce2e572cSDaniel J Blueman }; 49ce2e572cSDaniel J Blueman 50ce2e572cSDaniel J Blueman static void numachip_timer_interrupt(void) 51ce2e572cSDaniel J Blueman { 52ef34cc34SDaniel J Blueman struct clock_event_device *ced = this_cpu_ptr(&numachip2_ced); 53ce2e572cSDaniel J Blueman 54ce2e572cSDaniel J Blueman ced->event_handler(ced); 55ce2e572cSDaniel J Blueman } 56ce2e572cSDaniel J Blueman 57ce2e572cSDaniel J Blueman static __init void numachip_timer_each(struct work_struct *work) 58ce2e572cSDaniel J Blueman { 59ce2e572cSDaniel J Blueman unsigned local_apicid = __this_cpu_read(x86_cpu_to_apicid) & 0xff; 60ef34cc34SDaniel J Blueman struct clock_event_device *ced = this_cpu_ptr(&numachip2_ced); 61ce2e572cSDaniel J Blueman 62ce2e572cSDaniel J Blueman /* Setup IPI vector to local core and relative timing mode */ 63ce2e572cSDaniel J Blueman numachip2_write64_lcsr(NUMACHIP2_TIMER_INT + numachip2_timer(), 64ce2e572cSDaniel J Blueman (3 << 22) | (X86_PLATFORM_IPI_VECTOR << 14) | 65ce2e572cSDaniel J Blueman (local_apicid << 6)); 66ce2e572cSDaniel J Blueman 67ce2e572cSDaniel J Blueman *ced = numachip2_clockevent; 68ce2e572cSDaniel J Blueman ced->cpumask = cpumask_of(smp_processor_id()); 69ce2e572cSDaniel J Blueman clockevents_register_device(ced); 70ce2e572cSDaniel J Blueman } 71ce2e572cSDaniel J Blueman 72ce2e572cSDaniel J Blueman static int __init numachip_timer_init(void) 73ce2e572cSDaniel J Blueman { 74ce2e572cSDaniel J Blueman if (numachip_system != 2) 75ce2e572cSDaniel J Blueman return -ENODEV; 76ce2e572cSDaniel J Blueman 77ce2e572cSDaniel J Blueman /* Reset timer */ 78ce2e572cSDaniel J Blueman numachip2_write64_lcsr(NUMACHIP2_TIMER_RESET, 0); 79ce2e572cSDaniel J Blueman clocksource_register_hz(&numachip2_clocksource, NSEC_PER_SEC); 80ce2e572cSDaniel J Blueman 81ce2e572cSDaniel J Blueman /* Setup per-cpu clockevents */ 82ce2e572cSDaniel J Blueman x86_platform_ipi_callback = numachip_timer_interrupt; 83ce2e572cSDaniel J Blueman schedule_on_each_cpu(&numachip_timer_each); 84ce2e572cSDaniel J Blueman 85ce2e572cSDaniel J Blueman return 0; 86ce2e572cSDaniel J Blueman } 87ce2e572cSDaniel J Blueman 88ce2e572cSDaniel J Blueman arch_initcall(numachip_timer_init); 89