/*
 *  Copyright (c) 1996-2007 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
 *
 *
 * ncc_init.c - ARM9 Initialization routines, these routines are called
 *              from the reset handler in init.s, we have a small stack
 *              which is setup from SDRAM on cs4, so don't use global
 *              variables or initialized data, if you need to store something for 
 *              use later, we use a section of memory in the beginning of RAM 
 *              (called initdata) to store data such as keypad presses which 
 *              need to be accessed by the software later, the size of this piece 
 *              of memory is defined in the file customize.lx.
 *
 * Edit Date/Ver   Edit Description
 * ==============  =======================================================
 *    02/01/05     PAK  Added support for a continuous memory test from the debugger.
 *    06/22/05     PAK  Changed NETOS_DEBUG #ifdef to NCC_INIT_DEBUG to fix link errors.
 *    12/13/05     JZW  add volatile storage class for nccData in nccInit
 *                      nccCheckForSoftwareRestart to keep it from being 
 *                      optimized away - vantive 17375
 */

/*
 * Do not attempt to trace registers before the C library is
 * setup.  The global variables used by the trace library will
 * be in an undefined state until after the C library has
 * initilized the data segement.
 */
#ifdef NA_REG_TRACE_ENABLED
    #ifdef _REG_DEF_H
        #error Trace code compiled into init code.
    #endif
    #undef NA_REG_TRACE_ENABLED
#endif

#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "reg_def.h"
#include <cs.h>
#include <errhndlr.h>
#include <ncc_init.h>
#include <Npttypes.h>
#include <narmled.h>
#include <cache.h>
#include "gpio.h"
#include "scm_reg.h"
#include "bsp_refs.h"
#include "bsp_sys.h"
#include "bsp_drivers.h"
#include "bootldr.h"
#include "powersave.h"
#include "bsp_local.h"

#ifdef BSP_INCLUDE_PCI_DRIVER
#include <pcidev.h>
#endif
#include "errorcodes.h"
#if BSP_ENABLE_SLEEP_EXTERNAL_RESET
#include "nagpio.h" 
#include "gpio_def.h"
#endif

#define SOFTWARE_RESTART_FLAG       (0xff808421)

static unsigned int const NABspRomBuild = (unsigned int)&_NARomBuild;

static void   nccProgramChipSelects(unsigned int ram_sizes[]); 
static void   nccFlushMemControllerBuffer(WORD32 volatile *ram); 
static unsigned long nccGetRequiredRamSize(void);

unsigned short nccRomImageBuild(void)
{
    return (unsigned short)NABspRomBuild;
}    

static void nccDelay(unsigned long interations)
{
   volatile unsigned long loop_counter;

   loop_counter = interations;

   while (loop_counter)
   {
      loop_counter--;
   }
}


/*
 * Routine called to blink the LED when we run into a fatal error in nccInit()
 * We can't call the standard LED blink routine because we have no C library yet.
 * This routine does not return.
 */
void nccInitializationFailed(int reason)
{
    int i;

#ifdef NCC_INIT_DEBUG
/*    mprintf("nccInitializationFailed: reason %d\n", reason); */
#endif

    for (;;)
    {
        for (i = 0; i < LED_2_POST_FAILURE; i++)
        {
#define DIAG_BLINK_DELAY    250000
            NALedRedOn();
            nccDelay(DIAG_BLINK_DELAY);
            NALedRedOff();
            nccDelay(DIAG_BLINK_DELAY);
        }

        nccDelay (5 * DIAG_BLINK_DELAY);

        for (i = 0; i < LED_04_RAM; i++)
        {
            NALedRedOn();
            nccDelay(DIAG_BLINK_DELAY);
            NALedRedOff();
            nccDelay(DIAG_BLINK_DELAY);
        }

        nccDelay (5 * DIAG_BLINK_DELAY);

        for (i = 0; i < reason; i++)
        {
            NALedRedOn();
            nccDelay(DIAG_BLINK_DELAY);
            NALedRedOff();
            nccDelay(DIAG_BLINK_DELAY);
        }

        nccDelay(10 * DIAG_BLINK_DELAY);
    }
}


