162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Keystone broadcast clock-event
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2013 Texas Instruments, Inc.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Ivan Khoronzhuk <ivan.khoronzhuk@ti.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/clk.h>
1162306a36Sopenharmony_ci#include <linux/clockchips.h>
1262306a36Sopenharmony_ci#include <linux/clocksource.h>
1362306a36Sopenharmony_ci#include <linux/interrupt.h>
1462306a36Sopenharmony_ci#include <linux/of_address.h>
1562306a36Sopenharmony_ci#include <linux/of_irq.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define TIMER_NAME			"timer-keystone"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/* Timer register offsets */
2062306a36Sopenharmony_ci#define TIM12				0x10
2162306a36Sopenharmony_ci#define TIM34				0x14
2262306a36Sopenharmony_ci#define PRD12				0x18
2362306a36Sopenharmony_ci#define PRD34				0x1c
2462306a36Sopenharmony_ci#define TCR				0x20
2562306a36Sopenharmony_ci#define TGCR				0x24
2662306a36Sopenharmony_ci#define INTCTLSTAT			0x44
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/* Timer register bitfields */
2962306a36Sopenharmony_ci#define TCR_ENAMODE_MASK		0xC0
3062306a36Sopenharmony_ci#define TCR_ENAMODE_ONESHOT_MASK	0x40
3162306a36Sopenharmony_ci#define TCR_ENAMODE_PERIODIC_MASK	0x80
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define TGCR_TIM_UNRESET_MASK		0x03
3462306a36Sopenharmony_ci#define INTCTLSTAT_ENINT_MASK		0x01
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/**
3762306a36Sopenharmony_ci * struct keystone_timer: holds timer's data
3862306a36Sopenharmony_ci * @base: timer memory base address
3962306a36Sopenharmony_ci * @hz_period: cycles per HZ period
4062306a36Sopenharmony_ci * @event_dev: event device based on timer
4162306a36Sopenharmony_ci */
4262306a36Sopenharmony_cistatic struct keystone_timer {
4362306a36Sopenharmony_ci	void __iomem *base;
4462306a36Sopenharmony_ci	unsigned long hz_period;
4562306a36Sopenharmony_ci	struct clock_event_device event_dev;
4662306a36Sopenharmony_ci} timer;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic inline u32 keystone_timer_readl(unsigned long rg)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	return readl_relaxed(timer.base + rg);
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic inline void keystone_timer_writel(u32 val, unsigned long rg)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	writel_relaxed(val, timer.base + rg);
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/**
5962306a36Sopenharmony_ci * keystone_timer_barrier: write memory barrier
6062306a36Sopenharmony_ci * use explicit barrier to avoid using readl/writel non relaxed function
6162306a36Sopenharmony_ci * variants, because in our case non relaxed variants hide the true places
6262306a36Sopenharmony_ci * where barrier is needed.
6362306a36Sopenharmony_ci */
6462306a36Sopenharmony_cistatic inline void keystone_timer_barrier(void)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	__iowmb();
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/**
7062306a36Sopenharmony_ci * keystone_timer_config: configures timer to work in oneshot/periodic modes.
7162306a36Sopenharmony_ci * @ mask: mask of the mode to configure
7262306a36Sopenharmony_ci * @ period: cycles number to configure for
7362306a36Sopenharmony_ci */
7462306a36Sopenharmony_cistatic int keystone_timer_config(u64 period, int mask)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	u32 tcr;
7762306a36Sopenharmony_ci	u32 off;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	tcr = keystone_timer_readl(TCR);
8062306a36Sopenharmony_ci	off = tcr & ~(TCR_ENAMODE_MASK);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	/* set enable mode */
8362306a36Sopenharmony_ci	tcr |= mask;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	/* disable timer */
8662306a36Sopenharmony_ci	keystone_timer_writel(off, TCR);
8762306a36Sopenharmony_ci	/* here we have to be sure the timer has been disabled */
8862306a36Sopenharmony_ci	keystone_timer_barrier();
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	/* reset counter to zero, set new period */
9162306a36Sopenharmony_ci	keystone_timer_writel(0, TIM12);
9262306a36Sopenharmony_ci	keystone_timer_writel(0, TIM34);
9362306a36Sopenharmony_ci	keystone_timer_writel(period & 0xffffffff, PRD12);
9462306a36Sopenharmony_ci	keystone_timer_writel(period >> 32, PRD34);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	/*
9762306a36Sopenharmony_ci	 * enable timer
9862306a36Sopenharmony_ci	 * here we have to be sure that CNTLO, CNTHI, PRDLO, PRDHI registers
9962306a36Sopenharmony_ci	 * have been written.
10062306a36Sopenharmony_ci	 */
10162306a36Sopenharmony_ci	keystone_timer_barrier();
10262306a36Sopenharmony_ci	keystone_timer_writel(tcr, TCR);
10362306a36Sopenharmony_ci	return 0;
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic void keystone_timer_disable(void)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	u32 tcr;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	tcr = keystone_timer_readl(TCR);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	/* disable timer */
11362306a36Sopenharmony_ci	tcr &= ~(TCR_ENAMODE_MASK);
11462306a36Sopenharmony_ci	keystone_timer_writel(tcr, TCR);
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic irqreturn_t keystone_timer_interrupt(int irq, void *dev_id)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	struct clock_event_device *evt = dev_id;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	evt->event_handler(evt);
12262306a36Sopenharmony_ci	return IRQ_HANDLED;
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic int keystone_set_next_event(unsigned long cycles,
12662306a36Sopenharmony_ci				  struct clock_event_device *evt)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	return keystone_timer_config(cycles, TCR_ENAMODE_ONESHOT_MASK);
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic int keystone_shutdown(struct clock_event_device *evt)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	keystone_timer_disable();
13462306a36Sopenharmony_ci	return 0;
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic int keystone_set_periodic(struct clock_event_device *evt)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	keystone_timer_config(timer.hz_period, TCR_ENAMODE_PERIODIC_MASK);
14062306a36Sopenharmony_ci	return 0;
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic int __init keystone_timer_init(struct device_node *np)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	struct clock_event_device *event_dev = &timer.event_dev;
14662306a36Sopenharmony_ci	unsigned long rate;
14762306a36Sopenharmony_ci	struct clk *clk;
14862306a36Sopenharmony_ci	int irq, error;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	irq  = irq_of_parse_and_map(np, 0);
15162306a36Sopenharmony_ci	if (!irq) {
15262306a36Sopenharmony_ci		pr_err("%s: failed to map interrupts\n", __func__);
15362306a36Sopenharmony_ci		return -EINVAL;
15462306a36Sopenharmony_ci	}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	timer.base = of_iomap(np, 0);
15762306a36Sopenharmony_ci	if (!timer.base) {
15862306a36Sopenharmony_ci		pr_err("%s: failed to map registers\n", __func__);
15962306a36Sopenharmony_ci		return -ENXIO;
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	clk = of_clk_get(np, 0);
16362306a36Sopenharmony_ci	if (IS_ERR(clk)) {
16462306a36Sopenharmony_ci		pr_err("%s: failed to get clock\n", __func__);
16562306a36Sopenharmony_ci		iounmap(timer.base);
16662306a36Sopenharmony_ci		return PTR_ERR(clk);
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	error = clk_prepare_enable(clk);
17062306a36Sopenharmony_ci	if (error) {
17162306a36Sopenharmony_ci		pr_err("%s: failed to enable clock\n", __func__);
17262306a36Sopenharmony_ci		goto err;
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	rate = clk_get_rate(clk);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	/* disable, use internal clock source */
17862306a36Sopenharmony_ci	keystone_timer_writel(0, TCR);
17962306a36Sopenharmony_ci	/* here we have to be sure the timer has been disabled */
18062306a36Sopenharmony_ci	keystone_timer_barrier();
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	/* reset timer as 64-bit, no pre-scaler, plus features are disabled */
18362306a36Sopenharmony_ci	keystone_timer_writel(0, TGCR);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	/* unreset timer */
18662306a36Sopenharmony_ci	keystone_timer_writel(TGCR_TIM_UNRESET_MASK, TGCR);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	/* init counter to zero */
18962306a36Sopenharmony_ci	keystone_timer_writel(0, TIM12);
19062306a36Sopenharmony_ci	keystone_timer_writel(0, TIM34);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	timer.hz_period = DIV_ROUND_UP(rate, HZ);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	/* enable timer interrupts */
19562306a36Sopenharmony_ci	keystone_timer_writel(INTCTLSTAT_ENINT_MASK, INTCTLSTAT);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	error = request_irq(irq, keystone_timer_interrupt, IRQF_TIMER,
19862306a36Sopenharmony_ci			    TIMER_NAME, event_dev);
19962306a36Sopenharmony_ci	if (error) {
20062306a36Sopenharmony_ci		pr_err("%s: failed to setup irq\n", __func__);
20162306a36Sopenharmony_ci		goto err;
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	/* setup clockevent */
20562306a36Sopenharmony_ci	event_dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
20662306a36Sopenharmony_ci	event_dev->set_next_event = keystone_set_next_event;
20762306a36Sopenharmony_ci	event_dev->set_state_shutdown = keystone_shutdown;
20862306a36Sopenharmony_ci	event_dev->set_state_periodic = keystone_set_periodic;
20962306a36Sopenharmony_ci	event_dev->set_state_oneshot = keystone_shutdown;
21062306a36Sopenharmony_ci	event_dev->cpumask = cpu_possible_mask;
21162306a36Sopenharmony_ci	event_dev->owner = THIS_MODULE;
21262306a36Sopenharmony_ci	event_dev->name = TIMER_NAME;
21362306a36Sopenharmony_ci	event_dev->irq = irq;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	clockevents_config_and_register(event_dev, rate, 1, ULONG_MAX);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	pr_info("keystone timer clock @%lu Hz\n", rate);
21862306a36Sopenharmony_ci	return 0;
21962306a36Sopenharmony_cierr:
22062306a36Sopenharmony_ci	clk_put(clk);
22162306a36Sopenharmony_ci	iounmap(timer.base);
22262306a36Sopenharmony_ci	return error;
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ciTIMER_OF_DECLARE(keystone_timer, "ti,keystone-timer",
22662306a36Sopenharmony_ci			   keystone_timer_init);
227