clocksource/drivers/vf-pit: Set the scene for multiple timers
authorDaniel Lezcano <daniel.lezcano@linaro.org>
Mon, 4 Aug 2025 15:23:21 +0000 (17:23 +0200)
committerDaniel Lezcano <daniel.lezcano@linaro.org>
Tue, 23 Sep 2025 10:28:32 +0000 (12:28 +0200)
The driver is implemented as using a single timer and a single
clocksource. In order to take advantage of the multiple timers
supported in the PIT hardware and introduce different setup for a new
platform, let's encapsulate the data into a structure and pass this
structure around in the function parameter. The structure will be a
per timer instansiation in the next changes.

Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Link: https://lore.kernel.org/r/20250804152344.1109310-4-daniel.lezcano@linaro.org
drivers/clocksource/timer-vf-pit.c

index 8041a8f..e4a8b32 100644 (file)
@@ -15,7 +15,7 @@
  */
 #define PITMCR         0x00
 #define PIT0_OFFSET    0x100
-#define PITn_OFFSET(n) (PIT0_OFFSET + 0x10 * (n))
+#define PIT_CH(n)       (PIT0_OFFSET + 0x10 * (n))
 #define PITLDVAL       0x00
 #define PITCVAL                0x04
 #define PITTCTRL       0x08
 
 #define PITTFLG_TIF    0x1
 
+struct pit_timer {
+       void __iomem *clksrc_base;
+       void __iomem *clkevt_base;
+       unsigned long cycle_per_jiffy;
+       struct clock_event_device ced;
+       struct clocksource cs;
+};
+
+static struct pit_timer pit_timer;
+
 static void __iomem *clksrc_base;
-static void __iomem *clkevt_base;
-static unsigned long cycle_per_jiffy;
 
-static inline void pit_timer_enable(void)
+static inline struct pit_timer *ced_to_pit(struct clock_event_device *ced)
 {
-       writel(PITTCTRL_TEN | PITTCTRL_TIE, clkevt_base + PITTCTRL);
+       return container_of(ced, struct pit_timer, ced);
 }
 
-static inline void pit_timer_disable(void)
+static inline void pit_timer_enable(struct pit_timer *pit)
 {
-       writel(0, clkevt_base + PITTCTRL);
+       writel(PITTCTRL_TEN | PITTCTRL_TIE, pit->clkevt_base + PITTCTRL);
 }
 
-static inline void pit_irq_acknowledge(void)
+static inline void pit_timer_disable(struct pit_timer *pit)
 {
-       writel(PITTFLG_TIF, clkevt_base + PITTFLG);
+       writel(0, pit->clkevt_base + PITTCTRL);
+}
+
+static inline void pit_irq_acknowledge(struct pit_timer *pit)
+{
+       writel(PITTFLG_TIF, pit->clkevt_base + PITTFLG);
 }
 
 static u64 notrace pit_read_sched_clock(void)
@@ -53,21 +66,24 @@ static u64 notrace pit_read_sched_clock(void)
        return ~readl(clksrc_base + PITCVAL);
 }
 
