diff options
Diffstat (limited to 'arch/mips/mti-malta/malta-time.c')
| -rw-r--r-- | arch/mips/mti-malta/malta-time.c | 121 |
1 files changed, 82 insertions, 39 deletions
diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c index 0b97d47691f..3778a359f3a 100644 --- a/arch/mips/mti-malta/malta-time.c +++ b/arch/mips/mti-malta/malta-time.c @@ -17,35 +17,31 @@ * * Setting up the clock on the MIPS boards. */ - #include <linux/types.h> +#include <linux/i8253.h> #include <linux/init.h> #include <linux/kernel_stat.h> #include <linux/sched.h> #include <linux/spinlock.h> #include <linux/interrupt.h> -#include <linux/time.h> #include <linux/timex.h> #include <linux/mc146818rtc.h> +#include <asm/cpu.h> #include <asm/mipsregs.h> #include <asm/mipsmtregs.h> #include <asm/hardirq.h> -#include <asm/i8253.h> #include <asm/irq.h> #include <asm/div64.h> -#include <asm/cpu.h> +#include <asm/setup.h> #include <asm/time.h> #include <asm/mc146818-time.h> #include <asm/msc01_ic.h> +#include <asm/gic.h> #include <asm/mips-boards/generic.h> -#include <asm/mips-boards/prom.h> - #include <asm/mips-boards/maltaint.h> -unsigned long cpu_khz; - static int mips_cpu_timer_irq; static int mips_cpu_perf_irq; extern int cp0_perfcount_irq; @@ -60,49 +56,69 @@ static void mips_perf_dispatch(void) do_IRQ(mips_cpu_perf_irq); } +static unsigned int freqround(unsigned int freq, unsigned int amount) +{ + freq += amount; + freq -= freq % (amount*2); + return freq; +} + /* - * Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect + * Estimate CPU and GIC frequencies. */ -static unsigned int __init estimate_cpu_frequency(void) +static void __init estimate_frequencies(void) { - unsigned int prid = read_c0_prid() & 0xffff00; - unsigned int count; - unsigned long flags; - unsigned int start; + unsigned int count, start; +#ifdef CONFIG_IRQ_GIC + unsigned int giccount = 0, gicstart = 0; +#endif + +#if defined(CONFIG_KVM_GUEST) && CONFIG_KVM_GUEST_TIMER_FREQ + mips_hpt_frequency = CONFIG_KVM_GUEST_TIMER_FREQ * 1000000; + return; +#endif local_irq_save(flags); - /* Start counter exactly on falling edge of update flag */ + /* 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. */ + /* Initialize counters. */ start = read_c0_count(); +#ifdef CONFIG_IRQ_GIC + if (gic_present) + GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), gicstart); +#endif - /* Read counter exactly on falling edge of update flag */ + /* 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() - start; + count = read_c0_count(); +#ifdef CONFIG_IRQ_GIC + if (gic_present) + GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), giccount); +#endif - /* restore interrupts */ local_irq_restore(flags); + count -= start; 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; +#ifdef CONFIG_IRQ_GIC + if (gic_present) { + giccount -= gicstart; + gic_frequency = giccount; + } +#endif } -unsigned long read_persistent_clock(void) +void read_persistent_clock(struct timespec *ts) { - return mc146818_get_cmos_time(); + ts->tv_sec = mc146818_get_cmos_time(); + ts->tv_nsec = 0; } static void __init plat_perf_setup(void) @@ -118,12 +134,12 @@ static void __init plat_perf_setup(void) set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch); mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; #ifdef CONFIG_SMP - set_irq_handler(mips_cpu_perf_irq, handle_percpu_irq); + irq_set_handler(mips_cpu_perf_irq, handle_percpu_irq); #endif } } -unsigned int __cpuinit get_c0_compare_int(void) +unsigned int get_c0_compare_int(void) { #ifdef MSC01E_INT_BASE if (cpu_has_veic) { @@ -140,24 +156,51 @@ unsigned int __cpuinit get_c0_compare_int(void) return mips_cpu_timer_irq; } -void __init plat_time_init(void) +static void __init init_rtc(void) { - unsigned int est_freq; + /* stop the clock whilst setting it up */ + CMOS_WRITE(RTC_SET | RTC_24H, RTC_CONTROL); - /* Set Data mode - binary. */ - CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL); + /* 32KHz time base */ + CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_FREQ_SELECT); - est_freq = estimate_cpu_frequency(); + /* start the clock */ + CMOS_WRITE(RTC_24H, RTC_CONTROL); +} - printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, - (est_freq%1000000)*100/1000000); +void __init plat_time_init(void) +{ + unsigned int prid = read_c0_prid() & (PRID_COMP_MASK | PRID_IMP_MASK); + unsigned int freq; - cpu_khz = est_freq / 1000; + init_rtc(); + estimate_frequencies(); + + freq = mips_hpt_frequency; + if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) && + (prid != (PRID_COMP_MIPS | PRID_IMP_25KF))) + freq *= 2; + freq = freqround(freq, 5000); + printk("CPU frequency %d.%02d MHz\n", freq/1000000, + (freq%1000000)*100/1000000); mips_scroll_message(); -#ifdef CONFIG_I8253 /* Only Malta has a PIT */ + +#ifdef CONFIG_I8253 + /* Only Malta has a PIT. */ setup_pit_timer(); #endif +#ifdef CONFIG_IRQ_GIC + if (gic_present) { + freq = freqround(gic_frequency, 5000); + printk("GIC frequency %d.%02d MHz\n", freq/1000000, + (freq%1000000)*100/1000000); +#ifdef CONFIG_CSRC_GIC + gic_clocksource_init(gic_frequency); +#endif + } +#endif + plat_perf_setup(); } |
