//*****************************************************************************
//
// bl_check.c: Code to check for a forced update.
// Author    : QJ Wang. qjwang@ti.com
// Date      : 5-9-2013
//
// Copyright (c) 2006-2011 Texas Instruments Incorporated.  All rights reserved.
// Software License Agreement
// 
// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.
// 
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES, FOR ANY REASON WHATSOEVER.
//
//*****************************************************************************

#include "reg_gio.h"
#include "bl_config.h"
#include "bl_check.h"
#include "hw_sci.h"

//*****************************************************************************
//
//  bl_check_api
//
//*****************************************************************************

//*****************************************************************************
//
// This global is used to remember if a forced update occurred.
//
//*****************************************************************************
#ifdef ENABLE_UPDATE_CHECK
uint32 g_ulForced;
#endif


#if (FORCED_UPDATE_PORT == GPIO_PORTA_BASE)
#define gioPORT gioPORTA
#else
#define gioPORT gioPORTB
#endif


//*****************************************************************************
//
// Checks a GPIO for a forced update.
//
// This function checks the state of a GPIO to determine if a update is being
// requested.
//
// return Returns a non-zero value if an update is being requested and zero
// otherwise.
//
//*****************************************************************************
#ifdef ENABLE_UPDATE_CHECK
uint32
CheckGPIOForceUpdate(void)
{
    /** bring GIO module out of reset */
    gioREG->GCR0      = 1;
    gioREG->INTENACLR = 0xFF;
    gioREG->LVLCLR    = 0xFF;  

    // Set the pin as input
    gioPORT->DIR &= ~(1 << FORCED_UPDATE_PIN);

    // Enable the pull up/down.
    gioPORT->PULDIS &= ~(1 << FORCED_UPDATE_PIN);

    // Enable the weak pull up.
    gioPORT->PSL |= 1 << FORCED_UPDATE_PIN;

    // Check the pin to see if an update is being requested.

    if ((gioPORT->DIN & (0x1 << FORCED_UPDATE_PIN) ) == 0)
    {
        // Remember that this was a forced update.
        g_ulForced = 1;
        return(1);
    }

    // No update is being requested so return 0.
    return(0);
}
#endif

//*****************************************************************************
//
// Checks if an update is needed or is being requested.
//
// This function detects if an update is being requested or if there is no
// valid code presently located on the microcontroller.  This is used to tell
// whether or not to enter update mode.
//
// \return Returns a non-zero value if an update is needed or is being
// requested and zero otherwise.
//
//*****************************************************************************
uint32
CheckForceUpdate(void)
{
    uint32 *pulApp;

#ifdef ENABLE_UPDATE_CHECK
    g_ulForced = 0;
#endif

    //
    // See if the first location is 0xfffffffff or something that does not
    // look like a stack pointer, or if the second location is 0xffffffff or
    // something that does not look like a reset vector.
    // After reset the CM3 loads it's startup address from address 0x00000004.
    // The value at that location should be odd (LSB set) denoting the thumb
    // destination. All exception and interrupt vectors following reset vector
    // should be odd.
    //
    pulApp = (uint32 *)APP_START_ADDRESS;
    if((pulApp[0] == 0xffffffff) || ((pulApp[0] & 0xfff00000) != 0x08000000) ||
       (pulApp[1] == 0xffffffff) || ((pulApp[1] & 0xfff00001) != 0x00000001))
    {
        return(1);
    }

// if the checked location (last 4bytes of the 1st sector) is 0x5A5A5A5A, check GPIO forced update
#ifdef ENABLE_UPDATE_CHECK
    // If simple GPIO checking is configured, determine whether or not to force an update.
    return(CheckGPIOForceUpdate());
#else
    // GPIO checking is not required so, if we get here, a valid image exists and no update is needed.
    return(0);
#endif

}

