Oct 11, 2017

Hacking the Raspberry Pi Boot

The downloadable Rasbian image does not come with U-Boot (the most popular embedded system boot loader), yet can clearly boot Linux.  But since the Pi's 2nd stage boot loader is closed source, booting Pi with U-Boot allows me to perform non-standard boot actions (like exposing the RPi's JTAG pins).

How does the RPi boot?

An ARM booting is very different than the Intel/AMD system (BIOS or UEFI).  RPi's 1st stage bootloader is on-chip, and looks for the file bootcode.bin in the boot partition:

pi@raspberrypi:~ $ mount
/dev/mmcblk0p1 on /boot type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,errors=remount-ro)

pi@raspberrypi:~ $ ls -gh /boot/bootcode.bin 
-rwxr-xr-x 1 root 50K Jul  3 10:07 /boot/bootcode.bin

The 2nd stage bootloader runs on RPi's GPU (also on-chip), and requires the start_<device>.elf executables, also in /boot partition:

-rwxr-xr-x 1 root 645K Jul  3 14:07 start_cd.elf
-rwxr-xr-x 1 root 4.8M Jul  3 14:07 start_db.elf
-rwxr-xr-x 1 root 2.8M Jul  3 14:07 start.elf
-rwxr-xr-x 1 root 3.8M Jul  3 14:07 start_x.elf

A headless system will only have start.elf.  The 3rd stage bootloader (also running on the GPU) is currently booting straight into Linux, using the kernel.img and the DTB (device tree blob) files (also in /boot):

-rwxr-xr-x 1 root  18K May 15 19:09 bcm2708-rpi-3-b.dtb
-rwxr-xr-x 1 root 4.4M Jul  3 10:07 kernel7.img # for >= RPi2
-rwxr-xr-x 1 root 4.2M Jul  3 10:07 kernel.img # All other RPi

