Cleaned the timer driver to make it generic.

This commit is contained in:
Amit Mahajan
2009-10-24 21:02:47 +05:30
parent 24cbc8d441
commit 8a586860b3
7 changed files with 111 additions and 57 deletions

View File

@@ -9,19 +9,35 @@
#include INC_PLAT(platform.h)
#define SP804_TIMER01_BASE PLATFORM_TIMER_BASE
/* Run mode of timers */
#define SP804_TIMER_RUNMODE_FREERUN 0
#define SP804_TIMER_RUNMODE_PERIODIC 1
#define SP804_TIMER1LOAD (SP804_TIMER01_BASE + 0x0)
#define SP804_TIMER1VALUE (SP804_TIMER01_BASE + 0x4)
#define SP804_TIMER1CONTROL (SP804_TIMER01_BASE + 0x8)
#define SP804_TIMER1INTCLR (SP804_TIMER01_BASE + 0xC)
#define SP804_TIMER1RIS (SP804_TIMER01_BASE + 0x10)
#define SP804_TIMER1MIS (SP804_TIMER01_BASE + 0x14)
#define SP804_TIMER1BGLOAD (SP804_TIMER01_BASE + 0x18)
#define SP804_TIMER2OFFSET 0x20
/* Wrap mode of timers */
#define SP804_TIMER_WRAPMODE_WRAPPING 0
#define SP804_TIMER_WRAPMODE_ONESHOT 1
/* Operational width of timer */
#define SP804_TIMER_WIDTH16BIT 0
#define SP804_TIMER_WIDTH32BIT 1
/* Enable/disable irq on timer */
#define SP804_TIMER_IRQDISABLE 0
#define SP804_TIMER_IRQENABLE 1
/* Register offsets */
#define SP804_TIMERLOAD 0x0
#define SP804_TIMERVALUE 0x4
#define SP804_TIMERCONTROL 0x8
#define SP804_TIMERINTCLR 0xC
#define SP804_TIMERRIS 0x10
#define SP804_TIMERMIS 0x14
#define SP804_TIMERBGLOAD 0x18
void sp804_init(unsigned int timer_base, int runmode, int wrapmode, \
int width, int irq_enable);
void sp804_irq_handler(unsigned int timer_base);
void sp804_enable(unsigned int timer_base, int enable);
void sp804_set_irq(unsigned int timer_base, int enable);
void sp804_init(void);
void sp804_irq_handler(void);
void sp804_enable(int timer, int enable);
void sp804_set_irq(int timer, int enable);
#endif /* __SP804_TIMER_H__ */

View File

@@ -56,5 +56,6 @@
#define PB926_SYSCTRL_VBASE (IO_AREA0_VADDR + PB926_SYSCTRL_VOFFSET)
#define PB926_VIC_VBASE (IO_AREA0_VADDR + PB926_VIC_VOFFSET)
#define PB926_SIC_VBASE (IO_AREA0_VADDR + PB926_SIC_VOFFSET)
#endif /* __PLATFORM_PB926_OFFSETS_H__ */

View File

@@ -11,11 +11,22 @@
#include INC_GLUE(memlayout.h)
#define PLATFORM_CONSOLE_BASE PB926_UART0_VBASE
#define PLATFORM_TIMER_BASE PB926_TIMER01_VBASE
/* SP804 timer has TIMER1 at TIMER0 + 0x20 address */
#define PLATFORM_TIMER0_BASE PB926_TIMER01_VBASE
#define PLATFORM_SP810_BASE PB926_SYSCTRL_VBASE
#define PLATFORM_IRQCTRL_BASE PB926_VIC_VBASE
#define PLATFORM_SIRQCTRL_BASE PB926_SIC_VBASE
/* Total number of timers present in this platform */
#define TOTAL_TIMERS 4
#define PLATFORM_TIMER0 0
#define PLATFORM_TIMER1 1
#define PLATFORM_TIMER2 2
#define PLATFORM_TIMER3 3
void platform_irq_enable(int irq);
void platform_irq_disable(int irq);
void timer_start(void);

View File

