/*********************************************************************
*                    SEGGER Microcontroller GmbH                     *
*       Solutions for real time microcontroller applications         *
**********************************************************************
*                                                                    *
*            (c) 1995 - 2018 SEGGER Microcontroller GmbH             *
*                                                                    *
*       www.segger.com     Support: support@segger.com               *
*                                                                    *
**********************************************************************
----------------------------------------------------------------------
Purpose : J-Link script file for BeagleBoard which has a
          TI OMAP3530 (Cortex-A8 core) on it.
          By default, only the TI ICEPick is in the JTAG chain
          which means that we have to add the Cortex-A8 by configuring the ICEPick.
          Moreover, the OMAP3530 also requires to set the DEBGEN signal in order to allow debugging.
---------------------------END-OF-HEADER------------------------------
*/

/*********************************************************************
*
*       _StoreSelDP
*/
void _StoreSelDP(void) {
  JTAG_StoreIR(0xA);  // DPACC command
  JTAG_StoreClocks(1);
}

/*********************************************************************
*
*       _StoreSelAP
*/
void _StoreSelAP(void) {
  JTAG_StoreIR(0xB);  // APACC command
  JTAG_StoreClocks(1);
}

/*********************************************************************
*
*       _StoreTriggerReadAPDPReg
*
*  Function description
*    Triggers a read of an AP or DP register. Depends on the previous command (DPACC / APACC)
*/
int _StoreTriggerReadAPDPReg(unsigned int RegIndex) {
  U32 v;
  int BitPos;
  //
  // Write 35 bits (32 bits data, 2 bits addr, 1 bit RnW)
  //
  v  = 1;                // 1 indicates read access
  v |= (RegIndex << 1);
  JLINK_JTAG_StartDR();
  BitPos = JLINK_JTAG_WriteDRCont(v, 3);
  v = 0;
  JLINK_JTAG_WriteDREnd(v, 32);
  JTAG_StoreClocks(8);
  return BitPos;
}

/*********************************************************************
*
*       _StoreWriteAPDPReg
*
*  Function description
*    Writes an AP or DP register. Depends on the previous command (DPACC / APACC)
*/
int _StoreWriteAPDPReg(unsigned int RegIndex, U32 Data) {
  U32 v;
  int BitPos;
  //
  // Write 35 bits (32 bits data, 2 bits addr, 1 bit RnW)
  //
  v = 0;   // 0 indicates write access
  v |= (RegIndex << 1);
  JLINK_JTAG_StartDR();
  BitPos = JLINK_JTAG_WriteDRCont(v, 3);
  v = Data;
  JLINK_JTAG_WriteDREnd(v, 32);
  JTAG_StoreClocks(8);
  return BitPos;
}

