@@ -40,6 +40,7 @@
#include <mach/hardware.h>
#include <plat/dmtimer.h>
#include <mach/irqs.h>
+#include <linux/kernel.h>
/* register offsets */
#define _OMAP_TIMER_ID_OFFSET 0x00
@@ -160,6 +161,9 @@ struct omap_dm_timer {
unsigned reserved:1;
unsigned enabled:1;
unsigned posted:1;
+#ifdef CONFIG_ARCH_OMAP2PLUS
+ unsigned ms_correction:1;
+#endif
};
static int dm_timer_count;
@@ -218,8 +222,10 @@ static const int omap2_dm_timer_count = ARRAY_SIZE(omap2_dm_timers);
#ifdef CONFIG_ARCH_OMAP3
static struct omap_dm_timer omap3_dm_timers[] = {
- { .phys_base = 0x48318000, .irq = INT_24XX_GPTIMER1 },
- { .phys_base = 0x49032000, .irq = INT_24XX_GPTIMER2 },
+ { .phys_base = 0x48318000, .irq = INT_24XX_GPTIMER1,
+ .ms_correction = 1 },
+ { .phys_base = 0x49032000, .irq = INT_24XX_GPTIMER2,
+ .ms_correction = 1 },
{ .phys_base = 0x49034000, .irq = INT_24XX_GPTIMER3 },
{ .phys_base = 0x49036000, .irq = INT_24XX_GPTIMER4 },
{ .phys_base = 0x49038000, .irq = INT_24XX_GPTIMER5 },
@@ -227,7 +233,8 @@ static struct omap_dm_timer omap3_dm_timers[] = {
{ .phys_base = 0x4903C000, .irq = INT_24XX_GPTIMER7 },
{ .phys_base = 0x4903E000, .irq = INT_24XX_GPTIMER8 },
{ .phys_base = 0x49040000, .irq = INT_24XX_GPTIMER9 },
- { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 },
+ { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10,
+ .ms_correction = 1 },
{ .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 },
{ .phys_base = 0x48304000, .irq = INT_34XX_GPT12_IRQ },
};
@@ -250,8 +257,10 @@ static const int omap3_dm_timer_count = ARRAY_SIZE(omap3_dm_timers);
#ifdef CONFIG_ARCH_OMAP4
static struct omap_dm_timer omap4_dm_timers[] = {
- { .phys_base = 0x4a318000, .irq = OMAP44XX_IRQ_GPT1 },
- { .phys_base = 0x48032000, .irq = OMAP44XX_IRQ_GPT2 },
+ { .phys_base = 0x4a318000, .irq = OMAP44XX_IRQ_GPT1,
+ .ms_correction = 1 },
+ { .phys_base = 0x48032000, .irq = OMAP44XX_IRQ_GPT2,
+ .ms_correction = 1 },
{ .phys_base = 0x48034000, .irq = OMAP44XX_IRQ_GPT3 },
{ .phys_base = 0x48036000, .irq = OMAP44XX_IRQ_GPT4 },
{ .phys_base = 0x40138000, .irq = OMAP44XX_IRQ_GPT5 },
@@ -259,7 +268,8 @@ static struct omap_dm_timer omap4_dm_timers[] = {
{ .phys_base = 0x4013a000, .irq = OMAP44XX_IRQ_GPT7 },
{ .phys_base = 0x4013e000, .irq = OMAP44XX_IRQ_GPT8 },
{ .phys_base = 0x4803e000, .irq = OMAP44XX_IRQ_GPT9 },
- { .phys_base = 0x48086000, .irq = OMAP44XX_IRQ_GPT10 },
+ { .phys_base = 0x48086000, .irq = OMAP44XX_IRQ_GPT10,
+ .ms_correction = 1 },
{ .phys_base = 0x48088000, .irq = OMAP44XX_IRQ_GPT11 },
{ .phys_base = 0x4a320000, .irq = OMAP44XX_IRQ_GPT12 },
};
@@ -360,6 +370,23 @@ static void omap_dm_timer_prepare(struct omap_dm_timer *timer)
omap_dm_timer_enable(timer);
omap_dm_timer_reset(timer);
}
+/**
+ * omap_dm_timer_ms_correction - hardware correction for millisecond timer
+ * @timer: GPTIMER on which the correction support is to be applied
+ * @load: timer load value, used here to extract the expiry count
+ */
+static void omap_dm_timer_ms_correction(struct omap_dm_timer *timer, u32 load)
+{
+ int pos_increment, neg_increment;
+ unsigned int count = (0xFFFFFFFF - load) * 1024;
+
+ pos_increment = (DIV_ROUND_UP(count, 1000) * 1000000) \
+ - (count * 1000);
+ neg_increment = ((DIV_ROUND_UP(count, 1000) - 1) * 1000000) \
+ - (count * 1000);
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_TICK_POS_REG, pos_increment);
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_TICK_NEG_REG, neg_increment);
+}
struct omap_dm_timer *omap_dm_timer_request(void)
{
@@ -612,6 +639,10 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
{
u32 l;
+#ifdef CONFIG_ARCH_OMAP2PLUS
+ if (timer->ms_correction)
+ omap_dm_timer_ms_correction(timer, load);
+#endif
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
if (autoreload) {
l |= OMAP_TIMER_CTRL_AR;