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

Commit b720f732 authored by Russell King's avatar Russell King Committed by Russell King
Browse files

[PATCH] ARM: Convert ARM timer implementations to use readl/writel



Convert ARMs timer implementations to use readl/writel instead of accessing
the registers via a struct.

People have recently asked if accessing timers via a structure is the
"right way" and its not the Linux way.  So fix this code to conform to
"The Linux Way"(tm).

Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
Acked-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
parent 6904b246
Loading
Loading
Loading
Loading
+14 −28
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/hardware/amba.h>
#include <asm/hardware/arm_timer.h>
#include <asm/arch/cm.h>
#include <asm/system.h>
#include <asm/leds.h>
@@ -156,16 +157,6 @@ EXPORT_SYMBOL(cm_control);
#define TICKS2USECS(x)	((x) / TICKS_PER_uSEC)
#endif

/*
 * What does it look like?
 */
typedef struct TimerStruct {
	unsigned long TimerLoad;
	unsigned long TimerValue;
	unsigned long TimerControl;
	unsigned long TimerClear;
} TimerStruct_t;

static unsigned long timer_reload;

/*
@@ -174,7 +165,6 @@ static unsigned long timer_reload;
 */
unsigned long integrator_gettimeoffset(void)
{
	volatile TimerStruct_t *timer1 = (TimerStruct_t *)TIMER1_VA_BASE;
	unsigned long ticks1, ticks2, status;

	/*
@@ -183,11 +173,11 @@ unsigned long integrator_gettimeoffset(void)
	 * an interrupt.  We get around this by ensuring that the
	 * counter has not reloaded between our two reads.
	 */
	ticks2 = timer1->TimerValue & 0xffff;
	ticks2 = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff;
	do {
		ticks1 = ticks2;
		status = __raw_readl(VA_IC_BASE + IRQ_RAW_STATUS);
		ticks2 = timer1->TimerValue & 0xffff;
		ticks2 = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff;
	} while (ticks2 > ticks1);

	/*
@@ -213,20 +203,19 @@ unsigned long integrator_gettimeoffset(void)
static irqreturn_t
integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
	volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;

	write_seqlock(&xtime_lock);

	/*
	 * clear the interrupt
	 */
	timer1->TimerClear = 1;
	writel(1, TIMER1_VA_BASE + TIMER_INTCLR);

	/*
	 * the clock tick routines are only processed on the
	 * primary CPU
	 */
	if (hard_smp_processor_id() == 0) {
		nmi_tick();
		timer_tick(regs);
#ifdef CONFIG_SMP
		smp_send_timer();
@@ -256,32 +245,29 @@ static struct irqaction integrator_timer_irq = {
 */
void __init integrator_time_init(unsigned long reload, unsigned int ctrl)
{
	volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE;
	volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
	volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE;
	unsigned int timer_ctrl = 0x80 | 0x40;	/* periodic */
	unsigned int timer_ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;

	timer_reload = reload;
	timer_ctrl |= ctrl;

	if (timer_reload > 0x100000) {
		timer_reload >>= 8;
		timer_ctrl |= 0x08; /* /256 */
		timer_ctrl |= TIMER_CTRL_DIV256;
	} else if (timer_reload > 0x010000) {
		timer_reload >>= 4;
		timer_ctrl |= 0x04; /* /16 */
		timer_ctrl |= TIMER_CTRL_DIV16;
	}

	/*
	 * Initialise to a known state (all timers off)
	 */
	timer0->TimerControl = 0;
	timer1->TimerControl = 0;
	timer2->TimerControl = 0;
	writel(0, TIMER0_VA_BASE + TIMER_CTRL);
	writel(0, TIMER1_VA_BASE + TIMER_CTRL);
	writel(0, TIMER2_VA_BASE + TIMER_CTRL);

	timer1->TimerLoad    = timer_reload;
	timer1->TimerValue   = timer_reload;
	timer1->TimerControl = timer_ctrl;
	writel(timer_reload, TIMER1_VA_BASE + TIMER_LOAD);
	writel(timer_reload, TIMER1_VA_BASE + TIMER_VALUE);
	writel(timer_ctrl, TIMER1_VA_BASE + TIMER_CTRL);

	/*
	 * Make irqs happen for the system timer
+24 −37
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#include <asm/mach-types.h>
#include <asm/hardware/amba.h>
#include <asm/hardware/amba_clcd.h>
#include <asm/hardware/arm_timer.h>
#include <asm/hardware/icst307.h>

#include <asm/mach/arch.h>
@@ -788,38 +789,25 @@ void __init versatile_init(void)
 */
#define TIMER_INTERVAL	(TICKS_PER_uSEC * mSEC_10)
#if TIMER_INTERVAL >= 0x100000
#define TIMER_RELOAD	(TIMER_INTERVAL >> 8)		/* Divide by 256 */
#define TIMER_CTRL	0x88				/* Enable, Clock / 256 */
#define TIMER_RELOAD	(TIMER_INTERVAL >> 8)
#define TIMER_DIVISOR	(TIMER_CTRL_DIV256)
#define TICKS2USECS(x)	(256 * (x) / TICKS_PER_uSEC)
#elif TIMER_INTERVAL >= 0x10000
#define TIMER_RELOAD	(TIMER_INTERVAL >> 4)		/* Divide by 16 */
#define TIMER_CTRL	0x84				/* Enable, Clock / 16 */
#define TIMER_DIVISOR	(TIMER_CTRL_DIV16)
#define TICKS2USECS(x)	(16 * (x) / TICKS_PER_uSEC)
#else
#define TIMER_RELOAD	(TIMER_INTERVAL)
#define TIMER_CTRL	0x80				/* Enable */
#define TIMER_DIVISOR	(TIMER_CTRL_DIV1)
#define TICKS2USECS(x)	((x) / TICKS_PER_uSEC)
#endif

#define TIMER_CTRL_IE	(1 << 5)	/* Interrupt Enable */

/*
 * What does it look like?
 */
typedef struct TimerStruct {
	unsigned long TimerLoad;
	unsigned long TimerValue;
	unsigned long TimerControl;
	unsigned long TimerClear;
} TimerStruct_t;

/*
 * Returns number of ms since last clock interrupt.  Note that interrupts
 * will have been disabled by do_gettimeoffset()
 */
static unsigned long versatile_gettimeoffset(void)
{
	volatile TimerStruct_t *timer0 = (TimerStruct_t *)TIMER0_VA_BASE;
	unsigned long ticks1, ticks2, status;

	/*
@@ -828,11 +816,11 @@ static unsigned long versatile_gettimeoffset(void)
	 * an interrupt.  We get around this by ensuring that the
	 * counter has not reloaded between our two reads.
	 */
	ticks2 = timer0->TimerValue & 0xffff;
	ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
	do {
		ticks1 = ticks2;
		status = __raw_readl(VA_IC_BASE + VIC_IRQ_RAW_STATUS);
		ticks2 = timer0->TimerValue & 0xffff;
		ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
	} while (ticks2 > ticks1);

	/*
@@ -859,12 +847,10 @@ static unsigned long versatile_gettimeoffset(void)
 */
static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
	volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE;

	write_seqlock(&xtime_lock);

	// ...clear the interrupt
	timer0->TimerClear = 1;
	writel(1, TIMER0_VA_BASE + TIMER_INTCLR);

	timer_tick(regs);

@@ -884,31 +870,32 @@ static struct irqaction versatile_timer_irq = {
 */
static void __init versatile_timer_init(void)
{
	volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE;
	volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
	volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE;
	volatile TimerStruct_t *timer3 = (volatile TimerStruct_t *)TIMER3_VA_BASE;
	u32 val;

	/* 
	 * set clock frequency: 
	 *	VERSATILE_REFCLK is 32KHz
	 *	VERSATILE_TIMCLK is 1MHz
	 */
	*(volatile unsigned int *)IO_ADDRESS(VERSATILE_SCTL_BASE) |= 
	  ((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) | 
	   (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel));
	val = readl(IO_ADDRESS(VERSATILE_SCTL_BASE));
	writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) |
	       (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) | 
	       (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) |
	       (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val,
	       IO_ADDRESS(VERSATILE_SCTL_BASE));

	/*
	 * Initialise to a known state (all timers off)
	 */
	timer0->TimerControl = 0;
	timer1->TimerControl = 0;
	timer2->TimerControl = 0;
	timer3->TimerControl = 0;

	timer0->TimerLoad    = TIMER_RELOAD;
	timer0->TimerValue   = TIMER_RELOAD;
	timer0->TimerControl = TIMER_CTRL | 0x40 | TIMER_CTRL_IE;  /* periodic + IE */
	writel(0, TIMER0_VA_BASE + TIMER_CTRL);
	writel(0, TIMER1_VA_BASE + TIMER_CTRL);
	writel(0, TIMER2_VA_BASE + TIMER_CTRL);
	writel(0, TIMER3_VA_BASE + TIMER_CTRL);

	writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD);
	writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_VALUE);
	writel(TIMER_DIVISOR | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC |
	       TIMER_CTRL_IE, TIMER0_VA_BASE + TIMER_CTRL);

	/* 
	 * Make irqs happen for the system timer
+21 −0
Original line number Diff line number Diff line
#ifndef __ASM_ARM_HARDWARE_ARM_TIMER_H
#define __ASM_ARM_HARDWARE_ARM_TIMER_H

#define TIMER_LOAD	0x00
#define TIMER_VALUE	0x04
#define TIMER_CTRL	0x08
#define TIMER_CTRL_ONESHOT	(1 << 0)
#define TIMER_CTRL_32BIT	(1 << 1)
#define TIMER_CTRL_DIV1		(0 << 2)
#define TIMER_CTRL_DIV16	(1 << 2)
#define TIMER_CTRL_DIV256	(2 << 2)
#define TIMER_CTRL_IE		(1 << 5)	/* Interrupt Enable (versatile only) */
#define TIMER_CTRL_PERIODIC	(1 << 6)
#define TIMER_CTRL_ENABLE	(1 << 7)

#define TIMER_INTCLR	0x0c
#define TIMER_RIS	0x10
#define TIMER_MIS	0x14
#define TIMER_BGLOAD	0x18

#endif