diff options
Diffstat (limited to 'arch/arm/mach-omap2/timer.c')
| -rw-r--r-- | arch/arm/mach-omap2/timer.c | 234 |
1 files changed, 119 insertions, 115 deletions
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index b8ad6e632bb..43d03fbf4c0 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -41,12 +41,11 @@ #include <linux/of_irq.h> #include <linux/platform_device.h> #include <linux/platform_data/dmtimer-omap.h> +#include <linux/sched_clock.h> #include <asm/mach/time.h> #include <asm/smp_twd.h> -#include <asm/sched_clock.h> -#include <asm/arch_timer.h> #include "omap_hwmod.h" #include "omap_device.h" #include <plat/counter-32k.h> @@ -56,15 +55,7 @@ #include "soc.h" #include "common.h" #include "powerdomain.h" - -/* Parent clocks, eventually these will come from the clock framework */ - -#define OMAP2_MPU_SOURCE "sys_ck" -#define OMAP3_MPU_SOURCE OMAP2_MPU_SOURCE -#define OMAP4_MPU_SOURCE "sys_clkin_ck" -#define OMAP2_32K_SOURCE "func_32k_ck" -#define OMAP3_32K_SOURCE "omap_32k_fck" -#define OMAP4_32K_SOURCE "sys_32k_ck" +#include "omap-secure.h" #define REALTIME_COUNTER_BASE 0x48243200 #define INCREMENTER_NUMERATOR_OFFSET 0x10 @@ -76,6 +67,15 @@ static struct omap_dm_timer clkev; static struct clock_event_device clockevent_gpt; +#ifdef CONFIG_SOC_HAS_REALTIME_COUNTER +static unsigned long arch_timer_freq; + +void set_cntfreq(void) +{ + omap_smc1(OMAP5_DRA7_MON_SET_CNTFRQ_INDEX, arch_timer_freq); +} +#endif + static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) { struct clock_event_device *evt = &clockevent_gpt; @@ -88,7 +88,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) static struct irqaction omap2_gp_timer_irq = { .name = "gp_timer", - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, + .flags = IRQF_TIMER | IRQF_IRQPOLL, .handler = omap2_gp_timer_interrupt, }; @@ -129,9 +129,7 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode, } static struct clock_event_device clockevent_gpt = { - .name = "gp_timer", .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .shift = 32, .rating = 300, .set_next_event = omap2_gp_timer_set_next_event, .set_mode = omap2_gp_timer_set_mode, @@ -144,7 +142,12 @@ static struct property device_disabled = { }; static struct of_device_id omap_timer_match[] __initdata = { - { .compatible = "ti,omap2-timer", }, + { .compatible = "ti,omap2420-timer", }, + { .compatible = "ti,omap3430-timer", }, + { .compatible = "ti,omap4430-timer", }, + { .compatible = "ti,omap5430-timer", }, + { .compatible = "ti,am335x-timer", }, + { .compatible = "ti,am335x-timer-1ms", }, { } }; @@ -171,6 +174,12 @@ static struct device_node * __init omap_get_timer_dt(struct of_device_id *match, if (property && !of_get_property(np, property, NULL)) continue; + if (!property && (of_get_property(np, "ti,timer-alwon", NULL) || + of_get_property(np, "ti,timer-dsp", NULL) || + of_get_property(np, "ti,timer-pwm", NULL) || + of_get_property(np, "ti,timer-secure", NULL))) + continue; + of_add_property(np, &device_disabled); return np; } @@ -215,20 +224,21 @@ static u32 __init omap_dm_timer_get_errata(void) } static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, - int gptimer_id, - const char *fck_source, - const char *property, - int posted) + const char *fck_source, + const char *property, + const char **timer_name, + int posted) { char name[10]; /* 10 = sizeof("gptXX_Xck0") */ - const char *oh_name; + const char *oh_name = NULL; struct device_node *np; struct omap_hwmod *oh; struct resource irq, mem; + struct clk *src; int r = 0; if (of_have_populated_dt()) { - np = omap_get_timer_dt(omap_timer_match, NULL); + np = omap_get_timer_dt(omap_timer_match, property); if (!np) return -ENODEV; @@ -244,10 +254,10 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, of_node_put(np); } else { - if (omap_dm_timer_reserve_systimer(gptimer_id)) + if (omap_dm_timer_reserve_systimer(timer->id)) return -ENODEV; - sprintf(name, "timer%d", gptimer_id); + sprintf(name, "timer%d", timer->id); oh_name = name; } @@ -255,6 +265,8 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, if (!oh) return -ENODEV; + *timer_name = oh->name; + if (!of_have_populated_dt()) { r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL, &irq); @@ -277,24 +289,24 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, /* After the dmtimer is using hwmod these clocks won't be needed */ timer->fclk = clk_get(NULL, omap_hwmod_get_main_clk(oh)); if (IS_ERR(timer->fclk)) - return -ENODEV; + return PTR_ERR(timer->fclk); - /* FIXME: Need to remove hard-coded test on timer ID */ - if (gptimer_id != 12) { - struct clk *src; - - src = clk_get(NULL, fck_source); - if (IS_ERR(src)) { - r = -EINVAL; - } else { - r = clk_set_parent(timer->fclk, src); - if (IS_ERR_VALUE(r)) - pr_warn("%s: %s cannot set source\n", - __func__, oh->name); + src = clk_get(NULL, fck_source); + if (IS_ERR(src)) + return PTR_ERR(src); + + if (clk_get_parent(timer->fclk) != src) { + r = clk_set_parent(timer->fclk, src); + if (r < 0) { + pr_warn("%s: %s cannot set source\n", __func__, + oh->name); clk_put(src); + return r; } } + clk_put(src); + omap_hwmod_setup_one(oh_name); omap_hwmod_enable(oh); __omap_dm_timer_init_regs(timer); @@ -318,6 +330,7 @@ static void __init omap2_gp_clockevent_init(int gptimer_id, { int res; + clkev.id = gptimer_id; clkev.errata = omap_dm_timer_get_errata(); /* @@ -327,8 +340,8 @@ static void __init omap2_gp_clockevent_init(int gptimer_id, */ __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); + res = omap_dm_timer_init_one(&clkev, fck_source, property, + &clockevent_gpt.name, OMAP_TIMER_POSTED); BUG_ON(res); omap2_gp_timer_irq.dev_id = &clkev; @@ -336,25 +349,19 @@ static void __init omap2_gp_clockevent_init(int gptimer_id, __omap_dm_timer_int_enable(&clkev, OMAP_TIMER_INT_OVERFLOW); - clockevent_gpt.mult = div_sc(clkev.rate, NSEC_PER_SEC, - clockevent_gpt.shift); - clockevent_gpt.max_delta_ns = - clockevent_delta2ns(0xffffffff, &clockevent_gpt); - clockevent_gpt.min_delta_ns = - clockevent_delta2ns(3, &clockevent_gpt); - /* Timer internal resynch latency. */ - clockevent_gpt.cpumask = cpu_possible_mask; clockevent_gpt.irq = omap_dm_timer_get_irq(&clkev); - clockevents_register_device(&clockevent_gpt); + clockevents_config_and_register(&clockevent_gpt, clkev.rate, + 3, /* Timer internal resynch latency */ + 0xffffffff); - pr_info("OMAP clockevent source: GPTIMER%d at %lu Hz\n", - gptimer_id, clkev.rate); + pr_info("OMAP clockevent source: %s at %lu Hz\n", clockevent_gpt.name, + clkev.rate); } /* Clocksource code */ static struct omap_dm_timer clksrc; -static bool use_gptimer_clksrc; +static bool use_gptimer_clksrc __initdata; /* * clocksource @@ -366,14 +373,13 @@ static cycle_t clocksource_read_cycles(struct clocksource *cs) } static struct clocksource clocksource_gpt = { - .name = "gp_timer", .rating = 300, .read = clocksource_read_cycles, .mask = CLOCKSOURCE_MASK(32), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -static u32 notrace dmtimer_read_sched_clock(void) +static u64 notrace dmtimer_read_sched_clock(void) { if (clksrc.reserved) return __omap_dm_timer_read_counter(&clksrc, @@ -449,27 +455,30 @@ static int __init __maybe_unused omap2_sync32k_clocksource_init(void) } static void __init omap2_gptimer_clocksource_init(int gptimer_id, - const char *fck_source) + const char *fck_source, + const char *property) { int res; + clksrc.id = gptimer_id; clksrc.errata = omap_dm_timer_get_errata(); - res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source, NULL, + res = omap_dm_timer_init_one(&clksrc, fck_source, property, + &clocksource_gpt.name, OMAP_TIMER_NONPOSTED); BUG_ON(res); __omap_dm_timer_load_start(&clksrc, OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, OMAP_TIMER_NONPOSTED); - setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate); + sched_clock_register(dmtimer_read_sched_clock, 32, clksrc.rate); if (clocksource_register_hz(&clocksource_gpt, clksrc.rate)) pr_err("Could not register clocksource %s\n", clocksource_gpt.name); else - pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n", - gptimer_id, clksrc.rate); + pr_info("OMAP clocksource: %s at %lu Hz\n", + clocksource_gpt.name, clksrc.rate); } #ifdef CONFIG_SOC_HAS_REALTIME_COUNTER @@ -494,7 +503,7 @@ static void __init realtime_counter_init(void) pr_err("%s: ioremap failed\n", __func__); return; } - sys_clk = clk_get(NULL, "sys_clkin_ck"); + sys_clk = clk_get(NULL, "sys_clkin"); if (IS_ERR(sys_clk)) { pr_err("%s: failed to get system clock handle\n", __func__); iounmap(base); @@ -516,6 +525,10 @@ static void __init realtime_counter_init(void) num = 8; den = 25; break; + case 20000000: + num = 192; + den = 625; + break; case 2600000: num = 384; den = 1625; @@ -533,15 +546,18 @@ static void __init realtime_counter_init(void) } /* Program numerator and denumerator registers */ - reg = __raw_readl(base + INCREMENTER_NUMERATOR_OFFSET) & + reg = readl_relaxed(base + INCREMENTER_NUMERATOR_OFFSET) & NUMERATOR_DENUMERATOR_MASK; reg |= num; - __raw_writel(reg, base + INCREMENTER_NUMERATOR_OFFSET); + writel_relaxed(reg, base + INCREMENTER_NUMERATOR_OFFSET); - reg = __raw_readl(base + INCREMENTER_NUMERATOR_OFFSET) & + reg = readl_relaxed(base + INCREMENTER_DENUMERATOR_RELOAD_OFFSET) & NUMERATOR_DENUMERATOR_MASK; reg |= den; - __raw_writel(reg, base + INCREMENTER_DENUMERATOR_RELOAD_OFFSET); + writel_relaxed(reg, base + INCREMENTER_DENUMERATOR_RELOAD_OFFSET); + + arch_timer_freq = (rate / den) * num; + set_cntfreq(); iounmap(base); } @@ -551,62 +567,59 @@ static inline void __init realtime_counter_init(void) #endif #define OMAP_SYS_GP_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop, \ - clksrc_nr, clksrc_src) \ -static void __init omap##name##_gptimer_timer_init(void) \ + clksrc_nr, clksrc_src, clksrc_prop) \ +void __init omap##name##_gptimer_timer_init(void) \ { \ + omap_clk_init(); \ omap_dmtimer_init(); \ omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \ - omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src); \ + omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src, \ + clksrc_prop); \ } #define OMAP_SYS_32K_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop, \ - clksrc_nr, clksrc_src) \ -static void __init omap##name##_sync32k_timer_init(void) \ + clksrc_nr, clksrc_src, clksrc_prop) \ +void __init omap##name##_sync32k_timer_init(void) \ { \ + omap_clk_init(); \ omap_dmtimer_init(); \ omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \ /* Enable the use of clocksource="gp_timer" kernel parameter */ \ if (use_gptimer_clksrc) \ - omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src);\ + omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src, \ + clksrc_prop); \ else \ omap2_sync32k_clocksource_init(); \ } -#define OMAP_SYS_TIMER(name, clksrc) \ -struct sys_timer omap##name##_timer = { \ - .init = omap##name##_##clksrc##_timer_init, \ -}; - #ifdef CONFIG_ARCH_OMAP2 -OMAP_SYS_32K_TIMER_INIT(2, 1, OMAP2_32K_SOURCE, "ti,timer-alwon", - 2, OMAP2_MPU_SOURCE); -OMAP_SYS_TIMER(2, sync32k); +OMAP_SYS_32K_TIMER_INIT(2, 1, "timer_32k_ck", "ti,timer-alwon", + 2, "timer_sys_ck", NULL); #endif /* CONFIG_ARCH_OMAP2 */ -#ifdef CONFIG_ARCH_OMAP3 -OMAP_SYS_32K_TIMER_INIT(3, 1, OMAP3_32K_SOURCE, "ti,timer-alwon", - 2, OMAP3_MPU_SOURCE); -OMAP_SYS_TIMER(3, sync32k); -OMAP_SYS_32K_TIMER_INIT(3_secure, 12, OMAP3_32K_SOURCE, "ti,timer-secure", - 2, OMAP3_MPU_SOURCE); -OMAP_SYS_TIMER(3_secure, sync32k); -OMAP_SYS_GP_TIMER_INIT(3_gp, 1, OMAP3_MPU_SOURCE, "ti,timer-alwon", - 2, OMAP3_MPU_SOURCE); -OMAP_SYS_TIMER(3_gp, gptimer); +#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM43XX) +OMAP_SYS_32K_TIMER_INIT(3, 1, "timer_32k_ck", "ti,timer-alwon", + 2, "timer_sys_ck", NULL); +OMAP_SYS_32K_TIMER_INIT(3_secure, 12, "secure_32k_fck", "ti,timer-secure", + 2, "timer_sys_ck", NULL); #endif /* CONFIG_ARCH_OMAP3 */ -#ifdef CONFIG_SOC_AM33XX -OMAP_SYS_GP_TIMER_INIT(3_am33xx, 1, OMAP4_MPU_SOURCE, "ti,timer-alwon", - 2, OMAP4_MPU_SOURCE); -OMAP_SYS_TIMER(3_am33xx, gptimer); -#endif /* CONFIG_SOC_AM33XX */ +#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM33XX) || \ + defined(CONFIG_SOC_AM43XX) +OMAP_SYS_GP_TIMER_INIT(3, 2, "timer_sys_ck", NULL, + 1, "timer_sys_ck", "ti,timer-alwon"); +#endif + +#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ + defined(CONFIG_SOC_DRA7XX) +static OMAP_SYS_32K_TIMER_INIT(4, 1, "timer_32k_ck", "ti,timer-alwon", + 2, "sys_clkin_ck", NULL); +#endif #ifdef CONFIG_ARCH_OMAP4 -OMAP_SYS_32K_TIMER_INIT(4, 1, OMAP4_32K_SOURCE, "ti,timer-alwon", - 2, OMAP4_MPU_SOURCE); -#ifdef CONFIG_LOCAL_TIMERS +#ifdef CONFIG_HAVE_ARM_TWD static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, OMAP44XX_LOCAL_TWD_BASE, 29); -static void __init omap4_local_timer_init(void) +void __init omap4_local_timer_init(void) { omap4_sync32k_timer_init(); /* Local timers are not supprted on OMAP4430 ES1.0 */ @@ -614,7 +627,7 @@ static void __init omap4_local_timer_init(void) int err; if (of_have_populated_dt()) { - twd_local_timer_of_register(); + clocksource_of_init(); return; } @@ -623,31 +636,23 @@ static void __init omap4_local_timer_init(void) pr_err("twd_local_timer_register failed %d\n", err); } } -#else /* CONFIG_LOCAL_TIMERS */ -static void __init omap4_local_timer_init(void) +#else +void __init omap4_local_timer_init(void) { omap4_sync32k_timer_init(); } -#endif /* CONFIG_LOCAL_TIMERS */ -OMAP_SYS_TIMER(4, local); +#endif /* CONFIG_HAVE_ARM_TWD */ #endif /* CONFIG_ARCH_OMAP4 */ -#ifdef CONFIG_SOC_OMAP5 -OMAP_SYS_32K_TIMER_INIT(5, 1, OMAP4_32K_SOURCE, "ti,timer-alwon", - 2, OMAP4_MPU_SOURCE); -static void __init omap5_realtime_timer_init(void) +#if defined(CONFIG_SOC_OMAP5) || defined(CONFIG_SOC_DRA7XX) +void __init omap5_realtime_timer_init(void) { - int err; - - omap5_sync32k_timer_init(); + omap4_sync32k_timer_init(); realtime_counter_init(); - err = arch_timer_of_register(); - if (err) - pr_err("%s: arch_timer_register failed %d\n", __func__, err); + clocksource_of_init(); } -OMAP_SYS_TIMER(5, realtime); -#endif /* CONFIG_SOC_OMAP5 */ +#endif /* CONFIG_SOC_OMAP5 || CONFIG_SOC_DRA7XX */ /** * omap_timer_init - build and register timer device with an @@ -702,8 +707,7 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused) 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), - NULL, 0, 0); + pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata)); if (IS_ERR(pdev)) { pr_err("%s: Can't build omap_device for %s: %s.\n", @@ -738,7 +742,7 @@ static int __init omap2_dm_timer_init(void) return 0; } -arch_initcall(omap2_dm_timer_init); +omap_arch_initcall(omap2_dm_timer_init); /** * omap2_override_clocksource - clocksource override with user configuration |