/*ad*
 * The RAM APIs are used by code in cs.c to automatically determine the type and
 * amount of RAM installed on the board, and setup the chip selects accordingly.
 *
 *
 * These APIs are provided for applications that may use different
 * RAMs for different H/W builds.  If you know exactly what type and what size of
 * RAM will be used, then you should program the chip selects using hardcoded values
 * instead of calling these functions.
 *
 *
 * Once the RAM type has been determined, nccDetermineRamSize() should be called to size
 * it.
 *
 * @external
 * @category BSP:RAM
 * @since 6.0     
 * @overview RAM Setup API
 * @library bsp
 * @platform all
 * @include "ncc_init.h"
 * @see @link nccDetermineRamSize
 *
 * @note    If RAM is installed on more than one chip select, then all RAM chip
 *          selects must support the same type of RAM.  Once the RAM type has
 *          been set on the first chip select, nccCopyCSSetup() should be used
 *          to copy the RAM type configuration settings from the first chip select
 *          to others.   
*ad*/



/*ad*
 * This routine is called by the reset handler routine in init.s to initialize
 * the internal NS9750 hardware registers. This is called before the C 
 * initialization routine and has a small stack, so you cannot access any 
 * variables which are initialized by the C library. This routine also does 
 * the following:
 * <list type="unordered">
 *      <item> Check to see if we are in the debugger or if a software restart occured.</item>
 *      <item> Call SetupSimpleSerial to load a serial driver which
 * may be used for debugging.</item>
 *      <item> Call a customizeable routine to setup the GPIO pins. </item>
 *      <item> Call the customizeable chip select routines. </item>
 *      <item> Call the customizeable PCI setup routine. </item>
 *      <item> Initialize the internal NS9750 hardware registers. </item>
 *      <item> Turn on the intruction cache. </item>
 *      <item> Call a customizeable routine to check for and store any keypad buttons
 *              which where pressed on startup </item>
 *      <item> If we are not in the debugger call a routine to customize and memory 
 *             parameters such as the refresh rate.</item>
 *      <item> Call a routine to program the chip selects. </item>
 *      <item> Call a customizable memory test routine. </item>
 *      <item> Check to see if we have enough RAM to run our application by looking
 * at linker variable.</item>
 * </list>
 *
 * @param     restartFlags  Used only on ns9215 and ns9210 based platforms.  Since
 *                          the NS9215 and NS9210 do not have the extra bits in the 
 *                          AHB GEN config register, this flag is used in it's place
 *                          and passed via the r14 value.  Register R14 in the 
 *                          undefined mode will be loaded with SOFTWARE_RESTART_FLAG 
 *                          by the restart code.  The value of R14_UNDF will be passed 
 *                          to us in restartFlag.
 *
 * @external
 * @category BSP
 * @since 6.1
 *
 *
 * @note Make sure any routines called from this routine are safe to call
 * before the C library is initialized.
*ad*/

void nccInit(unsigned restartFlags)
{
    unsigned int      ramSize, ramSizeArray[NA_NUM_CHIP_SELECTS], bytes_needed;
    BOOLEAN           debugger, spi_boot, software_restart=0;
    int               chipType = nccChipType();
    unsigned char     *initdata = (unsigned char *)INIT_DATA_ADDRESS;
    volatile romstart_data_t   *nccData  = (romstart_data_t  *)NCC_INIT_DATA_ADDRESS;
#if (BSP_POST_TEST == TRUE) || (defined(NETOS_MEMORY_TEST))
    unsigned long     num_bytes_to_test=0;
    unsigned long     start_of_memory=0;
#endif
    BOOLEAN           sleep_wakeup;    

#if (PROCESSOR == ns9210) || (PROCESSOR == ns9215)
    software_restart = ((restartFlags & BL_SOFTWARE_RESTART_FLAG) != 0);
    narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, cpuClockSelect, SCM_CCR_2_TIMES_AHB_CLOCK);
