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