diff options
Diffstat (limited to 'arch/mips/kernel/time.c')
| -rw-r--r-- | arch/mips/kernel/time.c | 87 |
1 files changed, 33 insertions, 54 deletions
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 | } |
