/*
 *  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
 *
 * =======================================================================
 * This module is responsible for disableing clock to the modules which
 * are not started yet or not used.
 *
 * Edit Date/Ver   Edit Description
 * ==============  ===================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Npttypes.h>

#ifdef BSP_ARM9
#include <scm_reg.h>
#include "bsp_serial.h"
#include "reg_def.h"

#if (PROCESSOR == ns9210) || (PROCESSOR == ns9215)

#include "ncc_init.h"

/*
 * This routine is called from nccInit.  The original purpose was to return the value
 * for the cpuClockSelect field of the CCR register, which nccInit writes.  
 *
 * However, I have hijacked this routine to change the clock rate from 56 MHz, which
 * is the rate the H/W is strapped for, to 75 MHz.  For some reason, the H/W designer
 * strapped the board for the wrong speed, so we have to fix it in hardware.
 */
int customizeCpuSpeed(void)
{
#if WANT_TO_ADJUST_PLL_DIVIDER_TO_75MHZ
    #define CLOCK_DIVIDER_FOR_75MHZ     (0x5)
    
    /*
     * This statement sets the clock rate to be the same as the AHB clock.  Actually,
     * nccInit is going to do exactly the same thing when we return.  We do it here
     * because we want to be sure we don't set the AHB clock rate to 75 MHz while the
     * CPU clock doubling bit is set.
     */
    narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, cpuClockSelect, SCM_CCR_AHB_CLOCK);

    /*
     * Now we have to change the PLL setting.  This is really ugly.  THE CHIP IS
     * RESET WHEN WE WRITE TO THIS REGISTER.  This will terminate the debug session,
     * so we just don't do it if we using the debugger.
     */
    if (!are_we_in_debugger())
    {
        /*
         * We are not debugging.  We want to make sure we don't get in a loop writing
         * to this register, so check the current value of the divisor and only write 
         * to the register if the current value is not correct.
         */
        if (narm_read_reg(NA_SCM_PLL_REG, NA_SCM_PLL_ADDRESS, referenceClockDivider) != CLOCK_DIVIDER_FOR_75MHZ)
        {
            /*
             * Now set the PLL divider for 75 MHz.
             */
            narm_write_reg(NA_SCM_PLL_REG, NA_SCM_PLL_ADDRESS, referenceClockDivider, CLOCK_DIVIDER_FOR_75MHZ);
            
            /*
             * We don't get here because the chip just reset.
             */
        }
    }
#endif

	return  SCM_CCR_AHB_CLOCK;
}
#endif


/*
 * This routine is called from main() and disables the Ethernet MAC.  We
 * can't disable the Ethernet MAC in customizeClockDisable because that is
 * called from nccInit, and nccInit uses memory inside of the Ethernet module
 * for a temporary stack.
 */
void customizeClockDisableMain(void)
{
    #if (PROCESSOR == ns9210) || (PROCESSOR == ns9215)
        narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, ethernetMac, 0);
        narm_write_reg(NA_SCM_RSR_REG, NA_SCM_RSR_ADDRESS, ethernetMac, 0);
    #endif
}


