/***********************************************************************
*                    SEGGER Microcontroller GmbH                       *
*                        The Embedded Experts                          *
************************************************************************
*                                                                      *
*                  (c) SEGGER Microcontroller GmbH                     *
*                        All rights reserved                           *
*                          www.segger.com                              *
*                                                                      *
************************************************************************
*                                                                      *
************************************************************************
*                                                                      *
*                                                                      *
*  Licensing terms                                                     *
*                                                                      *
* The use in source and binary forms, with or without modification,    *
* is permitted for internal use only. The redistribution to any        *
* third party is prohibited.                                           *
*                                                                      *
*                                                                      *
* 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: Examplescript to modify TracePortWidth and Pin init
Literature:
  [1]  J-Link User Guide

Additional information:
  For more information about public functions that can be implemented in order to customize J-Link actions, please refer to [1]
*/

/*********************************************************************
*
*       Constants
*
**********************************************************************
*/
//
// IronSide SE IPC: application core shared memory and bellboard
//
__constant U32 _IPC_BUF_ADDR          = 0x2F88FB80;  // IRONSIDE_SE_APPLICATION_IPC_BUFFER_ADDRESS
__constant U32 _SECDOMBELLBOARD_BASE  = 0x5F099000;  // NRF_SECDOMBELLBOARD_NS_BASE
__constant U32 _APP_BELLBOARD_BASE    = 0x5F09A000;  // NRF_APPLICATION_BELLBOARD_NS_BASE

//
// IPC buffer layout (struct ironside_se_call_buf):
//   offset 0x00: uint16_t status
//   offset 0x02: uint16_t id
//   offset 0x04: uint32_t args[0]  (config)
//
__constant U32 _IPC_STATUS_IDLE       = 0;
__constant U32 _IPC_STATUS_REQ        = 6;
__constant U32 _IPC_STATUS_RSP_SUCCESS = 1;
__constant U32 _IPC_ID_TDD_CONFIGURE  = 4;
__constant U32 _TDD_CONFIG_ON_DEFAULT = 2;

//
// BELLBOARD register offsets:
//   TASKS_TRIGGER[n] at offset n*4
//   EVENTS_TRIGGERED[n] at offset 0x100 + n*4
//
__constant U32 _SECDOM_TX_BELL_IDX    = 12;   // IRONSIDE_SE_APPLICATION_BELLBOARD_IPC_TX_BELL_IDX
__constant U32 _APP_RX_BELL_IDX       = 0;    // IRONSIDE_SE_APPLICATION_BELLBOARD_IPC_RX_BELL_IDX

//
// GPIO P7 pin configuration for TPIU pins (P7.3-P7.7)
//   PIN_CNF[n] at GPIO7_BASE + 0x80 + n*4
//   DIR=output(1), INPUT=disconnect(1), PULL=none(0),
//   DRIVE0=H0(1), DRIVE1=H1(1), SENSE=none(0)
//
__constant U32 _GPIO7_BASE     = 0x5F938E00;
__constant U32 _PIN_CNF_OFFSET = 0x080;
__constant U32 _PIN_CNF_TPIU_DATA  = 0x00000503;  // output | disconnect | H0H1
__constant U32 _PIN_CNF_TPIU_CLOCK = 0x80000503;  // same + CLOCKPIN enabled (bit 31)

__constant U32 _DCACHE_BASE    = 0xE0083000;  // Local to application core

/*********************************************************************
*
*       Local functions
*
**********************************************************************
*/

