diff --git a/include/l4/drivers/timer/sp804/sp804_timer.h b/include/l4/drivers/timer/sp804/sp804_timer.h index d97d225..7039418 100644 --- a/include/l4/drivers/timer/sp804/sp804_timer.h +++ b/include/l4/drivers/timer/sp804/sp804_timer.h @@ -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__ */ diff --git a/include/l4/platform/pb926/offsets.h b/include/l4/platform/pb926/offsets.h index 4a49729..4a94b14 100644 --- a/include/l4/platform/pb926/offsets.h +++ b/include/l4/platform/pb926/offsets.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__ */ diff --git a/include/l4/platform/pb926/platform.h b/include/l4/platform/pb926/platform.h index dd4f4cb..cc15903 100644 --- a/include/l4/platform/pb926/platform.h +++ b/include/l4/platform/pb926/platform.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); diff --git a/src/drivers/timer/sp804/sp804_timer.c b/src/drivers/timer/sp804/sp804_timer.c index 573594c..e810f46 100644 --- a/src/drivers/timer/sp804/sp804_timer.c +++ b/src/drivers/timer/sp804/sp804_timer.c @@ -4,6 +4,7 @@ * Copyright (C) 2007 Bahadir Balban */ #include +#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); } diff --git a/src/platform/pb926/irq.c b/src/platform/pb926/irq.c index 7b63abf..6fe18ef 100644 --- a/src/platform/pb926/irq.c +++ b/src/platform/pb926/irq.c @@ -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", diff --git a/src/platform/pb926/platform.c b/src/platform/pb926/platform.c index d59c955..7e19654 100644 --- a/src/platform/pb926/platform.c +++ b/src/platform/pb926/platform.c @@ -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(); diff --git a/src/platform/pb926/timer.c b/src/platform/pb926/timer.c index fc290af..6bc9b8e 100644 --- a/src/platform/pb926/timer.c +++ b/src/platform/pb926/timer.c @@ -10,19 +10,25 @@ #include #include +/* 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); }