162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Rockchip timer support 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) Daniel Lezcano <daniel.lezcano@linaro.org> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include <linux/clk.h> 862306a36Sopenharmony_ci#include <linux/clockchips.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/interrupt.h> 1162306a36Sopenharmony_ci#include <linux/sched_clock.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <linux/of.h> 1462306a36Sopenharmony_ci#include <linux/of_address.h> 1562306a36Sopenharmony_ci#include <linux/of_irq.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define TIMER_NAME "rk_timer" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define TIMER_LOAD_COUNT0 0x00 2062306a36Sopenharmony_ci#define TIMER_LOAD_COUNT1 0x04 2162306a36Sopenharmony_ci#define TIMER_CURRENT_VALUE0 0x08 2262306a36Sopenharmony_ci#define TIMER_CURRENT_VALUE1 0x0C 2362306a36Sopenharmony_ci#define TIMER_CONTROL_REG3288 0x10 2462306a36Sopenharmony_ci#define TIMER_CONTROL_REG3399 0x1c 2562306a36Sopenharmony_ci#define TIMER_INT_STATUS 0x18 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define TIMER_DISABLE 0x0 2862306a36Sopenharmony_ci#define TIMER_ENABLE 0x1 2962306a36Sopenharmony_ci#define TIMER_MODE_FREE_RUNNING (0 << 1) 3062306a36Sopenharmony_ci#define TIMER_MODE_USER_DEFINED_COUNT (1 << 1) 3162306a36Sopenharmony_ci#define TIMER_INT_UNMASK (1 << 2) 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistruct rk_timer { 3462306a36Sopenharmony_ci void __iomem *base; 3562306a36Sopenharmony_ci void __iomem *ctrl; 3662306a36Sopenharmony_ci struct clk *clk; 3762306a36Sopenharmony_ci struct clk *pclk; 3862306a36Sopenharmony_ci u32 freq; 3962306a36Sopenharmony_ci int irq; 4062306a36Sopenharmony_ci}; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistruct rk_clkevt { 4362306a36Sopenharmony_ci struct clock_event_device ce; 4462306a36Sopenharmony_ci struct rk_timer timer; 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic struct rk_clkevt *rk_clkevt; 4862306a36Sopenharmony_cistatic struct rk_timer *rk_clksrc; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic inline struct rk_timer *rk_timer(struct clock_event_device *ce) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci return &container_of(ce, struct rk_clkevt, ce)->timer; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic inline void rk_timer_disable(struct rk_timer *timer) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci writel_relaxed(TIMER_DISABLE, timer->ctrl); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic inline void rk_timer_enable(struct rk_timer *timer, u32 flags) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci writel_relaxed(TIMER_ENABLE | flags, timer->ctrl); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic void rk_timer_update_counter(unsigned long cycles, 6662306a36Sopenharmony_ci struct rk_timer *timer) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci writel_relaxed(cycles, timer->base + TIMER_LOAD_COUNT0); 6962306a36Sopenharmony_ci writel_relaxed(0, timer->base + TIMER_LOAD_COUNT1); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic void rk_timer_interrupt_clear(struct rk_timer *timer) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci writel_relaxed(1, timer->base + TIMER_INT_STATUS); 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic inline int rk_timer_set_next_event(unsigned long cycles, 7862306a36Sopenharmony_ci struct clock_event_device *ce) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci struct rk_timer *timer = rk_timer(ce); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci rk_timer_disable(timer); 8362306a36Sopenharmony_ci rk_timer_update_counter(cycles, timer); 8462306a36Sopenharmony_ci rk_timer_enable(timer, TIMER_MODE_USER_DEFINED_COUNT | 8562306a36Sopenharmony_ci TIMER_INT_UNMASK); 8662306a36Sopenharmony_ci return 0; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic int rk_timer_shutdown(struct clock_event_device *ce) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct rk_timer *timer = rk_timer(ce); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci rk_timer_disable(timer); 9462306a36Sopenharmony_ci return 0; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic int rk_timer_set_periodic(struct clock_event_device *ce) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct rk_timer *timer = rk_timer(ce); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci rk_timer_disable(timer); 10262306a36Sopenharmony_ci rk_timer_update_counter(timer->freq / HZ - 1, timer); 10362306a36Sopenharmony_ci rk_timer_enable(timer, TIMER_MODE_FREE_RUNNING | TIMER_INT_UNMASK); 10462306a36Sopenharmony_ci return 0; 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic irqreturn_t rk_timer_interrupt(int irq, void *dev_id) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci struct clock_event_device *ce = dev_id; 11062306a36Sopenharmony_ci struct rk_timer *timer = rk_timer(ce); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci rk_timer_interrupt_clear(timer); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (clockevent_state_oneshot(ce)) 11562306a36Sopenharmony_ci rk_timer_disable(timer); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci ce->event_handler(ce); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return IRQ_HANDLED; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic u64 notrace rk_timer_sched_read(void) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci return ~readl_relaxed(rk_clksrc->base + TIMER_CURRENT_VALUE0); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic int __init 12862306a36Sopenharmony_cirk_timer_probe(struct rk_timer *timer, struct device_node *np) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct clk *timer_clk; 13162306a36Sopenharmony_ci struct clk *pclk; 13262306a36Sopenharmony_ci int ret = -EINVAL, irq; 13362306a36Sopenharmony_ci u32 ctrl_reg = TIMER_CONTROL_REG3288; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci timer->base = of_iomap(np, 0); 13662306a36Sopenharmony_ci if (!timer->base) { 13762306a36Sopenharmony_ci pr_err("Failed to get base address for '%s'\n", TIMER_NAME); 13862306a36Sopenharmony_ci return -ENXIO; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (of_device_is_compatible(np, "rockchip,rk3399-timer")) 14262306a36Sopenharmony_ci ctrl_reg = TIMER_CONTROL_REG3399; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci timer->ctrl = timer->base + ctrl_reg; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci pclk = of_clk_get_by_name(np, "pclk"); 14762306a36Sopenharmony_ci if (IS_ERR(pclk)) { 14862306a36Sopenharmony_ci ret = PTR_ERR(pclk); 14962306a36Sopenharmony_ci pr_err("Failed to get pclk for '%s'\n", TIMER_NAME); 15062306a36Sopenharmony_ci goto out_unmap; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci ret = clk_prepare_enable(pclk); 15462306a36Sopenharmony_ci if (ret) { 15562306a36Sopenharmony_ci pr_err("Failed to enable pclk for '%s'\n", TIMER_NAME); 15662306a36Sopenharmony_ci goto out_unmap; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci timer->pclk = pclk; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci timer_clk = of_clk_get_by_name(np, "timer"); 16162306a36Sopenharmony_ci if (IS_ERR(timer_clk)) { 16262306a36Sopenharmony_ci ret = PTR_ERR(timer_clk); 16362306a36Sopenharmony_ci pr_err("Failed to get timer clock for '%s'\n", TIMER_NAME); 16462306a36Sopenharmony_ci goto out_timer_clk; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci ret = clk_prepare_enable(timer_clk); 16862306a36Sopenharmony_ci if (ret) { 16962306a36Sopenharmony_ci pr_err("Failed to enable timer clock\n"); 17062306a36Sopenharmony_ci goto out_timer_clk; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci timer->clk = timer_clk; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci timer->freq = clk_get_rate(timer_clk); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci irq = irq_of_parse_and_map(np, 0); 17762306a36Sopenharmony_ci if (!irq) { 17862306a36Sopenharmony_ci ret = -EINVAL; 17962306a36Sopenharmony_ci pr_err("Failed to map interrupts for '%s'\n", TIMER_NAME); 18062306a36Sopenharmony_ci goto out_irq; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci timer->irq = irq; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci rk_timer_interrupt_clear(timer); 18562306a36Sopenharmony_ci rk_timer_disable(timer); 18662306a36Sopenharmony_ci return 0; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ciout_irq: 18962306a36Sopenharmony_ci clk_disable_unprepare(timer_clk); 19062306a36Sopenharmony_ciout_timer_clk: 19162306a36Sopenharmony_ci clk_disable_unprepare(pclk); 19262306a36Sopenharmony_ciout_unmap: 19362306a36Sopenharmony_ci iounmap(timer->base); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci return ret; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic void __init rk_timer_cleanup(struct rk_timer *timer) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci clk_disable_unprepare(timer->clk); 20162306a36Sopenharmony_ci clk_disable_unprepare(timer->pclk); 20262306a36Sopenharmony_ci iounmap(timer->base); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic int __init rk_clkevt_init(struct device_node *np) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci struct clock_event_device *ce; 20862306a36Sopenharmony_ci int ret = -EINVAL; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci rk_clkevt = kzalloc(sizeof(struct rk_clkevt), GFP_KERNEL); 21162306a36Sopenharmony_ci if (!rk_clkevt) { 21262306a36Sopenharmony_ci ret = -ENOMEM; 21362306a36Sopenharmony_ci goto out; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci ret = rk_timer_probe(&rk_clkevt->timer, np); 21762306a36Sopenharmony_ci if (ret) 21862306a36Sopenharmony_ci goto out_probe; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci ce = &rk_clkevt->ce; 22162306a36Sopenharmony_ci ce->name = TIMER_NAME; 22262306a36Sopenharmony_ci ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | 22362306a36Sopenharmony_ci CLOCK_EVT_FEAT_DYNIRQ; 22462306a36Sopenharmony_ci ce->set_next_event = rk_timer_set_next_event; 22562306a36Sopenharmony_ci ce->set_state_shutdown = rk_timer_shutdown; 22662306a36Sopenharmony_ci ce->set_state_periodic = rk_timer_set_periodic; 22762306a36Sopenharmony_ci ce->irq = rk_clkevt->timer.irq; 22862306a36Sopenharmony_ci ce->cpumask = cpu_possible_mask; 22962306a36Sopenharmony_ci ce->rating = 250; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci ret = request_irq(rk_clkevt->timer.irq, rk_timer_interrupt, IRQF_TIMER, 23262306a36Sopenharmony_ci TIMER_NAME, ce); 23362306a36Sopenharmony_ci if (ret) { 23462306a36Sopenharmony_ci pr_err("Failed to initialize '%s': %d\n", 23562306a36Sopenharmony_ci TIMER_NAME, ret); 23662306a36Sopenharmony_ci goto out_irq; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci clockevents_config_and_register(&rk_clkevt->ce, 24062306a36Sopenharmony_ci rk_clkevt->timer.freq, 1, UINT_MAX); 24162306a36Sopenharmony_ci return 0; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ciout_irq: 24462306a36Sopenharmony_ci rk_timer_cleanup(&rk_clkevt->timer); 24562306a36Sopenharmony_ciout_probe: 24662306a36Sopenharmony_ci kfree(rk_clkevt); 24762306a36Sopenharmony_ciout: 24862306a36Sopenharmony_ci /* Leave rk_clkevt not NULL to prevent future init */ 24962306a36Sopenharmony_ci rk_clkevt = ERR_PTR(ret); 25062306a36Sopenharmony_ci return ret; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic int __init rk_clksrc_init(struct device_node *np) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci int ret = -EINVAL; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci rk_clksrc = kzalloc(sizeof(struct rk_timer), GFP_KERNEL); 25862306a36Sopenharmony_ci if (!rk_clksrc) { 25962306a36Sopenharmony_ci ret = -ENOMEM; 26062306a36Sopenharmony_ci goto out; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci ret = rk_timer_probe(rk_clksrc, np); 26462306a36Sopenharmony_ci if (ret) 26562306a36Sopenharmony_ci goto out_probe; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci rk_timer_update_counter(UINT_MAX, rk_clksrc); 26862306a36Sopenharmony_ci rk_timer_enable(rk_clksrc, 0); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci ret = clocksource_mmio_init(rk_clksrc->base + TIMER_CURRENT_VALUE0, 27162306a36Sopenharmony_ci TIMER_NAME, rk_clksrc->freq, 250, 32, 27262306a36Sopenharmony_ci clocksource_mmio_readl_down); 27362306a36Sopenharmony_ci if (ret) { 27462306a36Sopenharmony_ci pr_err("Failed to register clocksource\n"); 27562306a36Sopenharmony_ci goto out_clocksource; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci sched_clock_register(rk_timer_sched_read, 32, rk_clksrc->freq); 27962306a36Sopenharmony_ci return 0; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ciout_clocksource: 28262306a36Sopenharmony_ci rk_timer_cleanup(rk_clksrc); 28362306a36Sopenharmony_ciout_probe: 28462306a36Sopenharmony_ci kfree(rk_clksrc); 28562306a36Sopenharmony_ciout: 28662306a36Sopenharmony_ci /* Leave rk_clksrc not NULL to prevent future init */ 28762306a36Sopenharmony_ci rk_clksrc = ERR_PTR(ret); 28862306a36Sopenharmony_ci return ret; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic int __init rk_timer_init(struct device_node *np) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci if (!rk_clkevt) 29462306a36Sopenharmony_ci return rk_clkevt_init(np); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (!rk_clksrc) 29762306a36Sopenharmony_ci return rk_clksrc_init(np); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci pr_err("Too many timer definitions for '%s'\n", TIMER_NAME); 30062306a36Sopenharmony_ci return -EINVAL; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ciTIMER_OF_DECLARE(rk3288_timer, "rockchip,rk3288-timer", rk_timer_init); 30462306a36Sopenharmony_ciTIMER_OF_DECLARE(rk3399_timer, "rockchip,rk3399-timer", rk_timer_init); 305