POK(kernelpart)
/home/jaouen/pok_official/pok/trunk/kernel/arch/ppc/timer.c
Go to the documentation of this file.
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 }