/*
 * -------------------------------------------
 *    CC3220 SDK - v0.10.00.00 
 * -------------------------------------------
 *
 *  Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ 
 *  
 *  Redistribution and use in source and binary forms, with or without 
 *  modification, are permitted provided that the following conditions 
 *  are met:
 *
 *    Redistributions of source code must retain the above copyright 
 *    notice, this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the 
 *    documentation and/or other materials provided with the   
 *    distribution.
 *
 *    Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *  
 */
//*****************************************************************************
//
//  flash.c
//
//  Driver for programming the on-chip flash.
//
//*****************************************************************************

//*****************************************************************************
//
//! \addtogroup flash_api
//! @{
//
//*****************************************************************************

#include "inc/hw_types.h"
#include "inc/hw_flash_ctrl.h"
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "inc/hw_gprcm.h"
#include "inc/hw_hib1p2.h"
#include "inc/hw_hib3p3.h"
#include "inc/hw_common_reg.h"
#include "inc/hw_stack_die_ctrl.h"
#include "debug.h"
#include "flash.h"
#include "utils.h"
#include "interrupt.h"

#define HAVE_WRITE_BUFFER       1



//*****************************************************************************
//
// An array that maps the specified memory bank to the appropriate Flash
// Memory Protection Program Enable (FMPPE) register.
//
//*****************************************************************************
static const unsigned long g_pulFMPPERegs[] =
{
    FLASH_FMPPE0,
    FLASH_FMPPE1,
    FLASH_FMPPE2,
    FLASH_FMPPE3,
    FLASH_FMPPE4,
    FLASH_FMPPE5,
    FLASH_FMPPE6,
    FLASH_FMPPE7,
    FLASH_FMPPE8,
    FLASH_FMPPE9,
    FLASH_FMPPE10,
    FLASH_FMPPE11,
    FLASH_FMPPE12,
    FLASH_FMPPE13,
    FLASH_FMPPE14,
    FLASH_FMPPE15


};

//*****************************************************************************
//
// An array that maps the specified memory bank to the appropriate Flash
// Memory Protection Read Enable (FMPRE) register.
//
//*****************************************************************************
static const unsigned long g_pulFMPRERegs[] =
{
    FLASH_FMPRE0,
    FLASH_FMPRE1,
    FLASH_FMPRE2,
    FLASH_FMPRE3,
    FLASH_FMPRE4,
    FLASH_FMPRE5,
    FLASH_FMPRE6,
    FLASH_FMPRE7,
    FLASH_FMPRE8,
    FLASH_FMPRE9,
    FLASH_FMPRE10,
    FLASH_FMPRE11,
    FLASH_FMPRE12,
    FLASH_FMPRE13,
    FLASH_FMPRE14,
    FLASH_FMPRE15,
};

//*****************************************************************************
//
//! Flash Disable
//!
//! This function Disables the internal Flash.
//!
//! \return None.
//
//*****************************************************************************
void
FlashDisable()
{

  //
  // Wait for Flash Busy to get cleared
  //
  while((HWREG(GPRCM_BASE + GPRCM_O_TOP_DIE_ENABLE)
          & GPRCM_TOP_DIE_ENABLE_FLASH_BUSY))
  {

  }

  //
  // Assert reset
  //
  HWREG(HIB1P2_BASE + HIB1P2_O_PORPOL_SPARE) = 0xFFFF0000;

  //
  // 50 usec Delay Loop
  //
  UtilsDelay((50*80)/3);

  //
  // Disable TDFlash
  //
  HWREG(GPRCM_BASE + GPRCM_O_TOP_DIE_ENABLE) = 0x0;

  //
  // 50 usec Delay Loop
  //
  UtilsDelay((50*80)/3);

  HWREG(HIB1P2_BASE + HIB1P2_O_BGAP_DUTY_CYCLING_EXIT_CFG) = 0x1;

  //
  // 50 usec Delay Loop
  //
  UtilsDelay((50*80)/3);
}