/*********************************************************************
*
*       _InitIcePick
*
*  Function description
*    Configures the ICEPick so that the CPU core also becomes
*    visible in the JTAG chain.
*/
int _InitIcePick(void) {
  int BitPos;
  int v;
  int DPIdCode;
  int ICEPickIdCode;
  int i;
  int Speed;

  Report("J-Link script: Init ICEPick");
  JTAG_Reset();                           // Perform TAP reset and J-Link JTAG auto-detection
  if (JTAG_TotalIRLen != 6) {
    MessageBox("Can not find Beagle eval board (IRLen mismatch)");
  }
  JTAG_DRPre  = 0;
  JTAG_DRPost = 0;
  JTAG_IRPre  = 0;
  JTAG_IRPost = 0;
  JTAG_IRLen  = 6;
  Speed       = JTAG_Speed;
  JTAG_Speed  = 50;
  //
  // Check IDCODE of ICEPick (do not confuse with ICEPICKCODE or IDCODE of JTAG-DP)
  //
  JTAG_WriteIR(4);   // IDCODE instruction for ICEPick device
  BitPos = JTAG_WriteDR(0x00000000, 32);
  v = JTAG_GetU32(BitPos);
  //
  // Seems the part number of the ICEPick has been changed
  // between BeagleBoard and BeagleBoard-xM, so we have
  // to check both part numbers.
  //
  if (((v & 0x0FFFFFFF) != 0x0B7AE02F) &&                       // ICEPICK-IDCODE of ICEPICK on BeagleBoard
      ((v & 0x0FFFFFFF) != 0x0B89102F)                          // ICEPICK-IDCODE of ICEPICK on BeagleBoard XM
     ) {
    MessageBox1("Can not find ICE-Pick (IDCODE mismatch). Expected 0x0B7AE02F / 0x0B89102F, found: ", v);
    return 1;
  }
  ICEPickIdCode = v;
  //
  // Read ICEPICKCODE
  //
  JTAG_WriteIR(5);
  BitPos = JTAG_WriteDR(0x00000000, 32);
  v = JTAG_GetU32(BitPos);
  if ((v & 0x0000FFF0) != 0x00001CC0) {
    MessageBox("Connected module is not an ICEPick Module (ICEPICKCODE mismatch)");
    return 1;
  }
  //
  // Put ARM core in JTAG chain
  //  
  JTAG_WriteIR(7);         // CONNECT
  JTAG_WriteDR(0x89, 8);   // The ICEPick documentation (SPRUE64, 2.6 CONNECT instruction: Accessing the debug connect register). Bit 7 set means: Write debug connect register. We write 0x9 to the debug connect register which is the debug connect key.
  JTAG_WriteIR(2);         // ROUTER (Accessing the mapped registers)
  v = 0
    | (1 << 31)            // Write mapped register
    | (0x23 << 24)         // SDTAP3 register
    | (1 << 13)            // Debug connect
    | (1 << 8)             // TAP select
    | (1 << 3)             // Force active
    ;
  JTAG_WriteDR(v, 32);
  JTAG_WriteIR(0x3F);      // Bypass
  JTAG_WriteClocks(10);
  //
  // Configure JTAG chain, so J-Link knows to which devices it has to "talk" to.
  // CPU core is in scan chain now, so we have to re-configure the JTAG chain settings
  //
  JTAG_DRPre  = 0;
  JTAG_DRPost = 1;
  JTAG_IRPre  = 0;
  JTAG_IRPost = 6;
  JTAG_IRLen  = 4;
  CPU=CORTEX_A8;
  JTAG_AllowTAPReset=0; 
  //
  // Check JTAG-DP ID
  // On the Cortex-A OMAP devices it seems that the manufacturer field of the JTAG-DP ID
  // is not set to ARM JEDEC ID but to TI JEDEC ID which is not really CoreSight compliant.
  // So we check if one of these manufacturer codes match.
  //
  JTAG_StoreIR(0xE);  // Read JTAG-DP IDCODE register
  v = 0;
  BitPos = JTAG_StoreDR(v, 32);  // Get ID
  v = JTAG_GetU32(BitPos);
  if (((v & 0x00000FFF) != 0x0000002F) &&                       // TI JEDEC ID
      ((v & 0x00000FFF) != 0x00000477)                          // ARM JEDEC ID
     ) {
    MessageBox("Can not find JTAG-DP (IDCODE mismatch)");
  }
  //
  // Set JTAG Ids for all devices in the JTAG chain
  //  
  JTAG_SetDeviceId(0, v);  // JTAG-DP
  JTAG_SetDeviceId(1, ICEPickIdCode);  // ICEPick
  //
  // Set DBGEN signal in order to enable invasive debugging
  //
  _StoreSelDP();
  _StoreWriteAPDPReg(1, 0xF0000000);  // Write JTAG-DP CTRL/STAT in order to power-up debug port
  v = 0
    | (1 << 24)   // Select AP 1 which is the APB-AP
    | (0 << 4)    // Select Bank 0
    ;
  _StoreWriteAPDPReg(2, v);  // Write JTAG-DP SELECT register, in order to select the APB-AP. On the OMAP3550 AP[1] is the APB-AP
  _StoreSelAP();
  _StoreWriteAPDPReg(0, 0x80000012);  // Write APB-AP CSW
  _StoreWriteAPDPReg(1, 0xD401D030);  // Write APB-AP TAR
  v = (1 << 13);  // Set DBGEN signal
  _StoreWriteAPDPReg(3, v);  // Write APB-AP DRW
  _StoreSelDP();
  JTAG_WriteClocks(1);  // Make sure all JTAG buffers are cleared
  JTAG_Speed = Speed;
}

/*********************************************************************
*
*       _SetBP
*/
void _SetBP(int DbgRegBaseAddr) {
  __int64 Ctrl;
  //
  // Select & setup APB-AP
  //
  _StoreSelDP();
  _StoreWriteAPDPReg(2, (1 << 24) | (0 << 4));  // Select AP[1], bank 0
  _StoreSelAP();
  Ctrl =  0
       | (2 << 0)    // AP-access size. Fixed to 2: 32-bit
       | (1 << 4)    // Auto increment TAR after read/write access. Increment is NOT performed on access to banked data registers 0-3.
       | (1 << 31)   // Enable software access to the Debug APB bus.
       ;
  _StoreWriteAPDPReg(0, Ctrl);
  //
  // Step 1. Disable the breakpoint being set.
  //
  _StoreWriteAPDPReg(1, DbgRegBaseAddr + (0x50 << 2));
  _StoreWriteAPDPReg(3, 0x00000000);
  //
  // Step 2. Write address to the BVR, leaving the bottom 2 bits zero.
  //
  _StoreWriteAPDPReg(1, DbgRegBaseAddr + (0x40 << 2));
  _StoreWriteAPDPReg(3, 0x00014000);
  //
  // Step 3. Write the mask and control register to enable the breakpoint.
  //
  _StoreWriteAPDPReg(1, DbgRegBaseAddr + (0x50 << 2));
  _StoreWriteAPDPReg(3, 7 | (0xF << 5) | (0 << 20));
  JTAG_WriteClocks(1);   // Make sure that JTAG buffers are empty and breakpoint is set
}

