1ce2e572cSDaniel J Blueman /* 2ce2e572cSDaniel J Blueman * 3ce2e572cSDaniel J Blueman * Copyright (C) 2015 Numascale AS. All rights reserved. 4ce2e572cSDaniel J Blueman * 5ce2e572cSDaniel J Blueman * This software is licensed under the terms of the GNU General Public 6ce2e572cSDaniel J Blueman * License version 2, as published by the Free Software Foundation, and 7ce2e572cSDaniel J Blueman * may be copied, distributed, and modified under those terms. 8ce2e572cSDaniel J Blueman * 9ce2e572cSDaniel J Blueman * This program is distributed in the hope that it will be useful, 10ce2e572cSDaniel J Blueman * but WITHOUT ANY WARRANTY; without even the implied warranty of 11ce2e572cSDaniel J Blueman * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12ce2e572cSDaniel J Blueman * GNU General Public License for more details. 13ce2e572cSDaniel J Blueman * 14ce2e572cSDaniel J Blueman */ 15ce2e572cSDaniel J Blueman 16ce2e572cSDaniel J Blueman #include <linux/clockchips.h> 17ce2e572cSDaniel J Blueman 18ce2e572cSDaniel J Blueman #include <asm/irq.h> 19ce2e572cSDaniel J Blueman #include <asm/numachip/numachip.h> 20ce2e572cSDaniel J Blueman #include <asm/numachip/numachip_csr.h> 21ce2e572cSDaniel J Blueman 22ef34cc34SDaniel J Blueman static DEFINE_PER_CPU(struct clock_event_device, numachip2_ced); 23ce2e572cSDaniel J Blueman 24ce2e572cSDaniel J Blueman static cycles_t numachip2_timer_read(struct clocksource *cs) 25ce2e572cSDaniel J Blueman { 26ce2e572cSDaniel J Blueman return numachip2_read64_lcsr(NUMACHIP2_TIMER_NOW); 27ce2e572cSDaniel J Blueman } 28ce2e572cSDaniel J Blueman 29ce2e572cSDaniel J Blueman static struct clocksource numachip2_clocksource = { 30ce2e572cSDaniel J Blueman .name = "numachip2", 31ce2e572cSDaniel J Blueman .rating = 295, 32ce2e572cSDaniel J Blueman .read = numachip2_timer_read, 33ce2e572cSDaniel J Blueman .mask = CLOCKSOURCE_MASK(64), 34ce2e572cSDaniel J Blueman .flags = CLOCK_SOURCE_IS_CONTINUOUS, 35ce2e572cSDaniel J Blueman .mult = 1, 36ce2e572cSDaniel J Blueman .shift = 0, 37ce2e572cSDaniel J Blueman }; 38ce2e572cSDaniel J Blueman 39ce2e572cSDaniel J Blueman static int numachip2_set_next_event(unsigned long delta, struct clock_event_device *ced) 40ce2e572cSDaniel J Blueman { 41ce2e572cSDaniel J Blueman numachip2_write64_lcsr(NUMACHIP2_TIMER_DEADLINE + numachip2_timer(), 42ce2e572cSDaniel J Blueman delta); 43ce2e572cSDaniel J Blueman return 0; 44ce2e572cSDaniel J Blueman } 45ce2e572cSDaniel J Blueman 46*10430364SBhumika Goyal static const struct clock_event_device numachip2_clockevent __initconst = { 47ce2e572cSDaniel J Blueman .name = "numachip2", 48ce2e572cSDaniel J Blueman .rating = 400, 49ce2e572cSDaniel J Blueman .set_next_event = numachip2_set_next_event, 50ce2e572cSDaniel J Blueman .features = CLOCK_EVT_FEAT_ONESHOT, 51ce2e572cSDaniel J Blueman .mult = 1, 52ce2e572cSDaniel J Blueman .shift = 0, 53ce2e572cSDaniel J Blueman .min_delta_ns = 1250, 546cf57ae8SNicolai Stange .min_delta_ticks = 1250, 55ce2e572cSDaniel J Blueman .max_delta_ns = LONG_MAX, 566cf57ae8SNicolai Stange .max_delta_ticks = LONG_MAX, 57ce2e572cSDaniel J Blueman }; 58ce2e572cSDaniel J Blueman 59ce2e572cSDaniel J Blueman static void numachip_timer_interrupt(void) 60ce2e572cSDaniel J Blueman { 61ef34cc34SDaniel J Blueman struct clock_event_device *ced = this_cpu_ptr(&numachip2_ced); 62ce2e572cSDaniel J Blueman 63ce2e572cSDaniel J Blueman ced->event_handler(ced); 64ce2e572cSDaniel J Blueman } 65ce2e572cSDaniel J Blueman 66ce2e572cSDaniel J Blueman static __init void numachip_timer_each(struct work_struct *work) 67ce2e572cSDaniel J Blueman { 68ce2e572cSDaniel J Blueman unsigned local_apicid = __this_cpu_read(x86_cpu_to_apicid) & 0xff; 69ef34cc34SDaniel J Blueman struct clock_event_device *ced = this_cpu_ptr(&numachip2_ced); 70ce2e572cSDaniel J Blueman 71ce2e572cSDaniel J Blueman /* Setup IPI vector to local core and relative timing mode */ 72ce2e572cSDaniel J Blueman numachip2_write64_lcsr(NUMACHIP2_TIMER_INT + numachip2_timer(), 73ce2e572cSDaniel J Blueman (3 << 22) | (X86_PLATFORM_IPI_VECTOR << 14) | 74ce2e572cSDaniel J Blueman (local_apicid << 6)); 75ce2e572cSDaniel J Blueman 76ce2e572cSDaniel J Blueman *ced = numachip2_clockevent; 77ce2e572cSDaniel J Blueman ced->cpumask = cpumask_of(smp_processor_id()); 78ce2e572cSDaniel J Blueman clockevents_register_device(ced); 79ce2e572cSDaniel J Blueman } 80ce2e572cSDaniel J Blueman 81ce2e572cSDaniel J Blueman static int __init numachip_timer_init(void) 82ce2e572cSDaniel J Blueman { 83ce2e572cSDaniel J Blueman if (numachip_system != 2) 84ce2e572cSDaniel J Blueman return -ENODEV; 85ce2e572cSDaniel J Blueman 86ce2e572cSDaniel J Blueman /* Reset timer */ 87ce2e572cSDaniel J Blueman numachip2_write64_lcsr(NUMACHIP2_TIMER_RESET, 0); 88ce2e572cSDaniel J Blueman clocksource_register_hz(&numachip2_clocksource, NSEC_PER_SEC); 89ce2e572cSDaniel J Blueman 90ce2e572cSDaniel J Blueman /* Setup per-cpu clockevents */ 91ce2e572cSDaniel J Blueman x86_platform_ipi_callback = numachip_timer_interrupt; 92ce2e572cSDaniel J Blueman schedule_on_each_cpu(&numachip_timer_each); 93ce2e572cSDaniel J Blueman 94ce2e572cSDaniel J Blueman return 0; 95ce2e572cSDaniel J Blueman } 96ce2e572cSDaniel J Blueman 97ce2e572cSDaniel J Blueman arch_initcall(numachip_timer_init); 98