📄 ppc403timer.c
字号:
/* ppc403Timer.c - PowerPC 403 timer library *//* Copyright 1984-1997 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------01o,19sep01,pch SPR 20698, 69142, 69143: TSR is write-to-clear, not read/modify/writeback01n,25sep97,ms2 corrected sysAuxClkTicksPerSecond (spr 9348)01m,16jul97,tam add code to enable change of sysClk rate on the fly for GCX. 01l,07may97,tam added use of IS_CPU_403GCX macro. 01k,17apr97,dat rework on SYS_CLK_FREQ, fixed SPR 8372 - extra calls to excIntConnect.01j,09apr97,mkw add support for 403GCX01i,24mar97,tam replace excCrtConnect by excIntCrtConnect in sysWdtConnect().01h,08nov96,wlf doc: cleanup.01g,07oct96,tam fixed spr 7242: declared sysBusClkFrequency as a LOCAL.01f,02jul96,tam added code to make system clock more accurate. Added timestamp support.01e,19mar96,tam fixed sysAuxClkEnable() & sysWdtClkEnable().01d,12mar96,tam changed excIntConnect to excIntConnectTimer for FIT & PIT.01c,11mar96,tam added functions for the watchdog timer (WDT).01b,07mar96,tam added functions for the auxiliary clock (FIT).01a,20feb96,tpr written, inspired from ppcDecTimer.c version 01g.*//*DESCRIPTIONThis library provides PowerPC 403 Timer routines. This library handlesthe system clock, the auxiliary clock and timestamp functions. Toinclude the timestamp timer facility, the macro INCLUDE_TIMESTAMP mustbe defined.The macro SYS_CLK_FREQ should be defined before usingthis module. This macro is the rate at which clock ticks occur. Fordouble clocked busses, this value should be half the actual clock speed.The macro PIT_CORRECTION is needed to adjust the reload value to accountfor the latency delay between generation of the interrupt and the timeto actually enter the service routine. If not defined, an approximatevalue is calculated from the SYS_CLK_FREQ value. The calculated valuefor a 25Mhz clock is a 9 microsecond correction.The macros SYS_CLK_RATE_MIN, SYS_CLK_RATE_MAX, AUX_CLK_RATE_MIN,and AUX_CLK_RATE_MAX must be defined to provideparameter checking for sysClkRateSet().The BSP is responsible for connecting the interrupt handlers, sysClkInt(),and sysAuxClkInt(), to the appropriate vectors.INCLUDE FILES: ppc403Timer.hSEE ALSO:.pG "Configuration"*//* includes */#include "vxLib.h"#include "intLib.h"#include "drv/timer/ppc403Timer.h"#include "arch/ppc/ppc403.h"#include "drv/timer/timestampDev.h"/* local defines *//* System clock speed, default is 25 MHz */#ifndef SYS_CLK_FREQ# define SYS_CLK_FREQ 25000000#endif/* * The PIT_CORRECTION is expressed in nanoseconds. It is used * to correct the reload value for the 403GA and 403GC cpus * which don't have an autoreload feature on the PIT clock. It accounts * for the latency time between when the interrupt was generated and when * the interrupt handler was entered. */#ifndef PIT_CORRECTION# define PIT_CORRECTION (225000000 / (SYS_CLK_FREQ / 1000))#endif/* IS_CPU_403GCX returns TRUE if the CPU is a 403GCX, FALSE otherwise */#ifndef IS_CPU_403GCX# define IS_CPU_403GCX ((vxPvrGet() & (_PVR_CCF_MSK | _PVR_PCF_MSK)) \ == (_PVR_CONF_403GCX << 8) ? 1:0)#endif/* Auxiliary clock default rate */#ifndef AUX_CLK_RATE_DEFAULT# define AUX_CLK_RATE_DEFAULT 10#endif/* extern declarations *//* Locals */LOCAL FIT_PERIOD fitTable[] = /* available FIT periods */ { { (1 << 9), 0x00000000}, { (1 << 13), 0x01000000}, { (1 << 17), 0x02000000}, { (1 << 21), 0x03000000}, };LOCAL WDT_PERIOD wdtTable[] = /* available WDT periods */ { { (1 << 17), 0x00000000}, { (1 << 21), 0x40000000}, { (1 << 25), 0x80000000}, { (1 << 29), 0xC0000000}, };LOCAL int sysClkTicksPerSecond = 60; /* default 60 ticks/second */LOCAL FUNCPTR sysClkRoutine = NULL;LOCAL int sysClkArg = NULL;LOCAL BOOL sysClkConnectFirstTime = TRUE;LOCAL BOOL sysClkRunning = FALSE;LOCAL BOOL sysClkReload = TRUE;LOCAL BOOL sysClkReloadOnce = FALSE;LOCAL int sysAuxClkTicksPerSecond = AUX_CLK_RATE_DEFAULT;LOCAL FUNCPTR sysAuxClkRoutine = NULL;LOCAL int sysAuxClkArg = NULL;LOCAL BOOL sysAuxClkRunning = FALSE;LOCAL int sysWdtTicksPerSecond = 1;LOCAL FUNCPTR sysWdtRoutine = NULL;LOCAL int sysWdtArg = NULL;LOCAL BOOL sysWdtRunning = FALSE;LOCAL UINT32 sysBusClkFrequency = TIMER_CLK_FREQ;LOCAL UINT32 pitCountVal; /* PIT counter value */LOCAL UINT32 fitPeriodMask = 0x01000000; /* default FIT period: 2^21 */LOCAL UINT32 wdtPeriodMask = 0xC0000000; /* default WDT period: 2^29 */LOCAL UINT32 pitCorrection;#ifdef INCLUDE_TIMESTAMPLOCAL BOOL sysTimestampRunning = FALSE; /* timestamp running flag */#endif /* INCLUDE_TIMESTAMP *//********************************************************************************* sysClkInt - clock interrupt handler** This routine handles the clock interrupt on the PowerPC 403 architecture. It* is attached to the Programmable Interval Timer vector by the routine* sysClkConnect().** RETURNS : N/A*/LOCAL void sysClkInt (void) { vxPitIntAck (); /* acknowledge PIT interrupt */ /* * Since the auto-reload feature of the PIT seems not to work properly * for non-GCX it is necessary to reload the Programmable Interrupt Timer. * The reload value should be adjusted each time because the time spent * between the exception generation and the moment the register is reloaded * changes. * Since the PIT does not keep decrementing after it reaches 0 we cannot * read it again and adjust pitCountVal. The current correction corresponds * to the average time spend between the exception generation and the * moment the register is reloaded. A better solution would be to use * the time base to calculate that value dynamically but that requires * adding code to the PPC interrupt stub routine. */ if (sysClkReload) vxPitSet(pitCountVal - pitCorrection); if (sysClkReloadOnce) { vxPitSet(pitCountVal); /* reload the PIT once after a call */ sysClkReloadOnce = FALSE; /* to sysClkRateSet() for GCX cpu */ } /* execute the system clock routine */ if (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. It also connects the* clock error interrupt service routine.** RETURNS: OK, or ERROR if the routine cannot be connected to the interrupt.** SEE ALSO: usrClock(), sysClkEnable()*/STATUS sysClkConnect ( FUNCPTR routine, /* routine to connect */ int arg /* argument with which to call the routine */ ) { if (sysClkConnectFirstTime) { sysHwInit2(); sysClkConnectFirstTime = FALSE; } 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) { /* clear the pending PIT interrupt */ vxTsrSet (_PPC403_TSR_PIS); /* load the PIT counter and the hidden register with interval value */ vxPitSet (pitCountVal); /* Enable the PIT interrupt & enable autoreload for 403GCX */ if (IS_CPU_403GCX) { vxTcrSet (vxTcrGet() | _PPC403_TCR_PIE | _PPC403_TCR_ARE); sysClkReload = FALSE; } else vxTcrSet (vxTcrGet() | _PPC403_TCR_PIE); /* set the running flag */ sysClkRunning = TRUE; } }/******************************************************************************** sysClkDisable - turn off system clock interrupts** This routine disables system clock interrupts.** RETURNS: N/A** SEE ALSO: sysClkEnable()*/void sysClkDisable (void) { if (sysClkRunning) { /* disable the PIT interrupt and auto-reload capability */ vxTcrSet (vxTcrGet() & ~ (_PPC403_TCR_PIE | _PPC403_TCR_ARE)); /* clear the PIT counter */ vxPitSet (0); /* clear the pending PIT interrupt */ vxTsrSet (_PPC403_TSR_PIS); /* reset the running flag */ 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 does not* enable system clock interrupts. 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; /* * compute the value to load in the decrementor. The new value will be * load in the decrementor after the end of the current period */ if (vxIocrGet () & _PPC403_IOCR_TCSM) sysBusClkFrequency = TIMER_CLK_FREQ; else sysBusClkFrequency = SYS_CLK_FREQ; pitCountVal = sysBusClkFrequency / ticksPerSecond; pitCorrection = (((sysBusClkFrequency / 1000000) * PIT_CORRECTION) / 1000); if (IS_CPU_403GCX) sysClkReloadOnce = TRUE; /* reload the PIT with new value */ return (OK); }/********************************************************************************* sysAuxClkInt - auxilary clock interrupt handler** This routine handles the auxilary clock interrupt on the PowerPC 403* architecture. It is attached to the Fix Interval Timer vector by the routine* sysAuxClkConnect().** RETURNS : N/A*/LOCAL void sysAuxClkInt (void) { vxFitIntAck (); /* acknowledge FIT interrupt */ /* program TCR with the FIT period */ vxTcrSet ((vxTcrGet() & ~_PPC403_TCR_FP) | fitPeriodMask); /* execute the system clock routine */ if (sysAuxClkRoutine != NULL) (*(FUNCPTR) 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: excIntConnectTimer(), sysAuxClkEnable()*/STATUS sysAuxClkConnect ( FUNCPTR routine, /* routine called at each aux. clock interrupt */ int arg /* argument to auxiliary clock interrupt */ ) { sysAuxClkRoutine = routine; sysAuxClkArg = arg; return (OK); }/********************************************************************************* sysAuxClkEnable - turn on auxiliary clock interrupts** This routine enables auxiliary clock interrupts.** RETURNS: N/A** SEE ALSO: sysAuxClkConnect(), sysAuxClkDisable(), sysAuxClkRateSet()*/void sysAuxClkEnable (void) { if (!sysAuxClkRunning) { /* clear the pending FIT interrupt */ vxTsrSet (_PPC403_TSR_FIS); /* program TCR with the FIT period */ vxTcrSet ((vxTcrGet() & ~_PPC403_TCR_FP) | fitPeriodMask); /* Enable the FIT interrupt */ vxTcrSet (vxTcrGet() | _PPC403_TCR_FIE); /* set the running flag */ sysAuxClkRunning = TRUE; } }/********************************************************************************* sysAuxClkDisable - turn off auxiliary clock interrupts** This routine disables auxiliary clock interrupts.*** RETURNS: N/A** SEE ALSO: sysAuxClkEnable()*/void sysAuxClkDisable (void) { if (sysAuxClkRunning) { /* disable the FIT interrupt */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -