From 971d0254480572bc6dc5574c28ef8fe014660a31 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 27 Sep 2012 11:49:45 -0500 Subject: ARM: OMAP: Add DMTIMER definitions for posted mode For OMAP2+ devices, when using DMTIMERs for system timers (clock-events and clock-source) the posted mode configuration of the timers is used. To allow the compiler to optimise the functions for configuring and reading the system timers, the posted flag variable is hard-coded with the value 1. To make it clear that posted mode is being used add some definitions so that it is more readable. Signed-off-by: Jon Hunter Acked-by: Santosh Shilimkar --- arch/arm/plat-omap/include/plat/dmtimer.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'arch/arm/plat-omap/include/plat') diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h index f8943c8f9db..1bee0ac8876 100644 --- a/arch/arm/plat-omap/include/plat/dmtimer.h +++ b/arch/arm/plat-omap/include/plat/dmtimer.h @@ -55,6 +55,10 @@ #define OMAP_TIMER_TRIGGER_OVERFLOW 0x01 #define OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE 0x02 +/* posted mode types */ +#define OMAP_TIMER_NONPOSTED 0x00 +#define OMAP_TIMER_POSTED 0x01 + /* timer capabilities used in hwmod database */ #define OMAP_TIMER_SECURE 0x80000000 #define OMAP_TIMER_ALWON 0x40000000 -- cgit v1.2.3-70-g09d2 From bfd6d021120d5994c4cc94d87ec03642be1540e7 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 27 Sep 2012 12:47:43 -0500 Subject: ARM: OMAP3+: Implement timer workaround for errata i103 and i767 Errata Titles: i103: Delay needed to read some GP timer, WD timer and sync timer registers after wakeup (OMAP3/4) i767: Delay needed to read some GP timer registers after wakeup (OMAP5) Description (i103/i767): If a General Purpose Timer (GPTimer) is in posted mode (TSICR [2].POSTED=1), due to internal resynchronizations, values read in TCRR, TCAR1 and TCAR2 registers right after the timer interface clock (L4) goes from stopped to active may not return the expected values. The most common event leading to this situation occurs upon wake up from idle. GPTimer non-posted synchronization mode is not impacted by this limitation. Workarounds: 1). Disable posted mode 2). Use static dependency between timer clock domain and MPUSS clock domain 3). Use no-idle mode when the timer is active Workarounds #2 and #3 are not pratical from a power standpoint and so workaround #1 has been implemented. Disabling posted mode adds some CPU overhead for configuring and reading the timers as the CPU has to wait for accesses to be re-synchronised within the timer. However, disabling posted mode guarantees correct operation. Please note that it is safe to use posted mode for timers if the counter (TCRR) and capture (TCARx) registers will never be read. An example of this is the clock-event system timer. This is used by the kernel to schedule events however, the timers counter is never read and capture registers are not used. Given that the kernel configures this timer often yet never reads the counter register it is safe to enable posted mode in this case. Hence, for the timer used for kernel clock-events, posted mode is enabled by overriding the errata for devices that are impacted by this defect. For drivers using the timers that do not read the counter or capture registers and wish to use posted mode, can override the errata and enable posted mode by making the following function calls. __omap_dm_timer_override_errata(timer, OMAP_TIMER_ERRATA_I103_I767); __omap_dm_timer_enable_posted(timer); Both dmtimers and watchdogs are impacted by this defect this patch only implements the workaround for the dmtimer. Currently the watchdog driver does not read the counter register and so no workaround is necessary. Posted mode will be disabled for all OMAP2+ devices (including AM33xx) using a GP timer as a clock-source timer to guarantee correct operation. This is not necessary for OMAP24xx devices but the default clock-source timer for OMAP24xx devices is the 32k-sync timer and not the GP timer and so should not have any impact. This should be re-visited for future devices if this errata is fixed. Confirmed with Vaibhav Hiremath that this bug also impacts AM33xx devices. Signed-off-by: Jon Hunter Acked-by: Santosh Shilimkar --- arch/arm/mach-omap2/timer.c | 49 ++++++++++++++++++++++++----- arch/arm/plat-omap/dmtimer.c | 3 +- arch/arm/plat-omap/include/plat/dmtimer.h | 52 +++++++++++++++++++++++++++++-- 3 files changed, 93 insertions(+), 11 deletions(-) (limited to 'arch/arm/plat-omap/include/plat') diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index a135d28e202..63229c5287e 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -222,10 +222,24 @@ void __init omap_dmtimer_init(void) } } +/** + * omap_dm_timer_get_errata - get errata flags for a timer + * + * Get the timer errata flags that are specific to the OMAP device being used. + */ +u32 __init omap_dm_timer_get_errata(void) +{ + if (cpu_is_omap24xx()) + return 0; + + return OMAP_TIMER_ERRATA_I103_I767; +} + static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, int gptimer_id, const char *fck_source, - const char *property) + const char *property, + int posted) { char name[10]; /* 10 = sizeof("gptXX_Xck0") */ const char *oh_name; @@ -311,10 +325,15 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, } __omap_dm_timer_init_regs(timer); __omap_dm_timer_reset(timer, 1, 1); - timer->posted = 1; - timer->rate = clk_get_rate(timer->fclk); + if (posted) + __omap_dm_timer_enable_posted(timer); + + /* Check that the intended posted configuration matches the actual */ + if (posted != timer->posted) + return -EINVAL; + timer->rate = clk_get_rate(timer->fclk); timer->reserved = 1; return res; @@ -326,7 +345,17 @@ static void __init omap2_gp_clockevent_init(int gptimer_id, { int res; - res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source, property); + clkev.errata = omap_dm_timer_get_errata(); + + /* + * For clock-event timers we never read the timer counter and + * so we are not impacted by errata i103 and i767. Therefore, + * we can safely ignore this errata for clock-event timers. + */ + __omap_dm_timer_override_errata(&clkev, OMAP_TIMER_ERRATA_I103_I767); + + res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source, property, + OMAP_TIMER_POSTED); BUG_ON(res); omap2_gp_timer_irq.dev_id = &clkev; @@ -360,7 +389,7 @@ static bool use_gptimer_clksrc; static cycle_t clocksource_read_cycles(struct clocksource *cs) { return (cycle_t)__omap_dm_timer_read_counter(&clksrc, - OMAP_TIMER_POSTED); + OMAP_TIMER_NONPOSTED); } static struct clocksource clocksource_gpt = { @@ -375,7 +404,7 @@ static u32 notrace dmtimer_read_sched_clock(void) { if (clksrc.reserved) return __omap_dm_timer_read_counter(&clksrc, - OMAP_TIMER_POSTED); + OMAP_TIMER_NONPOSTED); return 0; } @@ -453,12 +482,15 @@ static void __init omap2_gptimer_clocksource_init(int gptimer_id, { int res; - res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source, NULL); + clksrc.errata = omap_dm_timer_get_errata(); + + res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source, NULL, + OMAP_TIMER_NONPOSTED); BUG_ON(res); __omap_dm_timer_load_start(&clksrc, OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, - OMAP_TIMER_POSTED); + OMAP_TIMER_NONPOSTED); setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate); if (clocksource_register_hz(&clocksource_gpt, clksrc.rate)) @@ -696,6 +728,7 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused) if (timer_dev_attr) pdata->timer_capability = timer_dev_attr->timer_capability; + pdata->timer_errata = omap_dm_timer_get_errata(); pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count; pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata), diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index 9dca23e4d6b..381a612e6a1 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -128,8 +128,8 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer) } __omap_dm_timer_reset(timer, 0, 0); + __omap_dm_timer_enable_posted(timer); omap_dm_timer_disable(timer); - timer->posted = 1; } int omap_dm_timer_prepare(struct omap_dm_timer *timer) @@ -797,6 +797,7 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev) timer->capability |= OMAP_TIMER_SECURE; } else { timer->id = pdev->id; + timer->errata = pdata->timer_errata; timer->capability = pdata->timer_capability; timer->reserved = omap_dm_timer_reserved_systimer(timer->id); timer->get_context_loss_count = pdata->get_context_loss_count; diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h index 1bee0ac8876..ac16f1e9d0e 100644 --- a/arch/arm/plat-omap/include/plat/dmtimer.h +++ b/arch/arm/plat-omap/include/plat/dmtimer.h @@ -66,6 +66,16 @@ #define OMAP_TIMER_NEEDS_RESET 0x10000000 #define OMAP_TIMER_HAS_DSP_IRQ 0x08000000 +/* + * timer errata flags + * + * Errata i103/i767 impacts all OMAP3/4/5 devices including AM33xx. This + * errata prevents us from using posted mode on these devices, unless the + * timer counter register is never read. For more details please refer to + * the OMAP3/4/5 errata documents. + */ +#define OMAP_TIMER_ERRATA_I103_I767 0x80000000 + struct omap_timer_capability_dev_attr { u32 timer_capability; }; @@ -97,6 +107,7 @@ struct timer_regs { struct dmtimer_platform_data { /* set_timer_src - Only used for OMAP1 devices */ int (*set_timer_src)(struct platform_device *pdev, int source); + u32 timer_errata; u32 timer_capability; int (*get_context_loss_count)(struct device *); }; @@ -273,6 +284,7 @@ struct omap_dm_timer { int ctx_loss_count; int revision; u32 capability; + u32 errata; struct platform_device *pdev; struct list_head node; }; @@ -344,10 +356,46 @@ static inline void __omap_dm_timer_reset(struct omap_dm_timer *timer, l |= 1 << 2; __raw_writel(l, timer->io_base + OMAP_TIMER_OCP_CFG_OFFSET); +} + +/* + * __omap_dm_timer_enable_posted - enables write posted mode + * @timer: pointer to timer instance handle + * + * Enables the write posted mode for the timer. When posted mode is enabled + * writes to certain timer registers are immediately acknowledged by the + * internal bus and hence prevents stalling the CPU waiting for the write to + * complete. Enabling this feature can improve performance for writing to the + * timer registers. + */ +static inline void __omap_dm_timer_enable_posted(struct omap_dm_timer *timer) +{ + if (timer->posted) + return; + + if (timer->errata & OMAP_TIMER_ERRATA_I103_I767) + return; - /* Match hardware reset default of posted mode */ __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, - OMAP_TIMER_CTRL_POSTED, 0); + OMAP_TIMER_CTRL_POSTED, 0); + timer->context.tsicr = OMAP_TIMER_CTRL_POSTED; + timer->posted = OMAP_TIMER_POSTED; +} + +/** + * __omap_dm_timer_override_errata - override errata flags for a timer + * @timer: pointer to timer handle + * @errata: errata flags to be ignored + * + * For a given timer, override a timer errata by clearing the flags + * specified by the errata argument. A specific erratum should only be + * overridden for a timer if the timer is used in such a way the erratum + * has no impact. + */ +static inline void __omap_dm_timer_override_errata(struct omap_dm_timer *timer, + u32 errata) +{ + timer->errata &= ~errata; } static inline int __omap_dm_timer_set_source(struct clk *timer_fck, -- cgit v1.2.3-70-g09d2 From d3004bb43de180c2f6e965716a3abe9b43c8b861 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 28 Sep 2012 16:09:03 -0500 Subject: ARM: OMAP: Don't restore of DMTIMER TISTAT register The timer TISTAT register is a read-only register and therefore restoring the context is not needed. Furthermore, the context of TISTAT is never saved anywhere in the current code. The TISTAT register is read-only for all OMAP devices from OMAP1 to OMAP4. OMAP5 timers no longer have this register. Signed-off-by: Jon Hunter Acked-by: Santosh Shilimkar --- arch/arm/plat-omap/dmtimer.c | 3 --- arch/arm/plat-omap/include/plat/dmtimer.h | 1 - 2 files changed, 4 deletions(-) (limited to 'arch/arm/plat-omap/include/plat') diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index d4f95410539..320d1038171 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -83,9 +83,6 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg, static void omap_timer_restore_context(struct omap_dm_timer *timer) { - if (timer->revision == 1) - __raw_writel(timer->context.tistat, timer->sys_stat); - __raw_writel(timer->context.tisr, timer->irq_stat); omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, timer->context.twer); diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h index ac16f1e9d0e..2f9fd1d27ae 100644 --- a/arch/arm/plat-omap/include/plat/dmtimer.h +++ b/arch/arm/plat-omap/include/plat/dmtimer.h @@ -84,7 +84,6 @@ struct omap_dm_timer; struct timer_regs { u32 tidr; - u32 tistat; u32 tisr; u32 tier; u32 twer; -- cgit v1.2.3-70-g09d2 From 1eaff71017d97ce2bc8e22b9a5cf11e5c6dd6c78 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 4 Oct 2012 17:01:14 -0500 Subject: ARM: OMAP: Don't restore DMTIMER interrupt status register Restoring the timer interrupt status is not possible because writing a 1 to any bit in the register clears that bit if set and writing a 0 has no affect. Furthermore, if an interrupt is pending when someone attempts to disable a timer, the timer will fail to transition to the idle state and hence it's context will not be lost. Users should take care to service all interrupts before disabling the timer. Signed-off-by: Jon Hunter Acked-by: Santosh Shilimkar --- arch/arm/plat-omap/dmtimer.c | 5 +---- arch/arm/plat-omap/include/plat/dmtimer.h | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) (limited to 'arch/arm/plat-omap/include/plat') diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index 320d1038171..f0a3c4c72a4 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -83,7 +83,6 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg, static void omap_timer_restore_context(struct omap_dm_timer *timer) { - __raw_writel(timer->context.tisr, timer->irq_stat); omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, timer->context.twer); omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, @@ -440,7 +439,6 @@ int omap_dm_timer_stop(struct omap_dm_timer *timer) */ timer->context.tclr = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - timer->context.tisr = __raw_readl(timer->irq_stat); omap_dm_timer_disable(timer); return 0; } @@ -684,8 +682,7 @@ int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) return -EINVAL; __omap_dm_timer_write_status(timer, value); - /* Save the context */ - timer->context.tisr = value; + return 0; } EXPORT_SYMBOL_GPL(omap_dm_timer_write_status); diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h index 2f9fd1d27ae..0c07e375347 100644 --- a/arch/arm/plat-omap/include/plat/dmtimer.h +++ b/arch/arm/plat-omap/include/plat/dmtimer.h @@ -84,7 +84,6 @@ struct omap_dm_timer; struct timer_regs { u32 tidr; - u32 tisr; u32 tier; u32 twer; u32 tclr; -- cgit v1.2.3-70-g09d2 From 4249d96ca35a765c25a70b7d29df5b6d80987c7f Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 13 Jul 2012 14:03:18 -0500 Subject: ARM: OMAP: Add dmtimer interrupt disable function The OMAP dmtimer driver does not currently have a function to disable the timer interrupts. For some timer instances the timer interrupt enable function can be used to disable the interrupts because the same interrupt enable register is used to disable interrupts. However, some timer instances have separate interrupt enable/disable registers and so this will not work. Therefore, add a dedicated function to disable interrupts. This change is required for OMAP4+ devices. For OMAP4, all timers apart from 1, 2 and 10 need this function and for OMAP5 all timers need this function. Please note that the interrupt disable function has been written so that it can be used by all OMAP devices. Signed-off-by: Jon Hunter Acked-by: Santosh Shilimkar --- arch/arm/plat-omap/dmtimer.c | 31 +++++++++++++++++++++++++++++++ arch/arm/plat-omap/include/plat/dmtimer.h | 3 ++- 2 files changed, 33 insertions(+), 1 deletion(-) (limited to 'arch/arm/plat-omap/include/plat') diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index a38e8964c82..b4e6634380e 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -661,6 +661,37 @@ int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, } EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable); +/** + * omap_dm_timer_set_int_disable - disable timer interrupts + * @timer: pointer to timer handle + * @mask: bit mask of interrupts to be disabled + * + * Disables the specified timer interrupts for a timer. + */ +int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask) +{ + u32 l = mask; + + if (unlikely(!timer)) + return -EINVAL; + + omap_dm_timer_enable(timer); + + if (timer->revision == 1) + l = __raw_readl(timer->irq_ena) & ~mask; + + __raw_writel(l, timer->irq_dis); + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG) & ~mask; + omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, l); + + /* Save the context */ + timer->context.tier &= ~mask; + timer->context.twer &= ~mask; + omap_dm_timer_disable(timer); + return 0; +} +EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_disable); + unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) { unsigned int l; diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h index 0c07e375347..769efb6f30d 100644 --- a/arch/arm/plat-omap/include/plat/dmtimer.h +++ b/arch/arm/plat-omap/include/plat/dmtimer.h @@ -135,6 +135,7 @@ int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, int toggle, i int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler); int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value); +int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask); unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer); int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value); @@ -321,7 +322,7 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer) OMAP_TIMER_V1_SYS_STAT_OFFSET; timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET; timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET; - timer->irq_dis = NULL; + timer->irq_dis = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET; timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET; timer->func_base = timer->io_base; } else { -- cgit v1.2.3-70-g09d2 From b1538832191d59e29b1077e64cf416a7617b45bc Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 28 Sep 2012 11:43:30 -0500 Subject: ARM: OMAP: Remove __omap_dm_timer_set_source function The __omap_dm_timer_set_source() function is only used by the system timer (clock-events and clock-source) code for OMAP2+ devices. Therefore, we can remove this code from the dmtimer driver and move it to the system timer code for OMAP2+ devices. The current __omap_dm_timer_set_source() function calls clk_disable() before calling clk_set_parent() and clk_enable() afterwards. We can avoid these calls to clk_disable/enable by moving the calls to omap_hwmod_setup_one() and omap_hwmod_enable() to after the call to clk_set_parent() in omap_dm_timer_init_one(). The function omap_hwmod_setup_one() will enable the timers functional clock and therefore increment the use-count of the functional clock to 1. clk_set_parent() will fail if the use-count is not 0 when called. Hence, if omap_hwmod_setup_one() is called before clk_set_parent(), we will need to call clk_disable() before calling clk_set_parent() to decrement the use-count. Hence, avoid these extra calls to disable and enable the functional clock by moving the calls to omap_hwmod_setup_one() and omap_hwmod_enable() to after clk_set_parent(). We can also remove the delay from the __omap_dm_timer_set_source() function because enabling the clock will now be handled via the HWMOD framework by calling omap_hwmod_setup_one(). Therefore, by moving the calls to omap_hwmod_setup_one() and omap_hwmod_enable() to after the call to clk_set_parent(), we can simply replace __omap_dm_timer_set_source() with clk_set_parent(). It should be safe to move these hwmod calls to later in the omap_dm_timer_init_one() because other calls to the hwmod layer that occur before are just requesting resource information. Testing includes boot testing on OMAP2420 H4, OMAP3430 SDP and OMAP4430 Blaze with the following configurations: 1. CONFIG_OMAP_32K_TIMER=y 2. CONFIG_OMAP_32K_TIMER=y and boot parameter "clocksource=gp_timer" 3. CONFIG_OMAP_32K_TIMER not set 4. CONFIG_OMAP_32K_TIMER not set and boot parameter "clocksource=gp_timer" Signed-off-by: Jon Hunter Acked-by: Santosh Shilimkar --- arch/arm/mach-omap2/timer.c | 9 ++++----- arch/arm/plat-omap/dmtimer.c | 1 + arch/arm/plat-omap/include/plat/dmtimer.h | 19 ------------------- 3 files changed, 5 insertions(+), 24 deletions(-) (limited to 'arch/arm/plat-omap/include/plat') diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 19765bd96c8..099e4060afe 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -274,9 +274,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, oh_name = name; } - omap_hwmod_setup_one(oh_name); oh = omap_hwmod_lookup(oh_name); - if (!oh) return -ENODEV; @@ -306,8 +304,6 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, if (IS_ERR(timer->fclk)) return -ENODEV; - omap_hwmod_enable(oh); - /* FIXME: Need to remove hard-coded test on timer ID */ if (gptimer_id != 12) { struct clk *src; @@ -316,13 +312,16 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, if (IS_ERR(src)) { res = -EINVAL; } else { - res = __omap_dm_timer_set_source(timer->fclk, src); + res = clk_set_parent(timer->fclk, src); if (IS_ERR_VALUE(res)) pr_warn("%s: %s cannot set source\n", __func__, oh->name); clk_put(src); } } + + omap_hwmod_setup_one(oh_name); + omap_hwmod_enable(oh); __omap_dm_timer_init_regs(timer); if (posted) diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index 305faf53946..9deeb3064d3 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -35,6 +35,7 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h index 769efb6f30d..05a36e16f3f 100644 --- a/arch/arm/plat-omap/include/plat/dmtimer.h +++ b/arch/arm/plat-omap/include/plat/dmtimer.h @@ -32,7 +32,6 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include @@ -397,24 +396,6 @@ static inline void __omap_dm_timer_override_errata(struct omap_dm_timer *timer, timer->errata &= ~errata; } -static inline int __omap_dm_timer_set_source(struct clk *timer_fck, - struct clk *parent) -{ - int ret; - - clk_disable(timer_fck); - ret = clk_set_parent(timer_fck, parent); - clk_enable(timer_fck); - - /* - * When the functional clock disappears, too quick writes seem - * to cause an abort. XXX Is this still necessary? - */ - __delay(300000); - - return ret; -} - static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer, int posted, unsigned long rate) { -- cgit v1.2.3-70-g09d2