18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci//  Copyright (C) 2000-2001 Deep Blue Solutions
48c2ecf20Sopenharmony_ci//  Copyright (C) 2002 Shane Nay (shane@minirl.com)
58c2ecf20Sopenharmony_ci//  Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com)
68c2ecf20Sopenharmony_ci//  Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
78c2ecf20Sopenharmony_ci//  Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/err.h>
108c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
118c2ecf20Sopenharmony_ci#include <linux/irq.h>
128c2ecf20Sopenharmony_ci#include <linux/clockchips.h>
138c2ecf20Sopenharmony_ci#include <linux/clk.h>
148c2ecf20Sopenharmony_ci#include <linux/of.h>
158c2ecf20Sopenharmony_ci#include <linux/of_address.h>
168c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
178c2ecf20Sopenharmony_ci#include <linux/stmp_device.h>
188c2ecf20Sopenharmony_ci#include <linux/sched_clock.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/*
218c2ecf20Sopenharmony_ci * There are 2 versions of the timrot on Freescale MXS-based SoCs.
228c2ecf20Sopenharmony_ci * The v1 on MX23 only gets 16 bits counter, while v2 on MX28
238c2ecf20Sopenharmony_ci * extends the counter to 32 bits.
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci * The implementation uses two timers, one for clock_event and
268c2ecf20Sopenharmony_ci * another for clocksource. MX28 uses timrot 0 and 1, while MX23
278c2ecf20Sopenharmony_ci * uses 0 and 2.
288c2ecf20Sopenharmony_ci */
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define MX23_TIMROT_VERSION_OFFSET	0x0a0
318c2ecf20Sopenharmony_ci#define MX28_TIMROT_VERSION_OFFSET	0x120
328c2ecf20Sopenharmony_ci#define BP_TIMROT_MAJOR_VERSION		24
338c2ecf20Sopenharmony_ci#define BV_TIMROT_VERSION_1		0x01
348c2ecf20Sopenharmony_ci#define BV_TIMROT_VERSION_2		0x02
358c2ecf20Sopenharmony_ci#define timrot_is_v1()	(timrot_major_version == BV_TIMROT_VERSION_1)
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci/*
388c2ecf20Sopenharmony_ci * There are 4 registers for each timrotv2 instance, and 2 registers
398c2ecf20Sopenharmony_ci * for each timrotv1. So address step 0x40 in macros below strides
408c2ecf20Sopenharmony_ci * one instance of timrotv2 while two instances of timrotv1.
418c2ecf20Sopenharmony_ci *
428c2ecf20Sopenharmony_ci * As the result, HW_TIMROT_XXXn(1) defines the address of timrot1
438c2ecf20Sopenharmony_ci * on MX28 while timrot2 on MX23.
448c2ecf20Sopenharmony_ci */
458c2ecf20Sopenharmony_ci/* common between v1 and v2 */
468c2ecf20Sopenharmony_ci#define HW_TIMROT_ROTCTRL		0x00
478c2ecf20Sopenharmony_ci#define HW_TIMROT_TIMCTRLn(n)		(0x20 + (n) * 0x40)
488c2ecf20Sopenharmony_ci/* v1 only */
498c2ecf20Sopenharmony_ci#define HW_TIMROT_TIMCOUNTn(n)		(0x30 + (n) * 0x40)
508c2ecf20Sopenharmony_ci/* v2 only */
518c2ecf20Sopenharmony_ci#define HW_TIMROT_RUNNING_COUNTn(n)	(0x30 + (n) * 0x40)
528c2ecf20Sopenharmony_ci#define HW_TIMROT_FIXED_COUNTn(n)	(0x40 + (n) * 0x40)
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci#define BM_TIMROT_TIMCTRLn_RELOAD	(1 << 6)
558c2ecf20Sopenharmony_ci#define BM_TIMROT_TIMCTRLn_UPDATE	(1 << 7)
568c2ecf20Sopenharmony_ci#define BM_TIMROT_TIMCTRLn_IRQ_EN	(1 << 14)
578c2ecf20Sopenharmony_ci#define BM_TIMROT_TIMCTRLn_IRQ		(1 << 15)
588c2ecf20Sopenharmony_ci#define BP_TIMROT_TIMCTRLn_SELECT	0
598c2ecf20Sopenharmony_ci#define BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL		0x8
608c2ecf20Sopenharmony_ci#define BV_TIMROTv2_TIMCTRLn_SELECT__32KHZ_XTAL		0xb
618c2ecf20Sopenharmony_ci#define BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS	0xf
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic struct clock_event_device mxs_clockevent_device;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic void __iomem *mxs_timrot_base;
668c2ecf20Sopenharmony_cistatic u32 timrot_major_version;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic inline void timrot_irq_disable(void)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	__raw_writel(BM_TIMROT_TIMCTRLn_IRQ_EN, mxs_timrot_base +
718c2ecf20Sopenharmony_ci		     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_CLR);
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic inline void timrot_irq_enable(void)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	__raw_writel(BM_TIMROT_TIMCTRLn_IRQ_EN, mxs_timrot_base +
778c2ecf20Sopenharmony_ci		     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_SET);
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic void timrot_irq_acknowledge(void)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	__raw_writel(BM_TIMROT_TIMCTRLn_IRQ, mxs_timrot_base +
838c2ecf20Sopenharmony_ci		     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_CLR);
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic u64 timrotv1_get_cycles(struct clocksource *cs)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	return ~((__raw_readl(mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1))
898c2ecf20Sopenharmony_ci			& 0xffff0000) >> 16);
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic int timrotv1_set_next_event(unsigned long evt,
938c2ecf20Sopenharmony_ci					struct clock_event_device *dev)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	/* timrot decrements the count */
968c2ecf20Sopenharmony_ci	__raw_writel(evt, mxs_timrot_base + HW_TIMROT_TIMCOUNTn(0));
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	return 0;
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic int timrotv2_set_next_event(unsigned long evt,
1028c2ecf20Sopenharmony_ci					struct clock_event_device *dev)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	/* timrot decrements the count */
1058c2ecf20Sopenharmony_ci	__raw_writel(evt, mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(0));
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	return 0;
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic irqreturn_t mxs_timer_interrupt(int irq, void *dev_id)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	struct clock_event_device *evt = dev_id;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	timrot_irq_acknowledge();
1158c2ecf20Sopenharmony_ci	evt->event_handler(evt);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic void mxs_irq_clear(char *state)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	/* Disable interrupt in timer module */
1238c2ecf20Sopenharmony_ci	timrot_irq_disable();
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	/* Set event time into the furthest future */
1268c2ecf20Sopenharmony_ci	if (timrot_is_v1())
1278c2ecf20Sopenharmony_ci		__raw_writel(0xffff, mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1));
1288c2ecf20Sopenharmony_ci	else
1298c2ecf20Sopenharmony_ci		__raw_writel(0xffffffff,
1308c2ecf20Sopenharmony_ci			     mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1));
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	/* Clear pending interrupt */
1338c2ecf20Sopenharmony_ci	timrot_irq_acknowledge();
1348c2ecf20Sopenharmony_ci	pr_debug("%s: changing mode to %s\n", __func__, state);
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic int mxs_shutdown(struct clock_event_device *evt)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	mxs_irq_clear("shutdown");
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	return 0;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic int mxs_set_oneshot(struct clock_event_device *evt)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	if (clockevent_state_oneshot(evt))
1478c2ecf20Sopenharmony_ci		mxs_irq_clear("oneshot");
1488c2ecf20Sopenharmony_ci	timrot_irq_enable();
1498c2ecf20Sopenharmony_ci	return 0;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic struct clock_event_device mxs_clockevent_device = {
1538c2ecf20Sopenharmony_ci	.name			= "mxs_timrot",
1548c2ecf20Sopenharmony_ci	.features		= CLOCK_EVT_FEAT_ONESHOT,
1558c2ecf20Sopenharmony_ci	.set_state_shutdown	= mxs_shutdown,
1568c2ecf20Sopenharmony_ci	.set_state_oneshot	= mxs_set_oneshot,
1578c2ecf20Sopenharmony_ci	.tick_resume		= mxs_shutdown,
1588c2ecf20Sopenharmony_ci	.set_next_event		= timrotv2_set_next_event,
1598c2ecf20Sopenharmony_ci	.rating			= 200,
1608c2ecf20Sopenharmony_ci};
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic int __init mxs_clockevent_init(struct clk *timer_clk)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	if (timrot_is_v1())
1658c2ecf20Sopenharmony_ci		mxs_clockevent_device.set_next_event = timrotv1_set_next_event;
1668c2ecf20Sopenharmony_ci	mxs_clockevent_device.cpumask = cpumask_of(0);
1678c2ecf20Sopenharmony_ci	clockevents_config_and_register(&mxs_clockevent_device,
1688c2ecf20Sopenharmony_ci					clk_get_rate(timer_clk),
1698c2ecf20Sopenharmony_ci					timrot_is_v1() ? 0xf : 0x2,
1708c2ecf20Sopenharmony_ci					timrot_is_v1() ? 0xfffe : 0xfffffffe);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	return 0;
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic struct clocksource clocksource_mxs = {
1768c2ecf20Sopenharmony_ci	.name		= "mxs_timer",
1778c2ecf20Sopenharmony_ci	.rating		= 200,
1788c2ecf20Sopenharmony_ci	.read		= timrotv1_get_cycles,
1798c2ecf20Sopenharmony_ci	.mask		= CLOCKSOURCE_MASK(16),
1808c2ecf20Sopenharmony_ci	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
1818c2ecf20Sopenharmony_ci};
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cistatic u64 notrace mxs_read_sched_clock_v2(void)
1848c2ecf20Sopenharmony_ci{
1858c2ecf20Sopenharmony_ci	return ~readl_relaxed(mxs_timrot_base + HW_TIMROT_RUNNING_COUNTn(1));
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic int __init mxs_clocksource_init(struct clk *timer_clk)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	unsigned int c = clk_get_rate(timer_clk);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	if (timrot_is_v1())
1938c2ecf20Sopenharmony_ci		clocksource_register_hz(&clocksource_mxs, c);
1948c2ecf20Sopenharmony_ci	else {
1958c2ecf20Sopenharmony_ci		clocksource_mmio_init(mxs_timrot_base + HW_TIMROT_RUNNING_COUNTn(1),
1968c2ecf20Sopenharmony_ci			"mxs_timer", c, 200, 32, clocksource_mmio_readl_down);
1978c2ecf20Sopenharmony_ci		sched_clock_register(mxs_read_sched_clock_v2, 32, c);
1988c2ecf20Sopenharmony_ci	}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	return 0;
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_cistatic int __init mxs_timer_init(struct device_node *np)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	struct clk *timer_clk;
2068c2ecf20Sopenharmony_ci	int irq, ret;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	mxs_timrot_base = of_iomap(np, 0);
2098c2ecf20Sopenharmony_ci	WARN_ON(!mxs_timrot_base);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	timer_clk = of_clk_get(np, 0);
2128c2ecf20Sopenharmony_ci	if (IS_ERR(timer_clk)) {
2138c2ecf20Sopenharmony_ci		pr_err("%s: failed to get clk\n", __func__);
2148c2ecf20Sopenharmony_ci		return PTR_ERR(timer_clk);
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(timer_clk);
2188c2ecf20Sopenharmony_ci	if (ret)
2198c2ecf20Sopenharmony_ci		return ret;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	/*
2228c2ecf20Sopenharmony_ci	 * Initialize timers to a known state
2238c2ecf20Sopenharmony_ci	 */
2248c2ecf20Sopenharmony_ci	stmp_reset_block(mxs_timrot_base + HW_TIMROT_ROTCTRL);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	/* get timrot version */
2278c2ecf20Sopenharmony_ci	timrot_major_version = __raw_readl(mxs_timrot_base +
2288c2ecf20Sopenharmony_ci			(of_device_is_compatible(np, "fsl,imx23-timrot") ?
2298c2ecf20Sopenharmony_ci						MX23_TIMROT_VERSION_OFFSET :
2308c2ecf20Sopenharmony_ci						MX28_TIMROT_VERSION_OFFSET));
2318c2ecf20Sopenharmony_ci	timrot_major_version >>= BP_TIMROT_MAJOR_VERSION;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	/* one for clock_event */
2348c2ecf20Sopenharmony_ci	__raw_writel((timrot_is_v1() ?
2358c2ecf20Sopenharmony_ci			BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL :
2368c2ecf20Sopenharmony_ci			BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS) |
2378c2ecf20Sopenharmony_ci			BM_TIMROT_TIMCTRLn_UPDATE |
2388c2ecf20Sopenharmony_ci			BM_TIMROT_TIMCTRLn_IRQ_EN,
2398c2ecf20Sopenharmony_ci			mxs_timrot_base + HW_TIMROT_TIMCTRLn(0));
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	/* another for clocksource */
2428c2ecf20Sopenharmony_ci	__raw_writel((timrot_is_v1() ?
2438c2ecf20Sopenharmony_ci			BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL :
2448c2ecf20Sopenharmony_ci			BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS) |
2458c2ecf20Sopenharmony_ci			BM_TIMROT_TIMCTRLn_RELOAD,
2468c2ecf20Sopenharmony_ci			mxs_timrot_base + HW_TIMROT_TIMCTRLn(1));
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	/* set clocksource timer fixed count to the maximum */
2498c2ecf20Sopenharmony_ci	if (timrot_is_v1())
2508c2ecf20Sopenharmony_ci		__raw_writel(0xffff,
2518c2ecf20Sopenharmony_ci			mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1));
2528c2ecf20Sopenharmony_ci	else
2538c2ecf20Sopenharmony_ci		__raw_writel(0xffffffff,
2548c2ecf20Sopenharmony_ci			mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1));
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	/* init and register the timer to the framework */
2578c2ecf20Sopenharmony_ci	ret = mxs_clocksource_init(timer_clk);
2588c2ecf20Sopenharmony_ci	if (ret)
2598c2ecf20Sopenharmony_ci		return ret;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	ret = mxs_clockevent_init(timer_clk);
2628c2ecf20Sopenharmony_ci	if (ret)
2638c2ecf20Sopenharmony_ci		return ret;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	/* Make irqs happen */
2668c2ecf20Sopenharmony_ci	irq = irq_of_parse_and_map(np, 0);
2678c2ecf20Sopenharmony_ci	if (irq <= 0)
2688c2ecf20Sopenharmony_ci		return -EINVAL;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	return request_irq(irq, mxs_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
2718c2ecf20Sopenharmony_ci			   "MXS Timer Tick", &mxs_clockevent_device);
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(mxs, "fsl,timrot", mxs_timer_init);
274