18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * RDA8810PL SoC timer driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright RDA Microelectronics Company Limited
68c2ecf20Sopenharmony_ci * Copyright (c) 2017 Andreas Färber
78c2ecf20Sopenharmony_ci * Copyright (c) 2018 Manivannan Sadhasivam
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * RDA8810PL has two independent timers: OSTIMER (56 bit) and HWTIMER (64 bit).
108c2ecf20Sopenharmony_ci * Each timer provides optional interrupt support. In this driver, OSTIMER is
118c2ecf20Sopenharmony_ci * used for clockevents and HWTIMER is used for clocksource.
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/init.h>
158c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include "timer-of.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define RDA_OSTIMER_LOADVAL_L	0x000
208c2ecf20Sopenharmony_ci#define RDA_OSTIMER_CTRL	0x004
218c2ecf20Sopenharmony_ci#define RDA_HWTIMER_LOCKVAL_L	0x024
228c2ecf20Sopenharmony_ci#define RDA_HWTIMER_LOCKVAL_H	0x028
238c2ecf20Sopenharmony_ci#define RDA_TIMER_IRQ_MASK_SET	0x02c
248c2ecf20Sopenharmony_ci#define RDA_TIMER_IRQ_MASK_CLR	0x030
258c2ecf20Sopenharmony_ci#define RDA_TIMER_IRQ_CLR	0x034
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define RDA_OSTIMER_CTRL_ENABLE		BIT(24)
288c2ecf20Sopenharmony_ci#define RDA_OSTIMER_CTRL_REPEAT		BIT(28)
298c2ecf20Sopenharmony_ci#define RDA_OSTIMER_CTRL_LOAD		BIT(30)
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define RDA_TIMER_IRQ_MASK_OSTIMER	BIT(0)
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define RDA_TIMER_IRQ_CLR_OSTIMER	BIT(0)
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic int rda_ostimer_start(void __iomem *base, bool periodic, u64 cycles)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	u32 ctrl, load_l;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	load_l = (u32)cycles;
408c2ecf20Sopenharmony_ci	ctrl = ((cycles >> 32) & 0xffffff);
418c2ecf20Sopenharmony_ci	ctrl |= RDA_OSTIMER_CTRL_LOAD | RDA_OSTIMER_CTRL_ENABLE;
428c2ecf20Sopenharmony_ci	if (periodic)
438c2ecf20Sopenharmony_ci		ctrl |= RDA_OSTIMER_CTRL_REPEAT;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	/* Enable ostimer interrupt first */
468c2ecf20Sopenharmony_ci	writel_relaxed(RDA_TIMER_IRQ_MASK_OSTIMER,
478c2ecf20Sopenharmony_ci		       base + RDA_TIMER_IRQ_MASK_SET);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	/* Write low 32 bits first, high 24 bits are with ctrl */
508c2ecf20Sopenharmony_ci	writel_relaxed(load_l, base + RDA_OSTIMER_LOADVAL_L);
518c2ecf20Sopenharmony_ci	writel_relaxed(ctrl, base + RDA_OSTIMER_CTRL);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	return 0;
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic int rda_ostimer_stop(void __iomem *base)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	/* Disable ostimer interrupt first */
598c2ecf20Sopenharmony_ci	writel_relaxed(RDA_TIMER_IRQ_MASK_OSTIMER,
608c2ecf20Sopenharmony_ci		       base + RDA_TIMER_IRQ_MASK_CLR);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	writel_relaxed(0, base + RDA_OSTIMER_CTRL);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	return 0;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic int rda_ostimer_set_state_shutdown(struct clock_event_device *evt)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	struct timer_of *to = to_timer_of(evt);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	rda_ostimer_stop(timer_of_base(to));
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	return 0;
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic int rda_ostimer_set_state_oneshot(struct clock_event_device *evt)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	struct timer_of *to = to_timer_of(evt);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	rda_ostimer_stop(timer_of_base(to));
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	return 0;
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic int rda_ostimer_set_state_periodic(struct clock_event_device *evt)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	struct timer_of *to = to_timer_of(evt);
888c2ecf20Sopenharmony_ci	unsigned long cycles_per_jiffy;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	rda_ostimer_stop(timer_of_base(to));
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	cycles_per_jiffy = ((unsigned long long)NSEC_PER_SEC / HZ *
938c2ecf20Sopenharmony_ci			     evt->mult) >> evt->shift;
948c2ecf20Sopenharmony_ci	rda_ostimer_start(timer_of_base(to), true, cycles_per_jiffy);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	return 0;
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic int rda_ostimer_tick_resume(struct clock_event_device *evt)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	return 0;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic int rda_ostimer_set_next_event(unsigned long evt,
1058c2ecf20Sopenharmony_ci				      struct clock_event_device *ev)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	struct timer_of *to = to_timer_of(ev);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	rda_ostimer_start(timer_of_base(to), false, evt);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	return 0;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic irqreturn_t rda_ostimer_interrupt(int irq, void *dev_id)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	struct clock_event_device *evt = dev_id;
1178c2ecf20Sopenharmony_ci	struct timer_of *to = to_timer_of(evt);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	/* clear timer int */
1208c2ecf20Sopenharmony_ci	writel_relaxed(RDA_TIMER_IRQ_CLR_OSTIMER,
1218c2ecf20Sopenharmony_ci		       timer_of_base(to) + RDA_TIMER_IRQ_CLR);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (evt->event_handler)
1248c2ecf20Sopenharmony_ci		evt->event_handler(evt);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic struct timer_of rda_ostimer_of = {
1308c2ecf20Sopenharmony_ci	.flags = TIMER_OF_IRQ | TIMER_OF_BASE,
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	.clkevt = {
1338c2ecf20Sopenharmony_ci		.name = "rda-ostimer",
1348c2ecf20Sopenharmony_ci		.rating = 250,
1358c2ecf20Sopenharmony_ci		.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
1368c2ecf20Sopenharmony_ci			    CLOCK_EVT_FEAT_DYNIRQ,
1378c2ecf20Sopenharmony_ci		.set_state_shutdown = rda_ostimer_set_state_shutdown,
1388c2ecf20Sopenharmony_ci		.set_state_oneshot = rda_ostimer_set_state_oneshot,
1398c2ecf20Sopenharmony_ci		.set_state_periodic = rda_ostimer_set_state_periodic,
1408c2ecf20Sopenharmony_ci		.tick_resume = rda_ostimer_tick_resume,
1418c2ecf20Sopenharmony_ci		.set_next_event	= rda_ostimer_set_next_event,
1428c2ecf20Sopenharmony_ci	},
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	.of_base = {
1458c2ecf20Sopenharmony_ci		.name = "rda-timer",
1468c2ecf20Sopenharmony_ci		.index = 0,
1478c2ecf20Sopenharmony_ci	},
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	.of_irq = {
1508c2ecf20Sopenharmony_ci		.name = "ostimer",
1518c2ecf20Sopenharmony_ci		.handler = rda_ostimer_interrupt,
1528c2ecf20Sopenharmony_ci		.flags = IRQF_TIMER,
1538c2ecf20Sopenharmony_ci	},
1548c2ecf20Sopenharmony_ci};
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic u64 rda_hwtimer_read(struct clocksource *cs)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	void __iomem *base = timer_of_base(&rda_ostimer_of);
1598c2ecf20Sopenharmony_ci	u32 lo, hi;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	/* Always read low 32 bits first */
1628c2ecf20Sopenharmony_ci	do {
1638c2ecf20Sopenharmony_ci		lo = readl_relaxed(base + RDA_HWTIMER_LOCKVAL_L);
1648c2ecf20Sopenharmony_ci		hi = readl_relaxed(base + RDA_HWTIMER_LOCKVAL_H);
1658c2ecf20Sopenharmony_ci	} while (hi != readl_relaxed(base + RDA_HWTIMER_LOCKVAL_H));
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	return ((u64)hi << 32) | lo;
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic struct clocksource rda_hwtimer_clocksource = {
1718c2ecf20Sopenharmony_ci	.name           = "rda-timer",
1728c2ecf20Sopenharmony_ci	.rating         = 400,
1738c2ecf20Sopenharmony_ci	.read           = rda_hwtimer_read,
1748c2ecf20Sopenharmony_ci	.mask           = CLOCKSOURCE_MASK(64),
1758c2ecf20Sopenharmony_ci	.flags          = CLOCK_SOURCE_IS_CONTINUOUS,
1768c2ecf20Sopenharmony_ci};
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic int __init rda_timer_init(struct device_node *np)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	unsigned long rate = 2000000;
1818c2ecf20Sopenharmony_ci	int ret;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	ret = timer_of_init(np, &rda_ostimer_of);
1848c2ecf20Sopenharmony_ci	if (ret)
1858c2ecf20Sopenharmony_ci		return ret;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	clocksource_register_hz(&rda_hwtimer_clocksource, rate);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	clockevents_config_and_register(&rda_ostimer_of.clkevt, rate,
1908c2ecf20Sopenharmony_ci					0x2, UINT_MAX);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	return 0;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ciTIMER_OF_DECLARE(rda8810pl, "rda,8810pl-timer", rda_timer_init);
196