base/arch/arm/hal/mach-ep9301/ep9301-timer.c

Go to the documentation of this file.
00001 /*
00002  * ARM/EP9301 specific timer code
00003  *
00004  * COPYRIGHT (C) 2004 Michael Neuhauser, Firmix Software GmbH <mike@firmix.at>
00005  *
00006  * Acknowledgements:
00007  *  Paolo Mantegazza <mantegazza@aero.polimi.it>, creator of RTAI 
00008  *
00009  * This program is free software; you can redistribute it and/or modify it under
00010  * the terms of version 2 of the GNU General Public License as published by the
00011  * Free Software Foundation.
00012  *
00013  * This program is distributed in the hope that it will be useful, but WITHOUT
00014  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00015  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
00016  * details.
00017  *
00018  * You should have received a copy of the GNU General Public License along with
00019  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00020  * Place, Suite 330, Boston, MA  02111-1307  USA
00021  */
00022 
00023 #include <rtai.h>
00024 #include <rtai_trace.h>
00025 #include <asm/arch/ep93xx_tsc.h>
00026 
00027 /*
00028  * Install a timer interrupt handler as a real-time ISR and set hardware-timer
00029  * to requested period.
00030  * tick = 0: oneshot mode
00031  * tick > 0: periodic mode (and tick specifies the period in timer-ticks)
00032  */
00033 int
00034 rt_request_timer(rt_timer_irq_handler_t handler, unsigned int tick, int i386_legacy_dummy)
00035 {
00036     unsigned long flags;
00037     int is_oneshot = (tick == 0);
00038 
00039     TRACE_RTAI_TIMER(TRACE_RTAI_EV_TIMER_REQUEST, handler, tick);
00040 
00041     /* initial one-shot delay is 1/HZ seconds */
00042     if (is_oneshot)
00043     tick = LATCH;
00044 
00045     flags = rtai_critical_enter(NULL);
00046 
00047     /* stop timer & set reload value */
00048     outl(0, TIMER1CONTROL);
00049     outl(tick - 1, TIMER1LOAD);
00050 
00051     /* sync to jiffy clock phase (still neccessary with Adeos?) */
00052     rt_times.tick_time = ({
00053     ep93xx_tsc_t t0;
00054     unsigned long target_offset;
00055     unsigned long t;
00056 
00057     /* spin until we are not to close (~ 10 µs) before jiffy time-point */
00058     do {
00059         t0.ll = ep93xx_rdtsc();
00060         unsigned long long const realtime_jiffies = (long long)(t0.ll * HZ) / (long)RTAI_TSC_FREQ;
00061         unsigned long const current_offset = t0.ll - (realtime_jiffies * RTAI_TSC_FREQ) / HZ;
00062         target_offset = ((RTAI_TSC_FREQ + HZ/2) / HZ) - current_offset;
00063     } while (target_offset < 10);
00064 
00065     /* spin until we have passed jiffy time-point */
00066     do {
00067         t = inl(TIMER4VALUELOW);
00068     } while ((t - t0.u.low) < target_offset);
00069 
00070     /* quickly start timer (508.469 kHz clock, free runing or periodic mode) */
00071     outl((is_oneshot) ? 0x88 : 0xc8, TIMER1CONTROL);
00072 
00073     /* set t0 to current time */
00074     if (t < t0.u.low)
00075         ++t0.u.high;
00076     t0.u.low = t;
00077 
00078     t0.ll;
00079     });
00080 
00081     /* ack interrupt (timer may have underflowed since lock) */
00082     outl(1, TIMER1CLEAR);
00083 
00084     /* set up rt_times structure */
00085     if (is_oneshot) {
00086     /* oneshot mode: unit is TSC-tick */
00087     rt_times.linux_time = rtai_llimd(ep93xx_jiffies_done * LATCH, RTAI_TSC_FREQ, RTAI_TIMER_FREQ);
00088     rt_times.linux_tick = rtai_imuldiv(LATCH, RTAI_TSC_FREQ, RTAI_TIMER_FREQ);
00089     rt_times.periodic_tick  = rt_times.linux_tick;
00090     } else {
00091     /* periodic mode: unit is irq-timer-tick */
00092     rt_times.tick_time  = rtai_llimd(rt_times.tick_time, RTAI_TIMER_FREQ, RTAI_TSC_FREQ);
00093     rt_times.linux_time = ep93xx_jiffies_done * LATCH;
00094     rt_times.linux_tick = LATCH;
00095     rt_times.periodic_tick  = tick;
00096     }
00097     rt_times.intr_time  = rt_times.tick_time + rt_times.periodic_tick;
00098 
00099     rt_release_irq(RTAI_TIMER_IRQ);
00100     if (rt_request_irq(RTAI_TIMER_IRQ, (rt_irq_handler_t)handler, NULL, 0) < 0) {
00101     rtai_critical_exit(flags);
00102     return -EINVAL;
00103     }
00104 
00105     /* Note that it is not necessary to change the linux handler of the
00106      * timer-irq as it was done on RTAI/ARM before Adeos. This was done to
00107      * enable/disable hardware ack. Now Adeos will do all for us, using the
00108      * irq_des[].mask_ack function (which has to be set up accordingly in
00109      * arch/arm/mach-MACH/irq.c:MACH_init_irq()).
00110      */
00111 
00112     rtai_critical_exit(flags);
00113     return 0;
00114 }
00115 
00116 /*
00117  * Uninstall a timer handler previously set by rt_request_timer() and reset
00118  * hardware-timer to Linux HZ-tick.
00119  */
00120 void
00121 rt_free_timer(void)
00122 {
00123     unsigned long flags;
00124 
00125     TRACE_RTAI_TIMER(TRACE_RTAI_EV_TIMER_FREE, 0, 0);
00126 
00127     flags = rtai_critical_enter(NULL);
00128 
00129     /* no need to sync with linux jiffy clock because jiffy clock is synced to
00130      * TSC (i.e. absolute time) by linux timer interrupt handlers */
00131 
00132     /* stop timer for re-programming */
00133     outl(0, TIMER1CONTROL);
00134     /* set reload value */
00135     outl(LATCH - 1, TIMER1LOAD);
00136     /* set timer to 508 kHz clock, periodic mode and start it */
00137     outl(0xc8, TIMER1CONTROL);
00138     /* ack interrupt that may have occured */
00139     outl(1, TIMER1CLEAR);
00140 
00141     rt_release_irq(RTAI_TIMER_IRQ);
00142 
00143     rtai_critical_exit(flags);
00144 }

Generated on Tue Feb 2 17:46:04 2010 for RTAI API by  doxygen 1.4.7