POK(kernelpart)
|
00001 /* 00002 * POK header 00003 * 00004 * The following file is a part of the POK project. Any modification should 00005 * made according to the POK licence. You CANNOT use this file or a part of 00006 * this file is this part of a file for your own project 00007 * 00008 * For more information on the POK licence, please see our LICENCE FILE 00009 * 00010 * Please follow the coding guidelines described in doc/CODING_GUIDELINES 00011 * 00012 * Copyright (c) 2007-2009 POK team 00013 * 00014 * Created by julien on Thu Jan 15 23:34:13 2009 00015 */ 00016 00017 00018 #include <errno.h> 00019 #include <bsp.h> 00020 #include <core/time.h> 00021 #include <core/sched.h> 00022 00023 /* From platform. */ 00024 #define BUS_FREQ (100 * 1000000U) 00025 00026 #define FREQ_DIV 40 00027 00028 /* Last time when decr was set. */ 00029 static unsigned long long time_last; 00030 00031 /* Decrementer optimal value. */ 00032 static unsigned int time_inter; 00033 00034 /* Correctly get time base - handle carry. */ 00035 static inline unsigned long long get_ppc_tb (void) 00036 { 00037 unsigned int u; 00038 unsigned int l; 00039 unsigned int u1; 00040 00041 asm ("1:\n\t" 00042 "mftbu %0\n\t" 00043 "mftb %1\n\t" 00044 "mftbu %2\n\t" 00045 "cmpw %2,%0\n\t" 00046 "bne 1b\n" 00047 : "=r"(u), "=r"(l), "=r"(u1)); 00048 return (((unsigned long long)u) << 32) | l; 00049 } 00050 00051 /* Compute new value for the decrementer. If the value is in the future, 00052 sets the decrementer else returns an error. */ 00053 static int pok_arch_set_decr (void) 00054 { 00055 unsigned long long time_new = time_last + time_inter; 00056 unsigned long long time_cur = get_ppc_tb(); 00057 int delta = time_new - time_cur; 00058 00059 time_last = time_new; 00060 00061 if (delta < 0) 00062 { 00063 return POK_ERRNO_EINVAL; 00064 } 00065 else 00066 { 00067 asm volatile ("mtdec %0" : : "r"(delta)); 00068 return POK_ERRNO_OK; 00069 } 00070 } 00071 00072 /* Called by the interrupt handled. */ 00073 void pok_arch_decr_int (void) 00074 { 00075 int err; 00076 00077 do 00078 { 00079 err = pok_arch_set_decr(); 00080 00081 pok_tick_counter += FREQ_DIV; 00082 } while (err != POK_ERRNO_OK); 00083 00084 pok_sched (); 00085 } 00086 00087 pok_ret_t pok_bsp_time_init () 00088 { 00089 time_inter = (BUS_FREQ * FREQ_DIV) / POK_TIMER_FREQUENCY; 00090 time_last = get_ppc_tb (); 00091 pok_arch_set_decr(); 00092 00093 return (POK_ERRNO_OK); 00094 }