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