From ffae612634548210b4f2facab9ade01bbf8087af Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 22 Sep 2013 19:22:51 +0800 Subject: [PATCH] Kernel/armv7 - [realview_pb] Implemented basic timekeeping --- .../Kernel/arch/armv7/platform_realview_pb.c | 95 ++++++++++++++++++- KernelLand/Kernel/arch/armv7/time.c | 5 +- 2 files changed, 97 insertions(+), 3 deletions(-) diff --git a/KernelLand/Kernel/arch/armv7/platform_realview_pb.c b/KernelLand/Kernel/arch/armv7/platform_realview_pb.c index 4077f691..b8b6a6f9 100644 --- a/KernelLand/Kernel/arch/armv7/platform_realview_pb.c +++ b/KernelLand/Kernel/arch/armv7/platform_realview_pb.c @@ -7,15 +7,106 @@ */ #include +// === IMPORTS === +extern tTime giTimestamp; + // === PROTOTYPES === -void Time_Setup(void); +void Time_Setup(void); // TODO: Should be in header +void Time_int_RTCIRQHandler(int IRQ, void *unused); +void Time_int_TimerIRQHandler(int IRQ, void *unused); +tTime Time_GetTickOffset(void); // TODO: Should be in header // === GLOBALS === +tTime giTimeBase; +Uint32 giTime_PartMS; tPAddr gGIC_DistributorAddr = 0x1e001000; tPAddr gGIC_InterfaceAddr = 0x1e000000; +#define DIVISOR_ENC 1 +#define DIVISOR_REAL (1 << (4*DIVISOR_ENC)) +#define TICKS_PER_SECOND (1000000/DIVISOR_REAL) +#define TICKS_PER_IRQ (TICKS_PER_SECOND/2) // Tick twice a second +#define TICKS_PER_MS (TICKS_PER_SECOND/1000) +#define MS_PER_IRQ (TICKS_PER_IRQ*1000/TICKS_PER_SECOND) // (TICKS_PER_IRQ/(TICKS_PER_SECOND/1000)) +#define PART_PER_IRQ (TICKS_PER_IRQ%(TICKS_PER_SECOND/1000)) // (TICKS_PER_IRQ%(TICKS_PER_SECOND/1000)) + +// RTC +#define PL031_BASE 0x10017000 +#define PL031_IRQ 10 +volatile struct { + Uint32 DR; + Uint32 MR; + Uint32 LR; + Uint32 CR; + Uint32 IMSC; + Uint32 IS; + Uint32 MIS; + Uint32 ICR; +} *gTime_PL031; +// Timer +#define SP804_BASE 0x10011000 +#define SP805_IRQ 4 +volatile struct { + struct { + Uint32 Load; + Uint32 Value; + Uint32 Control; + Uint32 CIS; + Uint32 RIS; + Uint32 MIS; + Uint32 BGLoad; + Uint32 _unused2; + } Timers[2]; +} *gTime_SP804; + // === CODE === +void Time_int_RTCIRQHandler(int IRQ, void *unused) +{ + if( !(gTime_PL031->IS & 1) ) { + return ; + } + gTime_PL031->ICR = 1; // Clear interrupt +// giTimestamp = (Uint64)gTime_PL031->DR * 1000 - giTimeBase; +} + +void Time_int_TimerIRQHandler(int IRQ, void *unused) +{ + if( !(gTime_SP804->Timers[0].RIS) ) { + return ; + } + gTime_SP804->Timers[0].CIS = 1; + giTime_PartMS += PART_PER_IRQ; + giTimestamp += MS_PER_IRQ; + while( giTime_PartMS > TICKS_PER_MS ) { + giTime_PartMS -= TICKS_PER_MS; + giTimestamp ++; + } +} + void Time_Setup(void) { - // TODO: + // PL031 RTC + gTime_PL031 = MM_MapHWPages(PL031_BASE, 1); + //IRQ_AddHandler(PL031_IRQ, Time_int_RTCIRQHandler, NULL); + gTime_PL031->IMSC = 1; + gTime_PL031->ICR = 1; +// giTimestamp = (Uint64)gTime_PL031->DR * 1000; + + // SP804 Timer (Contains two basic ARM timers, each at 1MHz base) + gTime_SP804 = MM_MapHWPages(SP804_BASE, 1); + // - Use the first to maintain the system clock + gTime_SP804->Timers[0].Load = TICKS_PER_IRQ; + // > Enable,Periodic,IE,Div=1,32bit + gTime_SP804->Timers[0].Control = (1<<7)|(1<<6)|(1<<5)|(DIVISOR_ENC<<2)|(1<<1); + IRQ_AddHandler(SP805_IRQ, Time_int_TimerIRQHandler, NULL); + gTime_SP804->Timers[0].CIS = 1; + // - TODO: use the second for short events (and use RTC for long events) +} + +tTime Time_GetTickOffset(void) +{ + if( !gTime_SP804 ) + return 0; + // Want count of ms since last tick + return (giTime_PartMS + gTime_SP804->Timers[0].Value) / TICKS_PER_MS; } diff --git a/KernelLand/Kernel/arch/armv7/time.c b/KernelLand/Kernel/arch/armv7/time.c index d4ae4fa6..7be097f4 100644 --- a/KernelLand/Kernel/arch/armv7/time.c +++ b/KernelLand/Kernel/arch/armv7/time.c @@ -6,11 +6,14 @@ */ #include +// === IMPORTS === +extern tTime Time_GetTickOffset(void); + // === GLOBALS === tTime giTimestamp; // === CODE === tTime now(void) { - return giTimestamp; + return giTimestamp + Time_GetTickOffset(); } -- 2.20.1