@@ -4,6 +4,7 @@
* Copyright (C) 2007 Bahadir Balban
*/
#include <l4/drivers/timer/sp804/sp804_timer.h>
#include INC_PLAT(irq.h)
/* FIXME: Fix the shameful uart driver and change to single definition of this! */
#if defined(read)
@@ -17,91 +18,98 @@
#define write(v, a) (*((volatile unsigned int *)(a)) = v)
#define setbit(bit, a) write(read(a) | bit, a)
#define clrbit(bit, a) write(read(a) & ~bit, a)
#define devio(base, reg, bit, setclr) \
((setclr) ? setbit(bit, base + reg) \
#define devio(base, reg, bit, setclr) ((setclr) ? setbit(bit, base + reg) \
: clrbit(bit, base + reg))
void sp804_irq_handler(void)
void sp804_irq_handler(unsigned int timer_base)
{
/* Timer enabled as Periodic/Wrapper only needs irq clearing
* as it automatically reloads and wraps. */
write(1, SP804_TIMER1INTCLR);
/*
* Timer enabled as Periodic/Wrapper only needs irq clearing
* as it automatically reloads and wraps
*/
write(1, (timer_base + SP804_TIMERINTCLR));
}
static inline void sp804_control(int timer, int bit, int setclr)
static inline void sp804_control(unsigned int timer_base, int bit, int setclr)
{
unsigned long addr = SP804_TIMER1CONTROL + (timer ? SP804_TIMER2OFFSET : 0);
unsigned long addr = (timer_base + SP804_TIMERCONTROL);
setclr ? setbit(bit, addr) : clrbit(bit, addr);
}
/* Sets timer's run mode:
/*
* Sets timer's run mode:
* @periodic: periodic mode = 1, free-running = 0.
*/
#define SP804_PEREN (1 << 6)
static inline void sp804_set_runmode(int timer, int periodic)
static inline void sp804_set_runmode(unsigned int timer_base, int periodic)
{
sp804_control(timer, SP804_PEREN, periodic);
sp804_control(timer_base, SP804_PEREN, periodic);
}
/* Sets timer's wrapping mode:
/*
* Sets timer's wrapping mode:
* @oneshot: oneshot = 1, wrapping = 0.
*/
#define SP804_ONESHOT (1 << 0)
static inline void sp804_set_wrapmode(int timer, int oneshot)
static inline void sp804_set_wrapmode(unsigned int timer_base, int oneshot)
{
sp804_control(timer, SP804_ONESHOT, oneshot);
sp804_control(timer_base, SP804_ONESHOT, oneshot);
}
/* Sets the operational width of timers.
/*
* Sets the operational width of timers.
* In 16bit mode, top halfword is ignored.
* @width: 32bit mode = 1; 16bit mode = 0
*/
#define SP804_32BIT (1 << 1)
static inline void sp804_set_widthmode(int timer, int width)
static inline void sp804_set_widthmode(unsigned int timer_base, int width)
{
sp804_control(timer, SP804_32BIT, width);
sp804_control(timer_base, SP804_32BIT, width);
}
/* Enable/disable timer:
/*
* Enable/disable timer:
* @enable: enable = 1, disable = 0;
*/
#define SP804_ENABLE (1 << 7)
void sp804_enable(int timer, int enable)
void sp804_enable(unsigned int timer_base, int enable)
{
sp804_control(timer, SP804_ENABLE, enable);
sp804_control(timer_base, SP804_ENABLE, enable);
}
/* Enable/disable local irq register:
/*
* Enable/disable local irq register:
* @enable: enable = 1, disable = 0
*/
#define SP804_IRQEN (1 << 5)
void sp804_set_irq(int timer, int enable)
void sp804_set_irq(unsigned int timer_base, int enable)
{
sp804_control(timer, SP804_IRQEN, enable);
sp804_control(timer_base, SP804_IRQEN, enable);
}
/* Loads timer with value in val */
static inline void sp804_load_value(int timer, u32 val)
static inline void sp804_load_value(unsigned int timer_base, u32 val)
{
write(val, SP804_TIMER1LOAD + (timer ? SP804_TIMER2OFFSET : 0));
write(val, (timer_base + SP804_TIMERLOAD));
}
/* Returns current timer value */
static inline u32 sp804_read_value(int timer)
static inline u32 sp804_read_value(unsigned int timer_base)
{
return read(SP804_TIMER1VALUE + (timer ? SP804_TIMER2OFFSET : 0));
return read(timer_base + SP804_TIMERVALUE);
}
/* TODO: These are default settings! The values must be passed as arguments */
void sp804_init(void)
/* TODO: Define macro values for duration */
void sp804_init(unsigned int timer_base, int run_mode, int wrap_mode, \
int width, int irq_enable)
{
/* 1 tick per usec */
const int duration = 250;
sp804_set_runmode(0, 1); /* Periodic */
sp804_set_wrapmode(0, 0); /* Wrapping */
sp804_set_widthmode(0, 1); /* 32 bit */
sp804_set_irq(0, 1); /* Enable */
sp804_load_value(0, duration);
sp804_set_runmode(timer_base, run_mode); /* Periodic */
sp804_set_wrapmode(timer_base, wrap_mode); /* Wrapping */
sp804_set_widthmode(timer_base, width); /* 32 bit */
sp804_set_irq(timer_base, irq_enable); /* Enable */
sp804_load_value(timer_base, duration);
}

