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:
commit
030caf3f22
@ -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 */
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
Loading…
Reference in New Issue
Block a user