//*****************************************************************************
//
//! Erases a block of flash.
//!
//! \param ulAddress is the start address of the flash block to be erased.
//!
//! This function will erase a 2 kB block of the on-chip flash.  After erasing,
//! the block will be filled with 0xFF bytes.  Read-only and execute-only
//! blocks cannot be erased.
//!
//! This function will not return until the block has been erased.
//!
//! \return Returns 0 on success, or -1 if an invalid block address was
//! specified or the block is write-protected.
//
//*****************************************************************************
long
FlashErase(unsigned long ulAddress)
{
    //
    // Check the arguments.
    //
    ASSERT(!(ulAddress & (FLASH_CTRL_ERASE_SIZE - 1)));

    //
    // Clear the flash access and error interrupts.
    //
    HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FCMISC)
      = (FLASH_CTRL_FCMISC_AMISC | FLASH_CTRL_FCMISC_VOLTMISC |
                           FLASH_CTRL_FCMISC_ERMISC);

    // Erase the block.
    //
    HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FMA) = ulAddress;
    HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FMC)
                                = FLASH_CTRL_FMC_WRKEY | FLASH_CTRL_FMC_ERASE;

    //
    // Wait until the block has been erased.
    //
    while(HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FMC) & FLASH_CTRL_FMC_ERASE)
    {
    }

    //
    // Return an error if an access violation or erase error occurred.
    //
    if(HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FCRIS)
       & (FLASH_CTRL_FCRIS_ARIS | FLASH_CTRL_FCRIS_VOLTRIS |
                             FLASH_CTRL_FCRIS_ERRIS))


    {
        return(-1);
    }

    //
    // Success.
    //
    return(0);
}


//*****************************************************************************
//
//! Erases a block of flash but does not wait for completion.
//!
//! \param ulAddress is the start address of the flash block to be erased.
//!
//! This function will erase a 2 kB block of the on-chip flash.  After erasing,
//! the block will be filled with 0xFF bytes.  Read-only and execute-only
//! blocks cannot be erased.
//!
//! This function will return immediately after commanding the erase operation.
//! Applications making use of the function can determine completion state by
//! using a flash interrupt handler or by polling FlashIntStatus.
//!
//! \return None.
//
//*****************************************************************************
void
FlashEraseNonBlocking(unsigned long ulAddress)
{
    //
    // Check the arguments.
    //
    ASSERT(!(ulAddress & (FLASH_CTRL_ERASE_SIZE - 1)));

    //
    // Clear the flash access and error interrupts.
    //
    HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FCMISC) =
      (FLASH_CTRL_FCMISC_AMISC | FLASH_CTRL_FCMISC_VOLTMISC |
                           FLASH_CTRL_FCMISC_ERMISC);

    //
    // Command the flash controller to erase the block.
    //
    HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FMA) = ulAddress;
    HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FMC) = FLASH_CTRL_FMC_WRKEY | FLASH_CTRL_FMC_ERASE;
}


//*****************************************************************************
//
//! Erases a complele flash at shot.
//!
//! This function erases a complele flash at shot
//!
//! \return Returns 0 on success, or -1 if the block is write-protected.
//
//*****************************************************************************
long
FlashMassErase()
{
    //
    // Clear the flash access and error interrupts.
    //
    HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FCMISC) =
      (FLASH_CTRL_FCMISC_AMISC | FLASH_CTRL_FCMISC_VOLTMISC |
                           FLASH_CTRL_FCMISC_ERMISC);

    //
    // Command the flash controller for mass erase.
    //
    HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FMC) =
      FLASH_CTRL_FMC_WRKEY | FLASH_CTRL_FMC_MERASE1;

    //
    // Wait until mass erase completes.
    //
    while(HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FMC) & FLASH_CTRL_FMC_MERASE1)
    {

    }

    //
    // Return an error if an access violation or erase error occurred.
    //
    if(HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FCRIS)
       & (FLASH_CTRL_FCRIS_ARIS | FLASH_CTRL_FCRIS_VOLTRIS |
                             FLASH_CTRL_FCRIS_ERRIS))
    {
        return -1;
    }

    //
    // Success.
    //
    return 0;
}

