Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | /*
* IP32 timer calibration
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2001 Keith M Wesolowski
*/
#include <linux/bcd.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/param.h>
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/timex.h>
#include <asm/mipsregs.h>
#include <asm/param.h>
#include <asm/bootinfo.h>
#include <asm/cpu.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/ip32/crime.h>
#include <asm/ip32/ip32_ints.h>
#include <linux/mc146818rtc.h>
extern volatile unsigned long wall_jiffies;
u32 cc_interval;
/* Cycle counter value at the previous timer interrupt.. */
static unsigned int timerhi, timerlo;
/* An arbitrary time; this can be decreased if reliability looks good */
#define WAIT_MS 10
#define PER_MHZ (1000000 / 2 / HZ)
/*
* Change this if you have some constant time drift
*/
#define USECS_PER_JIFFY (1000000/HZ)
static irqreturn_t cc_timer_interrupt(int irq, void *dev_id, struct pt_regs * regs);
static inline uint64_t crime_time(void)
{
return crime_read(CRIME_TIMER) & CRIME_TIMER_MASK;
}
void __init ip32_timer_setup (struct irqaction *irq)
{
uint64_t time;
unsigned int cc_tick;
write_c0_count(0);
irq->handler = cc_timer_interrupt;
printk("Calibrating system timer... ");
time = crime_time();
cc_tick = read_c0_count();
while (crime_time() - time < WAIT_MS * 1000000 / CRIME_NS_PER_TICK) ;
cc_tick = read_c0_count() - cc_tick;
cc_interval = cc_tick / HZ * (1000 / WAIT_MS);
/*
* The round-off seems unnecessary; in testing, the error of the
* above procedure is < 100 ticks, which means it gets filtered
* out by the HZ adjustment.
*/
cc_interval = (cc_interval / PER_MHZ) * PER_MHZ;
printk("%d MHz CPU detected\n", (int) (cc_interval / PER_MHZ));
setup_irq(CLOCK_IRQ, irq);
#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
/* Set ourselves up for future interrupts */
write_c0_compare(read_c0_count() + cc_interval);
change_c0_status(ST0_IM, ALLINTS);
local_irq_enable();
}
static irqreturn_t cc_timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
unsigned int count;
/*
* The cycle counter is only 32 bit which is good for about
* a minute at current count rates of upto 150MHz or so.
*/
count = read_c0_count();
timerhi += (count < timerlo); /* Wrap around */
timerlo = count;
write_c0_compare((u32) (count + cc_interval));
kstat_this_cpu.irqs[irq]++;
do_timer(regs);
if (!jiffies) {
/*
* If jiffies has overflowed in this timer_interrupt we must
* update the timer[hi]/[lo] to make do_fast_gettimeoffset()
* quotient calc still valid. -arca
*/
timerhi = timerlo = 0;
}
return IRQ_HANDLED;
}
void __init ip32_time_init(void)
{
unsigned int epoch = 0, year, mon, day, hour, min, sec;
int i;
/* The Linux interpretation of the CMOS clock register contents:
* When the Update-In-Progress (UIP) flag goes from 1 to 0, the
* RTC registers show the second which has precisely just started.
* Let's hope other operating systems interpret the RTC the same way.
*/
/* read RTC exactly on falling edge of update flag */
for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
break;
for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
break;
do { /* Isn't this overkill ? UIP above should guarantee consistency */
sec = CMOS_READ(RTC_SECONDS);
min = CMOS_READ(RTC_MINUTES);
hour = CMOS_READ(RTC_HOURS);
day = CMOS_READ(RTC_DAY_OF_MONTH);
mon = CMOS_READ(RTC_MONTH);
year = CMOS_READ(RTC_YEAR);
} while (sec != CMOS_READ(RTC_SECONDS));
if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
sec = BCD2BIN(sec);
min = BCD2BIN(min);
hour = BCD2BIN(hour);
day = BCD2BIN(day);
mon = BCD2BIN(mon);
year = BCD2BIN(year);
}
/* Attempt to guess the epoch. This is the same heuristic as in
* rtc.c so no stupid things will happen to timekeeping. Who knows,
* maybe Ultrix also uses 1952 as epoch ...
*/
if (year > 10 && year < 44)
epoch = 1980;
else if (year < 96)
epoch = 1952;
year += epoch;
write_seqlock_irq(&xtime_lock);
xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
xtime.tv_nsec = 0;
write_sequnlock_irq(&xtime_lock);
}
|