aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/cevt-r4k.c12
-rw-r--r--arch/mips/kernel/time.c87
2 files changed, 40 insertions, 59 deletions
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c
index 076f52b9bb7..24a2d907aa0 100644
--- a/arch/mips/kernel/cevt-r4k.c
+++ b/arch/mips/kernel/cevt-r4k.c
@@ -219,7 +219,7 @@ static int c0_compare_int_usable(void)
219 return 1; 219 return 1;
220} 220}
221 221
222void __cpuinit mips_clockevent_init(void) 222int __cpuinit mips_clockevent_init(void)
223{ 223{
224 uint64_t mips_freq = mips_hpt_frequency; 224 uint64_t mips_freq = mips_hpt_frequency;
225 unsigned int cpu = smp_processor_id(); 225 unsigned int cpu = smp_processor_id();
@@ -227,7 +227,7 @@ void __cpuinit mips_clockevent_init(void)
227 unsigned int irq; 227 unsigned int irq;
228 228
229 if (!cpu_has_counter || !mips_hpt_frequency) 229 if (!cpu_has_counter || !mips_hpt_frequency)
230 return; 230 return -ENXIO;
231 231
232#ifdef CONFIG_MIPS_MT_SMTC 232#ifdef CONFIG_MIPS_MT_SMTC
233 setup_smtc_dummy_clockevent_device(); 233 setup_smtc_dummy_clockevent_device();
@@ -237,11 +237,11 @@ void __cpuinit mips_clockevent_init(void)
237 * device. 237 * device.
238 */ 238 */
239 if (cpu) 239 if (cpu)
240 return; 240 return 0;
241#endif 241#endif
242 242
243 if (!c0_compare_int_usable()) 243 if (!c0_compare_int_usable())
244 return; 244 return -ENXIO;
245 245
246 /* 246 /*
247 * With vectored interrupts things are getting platform specific. 247 * With vectored interrupts things are getting platform specific.
@@ -277,7 +277,7 @@ void __cpuinit mips_clockevent_init(void)
277 clockevents_register_device(cd); 277 clockevents_register_device(cd);
278 278
279 if (cp0_timer_irq_installed) 279 if (cp0_timer_irq_installed)
280 return; 280 return 0;
281 281
282 cp0_timer_irq_installed = 1; 282 cp0_timer_irq_installed = 1;
283 283
@@ -287,4 +287,6 @@ void __cpuinit mips_clockevent_init(void)
287#else 287#else
288 setup_irq(irq, &c0_compare_irqaction); 288 setup_irq(irq, &c0_compare_irqaction);
289#endif 289#endif
290
291 return 0;
290} 292}
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 3284b9b4eca..d7d52efff51 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -91,48 +91,6 @@ static struct clocksource clocksource_mips = {
91 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 91 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
92}; 92};
93 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) 94void __init clocksource_set_clock(struct clocksource *cs, unsigned int clock)
137{ 95{
138 u64 temp; 96 u64 temp;
@@ -194,21 +152,42 @@ void __init plat_timer_setup(void)
194 BUG(); 152 BUG();
195} 153}
196 154
155static __init int cpu_has_mfc0_count_bug(void)
156{
157 switch (current_cpu_type()) {
158 case CPU_R4000PC:
159 case CPU_R4000SC:
160 case CPU_R4000MC:
161 /*
162 * V3.0 is documented as suffering from the mfc0 from count bug.
163 * Afaik this is the last version of the R4000. Later versions
164 * were marketed as R4400.
165 */
166 return 1;
167
168 case CPU_R4400PC:
169 case CPU_R4400SC:
170 case CPU_R4400MC:
171 /*
172 * The published errata for the R4400 upto 3.0 say the CPU
173 * has the mfc0 from count bug.
174 */
175 if ((current_cpu_data.processor_id & 0xff) <= 0x30)
176 return 1;
177
178 /*
179 * I don't have erratas for newer R4400 so be paranoid.
180 */
181 return 1;
182 }
183
184 return 0;
185}
186
197void __init time_init(void) 187void __init time_init(void)
198{ 188{
199 plat_time_init(); 189 plat_time_init();
200 190
201 if (cpu_has_counter && (mips_hpt_frequency || mips_timer_state)) { 191 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(); 192 init_mips_clocksource();
211 }
212
213 mips_clockevent_init();
214} 193}