The RPi boot loader running on the GPU reads config.txt (also in /boot) for boot options, including which Linux kernel to load.  There is no "kernel" line in the config.txt right after a fresh install, so the boot loader defaults to  it loads the highest numbered kernel<num>.img.  Since we have a working system but want a boot loader capable of booting multiple OS, we should point the RPi bootloader to U-Boot image instead of the kernel<num>.img.  [other people seem to prefer renaming u-boot.bin to kernel8.img, taking advantage of the boot loader's search for the highest numbered kernel<num>.img.]

While booting the kernel, the RPi bootloader feeds the content of the file /boot/cmdline.txt to the kernel, but now I need U-Boot to do that.  When you view this file, it can get overwhelming, but just note it down somewhere for now, so you can punch it into U-Boot down below.

Let's first back up this known working /boot partition to the development before messing with it.

Cross compiler toolchain for RPi

Remember throughout this article that the RPi is the target and my 64-bit Ubuntu 16.04 is the development host, which also implies that I am cross compiling the RPi's programs (starting with the bootloader) on the host, using a toolchain graciously provided by the Raspberry Pi folks on gihub.  To clone the git repo:

parallels@ubuntu:$ git clone https://github.com/raspberrypi/tools

The tools are in the directory arm-bcm2708

$ ls arm-bcm2708/
arm-bcm2708hardfp-linux-gnueabi  gcc-linaro-arm-linux-gnueabihf-raspbian
arm-bcm2708-linux-gnueabi        gcc-linaro-arm-linux-gnueabihf-raspbian-x64
arm-rpi-4.9.3-linux-gnueabihf


I decided to use the Linaro toolchain, because it is popular among embedded developers.  Note that the 32-bit version of the toolchain will not even run on a 64-bit host (that's pretty much all PCs these days).  I need to put the toolchain's bin/ folder in $PATH, by adding the following line at the end of my ~/.profile, like this:

PATH="$HOME/rpi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin:$HOME/bin:$HOME/.local/bin:$PATH"

[If using .profile, you have to logout and log back in for the change to take effect.]

In the toolchain's bin folder, there are a whole bunch of executables, like this:

~/rpi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin$ ls
arm-linux-gnueabihf-addr2line     arm-linux-gnueabihf-gfortran
...


To build a either the kernel or U-Boot, an environment variable called CROSS_COMPILE is necessary, as a prefix for the tool it should run.  In the above case, that prefix is arm-linux-gnueabihf-, which I hard code in my .profile again.

Building U-Boot for RPi3

I clone the latest U-Boot repo:

$ git clone git://git.denx.de/u-boot.git

In the repo's configs/ folder, there are 4 RPi board configs:

~/rpi/u-boot$ ls configs/*rpi*
configs/rpi_2_defconfig      configs/rpi_3_defconfig
configs/rpi_3_32b_defconfig  configs/rpi_defconfig

These are the predefined U-Boot configs.  Without understanding the details of the config, I will try using the 32b version for now.  Remembering that I now have the environment variable CROSS_COMPILE, I seed this .config file from this defconfig:

~/rpi/u-boot$ make rpi_3_defconfig
  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/kconfig/conf.o
  HOSTCC  scripts/kconfig/zconf.tab.o
  HOSTLD  scripts/kconfig/conf
#
# configuration written to .config
#


And then build the U-Boot binary itself with

~/rpi/u-boot$ make

If all goes well, you should see and the ELF binary (with symbols) and the stripped (without symbol) in the root folder, like this:

-rwxrwxr-x   1 parallels 2.2M Oct  1 12:00 u-boot
-rw-rw-r--   1 parallels 372K Oct  1 12:00 u-boot.bin


Copy u-boot.bin to RPi's /boot folder.

To cause RPi boot loader to choose U-Boot instead of the kernel, just add a new line in the config.txt:

kernel=u-boot.bin

Overriding what the GPU boots this way (as supposed to changing the file that the GPU looks for) offers the possibility of backing out easily using the recovery method (which lets you modify the config.txt)--IF you are running the NOOBS install.  Also enable UART in config.txt, for the debugging session to begin shortly below.

enable_uart=1

U-Boot boots kernel7.img

When I reboot RPi with the HDMI monitor and keyboard connected, I see the U-Boot screen on the monitor with this message:

U-Boot 2017.09-00351-g7eefa35-dirty (Oct 11 2017 - 21:25:18 -0700)

DRAM:  896 MiB
RPI 3 Model B (0xa22082)
MMC:   sdhci@7e300000: 0
...
Hit any key to stop autoboot:  0
Scanning mmc 0:1...

Note that the memory available to the CPU is 128 MB shy of 512 MB DRAM on board, because I gave 128 MB to the GPU (in /boot/config.txt).

Anyway it's clearly not booting to Linux, so I reboot and  hit the Enter key to halt the U-Boot, and I am left with the U-Boot console:

U-Boot>

The next step is to configure U-Boot to load the kernel image already on /boot: kernel.img.  Load the image and the DTB file, and give those to the bootz command in the mmc_boot command, as you can see below.  [Note that "mmc 0:1" is pointing to the 2nd partition on the SD card--which is NOT the /boot partition for the NOOBS install (in which case it is the 0:6 partition).]

U-Boot> setenv fdtfile bcm2708-rpi-3-b.dtb
U-Boot> setenv bootcmd_mmc0 fatload mmc 0:1 ${kernel_addr_r} kernel7.img\;fatload mmc 0:1 ${fdt_addr} ${fdtfile}\;bootz ${kernel_addr_r} - ${fdt_addr}
This works because the default boot command--bootcmd--points to mmc_boot, as you can see in the boot command chain below:

U-Boot> printenv bootcmd
bootcmd=run distro_bootcmd

The distro_bootcmd, in turn, is a for loop, going through different boot hardware:

U-Boot> printenv distro_bootcmd
distro_bootcmd=for target in $boot_targets}; do run bootcmd_${target}; done

And the RPi3 config file set up multiple boot devices:

U-Boot> printenv boot_targets
boot_targets=mmc0 usb0 pxe dhcp

The kernel needs bootargs: the content of /boot/cmdline.txt that I saved away earlier.  In U-Boot, you do that through an environment called bootargs.  Because it is many lines long, it is easy to make a typo when creating this environment variable; so I do it in bite-sized chunks:

U-Boot> setenv rootargs "root=/dev/mmcblk0p2 rootfstype=ext4"
U-Boot> setenv fbargs "bcm2708_fb.fbwidth=1824 bcm2708_fb.fbheight=984 bcm2708_fb.fbswap=1"
U-Boot> setenv vcmemargs "vc_mem.mem_base=0x3ec00000 vc_mem.mem_size=0x40000000"
U-Boot> setenv miscargs "dwc_otg.lpm_enable=0 elevator=deadline fsck.repair=yes console=serial0,115200"
U-Boot> setenv bootargs ${rootargs} ${fbargs} ${miscargs}
${vcmemargs}

Note that I changed the rootfs device from a UUID to a more generic "2nd partition on the mmc device 0", to be more generic.  I found that for a NOOBS install (vs. a straight Rasbian imaging as I did), the ext4 partition is the 6th partition is the 6th partition, so you can adjust it to mmcblk0p6 above.

I save the configuration change to the U-Boot environment file (persisted in /boot) before rebooting.

U-Boot> saveenv
U-Boot> boot

After a few seconds, I see that RPi3 is starting to boot Linux, and then voilĂ : I am back to the Rasbian desktop!  I save the resulting /boot/uboot.env file for safe keeping.  Since I want to start the FW before booting Linux, I studied U-Boot's standalone examples.

From (https://dius.com.au/2015/08/19/raspberry-pi-uboot/), I learned that I could get the RPi bootloader to do all the heavy lifting of creating a merged DTB and putting it at the address specified in config.txt--for the device_tree_address line. The default U-Boot ${fdt_addr} is 0x2effb600, so I just added the following line to /boot/config.txt:

device_tree_address=0x2effb600
kernel=u-boot.bin

U-Boot Hello World example

According to U-Boot documentation, cache coherence problem can be worked around by having U-Boot build system package up the application binary into a U-Boot image (RPi's kernel.img I've been working with above is one such example).  U-Boot already builds a stand-alone hello_world example (examples/standalone), whose start address is defined in arch/arm/config.mk:

CONFIG_STANDALONE_LOAD_ADDR = 0xc100000

I can verify this by reading the ELF produced by the build.

parallels@ubuntu:~/rpi/u-boot/examples/standalone$ ${CROSS_COMPILE}readelf hello_world -h
...

  Entry point address:               0xc100000

I can copy the build output (hello_world.bin) to the SD card's /boot partition, and run it in U-Boot shell (note that my /boot partition on the SD card is partition #1 on device #0):

U-Boot> fatload mmc 0:1 0xc100000 hello_world.bin
U-Boot>go 0xc100000 Hello world
## Starting application at 0x0C100000 ...
0xc100000
arg[1] = Hello
arg[2] = world
arg[3] = ""
## Application terminated, rc = 0x0

This shows that a stand-alone application can control low level peripheral.

Aside: cache problem

On the U-Boot main website's documentation page (as well as the README at the top of the U-Boot repo) there is some discussion about cache coherence problem because U-Boot runs all stand alone code with cache disabled.  Supposedly, the workaround is to use the "bootm" script , which requires coaxing the U-Boot build system to produce a U-Boot image for this, I can copy the resulting file to the SD card.

~/rpi/u-boot/examples/standalone$ ../../tools/mkimage -A arm -O u-boot -T standalone -C none -a 0xc100000 -d hello_world.bin -v hello_world.img
Adding Image hello_world.bin
Image Name:  
Created:      Sat Oct  7 19:33:34 2017
Image Type:   ARM U-Boot Standalone Program (uncompressed)
Data Size:    630 Bytes = 0.62 KiB = 0.00 MiB
Load Address: 0c100000
Entry Point:  0c100000


But this did not work, because U-Boot rejects it as an invalid kernel image.

Modifying the hello_world example to toggle a GPIO line

Printing a string to console is nice, but controlling GPIO lines or SPI would be more practical for embedded applications.  In an industrial application, an RPi system can signal that it is about to boot the Linux kernel by bouncing a GPIO line, or sending out a SPI/I2C packet.  Let's say I want to toggle the RPi3 pin J8.15 right before booting the kernel.  On the bcm2835~7 SoC, GPIO22 drives that J8.15 pin, as the command  "gpio readall" (available in out-of-the-box Rasbian) shows (I yellow-highlighted it for you):

pi@raspberrypi:~ $ gpio readall
 +-----+-----+---------+------+---+---Pi 3---+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 |     |     |    3.3v |      |   |  1 || 2  |   |      | 5v      |     |     |
 |   2 |   8 |   SDA.1 |   IN | 1 |  3 || 4  |   |      | 5v      |     |     |
 |   3 |   9 |   SCL.1 |   IN | 1 |  5 || 6  |   |      | 0v      |     |     |
 |   4 |   7 |
JTAG_05 |   IN | 1 |  7 || 8  | 1 | ALT5 | TxD     | 15  | 14  |
 |     |     |      0v |      |   |  9 || 10 | 1 | ALT5 | RxD     | 16  | 15  |
 |  17 |   0 | GPIO. 0 |   IN | 0 | 11 || 12 | 0 | IN   | GPIO. 1 | 1   | 18  |
 |  27 |   2 | JTAG_07 |   IN | 0 | 13 || 14 |   |      | 0v      |     |     |
 |  22 |   3 | JTAG_03 |   IN | 0 | 15 || 16 | 0 | IN   | JTAG_11 | 4   | 23  |
 |     |     |    3.3v |      |   | 17 || 18 | 0 | IN   | JTAG_13 | 5   | 24  |
 |  10 |  12 |    MOSI |   IN | 0 | 19 || 20 |   |      | 0v      |     |     |
 |   9 |  13 |    MISO |   IN | 0 | 21 || 22 | 0 | IN   | JTAG_09 | 6   | 25  |
 |  11 |  14 |    SCLK |   IN | 0 | 23 || 24 | 1 | IN   | CE0     | 10  | 8   |
 |     |     |      0v |      |   | 25 || 26 | 1 | IN   | CE1     | 11  | 7   |
 |   0 |  30 |   SDA.0 |   IN | 1 | 27 || 28 | 1 | IN   | SCL.0   | 31  | 1   |
 |   5 |  21 | GPIO.21 |   IN | 1 | 29 || 30 |   |      | 0v      |     |     |
 |   6 |  22 | GPIO.22 |   IN | 1 | 31 || 32 | 0 | IN   | GPIO.26 | 26  | 12  |
 |  13 |  23 | GPIO.23 |   IN | 0 | 33 || 34 |   |      | 0v      |     |     |
 |  19 |  24 | GPIO.24 |   IN | 0 | 35 || 36 | 0 | IN   | GPIO.27 | 27  | 16  |
 |  26 |  25 | JTAG_05 |   IN | 0 | 37 || 38 | 0 | IN   | GPIO.28 | 28  | 20  |
 |     |     |      0v |      |   | 39 || 40 | 0 | IN   | GPIO.29 | 29  | 21  |


To bounce a specified GPIO line, I can modify the hello_world program (I can create another stand-alone project, but I am feeling lazy) like this:

/* see BMC2835 peripheral datasheet p.92, downloadable from RPi website */
#define GPIO_ALT_FUNCTION_IN  0x0
#define GPIO_ALT_FUNCTION_OUT 0x1
#define GPIO_ALT_FUNCTION_0   0x4
#define GPIO_ALT_FUNCTION_1   0x5
#define GPIO_ALT_FUNCTION_2   0x6
#define GPIO_ALT_FUNCTION_3   0x7
#define GPIO_ALT_FUNCTION_4   0x3
#define GPIO_ALT_FUNCTION_5   0x2

/* from dwelch67's bare metal project */
#define BCM2708_PERI_BASE            0x3f000000
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000)

__attribute__((always_inline)) static inline void GPIOOutSet(int GPIO)
{
    volatile uint32_t* GPIO_SET = (volatile uint32_t*)(GPIO_BASE + 0x1C);
    GPIO_SET[GPIO >= 32] |= 1 << (GPIO & 0x1F);
}
__attribute__((always_inline)) static inline void GPIOOutClear(int GPIO)
{
    volatile uint32_t* GPIO_CLR = (volatile uint32_t*)(GPIO_BASE + 0x28);
    GPIO_CLR[GPIO >= 32] |= 1 << (GPIO & 0x1F);
}

/* Have to forward declare because whatever text that appears at the beginning
 * is put at the entry point of the stand alone app.
 */
static void GPIOFunction(int GPIO, int functionCode);

int hello_world (int argc, char * const argv[])
{
    app_startup(argv);
    if (strcmp(argv[1], "gpio") == 0) {
        if (argc < 3) {
            printf("which pin? ");
            return 0;
        }
        unsigned pin = 10 * (argv[2][0] - '0') /* simpler than sscanf */
            + (argv[2][1] - '0');
        printf("%d\n", pin);
        GPIOFunction(pin, GPIO_ALT_FUNCTION_OUT);
        GPIOOutSet(pin); GPIOOutClear(pin);
    }
    return (0);
}

static unsigned _divide(unsigned n, unsigned d) {
    unsigned q = 0;
    while (n >= d) {
        ++q;
        n -= d;
    }
    return q;
}

static void GPIOFunction(int GPIO, int functionCode)
{
    int registerIndex = _divide(GPIO, 10);
    int bit = (GPIO - 10 * registerIndex) * 3;
    volatile uint32_t* GPIO_FSEL = (volatile uint32_t*)(GPIO_BASE + 0);
    uint32_t oldValue = GPIO_FSEL[registerIndex];
    uint32_t mask = 0b111 << bit;
    GPIO_FSEL[registerIndex] = (oldValue & ~mask) /* don't touch others */
                            | ((functionCode << bit) & mask);
}


As you can see, it's a complete rewrite of the hello world stand alone application.  But U-Boot's make system will dutifully produce a hello_world.bin with correct entry point.

parallels@ubuntu:~/rpi/u-boot$ ${CROSS_COMPILE}readelf examples/standalone/hello_world -h
...
  Entry point address:               0xc100000
  Start of program headers:          52 (bytes into file)


I then copied hello_world.bin to the SD card's /boot and tried it out in U-Boot command line:

U-Boot> fatload mmc 0:1 0xc100000 hello_world.bin
U-Boot> go 0xc100000 gpio 22

This is what saw in logic analyzer connected to the UART TX (J8.8) and J8.15:
UART TX is busy printing the printf statements, but the ~150 ns wide impulse is the GPIO bounce I wanted.

Enabling JTAG debugging on RPi3

Now that I can control the GPIO peripheral before booting the kernel, another cool thing to do is turn on the JTAG.  On p. 102 of the CM2835 peripheral datasheet mentioned above, thre is a table of GPIO alternative functions.  On the ALT4 column, GPIO22~26 are the ARM JTAG pins.  I configure these pins for JTAG using a similar code as above.

} else if (strcmp(argv[1], "jtag") == 0) {
    printf ("Remapping GPIO to JTAG ...\n");
    GPIOFunction(22, GPIO_ALT_FUNCTION_4);//TRST: JTAG 3
    GPIOFunction(4, GPIO_ALT_FUNCTION_5);//TDI : JTAG 5
    GPIOFunction(24, GPIO_ALT_FUNCTION_4);//TMS : JTAG 7
    GPIOFunction(25, GPIO_ALT_FUNCTION_4);//TCK : JTAG 9

    //Don't need: RPi doesn't "return" CLK
    //GPIOFunction(26, GPIO_ALT_FUNCTION_4);//RTCK: JTAG 11
    GPIOFunction(27, GPIO_ALT_FUNCTION_4);//TDO : JTAG 13
    if (argc > 2 && strcmp(argv[2], "wait") == 0) {
        printf ("Waiting ...\n");
        while (!tstc());
        (void) getc();
    }
}