-static int __init pit_clocksource_init(unsigned long rate)
+static int __init pit_clocksource_init(struct pit_timer *pit, unsigned long rate)
 {
        /* set the max load value and start the clock source counter */
-       writel(0, clksrc_base + PITTCTRL);
-       writel(~0UL, clksrc_base + PITLDVAL);
-       writel(PITTCTRL_TEN, clksrc_base + PITTCTRL);
+       writel(0, pit->clksrc_base + PITTCTRL);
+       writel(~0, pit->clksrc_base + PITLDVAL);
+       writel(PITTCTRL_TEN, pit->clksrc_base + PITTCTRL);
+
+       clksrc_base = pit->clksrc_base;
 
        sched_clock_register(pit_read_sched_clock, 32, rate);
-       return clocksource_mmio_init(clksrc_base + PITCVAL, "vf-pit", rate,
+       return clocksource_mmio_init(pit->clksrc_base + PITCVAL, "vf-pit", rate,
                        300, 32, clocksource_mmio_readl_down);
 }
 
-static int pit_set_next_event(unsigned long delta,
-                               struct clock_event_device *unused)
+static int pit_set_next_event(unsigned long delta, struct clock_event_device *ced)
 {
+       struct pit_timer *pit = ced_to_pit(ced);
+
        /*
         * set a new value to PITLDVAL register will not restart the timer,
         * to abort the current cycle and start a timer period with the new
@@ -75,30 +91,37 @@ static int pit_set_next_event(unsigned long delta,
         * and the PITLAVAL should be set to delta minus one according to pit
         * hardware requirement.
         */
-       pit_timer_disable();
-       writel(delta - 1, clkevt_base + PITLDVAL);
-       pit_timer_enable();
+       pit_timer_disable(pit);
+       writel(delta - 1, pit->clkevt_base + PITLDVAL);
+       pit_timer_enable(pit);
 
        return 0;
 }
 
-static int pit_shutdown(struct clock_event_device *evt)
+static int pit_shutdown(struct clock_event_device *ced)
 {
-       pit_timer_disable();
+       struct pit_timer *pit = ced_to_pit(ced);
+
+       pit_timer_disable(pit);
+
        return 0;
 }
 
-static int pit_set_periodic(struct clock_event_device *evt)
+static int pit_set_periodic(struct clock_event_device *ced)
 {
-       pit_set_next_event(cycle_per_jiffy, evt);
+       struct pit_timer *pit = ced_to_pit(ced);
+
+       pit_set_next_event(pit->cycle_per_jiffy, ced);
+
        return 0;
 }
 
 static irqreturn_t pit_timer_interrupt(int irq, void *dev_id)
 {
-       struct clock_event_device *evt = dev_id;
+       struct clock_event_device *ced = dev_id;
+       struct pit_timer *pit = ced_to_pit(ced);
 
-       pit_irq_acknowledge();
+       pit_irq_acknowledge(pit);
 
        /*
         * pit hardware doesn't support oneshot, it will generate an interrupt
@@ -106,33 +129,33 @@ static irqreturn_t pit_timer_interrupt(int irq, void *dev_id)
         * and start the counter again. So software need to disable the timer
         * to stop the counter loop in ONESHOT mode.
         */
-       if (likely(clockevent_state_oneshot(evt)))
-               pit_timer_disable();
+       if (likely(clockevent_state_oneshot(ced)))
+               pit_timer_disable(pit);
 
-       evt->event_handler(evt);
+       ced->event_handler(ced);
 
        return IRQ_HANDLED;
 }
 
-static struct clock_event_device clockevent_pit = {
-       .name           = "VF pit timer",
-       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
-       .set_state_shutdown = pit_shutdown,
-       .set_state_periodic = pit_set_periodic,
-       .set_next_event = pit_set_next_event,
-       .rating         = 300,
-};
-
-static int __init pit_clockevent_init(unsigned long rate, int irq)
+static int __init pit_clockevent_init(struct pit_timer *pit, unsigned long rate, int irq)
 {
-       writel(0, clkevt_base + PITTCTRL);
-       writel(PITTFLG_TIF, clkevt_base + PITTFLG);
+       writel(0, pit->clkevt_base + PITTCTRL);
+
+       writel(PITTFLG_TIF, pit->clkevt_base + PITTFLG);
 
        BUG_ON(request_irq(irq, pit_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
-                          "VF pit timer", &clockevent_pit));
+                          "VF pit timer", &pit->ced));
+
+       pit->ced.cpumask = cpumask_of(0);
+       pit->ced.irq = irq;
+
+       pit->ced.name = "VF pit timer";
+       pit->ced.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+       pit->ced.set_state_shutdown = pit_shutdown;
+       pit->ced.set_state_periodic = pit_set_periodic;
+       pit->ced.set_next_event = pit_set_next_event;
+       pit->ced.rating = 300;
 
-       clockevent_pit.cpumask = cpumask_of(0);
-       clockevent_pit.irq = irq;
        /*
         * The value for the LDVAL register trigger is calculated as:
         * LDVAL trigger = (period / clock period) - 1
@@ -141,7 +164,7 @@ static int __init pit_clockevent_init(unsigned long rate, int irq)
         * LDVAL trigger value is 1. And then the min_delta is
         * minimal LDVAL trigger value + 1, and the max_delta is full 32-bit.
         */
-       clockevents_config_and_register(&clockevent_pit, rate, 2, 0xffffffff);
+       clockevents_config_and_register(&pit->ced, rate, 2, 0xffffffff);
 
        return 0;
 }
@@ -164,8 +187,8 @@ static int __init pit_timer_init(struct device_node *np)
         * so choose PIT2 as clocksource, PIT3 as clockevent device,
         * and leave PIT0 and PIT1 unused for anyone else who needs them.
         */
-       clksrc_base = timer_base + PITn_OFFSET(2);
-       clkevt_base = timer_base + PITn_OFFSET(3);
+       pit_timer.clksrc_base = timer_base + PIT_CH(2);
+       pit_timer.clkevt_base = timer_base + PIT_CH(3);
 
        irq = irq_of_parse_and_map(np, 0);
        if (irq <= 0)
@@ -180,15 +203,15 @@ static int __init pit_timer_init(struct device_node *np)
                return ret;
 
        clk_rate = clk_get_rate(pit_clk);
-       cycle_per_jiffy = clk_rate / (HZ);
+       pit_timer.cycle_per_jiffy = clk_rate / (HZ);
 
        /* enable the pit module */
        writel(~PITMCR_MDIS, timer_base + PITMCR);
 
-       ret = pit_clocksource_init(clk_rate);
+       ret = pit_clocksource_init(&pit_timer, clk_rate);
        if (ret)
                return ret;
 
-       return pit_clockevent_init(clk_rate, irq);
+       return pit_clockevent_init(&pit_timer, clk_rate, irq);
 }
 TIMER_OF_DECLARE(vf610, "fsl,vf610-pit", pit_timer_init);