| Steven J. Hill | 3070033 | 2012-05-30 21:02:49 +0000 | [diff] [blame] | 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/setup.h> | 
 | 11 | #include <asm/time.h> | 
 | 12 | #include <asm/irq.h> | 
 | 13 | #include <asm/mips-boards/generic.h> | 
 | 14 | #include <asm/mips-boards/prom.h> | 
 | 15 |  | 
 | 16 | unsigned long cpu_khz; | 
 | 17 |  | 
 | 18 | static int mips_cpu_timer_irq; | 
 | 19 | static int mips_cpu_perf_irq; | 
 | 20 |  | 
 | 21 | static void mips_timer_dispatch(void) | 
 | 22 | { | 
 | 23 | 	do_IRQ(mips_cpu_timer_irq); | 
 | 24 | } | 
 | 25 |  | 
 | 26 | static void mips_perf_dispatch(void) | 
 | 27 | { | 
 | 28 | 	do_IRQ(mips_cpu_perf_irq); | 
 | 29 | } | 
 | 30 |  | 
 | 31 | static void __iomem *status_reg = (void __iomem *)0xbf000410; | 
 | 32 |  | 
 | 33 | /* | 
 | 34 |  * Estimate CPU frequency.  Sets mips_hpt_frequency as a side-effect. | 
 | 35 |  */ | 
 | 36 | static unsigned int __init estimate_cpu_frequency(void) | 
 | 37 | { | 
 | 38 | 	unsigned int prid = read_c0_prid() & 0xffff00; | 
 | 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 |  | 
 | 80 | void read_persistent_clock(struct timespec *ts) | 
 | 81 | { | 
 | 82 | 	ts->tv_sec = 0; | 
 | 83 | 	ts->tv_nsec = 0; | 
 | 84 | } | 
 | 85 |  | 
 | 86 | static 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 |  | 
 | 95 | unsigned int __cpuinit 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 |  | 
 | 103 | void __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 | } |