[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250705160129.3688026-3-daniel.lezcano@linaro.org>
Date: Sat, 5 Jul 2025 18:01:09 +0200
From: Daniel Lezcano <daniel.lezcano@...aro.org>
To: daniel.lezcano@...aro.org,
tglx@...utronix.de
Cc: ghennadi.procopciuc@....nxp.com,
S32@....com,
linux-kernel@...r.kernel.org
Subject: [PATCH 03/20] clocksource/drivers/vf_pit: Set the scene for multiple timers
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 instanciation in the next changes.
Signed-off-by: Daniel Lezcano <daniel.lezcano@...aro.org>
---
drivers/clocksource/timer-vf-pit.c | 119 +++++++++++++++++------------
1 file changed, 70 insertions(+), 49 deletions(-)
diff --git a/drivers/clocksource/timer-vf-pit.c b/drivers/clocksource/timer-vf-pit.c
index 8041a8f62d1f..581b46e7b111 100644
--- a/drivers/clocksource/timer-vf-pit.c
+++ b/drivers/clocksource/timer-vf-pit.c
@@ -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
@@ -29,23 +29,36 @@
#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)
+{
+ return container_of(ced, struct pit_timer, ced);
+}
+
+static inline void pit_timer_enable(struct pit_timer *pit)
{
- writel(PITTCTRL_TEN | PITTCTRL_TIE, clkevt_base + PITTCTRL);
+ writel(PITTCTRL_TEN | PITTCTRL_TIE, pit->clkevt_base + PITTCTRL);
}
-static inline void pit_timer_disable(void)
+static inline void pit_timer_disable(struct pit_timer *pit)
{
- writel(0, clkevt_base + PITTCTRL);
+ writel(0, pit->clkevt_base + PITTCTRL);
}
-static inline void pit_irq_acknowledge(void)
+static inline void pit_irq_acknowledge(struct pit_timer *pit)
{
- writel(PITTFLG_TIF, clkevt_base + PITTFLG);
+ writel(PITTFLG_TIF, pit->clkevt_base + PITTFLG);
}
static u64 notrace pit_read_sched_clock(void)
@@ -53,21 +66,22 @@ 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);
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 +89,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 +127,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 +162,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 +185,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 +201,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);
--
2.43.0
Powered by blists - more mailing lists