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 Thu Nov 20 11:49:47 2008 for RTAI API by doxygen 1.3.8