#else
    (void) restartFlags;
    /*
     * Check for a 'software restart' condition.  A software restart is not the
     * same as a software reset.  A software restart is when code deliberately 
     * jumps to the reset code.  This is typically done when a new application 
     * image is loaded into RAM.  The new application is started by jumping to 
     * the very beginning of it where the reset code is.
     *
     * The software detects a software restart condition by looking at the third
     * bit in the SCM AHB config register, this bit is always 0 on reset, so we 
     * set this bit to 1 and use it to tell us if the SW was restarted.      
     */
    software_restart = narm_read_reg(NA_SCM_AHB_GEN_CONFIG, NA_SCM_AHB_GEN_CONFIG_ADDR, 
                                     restart);

    narm_write_reg(NA_SCM_AHB_GEN_CONFIG, NA_SCM_AHB_GEN_CONFIG_ADDR, 
                   restart, 1);
#endif

    /* Save this field for later */
    nccData->software_reset      = software_restart;

	 
#if (PROCESSOR == ns9210) || (PROCESSOR == ns9215)	
    debugger = ((restartFlags & BL_DEBUGGER_FLAG) != 0);
    spi_boot = (narm_read_reg(NA_SCM_MSCSR_REG, NA_SCM_MSCSR_ADDRESS, bootMode) == SCM_MSCSR_bootFromSpi);
    sleep_wakeup = 0; /* NS9215 uses a different sleep mode */
#else
    /*
     * 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 
     * 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.
     */
    debugger = narm_read_reg(NA_SCM_AHB_GEN_CONFIG, NA_SCM_AHB_GEN_CONFIG_ADDR, 
                             debug);  

    spi_boot = 	!(*(unsigned long *)0xA0900184 & 0x800);  
		 
    sleep_wakeup = NAPDIsSleepWakeup();
