
/*
 *
 *     Module Name: nawait.c
 *	       Version: 1.00
 *   Original Date: 08/28/02	
 *	        Author: Charles Gordon
 *	      Language: Ansi C
 * Compile Options:
 * Compile defines:
 *	     Libraries:
 *    Link Options:
 *
 *    Entry Points: NAWait(), NAWaitSetSleepFn()
 *
 *  Copyright (c) Digi International Inc., All Rights Reserved
 *  
 *  This software contains proprietary and confidential information of Digi
 *  International Inc.  By accepting transfer of this copy, Recipient agrees
 *  to retain this software in confidence, to prevent disclosure to others,
 *  and to make no use of this software other than that for which it was
 *  delivered.  This is an unpublished copyrighted work of Digi International
 *  Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
 *  prohibited.
 *  
 *  Restricted Rights Legend
 * 
 *  Use, duplication, or disclosure by the Government is subject to
 *  restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
 *  Technical Data and Computer Software clause at DFARS 252.227-7031 or
 *  subparagraphs (c)(1) and (2) of the Commercial Computer Software -
 *  Restricted Rights at 48 CFR 52.227-19, as applicable.
 * 
 *  Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
 *
 * Description.
 * =======================================================================
 *  This module implements the NAWait() function.  
 *
 *
 *
 * Edit Date/Ver   Edit Description
 * ==============  =======================================================
 *
 *
 */

#include <stdlib.h>
#include <Npttypes.h>
#include <bsp_api.h>
#include <sysClock.h>
#include <reg_def.h>
#include <nawait.h>

#ifdef BSP_ARM9
#include <mctimer.h>
#endif
#include "natimer.h"


//#define NETOS_DEBUG


/*
 * This pointer will be set when ThreadX is started.
 */
static UINT ((*NASleepFn)(ULONG)) = NULL;
static UINT ((*NASleepFnCopy)(ULONG)) = NULL;



#ifdef BSP_ARM9

/*
 *
 *  Function: void NAMCWait(int timerReloadedValue)
 *
 *  Description:
 *
 *      Creates a short delay using NS9750 onboard timer.
 *
 *  Parameters:
 *
 *      timerReloadedValue   # of usecs to wait
 *
 *  Return Values:
 *
 *      none
 *
 */

static void NAMCWait(unsigned int usecs)
{
    timerHandleType handle = TIMER_BAD_HANDLE;
    WORD64 value;
	
	/*
	 * We use one of the timers in ARM9 (NS9750 chip)
	 * to more accurately setup a delay loop.
	 */
    timerConfigType config = {timerPeriod, {0}, (timerGatingType) 0, TRUE, NULL, NULL, FALSE};
    
    config.timeout.period.seconds = usecs / 1000000;
    config.timeout.period.nanoseconds = (usecs % 1000000) * 1000;
    
    if (NATimerOpen(NAWAIT_TIMER, &handle, timerNaturalSize) != timerSuccess)
    {
        customizeErrorHandler(ERROR_TIMER, ERROR_TIMER_NAWAIT_TIMER_UNAVAIL);
    }
    if (NATimerConfigure(handle, &config) != timerSuccess)
    {
        customizeErrorHandler(ERROR_TIMER, ERROR_TIMER_NAWAIT_TIMER_CONFIG);
    }

	NATimerStart(handle);
	do
	{
	    NATimerRead(handle, &value);
	} while (value.s.lsw != 0);

	NATimerStop(handle);
	NATimerClose(handle);
}




/*
 *
 *  Function: unsigned long waitMills(int mills)
 *
 *  Description:
 *
 *      This routine implements a timed delay.  If ThreadX is up and
 *      running, then NALedSleep will have been set.  In this case, we
 *      call the ThreadX thread sleep function to put this thread to
 *      sleep for the delay period.  If ThreadX hasn't been started,
 *      then we use a delay loop.
 *
 *  Parameters:
 *
 *      mills       number of milliseconds to delay
 *
 *  Return Values:
 *
 *      unused
 *
 */
static unsigned long waitMills(int mills)

