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