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 /*
31  * Prototypes of local functions.
32  */
33 /* 28-Jun-1994 sw - Note: hwt_restart() is also used in module 'drvfbi.c'. */
34 /*static void hwt_restart() ; */
35 
36 /************************
37  *
38  *	hwt_start
39  *
40  *	Start hardware timer (clock ticks are 16us).
41  *
42  *	void hwt_start(
43  *		struct s_smc *smc,
44  *		u_long time) ;
45  * In
46  *	smc - A pointer to the SMT Context structure.
47  *
48  *	time - The time in units of 16us to load the timer with.
49  * Out
50  *	Nothing.
51  *
52  ************************/
53 #define	HWT_MAX	(65000)
54 
hwt_start(struct s_smc * smc,u_long time)55 void hwt_start(struct s_smc *smc, u_long time)
56 {
57 	u_short	cnt ;
58 
59 	if (time > HWT_MAX)
60 		time = HWT_MAX ;
61 
62 	smc->hw.t_start = time ;
63 	smc->hw.t_stop = 0L ;
64 
65 	cnt = (u_short)time ;
66 	/*
67 	 * if time < 16 us
68 	 *	time = 16 us
69 	 */
70 	if (!cnt)
71 		cnt++ ;
72 
73 	outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ;	/* Load timer value. */
74 	outpw(ADDR(B2_TI_CRTL), TIM_START) ;		/* Start timer. */
75 
76 	smc->hw.timer_activ = TRUE ;
77 }
78 
79 /************************
80  *
81  *	hwt_stop
82  *
83  *	Stop hardware timer.
84  *
85  *	void hwt_stop(
86  *		struct s_smc *smc) ;
87  * In
88  *	smc - A pointer to the SMT Context structure.
89  * Out
90  *	Nothing.
91  *
92  ************************/
hwt_stop(struct s_smc * smc)93 void hwt_stop(struct s_smc *smc)
94 {
95 	outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
96 	outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ;
97 
98 	smc->hw.timer_activ = FALSE ;
99 }
100 
101 /************************
102  *
103  *	hwt_init
104  *
105  *	Initialize hardware timer.
106  *
107  *	void hwt_init(
108  *		struct s_smc *smc) ;
109  * In
110  *	smc - A pointer to the SMT Context structure.
111  * Out
112  *	Nothing.
113  *
114  ************************/
hwt_init(struct s_smc * smc)115 void hwt_init(struct s_smc *smc)
116 {
117 	smc->hw.t_start = 0 ;
118 	smc->hw.t_stop	= 0 ;
119 	smc->hw.timer_activ = FALSE ;
120 
121 	hwt_restart(smc) ;
122 }
123 
124 /************************
125  *
126  *	hwt_restart
127  *
128  *	Clear timer interrupt.
129  *
130  *	void hwt_restart(
131  *		struct s_smc *smc) ;
132  * In
133  *	smc - A pointer to the SMT Context structure.
134  * Out
135  *	Nothing.
136  *
137  ************************/
hwt_restart(struct s_smc * smc)138 void hwt_restart(struct s_smc *smc)
139 {
140 	hwt_stop(smc) ;
141 }
142 
143 /************************
144  *
145  *	hwt_read
146  *
147  *	Stop hardware timer and read time elapsed since last start.
148  *
149  *	u_long hwt_read(smc) ;
150  * In
151  *	smc - A pointer to the SMT Context structure.
152  * Out
153  *	The elapsed time since last start in units of 16us.
154  *
155  ************************/
hwt_read(struct s_smc * smc)156 u_long hwt_read(struct s_smc *smc)
157 {
158 	u_short	tr ;
159 	u_long	is ;
160 
161 	if (smc->hw.timer_activ) {
162 		hwt_stop(smc) ;
163 		tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ;
164 
165 		is = GET_ISR() ;
166 		/* Check if timer expired (or wraparound). */
167 		if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) {
168 			hwt_restart(smc) ;
169 			smc->hw.t_stop = smc->hw.t_start ;
170 		}
171 		else
172 			smc->hw.t_stop = smc->hw.t_start - tr ;
173 	}
174 	return smc->hw.t_stop;
175 }
176 
177 #ifdef	PCI
178 /************************
179  *
180  *	hwt_quick_read
181  *
182  *	Stop hardware timer and read timer value and start the timer again.
183  *
184  *	u_long hwt_read(smc) ;
185  * In
186  *	smc - A pointer to the SMT Context structure.
187  * Out
188  *	current timer value in units of 80ns.
189  *
190  ************************/
hwt_quick_read(struct s_smc * smc)191 u_long hwt_quick_read(struct s_smc *smc)
192 {
193 	u_long interval ;
194 	u_long time ;
195 
196 	interval = inpd(ADDR(B2_TI_INI)) ;
197 	outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
198 	time = inpd(ADDR(B2_TI_VAL)) ;
199 	outpd(ADDR(B2_TI_INI),time) ;
200 	outpw(ADDR(B2_TI_CRTL), TIM_START) ;
201 	outpd(ADDR(B2_TI_INI),interval) ;
202 
203 	return time;
204 }
205 
206 /************************
207  *
208  *	hwt_wait_time(smc,start,duration)
209  *
210  *	This function returnes after the amount of time is elapsed
211  *	since the start time.
212  *
213  * para	start		start time
214  *	duration	time to wait
215  *
216  * NOTE: The function will return immediately, if the timer is not
217  *	 started
218  ************************/
hwt_wait_time(struct s_smc * smc,u_long start,long int duration)219 void hwt_wait_time(struct s_smc *smc, u_long start, long int duration)
220 {
221 	long	diff ;
222 	long	interval ;
223 	int	wrapped ;
224 
225 	/*
226 	 * check if timer is running
227 	 */
228 	if (smc->hw.timer_activ == FALSE ||
229 		hwt_quick_read(smc) == hwt_quick_read(smc)) {
230 		return ;
231 	}
232 
233 	interval = inpd(ADDR(B2_TI_INI)) ;
234 	if (interval > duration) {
235 		do {
236 			diff = (long)(start - hwt_quick_read(smc)) ;
237 			if (diff < 0) {
238 				diff += interval ;
239 			}
240 		} while (diff <= duration) ;
241 	}
242 	else {
243 		diff = interval ;
244 		wrapped = 0 ;
245 		do {
246 			if (!wrapped) {
247 				if (hwt_quick_read(smc) >= start) {
248 					diff += interval ;
249 					wrapped = 1 ;
250 				}
251 			}
252 			else {
253 				if (hwt_quick_read(smc) < start) {
254 					wrapped = 0 ;
255 				}
256 			}
257 		} while (diff <= duration) ;
258 	}
259 }
260 #endif
261 
262