{
    int dummyReturnValue = 0;
   
/*
 * If ThreadX has been started, then use the standard ThreadX sleep call
 * and exit.
 */
    if (NASleepFn != NULL)
    {
        NASleepFn ((unsigned) ((mills * NABspTicksPerSecond)/1000));
    }
    else /* if ThreadX hasn't been started yet */
    {
/*
 * Determine our clock rate from the PLL setting and our crystal speed.
 */  

#ifdef BSP_ARM9
		/*
		 * We use one of the timers in ARM9 (NS9750 chip)
		 * to more accurately setup the delay loop.
		 */
		NAMCWait( 1000 * mills );
#else
        unsigned long clockRate;
        int cyclesPerIteration, cyclesToExecute;
        int numberIterations, iteration;

        clockRate = NAgetSysOscFreq();
        cyclesToExecute = (clockRate * mills) / 30;

        /*
         * Check to see if we are in the debugger.  We need to know if an ICE is 
         * being used because there are certain things we do not want to do if 
         * someone is trying to step through code in a debugger.  We don't want to 
         * turn cache on or run the FULL memory test.
         *
         * There is no reliable way of detecting an ICE.  By convention, the debugger 
         * scripts set the second bit of the SCM AHB Arbiter Gen Configuration 
         * register.  This bit is always cleared by a hard reset.
         */
        if (narm_read_reg(NA_SCM_AHB_GEN_CONFIG, NA_SCM_AHB_GEN_CONFIG_ADDR, debug))
        {
            cyclesPerIteration = 36;
        }
        else
        {
            cyclesPerIteration = 12;
        }

        numberIterations = cyclesToExecute / cyclesPerIteration;

/*
 * This is the delay loop.  The dummyReturnValue is there so that the compiler
 * does not optimize the loop away.
 */
        for (iteration = 0; iteration < numberIterations; iteration++)
        {
            dummyReturnValue += iteration + cyclesToExecute;
        }
#endif
    }

    return dummyReturnValue;
}




/*
 *
 *  Function: void NAuWait(int usecs)
 *
 *  Description:
 *
 *      Creates a short delay using NS9750 onboard timer.
 *
 *  Parameters:
 *
 *      usecs      indicates how many microseconds to delay
 *
 *  Return Values:
 *
 *      none
 *
 */
void NAuWait(unsigned int usecs)
{
	NAMCWait( usecs );
}
#endif



/*
 *
 *  Function: void NAWait(int mills)
 *
 *  Description:
 *
 *      Creates a short delay.  This function is a wrapper for
 *      waitMills().  It is used so that waitMills() can return
 *      a value, which it does so that the compiler will not 
 *      optimize away certain loop counters.
 *
 *  Parameters:
 *
 *      mills       indicates how many milliseconds to delay
 *
 *  Return Values:
 *
 *      none
 *
 */

void NAWait(int mills)
{
    waitMills(mills);
}






/*
 *
 *  Function: void NAWaitSetSleepFn(UINT ((*sleepFn)(ULONG)))
 *
 *  Description:
 *
 *      This function sets the function that NAWait() will use to
 *      put a thread to sleep.  If this function is never called, then
 *      NAWait() will use a spin loop to create a delay.
 *
 *  Parameters:
 *
 *      sleepFn         pointer to function to put a thread to sleep
 *
 *  Return Values:
 *
 *      none
 *
 */

void NAWaitSetSleepFn(UINT ((*sleepFn)(ULONG)))
{
    NASleepFn = sleepFn;
    NASleepFnCopy = sleepFn;
}


/*
 *
 *  Description:
 *
 *      This function clears the pointer set to the kernel sleep
 *      function.  This will cause NAWait to approximate the delay
 *      in an idle loop instead of calling the sleep function.
 *
 *  Parameters:
 *
 *      none
 *
 *  Return Values:
 *
 *      none
 *
 */
void NAWaitDisableSleep(void)
{
    NASleepFn = NULL;
}




/*
 *
 *  Description:
 *
 *      This function restores the sleep function pointer after it
 *      was cleared by NAWaitDisableSleep().
 *
 *  Parameters:
 *
 *      none
 *
 *  Return Values:
 *
 *      none
 *
 */
void NAWaitRestoreSleep(void)
{
    NASleepFn = NASleepFnCopy;
}


