| .. | .. |
|---|
| 18 | 18 | #include <linux/kernel.h> |
|---|
| 19 | 19 | #include <linux/mm.h> |
|---|
| 20 | 20 | #include <linux/tty.h> |
|---|
| 21 | +#include <linux/clocksource.h> |
|---|
| 21 | 22 | #include <linux/console.h> |
|---|
| 22 | 23 | #include <linux/linkage.h> |
|---|
| 23 | 24 | #include <linux/init.h> |
|---|
| .. | .. |
|---|
| 30 | 31 | #include <asm/bootinfo.h> |
|---|
| 31 | 32 | #include <asm/bootinfo-vme.h> |
|---|
| 32 | 33 | #include <asm/byteorder.h> |
|---|
| 33 | | -#include <asm/pgtable.h> |
|---|
| 34 | 34 | #include <asm/setup.h> |
|---|
| 35 | 35 | #include <asm/irq.h> |
|---|
| 36 | 36 | #include <asm/traps.h> |
|---|
| .. | .. |
|---|
| 39 | 39 | |
|---|
| 40 | 40 | static void bvme6000_get_model(char *model); |
|---|
| 41 | 41 | extern void bvme6000_sched_init(irq_handler_t handler); |
|---|
| 42 | | -extern u32 bvme6000_gettimeoffset(void); |
|---|
| 43 | 42 | extern int bvme6000_hwclk (int, struct rtc_time *); |
|---|
| 44 | 43 | extern void bvme6000_reset (void); |
|---|
| 45 | 44 | void bvme6000_set_vectors (void); |
|---|
| .. | .. |
|---|
| 105 | 104 | mach_max_dma_address = 0xffffffff; |
|---|
| 106 | 105 | mach_sched_init = bvme6000_sched_init; |
|---|
| 107 | 106 | mach_init_IRQ = bvme6000_init_IRQ; |
|---|
| 108 | | - arch_gettimeoffset = bvme6000_gettimeoffset; |
|---|
| 109 | 107 | mach_hwclk = bvme6000_hwclk; |
|---|
| 110 | 108 | mach_reset = bvme6000_reset; |
|---|
| 111 | 109 | mach_get_model = bvme6000_get_model; |
|---|
| .. | .. |
|---|
| 149 | 147 | return IRQ_HANDLED; |
|---|
| 150 | 148 | } |
|---|
| 151 | 149 | |
|---|
| 150 | +static u64 bvme6000_read_clk(struct clocksource *cs); |
|---|
| 151 | + |
|---|
| 152 | +static struct clocksource bvme6000_clk = { |
|---|
| 153 | + .name = "rtc", |
|---|
| 154 | + .rating = 250, |
|---|
| 155 | + .read = bvme6000_read_clk, |
|---|
| 156 | + .mask = CLOCKSOURCE_MASK(32), |
|---|
| 157 | + .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
|---|
| 158 | +}; |
|---|
| 159 | + |
|---|
| 160 | +static u32 clk_total, clk_offset; |
|---|
| 161 | + |
|---|
| 162 | +#define RTC_TIMER_CLOCK_FREQ 8000000 |
|---|
| 163 | +#define RTC_TIMER_CYCLES (RTC_TIMER_CLOCK_FREQ / HZ) |
|---|
| 164 | +#define RTC_TIMER_COUNT ((RTC_TIMER_CYCLES / 2) - 1) |
|---|
| 152 | 165 | |
|---|
| 153 | 166 | static irqreturn_t bvme6000_timer_int (int irq, void *dev_id) |
|---|
| 154 | 167 | { |
|---|
| .. | .. |
|---|
| 160 | 173 | local_irq_save(flags); |
|---|
| 161 | 174 | msr = rtc->msr & 0xc0; |
|---|
| 162 | 175 | rtc->msr = msr | 0x20; /* Ack the interrupt */ |
|---|
| 176 | + clk_total += RTC_TIMER_CYCLES; |
|---|
| 177 | + clk_offset = 0; |
|---|
| 163 | 178 | timer_routine(0, NULL); |
|---|
| 164 | 179 | local_irq_restore(flags); |
|---|
| 165 | 180 | |
|---|
| .. | .. |
|---|
| 182 | 197 | |
|---|
| 183 | 198 | rtc->msr = 0; /* Ensure timer registers accessible */ |
|---|
| 184 | 199 | |
|---|
| 185 | | - if (request_irq(BVME_IRQ_RTC, bvme6000_timer_int, 0, "timer", |
|---|
| 200 | + if (request_irq(BVME_IRQ_RTC, bvme6000_timer_int, IRQF_TIMER, "timer", |
|---|
| 186 | 201 | timer_routine)) |
|---|
| 187 | 202 | panic ("Couldn't register timer int"); |
|---|
| 188 | 203 | |
|---|
| 189 | 204 | rtc->t1cr_omr = 0x04; /* Mode 2, ext clk */ |
|---|
| 190 | | - rtc->t1msb = 39999 >> 8; |
|---|
| 191 | | - rtc->t1lsb = 39999 & 0xff; |
|---|
| 205 | + rtc->t1msb = RTC_TIMER_COUNT >> 8; |
|---|
| 206 | + rtc->t1lsb = RTC_TIMER_COUNT & 0xff; |
|---|
| 192 | 207 | rtc->irr_icr1 &= 0xef; /* Route timer 1 to INTR pin */ |
|---|
| 193 | 208 | rtc->msr = 0x40; /* Access int.cntrl, etc */ |
|---|
| 194 | 209 | rtc->pfr_icr0 = 0x80; /* Just timer 1 ints enabled */ |
|---|
| .. | .. |
|---|
| 200 | 215 | |
|---|
| 201 | 216 | rtc->msr = msr; |
|---|
| 202 | 217 | |
|---|
| 218 | + clocksource_register_hz(&bvme6000_clk, RTC_TIMER_CLOCK_FREQ); |
|---|
| 219 | + |
|---|
| 203 | 220 | if (request_irq(BVME_IRQ_ABORT, bvme6000_abort_int, 0, |
|---|
| 204 | 221 | "abort", bvme6000_abort_int)) |
|---|
| 205 | 222 | panic ("Couldn't register abort int"); |
|---|
| 206 | 223 | } |
|---|
| 207 | 224 | |
|---|
| 208 | | - |
|---|
| 209 | | -/* This is always executed with interrupts disabled. */ |
|---|
| 210 | 225 | |
|---|
| 211 | 226 | /* |
|---|
| 212 | 227 | * NOTE: Don't accept any readings within 5us of rollover, as |
|---|
| .. | .. |
|---|
| 215 | 230 | * results... |
|---|
| 216 | 231 | */ |
|---|
| 217 | 232 | |
|---|
| 218 | | -u32 bvme6000_gettimeoffset(void) |
|---|
| 233 | +static u64 bvme6000_read_clk(struct clocksource *cs) |
|---|
| 219 | 234 | { |
|---|
| 235 | + unsigned long flags; |
|---|
| 220 | 236 | volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE; |
|---|
| 221 | 237 | volatile PitRegsPtr pit = (PitRegsPtr)BVME_PIT_BASE; |
|---|
| 222 | | - unsigned char msr = rtc->msr & 0xc0; |
|---|
| 238 | + unsigned char msr, msb; |
|---|
| 223 | 239 | unsigned char t1int, t1op; |
|---|
| 224 | 240 | u32 v = 800000, ov; |
|---|
| 225 | 241 | |
|---|
| 242 | + local_irq_save(flags); |
|---|
| 243 | + |
|---|
| 244 | + msr = rtc->msr & 0xc0; |
|---|
| 226 | 245 | rtc->msr = 0; /* Ensure timer registers accessible */ |
|---|
| 227 | 246 | |
|---|
| 228 | 247 | do { |
|---|
| .. | .. |
|---|
| 230 | 249 | t1int = rtc->msr & 0x20; |
|---|
| 231 | 250 | t1op = pit->pcdr & 0x04; |
|---|
| 232 | 251 | rtc->t1cr_omr |= 0x40; /* Latch timer1 */ |
|---|
| 233 | | - v = rtc->t1msb << 8; /* Read timer1 */ |
|---|
| 234 | | - v |= rtc->t1lsb; /* Read timer1 */ |
|---|
| 252 | + msb = rtc->t1msb; /* Read timer1 */ |
|---|
| 253 | + v = (msb << 8) | rtc->t1lsb; /* Read timer1 */ |
|---|
| 235 | 254 | } while (t1int != (rtc->msr & 0x20) || |
|---|
| 236 | 255 | t1op != (pit->pcdr & 0x04) || |
|---|
| 237 | 256 | abs(ov-v) > 80 || |
|---|
| 238 | | - v > 39960); |
|---|
| 257 | + v > RTC_TIMER_COUNT - (RTC_TIMER_COUNT / 100)); |
|---|
| 239 | 258 | |
|---|
| 240 | | - v = 39999 - v; |
|---|
| 259 | + v = RTC_TIMER_COUNT - v; |
|---|
| 241 | 260 | if (!t1op) /* If in second half cycle.. */ |
|---|
| 242 | | - v += 40000; |
|---|
| 243 | | - v /= 8; /* Convert ticks to microseconds */ |
|---|
| 244 | | - if (t1int) |
|---|
| 245 | | - v += 10000; /* Int pending, + 10ms */ |
|---|
| 261 | + v += RTC_TIMER_CYCLES / 2; |
|---|
| 262 | + if (msb > 0 && t1int) |
|---|
| 263 | + clk_offset = RTC_TIMER_CYCLES; |
|---|
| 246 | 264 | rtc->msr = msr; |
|---|
| 247 | 265 | |
|---|
| 248 | | - return v * 1000; |
|---|
| 266 | + v += clk_offset + clk_total; |
|---|
| 267 | + |
|---|
| 268 | + local_irq_restore(flags); |
|---|
| 269 | + |
|---|
| 270 | + return v; |
|---|
| 249 | 271 | } |
|---|
| 250 | 272 | |
|---|
| 251 | 273 | /* |
|---|