1 /******************************************************************************
2 *
3 * (C)Copyright 1998,1999 SysKonnect,
4 * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
5 *
6 * See the file "skfddi.c" for further information.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * The information in this file is provided "AS IS" without warranty.
14 *
15 ******************************************************************************/
16
17 /*
18 * Timer Driver for FBI board (timer chip 82C54)
19 */
20
21 /*
22 * Modifications:
23 *
24 * 28-Jun-1994 sw Edit v1.6.
25 * MCA: Added support for the SK-NET FDDI-FM2 adapter. The
26 * following functions have been added(+) or modified(*):
27 * hwt_start(*), hwt_stop(*), hwt_restart(*), hwt_read(*)
28 */
29
30 #include "h/types.h"
31 #include "h/fddi.h"
32 #include "h/smc.h"
33
34 #ifndef lint
35 static const char ID_sccs[] = "@(#)hwt.c 1.13 97/04/23 (C) SK " ;
36 #endif
37
38 /*
39 * Prototypes of local functions.
40 */
41 /* 28-Jun-1994 sw - Note: hwt_restart() is also used in module 'drvfbi.c'. */
42 /*static*/ void hwt_restart() ;
43
44 /************************
45 *
46 * hwt_start
47 *
48 * Start hardware timer (clock ticks are 16us).
49 *
50 * void hwt_start(
51 * struct s_smc *smc,
52 * u_long time) ;
53 * In
54 * smc - A pointer to the SMT Context structure.
55 *
56 * time - The time in units of 16us to load the timer with.
57 * Out
58 * Nothing.
59 *
60 ************************/
61 #define HWT_MAX (65000)
62
hwt_start(smc,time)63 void hwt_start(smc, time)
64 struct s_smc *smc ;
65 u_long time ;
66 {
67 u_short cnt ;
68
69 if (time > HWT_MAX)
70 time = HWT_MAX ;
71
72 smc->hw.t_start = time ;
73 smc->hw.t_stop = 0L ;
74
75 cnt = (u_short)time ;
76 /*
77 * if time < 16 us
78 * time = 16 us
79 */
80 if (!cnt)
81 cnt++ ;
82 #ifndef PCI
83 /*
84 * 6.25MHz -> CLK0 : T0 (cnt0 = 16us) -> OUT0
85 * OUT0 -> CLK1 : T1 (cnt1) OUT1 -> ISRA(IS_TIMINT)
86 */
87 OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */
88 OUT_82c54_TIMER(1,cnt & 0xff) ; /* LSB */
89 OUT_82c54_TIMER(1,(cnt>>8) & 0xff) ; /* MSB */
90 /*
91 * start timer by switching counter 0 to mode 3
92 * T0 resolution 16 us (CLK0=0.16us)
93 */
94 OUT_82c54_TIMER(3,0<<6 | 3<<4 | 3<<1) ; /* counter 0, mode 3 */
95 OUT_82c54_TIMER(0,100) ; /* LSB */
96 OUT_82c54_TIMER(0,0) ; /* MSB */
97 #else /* PCI */
98 outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ; /* Load timer value. */
99 outpw(ADDR(B2_TI_CRTL), TIM_START) ; /* Start timer. */
100 #endif /* PCI */
101 smc->hw.timer_activ = TRUE ;
102 }
103
104 /************************
105 *
106 * hwt_stop
107 *
108 * Stop hardware timer.
109 *
110 * void hwt_stop(
111 * struct s_smc *smc) ;
112 * In
113 * smc - A pointer to the SMT Context structure.
114 * Out
115 * Nothing.
116 *
117 ************************/
hwt_stop(smc)118 void hwt_stop(smc)
119 struct s_smc *smc ;
120 {
121 #ifndef PCI
122 /* stop counter 0 by switching to mode 0 */
123 OUT_82c54_TIMER(3,0<<6 | 3<<4 | 0<<1) ; /* counter 0, mode 0 */
124 OUT_82c54_TIMER(0,0) ; /* LSB */
125 OUT_82c54_TIMER(0,0) ; /* MSB */
126 #else /* PCI */
127 outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
128 outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ;
129 #endif /* PCI */
130
131 smc->hw.timer_activ = FALSE ;
132 }
133
134 /************************
135 *
136 * hwt_init
137 *
138 * Initialize hardware timer.
139 *
140 * void hwt_init(
141 * struct s_smc *smc) ;
142 * In
143 * smc - A pointer to the SMT Context structure.
144 * Out
145 * Nothing.
146 *
147 ************************/
hwt_init(smc)148 void hwt_init(smc)
149 struct s_smc *smc ;
150 {
151 smc->hw.t_start = 0 ;
152 smc->hw.t_stop = 0 ;
153 smc->hw.timer_activ = FALSE ;
154
155 hwt_restart(smc) ;
156 }
157
158 /************************
159 *
160 * hwt_restart
161 *
162 * Clear timer interrupt.
163 *
164 * void hwt_restart(
165 * struct s_smc *smc) ;
166 * In
167 * smc - A pointer to the SMT Context structure.
168 * Out
169 * Nothing.
170 *
171 ************************/
hwt_restart(smc)172 void hwt_restart(smc)
173 struct s_smc *smc ;
174 {
175 hwt_stop(smc) ;
176 #ifndef PCI
177 OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */
178 OUT_82c54_TIMER(1,1 ) ; /* LSB */
179 OUT_82c54_TIMER(1,0 ) ; /* MSB */
180 #endif
181 }
182
183 /************************
184 *
185 * hwt_read
186 *
187 * Stop hardware timer and read time elapsed since last start.
188 *
189 * u_long hwt_read(smc) ;
190 * In
191 * smc - A pointer to the SMT Context structure.
192 * Out
193 * The elapsed time since last start in units of 16us.
194 *
195 ************************/
hwt_read(smc)196 u_long hwt_read(smc)
197 struct s_smc *smc ;
198 {
199 u_short tr ;
200 #ifndef PCI
201 u_short is ;
202 #else
203 u_long is ;
204 #endif
205
206 if (smc->hw.timer_activ) {
207 hwt_stop(smc) ;
208 #ifndef PCI
209 OUT_82c54_TIMER(3,1<<6) ; /* latch command */
210 tr = IN_82c54_TIMER(1) & 0xff ;
211 tr += (IN_82c54_TIMER(1) & 0xff)<<8 ;
212 #else /* PCI */
213 tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ;
214 #endif /* PCI */
215 is = GET_ISR() ;
216 /* Check if timer expired (or wraparound). */
217 if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) {
218 hwt_restart(smc) ;
219 smc->hw.t_stop = smc->hw.t_start ;
220 }
221 else
222 smc->hw.t_stop = smc->hw.t_start - tr ;
223 }
224 return (smc->hw.t_stop) ;
225 }
226
227 #ifdef PCI
228 /************************
229 *
230 * hwt_quick_read
231 *
232 * Stop hardware timer and read timer value and start the timer again.
233 *
234 * u_long hwt_read(smc) ;
235 * In
236 * smc - A pointer to the SMT Context structure.
237 * Out
238 * current timer value in units of 80ns.
239 *
240 ************************/
hwt_quick_read(smc)241 u_long hwt_quick_read(smc)
242 struct s_smc *smc ;
243 {
244 u_long interval ;
245 u_long time ;
246
247 interval = inpd(ADDR(B2_TI_INI)) ;
248 outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
249 time = inpd(ADDR(B2_TI_VAL)) ;
250 outpd(ADDR(B2_TI_INI),time) ;
251 outpw(ADDR(B2_TI_CRTL), TIM_START) ;
252 outpd(ADDR(B2_TI_INI),interval) ;
253
254 return(time) ;
255 }
256
257 /************************
258 *
259 * hwt_wait_time(smc,start,duration)
260 *
261 * This function returnes after the amount of time is elapsed
262 * since the start time.
263 *
264 * para start start time
265 * duration time to wait
266 *
267 * NOTE: The fuction will return immediatly, if the timer is not
268 * started
269 ************************/
hwt_wait_time(smc,start,duration)270 void hwt_wait_time(smc,start,duration)
271 struct s_smc *smc ;
272 u_long start ;
273 long duration ;
274 {
275 long diff ;
276 long interval ;
277 int wrapped ;
278
279 /*
280 * check if timer is running
281 */
282 if (smc->hw.timer_activ == FALSE ||
283 hwt_quick_read(smc) == hwt_quick_read(smc)) {
284 return ;
285 }
286
287 interval = inpd(ADDR(B2_TI_INI)) ;
288 if (interval > duration) {
289 do {
290 diff = (long)(start - hwt_quick_read(smc)) ;
291 if (diff < 0) {
292 diff += interval ;
293 }
294 } while (diff <= duration) ;
295 }
296 else {
297 diff = interval ;
298 wrapped = 0 ;
299 do {
300 if (!wrapped) {
301 if (hwt_quick_read(smc) >= start) {
302 diff += interval ;
303 wrapped = 1 ;
304 }
305 }
306 else {
307 if (hwt_quick_read(smc) < start) {
308 wrapped = 0 ;
309 }
310 }
311 } while (diff <= duration) ;
312 }
313 }
314 #endif
315