#endif
		 
    #ifdef MEMORY_TEST_FROM_THE_DEBUGGER
    software_restart = 0;
    debugger = 0;
    #endif 
    nccData->debugger = debugger;
    
    /* Please leave this on. Printf's in other parts of the bootloader hang without this */
    setupSimpleSerial();

    if (!software_restart)
    {
        NAWaitDisableSleep();

        /* Setup the GPIO ports. */
        customizeSetupGPIO(chipType, software_restart);

		

        #if BSP_AUTOMATICALLY_ENABLE_INSTRUCTION_CACHE
            /*
             * This statement does NOT initialize the MMU.  It turns on instruction
             * cache without initializing the MMU.  This causes the CPU to cache all
             * instruction fetches, but not data accesses.  No memory management 
             * functions are setup.  The MMU is initialized in the main() routine.
             */
            NAEnableICache();
        #endif

#ifdef NCC_INIT_DEBUG
        /* Enable serial port printf's */
        if (!sleep_wakeup)
            bsp_printf("ncc_init: Initializing register settings\n");
#endif        
        /* if running from Rom, we take the flash size from the linker file.
         * if Ram image, we use max size 256M and update the actual flash
         * size when flash driver is initialized.
         */
        if (nccRomImageBuild() == 1)
        {
            NABspFlashSize = (WORD32)&_NABspFlashSize;
        }
        else
        {
            NABspFlashSize = 0x10000000;
        }

        /* Setup the Static chip selects */
        customizeSetupCS0();
        customizeSetupCS1();
        customizeSetupCS2();
        customizeSetupCS3();

        /*
         * Get the size of each SDRAM.
         * Keep track of the amount of RAM on each chip select, we then need 
         * to arrange the memory map such that the largest SDRAM starts at 
         * address zero and then the other SDRAM chip selects are arangned 
         * in decending order.  This  gaurantees that our address space is 
         * continous. So cs4 may not necessarily start at address zero.
         */

        /* 
         * Clear to zero in case the customize routine doesn't initialize 
         * the ramSize variable correctly.
         */
        memset(ramSizeArray, 0, sizeof ramSizeArray);
		
        customizeSetupCS4(&ramSizeArray[0]);
#if	(defined (BSP_SEEK_SDRAM) && (BSP_SEEK_SDRAM == TRUE))
        customizeSetupCS5(&ramSizeArray[1]);
#else
		if(!spi_boot)
		{
            customizeSetupCS5(&ramSizeArray[1]);
            customizeSetupCS6(&ramSizeArray[2]);
            customizeSetupCS7(&ramSizeArray[3]);
		}
#endif
        customizeClockDisable(ramSizeArray);

        /* Calculate the total amount of RAM avaiable */
        ramSize = ramSizeArray[0] + ramSizeArray[1] +  ramSizeArray[2] + 
                  ramSizeArray[3];
		
		#ifdef BSP_INCLUDE_PCI_DRIVER		
        /*  Initializing the PCI bus must happen prior to any lengthy memory tests  */
        pciVeryEarlyInitialization(0);
		#endif

        if (!debugger && !sleep_wakeup)
        {

#ifdef NCC_INIT_DEBUG
            bsp_printf("ncc_init: Not in debugger.\n");
#endif
            /* Tweak the memory parameters. */
            customizeSetupMMCR();

#if (BSP_POST_TEST == TRUE) || (defined(NETOS_MEMORY_TEST))
            /* 
             * Test the RAM, but don't overwrite the stack we are currently 
             * are using, the memory test is defined in the platform file memtest.c, 
             * this routine returns -1 on failure, 0 on success.
             */

	    /* Starting address of the memory we need to test */
#if (PROCESSOR == NS9210) || (PROCESSOR == NS9215)
            /*
             * NS9215 has internal RAM which is used for the stack during initialization
             * (when we are in this routine for example), so we can test all of RAM.
             */
            start_of_memory   = 0;      
            /* The number of bytes we need to test */
            num_bytes_to_test = ramSize;
#else
            start_of_memory   = BSP_RAM_BASE + BSP_RAM_OFFSET + 
                                NCC_INIT_STACK_SIZE; 
            /* The number of bytes we need to test */
            num_bytes_to_test = ramSize - start_of_memory;
#endif
#endif
        }

        /*
         * Now that RAM is setup and tested, read any buttons or switches that
         * are being held down by the user.
         */
	
	    if (!software_restart)
	    {
            customizeReadPowerOnButtons(chipType, initdata);
        }

       /* 
         *  Program the chip select registers, we are currently using CS4
         *  as our stack, so we can't move the base address of CS4, the rule
         *  is that CS4 is always at address zero and is the largest
         *  chip select.        
         */
		
		
        nccProgramChipSelects(ramSizeArray);
         

#if (BSP_POST_TEST == TRUE) || (defined(NETOS_MEMORY_TEST))
    	/*  
         * RAM Testing
         */
        if (!debugger && !sleep_wakeup)
        {
            if (customizeMemoryTest((unsigned long *)start_of_memory,
                                    num_bytes_to_test) != 0)
            {
#ifdef NCC_INIT_DEBUG
                bsp_printf("ncc_init: ERROR - RAM test failure!\n");
#endif
                nccInitializationFailed (LED_004_DRAM_MISC);
            }
        }

#endif
 
    }
    else
    {
        ramSize = customizeGetRamSize();
    }
	
	
    /* Verify that the application fits inside of RAM. */
    bytes_needed = nccGetRequiredRamSize();

    if (bytes_needed > ramSize)
    {
        /* Not enough RAM to run the RAM linked image */
#ifdef NCC_INIT_DEBUG
        bsp_printf("ncc_init: ERROR - not enough RAM to run the RAM image.\n");
#endif
        nccInitializationFailed (LED_001_DRAM_SIZE);
    }

    /* coming out of sleep mode? */
    if (narm_read_reg(NA_SCM_AHB_GEN_CONFIG, NA_SCM_AHB_GEN_CONFIG_ADDR, 
                                         sleep))
    {
        volatile naPowerSaveData_t *p_data = (naPowerSaveData_t *)NA_SLEEP_DATA_ADDRESS;

        /* restore the saved values */
        *NA_SCM_CCR_ADDRESS = p_data->ccr;
        *NA_SCM_RSR_ADDRESS = p_data->rsr;
    }

#ifdef NCC_INIT_DEBUG
    if (!sleep_wakeup)
        bsp_printf("ncc_init: Initialization successful.\n");
#endif
    return;
}


/*ad*
 * Return the chip type. 
 *
 * @external
 * @category BSP:RAM
 * @since 6.0     
 *
 * @return The chip type as defined in bsp.h
 *
*ad*/
int nccChipType(void)
{
   return BSP_CHIP_TYPE;
}

#define NCC_MEM_TEST_PATTERN1 0x5555AAAA
#define NCC_MEM_TEST_PATTERN2 0xA5A55A5A

