1/* 2 * Carsten Langgaard, carstenl@mips.com 3 * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. 4 * 5 * This program is free software; you can distribute it and/or modify it 6 * under the terms of the GNU General Public License (Version 2) as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * for more details. 13 * 14 * You should have received a copy of the GNU General Public License along 15 * with this program; if not, write to the Free Software Foundation, Inc., 16 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 17 * 18 * Setting up the clock on the MIPS boards. 19 */ 20 21#include <linux/types.h> 22#include <linux/init.h> 23#include <linux/kernel_stat.h> 24#include <linux/sched.h> 25#include <linux/spinlock.h> 26#include <linux/interrupt.h> 27#include <linux/time.h> 28#include <linux/timex.h> 29 30#include <asm/mipsregs.h> 31#include <asm/mipsmtregs.h> 32#include <asm/hardirq.h> 33#include <asm/i8253.h> 34#include <asm/irq.h> 35#include <asm/div64.h> 36#include <asm/cpu.h> 37#include <asm/time.h> 38#include <asm/msc01_ic.h> 39 40#include <asm/mips-boards/generic.h> 41#include <asm/mips-boards/prom.h> 42 43unsigned long cpu_khz; 44 45static int mips_cpu_timer_irq; 46static int mips_cpu_perf_irq; 47extern int cp0_perfcount_irq; 48 49static void mips_timer_dispatch(void) 50{ 51 do_IRQ(mips_cpu_timer_irq); 52} 53 54static void mips_perf_dispatch(void) 55{ 56 do_IRQ(mips_cpu_perf_irq); 57} 58 59static void __iomem *status_reg = (void __iomem *)0xbf000410; 60 61/* 62 * Estimate CPU frequency. Sets mips_hpt_frequency as a side-effect 63 */ 64static unsigned int __init estimate_cpu_frequency(void) 65{ 66 unsigned int prid = read_c0_prid() & 0xffff00; 67 unsigned int tick = 0; 68 unsigned int freq; 69 unsigned int orig; 70 unsigned long flags; 71 72 local_irq_save(flags); 73 74 orig = readl(status_reg) & 0x2; /* get original sample */ 75 /* wait for transition */ 76 while ((readl(status_reg) & 0x2) == orig) 77 ; 78 orig = orig ^ 0x2; /* flip the bit */ 79 80 write_c0_count(0); 81 82 /* wait 1 second (the sampling clock transitions every 10ms) */ 83 while (tick < 100) { 84 /* wait for transition */ 85 while ((readl(status_reg) & 0x2) == orig) 86 ; 87 orig = orig ^ 0x2; /* flip the bit */ 88 tick++; 89 } 90 91 freq = read_c0_count(); 92 93 local_irq_restore(flags); 94 95 mips_hpt_frequency = freq; 96 97 /* Adjust for processor */ 98 if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) && 99 (prid != (PRID_COMP_MIPS | PRID_IMP_25KF))) 100 freq *= 2; 101 102 freq += 5000; /* rounding */ 103 freq -= freq%10000; 104 105 return freq ; 106} 107 108void read_persistent_clock(struct timespec *ts) 109{ 110 ts->tv_sec = 0; 111 ts->tv_nsec = 0; 112} 113 114static void __init plat_perf_setup(void) 115{ 116 if (cp0_perfcount_irq >= 0) { 117 if (cpu_has_vint) 118 set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch); 119 mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; 120 } 121} 122 123unsigned int __cpuinit get_c0_compare_int(void) 124{ 125 if (cpu_has_vint) 126 set_vi_handler(cp0_compare_irq, mips_timer_dispatch); 127 mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; 128 return mips_cpu_timer_irq; 129} 130 131void __init plat_time_init(void) 132{ 133 unsigned int est_freq; 134 135 est_freq = estimate_cpu_frequency(); 136 137 printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, 138 (est_freq%1000000)*100/1000000); 139 140 cpu_khz = est_freq / 1000; 141 142 mips_scroll_message(); 143 144 plat_perf_setup(); 145} 146