1/* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. 7 */ 8#include <linux/init.h> 9 10#include <asm/cpu.h> 11#include <asm/setup.h> 12#include <asm/time.h> 13#include <asm/irq.h> 14#include <asm/mips-boards/generic.h> 15 16unsigned long cpu_khz; 17 18static int mips_cpu_timer_irq; 19static int mips_cpu_perf_irq; 20 21static void mips_timer_dispatch(void) 22{ 23 do_IRQ(mips_cpu_timer_irq); 24} 25 26static void mips_perf_dispatch(void) 27{ 28 do_IRQ(mips_cpu_perf_irq); 29} 30 31static void __iomem *status_reg = (void __iomem *)0xbf000410; 32 33/* 34 * Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect. 35 */ 36static unsigned int __init estimate_cpu_frequency(void) 37{ 38 unsigned int prid = read_c0_prid() & (PRID_COMP_MASK | PRID_IMP_MASK); 39 unsigned int tick = 0; 40 unsigned int freq; 41 unsigned int orig; 42 unsigned long flags; 43 44 local_irq_save(flags); 45 46 orig = readl(status_reg) & 0x2; /* get original sample */ 47 /* wait for transition */ 48 while ((readl(status_reg) & 0x2) == orig) 49 ; 50 orig = orig ^ 0x2; /* flip the bit */ 51 52 write_c0_count(0); 53 54 /* wait 1 second (the sampling clock transitions every 10ms) */ 55 while (tick < 100) { 56 /* wait for transition */ 57 while ((readl(status_reg) & 0x2) == orig) 58 ; 59 orig = orig ^ 0x2; /* flip the bit */ 60 tick++; 61 } 62 63 freq = read_c0_count(); 64 65 local_irq_restore(flags); 66 67 mips_hpt_frequency = freq; 68 69 /* Adjust for processor */ 70 if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) && 71 (prid != (PRID_COMP_MIPS | PRID_IMP_25KF))) 72 freq *= 2; 73 74 freq += 5000; /* rounding */ 75 freq -= freq%10000; 76 77 return freq ; 78} 79 80void read_persistent_clock(struct timespec *ts) 81{ 82 ts->tv_sec = 0; 83 ts->tv_nsec = 0; 84} 85 86static void __init plat_perf_setup(void) 87{ 88 if (cp0_perfcount_irq >= 0) { 89 if (cpu_has_vint) 90 set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch); 91 mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; 92 } 93} 94 95unsigned int get_c0_compare_int(void) 96{ 97 if (cpu_has_vint) 98 set_vi_handler(cp0_compare_irq, mips_timer_dispatch); 99 mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; 100 return mips_cpu_timer_irq; 101} 102 103void __init plat_time_init(void) 104{ 105 unsigned int est_freq; 106 107 est_freq = estimate_cpu_frequency(); 108 109 pr_debug("CPU frequency %d.%02d MHz\n", (est_freq / 1000000), 110 (est_freq % 1000000) * 100 / 1000000); 111 112 cpu_khz = est_freq / 1000; 113 114 mips_scroll_message(); 115 116 plat_perf_setup(); 117} 118