aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/time.c')
-rw-r--r--arch/mips/kernel/time.c112
1 files changed, 33 insertions, 79 deletions
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 3284b9b4ecac..52075426c373 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -50,14 +50,6 @@ int update_persistent_clock(struct timespec now)
50 return rtc_mips_set_mmss(now.tv_sec); 50 return rtc_mips_set_mmss(now.tv_sec);
51} 51}
52 52
53/*
54 * High precision timer functions for a R4k-compatible timer.
55 */
56static cycle_t c0_hpt_read(void)
57{
58 return read_c0_count();
59}
60
61int (*mips_timer_state)(void); 53int (*mips_timer_state)(void);
62 54
63int null_perf_irq(void) 55int null_perf_irq(void)
@@ -84,55 +76,6 @@ EXPORT_SYMBOL(perf_irq);
84 76
85unsigned int mips_hpt_frequency; 77unsigned int mips_hpt_frequency;
86 78
87static struct clocksource clocksource_mips = {
88 .name = "MIPS",
89 .read = c0_hpt_read,
90 .mask = CLOCKSOURCE_MASK(32),
91 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
92};
93
94static unsigned int __init calibrate_hpt(void)
95{
96 cycle_t frequency, hpt_start, hpt_end, hpt_count, hz;
97
98 const int loops = HZ / 10;
99 int log_2_loops = 0;
100 int i;
101
102 /*
103 * We want to calibrate for 0.1s, but to avoid a 64-bit
104 * division we round the number of loops up to the nearest
105 * power of 2.
106 */
107 while (loops > 1 << log_2_loops)
108 log_2_loops++;
109 i = 1 << log_2_loops;
110
111 /*
112 * Wait for a rising edge of the timer interrupt.
113 */
114 while (mips_timer_state());
115 while (!mips_timer_state());
116
117 /*
118 * Now see how many high precision timer ticks happen
119 * during the calculated number of periods between timer
120 * interrupts.
121 */
122 hpt_start = clocksource_mips.read();
123 do {
124 while (mips_timer_state());
125 while (!mips_timer_state());
126 } while (--i);
127 hpt_end = clocksource_mips.read();
128
129 hpt_count = (hpt_end - hpt_start) & clocksource_mips.mask;
130 hz = HZ;
131 frequency = hpt_count * hz;
132
133 return frequency >> log_2_loops;
134}
135
136void __init clocksource_set_clock(struct clocksource *cs, unsigned int clock) 79void __init clocksource_set_clock(struct clocksource *cs, unsigned int clock)
137{ 80{
138 u64 temp; 81 u64 temp;
@@ -166,16 +109,6 @@ void __cpuinit clockevent_set_clock(struct clock_event_device *cd,
166 cd->mult = (u32) temp; 109 cd->mult = (u32) temp;
167} 110}
168 111
169static void __init init_mips_clocksource(void)
170{
171 /* Calclate a somewhat reasonable rating value */
172 clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
173
174 clocksource_set_clock(&clocksource_mips, mips_hpt_frequency);
175
176 clocksource_register(&clocksource_mips);
177}
178
179void __init __weak plat_time_init(void) 112void __init __weak plat_time_init(void)
180{ 113{
181} 114}
@@ -194,21 +127,42 @@ void __init plat_timer_setup(void)
194 BUG(); 127 BUG();
195} 128}
196 129
130static __init int cpu_has_mfc0_count_bug(void)
131{
132 switch (current_cpu_type()) {
133 case CPU_R4000PC:
134 case CPU_R4000SC:
135 case CPU_R4000MC:
136 /*
137 * V3.0 is documented as suffering from the mfc0 from count bug.
138 * Afaik this is the last version of the R4000. Later versions
139 * were marketed as R4400.
140 */
141 return 1;
142
143 case CPU_R4400PC:
144 case CPU_R4400SC:
145 case CPU_R4400MC:
146 /*
147 * The published errata for the R4400 upto 3.0 say the CPU
148 * has the mfc0 from count bug.
149 */
150 if ((current_cpu_data.processor_id & 0xff) <= 0x30)
151 return 1;
152
153 /*
154 * I don't have erratas for newer R4400 so be paranoid.
155 */
156 return 1;
157 }
158
159 return 0;
160}
161
197void __init time_init(void) 162void __init time_init(void)
198{ 163{
199 plat_time_init(); 164 plat_time_init();
200 165
201 if (cpu_has_counter && (mips_hpt_frequency || mips_timer_state)) { 166 if (mips_clockevent_init() || !cpu_has_mfc0_count_bug())
202 /* We know counter frequency. Or we can get it. */
203 if (!mips_hpt_frequency)
204 mips_hpt_frequency = calibrate_hpt();
205
206 /* Report the high precision timer rate for a reference. */
207 printk("Using %u.%03u MHz high precision timer.\n",
208 ((mips_hpt_frequency + 500) / 1000) / 1000,
209 ((mips_hpt_frequency + 500) / 1000) % 1000);
210 init_mips_clocksource(); 167 init_mips_clocksource();
211 }
212
213 mips_clockevent_init();
214} 168}