/*ad*
 * This function determines the amount of RAM attached to a chip select by setting 
 * the chip select to the maximum size, and incrementally testing RAM until it finds 
 * addresses that are aliased at the beginning of the part.  
 *
 * @external
 * @category BSP:RAM
 * @since 6.0     
 *
 * @param     baseAddress    Address at which to locate memory.
 * @param     maxSize        Maximum amount of RAM to configure on the chip select.
 * @param     csBaseRegAddr  Address of the CS base address register.
 * @param     csMaskRegAddr  Address of the CS mask register.
 *
 * @return    The amount of RAM attached to the chip select
 *
*ad*/
WORD32 nccDetermineRamSize(WORD32 baseAddress, WORD32 maxSize, WORD32 csBaseRegAddr, WORD32 csMaskRegAddr)
{
    WORD32 size;  
    WORD32 volatile *ram = (WORD32 *)baseAddress, mask;
    int    i=0;

    NA_ASSERT(csBaseRegAddr != 0);
    NA_ASSERT(csMaskRegAddr != 0);  

    /*
     * Set up the chip select to support the maximum possible amount of memory.  
     */
     mask = ~maxSize + 1;
    _narm_write_reg((WORD32 *)csMaskRegAddr, NA_SCM_DYNAMIC_CS_MASK_REG_mask, mask >> CS_MASK_SHIFT_BITS);
    _narm_write_reg((WORD32 *)csBaseRegAddr, NA_SCM_DYNAMIC_CS_BASE_REG_addr, baseAddress >> CS_BASE_SHIFT_BITS);  

    /*
     * Write a test value at the bottom of the memory.
     */
    ram[0] = NCC_MEM_TEST_PATTERN1;

    if (ram[0] != NCC_MEM_TEST_PATTERN1)
    {
        goto memsize_fail;
    }

    /*
     * NOTE: The memory controller has a 64 WORD buffer (cache).
     * After we do a write, we need to flush out the buffer in the memory
     * controller, otherwise when we read the same address again it will grab the
     * last value written to the buffer internal to the memory controller and
     * not from the SDRAM.
     */
     nccFlushMemControllerBuffer(ram);

    /*
     * Now go through the memory 1 Meg at a time until we find the point where 
     * writing a word causes the bottom most word to be overwritten.  That is
     * the point where the physical memory ends and is wrapped by the chip 
     * select.
     */
     for (size = CS_1_MEG; size < maxSize; size += CS_1_MEG, i++)
    {
        ram[size >> 2] = NCC_MEM_TEST_PATTERN2;

        if (ram[size >> 2] != NCC_MEM_TEST_PATTERN2)
        {
            goto memsize_fail; /* Memory error */
        }

        nccFlushMemControllerBuffer(ram);

        if (ram[0] != NCC_MEM_TEST_PATTERN1)
        {
            /* Found it. */
            return size;
        }
    }
    return maxSize;

memsize_fail:

#ifdef NCC_INIT_DEBUG
    bsp_printf("nccDetermineRamSize: memory error\n");
#endif
    nccInitializationFailed (LED_004_DRAM_MISC);
    return 0;
}

/*
 * This function is added for the 9p9360 in order to insure the
 * chip select is configured for its default address after a restart.
 * This is required in order to check for the presence and size of
 * RAM at a chip select past CS4.
 * If we find RAM there, the base address is adjusted via the 
 * nccProgramChipSelects() call to be contiguous with the end of the
 * previous chip select, and NAAdjustMmuTable() will adjust the range
 * of the MMU table entry to accomodate the total range.
 */

void nccSetCSDefault(WORD32 dynCS, WORD32 baseAddress, WORD32 maxSize)
{
	WORD32 volatile maskVal;

	/*
	 * Set up chip select to support the requested maximum amount of memory. 
	 */
	maskVal = ~maxSize + 1;

	narm_write_reg(NA_SCM_DYNAMIC_CS_MASK_REG,
			NA_SCM_SMCS_DYNAMIC_MEM_MASK(dynCS), mask,
					 maskVal >> CS_MASK_SHIFT_BITS);
	narm_write_reg(NA_SCM_DYNAMIC_CS_BASE_REG,
			NA_SCM_SMCS_DYNAMIC_MEM_BASE(dynCS), addr,
					 baseAddress >> CS_BASE_SHIFT_BITS);
#ifdef NS9360
	narm_write_reg(NA_SCM_DYNAMIC_CS_MASK_REG,
			NA_SCM_SMCS_DYNAMIC_MEM_MASK(dynCS), enable,
					 NA_SCM_ENABLE_DYNAMIC_CS);
#endif
}

