sim_time.c 2.9 KB
Newer Older
1 2 3 4 5 6 7
#include <linux/types.h>
#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/mc146818rtc.h>
8
#include <linux/smp.h>
9
#include <linux/timex.h>
N
Nicolas Kaiser 已提交
10

11 12 13 14
#include <asm/hardirq.h>
#include <asm/div64.h>
#include <asm/cpu.h>
#include <asm/time.h>
N
Nicolas Kaiser 已提交
15
#include <asm/irq.h>
16 17 18 19 20 21 22 23 24 25 26
#include <asm/mc146818-time.h>
#include <asm/msc01_ic.h>

#include <asm/mips-boards/generic.h>
#include <asm/mips-boards/prom.h>
#include <asm/mips-boards/simint.h>


unsigned long cpu_khz;

/*
27
 * Estimate CPU frequency.  Sets mips_hpt_frequency as a side-effect
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
 */
static unsigned int __init estimate_cpu_frequency(void)
{
	unsigned int prid = read_c0_prid() & 0xffff00;
	unsigned int count;

#if 1
	/*
	 * hardwire the board frequency to 12MHz.
	 */

	if ((prid == (PRID_COMP_MIPS | PRID_IMP_20KC)) ||
	    (prid == (PRID_COMP_MIPS | PRID_IMP_25KF)))
		count = 12000000;
	else
		count =  6000000;
#else
	unsigned int flags;

	local_irq_save(flags);

	/* Start counter exactly on falling edge of update flag */
	while (CMOS_READ(RTC_REG_A) & RTC_UIP);
	while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));

	/* Start r4k counter. */
	write_c0_count(0);

	/* Read counter exactly on falling edge of update flag */
	while (CMOS_READ(RTC_REG_A) & RTC_UIP);
	while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));

	count = read_c0_count();

	/* restore interrupts */
	local_irq_restore(flags);
#endif

	mips_hpt_frequency = count;

	if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) &&
	    (prid != (PRID_COMP_MIPS | PRID_IMP_25KF)))
		count *= 2;

	count += 5000;    /* round */
	count -= count%10000;

	return count;
}

78
void __init plat_time_init(void)
79 80 81 82 83
{
	unsigned int est_freq, flags;

	local_irq_save(flags);

84
	/* Set Data mode - binary. */
85 86
	CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL);

87
	est_freq = estimate_cpu_frequency();
88

89 90
	printk(KERN_INFO "CPU frequency %d.%02d MHz\n", est_freq / 1000000,
	       (est_freq % 1000000) * 100 / 1000000);
91

92
	cpu_khz = est_freq / 1000;
93 94 95 96 97 98

	local_irq_restore(flags);
}

static int mips_cpu_timer_irq;

99
static void mips_timer_dispatch(void)
100
{
101
	do_IRQ(mips_cpu_timer_irq);
102 103 104
}


105
void __init plat_timer_setup(struct irqaction *irq)
106 107 108 109
{
	if (cpu_has_veic) {
		set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch);
		mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR;
110
	} else {
111
		if (cpu_has_vint)
112 113
			set_vi_handler(cp0_compare_irq, mips_timer_dispatch);
		mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq;
114 115 116 117 118 119 120 121 122 123
	}

	/* we are using the cpu counter for timer interrupts */
	setup_irq(mips_cpu_timer_irq, irq);

#ifdef CONFIG_SMP
	/* irq_desc(riptor) is a global resource, when the interrupt overlaps
	   on seperate cpu's the first one tries to handle the second interrupt.
	   The effect is that the int remains disabled on the second cpu.
	   Mark the interrupt with IRQ_PER_CPU to avoid any confusion */
124 125
	irq_desc[mips_cpu_timer_irq].flags |= IRQ_PER_CPU;
	set_irq_handler(mips_cpu_timer_irq, handle_percpu_irq);
126 127
#endif
}