xref: /openbmc/linux/drivers/net/fddi/skfp/hwt.c (revision 2874c5fd284268364ece81a7bd936f3c8168e567)
1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
233f810b2SJeff Kirsher /******************************************************************************
333f810b2SJeff Kirsher  *
433f810b2SJeff Kirsher  *	(C)Copyright 1998,1999 SysKonnect,
533f810b2SJeff Kirsher  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
633f810b2SJeff Kirsher  *
733f810b2SJeff Kirsher  *	See the file "skfddi.c" for further information.
833f810b2SJeff Kirsher  *
933f810b2SJeff Kirsher  *	The information in this file is provided "AS IS" without warranty.
1033f810b2SJeff Kirsher  *
1133f810b2SJeff Kirsher  ******************************************************************************/
1233f810b2SJeff Kirsher 
1333f810b2SJeff Kirsher /*
1433f810b2SJeff Kirsher  * Timer Driver for FBI board (timer chip 82C54)
1533f810b2SJeff Kirsher  */
1633f810b2SJeff Kirsher 
1733f810b2SJeff Kirsher /*
1833f810b2SJeff Kirsher  * Modifications:
1933f810b2SJeff Kirsher  *
2033f810b2SJeff Kirsher  *	28-Jun-1994 sw	Edit v1.6.
2133f810b2SJeff Kirsher  *			MCA: Added support for the SK-NET FDDI-FM2 adapter. The
2233f810b2SJeff Kirsher  *			 following functions have been added(+) or modified(*):
2333f810b2SJeff Kirsher  *			 hwt_start(*), hwt_stop(*), hwt_restart(*), hwt_read(*)
2433f810b2SJeff Kirsher  */
2533f810b2SJeff Kirsher 
2633f810b2SJeff Kirsher #include "h/types.h"
2733f810b2SJeff Kirsher #include "h/fddi.h"
2833f810b2SJeff Kirsher #include "h/smc.h"
2933f810b2SJeff Kirsher 
3033f810b2SJeff Kirsher #ifndef	lint
3133f810b2SJeff Kirsher static const char ID_sccs[] = "@(#)hwt.c	1.13 97/04/23 (C) SK " ;
3233f810b2SJeff Kirsher #endif
3333f810b2SJeff Kirsher 
3433f810b2SJeff Kirsher /*
3533f810b2SJeff Kirsher  * Prototypes of local functions.
3633f810b2SJeff Kirsher  */
3733f810b2SJeff Kirsher /* 28-Jun-1994 sw - Note: hwt_restart() is also used in module 'drvfbi.c'. */
3833f810b2SJeff Kirsher /*static void hwt_restart() ; */
3933f810b2SJeff Kirsher 
4033f810b2SJeff Kirsher /************************
4133f810b2SJeff Kirsher  *
4233f810b2SJeff Kirsher  *	hwt_start
4333f810b2SJeff Kirsher  *
4433f810b2SJeff Kirsher  *	Start hardware timer (clock ticks are 16us).
4533f810b2SJeff Kirsher  *
4633f810b2SJeff Kirsher  *	void hwt_start(
4733f810b2SJeff Kirsher  *		struct s_smc *smc,
4833f810b2SJeff Kirsher  *		u_long time) ;
4933f810b2SJeff Kirsher  * In
5033f810b2SJeff Kirsher  *	smc - A pointer to the SMT Context structure.
5133f810b2SJeff Kirsher  *
5233f810b2SJeff Kirsher  *	time - The time in units of 16us to load the timer with.
5333f810b2SJeff Kirsher  * Out
5433f810b2SJeff Kirsher  *	Nothing.
5533f810b2SJeff Kirsher  *
5633f810b2SJeff Kirsher  ************************/
5733f810b2SJeff Kirsher #define	HWT_MAX	(65000)
5833f810b2SJeff Kirsher 
5933f810b2SJeff Kirsher void hwt_start(struct s_smc *smc, u_long time)
6033f810b2SJeff Kirsher {
6133f810b2SJeff Kirsher 	u_short	cnt ;
6233f810b2SJeff Kirsher 
6333f810b2SJeff Kirsher 	if (time > HWT_MAX)
6433f810b2SJeff Kirsher 		time = HWT_MAX ;
6533f810b2SJeff Kirsher 
6633f810b2SJeff Kirsher 	smc->hw.t_start = time ;
6733f810b2SJeff Kirsher 	smc->hw.t_stop = 0L ;
6833f810b2SJeff Kirsher 
6933f810b2SJeff Kirsher 	cnt = (u_short)time ;
7033f810b2SJeff Kirsher 	/*
7133f810b2SJeff Kirsher 	 * if time < 16 us
7233f810b2SJeff Kirsher 	 *	time = 16 us
7333f810b2SJeff Kirsher 	 */
7433f810b2SJeff Kirsher 	if (!cnt)
7533f810b2SJeff Kirsher 		cnt++ ;
7633f810b2SJeff Kirsher 
7733f810b2SJeff Kirsher 	outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ;	/* Load timer value. */
7833f810b2SJeff Kirsher 	outpw(ADDR(B2_TI_CRTL), TIM_START) ;		/* Start timer. */
7933f810b2SJeff Kirsher 
8033f810b2SJeff Kirsher 	smc->hw.timer_activ = TRUE ;
8133f810b2SJeff Kirsher }
8233f810b2SJeff Kirsher 
8333f810b2SJeff Kirsher /************************
8433f810b2SJeff Kirsher  *
8533f810b2SJeff Kirsher  *	hwt_stop
8633f810b2SJeff Kirsher  *
8733f810b2SJeff Kirsher  *	Stop hardware timer.
8833f810b2SJeff Kirsher  *
8933f810b2SJeff Kirsher  *	void hwt_stop(
9033f810b2SJeff Kirsher  *		struct s_smc *smc) ;
9133f810b2SJeff Kirsher  * In
9233f810b2SJeff Kirsher  *	smc - A pointer to the SMT Context structure.
9333f810b2SJeff Kirsher  * Out
9433f810b2SJeff Kirsher  *	Nothing.
9533f810b2SJeff Kirsher  *
9633f810b2SJeff Kirsher  ************************/
9733f810b2SJeff Kirsher void hwt_stop(struct s_smc *smc)
9833f810b2SJeff Kirsher {
9933f810b2SJeff Kirsher 	outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
10033f810b2SJeff Kirsher 	outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ;
10133f810b2SJeff Kirsher 
10233f810b2SJeff Kirsher 	smc->hw.timer_activ = FALSE ;
10333f810b2SJeff Kirsher }
10433f810b2SJeff Kirsher 
10533f810b2SJeff Kirsher /************************
10633f810b2SJeff Kirsher  *
10733f810b2SJeff Kirsher  *	hwt_init
10833f810b2SJeff Kirsher  *
10933f810b2SJeff Kirsher  *	Initialize hardware timer.
11033f810b2SJeff Kirsher  *
11133f810b2SJeff Kirsher  *	void hwt_init(
11233f810b2SJeff Kirsher  *		struct s_smc *smc) ;
11333f810b2SJeff Kirsher  * In
11433f810b2SJeff Kirsher  *	smc - A pointer to the SMT Context structure.
11533f810b2SJeff Kirsher  * Out
11633f810b2SJeff Kirsher  *	Nothing.
11733f810b2SJeff Kirsher  *
11833f810b2SJeff Kirsher  ************************/
11933f810b2SJeff Kirsher void hwt_init(struct s_smc *smc)
12033f810b2SJeff Kirsher {
12133f810b2SJeff Kirsher 	smc->hw.t_start = 0 ;
12233f810b2SJeff Kirsher 	smc->hw.t_stop	= 0 ;
12333f810b2SJeff Kirsher 	smc->hw.timer_activ = FALSE ;
12433f810b2SJeff Kirsher 
12533f810b2SJeff Kirsher 	hwt_restart(smc) ;
12633f810b2SJeff Kirsher }
12733f810b2SJeff Kirsher 
12833f810b2SJeff Kirsher /************************
12933f810b2SJeff Kirsher  *
13033f810b2SJeff Kirsher  *	hwt_restart
13133f810b2SJeff Kirsher  *
13233f810b2SJeff Kirsher  *	Clear timer interrupt.
13333f810b2SJeff Kirsher  *
13433f810b2SJeff Kirsher  *	void hwt_restart(
13533f810b2SJeff Kirsher  *		struct s_smc *smc) ;
13633f810b2SJeff Kirsher  * In
13733f810b2SJeff Kirsher  *	smc - A pointer to the SMT Context structure.
13833f810b2SJeff Kirsher  * Out
13933f810b2SJeff Kirsher  *	Nothing.
14033f810b2SJeff Kirsher  *
14133f810b2SJeff Kirsher  ************************/
14233f810b2SJeff Kirsher void hwt_restart(struct s_smc *smc)
14333f810b2SJeff Kirsher {
14433f810b2SJeff Kirsher 	hwt_stop(smc) ;
14533f810b2SJeff Kirsher }
14633f810b2SJeff Kirsher 
14733f810b2SJeff Kirsher /************************
14833f810b2SJeff Kirsher  *
14933f810b2SJeff Kirsher  *	hwt_read
15033f810b2SJeff Kirsher  *
15133f810b2SJeff Kirsher  *	Stop hardware timer and read time elapsed since last start.
15233f810b2SJeff Kirsher  *
15333f810b2SJeff Kirsher  *	u_long hwt_read(smc) ;
15433f810b2SJeff Kirsher  * In
15533f810b2SJeff Kirsher  *	smc - A pointer to the SMT Context structure.
15633f810b2SJeff Kirsher  * Out
15733f810b2SJeff Kirsher  *	The elapsed time since last start in units of 16us.
15833f810b2SJeff Kirsher  *
15933f810b2SJeff Kirsher  ************************/
16033f810b2SJeff Kirsher u_long hwt_read(struct s_smc *smc)
16133f810b2SJeff Kirsher {
16233f810b2SJeff Kirsher 	u_short	tr ;
16333f810b2SJeff Kirsher 	u_long	is ;
16433f810b2SJeff Kirsher 
16533f810b2SJeff Kirsher 	if (smc->hw.timer_activ) {
16633f810b2SJeff Kirsher 		hwt_stop(smc) ;
16733f810b2SJeff Kirsher 		tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ;
16833f810b2SJeff Kirsher 
16933f810b2SJeff Kirsher 		is = GET_ISR() ;
17033f810b2SJeff Kirsher 		/* Check if timer expired (or wraparound). */
17133f810b2SJeff Kirsher 		if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) {
17233f810b2SJeff Kirsher 			hwt_restart(smc) ;
17333f810b2SJeff Kirsher 			smc->hw.t_stop = smc->hw.t_start ;
17433f810b2SJeff Kirsher 		}
17533f810b2SJeff Kirsher 		else
17633f810b2SJeff Kirsher 			smc->hw.t_stop = smc->hw.t_start - tr ;
17733f810b2SJeff Kirsher 	}
17833f810b2SJeff Kirsher 	return smc->hw.t_stop;
17933f810b2SJeff Kirsher }
18033f810b2SJeff Kirsher 
18133f810b2SJeff Kirsher #ifdef	PCI
18233f810b2SJeff Kirsher /************************
18333f810b2SJeff Kirsher  *
18433f810b2SJeff Kirsher  *	hwt_quick_read
18533f810b2SJeff Kirsher  *
18633f810b2SJeff Kirsher  *	Stop hardware timer and read timer value and start the timer again.
18733f810b2SJeff Kirsher  *
18833f810b2SJeff Kirsher  *	u_long hwt_read(smc) ;
18933f810b2SJeff Kirsher  * In
19033f810b2SJeff Kirsher  *	smc - A pointer to the SMT Context structure.
19133f810b2SJeff Kirsher  * Out
19233f810b2SJeff Kirsher  *	current timer value in units of 80ns.
19333f810b2SJeff Kirsher  *
19433f810b2SJeff Kirsher  ************************/
19533f810b2SJeff Kirsher u_long hwt_quick_read(struct s_smc *smc)
19633f810b2SJeff Kirsher {
19733f810b2SJeff Kirsher 	u_long interval ;
19833f810b2SJeff Kirsher 	u_long time ;
19933f810b2SJeff Kirsher 
20033f810b2SJeff Kirsher 	interval = inpd(ADDR(B2_TI_INI)) ;
20133f810b2SJeff Kirsher 	outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
20233f810b2SJeff Kirsher 	time = inpd(ADDR(B2_TI_VAL)) ;
20333f810b2SJeff Kirsher 	outpd(ADDR(B2_TI_INI),time) ;
20433f810b2SJeff Kirsher 	outpw(ADDR(B2_TI_CRTL), TIM_START) ;
20533f810b2SJeff Kirsher 	outpd(ADDR(B2_TI_INI),interval) ;
20633f810b2SJeff Kirsher 
20733f810b2SJeff Kirsher 	return time;
20833f810b2SJeff Kirsher }
20933f810b2SJeff Kirsher 
21033f810b2SJeff Kirsher /************************
21133f810b2SJeff Kirsher  *
21233f810b2SJeff Kirsher  *	hwt_wait_time(smc,start,duration)
21333f810b2SJeff Kirsher  *
21433f810b2SJeff Kirsher  *	This function returnes after the amount of time is elapsed
21533f810b2SJeff Kirsher  *	since the start time.
21633f810b2SJeff Kirsher  *
21733f810b2SJeff Kirsher  * para	start		start time
21833f810b2SJeff Kirsher  *	duration	time to wait
21933f810b2SJeff Kirsher  *
22033f810b2SJeff Kirsher  * NOTE: The function will return immediately, if the timer is not
22133f810b2SJeff Kirsher  *	 started
22233f810b2SJeff Kirsher  ************************/
22333f810b2SJeff Kirsher void hwt_wait_time(struct s_smc *smc, u_long start, long int duration)
22433f810b2SJeff Kirsher {
22533f810b2SJeff Kirsher 	long	diff ;
22633f810b2SJeff Kirsher 	long	interval ;
22733f810b2SJeff Kirsher 	int	wrapped ;
22833f810b2SJeff Kirsher 
22933f810b2SJeff Kirsher 	/*
23033f810b2SJeff Kirsher 	 * check if timer is running
23133f810b2SJeff Kirsher 	 */
23233f810b2SJeff Kirsher 	if (smc->hw.timer_activ == FALSE ||
23333f810b2SJeff Kirsher 		hwt_quick_read(smc) == hwt_quick_read(smc)) {
23433f810b2SJeff Kirsher 		return ;
23533f810b2SJeff Kirsher 	}
23633f810b2SJeff Kirsher 
23733f810b2SJeff Kirsher 	interval = inpd(ADDR(B2_TI_INI)) ;
23833f810b2SJeff Kirsher 	if (interval > duration) {
23933f810b2SJeff Kirsher 		do {
24033f810b2SJeff Kirsher 			diff = (long)(start - hwt_quick_read(smc)) ;
24133f810b2SJeff Kirsher 			if (diff < 0) {
24233f810b2SJeff Kirsher 				diff += interval ;
24333f810b2SJeff Kirsher 			}
24433f810b2SJeff Kirsher 		} while (diff <= duration) ;
24533f810b2SJeff Kirsher 	}
24633f810b2SJeff Kirsher 	else {
24733f810b2SJeff Kirsher 		diff = interval ;
24833f810b2SJeff Kirsher 		wrapped = 0 ;
24933f810b2SJeff Kirsher 		do {
25033f810b2SJeff Kirsher 			if (!wrapped) {
25133f810b2SJeff Kirsher 				if (hwt_quick_read(smc) >= start) {
25233f810b2SJeff Kirsher 					diff += interval ;
25333f810b2SJeff Kirsher 					wrapped = 1 ;
25433f810b2SJeff Kirsher 				}
25533f810b2SJeff Kirsher 			}
25633f810b2SJeff Kirsher 			else {
25733f810b2SJeff Kirsher 				if (hwt_quick_read(smc) < start) {
25833f810b2SJeff Kirsher 					wrapped = 0 ;
25933f810b2SJeff Kirsher 				}
26033f810b2SJeff Kirsher 			}
26133f810b2SJeff Kirsher 		} while (diff <= duration) ;
26233f810b2SJeff Kirsher 	}
26333f810b2SJeff Kirsher }
26433f810b2SJeff Kirsher #endif
26533f810b2SJeff Kirsher 
266