//*****************************************************************************
//
//! Erases a complele flash at shot but does not wait for completion.
//!
//!
//! This function will not return until the Flash has been erased.
//!
//! \return None.
//
//*****************************************************************************
void
FlashMassEraseNonBlocking()
{
    //
    // Clear the flash access and error interrupts.
    //
    HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FCMISC) =
      (FLASH_CTRL_FCMISC_AMISC | FLASH_CTRL_FCMISC_VOLTMISC |
                           FLASH_CTRL_FCMISC_ERMISC);

    //
    // Command the flash controller for mass erase.
    //
    HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FMC) =
      FLASH_CTRL_FMC_WRKEY | FLASH_CTRL_FMC_MERASE1;

}

//*****************************************************************************
//
//! Programs flash.
//!
//! \param pulData is a pointer to the data to be programmed.
//! \param ulAddress is the starting address in flash to be programmed.  Must
//! be a multiple of four.
//! \param ulCount is the number of bytes to be programmed.  Must be a multiple
//! of four.
//!
//! This function will program a sequence of words into the on-chip flash.
//! Each word in a page of flash can only be programmed one time between an
//! erase of that page; programming a word multiple times will result in an
//! unpredictable value in that word of flash.
//!
//! Since the flash is programmed one word at a time, the starting address and
//! byte count must both be multiples of four.  It is up to the caller to
//! verify the programmed contents, if such verification is required.
//!
//! This function will not return until the data has been programmed.
//!
//! \return Returns 0 on success, or -1 if a programming error is encountered.
//
//*****************************************************************************
long
FlashProgram(unsigned long *pulData, unsigned long ulAddress,
             unsigned long ulCount)
{
    //
    // Check the arguments.
    //
    ASSERT(!(ulAddress & 3));
    ASSERT(!(ulCount & 3));

    //
    // Clear the flash access and error interrupts.
    //
    HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FCMISC)
      = (FLASH_CTRL_FCMISC_AMISC | FLASH_CTRL_FCMISC_VOLTMISC |
                           FLASH_CTRL_FCMISC_INVDMISC | FLASH_CTRL_FCMISC_PROGMISC);


    //
    // See if this device has a write buffer.
    //

#if HAVE_WRITE_BUFFER
    {
        //
        // Loop over the words to be programmed.
        //
        while(ulCount)
        {
            //
            // Set the address of this block of words. for 1 MB
            //
            HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FMA) = ulAddress & ~(0x7F);

            //
            // Loop over the words in this 32-word block.
            //
            while(((ulAddress & 0x7C) ||
                   (HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FWBVAL) == 0)) &&
                  (ulCount != 0))
            {
                //
                // Write this word into the write buffer.
                //
                HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FWBN
                      + (ulAddress & 0x7C)) = *pulData++;
                ulAddress += 4;
                ulCount -= 4;
            }

            //
            // Program the contents of the write buffer into flash.
            //
            HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FMC2)
              = FLASH_CTRL_FMC2_WRKEY | FLASH_CTRL_FMC2_WRBUF;

            //
            // Wait until the write buffer has been programmed.
            //
            while(HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FMC2) & FLASH_CTRL_FMC2_WRBUF)
            {
            }
        }
    }
#else
    {
        //
        // Loop over the words to be programmed.
        //
        while(ulCount)
        {
            //
            // Program the next word.
            //
            HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FMA) = ulAddress;
            HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FMD) = *pulData;
            HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FMC) = FLASH_CTRL_FMC_WRKEY | FLASH_CTRL_FMC_WRITE;

            //
            // Wait until the word has been programmed.
            //
            while(HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FMC) & FLASH_CTRL_FMC_WRITE)
            {
            }

            //
            // Increment to the next word.
            //
            pulData++;
            ulAddress += 4;
            ulCount -= 4;
        }
    }