Now I need to find these pins on the J8 header.  I marked them with a gray highlighter above.  I use SEGGER J-Link, and the JTAG pin definitions are listed in the 20-pin J-Link connector section of the J-Link manual. When I run JLinkGDBServer, I see the this error:

parallels@ubuntu:~$ JLinkGDBServer -device cortex-a7
...
------Target related settings------
Target device:                 cortex-a7
Target interface:              JTAG
Target interface speed:        1000kHz
Target endian:                 little
...
Target voltage: 3.31 V
Listening on TCP/IP port 2331
Connecting to target...ERROR: Cortex-A/R-JTAG (connect): Could not determine address of core debug registers. Incorrect CoreSight ROM table in device?
ERROR: Could not connect to target.
Target connection failed. GDBServer will be closed...Restoring target state and closing J-Link connection...
Shutting down...
Could not connect to target.
Please check power, connection and settings.


When I look at TDO (which is driven from from RPi), I see that the target is responding , as you  can see here.

JLinkExe fails to find core debug registers

JLinkExe can even get some information out of the target as well

Connecting to target via JTAG
TotalIRLen = 4, IRPrint = 0x01
JTAG chain detection found 1 devices:
 #0 Id: 0x4BA00477, IRLen: 04, CoreSight JTAG-DP
ARM AP[0]: 0x24770002, APB-AP
ROMTbl[0][0]: CompAddr: 80010000 CID: B105900D, PID:04-004BBD03
ROMTbl[0][1]: CompAddr: 80011000 CID: B105900D, PID:04-004BB9D3
ROMTbl[0][2]: CompAddr: 80012000 CID: B105900D, PID:04-004BBD03
ROMTbl[0][3]: CompAddr: 80013000 CID: B105900D, PID:04-004BB9D3
ROMTbl[0][4]: CompAddr: 80014000 CID: B105900D, PID:04-004BBD03
ROMTbl[0][5]: CompAddr: 80015000 CID: B105900D, PID:04-004BB9D3
ROMTbl[0][6]: CompAddr: 80016000 CID: B105900D, PID:04-004BBD03
ROMTbl[0][7]: CompAddr: 80017000 CID: B105900D, PID:04-004BB9D3
TotalIRLen = 4, IRPrint = 0x01
JTAG chain detection found 1 devices:
 #0 Id: 0x4BA00477, IRLen: 04, CoreSight JTAG-DP

