1*d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22d3bc644SDaniel Lezcano /*
32d3bc644SDaniel Lezcano  * Rockchip timer support
42d3bc644SDaniel Lezcano  *
52d3bc644SDaniel Lezcano  * Copyright (C) Daniel Lezcano <[email protected]>
62d3bc644SDaniel Lezcano  */
72d3bc644SDaniel Lezcano #include <linux/clk.h>
82d3bc644SDaniel Lezcano #include <linux/clockchips.h>
92d3bc644SDaniel Lezcano #include <linux/init.h>
102d3bc644SDaniel Lezcano #include <linux/interrupt.h>
112d3bc644SDaniel Lezcano #include <linux/sched_clock.h>
122d3bc644SDaniel Lezcano #include <linux/slab.h>
132d3bc644SDaniel Lezcano #include <linux/of.h>
142d3bc644SDaniel Lezcano #include <linux/of_address.h>
152d3bc644SDaniel Lezcano #include <linux/of_irq.h>
162d3bc644SDaniel Lezcano 
172d3bc644SDaniel Lezcano #define TIMER_NAME "rk_timer"
182d3bc644SDaniel Lezcano 
192d3bc644SDaniel Lezcano #define TIMER_LOAD_COUNT0	0x00
202d3bc644SDaniel Lezcano #define TIMER_LOAD_COUNT1	0x04
212d3bc644SDaniel Lezcano #define TIMER_CURRENT_VALUE0	0x08
222d3bc644SDaniel Lezcano #define TIMER_CURRENT_VALUE1	0x0C
232d3bc644SDaniel Lezcano #define TIMER_CONTROL_REG3288	0x10
242d3bc644SDaniel Lezcano #define TIMER_CONTROL_REG3399	0x1c
252d3bc644SDaniel Lezcano #define TIMER_INT_STATUS	0x18
262d3bc644SDaniel Lezcano 
272d3bc644SDaniel Lezcano #define TIMER_DISABLE		0x0
282d3bc644SDaniel Lezcano #define TIMER_ENABLE		0x1
292d3bc644SDaniel Lezcano #define TIMER_MODE_FREE_RUNNING			(0 << 1)
302d3bc644SDaniel Lezcano #define TIMER_MODE_USER_DEFINED_COUNT		(1 << 1)
312d3bc644SDaniel Lezcano #define TIMER_INT_UNMASK			(1 << 2)
322d3bc644SDaniel Lezcano 
332d3bc644SDaniel Lezcano struct rk_timer {
342d3bc644SDaniel Lezcano 	void __iomem *base;
352d3bc644SDaniel Lezcano 	void __iomem *ctrl;
362d3bc644SDaniel Lezcano 	struct clk *clk;
372d3bc644SDaniel Lezcano 	struct clk *pclk;
382d3bc644SDaniel Lezcano 	u32 freq;
392d3bc644SDaniel Lezcano 	int irq;
402d3bc644SDaniel Lezcano };
412d3bc644SDaniel Lezcano 
422d3bc644SDaniel Lezcano struct rk_clkevt {
432d3bc644SDaniel Lezcano 	struct clock_event_device ce;
442d3bc644SDaniel Lezcano 	struct rk_timer timer;
452d3bc644SDaniel Lezcano };
462d3bc644SDaniel Lezcano 
472d3bc644SDaniel Lezcano static struct rk_clkevt *rk_clkevt;
482d3bc644SDaniel Lezcano static struct rk_timer *rk_clksrc;
492d3bc644SDaniel Lezcano 
rk_timer(struct clock_event_device * ce)502d3bc644SDaniel Lezcano static inline struct rk_timer *rk_timer(struct clock_event_device *ce)
512d3bc644SDaniel Lezcano {
522d3bc644SDaniel Lezcano 	return &container_of(ce, struct rk_clkevt, ce)->timer;
532d3bc644SDaniel Lezcano }
542d3bc644SDaniel Lezcano 
rk_timer_disable(struct rk_timer * timer)552d3bc644SDaniel Lezcano static inline void rk_timer_disable(struct rk_timer *timer)
562d3bc644SDaniel Lezcano {
572d3bc644SDaniel Lezcano 	writel_relaxed(TIMER_DISABLE, timer->ctrl);
582d3bc644SDaniel Lezcano }
592d3bc644SDaniel Lezcano 
rk_timer_enable(struct rk_timer * timer,u32 flags)602d3bc644SDaniel Lezcano static inline void rk_timer_enable(struct rk_timer *timer, u32 flags)
612d3bc644SDaniel Lezcano {
622d3bc644SDaniel Lezcano 	writel_relaxed(TIMER_ENABLE | flags, timer->ctrl);
632d3bc644SDaniel Lezcano }
642d3bc644SDaniel Lezcano 
rk_timer_update_counter(unsigned long cycles,struct rk_timer * timer)652d3bc644SDaniel Lezcano static void rk_timer_update_counter(unsigned long cycles,
662d3bc644SDaniel Lezcano 				    struct rk_timer *timer)
672d3bc644SDaniel Lezcano {
682d3bc644SDaniel Lezcano 	writel_relaxed(cycles, timer->base + TIMER_LOAD_COUNT0);
692d3bc644SDaniel Lezcano 	writel_relaxed(0, timer->base + TIMER_LOAD_COUNT1);
702d3bc644SDaniel Lezcano }
712d3bc644SDaniel Lezcano 
rk_timer_interrupt_clear(struct rk_timer * timer)722d3bc644SDaniel Lezcano static void rk_timer_interrupt_clear(struct rk_timer *timer)
732d3bc644SDaniel Lezcano {
742d3bc644SDaniel Lezcano 	writel_relaxed(1, timer->base + TIMER_INT_STATUS);
752d3bc644SDaniel Lezcano }
762d3bc644SDaniel Lezcano 
rk_timer_set_next_event(unsigned long cycles,struct clock_event_device * ce)772d3bc644SDaniel Lezcano static inline int rk_timer_set_next_event(unsigned long cycles,
782d3bc644SDaniel Lezcano 					  struct clock_event_device *ce)
792d3bc644SDaniel Lezcano {
802d3bc644SDaniel Lezcano 	struct rk_timer *timer = rk_timer(ce);
812d3bc644SDaniel Lezcano 
822d3bc644SDaniel Lezcano 	rk_timer_disable(timer);
832d3bc644SDaniel Lezcano 	rk_timer_update_counter(cycles, timer);
842d3bc644SDaniel Lezcano 	rk_timer_enable(timer, TIMER_MODE_USER_DEFINED_COUNT |
852d3bc644SDaniel Lezcano 			       TIMER_INT_UNMASK);
862d3bc644SDaniel Lezcano 	return 0;
872d3bc644SDaniel Lezcano }
882d3bc644SDaniel Lezcano 
rk_timer_shutdown(struct clock_event_device * ce)892d3bc644SDaniel Lezcano static int rk_timer_shutdown(struct clock_event_device *ce)
902d3bc644SDaniel Lezcano {
912d3bc644SDaniel Lezcano 	struct rk_timer *timer = rk_timer(ce);
922d3bc644SDaniel Lezcano 
932d3bc644SDaniel Lezcano 	rk_timer_disable(timer);
942d3bc644SDaniel Lezcano 	return 0;
952d3bc644SDaniel Lezcano }
962d3bc644SDaniel Lezcano 
rk_timer_set_periodic(struct clock_event_device * ce)972d3bc644SDaniel Lezcano static int rk_timer_set_periodic(struct clock_event_device *ce)
982d3bc644SDaniel Lezcano {
992d3bc644SDaniel Lezcano 	struct rk_timer *timer = rk_timer(ce);
1002d3bc644SDaniel Lezcano 
1012d3bc644SDaniel Lezcano 	rk_timer_disable(timer);
1022d3bc644SDaniel Lezcano 	rk_timer_update_counter(timer->freq / HZ - 1, timer);
1032d3bc644SDaniel Lezcano 	rk_timer_enable(timer, TIMER_MODE_FREE_RUNNING | TIMER_INT_UNMASK);
1042d3bc644SDaniel Lezcano 	return 0;
1052d3bc644SDaniel Lezcano }
1062d3bc644SDaniel Lezcano 
rk_timer_interrupt(int irq,void * dev_id)1072d3bc644SDaniel Lezcano static irqreturn_t rk_timer_interrupt(int irq, void *dev_id)
1082d3bc644SDaniel Lezcano {
1092d3bc644SDaniel Lezcano 	struct clock_event_device *ce = dev_id;
1102d3bc644SDaniel Lezcano 	struct rk_timer *timer = rk_timer(ce);
1112d3bc644SDaniel Lezcano 
1122d3bc644SDaniel Lezcano 	rk_timer_interrupt_clear(timer);
1132d3bc644SDaniel Lezcano 
1142d3bc644SDaniel Lezcano 	if (clockevent_state_oneshot(ce))
1152d3bc644SDaniel Lezcano 		rk_timer_disable(timer);
1162d3bc644SDaniel Lezcano 
1172d3bc644SDaniel Lezcano 	ce->event_handler(ce);
1182d3bc644SDaniel Lezcano 
1192d3bc644SDaniel Lezcano 	return IRQ_HANDLED;
1202d3bc644SDaniel Lezcano }
1212d3bc644SDaniel Lezcano 
rk_timer_sched_read(void)1222d3bc644SDaniel Lezcano static u64 notrace rk_timer_sched_read(void)
1232d3bc644SDaniel Lezcano {
1242d3bc644SDaniel Lezcano 	return ~readl_relaxed(rk_clksrc->base + TIMER_CURRENT_VALUE0);
1252d3bc644SDaniel Lezcano }
1262d3bc644SDaniel Lezcano 
1272d3bc644SDaniel Lezcano static int __init
rk_timer_probe(struct rk_timer * timer,struct device_node * np)1282d3bc644SDaniel Lezcano rk_timer_probe(struct rk_timer *timer, struct device_node *np)
1292d3bc644SDaniel Lezcano {
1302d3bc644SDaniel Lezcano 	struct clk *timer_clk;
1312d3bc644SDaniel Lezcano 	struct clk *pclk;
1322d3bc644SDaniel Lezcano 	int ret = -EINVAL, irq;
1332d3bc644SDaniel Lezcano 	u32 ctrl_reg = TIMER_CONTROL_REG3288;
1342d3bc644SDaniel Lezcano 
1352d3bc644SDaniel Lezcano 	timer->base = of_iomap(np, 0);
1362d3bc644SDaniel Lezcano 	if (!timer->base) {
1372d3bc644SDaniel Lezcano 		pr_err("Failed to get base address for '%s'\n", TIMER_NAME);
1382d3bc644SDaniel Lezcano 		return -ENXIO;
1392d3bc644SDaniel Lezcano 	}
1402d3bc644SDaniel Lezcano 
1412d3bc644SDaniel Lezcano 	if (of_device_is_compatible(np, "rockchip,rk3399-timer"))
1422d3bc644SDaniel Lezcano 		ctrl_reg = TIMER_CONTROL_REG3399;
1432d3bc644SDaniel Lezcano 
1442d3bc644SDaniel Lezcano 	timer->ctrl = timer->base + ctrl_reg;
1452d3bc644SDaniel Lezcano 
1462d3bc644SDaniel Lezcano 	pclk = of_clk_get_by_name(np, "pclk");
1472d3bc644SDaniel Lezcano 	if (IS_ERR(pclk)) {
1482d3bc644SDaniel Lezcano 		ret = PTR_ERR(pclk);
1492d3bc644SDaniel Lezcano 		pr_err("Failed to get pclk for '%s'\n", TIMER_NAME);
1502d3bc644SDaniel Lezcano 		goto out_unmap;
1512d3bc644SDaniel Lezcano 	}
1522d3bc644SDaniel Lezcano 
1532d3bc644SDaniel Lezcano 	ret = clk_prepare_enable(pclk);
1542d3bc644SDaniel Lezcano 	if (ret) {
1552d3bc644SDaniel Lezcano 		pr_err("Failed to enable pclk for '%s'\n", TIMER_NAME);
1562d3bc644SDaniel Lezcano 		goto out_unmap;
1572d3bc644SDaniel Lezcano 	}
1582d3bc644SDaniel Lezcano 	timer->pclk = pclk;
1592d3bc644SDaniel Lezcano 
1602d3bc644SDaniel Lezcano 	timer_clk = of_clk_get_by_name(np, "timer");
1612d3bc644SDaniel Lezcano 	if (IS_ERR(timer_clk)) {
1622d3bc644SDaniel Lezcano 		ret = PTR_ERR(timer_clk);
1632d3bc644SDaniel Lezcano 		pr_err("Failed to get timer clock for '%s'\n", TIMER_NAME);
1642d3bc644SDaniel Lezcano 		goto out_timer_clk;
1652d3bc644SDaniel Lezcano 	}
1662d3bc644SDaniel Lezcano 
1672d3bc644SDaniel Lezcano 	ret = clk_prepare_enable(timer_clk);
1682d3bc644SDaniel Lezcano 	if (ret) {
1692d3bc644SDaniel Lezcano 		pr_err("Failed to enable timer clock\n");
1702d3bc644SDaniel Lezcano 		goto out_timer_clk;
1712d3bc644SDaniel Lezcano 	}
1722d3bc644SDaniel Lezcano 	timer->clk = timer_clk;
1732d3bc644SDaniel Lezcano 
1742d3bc644SDaniel Lezcano 	timer->freq = clk_get_rate(timer_clk);
1752d3bc644SDaniel Lezcano 
1762d3bc644SDaniel Lezcano 	irq = irq_of_parse_and_map(np, 0);
1772d3bc644SDaniel Lezcano 	if (!irq) {
1782d3bc644SDaniel Lezcano 		ret = -EINVAL;
1792d3bc644SDaniel Lezcano 		pr_err("Failed to map interrupts for '%s'\n", TIMER_NAME);
1802d3bc644SDaniel Lezcano 		goto out_irq;
1812d3bc644SDaniel Lezcano 	}
1822d3bc644SDaniel Lezcano 	timer->irq = irq;
1832d3bc644SDaniel Lezcano 
1842d3bc644SDaniel Lezcano 	rk_timer_interrupt_clear(timer);
1852d3bc644SDaniel Lezcano 	rk_timer_disable(timer);
1862d3bc644SDaniel Lezcano 	return 0;
1872d3bc644SDaniel Lezcano 
1882d3bc644SDaniel Lezcano out_irq:
1892d3bc644SDaniel Lezcano 	clk_disable_unprepare(timer_clk);
1902d3bc644SDaniel Lezcano out_timer_clk:
1912d3bc644SDaniel Lezcano 	clk_disable_unprepare(pclk);
1922d3bc644SDaniel Lezcano out_unmap:
1932d3bc644SDaniel Lezcano 	iounmap(timer->base);
1942d3bc644SDaniel Lezcano 
1952d3bc644SDaniel Lezcano 	return ret;
1962d3bc644SDaniel Lezcano }
1972d3bc644SDaniel Lezcano 
rk_timer_cleanup(struct rk_timer * timer)1982d3bc644SDaniel Lezcano static void __init rk_timer_cleanup(struct rk_timer *timer)
1992d3bc644SDaniel Lezcano {
2002d3bc644SDaniel Lezcano 	clk_disable_unprepare(timer->clk);
2012d3bc644SDaniel Lezcano 	clk_disable_unprepare(timer->pclk);
2022d3bc644SDaniel Lezcano 	iounmap(timer->base);
2032d3bc644SDaniel Lezcano }
2042d3bc644SDaniel Lezcano 
rk_clkevt_init(struct device_node * np)2052d3bc644SDaniel Lezcano static int __init rk_clkevt_init(struct device_node *np)
2062d3bc644SDaniel Lezcano {
2072d3bc644SDaniel Lezcano 	struct clock_event_device *ce;
2082d3bc644SDaniel Lezcano 	int ret = -EINVAL;
2092d3bc644SDaniel Lezcano 
2102d3bc644SDaniel Lezcano 	rk_clkevt = kzalloc(sizeof(struct rk_clkevt), GFP_KERNEL);
2112d3bc644SDaniel Lezcano 	if (!rk_clkevt) {
2122d3bc644SDaniel Lezcano 		ret = -ENOMEM;
2132d3bc644SDaniel Lezcano 		goto out;
2142d3bc644SDaniel Lezcano 	}
2152d3bc644SDaniel Lezcano 
2162d3bc644SDaniel Lezcano 	ret = rk_timer_probe(&rk_clkevt->timer, np);
2172d3bc644SDaniel Lezcano 	if (ret)
2182d3bc644SDaniel Lezcano 		goto out_probe;
2192d3bc644SDaniel Lezcano 
2202d3bc644SDaniel Lezcano 	ce = &rk_clkevt->ce;
2212d3bc644SDaniel Lezcano 	ce->name = TIMER_NAME;
2222d3bc644SDaniel Lezcano 	ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
2232d3bc644SDaniel Lezcano 		       CLOCK_EVT_FEAT_DYNIRQ;
2242d3bc644SDaniel Lezcano 	ce->set_next_event = rk_timer_set_next_event;
2252d3bc644SDaniel Lezcano 	ce->set_state_shutdown = rk_timer_shutdown;
2262d3bc644SDaniel Lezcano 	ce->set_state_periodic = rk_timer_set_periodic;
2272d3bc644SDaniel Lezcano 	ce->irq = rk_clkevt->timer.irq;
2282d3bc644SDaniel Lezcano 	ce->cpumask = cpu_possible_mask;
2292d3bc644SDaniel Lezcano 	ce->rating = 250;
2302d3bc644SDaniel Lezcano 
2312d3bc644SDaniel Lezcano 	ret = request_irq(rk_clkevt->timer.irq, rk_timer_interrupt, IRQF_TIMER,
2322d3bc644SDaniel Lezcano 			  TIMER_NAME, ce);
2332d3bc644SDaniel Lezcano 	if (ret) {
2342d3bc644SDaniel Lezcano 		pr_err("Failed to initialize '%s': %d\n",
2352d3bc644SDaniel Lezcano 			TIMER_NAME, ret);
2362d3bc644SDaniel Lezcano 		goto out_irq;
2372d3bc644SDaniel Lezcano 	}
2382d3bc644SDaniel Lezcano 
2392d3bc644SDaniel Lezcano 	clockevents_config_and_register(&rk_clkevt->ce,
2402d3bc644SDaniel Lezcano 					rk_clkevt->timer.freq, 1, UINT_MAX);
2412d3bc644SDaniel Lezcano 	return 0;
2422d3bc644SDaniel Lezcano 
2432d3bc644SDaniel Lezcano out_irq:
2442d3bc644SDaniel Lezcano 	rk_timer_cleanup(&rk_clkevt->timer);
2452d3bc644SDaniel Lezcano out_probe:
2462d3bc644SDaniel Lezcano 	kfree(rk_clkevt);
2472d3bc644SDaniel Lezcano out:
2482d3bc644SDaniel Lezcano 	/* Leave rk_clkevt not NULL to prevent future init */
2492d3bc644SDaniel Lezcano 	rk_clkevt = ERR_PTR(ret);
2502d3bc644SDaniel Lezcano 	return ret;
2512d3bc644SDaniel Lezcano }
2522d3bc644SDaniel Lezcano 
rk_clksrc_init(struct device_node * np)2532d3bc644SDaniel Lezcano static int __init rk_clksrc_init(struct device_node *np)
2542d3bc644SDaniel Lezcano {
2552d3bc644SDaniel Lezcano 	int ret = -EINVAL;
2562d3bc644SDaniel Lezcano 
2572d3bc644SDaniel Lezcano 	rk_clksrc = kzalloc(sizeof(struct rk_timer), GFP_KERNEL);
2582d3bc644SDaniel Lezcano 	if (!rk_clksrc) {
2592d3bc644SDaniel Lezcano 		ret = -ENOMEM;
2602d3bc644SDaniel Lezcano 		goto out;
2612d3bc644SDaniel Lezcano 	}
2622d3bc644SDaniel Lezcano 
2632d3bc644SDaniel Lezcano 	ret = rk_timer_probe(rk_clksrc, np);
2642d3bc644SDaniel Lezcano 	if (ret)
2652d3bc644SDaniel Lezcano 		goto out_probe;
2662d3bc644SDaniel Lezcano 
2672d3bc644SDaniel Lezcano 	rk_timer_update_counter(UINT_MAX, rk_clksrc);
2682d3bc644SDaniel Lezcano 	rk_timer_enable(rk_clksrc, 0);
2692d3bc644SDaniel Lezcano 
2702d3bc644SDaniel Lezcano 	ret = clocksource_mmio_init(rk_clksrc->base + TIMER_CURRENT_VALUE0,
2712d3bc644SDaniel Lezcano 		TIMER_NAME, rk_clksrc->freq, 250, 32,
2722d3bc644SDaniel Lezcano 		clocksource_mmio_readl_down);
2732d3bc644SDaniel Lezcano 	if (ret) {
2742d3bc644SDaniel Lezcano 		pr_err("Failed to register clocksource\n");
2752d3bc644SDaniel Lezcano 		goto out_clocksource;
2762d3bc644SDaniel Lezcano 	}
2772d3bc644SDaniel Lezcano 
2782d3bc644SDaniel Lezcano 	sched_clock_register(rk_timer_sched_read, 32, rk_clksrc->freq);
2792d3bc644SDaniel Lezcano 	return 0;
2802d3bc644SDaniel Lezcano 
2812d3bc644SDaniel Lezcano out_clocksource:
2822d3bc644SDaniel Lezcano 	rk_timer_cleanup(rk_clksrc);
2832d3bc644SDaniel Lezcano out_probe:
2842d3bc644SDaniel Lezcano 	kfree(rk_clksrc);
2852d3bc644SDaniel Lezcano out:
2862d3bc644SDaniel Lezcano 	/* Leave rk_clksrc not NULL to prevent future init */
2872d3bc644SDaniel Lezcano 	rk_clksrc = ERR_PTR(ret);
2882d3bc644SDaniel Lezcano 	return ret;
2892d3bc644SDaniel Lezcano }
2902d3bc644SDaniel Lezcano 
rk_timer_init(struct device_node * np)2912d3bc644SDaniel Lezcano static int __init rk_timer_init(struct device_node *np)
2922d3bc644SDaniel Lezcano {
2932d3bc644SDaniel Lezcano 	if (!rk_clkevt)
2942d3bc644SDaniel Lezcano 		return rk_clkevt_init(np);
2952d3bc644SDaniel Lezcano 
2962d3bc644SDaniel Lezcano 	if (!rk_clksrc)
2972d3bc644SDaniel Lezcano 		return rk_clksrc_init(np);
2982d3bc644SDaniel Lezcano 
2992d3bc644SDaniel Lezcano 	pr_err("Too many timer definitions for '%s'\n", TIMER_NAME);
3002d3bc644SDaniel Lezcano 	return -EINVAL;
3012d3bc644SDaniel Lezcano }
3022d3bc644SDaniel Lezcano 
3032d3bc644SDaniel Lezcano TIMER_OF_DECLARE(rk3288_timer, "rockchip,rk3288-timer", rk_timer_init);
3042d3bc644SDaniel Lezcano TIMER_OF_DECLARE(rk3399_timer, "rockchip,rk3399-timer", rk_timer_init);
305