#endif
    //
    // Return an error if an access violation occurred.
    //

    if(HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FCRIS) & (FLASH_CTRL_FCRIS_ARIS | FLASH_CTRL_FCRIS_VOLTRIS |
                             FLASH_CTRL_FCRIS_INVDRIS | FLASH_CTRL_FCRIS_PROGRIS))

    {
        return(-1);
    }

    //
    // Success.
    //
    return(0);
}


//*****************************************************************************
//
//! Programs flash but does not poll for completion.
//!
//! \param pulData is a pointer to the data to be programmed.
//! \param ulAddress is the starting address in flash to be programmed.  Must
//! be a multiple of four.
//! \param ulCount is the number of bytes to be programmed.  Must be a multiple
//! of four.
//!
//! This function will start programming one or more words into the on-chip
//! flash and return immediately.  The number of words that can be programmed
//! in a single call depends the part on which the function is running.  For
//! parts without support for a flash write buffer, only a single word may be
//! programmed on each call to this function (\e ulCount must be 1).  If a
//! write buffer is present, up to 32 words may be programmed on condition
//! that the block being programmed does not straddle a 32 word address
//! boundary.  For example, wherease 32 words can be programmed if the address
//! passed is 0x100 (a multiple of 128 bytes or 32 words), only 31 words could
//! be programmed at 0x104 since attempting to write 32 would cross the 32
//! word boundary at 0x180.
//!
//! Since the flash is programmed one word at a time, the starting address and
//! byte count must both be multiples of four.  It is up to the caller to
//! verify the programmed contents, if such verification is required.
//!
//! This function will return immediately after commanding the erase operation.
//! Applications making use of the function can determine completion state by
//! using a flash interrupt handler or by polling FlashIntStatus.
//!
//! \return 0 if the write was started successfully, -1 if there was an error.
//
//*****************************************************************************
long
FlashProgramNonBlocking(unsigned long *pulData, unsigned long ulAddress,
                        unsigned long ulCount)
{
    //
    // Check the arguments.
    //
    ASSERT(!(ulAddress & 3));
    ASSERT(!(ulCount & 3));

    //
    // Clear the flash access and error interrupts.
    //
    HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FCMISC)
      = (FLASH_CTRL_FCMISC_AMISC | FLASH_CTRL_FCMISC_VOLTMISC |
                           FLASH_CTRL_FCMISC_INVDMISC | FLASH_CTRL_FCMISC_PROGMISC);

    //
    // See if this device has a write buffer.
    //

#if HAVE_WRITE_BUFFER
    {
        //
        // Make sure the address/count specified doesn't straddle a 32 word
        // boundary.
        //
        if(((ulAddress + (ulCount - 1)) & ~0x7F) != (ulAddress & ~0x7F))
        {
            return(-1);
        }

        //
        // Loop over the words to be programmed.
        //
        while(ulCount)
        {
            //
            // Set the address of this block of words.
            //
            HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FMA) = ulAddress & ~(0x7F);

            //
            // Loop over the words in this 32-word block.
            //
            while(((ulAddress & 0x7C) || (HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FWBVAL) == 0)) &&
                  (ulCount != 0))
            {
                //
                // Write this word into the write buffer.
                //
                HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FWBN + (ulAddress & 0x7C)) = *pulData++;
                ulAddress += 4;
                ulCount -= 4;
            }

            //
            // Program the contents of the write buffer into flash.
            //
            HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FMC2) = FLASH_CTRL_FMC2_WRKEY | FLASH_CTRL_FMC2_WRBUF;
        }
    }
