diff options
| -rw-r--r-- | arch/mips/kernel/cevt-r4k.c | 12 | ||||
| -rw-r--r-- | arch/mips/kernel/time.c | 87 | ||||
| -rw-r--r-- | include/asm-mips/time.h | 5 |
3 files changed, 43 insertions, 61 deletions
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c index 076f52b9bb79..24a2d907aa0d 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 | ||
| 222 | void __cpuinit mips_clockevent_init(void) | 222 | int __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 3284b9b4ecac..d7d52efff51f 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 | ||
| 94 | static 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 | |||
| 136 | void __init clocksource_set_clock(struct clocksource *cs, unsigned int clock) | 94 | void __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 | ||
| 155 | static __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 | |||
| 197 | void __init time_init(void) | 187 | void __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 | } |
diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h index ee1663e64da1..1922494a0d9e 100644 --- a/include/asm-mips/time.h +++ b/include/asm-mips/time.h | |||
| @@ -58,11 +58,12 @@ extern int (*perf_irq)(void); | |||
| 58 | * Initialize the calling CPU's compare interrupt as clockevent device | 58 | * Initialize the calling CPU's compare interrupt as clockevent device |
| 59 | */ | 59 | */ |
| 60 | #ifdef CONFIG_CEVT_R4K | 60 | #ifdef CONFIG_CEVT_R4K |
| 61 | extern void mips_clockevent_init(void); | 61 | extern int mips_clockevent_init(void); |
| 62 | extern unsigned int __weak get_c0_compare_int(void); | 62 | extern unsigned int __weak get_c0_compare_int(void); |
| 63 | #else | 63 | #else |
| 64 | static inline void mips_clockevent_init(void) | 64 | static inline int mips_clockevent_init(void) |
| 65 | { | 65 | { |
| 66 | return -ENXIO; | ||
| 66 | } | 67 | } |
| 67 | #endif | 68 | #endif |
| 68 | 69 | ||
