|  | /* | 
|  | *  linux/arch/cris/arch-v10/kernel/time.c | 
|  | * | 
|  | *  Copyright (C) 1991, 1992, 1995  Linus Torvalds | 
|  | *  Copyright (C) 1999-2002 Axis Communications AB | 
|  | * | 
|  | */ | 
|  |  | 
|  | #include <linux/timex.h> | 
|  | #include <linux/time.h> | 
|  | #include <linux/jiffies.h> | 
|  | #include <linux/interrupt.h> | 
|  | #include <linux/swap.h> | 
|  | #include <linux/sched.h> | 
|  | #include <linux/init.h> | 
|  | #include <linux/mm.h> | 
|  | #include <asm/types.h> | 
|  | #include <asm/signal.h> | 
|  | #include <asm/io.h> | 
|  | #include <asm/delay.h> | 
|  | #include <asm/irq_regs.h> | 
|  |  | 
|  | /* define this if you need to use print_timestamp */ | 
|  | /* it will make jiffies at 96 hz instead of 100 hz though */ | 
|  | #undef USE_CASCADE_TIMERS | 
|  |  | 
|  | unsigned long get_ns_in_jiffie(void) | 
|  | { | 
|  | unsigned char timer_count, t1; | 
|  | unsigned short presc_count; | 
|  | unsigned long ns; | 
|  | unsigned long flags; | 
|  |  | 
|  | local_irq_save(flags); | 
|  | timer_count = *R_TIMER0_DATA; | 
|  | presc_count = *R_TIM_PRESC_STATUS; | 
|  | /* presc_count might be wrapped */ | 
|  | t1 = *R_TIMER0_DATA; | 
|  |  | 
|  | if (timer_count != t1){ | 
|  | /* it wrapped, read prescaler again...  */ | 
|  | presc_count = *R_TIM_PRESC_STATUS; | 
|  | timer_count = t1; | 
|  | } | 
|  | local_irq_restore(flags); | 
|  | if (presc_count >= PRESCALE_VALUE/2 ){ | 
|  | presc_count =  PRESCALE_VALUE - presc_count + PRESCALE_VALUE/2; | 
|  | } else { | 
|  | presc_count =  PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2; | 
|  | } | 
|  |  | 
|  | ns = ( (TIMER0_DIV - timer_count) * ((1000000000/HZ)/TIMER0_DIV )) + | 
|  | ( (presc_count) * (1000000000/PRESCALE_FREQ)); | 
|  | return ns; | 
|  | } | 
|  |  | 
|  | static u32 cris_v10_gettimeoffset(void) | 
|  | { | 
|  | u32 count; | 
|  |  | 
|  | /* The timer interrupt comes from Etrax timer 0. In order to get | 
|  | * better precision, we check the current value. It might have | 
|  | * underflowed already though. | 
|  | */ | 
|  | count = *R_TIMER0_DATA; | 
|  |  | 
|  | /* Convert timer value to nsec */ | 
|  | return (TIMER0_DIV - count) * (NSEC_PER_SEC/HZ)/TIMER0_DIV; | 
|  | } | 
|  |  | 
|  | /* Excerpt from the Etrax100 HSDD about the built-in watchdog: | 
|  | * | 
|  | * 3.10.4 Watchdog timer | 
|  |  | 
|  | * When the watchdog timer is started, it generates an NMI if the watchdog | 
|  | * isn't restarted or stopped within 0.1 s. If it still isn't restarted or | 
|  | * stopped after an additional 3.3 ms, the watchdog resets the chip. | 
|  | * The watchdog timer is stopped after reset. The watchdog timer is controlled | 
|  | * by the R_WATCHDOG register. The R_WATCHDOG register contains an enable bit | 
|  | * and a 3-bit key value. The effect of writing to the R_WATCHDOG register is | 
|  | * described in the table below: | 
|  | * | 
|  | *   Watchdog    Value written: | 
|  | *   state:      To enable:  To key:      Operation: | 
|  | *   --------    ----------  -------      ---------- | 
|  | *   stopped         0         X          No effect. | 
|  | *   stopped         1       key_val      Start watchdog with key = key_val. | 
|  | *   started         0       ~key         Stop watchdog | 
|  | *   started         1       ~key         Restart watchdog with key = ~key. | 
|  | *   started         X       new_key_val  Change key to new_key_val. | 
|  | * | 
|  | * Note: '~' is the bitwise NOT operator. | 
|  | * | 
|  | */ | 
|  |  | 
|  | /* right now, starting the watchdog is the same as resetting it */ | 
|  | #define start_watchdog reset_watchdog | 
|  |  | 
|  | #ifdef CONFIG_ETRAX_WATCHDOG | 
|  | static int watchdog_key = 0;  /* arbitrary number */ | 
|  | #endif | 
|  |  | 
|  | /* number of pages to consider "out of memory". it is normal that the memory | 
|  | * is used though, so put this really low. | 
|  | */ | 
|  |  | 
|  | #define WATCHDOG_MIN_FREE_PAGES 8 | 
|  |  | 
|  | void reset_watchdog(void) | 
|  | { | 
|  | #if defined(CONFIG_ETRAX_WATCHDOG) | 
|  | /* only keep watchdog happy as long as we have memory left! */ | 
|  | if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) { | 
|  | /* reset the watchdog with the inverse of the old key */ | 
|  | watchdog_key ^= 0x7; /* invert key, which is 3 bits */ | 
|  | *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) | | 
|  | IO_STATE(R_WATCHDOG, enable, start); | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | /* stop the watchdog - we still need the correct key */ | 
|  |  | 
|  | void stop_watchdog(void) | 
|  | { | 
|  | #ifdef CONFIG_ETRAX_WATCHDOG | 
|  | watchdog_key ^= 0x7; /* invert key, which is 3 bits */ | 
|  | *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) | | 
|  | IO_STATE(R_WATCHDOG, enable, stop); | 
|  | #endif | 
|  | } | 
|  |  | 
|  |  | 
|  | extern void cris_do_profile(struct pt_regs *regs); | 
|  |  | 
|  | /* | 
|  | * timer_interrupt() needs to keep up the real-time clock, | 
|  | * as well as call the "xtime_update()" routine every clocktick | 
|  | */ | 
|  | static inline irqreturn_t timer_interrupt(int irq, void *dev_id) | 
|  | { | 
|  | struct pt_regs *regs = get_irq_regs(); | 
|  | /* acknowledge the timer irq */ | 
|  |  | 
|  | #ifdef USE_CASCADE_TIMERS | 
|  | *R_TIMER_CTRL = | 
|  | IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | | 
|  | IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | | 
|  | IO_STATE( R_TIMER_CTRL, i1, clr) | | 
|  | IO_STATE( R_TIMER_CTRL, tm1, run) | | 
|  | IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | | 
|  | IO_STATE( R_TIMER_CTRL, i0, clr) | | 
|  | IO_STATE( R_TIMER_CTRL, tm0, run) | | 
|  | IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); | 
|  | #else | 
|  | *R_TIMER_CTRL = r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i0, clr); | 
|  | #endif | 
|  |  | 
|  | /* reset watchdog otherwise it resets us! */ | 
|  | reset_watchdog(); | 
|  |  | 
|  | /* Update statistics. */ | 
|  | update_process_times(user_mode(regs)); | 
|  |  | 
|  | /* call the real timer interrupt handler */ | 
|  | xtime_update(1); | 
|  |  | 
|  | cris_do_profile(regs); /* Save profiling information */ | 
|  | return IRQ_HANDLED; | 
|  | } | 
|  |  | 
|  | /* timer is IRQF_SHARED so drivers can add stuff to the timer irq chain */ | 
|  |  | 
|  | static struct irqaction irq2  = { | 
|  | .handler = timer_interrupt, | 
|  | .flags = IRQF_SHARED, | 
|  | .name = "timer", | 
|  | }; | 
|  |  | 
|  | void __init time_init(void) | 
|  | { | 
|  | arch_gettimeoffset = cris_v10_gettimeoffset; | 
|  |  | 
|  | /* probe for the RTC and read it if it exists | 
|  | * Before the RTC can be probed the loops_per_usec variable needs | 
|  | * to be initialized to make usleep work. A better value for | 
|  | * loops_per_usec is calculated by the kernel later once the | 
|  | * clock has started. | 
|  | */ | 
|  | loops_per_usec = 50; | 
|  |  | 
|  | /* Setup the etrax timers | 
|  | * Base frequency is 25000 hz, divider 250 -> 100 HZ | 
|  | * In normal mode, we use timer0, so timer1 is free. In cascade | 
|  | * mode (which we sometimes use for debugging) both timers are used. | 
|  | * Remember that linux/timex.h contains #defines that rely on the | 
|  | * timer settings below (hz and divide factor) !!! | 
|  | */ | 
|  |  | 
|  | #ifdef USE_CASCADE_TIMERS | 
|  | *R_TIMER_CTRL = | 
|  | IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | | 
|  | IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | | 
|  | IO_STATE( R_TIMER_CTRL, i1, nop) | | 
|  | IO_STATE( R_TIMER_CTRL, tm1, stop_ld) | | 
|  | IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | | 
|  | IO_STATE( R_TIMER_CTRL, i0, nop) | | 
|  | IO_STATE( R_TIMER_CTRL, tm0, stop_ld) | | 
|  | IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); | 
|  |  | 
|  | *R_TIMER_CTRL = r_timer_ctrl_shadow = | 
|  | IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | | 
|  | IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | | 
|  | IO_STATE( R_TIMER_CTRL, i1, nop) | | 
|  | IO_STATE( R_TIMER_CTRL, tm1, run) | | 
|  | IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | | 
|  | IO_STATE( R_TIMER_CTRL, i0, nop) | | 
|  | IO_STATE( R_TIMER_CTRL, tm0, run) | | 
|  | IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); | 
|  | #else | 
|  | *R_TIMER_CTRL = | 
|  | IO_FIELD(R_TIMER_CTRL, timerdiv1, 192)      | | 
|  | IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV)      | | 
|  | IO_STATE(R_TIMER_CTRL, i1,        nop)      | | 
|  | IO_STATE(R_TIMER_CTRL, tm1,       stop_ld)  | | 
|  | IO_STATE(R_TIMER_CTRL, clksel1,   c19k2Hz)  | | 
|  | IO_STATE(R_TIMER_CTRL, i0,        nop)      | | 
|  | IO_STATE(R_TIMER_CTRL, tm0,       stop_ld)  | | 
|  | IO_STATE(R_TIMER_CTRL, clksel0,   flexible); | 
|  |  | 
|  | *R_TIMER_CTRL = r_timer_ctrl_shadow = | 
|  | IO_FIELD(R_TIMER_CTRL, timerdiv1, 192)      | | 
|  | IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV)      | | 
|  | IO_STATE(R_TIMER_CTRL, i1,        nop)      | | 
|  | IO_STATE(R_TIMER_CTRL, tm1,       run)      | | 
|  | IO_STATE(R_TIMER_CTRL, clksel1,   c19k2Hz)  | | 
|  | IO_STATE(R_TIMER_CTRL, i0,        nop)      | | 
|  | IO_STATE(R_TIMER_CTRL, tm0,       run)      | | 
|  | IO_STATE(R_TIMER_CTRL, clksel0,   flexible); | 
|  |  | 
|  | *R_TIMER_PRESCALE = PRESCALE_VALUE; | 
|  | #endif | 
|  |  | 
|  | /* unmask the timer irq */ | 
|  | *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer0, set); | 
|  |  | 
|  | /* now actually register the irq handler that calls timer_interrupt() */ | 
|  | setup_irq(2, &irq2); /* irq 2 is the timer0 irq in etrax */ | 
|  |  | 
|  | /* enable watchdog if we should use one */ | 
|  | #if defined(CONFIG_ETRAX_WATCHDOG) | 
|  | printk("Enabling watchdog...\n"); | 
|  | start_watchdog(); | 
|  |  | 
|  | /* If we use the hardware watchdog, we want to trap it as an NMI | 
|  | and dump registers before it resets us.  For this to happen, we | 
|  | must set the "m" NMI enable flag (which once set, is unset only | 
|  | when an NMI is taken). | 
|  |  | 
|  | The same goes for the external NMI, but that doesn't have any | 
|  | driver or infrastructure support yet.  */ | 
|  | asm ("setf m"); | 
|  |  | 
|  | *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, watchdog_nmi, set); | 
|  | *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, nmi, set); | 
|  | #endif | 
|  | } |