#else
    {
        //
        // We don't have a write buffer so we can only write a single word.
        //
        if(ulCount > 1)
        {
            return(-1);
        }

        //
        // Write a single word.
        //
        HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FMA) = ulAddress;
        HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FMD) = *pulData;
        HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FMC) = FLASH_CTRL_FMC_WRKEY | FLASH_CTRL_FMC_WRITE;
    }
#endif
    //
    // Success.
    //
    return(0);
}


//*****************************************************************************
//
//! Gets the protection setting for a block of flash.
//!
//! \param ulAddress is the start address of the flash block to be queried.
//!
//! This function gets the current protection for the specified 2-kB block
//! of flash.  Each block can be read/write, read-only, or execute-only.
//! Read/write blocks can be read, executed, erased, and programmed.  Read-only
//! blocks can be read and executed.  Execute-only blocks can only be executed;
//! processor and debugger data reads are not allowed.
//!
//! \return Returns the protection setting for this block.  See
//! FlashProtectSet() for possible values.
//
//*****************************************************************************
tFlashProtection
FlashProtectGet(unsigned long ulAddress)
{
    unsigned long ulFMPRE, ulFMPPE;
    unsigned long ulBank;

    //
    // Check the argument.
    //
    ASSERT(!(ulAddress & (FLASH_PROTECT_SIZE - 1)));

    //
    // Calculate the Flash Bank from Base Address, and mask off the Bank
    // from ulAddress for subsequent reference.
    //
    ulBank = (((ulAddress / FLASH_PROTECT_SIZE) / 32) % 16);
    ulAddress &= ((FLASH_PROTECT_SIZE * 32) - 1);

    //
    // Read the appropriate flash protection registers for the specified
    // flash bank.
    //
    ulFMPRE = HWREG(g_pulFMPRERegs[ulBank]);
    ulFMPPE = HWREG(g_pulFMPPERegs[ulBank]);

    //
    // Check the appropriate protection bits for the block of memory that
    // is specified by the address.
    //
    switch((((ulFMPRE >> (ulAddress / FLASH_PROTECT_SIZE)) &
             FLASH_FMP_BLOCK_0) << 1) |
           ((ulFMPPE >> (ulAddress / FLASH_PROTECT_SIZE)) & FLASH_FMP_BLOCK_0))
    {
        //
        // This block is marked as execute only (that is, it can not be erased
        // or programmed, and the only reads allowed are via the instruction
        // fetch interface).
        //
        case 0:
        case 1:
        {
            return(FlashExecuteOnly);
        }

        //
        // This block is marked as read only (that is, it can not be erased or
        // programmed).
        //
        case 2:
        {
            return(FlashReadOnly);
        }

        //
        // This block is read/write; it can be read, erased, and programmed.
        //
        case 3:
        default:
        {
            return(FlashReadWrite);
        }
    }
}

//*****************************************************************************
//
//! Registers an interrupt handler for the flash interrupt.
//!
//! \param pfnHandler is a pointer to the function to be called when the flash
//! interrupt occurs.
//!
//! This sets the handler to be called when the flash interrupt occurs.  The
//! flash controller can generate an interrupt when an invalid flash access
//! occurs, such as trying to program or erase a read-only block, or trying to
//! read from an execute-only block.  It can also generate an interrupt when a
//! program or erase operation has completed.  The interrupt will be
//! automatically enabled when the handler is registered.
//!
//! \sa IntRegister() for important information about registering interrupt
//! handlers.
//!
//! \return None.
//
//*****************************************************************************
void
FlashIntRegister(void (*pfnHandler)(void))
{
    //
    // Register the interrupt handler, returning an error if an error occurs.
    //
    IntRegister(INT_FLASH, pfnHandler);

    //
    // Enable the flash interrupt.
    //
    IntEnable(INT_FLASH);
}

