Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -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 */
+1 −15
Original line number Diff line number Diff line
@@ -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();
}

+24 −4
Original line number Diff line number Diff line
@@ -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();
	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();

	return true;
	return ret;
}
+93 −25
Original line number Diff line number Diff line
@@ -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);
+39 −52
Original line number Diff line number Diff line
@@ -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,41 +69,23 @@ 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";

	if (cpu_is_omap16xx() || cpu_class_is_omap2()) {
		u32 pbase;
		unsigned long size = SZ_4K;
		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;
	int ret;

	/*
	 * 32k sync Counter register offset is at 0x10
	 */
	sync32k_cnt_reg = vbase + OMAP2_32KSYNCNT_CR_OFF;

	/*
	 * 120000 rough estimate from the calculations in
@@ -111,11 +94,15 @@ int __init omap_init_clocksource_32k(void)
	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");
	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;
}
Loading