Raspberry Pi 2 Bare Metal Multicore JTAG Debugging

To get going with multicore development and JTAG debugging, these code snippets and pieces of information should be useful.

1. JTAG debugging

To enable JTAG on Raspberry Pi 2, some of the GPIO pins needs to be configured to their “alternate” function. Create a small application that calls the function below. Build the application, and place the kernel.img file on the SD-card. Now, when the Raspberry Pi 2 boots, JTAG pins will be enabled.

/*--------------------------------------------------*/
static void jtag_enable(void)
{
    // http://sysprogs.com/VisualKernel/tutorials/raspberry/jtagsetup/
    /* -------- JTAG SETUP --------
    JTAG pin    JTAG sig    GPIO        Header pin
    1           VREF        N/A         1
    3           nTRST       GPIO22      15
    4           GND         N/A         9
    5           TDI         GPIO4       7
    7           TMS         GPIO27      13
    9           TCK         GPIO25      22
    11          RTCK        GPIO23      16
    13          TDO         GPIO24      18
    -------------------------------*/

    GPFSEL2_bit.FSEL22 = GPFSEL_ALT4;   // nTRST
    GPFSEL0_bit.FSEL4  = GPFSEL_ALT5;   // TDI
    GPFSEL2_bit.FSEL27 = GPFSEL_ALT4;   // TMS
    GPFSEL2_bit.FSEL25 = GPFSEL_ALT4;   // TCK
    GPFSEL2_bit.FSEL23 = GPFSEL_ALT4;   // RTCK
    GPFSEL2_bit.FSEL24 = GPFSEL_ALT4;   // TDO
}

2. Multicore JTAG debugging

To get in contact with all 4 CPU cores, write the following in a bcm2836.ProbeConfig file:

"A7_0" "Cortex-A7:0@0x80010000"
+"A7_1" "Cortex-A7:0@0x80012000"
+"A7_2" "Cortex-A7:0@0x80014000"
+"A7_3" "Cortex-A7:0@0x80016000"

Specify the ProbeConfig file on: Project > Options > I-jet > JTAG/SWD > Probe configuration file.

Enable Multicore with: Project > Options > Debugger > Multicore > Number of cores : 4.

The Debug Log should say:

Connecting on DAP APB-AP port 0 to core Cortex-A7 r0p5 at 0x80010000. 
Connecting on DAP APB-AP port 0 to core Cortex-A7 r0p5 at 0x80012000. 
Connecting on DAP APB-AP port 0 to core Cortex-A7 r0p5 at 0x80014000. 
Connecting on DAP APB-AP port 0 to core Cortex-A7 r0p5 at 0x80016000.

3. Multicore coding

To enable a specific core, use the function below:

#define CORE0_MBOX3_SET             0x4000008C

static void core_enable(uint32_t core, uint32_t addr)
{
    // http://www.raspberrypi.org/forums/viewtopic.php?f=72&t=98904&start=25
    volatile uint32_t *p;
    p = (uint32_t*)(CORE0_MBOX3_SET + 0x10 * core);

    *p = addr;
}

For example, to enable all CPU cores and make them start at address 0x8000:

core_enable(1, 0x8000);
core_enable(2, 0x8000);
core_enable(3, 0x8000);

Another nice function to have is get_core_id:

uint32_t get_core_id(void)
{
    uint32_t core_id;
    asm volatile ("mrc p15, 0, %0, c0, c0,  5" : "=r" (core_id));
    return core_id & 0x3;
}

With this function, the running code can detect on which CPU core it is executing. This is useful for a switch-case, like this for example:

volatile uint32_t core_id = get_core_id();

switch (core_id) {
case 0:
    // Code for Core 0
    core_enable(1, 0x8000);
    core_enable(2, 0x8000);
    core_enable(3, 0x8000);
    break;
case 1:
    // Code for Core 1
    break;
case 2:
    // Code for Core 2
    break;
case 3:
    // Code for Core 3
    break;
default:
    while (1) {}
    break;
}