Commit 030caf3f authored by Olof Johansson's avatar Olof Johansson

Merge tag 'omap-cleanup-timer-for-v3.5' of...

Merge tag 'omap-cleanup-timer-for-v3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/cleanup2

Timer changes to make it easier to support various SoCs

By Vaibhav Hiremath
via Tony Lindgren
* tag 'omap-cleanup-timer-for-v3.5' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap:
  ARM: OMAP: Make OMAP clocksource source selection using kernel param
  ARM: OMAP2+: Replace space with underscore in the name field of system timers
  ARM: OMAP1: Add checks for possible error condition in timer_init
parents e2e9bbee 1fe97c8f
...@@ -57,7 +57,14 @@ void omap1_init_irq(void); ...@@ -57,7 +57,14 @@ void omap1_init_irq(void);
void omap1_restart(char, const char *); void omap1_restart(char, const char *);
extern struct sys_timer omap1_timer; extern struct sys_timer omap1_timer;
extern bool omap_32k_timer_init(void); #ifdef CONFIG_OMAP_32K_TIMER
extern int omap_32k_timer_init(void);
#else
static inline int __init omap_32k_timer_init(void)
{
return -ENODEV;
}
#endif
extern void __init omap_init_consistent_dma_size(void); extern void __init omap_init_consistent_dma_size(void);
#endif /* __ARCH_ARM_MACH_OMAP1_COMMON_H */ #endif /* __ARCH_ARM_MACH_OMAP1_COMMON_H */
...@@ -232,20 +232,6 @@ static inline void omap_mpu_timer_init(void) ...@@ -232,20 +232,6 @@ static inline void omap_mpu_timer_init(void)
} }
#endif /* CONFIG_OMAP_MPU_TIMER */ #endif /* CONFIG_OMAP_MPU_TIMER */
static inline int omap_32k_timer_usable(void)
{
int res = false;
if (cpu_is_omap730() || cpu_is_omap15xx())
return res;
#ifdef CONFIG_OMAP_32K_TIMER
res = omap_32k_timer_init();
#endif
return res;
}
/* /*
* --------------------------------------------------------------------------- * ---------------------------------------------------------------------------
* Timer initialization * Timer initialization
...@@ -253,7 +239,7 @@ static inline int omap_32k_timer_usable(void) ...@@ -253,7 +239,7 @@ static inline int omap_32k_timer_usable(void)
*/ */
static void __init omap1_timer_init(void) static void __init omap1_timer_init(void)
{ {
if (!omap_32k_timer_usable()) if (omap_32k_timer_init() != 0)
omap_mpu_timer_init(); omap_mpu_timer_init();
} }
......
...@@ -71,6 +71,7 @@ ...@@ -71,6 +71,7 @@
/* 16xx specific defines */ /* 16xx specific defines */
#define OMAP1_32K_TIMER_BASE 0xfffb9000 #define OMAP1_32K_TIMER_BASE 0xfffb9000
#define OMAP1_32KSYNC_TIMER_BASE 0xfffbc400
#define OMAP1_32K_TIMER_CR 0x08 #define OMAP1_32K_TIMER_CR 0x08
#define OMAP1_32K_TIMER_TVR 0x00 #define OMAP1_32K_TIMER_TVR 0x00
#define OMAP1_32K_TIMER_TCR 0x04 #define OMAP1_32K_TIMER_TCR 0x04
...@@ -182,10 +183,29 @@ static __init void omap_init_32k_timer(void) ...@@ -182,10 +183,29 @@ static __init void omap_init_32k_timer(void)
* Timer initialization * Timer initialization
* --------------------------------------------------------------------------- * ---------------------------------------------------------------------------
*/ */
bool __init omap_32k_timer_init(void) int __init omap_32k_timer_init(void)
{ {
omap_init_clocksource_32k(); int ret = -ENODEV;
if (cpu_is_omap16xx()) {
void __iomem *base;
struct clk *sync32k_ick;
base = ioremap(OMAP1_32KSYNC_TIMER_BASE, SZ_1K);
if (!base) {
pr_err("32k_counter: failed to map base addr\n");
return -ENODEV;
}
sync32k_ick = clk_get(NULL, "omap_32ksync_ick");
if (!IS_ERR(sync32k_ick))
clk_enable(sync32k_ick);
ret = omap_init_clocksource_32k(base);
}
if (!ret)
omap_init_32k_timer(); omap_init_32k_timer();
return true; return ret;
} }
...@@ -90,7 +90,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) ...@@ -90,7 +90,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
} }
static struct irqaction omap2_gp_timer_irq = { static struct irqaction omap2_gp_timer_irq = {
.name = "gp timer", .name = "gp_timer",
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = omap2_gp_timer_interrupt, .handler = omap2_gp_timer_interrupt,
}; };
...@@ -132,7 +132,7 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode, ...@@ -132,7 +132,7 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
} }
static struct clock_event_device clockevent_gpt = { static struct clock_event_device clockevent_gpt = {
.name = "gp timer", .name = "gp_timer",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.shift = 32, .shift = 32,
.set_next_event = omap2_gp_timer_set_next_event, .set_next_event = omap2_gp_timer_set_next_event,
...@@ -236,22 +236,8 @@ static void __init omap2_gp_clockevent_init(int gptimer_id, ...@@ -236,22 +236,8 @@ static void __init omap2_gp_clockevent_init(int gptimer_id,
} }
/* Clocksource code */ /* Clocksource code */
#ifdef CONFIG_OMAP_32K_TIMER
/*
* When 32k-timer is enabled, don't use GPTimer for clocksource
* instead, just leave default clocksource which uses the 32k
* sync counter. See clocksource setup in plat-omap/counter_32k.c
*/
static void __init omap2_gp_clocksource_init(int unused, const char *dummy)
{
omap_init_clocksource_32k();
}
#else
static struct omap_dm_timer clksrc; static struct omap_dm_timer clksrc;
static bool use_gptimer_clksrc;
/* /*
* clocksource * clocksource
...@@ -262,7 +248,7 @@ static cycle_t clocksource_read_cycles(struct clocksource *cs) ...@@ -262,7 +248,7 @@ static cycle_t clocksource_read_cycles(struct clocksource *cs)
} }
static struct clocksource clocksource_gpt = { static struct clocksource clocksource_gpt = {
.name = "gp timer", .name = "gp_timer",
.rating = 300, .rating = 300,
.read = clocksource_read_cycles, .read = clocksource_read_cycles,
.mask = CLOCKSOURCE_MASK(32), .mask = CLOCKSOURCE_MASK(32),
...@@ -278,7 +264,46 @@ static u32 notrace dmtimer_read_sched_clock(void) ...@@ -278,7 +264,46 @@ static u32 notrace dmtimer_read_sched_clock(void)
} }
/* Setup free-running counter for clocksource */ /* Setup free-running counter for clocksource */
static void __init omap2_gp_clocksource_init(int gptimer_id, static int __init omap2_sync32k_clocksource_init(void)
{
int ret;
struct omap_hwmod *oh;
void __iomem *vbase;
const char *oh_name = "counter_32k";
/*
* First check hwmod data is available for sync32k counter
*/
oh = omap_hwmod_lookup(oh_name);
if (!oh || oh->slaves_cnt == 0)
return -ENODEV;
omap_hwmod_setup_one(oh_name);
vbase = omap_hwmod_get_mpu_rt_va(oh);
if (!vbase) {
pr_warn("%s: failed to get counter_32k resource\n", __func__);
return -ENXIO;
}
ret = omap_hwmod_enable(oh);
if (ret) {
pr_warn("%s: failed to enable counter_32k module (%d)\n",
__func__, ret);
return ret;
}
ret = omap_init_clocksource_32k(vbase);
if (ret) {
pr_warn("%s: failed to initialize counter_32k as a clocksource (%d)\n",
__func__, ret);
omap_hwmod_idle(oh);
}
return ret;
}
static void __init omap2_gptimer_clocksource_init(int gptimer_id,
const char *fck_source) const char *fck_source)
{ {
int res; int res;
...@@ -286,9 +311,6 @@ static void __init omap2_gp_clocksource_init(int gptimer_id, ...@@ -286,9 +311,6 @@ static void __init omap2_gp_clocksource_init(int gptimer_id,
res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source); res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source);
BUG_ON(res); BUG_ON(res);
pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n",
gptimer_id, clksrc.rate);
__omap_dm_timer_load_start(&clksrc, __omap_dm_timer_load_start(&clksrc,
OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1); OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate); setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate);
...@@ -296,15 +318,36 @@ static void __init omap2_gp_clocksource_init(int gptimer_id, ...@@ -296,15 +318,36 @@ static void __init omap2_gp_clocksource_init(int gptimer_id,
if (clocksource_register_hz(&clocksource_gpt, clksrc.rate)) if (clocksource_register_hz(&clocksource_gpt, clksrc.rate))
pr_err("Could not register clocksource %s\n", pr_err("Could not register clocksource %s\n",
clocksource_gpt.name); clocksource_gpt.name);
else
pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n",
gptimer_id, clksrc.rate);
}
static void __init omap2_clocksource_init(int gptimer_id,
const char *fck_source)
{
/*
* First give preference to kernel parameter configuration
* by user (clocksource="gp_timer").
*
* In case of missing kernel parameter for clocksource,
* first check for availability for 32k-sync timer, in case
* of failure in finding 32k_counter module or registering
* it as clocksource, execution will fallback to gp-timer.
*/
if (use_gptimer_clksrc == true)
omap2_gptimer_clocksource_init(gptimer_id, fck_source);
else if (omap2_sync32k_clocksource_init())
/* Fall back to gp-timer code */
omap2_gptimer_clocksource_init(gptimer_id, fck_source);
} }
#endif
#define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src, \ #define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src, \
clksrc_nr, clksrc_src) \ clksrc_nr, clksrc_src) \
static void __init omap##name##_timer_init(void) \ static void __init omap##name##_timer_init(void) \
{ \ { \
omap2_gp_clockevent_init((clkev_nr), clkev_src); \ omap2_gp_clockevent_init((clkev_nr), clkev_src); \
omap2_gp_clocksource_init((clksrc_nr), clksrc_src); \ omap2_clocksource_init((clksrc_nr), clksrc_src); \
} }
#define OMAP_SYS_TIMER(name) \ #define OMAP_SYS_TIMER(name) \
...@@ -335,7 +378,7 @@ static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, ...@@ -335,7 +378,7 @@ static DEFINE_TWD_LOCAL_TIMER(twd_local_timer,
static void __init omap4_timer_init(void) static void __init omap4_timer_init(void)
{ {
omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE); omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE);
omap2_gp_clocksource_init(2, OMAP4_MPU_SOURCE); omap2_clocksource_init(2, OMAP4_MPU_SOURCE);
#ifdef CONFIG_LOCAL_TIMERS #ifdef CONFIG_LOCAL_TIMERS
/* Local timers are not supprted on OMAP4430 ES1.0 */ /* Local timers are not supprted on OMAP4430 ES1.0 */
if (omap_rev() != OMAP4430_REV_ES1_0) { if (omap_rev() != OMAP4430_REV_ES1_0) {
...@@ -503,3 +546,28 @@ static int __init omap2_dm_timer_init(void) ...@@ -503,3 +546,28 @@ static int __init omap2_dm_timer_init(void)
return 0; return 0;
} }
arch_initcall(omap2_dm_timer_init); arch_initcall(omap2_dm_timer_init);
/**
* omap2_override_clocksource - clocksource override with user configuration
*
* Allows user to override default clocksource, using kernel parameter
* clocksource="gp_timer" (For all OMAP2PLUS architectures)
*
* Note that, here we are using same standard kernel parameter "clocksource=",
* and not introducing any OMAP specific interface.
*/
static int __init omap2_override_clocksource(char *str)
{
if (!str)
return 0;
/*
* For OMAP architecture, we only have two options
* - sync_32k (default)
* - gp_timer (sys_clk based)
*/
if (!strcmp(str, "gp_timer"))
use_gptimer_clksrc = true;
return 0;
}
early_param("clocksource", omap2_override_clocksource);
...@@ -27,19 +27,20 @@ ...@@ -27,19 +27,20 @@
#include <plat/clock.h> #include <plat/clock.h>
/* OMAP2_32KSYNCNT_CR_OFF: offset of 32ksync counter register */
#define OMAP2_32KSYNCNT_CR_OFF 0x10
/* /*
* 32KHz clocksource ... always available, on pretty most chips except * 32KHz clocksource ... always available, on pretty most chips except
* OMAP 730 and 1510. Other timers could be used as clocksources, with * OMAP 730 and 1510. Other timers could be used as clocksources, with
* higher resolution in free-running counter modes (e.g. 12 MHz xtal), * higher resolution in free-running counter modes (e.g. 12 MHz xtal),
* but systems won't necessarily want to spend resources that way. * but systems won't necessarily want to spend resources that way.
*/ */
static void __iomem *timer_32k_base; static void __iomem *sync32k_cnt_reg;
#define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410
static u32 notrace omap_32k_read_sched_clock(void) static u32 notrace omap_32k_read_sched_clock(void)
{ {
return timer_32k_base ? __raw_readl(timer_32k_base) : 0; return sync32k_cnt_reg ? __raw_readl(sync32k_cnt_reg) : 0;
} }
/** /**
...@@ -59,7 +60,7 @@ void read_persistent_clock(struct timespec *ts) ...@@ -59,7 +60,7 @@ void read_persistent_clock(struct timespec *ts)
struct timespec *tsp = &persistent_ts; struct timespec *tsp = &persistent_ts;
last_cycles = cycles; last_cycles = cycles;
cycles = timer_32k_base ? __raw_readl(timer_32k_base) : 0; cycles = sync32k_cnt_reg ? __raw_readl(sync32k_cnt_reg) : 0;
delta = cycles - last_cycles; delta = cycles - last_cycles;
nsecs = clocksource_cyc2ns(delta, persistent_mult, persistent_shift); nsecs = clocksource_cyc2ns(delta, persistent_mult, persistent_shift);
...@@ -68,41 +69,23 @@ void read_persistent_clock(struct timespec *ts) ...@@ -68,41 +69,23 @@ void read_persistent_clock(struct timespec *ts)
*ts = *tsp; *ts = *tsp;
} }
int __init omap_init_clocksource_32k(void) /**
* omap_init_clocksource_32k - setup and register counter 32k as a
* kernel clocksource
* @pbase: base addr of counter_32k module
* @size: size of counter_32k to map
*
* Returns 0 upon success or negative error code upon failure.
*
*/
int __init omap_init_clocksource_32k(void __iomem *vbase)
{ {
static char err[] __initdata = KERN_ERR int ret;
"%s: can't register clocksource!\n";
/*
if (cpu_is_omap16xx() || cpu_class_is_omap2()) { * 32k sync Counter register offset is at 0x10
u32 pbase; */
unsigned long size = SZ_4K; sync32k_cnt_reg = vbase + OMAP2_32KSYNCNT_CR_OFF;
void __iomem *base;
struct clk *sync_32k_ick;
if (cpu_is_omap16xx()) {
pbase = OMAP16XX_TIMER_32K_SYNCHRONIZED;
size = SZ_1K;
} else if (cpu_is_omap2420())
pbase = OMAP2420_32KSYNCT_BASE + 0x10;
else if (cpu_is_omap2430())
pbase = OMAP2430_32KSYNCT_BASE + 0x10;
else if (cpu_is_omap34xx())
pbase = OMAP3430_32KSYNCT_BASE + 0x10;
else if (cpu_is_omap44xx())
pbase = OMAP4430_32KSYNCT_BASE + 0x10;
else
return -ENODEV;
/* For this to work we must have a static mapping in io.c for this area */
base = ioremap(pbase, size);
if (!base)
return -ENODEV;
sync_32k_ick = clk_get(NULL, "omap_32ksync_ick");
if (!IS_ERR(sync_32k_ick))
clk_enable(sync_32k_ick);
timer_32k_base = base;
/* /*
* 120000 rough estimate from the calculations in * 120000 rough estimate from the calculations in
...@@ -111,11 +94,15 @@ int __init omap_init_clocksource_32k(void) ...@@ -111,11 +94,15 @@ int __init omap_init_clocksource_32k(void)
clocks_calc_mult_shift(&persistent_mult, &persistent_shift, clocks_calc_mult_shift(&persistent_mult, &persistent_shift,
32768, NSEC_PER_SEC, 120000); 32768, NSEC_PER_SEC, 120000);
if (clocksource_mmio_init(base, "32k_counter", 32768, 250, 32, ret = clocksource_mmio_init(sync32k_cnt_reg, "32k_counter", 32768,
clocksource_mmio_readl_up)) 250, 32, clocksource_mmio_readl_up);
printk(err, "32k_counter"); if (ret) {
pr_err("32k_counter: can't register clocksource\n");
return ret;
}
setup_sched_clock(omap_32k_read_sched_clock, 32, 32768); setup_sched_clock(omap_32k_read_sched_clock, 32, 32768);
} pr_info("OMAP clocksource: 32k_counter at 32768 Hz\n");
return 0; return 0;
} }
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include <plat/i2c.h> #include <plat/i2c.h>
#include <plat/omap_hwmod.h> #include <plat/omap_hwmod.h>
extern int __init omap_init_clocksource_32k(void); extern int __init omap_init_clocksource_32k(void __iomem *vbase);
extern void omap_reserve(void); extern void omap_reserve(void);
extern int omap_dss_reset(struct omap_hwmod *); extern int omap_dss_reset(struct omap_hwmod *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment