📄 m8260timer.c
字号:
/* sbcm8260Timer.c - PowerPC/8260 timer library */
/* Copyright 1984-1999 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/*
modification history
--------------------
01a,22apr99,elk adapted from ppc860Timer.c (ver 01a). Also updated to
include SPR #10000 from ppcDecTimer.c (ver 01o).
*/
/*
DESCRIPTION
This library provides PowerPC/8260 system clock, auxiliary clock, and
timestamp support.
The PowerPC decrementer timer, is used to implement a system clock, and CPM
TIMER2 for a 16-bit auxiliary clock. CPM timers TIMER3, and TIMER4
are cascaded into a free-running 32-bit timer for timestamp support.
The macro, DEC_CLOCK_FREQ, the frequency of the decrementer input clock, must
be defined before using this module. The macro, DEC_CLK_TO_INC, the ratio
between the number of decrementer input clock cycles and one counter
increment, may be redefined prior to including this file in sysLib.c.
The macros SYS_CLK_RATE_MIN, SYS_CLK_RATE_MAX, AUX_CLK_RATE_MIN, and
AUX_CLK_RATE_MAX must be defined to provide parameter checking for
sysClkRateSet(), and sysAuxClkRateSet() routines.
To include the timestamp timer facility, the macro INCLUDE_TIMESTAMP must be
defined.
To enable dynamic bus clock rates, the BSP should set the macro,
PPC_TMR_RATE_SET_ADJUST, to call an apropriate routine. This call, will be
made each time sysClkRateSet() is called. E.g. To use sysClkRateAdjust to
compute a correct value for sysDecClkFrequency.
#define PPC_TMR_RATE_SET_ADJUST sysClkRateAdjust (&sysDecClkFrequency)
The macro, PPC_TMR_RATE_SET_ADJUST, is by default not defined.
INCLUDE FILES: timerDev.h, vxPpcLib.h
SEE ALSO:
.pG "Configuration"
*/
/* includes */
#include "arch/ppc/vxPpcLib.h"
#include "drv/timer/timerDev.h"
#include "drv/timer/m8260Clock.h"
#include "drv/timer/m8260Timer.h"
#include "m8260IntrCtl.h"
/* local defines */
#define SYS_CLK_LED 0x40
#define SYS_AUX_LED 0x20
#define SYS_TIMESTAMP_LED 0x10
#ifndef DEC_CLK_TO_INC
#define DEC_CLK_TO_INC 4 /* # bus clks per increment */
#endif
#define DEFAULT_DEC_CLK_FREQ 33333333 /* 33.33 Mhz default */
#ifndef CPU_INT_UNLOCK
# define CPU_INT_UNLOCK(x) (intUnlock(x))
#endif
#ifndef CPU_INT_LOCK
# define CPU_INT_LOCK(x) (*x = intlock())
#endif
/* extern declarations */
IMPORT STATUS excIntConnect (VOIDFUNCPTR *, VOIDFUNCPTR);
IMPORT void sysLedOn(UINT8 led);
IMPORT void sysLedOff(UINT8 led);
#ifdef PPC_TMR_RATE_SET_ADJUST
IMPORT void sysClkRateAdjust (int *);
#endif /* PPC_TMR_RATE_SET_ADJUST */
/* locals */
LOCAL int sysClkTicksPerSecond = 60; /* default 60 ticks/second */
LOCAL FUNCPTR sysClkRoutine = NULL;
LOCAL int sysClkArg = NULL;
LOCAL BOOL sysClkConnectFirstTime = TRUE;
LOCAL int decCountVal = 10000000; /* default dec value */
LOCAL BOOL sysClkRunning = FALSE;
LOCAL int sysDecClkFrequency = DEFAULT_DEC_CLK_FREQ/DEC_CLK_TO_INC;
#ifdef INCLUDE_SYSCLK_LED
LOCAL int sysClkCount = 0;
#endif /* INCLUDE_SYSCLK_LED */
#ifdef INCLUDE_AUX_CLK
LOCAL FUNCPTR sysAuxClkRoutine = NULL;
LOCAL int sysAuxClkArg = NULL;
LOCAL BOOL sysAuxClkRunning = FALSE;
LOCAL BOOL sysAuxClkIntConnected = FALSE;
LOCAL int sysAuxClkTicksPerSecond = 60;
#ifdef INCLUDE_AUXCLK_LED
LOCAL int sysAuxClkCount = 0;
#endif /* INCLUDE_AUXCLK_LED */
#endif /* INCLUDE_AUX_CLK */
#ifdef INCLUDE_TIMESTAMP
LOCAL BOOL sysTimestampRunning = FALSE; /* timestamp running flag */
LOCAL FUNCPTR sysTimestampRoutine = NULL;
LOCAL int sysTimestampArg = NULL;
LOCAL BOOL sysTimestampIntConnected = FALSE;
#endif /* INCLUDE_TIMESTAMP */
/*******************************************************************************
*
* sysClkInt - clock interrupt handler
*
* This routine handles the clock interrupt on the PowerPC architecture. It is
* attached to the decrementer vector by the routine sysClkConnect().
*
* RETURNS : N/A
*/
#ifdef __DCC__
asm void ClkIntMacro(int count)
{
% lab sysClkIntLoop; reg count
! "r4"
mfdec r4
sysClkIntLoop:
add. r4, count, r4
ble sysClkIntLoop
mtdec r4
}
#endif
LOCAL void sysClkInt (void)
{
/*
* The PowerPC decrementer doesn't reload the value by itself. The reload
* need to be performed in this handler. The reload value should be
* adjusted each time because the time spent between the exception
* generation and the moment the register is reloaded changes.
* By reading the decrementer we obtain the time spent between the
* two events and can adjust the value to reload. This is done in assembly
* language in order to minimize time spent between reading and writing
* to the decrementer register in order to maximize system clock accuracy.
*/
#ifdef __DCC__
ClkIntMacro(decCountVal);
#else
__asm__ ("
mfdec 3
sysClkIntLoop:
add. 3, %0, 3
ble sysClkIntLoop /* check if we missed tick(s) */
mtdec 3"
: /* no output operands */
: "r" (decCountVal) /* input operand, %0 = decCountVal */
: "3", "cc"/* side-effects: r3 clobbered, 'condition code' is clobbered */
);
#endif
/* Unlock interrupts during decrementer processing */
CPU_INT_UNLOCK (_PPC_MSR_EE);
#ifdef INCLUDE_SYSCLK_LED
sysClkCount++;
if (sysClkCount > sysClkTicksPerSecond)
{ sysClkCount = 0;
sysLedOff(SYS_CLK_LED);
}
else if (sysClkCount == (sysClkTicksPerSecond/2))
sysLedOn(SYS_CLK_LED);
#endif /* INCLUDE_SYSCLK_LED */
/* execute the system clock routine */
if (sysClkRunning && (sysClkRoutine != NULL))
(*(FUNCPTR) sysClkRoutine) (sysClkArg);
}
/*******************************************************************************
*
* sysClkConnect - connect a routine to the system clock interrupt
*
* This routine specifies the interrupt service routine to be called at each
* clock interrupt. Normally, it is called from usrRoot() in usrConfig.c to
* connect usrClock() to the system clock interrupt.
*
* RETURNS: OK, or ERROR if the routine cannot be connected to the interrupt.
*
* SEE ALSO: intConnect(), usrClock(), sysClkEnable()
*/
STATUS sysClkConnect
(
FUNCPTR routine, /* routine to connect */
int arg /* argument for the routine */
)
{
if (sysClkConnectFirstTime)
{
sysHwInit2();
sysClkConnectFirstTime = FALSE;
}
#ifdef DEC_CLOCK_FREQ
sysDecClkFrequency = DEC_CLOCK_FREQ / DEC_CLK_TO_INC;
#endif /* DEC_CLOCK_FREQ */
/* connect the routine to the decrementer exception */
excIntConnect ((VOIDFUNCPTR *) _EXC_OFF_DECR, (VOIDFUNCPTR) sysClkInt);
sysClkRoutine = routine;
sysClkArg = arg;
return (OK);
}
/******************************************************************************
*
* sysClkEnable - turn on system clock interrupts
*
* This routine enables system clock interrupts.
*
* RETURNS: N/A
*
* SEE ALSO: sysClkConnect(), sysClkDisable(), sysClkRateSet()
*/
void sysClkEnable (void)
{
if (!sysClkRunning)
{
sysClkRunning = TRUE;
vxDecSet (decCountVal);
}
}
/******************************************************************************
*
* sysClkDisable - turn off system clock interrupts
*
* This routine disables system clock interrupts.
*
* RETURNS: N/A
*
* SEE ALSO: sysClkEnable()
*/
void sysClkDisable (void)
{
if (sysClkRunning)
sysClkRunning = FALSE;
}
/******************************************************************************
*
* sysClkRateGet - get the system clock rate
*
* This routine returns the system clock rate.
*
* RETURNS: The number of ticks per second of the system clock.
*
* SEE ALSO: sysClkEnable(), sysClkRateSet()
*/
int sysClkRateGet (void)
{
return (sysClkTicksPerSecond);
}
/******************************************************************************
*
* sysClkRateSet - set the system clock rate
*
* This routine sets the interrupt rate of the system clock. It is called
* by usrRoot() in usrConfig.c.
*
* RETURNS: OK, or ERROR if the tick rate is invalid or the timer cannot be set.
*
* SEE ALSO: sysClkEnable(), sysClkRateGet()
*/
STATUS sysClkRateSet
(
int ticksPerSecond /* number of clock interrupts per second */
)
{
if (ticksPerSecond < SYS_CLK_RATE_MIN || ticksPerSecond > SYS_CLK_RATE_MAX)
return (ERROR);
/* save the clock speed */
sysClkTicksPerSecond = ticksPerSecond;
/* Calibrate the clock, if needed. */
#ifdef PPC_TMR_RATE_SET_ADJUST
PPC_TMR_RATE_SET_ADJUST;
#endif
/*
* compute the value to load in the decrementer. The new value will be
* load in the decrementer after the end of the current period
*/
decCountVal = sysDecClkFrequency / ticksPerSecond;
return (OK);
}
#ifdef INCLUDE_AUX_CLK
/*******************************************************************************
*
* sysAuxClkInt - auxiliary clock interrupt handler
*
* This routine handles the auxiliary clock interrupt. It calls a user routine
* if one was specified by the routine sysAuxClkConnect().
*/
LOCAL void sysAuxClkInt (void)
{
UINT32 immrVal = vxImmrGet();
*M8260_TER2(immrVal) |= M8260_TER_REF; /* clear event register */
*M8260_SIPNR_L(immrVal) = 0x00000008; /* clear in-service bit */
#ifdef INCLUDE_AUXCLK_LED
sysAuxClkCount++;
if (sysAuxClkCount > sysAuxClkTicksPerSecond)
{ sysAuxClkCount = 0;
sysLedOff(SYS_AUX_LED);
}
else if (sysAuxClkCount == (sysAuxClkTicksPerSecond/2))
sysLedOn(SYS_AUX_LED);
#endif /* INCLUDE_AUXCLK_LED */
if (sysAuxClkRoutine != NULL)
(*sysAuxClkRoutine) (sysAuxClkArg);
}
/*******************************************************************************
*
* sysAuxClkConnect - connect a routine to the auxiliary clock interrupt
*
* This routine specifies the interrupt service routine to be called at each
* auxiliary clock interrupt. It does not enable auxiliary clock
* interrupts.
*
* RETURNS: OK, or ERROR if the routine cannot be connected to the interrupt.
*
* SEE ALSO: intConnect(), sysAuxClkEnable()
*/
STATUS sysAuxClkConnect
(
FUNCPTR routine, /* routine called at each aux. clock interrupt */
int arg /* argument to auxiliary clock interrupt routine */
)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -