Letux 400 Hardware

JtagFlash

You are looking at an old revision of the page JtagFlash. This revision was created by Lubomir Rintel.

Table of Content

Bad flash recovery using JTAG with a Raspberry Pi

Introduction

This short write-up will describe how do I connect to a Skytone Alpha 400 board (like the one in Letux 400) via JTAG and recover from botched flash.

I do use a OpenOCD's GPIO driver to bit-bang JTAG with a Raspberry Pi. Please note that it is probably not the smartest way to do this and certainly not the only one but works well enough using hardware you may already have handy.

Wiring the hardware

The JTAG is either accessible from the fine pitch 24-pin flat cable connector J500 on the bottom of the board (the cable can be connected via the battery compartment) or from a set of test pads no the top of the board.

The test pads are quite large and easy to solder to. I've chosen to do that because I don't have a correct cable or a breakout.

See the details in schematics:

I've wired the JTAG pins to a rather arbitrarily chosen GPIO pins on a Raspberry Pi like this:

                                             __________
                                                   _   |
                            ^ edge of the RPi ^   (_)  |
                                                       |
                                     3v3 Power  1 o o 2  5v Power
                             (I2C1 SDA) GPIO 2  3 o o 4  5v Power
                             (I2C1 SCL) GPIO 3  5 o o 6  Ground
                               (GPCLK0) GPIO 4  7 o o 8  GPIO 14 (UART TX)
                                        Ground  9 o o 10 GPIO 15 (UART RX)
                                       GPIO 17 11 o o 12 GPIO 18 (PCM CLK)
                                       GPIO 27 13 o o 14 Ground
                                       GPIO 22 15 o o 16 GPIO 23
                                     3v3 Power 17 o o 18 GPIO 24
J500/9 or TP516 <--[TCK]-- (SPI0 MOSI) GPIO 10 19 o o 20 Ground -----------> Well, some ground somewhere
J500/7 or TP514 <--[TMS]-- (SPI0 MISO) GPIO  9 21 o o 22 GPIO 25 -------------[TDO]---> TP517 or J500/10
J500/8 or TP515 <--[TDI]-- (SPI0 SCLK) GPIO 11 23 o o 24 GPIO  8 (SPI0 CE0) --[TRST]--> TP513 or J500/6
                                        Ground 25 o o 26 GPIO  7 (SPI0 CE1)
                          (EEPROM SDA) GPIO  0 27 o o 28 GPIO  1 (EEPROM SCL)
                                       GPIO  5 29 o o 30 Ground
                                       GPIO  6 31 o o 32 GPIO 12 (PWM0)
                                (PWM1) GPIO 13 33 o o 34 Ground
                              (PCM FS) GPIO 19 35 o o 36 GPIO 16
                                       GPIO 26 37 o o 38 GPIO 20 (PCM DIN)
                                        Ground 39 o o 40 GPIO 21 (PCM DOUT)
                                                   _   |
                         v  ethernet/usb ports v  (_)  |
                                                       |
                                                       |

Pin names courtesy of https://pinout.xyz/.

Make sure to also connect the ground. None of the test pads is ground, so I chose to connect the pin from the UART port.

Build OpenOCD

Get the OpenOCD fork with JZ4730 support. Effort is underway to merge this into mainline, but we're not there yet.

$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/lkundrak/openocd-jz4730.git
$ cd openocd-jz4730
$ git checkout lr/jz4730
$

Configure and build OpenOCD. Unfortuntately, I lost track of which dependencies and configure options are needed. If someone finds out, please add it here. I suppose you need to enable linux-gpiod support at the very least:

$ ./configure --enable-linuxgpiod
$ make
$ sudo make install
$

Once it's installed you also need a configuration file. Here's what I use for the wiring above:

$ cat >openocd.cfg <<EOF
adapter driver linuxgpiod
transport select jtag
linuxgpiod_gpiochip 0
linuxgpiod_tck_num 10
linuxgpiod_tms_num 9
linuxgpiod_tdo_num 25
linuxgpiod_tdi_num 11
linuxgpiod_trst_num 8

source [find board/skytone_alpha400.cfg]
EOF

If you wish to telnet to the Raspberry Pi remotely, like I do, add a "bindto 0.0.0.0" line.

At this point it is a good idea that your setup works. Power on the board, start OpenOCD and leave it running. You can either start it as root, or add yourself to the gpio group.

$ openocd -f openocd.cfg
Open On-Chip Debugger 0.10.0+dev-01412-gbb09a0eb2-dirty (2020-09-26-12:54)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : Linux GPIOD JTAG/SWD bitbang driver
Info : This adapter doesn't support configurable speed
Info : JTAG tap: jz4730.cpu tap/device found: 0x0000024f (mfg: 0x127 (MIPS Technologies), part: 0x0000, ver: 0x0)
Info : starting gdb server for jz4730.cpu on 3333
Info : Listening on port 3333 for gdb connections
Info : accepting 'telnet' connection on tcp/4444

Connect to OpenOCD from another terminal and check that things work:

$ telnet localhost 4444
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> reset
JTAG tap: jz4730.cpu tap/device found: 0x0000024f (mfg: 0x127 (MIPS Technologies), part: 0x0000, ver: 0x0)
> halt
Failed to enter Debug Mode!
MIPS32 only implemented
target halted in MIPS32 mode due to debug-request, pc: 0x800191dc
> nand probe 0
NAND flash device 'NAND 1GiB 3.3V 8-bit (Samsung)' found
>

If they don't then tough luck I guess.

Build U-Boot

$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/lkundrak/u-boot.git u-boot-jz4740
$ git checkout lr/alpha400
$ make alpha400_nand_defconfig
$ make CROSS_COMPILE=mips64-linux-gnu-
  CAT     u-boot-with-spl.bin
  CFGCHK  u-boot.cfg
$

Recovering the NAND boot loader

One thing that you need to realize first: things are super-slow especially if you're dicking around with Raspberry Pi GPIO bit-banging. They may be faster if you use a reasonable JTAG dongle instead, like a grown-up man. Please let me know if you try being one.

This means that you won't be recovering the whole NAND via JTAG, merely the boot loader so that you can boot from the SD card.

A typical image with U-Boot and SPL (and quite some useless padding which is convenient to ignore) will weight a little over 600K and will take a little under 2 and a half our to copy.

Erase the first meg where the boot loader would go:

> nand erase 0 0 0x100000
erased blocks 0 to 7 on NAND flash device #0 'NAND 1GiB 3.3V 8-bit'
>

The erase block size is 128K (0x20000), so you need to erase in the multiplies of 128K. The first erase block is the 4K of NAND SPL followed by padding (the other 124K). Then goes the U-Boot proper.

The u-boot-with-spl.bin image contains just that: SPL, padding and U-Boot:

> nand write 0 u-boot-with-spl.bin 0
wrote file u-boot-with-spl.bin to NAND flash 0 up to offset 0x00099800 in 7082.249512s (0.086 KiB/s)
>

Very lovely.

> reboot
>

Or push and hold the power button and then power-on again.

Recovering the rest

TODO: Write this up.

Generally you'll want to spin put the Letux 400 Debian image and use mtd-utils to erase and write the kernel and main partition.

Some random notes

It is possible to render JTAG inaccessible with software; e.g. by powering down the processor, changing the JTAG pin function or perhaps crashing the processor in some peculiar way. If you ruin your boot block in a way that ends up disabling JTAG you can still recover with a bit of efrort.

When the machine powers up, it executes the internal boot ROM that fetches the first 4K of NAND into the L1 caches. This is hardwired in the processor and you can't ruin it. The NAND read takes some short time and you can attach JTAG during this time.

Just power-on the machine and run "reset; halt" about a second or so afterwards. If you're lucky the CPU will manage to halt running instructions in the 0xbfc00000 range (where the ROM is mapped). This requires some luck, but if you try hard enough you'll eventually succeed.

Or not.

Created: 4 years 5 months ago
by Lubomir Rintel

Updated: 4 years 5 months ago
by Lubomir Rintel

Old Revisions