August 27, 2018

Nanopi Fire3 and bl1-nanopi-m3

A fellow who calls himself "rafaello7" on Github has some interesting things related to the NanoPi M3 (which is also based on the s5p6818 like the Fire3). One of these is "bl1-nanopi-m3". I cloned this and found that just typing "make" built it nicely:
[tom@trona bl1-nanopi-m3]$ make
[compile....src/startup_aarch64.S]
[compile....src/aarch64_libs.S]
[compile....src/aarch64_exception_handler.c]
[compile....src/secondboot.c]
[compile....src/subcpu.c]
[compile....src/sleep.c]
[compile....src/resetcon.c]
[compile....src/GPIO.c]
[compile....src/CRC32.c]
[compile....src/SecureManager.c]
[compile....src/clockinit.c]
[compile....src/debug.c]
[compile....src/lib2ndboot.c]
[compile....src/buildinfo.c]
[compile....src/printf.c]
[compile....src/psci.c]
[compile....src/sysbus.c]
[compile....src/init_DDR3.c]
[compile....src/CRYPTO.c]
[compile....src/i2c_gpio.c]
[compile....src/pmic.c]
[compile....src/iUSBBOOT.c]
[compile....src/iSDHCBOOT.c]
[link.... out/bl1-nanopi.elf]
[binary.... out/bl1-nanopi.bin]
A quick at the LDS file shows that it links to run at 0xffff0000, just where you would want it to to be loaded by the on-chip bootrom. His comments say that this can be used to load U-Boot, and that might be a fine idea instead of using the fip-secure gadget that the linux setup uses. A quick peek at the final "bin" file shows that it has what looks like a proper NSIH header like the boot loader wants, so we could just try loading it with my usb_loader. The first time I try this, the transfer works, but I see no messages on the serial console or any evidence that anything at all has happened.
[root@trona out]# usb_loader bl1-nanopi.bin
Start transfer, size = 31264
Transfer successful

[root@trona out]# usb_loader bl1-nanopi.bin
Start transfer, size = 31264
USB bulk transfer failed
Download failed
Without resetting the board, I try loading it again (the second command above) and get the following on the serial console:
I2C_WriteByte nack returned
I2C Device Address Write Abitration Error
I2C_WriteByte nack returned
I2C Device Address Write Abitration Error
I2C_WriteByte nack returned
I2C Device Address Write Abitration Error
I2C_WriteByte nack returned
I2C Device Address Write Abitration Error
Wakeup Sub CPU 1234567
CPU Wakeup done! WFI is expected.
CPU0 is Master!

Card Identify Failure
Cannot Detect SDMMC
 Image Loading Failure Try to USB boot
Also I get these messages on my linux host logs:
Aug 27 16:05:59 trona kernel: usb 2-1.8: new high-speed USB device number 60 using ehci-pci
Aug 27 16:06:00 trona kernel: usb 2-1.8: New USB device found, idVendor=04e8, idProduct=1234, bcdDevice= 0.00
Aug 27 16:06:00 trona kernel: usb 2-1.8: New USB device strings: Mfr=0, Product=0, SerialNumber=0
If I try this a third and fourth time, I get the same kind of behavior (but now I am talking to this bl1 loader) however now messages like this appear for CPU 1 through 7. After a bit of thought, I find a way to fix this crazy business (see below).
Wakeup Sub CPU cpu 1 is not bringup, retry
cpu 1 is not bringup, retry
cpu 1 is not bringup, retry
cpu 1 is not bringup, retry
No doubt these processors are already running and trying to get them running a second time yields this result.

Fix the "start on second load" problem

My suspicion was that this was due to the size field being incorrect in the NSIH header. And indeed this was the case -- and I fixed this in my usb_loader program by calculating the correct value and placing it there, even for a verbatim download. What I suspect is this. This doesn't matter when booting this from and SD card. The firware believes the value in the NSIH header and reads that many bytes from the SD card, which is always possible, even if it reads extra rubbish. In the case of a USB transfer though, the transfer protocol provides a byte count when finished -- and apparently if this doesn't match the value in the header it does not start the thing running. Heaven only knows why it starts it the second time. At any rate, when I changed my download program to put a proper value in the header everything works as it should.

Lessons Learned

This loader runs in A64 mode, with a clever mode swith in the NSIH header better and better documented than what I found elsewhere.

The sources (18854 lines of them) provide all kinds of valuable and interesting information. They even have code to start up additional cores (although why a stage 2 boot loader needs or wants to do that is beyond me). A far more digestable source of information than paddling through the linux sources.

An even more interesting source of information is the prototype/module directory, which holds over 76,000 lines of source code.

This thing seems to use an NSIH header to download whatever comes next. And U-Boot itself could be whatever comes next, rather than the fip-secure thing that the standard linux boot sequence uses.


Have any comments? Questions? Drop me a line!

Tom's electronics pages / tom@mmto.org