/*********************************************************************
*
*       _Enable_TDD()
*
*  Function description
*    TDD power domain control via IronSide SE IPC.
*    Reproduces the ironside_se_tdd_configure(ON_DEFAULT) call:
*      1. Write the IPC request into the shared buffer.
*      2. Ring the secure domain bellboard to dispatch the request.
*      3. Busy-wait for the response on the application bellboard.
*      4. Release the buffer.
*
*  Return value
*    >= 0:  O.K.
*     < 0:  Error
*/
int _Enable_TDD(void) {
  U32 StatusId;
  U32 EventAddr;
  U32 Timeout;
  U32 v;
  //
  // The application core needs to be halted, otherwise we might not see the reponse to the IPC call.
  //
  JLINK_TARGET_Halt();
  EventAddr = _APP_BELLBOARD_BASE + 0x100 + (_APP_RX_BELL_IDX * 4);
  //
  // The firmware may have used this IPC buffer and bellboard channel
  // before the debugger halted the CPU.  Clear any stale event and
  // reset the buffer to IDLE before issuing our own request.
  //
  JLINK_MEM_WriteU32(EventAddr, 0);
  JLINK_MEM_WriteU32(_IPC_BUF_ADDR + 0x00, _IPC_STATUS_IDLE);
  //
  // Pack status (REQ=6, lower 16 bits) and id (TDD_CONFIGURE=4, upper 16 bits)
  // into a single 32-bit write covering both uint16_t fields.
  //
  StatusId = (_IPC_ID_TDD_CONFIGURE << 16) | _IPC_STATUS_REQ;
  JLINK_MEM_WriteU32(_IPC_BUF_ADDR + 0x00, StatusId);
  JLINK_MEM_WriteU32(_IPC_BUF_ADDR + 0x04, _TDD_CONFIG_ON_DEFAULT);
  JLINK_MEM_WriteU32(_DCACHE_BASE + 0x10, 1); // Flush the data cache
  JLINK_MEM_WriteU32(_SECDOMBELLBOARD_BASE + (_SECDOM_TX_BELL_IDX * 4), 1); // Trigger SECDOMBELLBOARD TASKS_TRIGGER[12]
  //
  // Poll EVENTS_TRIGGERED[0] on application bellboard
  //
  Timeout = 0;
  v = 0;
  while ((v == 0) && (Timeout < 1000)) {
    v = JLINK_MEM_ReadU32(EventAddr);
	JLINK_SYS_Sleep(1);
    Timeout = Timeout + 1;
  }
  if (v == 0) {
    JLINK_SYS_Report("  ERROR: TDD enable timed out waiting for IronSide SE response");
    return -1;
  }
  JLINK_MEM_WriteU32(EventAddr, 0); // Clear the event
  //
  // Check response status
  //
  StatusId = JLINK_MEM_ReadU32(_IPC_BUF_ADDR + 0x00);
  if ((StatusId & 0xFFFF) != _IPC_STATUS_RSP_SUCCESS) {
    JLINK_SYS_Report1("  ERROR: TDD enable IPC call failed: ", StatusId);
    return -1;
  }
  //
  // Release buffer (set status to IDLE)
  //
  JLINK_MEM_WriteU32(_IPC_BUF_ADDR + 0x00, _IPC_STATUS_IDLE);
  JLINK_SYS_Report("  TDD power domain enabled");
  return 0;
}

/*********************************************************************
*
*       Global functions
*
**********************************************************************
*/

/*********************************************************************
*
*       OnTraceStart()
*
*  Function description
*    If present, called right before trace is started.
*    Used to initialize MCU specific trace related things like configuring the trace pins for alternate function.
*
*  Return value
*    >= 0:  O.K.
*     < 0:  Error
*
*  Notes
*    (1) May use high-level API functions like JLINK_MEM_ etc.
*    (2) Should not call JLINK_TARGET_Halt(). Can rely on target being halted when entering this function
*/
int OnTraceStart(void) {
  U32 GPIOBaseAddr;
  
  GPIOBaseAddr = _GPIO7_BASE + _PIN_CNF_OFFSET;
  if (_Enable_TDD() != 0) { // Use IronSide IPC to enable the Test & Debug Domain
    return -1;
  }
  //
  // Configure GPIO pins for trace output
  // Pin mux (GPIO CTRLSEL) is assumed to already be configured via UICR * PERIPHCONF at boot.
  //
  JLINK_MEM_WriteU32(GPIOBaseAddr + (3 * 4), _PIN_CNF_TPIU_CLOCK);  // P7.3 TPIU_CLOCK
  JLINK_MEM_WriteU32(GPIOBaseAddr + (4 * 4), _PIN_CNF_TPIU_DATA);   // P7.4 TPIU_DATA0
  if (JLINK_TRACE_PortWidth > 1) {
      JLINK_MEM_WriteU32(GPIOBaseAddr + (5 * 4), _PIN_CNF_TPIU_DATA);   // P7.5 TPIU_DATA1
  }
  if (JLINK_TRACE_PortWidth > 2) {
      JLINK_MEM_WriteU32(GPIOBaseAddr + (6 * 4), _PIN_CNF_TPIU_DATA);   // P7.6 TPIU_DATA2
      JLINK_MEM_WriteU32(GPIOBaseAddr + (7 * 4), _PIN_CNF_TPIU_DATA);   // P7.7 TPIU_DATA3
  }
  JLINK_SYS_Report("Trace Pins Configured.");
  return 0;
}