****** Error: Cortex-A/R-JTAG (connect): Could not determine address of core debug registers. Incorrect CoreSight ROM table in device?
TotalIRLen = 4, IRPrint = 0x01
JTAG chain detection found 1 devices:
 #0 Id: 0x4BA00477, IRLen: 04, CoreSight JTAG-DP
TotalIRLen = 4, IRPrint = 0x01
JTAG chain detection found 1 devices:
 #0 Id: 0x4BA00477, IRLen: 04, CoreSight JTAG-DP
Cannot connect to target.


I then tried OpenOCD instead.

OpenOCD cannot connect either

OpenOCD does its own thing, but it can also get some response from RPi as well.

$ openocd -f /usr/share/openocd/scripts/interface/jlink.cfg -f ~/rpi/openocd/rpi3.cfg
Open On-Chip Debugger 0.9.0 (2015-09-02-10:42)
Licensed under GNU GPL v2
For bug reports, read
    http://openocd.org/doc/doxygen/bugs.html
adapter speed: 1000 kHz
adapter_nsrst_delay: 400
none separate
Info : auto-selecting first available session transport "jtag". To override use 'transport select <transport>'.
Info : J-Link ARM V8 compiled Nov 28 2014 13:44:46
Info : J-Link caps 0xb9ff7bbf
Info : J-Link hw version 80000
Info : J-Link hw type J-Link
Info : J-Link max mem block 9224
Info : J-Link configuration
Info : USB-Address: 0x0
Info : Kickstart power on JTAG-pin 19: 0xffffffff
Info : Vref = 3.306 TCK = 1 TDI = 0 TDO = 1 TMS = 0 SRST = 1 TRST = 1
Info : J-Link JTAG Interface ready
Info : clock speed 1000 kHz
Info : JTAG tap: rspi.arm tap/device found: 0x4ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x4)
Warn : JTAG tap: rspi.arm       UNEXPECTED: 0x4ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x4)
Error: JTAG tap: rspi.arm  expected 1 of 1: 0x07b7617f (mfg: 0x0bf, part: 0x7b76, ver: 0x0)
Error: Trying to use configured scan chain anyway...
Warn : Bypassing JTAG setup events due to errors
Error: 'arm11 target' JTAG error SCREG OUT 0x00
Error: unexpected ARM11 ID code


It seems that JTAG pin mapping works, but the client side tools don't play well with RPi3.  I will come back after getting a response back from SEGGER.