/***********************************************************************
*                    SEGGER Microcontroller GmbH                       *
*                        The Embedded Experts                          *
************************************************************************
*                                                                      *
*                  (c) SEGGER Microcontroller GmbH                     *
*                        All rights reserved                           *
*                          www.segger.com                              *
*                                                                      *
************************************************************************
*                                                                      *
************************************************************************
*                                                                      *
*                                                                      *
*  Licensing terms                                                     *
*                                                                      *
* This software may be distributed to your customers free of charge.   *
* This grant of redistribution does not entitle YOU or enduser to      *
* receive from SEGGER hard-copy documentation, technical support,      *
* phone assistance, or enhancements or updates to the Software unless  *
* a specific agreement clearly states otherwise.                       *
*                                                                      *
*                                                                      *
* THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER "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 COPYRIGHT HOLDER 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.                                                              *
*                                                                      *
************************************************************************

-------------------------- END-OF-HEADER -----------------------------

Purpose: Implementation of the generic Cortex-M with ARMv7-M and ARMv6-M architecture device reset (Reset strategy Type 2: ResetPin).
Literature:
  [1]  J-Link User Guide
  [2]  https://wiki.segger.com/J-Link_Reset_Strategies#Type_2:_ResetPin
*/

/*********************************************************************
*
*       Constants, fixed
*
**********************************************************************
*/
//
// Registers (ARM)
//
__constant U32 _DHCSR_ADDR         = 0xE000EDF0; // Debug Halting Control and Status Register
__constant U32 _DEMCR_ADDR         = 0xE000EDFC; // Debug Exception and Monitor Control Register

//
// Bits & Shifts (ARM)
//
__constant U32 _DP_CTRL_STAT_BIT_STICKYERR = (1 <<  5);

__constant U32 _DHCSR_DBGKEY               = (0xA05F << 16);
__constant U32 _DHCSR_C_DEBUGEN            = (1 <<  0);
__constant U32 _DHCSR_C_HALT               = (1 <<  1);

__constant U32 _DEMCR_VC_CORERESET         = (1 <<  0);
__constant U32 _DEMCR_TRCENA               = (1 << 24);

/*********************************************************************
*
*       Constants, configurable
*
**********************************************************************
*/
//
// Timeouts
//
__constant U32 _DEF_RESET_PULSE_LEN = 50;
__constant U32 _DEF_RESET_DELAY     = 100;
__constant U32 _DEF_BUSY_TIMEOUT    = 500;
//
// AHB-AP related defines
//
__constant U32 _INDEX_AHB_AP_CORTEX_M7           = 0;  // AHB-AP connected to Cortex-M7 core.
__constant U32 _ACC_SIZE_WORD                    = 2;

/*********************************************************************
*
*       Static code
*
**********************************************************************
*/

/*********************************************************************
*
*       _DAPClrStickyErr
*
*  Function description
*    Clears the DAP sticky error flags.
*/
static void _DAPClrStickyErr(void) {
  U32 v;
  //
  // The DP is slightly different for JTAG and SWD regarding clearing sticky error bits.
  //
  if (JLINK_ActiveTIF == JLINK_TIF_SWD) {
    JLINK_CORESIGHT_WriteDP(JLINK_CORESIGHT_DP_REG_ABORT, 0x1E);
  } else {
    v  = JLINK_CORESIGHT_ReadDP(JLINK_CORESIGHT_DP_REG_CTRL_STAT);
    v |= _DP_CTRL_STAT_BIT_STICKYERR;
    JLINK_CORESIGHT_WriteDP(JLINK_CORESIGHT_DP_REG_CTRL_STAT, v);
  }
}

/*********************************************************************
*
*       _ConfigAP()
*
*  Function description
*    Configures selected AP for debugging.
*/
static int _ConfigAP(U32 Index, U32 AccSize, U8 IsAHBnAPB) {
  U32 v;
  int r;
  //
  // Select AP and bank to use
  //
  v = 0
    | (0     <<  4)   // Select bank 0 (this is default for most casese).
    | (Index << 24)   // Select AP[Index] (AHB-AP)
    ;
  JLINK_CORESIGHT_WriteDP(JLINK_CORESIGHT_DP_REG_SELECT,  v);
  //
  // Initialize DAP for debug use.
  //
  v = (AccSize <<  0) // Set access size
    | (0       <<  4) // No auto increment
    ;
  if (IsAHBnAPB) {
    v = v
      | (1     << 24) // Reserved
      | (1     << 25) // Private access
      | (1     << 29) // MasterType == Debug
      ;
  } else {
    v = v
      | (1     << 31) // DbgSwEnable == Enable
      ;
  }
  r = JLINK_CORESIGHT_WriteAP(JLINK_CORESIGHT_AP_REG_CTRL, v);
  if (r < 0) {
    JLINK_SYS_Report("Error: Failed to configure AP.");
    return -1;
  }
  return 0;
}

