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