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 Original line Diff line number Diff line
@@ -20,6 +20,7 @@
#include <asm/irq.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/io.h>
#include <asm/hardware/amba.h>
#include <asm/hardware/amba.h>
#include <asm/hardware/arm_timer.h>
#include <asm/arch/cm.h>
#include <asm/arch/cm.h>
#include <asm/system.h>
#include <asm/system.h>
#include <asm/leds.h>
#include <asm/leds.h>
@@ -156,16 +157,6 @@ EXPORT_SYMBOL(cm_control);
#define TICKS2USECS(x)	((x) / TICKS_PER_uSEC)
#define TICKS2USECS(x)	((x) / TICKS_PER_uSEC)
#endif
#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;
static unsigned long timer_reload;


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


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


	/*
	/*
@@ -213,20 +203,19 @@ unsigned long integrator_gettimeoffset(void)
static irqreturn_t
static irqreturn_t
integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
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);
	write_seqlock(&xtime_lock);


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


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


	timer_reload = reload;
	timer_reload = reload;
	timer_ctrl |= ctrl;
	timer_ctrl |= ctrl;


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


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


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


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


#include <asm/mach/arch.h>
#include <asm/mach/arch.h>
@@ -788,38 +789,25 @@ void __init versatile_init(void)
 */
 */
#define TIMER_INTERVAL	(TICKS_PER_uSEC * mSEC_10)
#define TIMER_INTERVAL	(TICKS_PER_uSEC * mSEC_10)
#if TIMER_INTERVAL >= 0x100000
#if TIMER_INTERVAL >= 0x100000
#define TIMER_RELOAD	(TIMER_INTERVAL >> 8)		/* Divide by 256 */
#define TIMER_RELOAD	(TIMER_INTERVAL >> 8)
#define TIMER_CTRL	0x88				/* Enable, Clock / 256 */
#define TIMER_DIVISOR	(TIMER_CTRL_DIV256)
#define TICKS2USECS(x)	(256 * (x) / TICKS_PER_uSEC)
#define TICKS2USECS(x)	(256 * (x) / TICKS_PER_uSEC)
#elif TIMER_INTERVAL >= 0x10000
#elif TIMER_INTERVAL >= 0x10000
#define TIMER_RELOAD	(TIMER_INTERVAL >> 4)		/* Divide by 16 */
#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)
#define TICKS2USECS(x)	(16 * (x) / TICKS_PER_uSEC)
#else
#else
#define TIMER_RELOAD	(TIMER_INTERVAL)
#define TIMER_RELOAD	(TIMER_INTERVAL)
#define TIMER_CTRL	0x80				/* Enable */
#define TIMER_DIVISOR	(TIMER_CTRL_DIV1)
#define TICKS2USECS(x)	((x) / TICKS_PER_uSEC)
#define TICKS2USECS(x)	((x) / TICKS_PER_uSEC)
#endif
#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
 * Returns number of ms since last clock interrupt.  Note that interrupts
 * will have been disabled by do_gettimeoffset()
 * will have been disabled by do_gettimeoffset()
 */
 */
static unsigned long versatile_gettimeoffset(void)
static unsigned long versatile_gettimeoffset(void)
{
{
	volatile TimerStruct_t *timer0 = (TimerStruct_t *)TIMER0_VA_BASE;
	unsigned long ticks1, ticks2, status;
	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
	 * an interrupt.  We get around this by ensuring that the
	 * counter has not reloaded between our two reads.
	 * counter has not reloaded between our two reads.
	 */
	 */
	ticks2 = timer0->TimerValue & 0xffff;
	ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
	do {
	do {
		ticks1 = ticks2;
		ticks1 = ticks2;
		status = __raw_readl(VA_IC_BASE + VIC_IRQ_RAW_STATUS);
		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);
	} 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)
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);
	write_seqlock(&xtime_lock);


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


	timer_tick(regs);
	timer_tick(regs);


@@ -884,31 +870,32 @@ static struct irqaction versatile_timer_irq = {
 */
 */
static void __init versatile_timer_init(void)
static void __init versatile_timer_init(void)
{
{
	volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE;
	u32 val;
	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;


	/* 
	/* 
	 * set clock frequency: 
	 * set clock frequency: 
	 *	VERSATILE_REFCLK is 32KHz
	 *	VERSATILE_REFCLK is 32KHz
	 *	VERSATILE_TIMCLK is 1MHz
	 *	VERSATILE_TIMCLK is 1MHz
	 */
	 */
	*(volatile unsigned int *)IO_ADDRESS(VERSATILE_SCTL_BASE) |= 
	val = readl(IO_ADDRESS(VERSATILE_SCTL_BASE));
	  ((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) | 
	writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) |
	   (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER4_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)
	 * Initialise to a known state (all timers off)
	 */
	 */
	timer0->TimerControl = 0;
	writel(0, TIMER0_VA_BASE + TIMER_CTRL);
	timer1->TimerControl = 0;
	writel(0, TIMER1_VA_BASE + TIMER_CTRL);
	timer2->TimerControl = 0;
	writel(0, TIMER2_VA_BASE + TIMER_CTRL);
	timer3->TimerControl = 0;
	writel(0, TIMER3_VA_BASE + TIMER_CTRL);


	timer0->TimerLoad    = TIMER_RELOAD;
	writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD);
	timer0->TimerValue   = TIMER_RELOAD;
	writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_VALUE);
	timer0->TimerControl = TIMER_CTRL | 0x40 | TIMER_CTRL_IE;  /* periodic + IE */
	writel(TIMER_DIVISOR | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC |
	       TIMER_CTRL_IE, TIMER0_VA_BASE + TIMER_CTRL);


	/* 
	/* 
	 * Make irqs happen for the system timer
	 * Make irqs happen for the system timer
+21 −0
Original line number Original line 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