mirror of
https://github.com/drasko/codezero.git
synced 2026-01-12 02:43:15 +01:00
Cleaned the timer driver to make it generic.
This commit is contained in:
@@ -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__ */
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user