Re: [PATCH 2/5] clocksource: Add Allwinner SoCs HS timers driver

From: Maxime Ripard
Date: Thu Sep 26 2013 - 08:59:00 EST


Hi Stephen,

On Wed, Sep 25, 2013 at 04:16:14PM -0700, Stephen Boyd wrote:
> On 09/25/13 07:03, Maxime Ripard wrote:
> > diff --git a/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt b/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt
> > new file mode 100644
> > index 0000000..b1f81e9
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt
> > @@ -0,0 +1,22 @@
> > +Allwinner SoCs High Speed Timer Controller
> > +
> > +Required properties:
> > +
> > +- compatible : should be "allwinner,sun5i-a13-hstimer" or
> > + "allwinner,sun7i-a20-hstimer"
> > +- reg : Specifies base physical address and size of the registers.
> > +- interrupts : The interrupts of these timers (2 for the sun5i IP, 4 for the sun7i
> > + one)
> > +- clocks: phandle to the source clock (usually the AHB clock)
> > +
> > +Example:
> > +
> > +hstimer@01c60000 {
>
> This should just be 'timer@1c60000'

Ok.

> > + compatible = "allwinner,sun7i-a20-hstimer";
> > + reg = <0x01c60000 0x1000>;
> > + interrupts = <0 51 1>,
> > + <0 52 1>,
> > + <0 53 1>,
> > + <0 54 1>;
> > + clocks = <&ahb1_gates 19>;
> > +};
>
> Weird mix of tabs and spaces here.

Right.

> > +
> > +static void __iomem *timer_base;
> > +static u32 ticks_per_jiffy;
> > +
> > +/*
> > + * When we disable a timer, we need to wait at least for 2 cycles of
> > + * the timer source clock. We will use for that the clocksource timer
> > + * that is already setup and runs at the same frequency than the other
> > + * timers, and we never will be disabled.
> > + */
> > +static void sun5i_clkevt_sync(void)
> > +{
> > + u32 old = readl(timer_base + TIMER_CNTVAL_LO_REG(1));
> > +
> > + while ((old - readl(timer_base + TIMER_CNTVAL_LO_REG(1))) < 3)
> > + cpu_relax();
> > +}
> > +
> [...]
> > +
> > +static int sun5i_clkevt_next_event(unsigned long evt,
> > + struct clock_event_device *unused)
> > +{
> > + sun5i_clkevt_time_stop(0);
> > + sun5i_clkevt_time_setup(0, evt);
> > + sun5i_clkevt_time_start(0, false);
>
> I suppose the min delta wants to be 3 instead of 1 because if we program
> an evt one tick in the future first we'll wait for two ticks (or is that
> three?) while we stop the timer and then program the timer to fire one
> tick after that. Perhaps we should subtract two ticks from the evt as
> well when we program it here?

Hmmm, indeed.

> > +
> > + return 0;
> > +}
> > +
> > +static struct clock_event_device sun5i_clockevent = {
> > + .name = "sun5i_tick",
> > + .rating = 350,
> > + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
> > + .set_mode = sun5i_clkevt_mode,
> > + .set_next_event = sun5i_clkevt_next_event,
> > +};
> > +
> > +
> > +static irqreturn_t sun5i_timer_interrupt(int irq, void *dev_id)
> > +{
> > + struct clock_event_device *evt = (struct clock_event_device *)dev_id;
> > +
> > + writel(0x1, timer_base + TIMER_IRQ_ST_REG);
> > + evt->event_handler(evt);
> > +
> > + return IRQ_HANDLED;
> > +}
> > +
> > +static struct irqaction sun5i_timer_irq = {
> > + .name = "sun5i_timer0",
> > + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
>
> IRQF_DISABLED is a no-op and can be dropped.

Right.

> > +
> > +static u32 sun5i_timer_sched_read(void)
> > +{
> > + return ~readl(timer_base + TIMER_CNTVAL_LO_REG(1));
> > +}
> > +
> > +static void __init sun5i_timer_init(struct device_node *node)
> > +{
> [...]
> > +
> > + sun5i_clockevent.cpumask = cpumask_of(0);
>
> Can this timer interrupt any CPU or is it hardwired to CPU0? If the
> interrupt can go to any CPU this should be cpu_possible_mask instead.

This is an interrupt that can interrupt any CPU available on the system,
so yes, cpu_possible_mask would make sense.

Thanks!
Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

Attachment: signature.asc
Description: Digital signature