Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484// SPDX-License-Identifier: GPL-2.0/* * RZ/N1 timers driver * * Copyright (C) 2026 Schneider-Electric * * Author: Herve Codina <herve.codina@bootlin.com> */
#include <linux/bits.h>#include <linux/clk.h>#include <linux/clockchips.h>#include <linux/clocksource.h>#include <linux/cpuhotplug.h>#include <linux/interrupt.h>#include <linux/of.h>#include <linux/platform_device.h>#include <linux/sched_clock.h>
/* Per-timer register offsets */#define RZN1_TIMER_LOAD_COUNT_REG 0x00#define RZN1_TIMER_CURRENT_COUNT_REG 0x04#define RZN1_TIMER_CONTROL_REG 0x08#define RZN1_TIMER_CONTROL_INT_UNMASK BIT(3)#define RZN1_TIMER_CONTROL_ENABLE BIT(2)#define RZN1_TIMER_CONTROL_AUTORELOAD BIT(1)#define RZN1_TIMER_CONTROL_PRESCALER_DIV25 BIT(0)#define RZN1_TIMER_CLEAR_INT_REG 0x0c#define RZN1_TIMER_STATUS_INT0_REG 0x10#define RZN1_TIMER_STATUS_INT1_REG 0x14
/* * 8 timers are available. Among those 8 timers, the first 6 timers are 16-bit * timers and the last two ones are 32-bit timers. */#define RZN1_TIMER_BASE_INDEX_16BIT_TIMERS 0#define RZN1_TIMER_NB_16BIT_TIMERS 6#define RZN1_TIMER_LAST_INDEX_16BIT_TIMERS (RZN1_TIMER_BASE_INDEX_16BIT_TIMERS + \ RZN1_TIMER_NB_16BIT_TIMERS - 1)
#define RZN1_TIMER_BASE_INDEX_32BIT_TIMERS 6#define RZN1_TIMER_NB_32BIT_TIMERS 2#define RZN1_TIMER_LAST_INDEX_32BIT_TIMERS (RZN1_TIMER_BASE_INDEX_32BIT_TIMERS + \ RZN1_TIMER_NB_32BIT_TIMERS - 1)
#define RZN1_TIMER_IS_16BIT_TIMER(_i) ((_i) < RZN1_TIMER_BASE_INDEX_32BIT_TIMERS)
/* Total numbers of timers */#define RZN1_TIMER_NB_TIMERS (RZN1_TIMER_NB_16BIT_TIMERS + \ RZN1_TIMER_NB_32BIT_TIMERS)
/* Offset of registers related to the timer number _i in the timers regs area */#define RZN1_TIMER_REGS_OFFSET(_i) (0x20 * (_i))
struct rzn1_timer { void __iomem *base; unsigned int width; unsigned long rate; unsigned long hz_period; struct clock_event_device ced;};
static int rzn1_timer_config(struct rzn1_timer *timer, u32 period, bool is_periodic){ u32 ctrl;
ctrl = readl(timer->base + RZN1_TIMER_CONTROL_REG);
/* Disable the timer */ writel(ctrl & ~RZN1_TIMER_CONTROL_ENABLE, timer->base + RZN1_TIMER_CONTROL_REG);
/* Set the new period */ writel(period, timer->base + RZN1_TIMER_LOAD_COUNT_REG);
/* Prepare the timer mode */ if (is_periodic) ctrl |= RZN1_TIMER_CONTROL_AUTORELOAD; else ctrl &= ~RZN1_TIMER_CONTROL_AUTORELOAD;
/* * Enable the timer. * * This automatically resets the CURRENT_COUNT register. */ ctrl |= RZN1_TIMER_CONTROL_ENABLE; writel(ctrl, timer->base + RZN1_TIMER_CONTROL_REG);
return 0;}
static void rzn1_timer_disable(struct rzn1_timer *timer){ u32 ctrl;
ctrl = readl(timer->base + RZN1_TIMER_CONTROL_REG); ctrl &= ~RZN1_TIMER_CONTROL_ENABLE; writel(ctrl, timer->base + RZN1_TIMER_CONTROL_REG);}
static void rzn1_timer_int_enable(struct rzn1_timer *timer){ u32 ctrl;
ctrl = readl(timer->base + RZN1_TIMER_CONTROL_REG); ctrl |= RZN1_TIMER_CONTROL_INT_UNMASK; writel(ctrl, timer->base + RZN1_TIMER_CONTROL_REG);}
static irqreturn_t rzn1_timer_interrupt(int irq, void *dev_id){ struct rzn1_timer *timer = dev_id;
/* Ack the interrupt */ readl(timer->base + RZN1_TIMER_CLEAR_INT_REG);
if (timer->ced.event_handler) timer->ced.event_handler(&timer->ced);
return IRQ_HANDLED;}
static int rzn1_clkevt_set_next_event(unsigned long cycles, struct clock_event_device *evt){ struct rzn1_timer *timer = container_of(evt, struct rzn1_timer, ced);
return rzn1_timer_config(timer, cycles, false);}
static int rzn1_clkevt_shutdown(struct clock_event_device *evt){ struct rzn1_timer *timer = container_of(evt, struct rzn1_timer, ced);
rzn1_timer_disable(timer); return 0;}
static int rzn1_clkevt_set_periodic(struct clock_event_device *evt){ struct rzn1_timer *timer = container_of(evt, struct rzn1_timer, ced);
rzn1_timer_config(timer, timer->hz_period, true); return 0;}
/* * This global lock is used to prevent race conditions during global timers * test and set operation in case the driver is using the async probe option. */static DEFINE_MUTEX(rzn1_global_timers_lock);
static int rzn1_timer_instance;
/* scheduler and clocksource */static struct rzn1_timer *rzn1_sched_clock;
static u64 notrace rzn1_sched_read(void){ return readl_relaxed(rzn1_sched_clock->base + RZN1_TIMER_CURRENT_COUNT_REG);}
static u64 rzn1_clksrc_read(struct clocksource *cs){ return readl_relaxed(rzn1_sched_clock->base + RZN1_TIMER_CURRENT_COUNT_REG);}
static struct clocksource rzn1_clocksource = { .name = "rzn1_timer_clocksource", .rating = 200, .flags = CLOCK_SOURCE_IS_CONTINUOUS, .read = rzn1_clksrc_read,};
/* Timers table where 16-bit timers will be assigned per-cpu */static struct rzn1_timer *rzn1_tab_timers;
static int rzn1_local_timer_starting_cpu(unsigned int cpu){ struct rzn1_timer *timer;
/* We assign the first and second 16-bit timer as per-cpu timers. */ if (cpu >= 2) return 0;
timer = &rzn1_tab_timers[cpu + RZN1_TIMER_BASE_INDEX_16BIT_TIMERS];
timer->ced.cpumask = cpumask_of(cpu); irq_force_affinity(timer->ced.irq, cpumask_of(cpu));
clockevents_config_and_register(&timer->ced, timer->rate, 1, GENMASK(timer->width - 1, 0)); /* * Time to enable the interrupt even if no interrupt can be fired yet. * Indeed, the timer is still globally disabled. * It will be enabled when rzn1_timer_config() is called */ enable_irq(timer->ced.irq); return 0;}
static int rzn1_local_timer_dying_cpu(unsigned int cpu){ struct rzn1_timer *timer;
if (cpu >= 2) return 0;
timer = &rzn1_tab_timers[cpu + RZN1_TIMER_BASE_INDEX_16BIT_TIMERS];
rzn1_timer_disable(timer); disable_irq_nosync(timer->ced.irq); return 0;}
static void rzn1_timer_init(struct rzn1_timer *timer, unsigned int index, void __iomem *timers_base, unsigned long clock_rate){ timer->base = timers_base + RZN1_TIMER_REGS_OFFSET(index);
/* Disable the timer */ writel(0, timer->base + RZN1_TIMER_CONTROL_REG);
/* Clear potential interrupts */ readl(timer->base + RZN1_TIMER_CLEAR_INT_REG);
if (RZN1_TIMER_IS_16BIT_TIMER(index)) { timer->width = 16; /* * Enable pre-scaler for 16-bit timers. * * Timers are fed by a 25MHz clock. With this pre-scaler (1/25) * enabled, the 16-bit timers resolution is 1 microsecond. */ writel(RZN1_TIMER_CONTROL_PRESCALER_DIV25, timer->base + RZN1_TIMER_CONTROL_REG); timer->rate = clock_rate / 25; } else { timer->width = 32; timer->rate = clock_rate; } timer->hz_period = DIV_ROUND_UP(timer->rate, HZ);}
static void rzn1_timer_clkevt_init_ced(struct rzn1_timer *timer, const char *name, int irq){ timer->ced.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; timer->ced.set_next_event = rzn1_clkevt_set_next_event; timer->ced.set_state_shutdown = rzn1_clkevt_shutdown; timer->ced.set_state_periodic = rzn1_clkevt_set_periodic; timer->ced.cpumask = cpu_possible_mask;
/* * 32-bit timers are fed with a 25 MHz clock directly derived from the * main PLL (1 GHz). The arch timer, ARMv7 CP15 in RZ/N1 SoCs, is fed * with to a 6.25 MHz clock. * * The clock of the RZ/N1 timers block is a stable one and the RZ/N1 * timers have a higher resolution than the ARM CP15 one. * * Use a high rating for the 32-bit RZ/N1 timers. */ timer->ced.rating = timer->width == 16 ? 200 : 460; timer->ced.owner = THIS_MODULE; timer->ced.name = name; timer->ced.irq = irq;}
static int rzn1_timer_setup_timers(struct platform_device *pdev, struct rzn1_timer *tab_timers, unsigned int first_timer_index, unsigned int last_timer_index, void __iomem *base, unsigned long clock_rate){ struct device *dev = &pdev->dev; struct rzn1_timer *timer; unsigned int i; char *name; int irq; int ret;
for (i = first_timer_index; i <= last_timer_index; i++) { timer = &tab_timers[i];
rzn1_timer_init(timer, i, base, clock_rate);
irq = platform_get_irq(pdev, i); if (irq < 0) return irq;
name = devm_kasprintf(dev, GFP_KERNEL, "%s-%u", dev_name(dev), i); if (!name) return -ENOMEM;
rzn1_timer_clkevt_init_ced(timer, name, irq);
ret = devm_request_irq(dev, timer->ced.irq, rzn1_timer_interrupt, IRQF_TIMER | IRQF_NO_AUTOEN, timer->ced.name, timer); if (ret < 0) return dev_err_probe(dev, ret, "timer%u: Failed to request IRQ\n", i);
rzn1_timer_int_enable(timer); } return 0;}
static void rzn1_timer_register_clkevt(struct rzn1_timer *tab_timers, unsigned int first_timer_index, unsigned int last_timer_index){ struct rzn1_timer *timer; unsigned int i;
for (i = first_timer_index; i <= last_timer_index; i++) { timer = &tab_timers[i]; clockevents_config_and_register(&timer->ced, timer->rate, 1, GENMASK(timer->width - 1, 0)); /* * Time to enable the interrupt even if no interrupt can be * fired yet. Indeed, the timer is still globally disabled. * It will be enabled when rzn1_timer_config() is called */ enable_irq(timer->ced.irq); }}
static int rzn1_timer_probe_first(struct platform_device *pdev, struct rzn1_timer *tab_timers, void __iomem *base, unsigned long clock_rate){ struct device *dev = &pdev->dev; struct rzn1_timer *timer; int ret;
/* * Each timer instance has 6 x 16-bit timers and 2 x 32-bit timers. * * Probe the first instance. In that case, timers are assigned as * follow: * - First and second 16-bit timers: clock events per CPU * - Last (second one) 32-bit timer: clocksource and sched_clock * - Other timers: clock events for all possible CPUs * * First step, perform all operation that could fail without calling * clockevents_config_and_register(), sched_clock_register() nor * cpuhp_setup_state(). Those operation don't have unregister nor * teardown counterparts and so, once called, we cannot remove the * related resource. */
/* First step for 16-bit timers and the first 32-bit timers. */ ret = rzn1_timer_setup_timers(pdev, tab_timers, RZN1_TIMER_BASE_INDEX_16BIT_TIMERS, RZN1_TIMER_BASE_INDEX_32BIT_TIMERS, base, clock_rate); if (ret) return ret;
/* * Second step, almost all operations that can fail have been called. * Timers are ready to work. Start with the last operation that can fail, * installing and invoking hotplug callbacks */ rzn1_tab_timers = tab_timers; ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "clockevents/rzn1/global_timer:starting", rzn1_local_timer_starting_cpu, rzn1_local_timer_dying_cpu); if (ret < 0) return dev_err_probe(dev, ret, "Setup CPU hotplug state failed\n");
/* * At this point, no more operations can fail. Perform remaining * operations. Starting by handling the last (second one) 32-bit timer */ timer = &tab_timers[RZN1_TIMER_LAST_INDEX_32BIT_TIMERS];
rzn1_timer_init(timer, RZN1_TIMER_LAST_INDEX_32BIT_TIMERS, base, clock_rate); rzn1_timer_config(timer, GENMASK(timer->width - 1, 0), true);
rzn1_sched_clock = timer;
sched_clock_register(rzn1_sched_read, rzn1_sched_clock->width, rzn1_sched_clock->rate);
rzn1_clocksource.mask = CLOCKSOURCE_MASK(rzn1_sched_clock->width); clocksource_register_hz(&rzn1_clocksource, rzn1_sched_clock->rate);
/* * Register clockevents for 16-bit timers (except the first and second * ones) and for the first 32-bit timer. The first and second 16-bit * timers clockevents are registered by CPU hotplug startup function set * previously by the cpuhp_setup_state() call. */ rzn1_timer_register_clkevt(tab_timers, RZN1_TIMER_BASE_INDEX_16BIT_TIMERS + 2, RZN1_TIMER_BASE_INDEX_32BIT_TIMERS);
return 0;}
static int rzn1_timer_probe_other(struct platform_device *pdev, struct rzn1_timer *tab_timers, void __iomem *base, unsigned long clock_rate){ int ret;
/* * Probe other instance(s), i.e. not the first one. In that case, * all timers are used as clock events and available for all possible * CPUs * * First step, perform all operation that could fail without calling * clockevents_config_and_register(). Unregister counterpart does not * exist and so, once called, we cannot remove the related resource. */ ret = rzn1_timer_setup_timers(pdev, tab_timers, RZN1_TIMER_BASE_INDEX_16BIT_TIMERS, RZN1_TIMER_LAST_INDEX_32BIT_TIMERS, base, clock_rate); if (ret) return ret;
/* * Second step, all operation that can fail have been called. We can * register our timers. */ rzn1_timer_register_clkevt(tab_timers, RZN1_TIMER_BASE_INDEX_16BIT_TIMERS, RZN1_TIMER_LAST_INDEX_32BIT_TIMERS); return 0;}
static int rzn1_timer_probe(struct platform_device *pdev){ struct device *dev = &pdev->dev; struct rzn1_timer *tab_timers; unsigned long clock_rate; void __iomem *base; struct clk *clk; int ret;
tab_timers = devm_kcalloc(dev, RZN1_TIMER_NB_TIMERS, sizeof(*tab_timers), GFP_KERNEL); if (!tab_timers) return -ENOMEM;
base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base);
clk = devm_clk_get_enabled(dev, "pclk"); if (IS_ERR(clk)) return dev_err_probe(dev, PTR_ERR(clk), "Failed to get pclk\n");
clock_rate = clk_get_rate(clk);
scoped_guard(mutex, &rzn1_global_timers_lock) { ret = !rzn1_timer_instance ? rzn1_timer_probe_first(pdev, tab_timers, base, clock_rate) : rzn1_timer_probe_other(pdev, tab_timers, base, clock_rate); if (!ret) rzn1_timer_instance++; }
return ret;}
static const struct of_device_id rzn1_timer_of_match[] = { { .compatible = "renesas,rzn1-timer", }, { /* sentinel */ }};
static struct platform_driver rzn1_timer_driver = { .driver = { .name = "rzn1_timer", .of_match_table = rzn1_timer_of_match, .suppress_bind_attrs = true, },};builtin_platform_driver_probe(rzn1_timer_driver, rzn1_timer_probe);