/* the variable dynCS is 0-3 for the four dynamic chip selects 4-7 */

void nccSetCSDisable(WORD32 dynCS)
{
#ifdef NS9360
	narm_write_reg(NA_SCM_DYNAMIC_CS_MASK_REG,
			NA_SCM_SMCS_DYNAMIC_MEM_MASK(dynCS), enable,
					 NA_SCM_DISABLE_DYNAMIC_CS);
#else
	NA_UNUSED_PARAM(dynCS);
#endif
}

void nccCopyDynCfgReg(unsigned long volatile *toReg, unsigned long volatile *fromReg)
{
	unsigned long volatile regVal;

	regVal = narm_read_reg32(fromReg);
	narm_write_reg32(toReg, regVal);
}


/*ad*
 * This routine reads and writes to the specified chip select 
 * to determine if RAM is present.
 *
 * @external
 * @category BSP:RAM
 * @since 6.0     
 *
 * @param     baseAddress       Address at which to locate memory
 *
 * @return    NCC_RAM_DETECTED      RAM was detected, and the chip select has 
 *                                  been configured to support it.
 * @return    NCC_NO_RAM            No RAM was detected.
 *
 *
 * @see @link ram_errors
*ad*/
int nccCheckIfRamExists(WORD32 baseAddress)
{
    WORD32 volatile *ram = (WORD32 *)baseAddress;
    WORD32 val = NCC_MEM_TEST_PATTERN1, val1 = NCC_MEM_TEST_PATTERN2, read_val;

    /* Attempt to write from the RAM and then read it back. */
    ram[0]   = val;

    /* Make sure we aren't reading cache */
    nccFlushMemControllerBuffer(ram);

    read_val = ram[0];

    if (read_val != val)
    {
        return NCC_NO_RAM;
    }

    ram[0]   = val1;

    nccFlushMemControllerBuffer(ram);

    read_val = ram[0];

    if (read_val != val1)
    {
        return NCC_NO_RAM;
    }

    return NCC_RAM_DETECTED;
}

/*
 * Create a table which is used to program the chip select registers in init.s, 
 * the table is an array words, two words for each chip select,
 * for the base and mask registers, init.s then programs the chip selects from
 * this table, we need to order the chip selects from the largest to the
 * smallest so we have one continous address space which spans over all the
 * SDRAM chip selects. So we may need to move
 * cs4 which contains the stack we are currently using.
 *
 * NOTE: The largest memory must be connected to CS4 which is used as the
 *       program stack for this routine.
 */
static void nccProgramChipSelects(unsigned int ram_sizes[])
{
    int               i, j, largest=0, current_address=0;
    DynamicRamTable_t ram_table;
    int dynamicCs;


    for (j=0; j < NA_NUM_CHIP_SELECTS; j++)
    {
        /* 
         * See if there a larger RAM on one of the other chip selects.
         */
        for (i=0; i < NA_NUM_CHIP_SELECTS; i++)
        {
            if (ram_sizes[i] > ram_sizes[largest])
            {
                largest = i;
                if (i == (NA_NUM_CHIP_SELECTS-1))  
                    break;      /* The last one is the largest */
            }
        }

        /* Set the base address and mask */
        ram_table.cs[j].base = current_address;
        ram_table.cs[j].mask = ~ram_sizes[largest] + 1;

        current_address += ram_sizes[largest];

        ram_sizes[largest] = 0;
    }
    
    for (dynamicCs = 0; dynamicCs < NA_NUM_CHIP_SELECTS; dynamicCs++)
    {
        if (ram_table.cs[dynamicCs].mask)
        {
            narm_write_reg(NA_SCM_DYNAMIC_CS_MASK_REG, NA_SCM_SMCS_DYNAMIC_MEM_MASK(dynamicCs), mask, (ram_table.cs[dynamicCs].mask >> CS_MASK_SHIFT_BITS));
            narm_write_reg(NA_SCM_DYNAMIC_CS_BASE_REG, NA_SCM_SMCS_DYNAMIC_MEM_BASE(dynamicCs), addr, (ram_table.cs[dynamicCs].base >> CS_BASE_SHIFT_BITS));
            #ifdef NS9360
                narm_write_reg(NA_SCM_DYNAMIC_CS_MASK_REG, NA_SCM_SMCS_DYNAMIC_MEM_MASK(dynamicCs), enable, NA_SCM_ENABLE_DYNAMIC_CS);
            #endif
        }
    }
    return;
}