void clockSet(unsigned isEnabled, unsigned int *ramSizes)
{
    NA_UNUSED_PARAM(isEnabled);         /* needed in case not a NS9210/NS9215 */
    
    if (ramSizes)
    {
	    /*
	    * Disable clocks on unused chip selects and other devices to reduce EMI noise.
	    */
	    narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, memoryClock0, (ramSizes[0] != 0)?SCM_CCR_ENABLE_MEM_CLOCK:SCM_CCR_DISABLE_MEM_CLOCK);
	    narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, memoryClock1, (ramSizes[1] != 0)?SCM_CCR_ENABLE_MEM_CLOCK:SCM_CCR_DISABLE_MEM_CLOCK);
	    narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, memoryClock2, (ramSizes[2] != 0)?SCM_CCR_ENABLE_MEM_CLOCK:SCM_CCR_DISABLE_MEM_CLOCK);
	    narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, memoryClock3, (ramSizes[3] != 0)?SCM_CCR_ENABLE_MEM_CLOCK:SCM_CCR_DISABLE_MEM_CLOCK);

	    narm_write_reg(NA_SCM_DYNAMIC_CS_MASK_REG, NA_SCM_SMCS_DYNAMIC_MEM_MASK(0), enable, (ramSizes[0] != 0));
	    narm_write_reg(NA_SCM_DYNAMIC_CS_MASK_REG, NA_SCM_SMCS_DYNAMIC_MEM_MASK(1), enable, (ramSizes[1] != 0));
	    narm_write_reg(NA_SCM_DYNAMIC_CS_MASK_REG, NA_SCM_SMCS_DYNAMIC_MEM_MASK(2), enable, (ramSizes[2] != 0));
	    narm_write_reg(NA_SCM_DYNAMIC_CS_MASK_REG, NA_SCM_SMCS_DYNAMIC_MEM_MASK(3), enable, (ramSizes[3] != 0));
    }

    #if (PROCESSOR == ns9210) || (PROCESSOR == ns9215)
    /*
     * Just turning off some clocks for devices that aren't needed yet.
     * This will reduce EMI emissions.  The drivers for these devices will
     * turn the clocks on if the devices are needed.
     */
        narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, rtc, isEnabled);
        narm_write_reg(NA_SCM_RSR_REG, NA_SCM_RSR_ADDRESS, rtc, isEnabled);

        narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, reserved1, isEnabled);
        narm_write_reg(NA_SCM_RSR_REG, NA_SCM_RSR_ADDRESS, reserved1, isEnabled);

        narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, reserved2, isEnabled);
        narm_write_reg(NA_SCM_RSR_REG, NA_SCM_RSR_ADDRESS, reserved2, isEnabled);

        narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, reserved3, isEnabled);
        narm_write_reg(NA_SCM_RSR_REG, NA_SCM_RSR_ADDRESS, reserved3, isEnabled);

        narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, iop0, isEnabled);
        narm_write_reg(NA_SCM_RSR_REG, NA_SCM_RSR_ADDRESS, iop0, isEnabled);

        narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, iop1, isEnabled);
        narm_write_reg(NA_SCM_RSR_REG, NA_SCM_RSR_ADDRESS, iop1, isEnabled);


        narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, adc, isEnabled);       
        narm_write_reg(NA_SCM_RSR_REG, NA_SCM_RSR_ADDRESS, adc, isEnabled);       

        narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, aes, isEnabled);       
        narm_write_reg(NA_SCM_RSR_REG, NA_SCM_RSR_ADDRESS, aes, isEnabled);       
        narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, externalDma, isEnabled);
        narm_write_reg(NA_SCM_RSR_REG, NA_SCM_RSR_ADDRESS, externalDma, isEnabled);

        narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, i2c, isEnabled);
        narm_write_reg(NA_SCM_RSR_REG, NA_SCM_RSR_ADDRESS, i2c, isEnabled);

        narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, spi, isEnabled);
        narm_write_reg(NA_SCM_RSR_REG, NA_SCM_RSR_ADDRESS, spi, isEnabled);
        
        #if (BSP_SIMPLE_SERIAL_PORT != BSP_SIMPLE_SERIAL_ON_PORTD)
            narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, uartd, isEnabled);
            narm_write_reg(NA_SCM_RSR_REG, NA_SCM_RSR_ADDRESS, uartd, isEnabled);
        #endif
        #if (BSP_SIMPLE_SERIAL_PORT != BSP_SIMPLE_SERIAL_ON_PORTC)
            narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, uartc, isEnabled);
            narm_write_reg(NA_SCM_RSR_REG, NA_SCM_RSR_ADDRESS, uartc, isEnabled);
        #endif
        #if (BSP_SIMPLE_SERIAL_PORT != BSP_SIMPLE_SERIAL_ON_PORTB)
            narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, uartb, isEnabled);
            narm_write_reg(NA_SCM_RSR_REG, NA_SCM_RSR_ADDRESS, uartb, isEnabled);
        #endif
        #if (BSP_SIMPLE_SERIAL_PORT != BSP_SIMPLE_SERIAL_ON_PORTA)
            narm_write_reg(NA_SCM_CCR_REG, NA_SCM_CCR_ADDRESS, uarta, isEnabled);
            narm_write_reg(NA_SCM_RSR_REG, NA_SCM_RSR_ADDRESS, uarta, isEnabled);
        #endif

    #endif    
}


void customizeClockDisable(unsigned int *ramSizes)
{
#define DISABLE_CLOCK       (0)
    
    clockSet(DISABLE_CLOCK, ramSizes);
}

/*
 * This routine is used by the bootloader to enable all clocks.
 * We need to do this to support old application images that 
 * do not turn on the clocks to the modules they use, but just
 * assume the clocks are already on.
 */
void customizeClockEnable(void)
{
#define ENABLE_CLOCK        (1)
    
    clockSet(ENABLE_CLOCK, NULL);
}

#endif /* BSP_ARM9 */