View File

@@ -41,12 +41,18 @@ struct irq_chip irq_chip_array[IRQ_CHIPS_MAX] = {
static int platform_timer_handler(void)
{
sp804_irq_handler();
/*
* Microkernel is using just TIMER0,
* so we call handler with TIMER01 index
*/
sp804_irq_handler(PLATFORM_TIMER0_BASE);
return do_timer_irq();
}
/* Built-in irq handlers initialised at compile time.
* Else register with register_irq() */
/*
* Built-in irq handlers initialised at compile time.
* Else register with register_irq()
*/
struct irq_desc irq_desc_array[IRQS_MAX] = {
[IRQ_TIMER01] = {
.name = "Timer01",

View File

@@ -37,8 +37,14 @@ void init_platform_console(void)
void init_platform_timer(void)
{
add_boot_mapping(PB926_TIMER01_BASE, PLATFORM_TIMER_BASE, PAGE_SIZE,
/*
* We are using TIMER0 only, so we map TIMER0 base,
* incase any other timer is needed we need to map it
* to userspace or kernel space as needed
*/
add_boot_mapping(PB926_TIMER01_BASE, PLATFORM_TIMER0_BASE, PAGE_SIZE,
MAP_IO_DEFAULT_FLAGS);
add_boot_mapping(PB926_SYSCTRL_BASE, PB926_SYSCTRL_VBASE, PAGE_SIZE,
MAP_IO_DEFAULT_FLAGS);
timer_init();

View File

@@ -10,19 +10,25 @@
#include <l4/drivers/timer/sp804/sp804_timer.h>
#include <l4/drivers/misc/sp810/sp810_sysctrl.h>
/* Microkernel is using TIMER0, so we will initialize only this one */
void timer_init(void)
{
/* Set timer 0 to 1MHz */
sp810_set_timclk(0, 1);
/* Set frequency of timer to 1MHz */
sp810_set_timclk(PLATFORM_TIMER0, 1);
/* Initialise timer */
sp804_init();
sp804_init(PLATFORM_TIMER0_BASE, SP804_TIMER_RUNMODE_PERIODIC, \
SP804_TIMER_WRAPMODE_WRAPPING, SP804_TIMER_WIDTH32BIT, \
SP804_TIMER_IRQENABLE);
}
/* Microkernel is using TIMER0, so we will initialize only this one */
void timer_start(void)
{
/* Enable irq line for TIMER0*/
irq_enable(IRQ_TIMER01);
sp804_set_irq(0, 1); /* Enable timer0 irq */
sp804_enable(0, 1); /* Enable timer0 */
/* Enable timer */
sp804_enable(PLATFORM_TIMER0_BASE, 1);
}