Commit b0c74b96 authored by Bartosz Golaszewski's avatar Bartosz Golaszewski Committed by Daniel Lezcano
Browse files

clocksource/drivers/davinci: Add support for clocksource



Extend the davinci-timer driver to also register a clock source.

Signed-off-by: default avatarBartosz Golaszewski <bgolaszewski@baylibre.com>
Signed-off-by: default avatarDaniel Lezcano <daniel.lezcano@linaro.org>
parent 721154f9
Loading
Loading
Loading
Loading
+85 −0
Original line number Diff line number Diff line
@@ -43,6 +43,8 @@
#define DAVINCI_TIMER_MIN_DELTA			0x01
#define DAVINCI_TIMER_MAX_DELTA			0xfffffffe

#define DAVINCI_TIMER_CLKSRC_BITS		32

#define DAVINCI_TIMER_TGCR_DEFAULT \
		(DAVINCI_TIMER_TIMMODE_32BIT_UNCHAINED | DAVINCI_TIMER_UNRESET)

@@ -52,6 +54,16 @@ struct davinci_clockevent {
	unsigned int cmp_off;
};

/*
 * This must be globally accessible by davinci_timer_read_sched_clock(), so
 * let's keep it here.
 */
static struct {
	struct clocksource dev;
	void __iomem *base;
	unsigned int tim_off;
} davinci_clocksource;

static struct davinci_clockevent *
to_davinci_clockevent(struct clock_event_device *clockevent)
{
@@ -166,6 +178,53 @@ static irqreturn_t davinci_timer_irq_timer(int irq, void *data)
	return IRQ_HANDLED;
}

static u64 notrace davinci_timer_read_sched_clock(void)
{
	return readl_relaxed(davinci_clocksource.base +
			     davinci_clocksource.tim_off);
}

static u64 davinci_clocksource_read(struct clocksource *dev)
{
	return davinci_timer_read_sched_clock();
}

/*
 * Standard use-case: we're using tim12 for clockevent and tim34 for
 * clocksource. The default is making the former run in oneshot mode
 * and the latter in periodic mode.
 */
static void davinci_clocksource_init_tim34(void __iomem *base)
{
	int tcr;

	tcr = DAVINCI_TIMER_ENAMODE_PERIODIC <<
		DAVINCI_TIMER_ENAMODE_SHIFT_TIM34;
	tcr |= DAVINCI_TIMER_ENAMODE_ONESHOT <<
		DAVINCI_TIMER_ENAMODE_SHIFT_TIM12;

	writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TIM34);
	writel_relaxed(UINT_MAX, base + DAVINCI_TIMER_REG_PRD34);
	writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR);
}

/*
 * Special use-case on da830: the DSP may use tim34. We're using tim12 for
 * both clocksource and clockevent. We set tim12 to periodic and don't touch
 * tim34.
 */
static void davinci_clocksource_init_tim12(void __iomem *base)
{
	unsigned int tcr;

	tcr = DAVINCI_TIMER_ENAMODE_PERIODIC <<
		DAVINCI_TIMER_ENAMODE_SHIFT_TIM12;

	writel_relaxed(0x0, base + DAVINCI_TIMER_REG_TIM12);
	writel_relaxed(UINT_MAX, base + DAVINCI_TIMER_REG_PRD12);
	writel_relaxed(tcr, base + DAVINCI_TIMER_REG_TCR);
}

static void davinci_timer_init(void __iomem *base)
{
	/* Set clock to internal mode and disable it. */
@@ -247,6 +306,32 @@ int __init davinci_timer_register(struct clk *clk,
					DAVINCI_TIMER_MIN_DELTA,
					DAVINCI_TIMER_MAX_DELTA);

	davinci_clocksource.dev.rating = 300;
	davinci_clocksource.dev.read = davinci_clocksource_read;
	davinci_clocksource.dev.mask =
			CLOCKSOURCE_MASK(DAVINCI_TIMER_CLKSRC_BITS);
	davinci_clocksource.dev.flags = CLOCK_SOURCE_IS_CONTINUOUS;
	davinci_clocksource.base = base;

	if (timer_cfg->cmp_off) {
		davinci_clocksource.dev.name = "tim12";
		davinci_clocksource.tim_off = DAVINCI_TIMER_REG_TIM12;
		davinci_clocksource_init_tim12(base);
	} else {
		davinci_clocksource.dev.name = "tim34";
		davinci_clocksource.tim_off = DAVINCI_TIMER_REG_TIM34;
		davinci_clocksource_init_tim34(base);
	}

	rv = clocksource_register_hz(&davinci_clocksource.dev, tick_rate);
	if (rv) {
		pr_err("Unable to register clocksource");
		return rv;
	}

	sched_clock_register(davinci_timer_read_sched_clock,
			     DAVINCI_TIMER_CLKSRC_BITS, tick_rate);

	return 0;
}