diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-10-05 01:18:40 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-10-05 01:18:40 +0000 |
commit | 012bb3e61e5eced6c610f9e036372bf0c8def2d1 (patch) | |
tree | 87efc733f9b164e8c85c0336f92c8fb7eff6d183 /arch/ppc/kernel/prep_setup.c | |
parent | 625a1589d3d6464b5d90b8a0918789e3afffd220 (diff) |
Merge with Linux 2.4.0-test9. Please check DECstation, I had a number
of rejects to fixup while integrating Linus patches. I also found
that this kernel will only boot SMP on Origin; the UP kernel freeze
soon after bootup with SCSI timeout messages. I commit this anyway
since I found that the last CVS versions had the same problem.
Diffstat (limited to 'arch/ppc/kernel/prep_setup.c')
-rw-r--r-- | arch/ppc/kernel/prep_setup.c | 107 |
1 files changed, 67 insertions, 40 deletions
diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c index a09b4cf81..d72e74735 100644 --- a/arch/ppc/kernel/prep_setup.c +++ b/arch/ppc/kernel/prep_setup.c @@ -365,14 +365,13 @@ prep_setup_arch(void) */ void __init prep_res_calibrate_decr(void) { - int freq, divisor; + unsigned long freq, divisor=4; freq = res->VitalProductData.ProcessorBusHz; - divisor = 4; - printk("time_init: decrementer frequency = %d/%d\n", freq, divisor); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + (freq/divisor)/1000000, (freq/divisor)%1000000); + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); } /* @@ -381,32 +380,30 @@ void __init prep_res_calibrate_decr(void) * but on prep we have to figure it out. * -- Cort */ -int calibrate_done = 0; -volatile int *done_ptr = &calibrate_done; +/* Done with 3 interrupts: the first one primes the cache and the + * 2 following ones measure the interval. The precision of the method + * is still doubtful due to the short interval sampled. + */ +static __initdata volatile int calibrate_steps = 3; +static __initdata unsigned tbstamp; void __init prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs *regs) { - unsigned long freq, divisor; - static unsigned long t1 = 0, t2 = 0; - - if ( !t1 ) - t1 = get_dec(); - else if (!t2) - { - t2 = get_dec(); - t2 = t1-t2; /* decr's in 1/HZ */ - t2 = t2*HZ; /* # decrs in 1s - thus in Hz */ - freq = t2 * 60; /* try to make freq/1e6 an integer */ - divisor = 60; - printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n", - freq, divisor,t2>>20); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; - *done_ptr = 1; + unsigned long t, freq; + int step=--calibrate_steps; + + t = get_tbl(); + if (step > 0) { + tbstamp = t; + } else { + freq = (t - tbstamp)*HZ; + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); } } @@ -428,17 +425,43 @@ void __init prep_calibrate_decr(void) if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0) panic("Could not allocate timer IRQ!"); __sti(); - while ( ! *done_ptr ) /* nothing */; /* wait for calibrate */ + while ( calibrate_steps ) /* nothing */; /* wait for calibrate */ restore_flags(flags); free_irq( 0, NULL); } -/* We use the NVRAM RTC to time a second to calibrate the decrementer. */ +static long __init mk48t59_init(void) { + unsigned char tmp; + + tmp = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB); + if (tmp & MK48T59_RTC_CB_STOP) { + printk("Warning: RTC was stopped, date will be wrong.\n"); + ppc_md.nvram_write_val(MK48T59_RTC_CONTROLB, + tmp & ~MK48T59_RTC_CB_STOP); + /* Low frequency crystal oscillators may take a very long + * time to startup and stabilize. For now just ignore the + * the issue, but attempting to calibrate the decrementer + * from the RTC just after this wakeup is likely to be very + * inaccurate. Firmware should not allow to load + * the OS with the clock stopped anyway... + */ + } + /* Ensure that the clock registers are updated */ + tmp = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA); + tmp &= ~(MK48T59_RTC_CA_READ | MK48T59_RTC_CA_WRITE); + ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, tmp); + return 0; +} + +/* We use the NVRAM RTC to time a second to calibrate the decrementer, + * the RTC registers have just been set up in the right state by the + * preceding routine. + */ void __init mk48t59_calibrate_decr(void) { - unsigned long freq, divisor; - unsigned long t1, t2; + unsigned long freq; + unsigned long t1; unsigned char save_control; long i; unsigned char sec; @@ -458,29 +481,31 @@ void __init mk48t59_calibrate_decr(void) /* Read the seconds value to see when it changes. */ sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS); + /* Actually this is bad for precision, we should have a loop in + * which we only read the seconds counter. nvram_read_val writes + * the address bytes on every call and this takes a lot of time. + * Perhaps an nvram_wait_change method returning a time + * stamp with a loop count as parameter would be the solution. + */ for (i = 0 ; i < 1000000 ; i++) { /* may take up to 1 second... */ + t1 = get_tbl(); if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) { break; } } - t1 = get_dec(); sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS); for (i = 0 ; i < 1000000 ; i++) { /* Should take up 1 second... */ + freq = get_tbl()-t1; if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) { break; } } - t2 = t1 - get_dec(); - - freq = t2 * 60; /* try to make freq/1e6 an integer */ - divisor = 60; - printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n", - freq, divisor,t2>>20); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); } void __prep @@ -788,6 +813,7 @@ prep_init(unsigned long r3, unsigned long r4, unsigned long r5, { ppc_md.set_rtc_time = mk48t59_set_rtc_time; ppc_md.get_rtc_time = mk48t59_get_rtc_time; + ppc_md.time_init = mk48t59_init; } else { @@ -808,6 +834,7 @@ prep_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.set_rtc_time = mk48t59_set_rtc_time; ppc_md.get_rtc_time = mk48t59_get_rtc_time; ppc_md.calibrate_decr = mk48t59_calibrate_decr; + ppc_md.time_init = mk48t59_init; } #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) |