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