/*********************************************************************
*
*       _InitDAP()
*
*  Function description
*    Initializes DAP, so JLINK_CORESIGHT_ functions can be used.
*
*  Return value
*    =  0  O.K.
*    <  0  Error
*/
static int _InitDAP(void) {
  U32 v;
  int r;
  int t;

  _DAPClrStickyErr(); // Clear sticky error flags and power up DAP
  //
  // Wait for power up DAP complete
  //
  r = -1;
  t = JLINK_GetTime() + _DEF_BUSY_TIMEOUT;
  do {
    r = JLINK_CORESIGHT_ReadDP(JLINK_CORESIGHT_DP_REG_CTRL_STAT);
    if (r == -1) {                     // Any error occurred while reading from the DP, we are done
      break;
    }
    v = r;
    if (v & (0xF << 28)) {             // CSYSPWRUPACK and CDBGPWRUPACK set, so both ports have been completely powered?
      r = 0;
      break;
    }
    if ((t - JLINK_GetTime()) <= 0) {
      break;
    }
  } while(1);
  if (r < 0) {
    JLINK_SYS_Report("Error: Failed to initialize DAP.");
    return -1;
  }
  r = _ConfigAP(_INDEX_AHB_AP_CORTEX_M7, _ACC_SIZE_WORD, 1);  // Finally configure the AP so we can use it.
  if (r < 0) {
    return -1;
  }
  JLINK_SYS_Report("DAP initialized successfully.");
  return 0;
}

/*********************************************************************
*
*       Global functions
*
**********************************************************************
*/

/*********************************************************************
*
*       ResetTarget()
*
*  Function description
*    Replaces reset strategies of DLL. No matter what reset type is selected in the DLL, if this function is present, it will be called instead of the DLL internal reset.
*
*  Return value
*    <= 0  O.K.
*    <  0  Error
*
*  Notes
*    (1) DLL expects target CPU to be halted / in debug mode, when leaving this function
*    (2) May use MEM_ API functions
*    (3) The caller ensures that the J-Link SW / FW caches are invalidated after this function
*/
int ResetTarget(void) {
  int t;
  int r;
  //
  // Halt the CPU
  //
  JLINK_SYS_Report("Reset: Halt core after reset via DEMCR.VC_CORERESET.");
  JLINK_MEM_WriteU32(_DHCSR_ADDR, (_DHCSR_DBGKEY | _DHCSR_C_HALT | _DHCSR_C_DEBUGEN)); // Halt the CPU
  JLINK_MEM_WriteU32(_DEMCR_ADDR, (_DEMCR_VC_CORERESET | _DEMCR_TRCENA));              // Set vector catch on reset (to halt the CPU immediately after reset)
  //
  // Issue reset request via nRESET pin
  //
  JLINK_SYS_Report("Reset: Reset device via reset pin.");
  JLINK_TIF_ActivateTargetReset();
  JLINK_SYS_Sleep(_DEF_RESET_PULSE_LEN);
  JLINK_TIF_ReleaseTargetReset();
  //
  // Give  target some time to "recover" from RESET. This is because RESET typically has a capacitor connected and needs some
  // time to be deactivated. If the reset strategy worked, this is no problem since the CPU is already halted.
  // This delay here increases the stability.
  //
  JLINK_SYS_Sleep(_DEF_RESET_DELAY);
  //
  // Make sure DLL no longer assumes that device is halted and any cached CPU register values are valid.
  //
  JLINK_ExecCommand("InvalidateCPUState");
  //
  // Manually halt CPU, in case vector catch did not work.
  // Can happen on devices which also reset the debug logic when toggling the reset pin. (E.g. Atmel SAM3U)
  //
  if (JLINK_TARGET_IsHalted() == 0) {
    JLINK_SYS_Report("Reset: VC_CORERESET did not halt CPU. (Debug logic also reset by reset pin?).");
    JLINK_SYS_Report("Reset: Reconnecting and manually halting CPU.");
    r = _InitDAP();       // Reconnect after system reset.
    JLINK_TARGET_Halt();
    //
    // Wait until CPU is halted.
    //
    t = JLINK_GetTime() + _DEF_BUSY_TIMEOUT;
    do {
      if (JLINK_TARGET_IsHalted()) {
        break;
      }
      if ((t - JLINK_GetTime()) < 0) {
        JLINK_SYS_Report("Reset: Timeout while waiting for CPU to halt.");
        r = -1;
      }
    } while (1);
  }
  //
  // Make sure we clear the vector catch we have set before
  //
  JLINK_MEM_WriteU32(_DEMCR_ADDR, (_DEMCR_TRCENA));
  return r;
}

/*************************** end of file ****************************/
