ARM: ixp4xx: fix timer latch calculation
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Mon, 3 Feb 2014 10:31:19 +0000 (11:31 +0100)
committerUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Tue, 18 Feb 2014 20:23:19 +0000 (21:23 +0100)
In commit f0402f9b4711 ("ARM: ixp4xx: stop using <mach/timex.h>")
I didn't intend to implement a functional change, but as Olof noticed I
failed---at least a bit. Before this commit the following was used to
determine the latch value used:

#define IXP4XX_TIMER_FREQ 66666000
#define CLOCK_TICK_RATE \
(((IXP4XX_TIMER_FREQ / HZ & ~IXP4XX_OST_RELOAD_MASK) + 1) * HZ)
#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ)

The complicated calculation was done "b/c the timer register ignores the
bottom 2 bits of the LATCH value." With HZ=100 CLOCK_TICK_RATE used to
calculate to 66666100 and so LATCH to 666661. In ixp4xx_set_mode the
term

LATCH & ~IXP4XX_OST_RELOAD_MASK

was used to write to the relevant register (with IXP4XX_OST_RELOAD_MASK
being 3) and so effectively 666660 was used.

In commit f0402f9b4711 I translated that to:

#define IXP4XX_TIMER_FREQ 66666000
#define IXP4XX_LATCH DIV_ROUND_CLOSEST(IXP4XX_TIMER_FREQ, HZ)

which results in the same register writes, but still doesn't bear in
mind that the two least significant bits cannot be specified (which is
relevant only when HZ or IXP4XX_TIMER_FREQ are changed).

Instead of reverting back to the old approach use a more obvious and
also more correct way to calculate LATCH. (Regarding the more
correct claim: With IXP4XX_TIMER_FREQ == 66665999, the old code resulted
in LATCH = 666657 corresponding to a cycle time of 0.009999940149400597
seconds (error: -6.0e-8 s) while the new approach results in LATCH =
666660 and so a cycle time of 0.010000000150001503 seconds
(error: 1.5e-10 s).)

Fixes: f0402f9b4711 ("ARM: ixp4xx: stop using <mach/timex.h>")
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
arch/arm/mach-ixp4xx/common.c

index 20b62aa30086fc3deb5ec7ce8d1bc53d7d617044..37e6cdac1642e61daff91d972244e7cf0a4b63b0 100644 (file)
 #include <asm/mach/time.h>
 
 #define IXP4XX_TIMER_FREQ 66666000
-#define IXP4XX_LATCH DIV_ROUND_CLOSEST(IXP4XX_TIMER_FREQ, HZ)
+
+/*
+ * The timer register doesn't allow to specify the two least significant bits of
+ * the timeout value and assumes them being zero. So make sure IXP4XX_LATCH is
+ * the best value with the two least significant bits unset.
+ */
+#define IXP4XX_LATCH DIV_ROUND_CLOSEST(IXP4XX_TIMER_FREQ, \
+                                      (IXP4XX_OST_RELOAD_MASK + 1) * HZ) * \
+                       (IXP4XX_OST_RELOAD_MASK + 1)
 
 static void __init ixp4xx_clocksource_init(void);
 static void __init ixp4xx_clockevent_init(void);