Timer changes to make it easier to support various SoCs

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJPqwArAAoJEBvUPslcq6Vz0KMP+wWpRkFC+Retu1O1Lxy00Ea4
 Zjg5wVfYGLuDAJf3i0xFKcDZA8AfDJws/kHi4sC0cbP296AfHqz7I25gKZqPoXf4
 Y6iDRU/qLlO8djhJh7i+OP7/A4IlgMtOlMWJEZXrmhvuHRI5VusfpU/2p802yvFR
 xn3oWJrQ1WtE+vvNo9sK67HXLogt+49r83XGWNY66WGePKTpBf/LD+wN7zsCVaW2
 xK6vqg6Z/jq8naS6WN9+zdhqgB8huULM9RX/FcOmV8hgm9oSJrqzxHIB9jyVvjXQ
 OMTz7WjHlakkneYBWxEGCsF8I4w5PJIXOav1OACvrsERKZpPJ0AmvYW05ZusJwLC
 XWuYER9v+IJG1zzym7SBa/jIkGWrCKrQKxERvi8MD9NUl2y33flGzS89Hvm9Zjap
 TO5U2yXIADqL83zHhtkgmWT6isHnFbQcwbc2Nz+oh/0Tnm2vrwRf88jxeFVX0k7D
 l9A+XgPpUeoVEdyFtb1Gt++xojuwgEjZWKHuMfS+fJrj3WwolC2MLAVW6pDsTTQd
 AERUuOHMgzODQ2Jx1rnljTAh57+3gVkw2iICtrWzecbbqHb6bOiB/sRN1KK+oQKh
 CDiH2TzibDL1T+WDLFHBJTx0eTbRiQjViYaYtgM28k3r+wlNNRbf7WTU8PjA7AZp
 rd/0s6+c+/kI4BcRVVF/
 =ALlA
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Olof Johansson 2012-05-10 23:46:06 -07:00
commit 030caf3f22
6 changed files with 163 additions and 95 deletions

View File

@ -57,7 +57,14 @@ void omap1_init_irq(void);
void omap1_restart(char, const char *);
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);
#endif /* __ARCH_ARM_MACH_OMAP1_COMMON_H */

View File

@ -232,20 +232,6 @@ static inline void omap_mpu_timer_init(void)
}
#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
@ -253,7 +239,7 @@ static inline int omap_32k_timer_usable(void)
*/
static void __init omap1_timer_init(void)
{
if (!omap_32k_timer_usable())
if (omap_32k_timer_init() != 0)
omap_mpu_timer_init();
}

View File

@ -71,6 +71,7 @@
/* 16xx specific defines */
#define OMAP1_32K_TIMER_BASE 0xfffb9000
#define OMAP1_32KSYNC_TIMER_BASE 0xfffbc400
#define OMAP1_32K_TIMER_CR 0x08
#define OMAP1_32K_TIMER_TVR 0x00
#define OMAP1_32K_TIMER_TCR 0x04
@ -182,10 +183,29 @@ static __init void omap_init_32k_timer(void)
* Timer initialization
* ---------------------------------------------------------------------------
*/
bool __init omap_32k_timer_init(void)
int __init omap_32k_timer_init(void)
{
omap_init_clocksource_32k();
omap_init_32k_timer();
int ret = -ENODEV;
return true;
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();
return ret;
}

View File

@ -90,7 +90,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
}
static struct irqaction omap2_gp_timer_irq = {
.name = "gp timer",
.name = "gp_timer",
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = omap2_gp_timer_interrupt,
};
@ -132,7 +132,7 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
}
static struct clock_event_device clockevent_gpt = {
.name = "gp timer",
.name = "gp_timer",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.shift = 32,
.set_next_event = omap2_gp_timer_set_next_event,
@ -236,22 +236,8 @@ static void __init omap2_gp_clockevent_init(int gptimer_id,
}
/* 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 bool use_gptimer_clksrc;
/*
* clocksource
@ -262,7 +248,7 @@ static cycle_t clocksource_read_cycles(struct clocksource *cs)
}
static struct clocksource clocksource_gpt = {
.name = "gp timer",
.name = "gp_timer",
.rating = 300,
.read = clocksource_read_cycles,
.mask = CLOCKSOURCE_MASK(32),
@ -278,7 +264,46 @@ static u32 notrace dmtimer_read_sched_clock(void)
}
/* 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)
{
int res;
@ -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);
BUG_ON(res);
pr_info("OMAP clocksource: GPTIMER%d at %lu Hz\n",
gptimer_id, clksrc.rate);
__omap_dm_timer_load_start(&clksrc,
OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1);
setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate);
@ -296,15 +318,36 @@ static void __init omap2_gp_clocksource_init(int gptimer_id,
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);
}
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, \
clksrc_nr, clksrc_src) \
static void __init omap##name##_timer_init(void) \
{ \
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) \
@ -335,7 +378,7 @@ static DEFINE_TWD_LOCAL_TIMER(twd_local_timer,
static void __init omap4_timer_init(void)
{
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
/* Local timers are not supprted on OMAP4430 ES1.0 */
if (omap_rev() != OMAP4430_REV_ES1_0) {
@ -503,3 +546,28 @@ static int __init omap2_dm_timer_init(void)
return 0;
}
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);

View File

@ -27,19 +27,20 @@
#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
* OMAP 730 and 1510. Other timers could be used as clocksources, with
* higher resolution in free-running counter modes (e.g. 12 MHz xtal),
* but systems won't necessarily want to spend resources that way.
*/
static void __iomem *timer_32k_base;
#define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410
static void __iomem *sync32k_cnt_reg;
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)
struct timespec *tsp = &persistent_ts;
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;
nsecs = clocksource_cyc2ns(delta, persistent_mult, persistent_shift);
@ -68,54 +69,40 @@ void read_persistent_clock(struct timespec *ts)
*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
"%s: can't register clocksource!\n";
int ret;
if (cpu_is_omap16xx() || cpu_class_is_omap2()) {
u32 pbase;
unsigned long size = SZ_4K;
void __iomem *base;
struct clk *sync_32k_ick;
/*
* 32k sync Counter register offset is at 0x10
*/
sync32k_cnt_reg = vbase + OMAP2_32KSYNCNT_CR_OFF;
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;
/*
* 120000 rough estimate from the calculations in
* __clocksource_updatefreq_scale.
*/
clocks_calc_mult_shift(&persistent_mult, &persistent_shift,
32768, NSEC_PER_SEC, 120000);
/* 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
* __clocksource_updatefreq_scale.
*/
clocks_calc_mult_shift(&persistent_mult, &persistent_shift,
32768, NSEC_PER_SEC, 120000);
if (clocksource_mmio_init(base, "32k_counter", 32768, 250, 32,
clocksource_mmio_readl_up))
printk(err, "32k_counter");
setup_sched_clock(omap_32k_read_sched_clock, 32, 32768);
ret = clocksource_mmio_init(sync32k_cnt_reg, "32k_counter", 32768,
250, 32, clocksource_mmio_readl_up);
if (ret) {
pr_err("32k_counter: can't register clocksource\n");
return ret;
}
setup_sched_clock(omap_32k_read_sched_clock, 32, 32768);
pr_info("OMAP clocksource: 32k_counter at 32768 Hz\n");
return 0;
}

View File

@ -30,7 +30,7 @@
#include <plat/i2c.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 int omap_dss_reset(struct omap_hwmod *);