18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016-17 Synopsys, Inc. (www.synopsys.com) 48c2ecf20Sopenharmony_ci * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci/* ARC700 has two 32bit independent prog Timers: TIMER0 and TIMER1, Each can be 88c2ecf20Sopenharmony_ci * programmed to go from @count to @limit and optionally interrupt. 98c2ecf20Sopenharmony_ci * We've designated TIMER0 for clockevents and TIMER1 for clocksource 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * ARCv2 based HS38 cores have RTC (in-core) and GFRC (inside ARConnect/MCIP) 128c2ecf20Sopenharmony_ci * which are suitable for UP and SMP based clocksources respectively 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci#include <linux/bits.h> 178c2ecf20Sopenharmony_ci#include <linux/clk.h> 188c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 198c2ecf20Sopenharmony_ci#include <linux/clocksource.h> 208c2ecf20Sopenharmony_ci#include <linux/clockchips.h> 218c2ecf20Sopenharmony_ci#include <linux/cpu.h> 228c2ecf20Sopenharmony_ci#include <linux/of.h> 238c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 248c2ecf20Sopenharmony_ci#include <linux/sched_clock.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <soc/arc/timers.h> 278c2ecf20Sopenharmony_ci#include <soc/arc/mcip.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic unsigned long arc_timer_freq; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic int noinline arc_get_timer_clk(struct device_node *node) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct clk *clk; 358c2ecf20Sopenharmony_ci int ret; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci clk = of_clk_get(node, 0); 388c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 398c2ecf20Sopenharmony_ci pr_err("timer missing clk\n"); 408c2ecf20Sopenharmony_ci return PTR_ERR(clk); 418c2ecf20Sopenharmony_ci } 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci ret = clk_prepare_enable(clk); 448c2ecf20Sopenharmony_ci if (ret) { 458c2ecf20Sopenharmony_ci pr_err("Couldn't enable parent clk\n"); 468c2ecf20Sopenharmony_ci return ret; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci arc_timer_freq = clk_get_rate(clk); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci return 0; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/********** Clock Source Device *********/ 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#ifdef CONFIG_ARC_TIMERS_64BIT 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic u64 arc_read_gfrc(struct clocksource *cs) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci unsigned long flags; 618c2ecf20Sopenharmony_ci u32 l, h; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci /* 648c2ecf20Sopenharmony_ci * From a programming model pov, there seems to be just one instance of 658c2ecf20Sopenharmony_ci * MCIP_CMD/MCIP_READBACK however micro-architecturally there's 668c2ecf20Sopenharmony_ci * an instance PER ARC CORE (not per cluster), and there are dedicated 678c2ecf20Sopenharmony_ci * hardware decode logic (per core) inside ARConnect to handle 688c2ecf20Sopenharmony_ci * simultaneous read/write accesses from cores via those two registers. 698c2ecf20Sopenharmony_ci * So several concurrent commands to ARConnect are OK if they are 708c2ecf20Sopenharmony_ci * trying to access two different sub-components (like GFRC, 718c2ecf20Sopenharmony_ci * inter-core interrupt, etc...). HW also supports simultaneously 728c2ecf20Sopenharmony_ci * accessing GFRC by multiple cores. 738c2ecf20Sopenharmony_ci * That's why it is safe to disable hard interrupts on the local CPU 748c2ecf20Sopenharmony_ci * before access to GFRC instead of taking global MCIP spinlock 758c2ecf20Sopenharmony_ci * defined in arch/arc/kernel/mcip.c 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ci local_irq_save(flags); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci __mcip_cmd(CMD_GFRC_READ_LO, 0); 808c2ecf20Sopenharmony_ci l = read_aux_reg(ARC_REG_MCIP_READBACK); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci __mcip_cmd(CMD_GFRC_READ_HI, 0); 838c2ecf20Sopenharmony_ci h = read_aux_reg(ARC_REG_MCIP_READBACK); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci local_irq_restore(flags); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci return (((u64)h) << 32) | l; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic notrace u64 arc_gfrc_clock_read(void) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci return arc_read_gfrc(NULL); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic struct clocksource arc_counter_gfrc = { 968c2ecf20Sopenharmony_ci .name = "ARConnect GFRC", 978c2ecf20Sopenharmony_ci .rating = 400, 988c2ecf20Sopenharmony_ci .read = arc_read_gfrc, 998c2ecf20Sopenharmony_ci .mask = CLOCKSOURCE_MASK(64), 1008c2ecf20Sopenharmony_ci .flags = CLOCK_SOURCE_IS_CONTINUOUS, 1018c2ecf20Sopenharmony_ci}; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int __init arc_cs_setup_gfrc(struct device_node *node) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct mcip_bcr mp; 1068c2ecf20Sopenharmony_ci int ret; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci READ_BCR(ARC_REG_MCIP_BCR, mp); 1098c2ecf20Sopenharmony_ci if (!mp.gfrc) { 1108c2ecf20Sopenharmony_ci pr_warn("Global-64-bit-Ctr clocksource not detected\n"); 1118c2ecf20Sopenharmony_ci return -ENXIO; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci ret = arc_get_timer_clk(node); 1158c2ecf20Sopenharmony_ci if (ret) 1168c2ecf20Sopenharmony_ci return ret; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci sched_clock_register(arc_gfrc_clock_read, 64, arc_timer_freq); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return clocksource_register_hz(&arc_counter_gfrc, arc_timer_freq); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#define AUX_RTC_CTRL 0x103 1258c2ecf20Sopenharmony_ci#define AUX_RTC_LOW 0x104 1268c2ecf20Sopenharmony_ci#define AUX_RTC_HIGH 0x105 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic u64 arc_read_rtc(struct clocksource *cs) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci unsigned long status; 1318c2ecf20Sopenharmony_ci u32 l, h; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* 1348c2ecf20Sopenharmony_ci * hardware has an internal state machine which tracks readout of 1358c2ecf20Sopenharmony_ci * low/high and updates the CTRL.status if 1368c2ecf20Sopenharmony_ci * - interrupt/exception taken between the two reads 1378c2ecf20Sopenharmony_ci * - high increments after low has been read 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_ci do { 1408c2ecf20Sopenharmony_ci l = read_aux_reg(AUX_RTC_LOW); 1418c2ecf20Sopenharmony_ci h = read_aux_reg(AUX_RTC_HIGH); 1428c2ecf20Sopenharmony_ci status = read_aux_reg(AUX_RTC_CTRL); 1438c2ecf20Sopenharmony_ci } while (!(status & BIT(31))); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci return (((u64)h) << 32) | l; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic notrace u64 arc_rtc_clock_read(void) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci return arc_read_rtc(NULL); 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic struct clocksource arc_counter_rtc = { 1548c2ecf20Sopenharmony_ci .name = "ARCv2 RTC", 1558c2ecf20Sopenharmony_ci .rating = 350, 1568c2ecf20Sopenharmony_ci .read = arc_read_rtc, 1578c2ecf20Sopenharmony_ci .mask = CLOCKSOURCE_MASK(64), 1588c2ecf20Sopenharmony_ci .flags = CLOCK_SOURCE_IS_CONTINUOUS, 1598c2ecf20Sopenharmony_ci}; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic int __init arc_cs_setup_rtc(struct device_node *node) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci struct bcr_timer timer; 1648c2ecf20Sopenharmony_ci int ret; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci READ_BCR(ARC_REG_TIMERS_BCR, timer); 1678c2ecf20Sopenharmony_ci if (!timer.rtc) { 1688c2ecf20Sopenharmony_ci pr_warn("Local-64-bit-Ctr clocksource not detected\n"); 1698c2ecf20Sopenharmony_ci return -ENXIO; 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* Local to CPU hence not usable in SMP */ 1738c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_SMP)) { 1748c2ecf20Sopenharmony_ci pr_warn("Local-64-bit-Ctr not usable in SMP\n"); 1758c2ecf20Sopenharmony_ci return -EINVAL; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci ret = arc_get_timer_clk(node); 1798c2ecf20Sopenharmony_ci if (ret) 1808c2ecf20Sopenharmony_ci return ret; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci write_aux_reg(AUX_RTC_CTRL, 1); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci sched_clock_register(arc_rtc_clock_read, 64, arc_timer_freq); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci return clocksource_register_hz(&arc_counter_rtc, arc_timer_freq); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(arc_rtc, "snps,archs-timer-rtc", arc_cs_setup_rtc); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci#endif 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/* 1938c2ecf20Sopenharmony_ci * 32bit TIMER1 to keep counting monotonically and wraparound 1948c2ecf20Sopenharmony_ci */ 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic u64 arc_read_timer1(struct clocksource *cs) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci return (u64) read_aux_reg(ARC_REG_TIMER1_CNT); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic notrace u64 arc_timer1_clock_read(void) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci return arc_read_timer1(NULL); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic struct clocksource arc_counter_timer1 = { 2078c2ecf20Sopenharmony_ci .name = "ARC Timer1", 2088c2ecf20Sopenharmony_ci .rating = 300, 2098c2ecf20Sopenharmony_ci .read = arc_read_timer1, 2108c2ecf20Sopenharmony_ci .mask = CLOCKSOURCE_MASK(32), 2118c2ecf20Sopenharmony_ci .flags = CLOCK_SOURCE_IS_CONTINUOUS, 2128c2ecf20Sopenharmony_ci}; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int __init arc_cs_setup_timer1(struct device_node *node) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci int ret; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci /* Local to CPU hence not usable in SMP */ 2198c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_SMP)) 2208c2ecf20Sopenharmony_ci return -EINVAL; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci ret = arc_get_timer_clk(node); 2238c2ecf20Sopenharmony_ci if (ret) 2248c2ecf20Sopenharmony_ci return ret; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMERN_MAX); 2278c2ecf20Sopenharmony_ci write_aux_reg(ARC_REG_TIMER1_CNT, 0); 2288c2ecf20Sopenharmony_ci write_aux_reg(ARC_REG_TIMER1_CTRL, TIMER_CTRL_NH); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci sched_clock_register(arc_timer1_clock_read, 32, arc_timer_freq); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return clocksource_register_hz(&arc_counter_timer1, arc_timer_freq); 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci/********** Clock Event Device *********/ 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic int arc_timer_irq; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci/* 2408c2ecf20Sopenharmony_ci * Arm the timer to interrupt after @cycles 2418c2ecf20Sopenharmony_ci * The distinction for oneshot/periodic is done in arc_event_timer_ack() below 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_cistatic void arc_timer_event_setup(unsigned int cycles) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci write_aux_reg(ARC_REG_TIMER0_LIMIT, cycles); 2468c2ecf20Sopenharmony_ci write_aux_reg(ARC_REG_TIMER0_CNT, 0); /* start from 0 */ 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci write_aux_reg(ARC_REG_TIMER0_CTRL, TIMER_CTRL_IE | TIMER_CTRL_NH); 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic int arc_clkevent_set_next_event(unsigned long delta, 2538c2ecf20Sopenharmony_ci struct clock_event_device *dev) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci arc_timer_event_setup(delta); 2568c2ecf20Sopenharmony_ci return 0; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic int arc_clkevent_set_periodic(struct clock_event_device *dev) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci /* 2628c2ecf20Sopenharmony_ci * At X Hz, 1 sec = 1000ms -> X cycles; 2638c2ecf20Sopenharmony_ci * 10ms -> X / 100 cycles 2648c2ecf20Sopenharmony_ci */ 2658c2ecf20Sopenharmony_ci arc_timer_event_setup(arc_timer_freq / HZ); 2668c2ecf20Sopenharmony_ci return 0; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct clock_event_device, arc_clockevent_device) = { 2708c2ecf20Sopenharmony_ci .name = "ARC Timer0", 2718c2ecf20Sopenharmony_ci .features = CLOCK_EVT_FEAT_ONESHOT | 2728c2ecf20Sopenharmony_ci CLOCK_EVT_FEAT_PERIODIC, 2738c2ecf20Sopenharmony_ci .rating = 300, 2748c2ecf20Sopenharmony_ci .set_next_event = arc_clkevent_set_next_event, 2758c2ecf20Sopenharmony_ci .set_state_periodic = arc_clkevent_set_periodic, 2768c2ecf20Sopenharmony_ci}; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic irqreturn_t timer_irq_handler(int irq, void *dev_id) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci /* 2818c2ecf20Sopenharmony_ci * Note that generic IRQ core could have passed @evt for @dev_id if 2828c2ecf20Sopenharmony_ci * irq_set_chip_and_handler() asked for handle_percpu_devid_irq() 2838c2ecf20Sopenharmony_ci */ 2848c2ecf20Sopenharmony_ci struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device); 2858c2ecf20Sopenharmony_ci int irq_reenable = clockevent_state_periodic(evt); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* 2888c2ecf20Sopenharmony_ci * 1. ACK the interrupt 2898c2ecf20Sopenharmony_ci * - For ARC700, any write to CTRL reg ACKs it, so just rewrite 2908c2ecf20Sopenharmony_ci * Count when [N]ot [H]alted bit. 2918c2ecf20Sopenharmony_ci * - For HS3x, it is a bit subtle. On taken count-down interrupt, 2928c2ecf20Sopenharmony_ci * IP bit [3] is set, which needs to be cleared for ACK'ing. 2938c2ecf20Sopenharmony_ci * The write below can only update the other two bits, hence 2948c2ecf20Sopenharmony_ci * explicitly clears IP bit 2958c2ecf20Sopenharmony_ci * 2. Re-arm interrupt if periodic by writing to IE bit [0] 2968c2ecf20Sopenharmony_ci */ 2978c2ecf20Sopenharmony_ci write_aux_reg(ARC_REG_TIMER0_CTRL, irq_reenable | TIMER_CTRL_NH); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci evt->event_handler(evt); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic int arc_timer_starting_cpu(unsigned int cpu) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci evt->cpumask = cpumask_of(smp_processor_id()); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci clockevents_config_and_register(evt, arc_timer_freq, 0, ARC_TIMERN_MAX); 3128c2ecf20Sopenharmony_ci enable_percpu_irq(arc_timer_irq, 0); 3138c2ecf20Sopenharmony_ci return 0; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic int arc_timer_dying_cpu(unsigned int cpu) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci disable_percpu_irq(arc_timer_irq); 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci/* 3238c2ecf20Sopenharmony_ci * clockevent setup for boot CPU 3248c2ecf20Sopenharmony_ci */ 3258c2ecf20Sopenharmony_cistatic int __init arc_clockevent_setup(struct device_node *node) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device); 3288c2ecf20Sopenharmony_ci int ret; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci arc_timer_irq = irq_of_parse_and_map(node, 0); 3318c2ecf20Sopenharmony_ci if (arc_timer_irq <= 0) { 3328c2ecf20Sopenharmony_ci pr_err("clockevent: missing irq\n"); 3338c2ecf20Sopenharmony_ci return -EINVAL; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci ret = arc_get_timer_clk(node); 3378c2ecf20Sopenharmony_ci if (ret) 3388c2ecf20Sopenharmony_ci return ret; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* Needs apriori irq_set_percpu_devid() done in intc map function */ 3418c2ecf20Sopenharmony_ci ret = request_percpu_irq(arc_timer_irq, timer_irq_handler, 3428c2ecf20Sopenharmony_ci "Timer0 (per-cpu-tick)", evt); 3438c2ecf20Sopenharmony_ci if (ret) { 3448c2ecf20Sopenharmony_ci pr_err("clockevent: unable to request irq\n"); 3458c2ecf20Sopenharmony_ci return ret; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci ret = cpuhp_setup_state(CPUHP_AP_ARC_TIMER_STARTING, 3498c2ecf20Sopenharmony_ci "clockevents/arc/timer:starting", 3508c2ecf20Sopenharmony_ci arc_timer_starting_cpu, 3518c2ecf20Sopenharmony_ci arc_timer_dying_cpu); 3528c2ecf20Sopenharmony_ci if (ret) { 3538c2ecf20Sopenharmony_ci pr_err("Failed to setup hotplug state\n"); 3548c2ecf20Sopenharmony_ci return ret; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci return 0; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic int __init arc_of_timer_init(struct device_node *np) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci static int init_count = 0; 3628c2ecf20Sopenharmony_ci int ret; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (!init_count) { 3658c2ecf20Sopenharmony_ci init_count = 1; 3668c2ecf20Sopenharmony_ci ret = arc_clockevent_setup(np); 3678c2ecf20Sopenharmony_ci } else { 3688c2ecf20Sopenharmony_ci ret = arc_cs_setup_timer1(np); 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci return ret; 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(arc_clkevt, "snps,arc-timer", arc_of_timer_init); 374