/*
 * Calculate the number of bytes required for the application to fit inside of 
 * RAM.  Include all the  space needed from the begining of the text to the 
 * begining of the heap, this includes everything in between (text, data, 
 * bss, stack ..etc).This also includes the free_mem area; refer to the 
 * linker files image.ldr (GNU) and image.lx (Green Hills) for the exact 
 * memory map.
 *
 */
static unsigned long nccGetRequiredRamSize(void)
{
    unsigned int text_size, data_size, bytes_needed, heap_size;
    char         *heap_begin=0, *text_start=0, *text_end=0, *_data_start=0, *heap_end=0;
    
    #ifdef NETOS_GNU_TOOLS
        text_start      = btext;
        text_end        = _endtext;
        _data_start      = data_start;
        heap_begin      = heap_start;
        heap_end        = heap_limit;
    #elif defined NETOS_ARM_TOOLS
        char *data_end = (char *)&Image$$ncc_initdata$$ZI$$Base;
    	text_start = (char *)&Image$$RAM_EXEC$$Base;
        text_end = (char *)&Image$$netosstack$$ZI$$Base;
        _data_start = (char *)&Image$$ncc_initdata$$ZI$$Base;
        heap_begin = (char *)&Image$$HEAP$$ZI$$Base;
        heap_end = (char *)&Image$$HEAP$$ZI$$Limit;
    #else
        char *data_end = __ghsbegin_ncc_initdata;
        text_start    = __ghsbegin_text;
        text_end      = __ghsbegin_intercall;
        _data_start    = __ghsbegin_ncc_initdata;
        heap_begin    = (char *)__ghsbegin_heap;
        heap_end      = __ghsend_heap;
    #endif 

    text_size    = text_end   - text_start;
    
    #ifdef NETOS_GNU_TOOLS
       data_size    = heap_begin - _data_start;
    #else
        data_size    = data_end - _data_start;
    #endif    
    heap_size    = heap_end   - heap_begin;

    /* exclude text section when running from ROM */
    if (nccRomImageBuild() == 1)
    {
        bytes_needed = heap_size + data_size;
    }
    else
    {
        bytes_needed = heap_size + text_size + data_size;
    }
    return bytes_needed;
}

/*ad*
 * Flush the memory controller buffer.
 * The memory controller has a 64 WORD buffer (cache).
 * After we do a write, we need to flush out the buffer in the memory
 * controller, otherwise when we read the same address again it will grab the
 * last value written from the cache buffer of the memory controller - not
 * from actual memory. It doesn't matter where we do the read from, as long 
 * as it's a valid location in RAM.
 *
 * @external
 * @category BSP:RAM
 * @since 6.1
 *
 * @param ram Address of SDRAM memory which we can use to flush the
 * memory controller.
*ad*/
void nccFlushMemControllerBuffer(WORD32 volatile * ram)
{
    int i, read_val;

    /*
     * The values for MEMC_READ_LOCATION and MEMC_CTRL_BUF_LEN are defined
     * in the header file bsp.h.  The MEMC_READ_LOCATION is an offset into 
     * RAM which is read to flush the memory controller cache which is 64 words.
     * This value is typically 4K, you need to make sure that this does
     * not exceed the end of RAM.
     */
    for (i = MEMC_READ_LOCATION; i < MEMC_READ_LOCATION + MEMC_CTRL_BUF_LEN; 
         read_val = ram[i], i++);
    
    i = read_val;
    
}
   

/*ad*
 * This routine determines if the software has been restarted, this
 * typically happens if new firmware has been downloaded and we jump
 * to the Reset Vector to restart the software.
 * 
 * @external
 * @category BSP:RAM
 * @since 6.1
 *
 * @return 1 The software has been restarted.
 * @return 0 The software has not been restarted.
*ad*/
BOOLEAN nccCheckForSoftwareRestart(void)
{
    volatile romstart_data_t   *nccData  = (romstart_data_t  *)NCC_INIT_DATA_ADDRESS;

    /* We save this information in nccInit() on startup */
    return nccData->software_reset;
}