//*****************************************************************************
//
//! Unregisters the interrupt handler for the flash interrupt.
//!
//! This function will clear the handler to be called when the flash interrupt
//! occurs.  This will also mask off the interrupt in the interrupt controller
//! so that the interrupt handler is no longer called.
//!
//! \sa IntRegister() for important information about registering interrupt
//! handlers.
//!
//! \return None.
//
//*****************************************************************************
void
FlashIntUnregister(void)
{
    //
    // Disable the interrupt.
    //
    IntDisable(INT_FLASH);

    //
    // Unregister the interrupt handler.
    //
    IntUnregister(INT_FLASH);
}

//*****************************************************************************
//
//! Enables individual flash controller interrupt sources.
//!
//! \param ulIntFlags is a bit mask of the interrupt sources to be enabled.
//! Can be any of the \b FLASH_CTRL_PROGRAM or \b FLASH_CTRL_ACCESS values.
//!
//! Enables the indicated flash controller interrupt sources.  Only the sources
//! that are enabled can be reflected to the processor interrupt; disabled
//! sources have no effect on the processor.
//!
//! \return None.
//
//*****************************************************************************
void
FlashIntEnable(unsigned long ulIntFlags)
{
    //
    // Enable the specified interrupts.
    //
    HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FCIM) |= ulIntFlags;
}

//*****************************************************************************
//
//! Disables individual flash controller interrupt sources.
//!
//! \param ulIntFlags is a bit mask of the interrupt sources to be disabled.
//! Can be any of the \b FLASH_CTRL_PROGRAM or \b FLASH_CTRL_ACCESS values.
//!
//! Disables the indicated flash controller interrupt sources.  Only the
//! sources that are enabled can be reflected to the processor interrupt;
//! disabled sources have no effect on the processor.
//!
//! \return None.
//
//*****************************************************************************
void
FlashIntDisable(unsigned long ulIntFlags)
{
    //
    // Disable the specified interrupts.
    //
    HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FCIM) &= ~(ulIntFlags);
}

//*****************************************************************************
//
//! Gets the current interrupt status.
//!
//! \param bMasked is false if the raw interrupt status is required and true if
//! the masked interrupt status is required.
//!
//! This returns the interrupt status for the flash controller.  Either the raw
//! interrupt status or the status of interrupts that are allowed to reflect to
//! the processor can be returned.
//!
//! \return The current interrupt status, enumerated as a bit field of
//! \b FLASH_CTRL_PROGRAM and \b FLASH_CTRL_ACCESS.
//
//*****************************************************************************
unsigned long
FlashIntStatus(tBoolean bMasked)
{
    //
    // Return either the interrupt status or the raw interrupt status as
    // requested.
    //
    if(bMasked)
    {
        return(HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FCMISC));
    }
    else
    {
        return(HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FCRIS));
    }
}

//*****************************************************************************
//
//! Clears flash controller interrupt sources.
//!
//! \param ulIntFlags is the bit mask of the interrupt sources to be cleared.
//! Can be any of the \b FLASH_CTRL_PROGRAM or \b FLASH_CTRL_AMISC values.
//!
//! The specified flash controller interrupt sources are cleared, so that they
//! no longer assert.  This must be done in the interrupt handler to keep it
//! from being called again immediately upon exit.
//!
//! \note Because there is a write buffer in the Cortex-M3 processor, it may
//! take several clock cycles before the interrupt source is actually cleared.
//! Therefore, it is recommended that the interrupt source be cleared early in
//! the interrupt handler (as opposed to the very last action) to avoid
//! returning from the interrupt handler before the interrupt source is
//! actually cleared.  Failure to do so may result in the interrupt handler
//! being immediately reentered (because the interrupt controller still sees
//! the interrupt source asserted).
//!
//! \return None.
//
//*****************************************************************************
void
FlashIntClear(unsigned long ulIntFlags)
{
    //
    // Clear the flash interrupt.
    //
    HWREG(FLASH_CONTROL_BASE + FLASH_CTRL_O_FCMISC) = ulIntFlags;
}

//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
