Kernel/armv7 - [realview_pb] Implemented basic timekeeping
authorJohn Hodge <[email protected]>
Sun, 22 Sep 2013 11:22:51 +0000 (19:22 +0800)
committerJohn Hodge <[email protected]>
Sun, 22 Sep 2013 11:22:51 +0000 (19:22 +0800)
KernelLand/Kernel/arch/armv7/platform_realview_pb.c
KernelLand/Kernel/arch/armv7/time.c

index 4077f69..b8b6a6f 100644 (file)
  */
 #include <acess.h>
 
+// === 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;
 }
index d4ae4fa..7be097f 100644 (file)
@@ -6,11 +6,14 @@
  */
 #include <acess.h>
 
+// === IMPORTS ===
+extern tTime   Time_GetTickOffset(void);
+
 // === GLOBALS ===
 tTime  giTimestamp;
 
 // === CODE ===
 tTime now(void)
 {
-       return giTimestamp;
+       return giTimestamp + Time_GetTickOffset();
 }

UCC git Repository :: git.ucc.asn.au