/*ad*
 * Return nonzero if we detected an debugger at powerup.
 * This function is used by the code in crt0.S for GNU.
 *                               
 * @external
 * @category general_purpose 
 * @since 6.1
 *
 * @return 0  No debugger detected
 * @return 1  Debugger detected
*ad*/
BOOLEAN are_we_in_debugger(void)
{
    volatile romstart_data_t   *nccData  = (romstart_data_t  *)NCC_INIT_DATA_ADDRESS;

    return nccData->debugger;
}

/*ad*
 * Function is used to determine whether the system is coming out of sleep mode. 
 * Function returns true if the bit 3 in general configuration register is set 
 * (normal sleep wakeup) or if the BSP_SLEEP_STATUS_PIN value is set to 1 
 * (deep sleep wakeup).  
 *
 * @external
 * @category BSP:RAM
 * @since 7.0     
 *
 * @return TRUE    coming out of wakeup mode
 * @return FALSE   normal reset mode
 *
*ad*/
BOOLEAN NAPDIsSleepWakeup(void)
{
    BOOLEAN debugger, flag = FALSE;

    debugger = narm_read_reg(NA_SCM_AHB_GEN_CONFIG, NA_SCM_AHB_GEN_CONFIG_ADDR,
                             debug);

    if (!debugger)
    {   
        if (narm_read_reg(NA_SCM_AHB_GEN_CONFIG, NA_SCM_AHB_GEN_CONFIG_ADDR, 
                                         sleep))
        {
            flag = TRUE;
        }
#if BSP_ENABLE_SLEEP_EXTERNAL_RESET
        else if (narm_read_reg(NA_SCM_AHB_GEN_CONFIG, NA_SCM_AHB_GEN_CONFIG_ADDR, 
                                         deep_sleep))
        {
            flag = TRUE;
        }
        else
        {
            unsigned long value;
        
#ifdef NS9360
            value = narm_read_reg(NA_SCM_RSR_REG, NA_SCM_RSR_ADDRESS, resetStatus);
            if (value != 1)
                return FALSE;
#endif

            value = naGpioGetValue(GPIO_PSAVE_STATUS);
            if ((value != (unsigned long)-1) && (value))
            {
                flag = TRUE;
                narm_write_reg(NA_SCM_AHB_GEN_CONFIG, NA_SCM_AHB_GEN_CONFIG_ADDR, 
                                         deep_sleep, 1);
                /* clear the pin value */
                naGpioSetOutput(GPIO_PSAVE_STATUS, 0);
                naGpioSetInput(GPIO_PSAVE_STATUS);
            }
        }
#endif  /* BSP_ENABLE_SLEEP_EXTERNAL_RESET */
    }

    return flag;
}

/*
 * Function is called by sleep mode wakeup related functions just to bypass
 * decompression and memory check related overhead. Function never returns 
 * in successful execution.
 *
 * @external
 * @category BSP:RAM
 * @since 7.0     
 *
 * @return TRUE    cannot execute this function at this time
 * @return FALSE   failed to run the application in RAM
 *
 */
BOOLEAN nccStartAppInRam(void)
{
#ifdef BSP_ENABLE_SLEEP_EXTERNAL_RESET
    volatile romstart_data_t   *nccData  = (romstart_data_t  *)NCC_INIT_DATA_ADDRESS;

    if (narm_read_reg(NA_SCM_AHB_GEN_CONFIG, NA_SCM_AHB_GEN_CONFIG_ADDR, 
                                     sleep))
    {
        return TRUE;
    }

    if (NAPDIsSleepWakeup() && (!(nccData->software_reset)))
    {
        /*
         * If we are coming out of sleep mode then just jump to RAM location and rerun
         * the application.
         */
        blImageHeaderType *imageInfo = (blImageHeaderType *) NABspApplicationFlashAddress;
        blExecuteImage((WORD32 *) imageInfo->ramAddress);
        return FALSE;
    }
#endif    
    return TRUE;
}