/*********************************************************************
*
*       ResetTarget
*/
void ResetTarget(void) {
  int DbgRegBaseAddr;
  int Speed;
  int BitPos;
  int Ctrl;
  __int64 v;

  Report("J-Link script: Reset");
  Speed = JTAG_Speed;
  JTAG_Speed = 100;
  DbgRegBaseAddr = 0x54011000;
  //
  // Set breakpoint to halt target as fast as possible after reset
  //
  _SetBP(DbgRegBaseAddr);
  //
  // Setup JTAG config to "talk" to the ICEPick, so we can use the JTAG API functions
  //
  JTAG_DRPre  = 1;
  JTAG_DRPost = 0;
  JTAG_IRPre  = 4;
  JTAG_IRPost = 0;
  JTAG_IRLen  = 6;
  //
  // Perform reset via ICEPick system control register, by setting the SysReset bit
  //
  JTAG_StoreIR(2);                        // Cmd: ROUTER
  v = 0x01000000;                         // Read SYS_CNTL
  JTAG_StoreDR(v, 32);                    // Send read register command
  BitPos = JTAG_StoreDR(v, 32);           // Shift out register content
  v = JTAG_GetU32(BitPos);
  v &= 0x00FFFFFF;
  v |= 0x81000001;                        // Write SYS_CNTL and set SysReset bit
  JTAG_StoreDR(v, 32);
  JTAG_WriteClocks(10);                   // The reset needs some time to get active
  //
  // Setup JTAG config to "talk" to the CPU core again
  //
  JTAG_DRPre  = 0;
  JTAG_DRPost = 1;
  JTAG_IRPre  = 0;
  JTAG_IRPost = 6;
  JTAG_IRLen  = 4;
  //
  // Check if CPU is halted. If not, halt it.
  // Select & setup APB-AP
  //
  _StoreSelDP();
  _StoreWriteAPDPReg(2, (1 << 24) | (0 << 4));  // Select AP[1], bank 0
  _StoreSelAP();
  Ctrl =  0
       | (2 << 0)    // AP-access size. Fixed to 2: 32-bit
       | (1 << 4)    // Auto increment TAR after read/write access. Increment is NOT performed on access to banked data registers 0-3.
       | (1 << 31)   // Enable software access to the Debug APB bus.
       ;
  _StoreWriteAPDPReg(0, Ctrl);
  //
  // Read DSCR to check if CPU is halted
  //
  _StoreWriteAPDPReg(1, DbgRegBaseAddr + (0x22 << 2));
  _StoreTriggerReadAPDPReg(3);
  _StoreSelDP();
  BitPos = _StoreTriggerReadAPDPReg(3);
  v = JTAG_GetU32(BitPos + 3);
  _StoreSelAP();
  if ((v & 1) == 0) {
    //
    // If CPU did not halt after reset, halt it
    //
    Report("J-Link script: Core did not halt after reset. Halting core...");
    v |= (1 << 14);
    _StoreWriteAPDPReg(1, DbgRegBaseAddr + (0x22 << 2));   // Enable debug halt mode by writing the DSCR
    _StoreWriteAPDPReg(3, v);
    _StoreWriteAPDPReg(1, DbgRegBaseAddr + (0x24 << 2));   // Write DRCR to halt CPU
    _StoreWriteAPDPReg(3, 1);
    JTAG_WriteClocks(1);
  }
  //
  // Remove breakpoint
  //
  _StoreWriteAPDPReg(1, DbgRegBaseAddr + (0x50 << 2));
  _StoreWriteAPDPReg(3, 0);
  _StoreSelDP();
  JTAG_WriteClocks(1);
  JTAG_Speed = Speed;
}

/*********************************************************************
*
*       InitEMU
*/
void InitEMU(void) {
  EMU_ETB_IsPresent = 0;
}

/*********************************************************************
*
*       InitTarget
*/
void InitTarget(void) {
  int v;

  Report("Beagle Board OMAP3530 (Cortex-A8 core) J-Link script");
  JTAG_TRSTPin = 0;
  SYS_Sleep(50);
  JTAG_TRSTPin = 1;
  SYS_Sleep(50);
  JTAG_Write(0x1F, 0, 6);
  _InitIcePick();
}