/*********************************************************************
*               (c) SEGGER Microcontroller GmbH & Co. KG             *
*                        The Embedded Experts                        *
*                           www.segger.com                           *
**********************************************************************

-------------------------- END-OF-HEADER -----------------------------

File    : AMAPH1KK-KBR.JLinkScript
Purpose : Handle reset for AmbiqMicro AMA3B1KK series of MCUs
Literature:
  [1]  J-Link User Guide (UM08001_JLink.pdf)

Additional information:
  For more information about public functions that can be implemented
  in order to customize J-Link actions, please refer to [1]
*********************************************************************/

/*********************************************************************
*
*       ResetTarget()
* Reset and wait until CPU is halted.
*********************************************************************/
void ResetTarget(void) {

  // Register Address Values
  int AIRCR_ADDR     ;
  int DHCSR_ADDR     ;
  int DEMCR_ADDR     ;
  int AHBAP_REG_CTRL ;
  int AHBAP_REG_ADDR ;
  int AHBAP_REG_DATA ;
  int DP_REG_SELECT  ;
  int MCUCTRL_SCRATCH0  ;
  int MCUCTRL_BOOTLDR  ;
  int JDEC_PID  ;

  // Internal Variables
  int Ctrl;
  int demcr;
  int scratch0;
  int bootldr;
  int jdecpid;
  int v;
  int Tries;
  int Done;
  int nonsecure;
  int timeout;

  // Initialize the Register Address and Internal vars.
  AIRCR_ADDR         = 0xE000ED0C;
  DHCSR_ADDR         = 0xE000EDF0;
  DEMCR_ADDR         = 0xE000EDFC;
  MCUCTRL_SCRATCH0   = 0x400401B0;
  MCUCTRL_BOOTLDR    = 0x400401A0;
  JDEC_PID           = 0xF0000FE0;
  AHBAP_REG_CTRL     = 0;
  AHBAP_REG_ADDR     = 1;
  AHBAP_REG_DATA     = 3;
  DP_REG_SELECT      = 2;
  nonsecure          = 1;
  timeout            = 0;


  // Check global variable to detect whether debugger is using JTAG or SWO and configure JTAG is necessary.
  if (MAIN_ActiveTIF == JLINK_TIF_JTAG) {
    JLINK_CORESIGHT_Configure("IRPre=0;DRPre=0;IRPost=0;DRPost=0;IRLenDevice=4");
  } else {
    JLINK_CORESIGHT_Configure(""); // For SWD, no special setup is needed, just output the switching sequence
  }
  
  // Power-up complete DAP
  Ctrl = 0
       | (1 << 30)     // System power-up
       | (1 << 28)     // Debug popwer-up
       | (1 << 5)      // Clear STICKYERR
       ;
  JLINK_CORESIGHT_WriteDP(1, Ctrl);
  
  // Select AHB-AP and configure it 
  JLINK_CORESIGHT_WriteDP(DP_REG_SELECT,  (0 << 4) | (0 << 24));                                     // Select AP[0] (AHB-AP) bank 0
  JLINK_CORESIGHT_WriteAP(AHBAP_REG_CTRL, (1 << 4) | (1 << 24) | (1 << 25) | (1 << 29) | (2 << 0));  // Auto-increment, Private access, HMASTER = DEBUG, Access size: word
 
  // Enable Debug and Halt the MCU Core.
  JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, DHCSR_ADDR);
  v = JLINK_CORESIGHT_ReadAP(AHBAP_REG_DATA);
  v &= 0x3F;                   // Mask out "debug" bits
  v |= 0xA05F0000;             // Debug key to make a write to the DHCSR a valid one
  v |= 0x00000002;             // Halt the core
  v |= 0x00000001;             // Enable debug functionalities of the core
  JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, DHCSR_ADDR);
  JLINK_CORESIGHT_WriteAP(AHBAP_REG_DATA, v);

  // Read the Peripheral ID.
  JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, JDEC_PID);
  jdecpid = JLINK_CORESIGHT_ReadAP(AHBAP_REG_DATA);
  Report1("JDEC PID ", jdecpid);
 
  // Is this Apollo3-Blue MCU?
  if ((jdecpid & 0xF0) == 0xC0)
  {
    // Apollo3
    Report("Ambiq Apollo3 ResetTarget");

    // Read MCUCTRL_BOOTLDR to determine if it is a secure or non-secure chip
    JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, MCUCTRL_BOOTLDR);
    bootldr = JLINK_CORESIGHT_ReadAP(AHBAP_REG_DATA);
    Report1("Bootldr = ", bootldr);
    if ((bootldr & 0x0C000000) == 0x04000000)
    {
        Report("Secure Part.");
		nonsecure = 0;
    }
  }

  if (nonsecure == 0)
  {
      // Set MCUCTRL Scratch0, indicating that the Bootloader needs to run, then halt when it is finished.
      Report("Secure Chip. Bootloader needs to run which will then halt when finish.");
      JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, MCUCTRL_SCRATCH0);
      scratch0 = JLINK_CORESIGHT_ReadAP(AHBAP_REG_DATA);
      JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, MCUCTRL_SCRATCH0);
      JLINK_CORESIGHT_WriteAP(AHBAP_REG_DATA, scratch0 | 0x1);
  } else
  {
      // Set VC_CORERESET in the DEMCR.
      Report("Non-Secure Chip. Following normal Reset procedure.");
      JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, DEMCR_ADDR);
      demcr = JLINK_CORESIGHT_ReadAP(AHBAP_REG_DATA);
      JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, DEMCR_ADDR);
      JLINK_CORESIGHT_WriteAP(AHBAP_REG_DATA, demcr | 0x00000001);
  }

  // Set the SYSRESETREQ bit in the AIRCR.
  // This will request the MCU Core to reset.
  JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, AIRCR_ADDR);
  JLINK_CORESIGHT_WriteAP(AHBAP_REG_DATA, 0x05FA0004);
  
  // Wait until CPU is halted
  Tries = 0;
  Done  = 0;
  do {
    JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, DHCSR_ADDR);
    v = JLINK_CORESIGHT_ReadAP(AHBAP_REG_DATA);
    // Check if CPU is halted. If so, we are done
    if (Tries >= 25) // wait for up to 2.5 seconds.
	{
      Report("Apollo3 (connect): Timeout while waiting for CPU to halt after reset. Manually halting CPU.");
      Done = 1;
      timeout = 1;
    } 
	else if ((v != 0xFFFFFFFF) && (v & 0x00020000)) // Bit 17: S_HALT in the DHCSR.
	{
      Report1("CPU halted after reset. Num Tries = ", Tries);
      Done = 1;
    }
    Tries = Tries + 1;
    SYS_Sleep(100);  // Go to sleep for 100 msec.
  } while(Done == 0);
  
  // Let's try one more time using regular reset method
  if ((timeout == 1) && (nonsecure == 0))
  {
    // Set VC_CORERESET
    Report("Secure Part Reset timed out. Reverting to normal Reset procedure.");
    JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, DEMCR_ADDR);
    demcr = JLINK_CORESIGHT_ReadAP(AHBAP_REG_DATA);
    JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, DEMCR_ADDR);
    JLINK_CORESIGHT_WriteAP(AHBAP_REG_DATA, demcr | 0x00000001);
    // SYSRESETREQ
    JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, AIRCR_ADDR);
    JLINK_CORESIGHT_WriteAP(AHBAP_REG_DATA, 0x05FA0004);
    //
    // Wait until CPU is halted
    //
    Tries = 0;
    Done  = 0;
    do {
      JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, DHCSR_ADDR);
      v = JLINK_CORESIGHT_ReadAP(AHBAP_REG_DATA);
      // Check if CPU is halted. If so, we are done
      if (Tries >= 25) // wait for up to 2.5 seconds.
	  {
        Report("Apollo3 (connect): Timeout while waiting for CPU to halt after reset. Manually halting CPU.");
        Done = 1;
        timeout = 1;
      } 
	  else if ((v != 0xFFFFFFFF) && (v & 0x00020000)) // Bit 17: S_HALT in the DHCSR.
	  {
        Report1("CPU halted after reset. Num Tries = ", Tries);
        Done = 1;
      }
      Tries = Tries + 1;
      SYS_Sleep(100);  // Go to sleep for 100 msec.
    } while(Done == 0);
  }
  
  // If non-secure part,... 
  if (nonsecure == 1)
  {
      // Clear VC_CORERESET in the DEMCR.
      JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, DEMCR_ADDR);
      demcr = JLINK_CORESIGHT_ReadAP(AHBAP_REG_DATA);
      JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, DEMCR_ADDR);
      JLINK_CORESIGHT_WriteAP(AHBAP_REG_DATA, (demcr & 0xFFFFFFFE));
   }


}
