93 lines
2.2 KiB
C
93 lines
2.2 KiB
C
#include "etherboot.h"
|
|
#include "timer.h"
|
|
#include "sal.h"
|
|
#include "pal.h"
|
|
#include "init.h"
|
|
|
|
static inline unsigned long get_cycles(void)
|
|
{
|
|
unsigned long result;
|
|
__asm__ __volatile__(";;mov %0=ar.itc;;" : "=r"(result));
|
|
return result;
|
|
}
|
|
|
|
/* ------ Calibrate the TSC -------
|
|
* Time how long it takes to excute a loop that runs in known time.
|
|
* And find the convertion needed to get to CLOCK_TICK_RATE
|
|
*/
|
|
|
|
static unsigned long calibrate_cycles(void)
|
|
{
|
|
unsigned long platform_ticks_per_second, drift_info;
|
|
struct pal_freq_ratio itc_ratio;
|
|
long result;
|
|
result = sal_freq_base(SAL_FREQ_BASE_PLATFORM, &platform_ticks_per_second, &drift_info);
|
|
if (result != 0) {
|
|
printf("sal_freq_base failed: %lx\n",result);
|
|
exit(1);
|
|
} else {
|
|
result = pal_freq_ratios(0,0,&itc_ratio);
|
|
if (result != 0) {
|
|
printf("pal_freq_ratios failed: %lx\n", result);
|
|
exit(1);
|
|
}
|
|
}
|
|
/* Avoid division by zero */
|
|
if (itc_ratio.den == 0)
|
|
itc_ratio.den = 1;
|
|
|
|
return (platform_ticks_per_second *itc_ratio.num)/(itc_ratio.den*TICKS_PER_SEC);
|
|
}
|
|
|
|
static unsigned long clocks_per_tick;
|
|
static void setup_timers(void)
|
|
{
|
|
if (!clocks_per_tick) {
|
|
clocks_per_tick = calibrate_cycles();
|
|
/* Display the CPU Mhz to easily test if the calibration was bad */
|
|
printf("ITC %ld Mhz\n", (clocks_per_tick/1000 * TICKS_PER_SEC)/1000);
|
|
}
|
|
}
|
|
|
|
unsigned long currticks(void)
|
|
{
|
|
return get_cycles()/clocks_per_tick;
|
|
}
|
|
|
|
static unsigned long timer_timeout;
|
|
static int __timer_running(void)
|
|
{
|
|
return get_cycles() < timer_timeout;
|
|
}
|
|
|
|
void udelay(unsigned int usecs)
|
|
{
|
|
unsigned long now;
|
|
now = get_cycles();
|
|
timer_timeout = now + usecs * ((clocks_per_tick * TICKS_PER_SEC)/(1000*1000));
|
|
while(__timer_running());
|
|
}
|
|
void ndelay(unsigned int nsecs)
|
|
{
|
|
unsigned long now;
|
|
now = get_cycles();
|
|
timer_timeout = now + nsecs * ((clocks_per_tick * TICKS_PER_SEC)/(1000*1000*1000));
|
|
while(__timer_running());
|
|
}
|
|
|
|
void load_timer2(unsigned int timer2_ticks)
|
|
{
|
|
unsigned long now;
|
|
unsigned long clocks;
|
|
now = get_cycles();
|
|
clocks = timer2_ticks * ((clocks_per_tick * TICKS_PER_SEC)/CLOCK_TICK_RATE);
|
|
timer_timeout = now + clocks;
|
|
}
|
|
|
|
int timer2_running(void)
|
|
{
|
|
return __timer_running();
|
|
}
|
|
|
|
INIT_FN ( INIT_TIMERS, setup_timers, NULL, NULL );
|