diff options
Diffstat (limited to 'arch/mips/mti-sead3/sead3-time.c')
-rw-r--r-- | arch/mips/mti-sead3/sead3-time.c | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/arch/mips/mti-sead3/sead3-time.c b/arch/mips/mti-sead3/sead3-time.c new file mode 100644 index 00000000000..048e781a17a --- /dev/null +++ b/arch/mips/mti-sead3/sead3-time.c @@ -0,0 +1,117 @@ +/* + * 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) 2012 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/init.h> + +#include <asm/setup.h> +#include <asm/time.h> +#include <asm/irq.h> +#include <asm/mips-boards/generic.h> +#include <asm/mips-boards/prom.h> + +unsigned long cpu_khz; + +static int mips_cpu_timer_irq; +static int mips_cpu_perf_irq; + +static void mips_timer_dispatch(void) +{ + do_IRQ(mips_cpu_timer_irq); +} + +static void mips_perf_dispatch(void) +{ + do_IRQ(mips_cpu_perf_irq); +} + +static void __iomem *status_reg = (void __iomem *)0xbf000410; + +/* + * Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect. + */ +static unsigned int __init estimate_cpu_frequency(void) +{ + unsigned int prid = read_c0_prid() & 0xffff00; + unsigned int tick = 0; + unsigned int freq; + unsigned int orig; + unsigned long flags; + + local_irq_save(flags); + + orig = readl(status_reg) & 0x2; /* get original sample */ + /* wait for transition */ + while ((readl(status_reg) & 0x2) == orig) + ; + orig = orig ^ 0x2; /* flip the bit */ + + write_c0_count(0); + + /* wait 1 second (the sampling clock transitions every 10ms) */ + while (tick < 100) { + /* wait for transition */ + while ((readl(status_reg) & 0x2) == orig) + ; + orig = orig ^ 0x2; /* flip the bit */ + tick++; + } + + freq = read_c0_count(); + + local_irq_restore(flags); + + mips_hpt_frequency = freq; + + /* Adjust for processor */ + if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) && + (prid != (PRID_COMP_MIPS | PRID_IMP_25KF))) + freq *= 2; + + freq += 5000; /* rounding */ + freq -= freq%10000; + + return freq ; +} + +void read_persistent_clock(struct timespec *ts) +{ + ts->tv_sec = 0; + ts->tv_nsec = 0; +} + +static void __init plat_perf_setup(void) +{ + if (cp0_perfcount_irq >= 0) { + if (cpu_has_vint) + set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch); + mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; + } +} + +unsigned int __cpuinit get_c0_compare_int(void) +{ + if (cpu_has_vint) + set_vi_handler(cp0_compare_irq, mips_timer_dispatch); + mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; + return mips_cpu_timer_irq; +} + +void __init plat_time_init(void) +{ + unsigned int est_freq; + + est_freq = estimate_cpu_frequency(); + + pr_debug("CPU frequency %d.%02d MHz\n", (est_freq / 1000000), + (est_freq % 1000000) * 100 / 1000000); + + cpu_khz = est_freq / 1000; + + mips_scroll_message(); + + plat_perf_setup(); +} |