162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * arch/arm/mach-pxa/time.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * PXA clocksource, clockevents, and OST interrupt handlers.
662306a36Sopenharmony_ci * Copyright (c) 2007 by Bill Gatliff <bgat@billgatliff.com>.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Derived from Nicolas Pitre's PXA timer handler Copyright (c) 2001
962306a36Sopenharmony_ci * by MontaVista Software, Inc.  (Nico, your code rocks!)
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/init.h>
1462306a36Sopenharmony_ci#include <linux/interrupt.h>
1562306a36Sopenharmony_ci#include <linux/clk.h>
1662306a36Sopenharmony_ci#include <linux/clockchips.h>
1762306a36Sopenharmony_ci#include <linux/of_address.h>
1862306a36Sopenharmony_ci#include <linux/of_irq.h>
1962306a36Sopenharmony_ci#include <linux/sched/clock.h>
2062306a36Sopenharmony_ci#include <linux/sched_clock.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include <clocksource/pxa.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <asm/div64.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define OSMR0		0x00	/* OS Timer 0 Match Register */
2762306a36Sopenharmony_ci#define OSMR1		0x04	/* OS Timer 1 Match Register */
2862306a36Sopenharmony_ci#define OSMR2		0x08	/* OS Timer 2 Match Register */
2962306a36Sopenharmony_ci#define OSMR3		0x0C	/* OS Timer 3 Match Register */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define OSCR		0x10	/* OS Timer Counter Register */
3262306a36Sopenharmony_ci#define OSSR		0x14	/* OS Timer Status Register */
3362306a36Sopenharmony_ci#define OWER		0x18	/* OS Timer Watchdog Enable Register */
3462306a36Sopenharmony_ci#define OIER		0x1C	/* OS Timer Interrupt Enable Register */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define OSSR_M3		(1 << 3)	/* Match status channel 3 */
3762306a36Sopenharmony_ci#define OSSR_M2		(1 << 2)	/* Match status channel 2 */
3862306a36Sopenharmony_ci#define OSSR_M1		(1 << 1)	/* Match status channel 1 */
3962306a36Sopenharmony_ci#define OSSR_M0		(1 << 0)	/* Match status channel 0 */
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define OIER_E0		(1 << 0)	/* Interrupt enable channel 0 */
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/*
4462306a36Sopenharmony_ci * This is PXA's sched_clock implementation. This has a resolution
4562306a36Sopenharmony_ci * of at least 308 ns and a maximum value of 208 days.
4662306a36Sopenharmony_ci *
4762306a36Sopenharmony_ci * The return value is guaranteed to be monotonic in that range as
4862306a36Sopenharmony_ci * long as there is always less than 582 seconds between successive
4962306a36Sopenharmony_ci * calls to sched_clock() which should always be the case in practice.
5062306a36Sopenharmony_ci */
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define timer_readl(reg) readl_relaxed(timer_base + (reg))
5362306a36Sopenharmony_ci#define timer_writel(val, reg) writel_relaxed((val), timer_base + (reg))
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic void __iomem *timer_base;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic u64 notrace pxa_read_sched_clock(void)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	return timer_readl(OSCR);
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define MIN_OSCR_DELTA 16
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic irqreturn_t
6662306a36Sopenharmony_cipxa_ost0_interrupt(int irq, void *dev_id)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	struct clock_event_device *c = dev_id;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/* Disarm the compare/match, signal the event. */
7162306a36Sopenharmony_ci	timer_writel(timer_readl(OIER) & ~OIER_E0, OIER);
7262306a36Sopenharmony_ci	timer_writel(OSSR_M0, OSSR);
7362306a36Sopenharmony_ci	c->event_handler(c);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	return IRQ_HANDLED;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic int
7962306a36Sopenharmony_cipxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	unsigned long next, oscr;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	timer_writel(timer_readl(OIER) | OIER_E0, OIER);
8462306a36Sopenharmony_ci	next = timer_readl(OSCR) + delta;
8562306a36Sopenharmony_ci	timer_writel(next, OSMR0);
8662306a36Sopenharmony_ci	oscr = timer_readl(OSCR);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic int pxa_osmr0_shutdown(struct clock_event_device *evt)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	/* initializing, released, or preparing for suspend */
9462306a36Sopenharmony_ci	timer_writel(timer_readl(OIER) & ~OIER_E0, OIER);
9562306a36Sopenharmony_ci	timer_writel(OSSR_M0, OSSR);
9662306a36Sopenharmony_ci	return 0;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci#ifdef CONFIG_PM
10062306a36Sopenharmony_cistatic unsigned long osmr[4], oier, oscr;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic void pxa_timer_suspend(struct clock_event_device *cedev)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	osmr[0] = timer_readl(OSMR0);
10562306a36Sopenharmony_ci	osmr[1] = timer_readl(OSMR1);
10662306a36Sopenharmony_ci	osmr[2] = timer_readl(OSMR2);
10762306a36Sopenharmony_ci	osmr[3] = timer_readl(OSMR3);
10862306a36Sopenharmony_ci	oier = timer_readl(OIER);
10962306a36Sopenharmony_ci	oscr = timer_readl(OSCR);
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic void pxa_timer_resume(struct clock_event_device *cedev)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	/*
11562306a36Sopenharmony_ci	 * Ensure that we have at least MIN_OSCR_DELTA between match
11662306a36Sopenharmony_ci	 * register 0 and the OSCR, to guarantee that we will receive
11762306a36Sopenharmony_ci	 * the one-shot timer interrupt.  We adjust OSMR0 in preference
11862306a36Sopenharmony_ci	 * to OSCR to guarantee that OSCR is monotonically incrementing.
11962306a36Sopenharmony_ci	 */
12062306a36Sopenharmony_ci	if (osmr[0] - oscr < MIN_OSCR_DELTA)
12162306a36Sopenharmony_ci		osmr[0] += MIN_OSCR_DELTA;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	timer_writel(osmr[0], OSMR0);
12462306a36Sopenharmony_ci	timer_writel(osmr[1], OSMR1);
12562306a36Sopenharmony_ci	timer_writel(osmr[2], OSMR2);
12662306a36Sopenharmony_ci	timer_writel(osmr[3], OSMR3);
12762306a36Sopenharmony_ci	timer_writel(oier, OIER);
12862306a36Sopenharmony_ci	timer_writel(oscr, OSCR);
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci#else
13162306a36Sopenharmony_ci#define pxa_timer_suspend NULL
13262306a36Sopenharmony_ci#define pxa_timer_resume NULL
13362306a36Sopenharmony_ci#endif
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic struct clock_event_device ckevt_pxa_osmr0 = {
13662306a36Sopenharmony_ci	.name			= "osmr0",
13762306a36Sopenharmony_ci	.features		= CLOCK_EVT_FEAT_ONESHOT,
13862306a36Sopenharmony_ci	.rating			= 200,
13962306a36Sopenharmony_ci	.set_next_event		= pxa_osmr0_set_next_event,
14062306a36Sopenharmony_ci	.set_state_shutdown	= pxa_osmr0_shutdown,
14162306a36Sopenharmony_ci	.set_state_oneshot	= pxa_osmr0_shutdown,
14262306a36Sopenharmony_ci	.suspend		= pxa_timer_suspend,
14362306a36Sopenharmony_ci	.resume			= pxa_timer_resume,
14462306a36Sopenharmony_ci};
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic int __init pxa_timer_common_init(int irq, unsigned long clock_tick_rate)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	int ret;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	timer_writel(0, OIER);
15162306a36Sopenharmony_ci	timer_writel(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	sched_clock_register(pxa_read_sched_clock, 32, clock_tick_rate);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	ckevt_pxa_osmr0.cpumask = cpumask_of(0);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	ret = request_irq(irq, pxa_ost0_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
15862306a36Sopenharmony_ci			  "ost0", &ckevt_pxa_osmr0);
15962306a36Sopenharmony_ci	if (ret) {
16062306a36Sopenharmony_ci		pr_err("Failed to setup irq\n");
16162306a36Sopenharmony_ci		return ret;
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	ret = clocksource_mmio_init(timer_base + OSCR, "oscr0", clock_tick_rate, 200,
16562306a36Sopenharmony_ci				    32, clocksource_mmio_readl_up);
16662306a36Sopenharmony_ci	if (ret) {
16762306a36Sopenharmony_ci		pr_err("Failed to init clocksource\n");
16862306a36Sopenharmony_ci		return ret;
16962306a36Sopenharmony_ci	}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	clockevents_config_and_register(&ckevt_pxa_osmr0, clock_tick_rate,
17262306a36Sopenharmony_ci					MIN_OSCR_DELTA * 2, 0x7fffffff);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	return 0;
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic int __init pxa_timer_dt_init(struct device_node *np)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	struct clk *clk;
18062306a36Sopenharmony_ci	int irq, ret;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	/* timer registers are shared with watchdog timer */
18362306a36Sopenharmony_ci	timer_base = of_iomap(np, 0);
18462306a36Sopenharmony_ci	if (!timer_base) {
18562306a36Sopenharmony_ci		pr_err("%pOFn: unable to map resource\n", np);
18662306a36Sopenharmony_ci		return -ENXIO;
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	clk = of_clk_get(np, 0);
19062306a36Sopenharmony_ci	if (IS_ERR(clk)) {
19162306a36Sopenharmony_ci		pr_crit("%pOFn: unable to get clk\n", np);
19262306a36Sopenharmony_ci		return PTR_ERR(clk);
19362306a36Sopenharmony_ci	}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	ret = clk_prepare_enable(clk);
19662306a36Sopenharmony_ci	if (ret) {
19762306a36Sopenharmony_ci		pr_crit("Failed to prepare clock\n");
19862306a36Sopenharmony_ci		return ret;
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	/* we are only interested in OS-timer0 irq */
20262306a36Sopenharmony_ci	irq = irq_of_parse_and_map(np, 0);
20362306a36Sopenharmony_ci	if (irq <= 0) {
20462306a36Sopenharmony_ci		pr_crit("%pOFn: unable to parse OS-timer0 irq\n", np);
20562306a36Sopenharmony_ci		return -EINVAL;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	return pxa_timer_common_init(irq, clk_get_rate(clk));
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ciTIMER_OF_DECLARE(pxa_timer, "marvell,pxa-timer", pxa_timer_dt_init);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci/*
21362306a36Sopenharmony_ci * Legacy timer init for non device-tree boards.
21462306a36Sopenharmony_ci */
21562306a36Sopenharmony_civoid __init pxa_timer_nodt_init(int irq, void __iomem *base)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	struct clk *clk;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	timer_base = base;
22062306a36Sopenharmony_ci	clk = clk_get(NULL, "OSTIMER0");
22162306a36Sopenharmony_ci	if (clk && !IS_ERR(clk)) {
22262306a36Sopenharmony_ci		clk_prepare_enable(clk);
22362306a36Sopenharmony_ci		pxa_timer_common_init(irq, clk_get_rate(clk));
22462306a36Sopenharmony_ci	} else {
22562306a36Sopenharmony_ci		pr_crit("%s: unable to get clk\n", __func__);
22662306a36Sopenharmony_ci	}
22762306a36Sopenharmony_ci}
228