January 21, 2025

Antminer S9 board - U-boot - plan B

cd /u1/Projects/OrangePi/Xulong/u-boot-orangepi
tar cvf /home/tom/ub.tar .
/u1/Projects/Zynq
mkdir u-boot-2020
ln -s u-boot-2020 u-boot
cd u-boot
tar xpvf /home/tom/ub.tar
rm -rf .git
cd /home/tom
rm ub.tar
I got rid of the ".git" directory since it traces back to the Xulong/sunxi site for the OrangePi and that has no relevance here. In fact it might be the worst possible thing if I got stupid and did a git fetch or update.

So now we are all set up and can get busy. I edit the Makefile and add:

CROSS_COMPILE = arm-none-eabi-
Then I do a "make distclean" which gets rid of my tags file.
make zynq_zybo_defconfig
  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/kconfig/conf.o
  YACC    scripts/kconfig/zconf.tab.c
  LEX     scripts/kconfig/zconf.lex.c
  HOSTCC  scripts/kconfig/zconf.tab.o
  HOSTLD  scripts/kconfig/conf
#
# configuration written to .config
#
Then away we go:
make
I get lots of warnings, but I suspect this has to do with the gcc version I now use having more warnings turned on by default. Most of the warnings are in "tools" and have to do with tools building lib/rsa/rsa-sign.c which uses the deprecated openssl/engine thing. This may be part of mkimage, but at any event, if it becomes an issue in the future I can figure out what to toss overboard.

The build is fairly fast and finishes without any serious complaint.
It ends like this:

  LD      spl/u-boot-spl
arm-none-eabi-ld.bfd: warning: u-boot-spl has a LOAD segment with RWX permissions
  OBJCOPY spl/u-boot-spl-nodtb.bin
  COPY    spl/u-boot-spl.dtb
  CAT     spl/u-boot-spl-dtb.bin
  COPY    spl/u-boot-spl.bin
  MKIMAGE spl/boot.bin
  MKIMAGE u-boot.img
  COPY    u-boot.dtb
  MKIMAGE u-boot-dtb.img
  LDS     u-boot-elf.lds
  LD      u-boot.elf
  CFGCHK  u-boot.cfg
The linker warning is a stupid thing that has no relevance for embedded code like this. I have notes elsewhere about how to make it go away. For a record, I repeat the build twice, as follows:
make clean
make &> build.log
make clean
make V=1 &> buildV.log
It is too much to resist. The build has generated spl/boot.bin which is an image with the zynq bootrom header. I can just put this onto my SD card and see what happens.
cd spl
boot.bin /run/media/tom/1936-F32A/BOOT.BIN
I do get serial output, but not at 115200 baud. I try a variety of baud rates, but none that my serial emulators offer do the job. For fun, I fire up my JTAG and do:
> halt
zynq.cpu0: MPIDR level2 0, cluster 0, core 0, multi core, no SMT
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x600001d3 pc: 0x000041c4
MMU: disabled, D-Cache: disabled, I-Cache: enabled
This is nice! The processor is not off in the weeds somewhere like it was with the "plan A" build from the xlnx sources. We ask openOCD to disassemble code in this area and we see:
0x000041c4  fffe eaff	b	#0x41c4
So we are parked in a spin loop, which is reasonable since the SPL should no be able to find a u-boot image to load and transfer too. Sanity is nice.

I disassemble the spl using:

cd spl
arm-none-eabi-objdump -marm -d u-boot-spl -z >elf.dis
The spin is inside a function named "hang", which also sounds reasonable. I can do this:
cd u-boot
make tags
vi -t hang
However this finds a definition of "hang()" in the examples directory. There are a myriad of calls to hang() in the source tree. When I look at my disassembly (elf.dis) I find one in "spl_boot_device()" another in board_init_r(), and another in __div0(). That is it!

Again when I use "vi -t" to try to find these symbols, it shows me the first one it finds, and I know there are many. I can use vim to look at the tags file myself:

spl_boot_device ./arch/arm/mach-zynq/spl.c
board_init_r    ./common/board_r.c
board_init_r    ./common/spl/spl.c
The code for spl_boot_device() in arch/arm/mach-zynq/spl.c is simple and interesting. It shows a switch on zynq_slcr_get_boot_mode() and the case for the SD card requires an option to be on:
CONFIG_SPL_MMC_SUPPORT
A peek at the zed_defconfig shows no such option either on or off. Without it, we end up in the default, which is:
default:
        puts("Unsupported boot mode selected\n");
        hang();
So, what about that baud rate? I don't see any baud rate getting set in any zynq defconfig files, so the place to look is the device tree.

Holy cow! Actual Antminer S9 support.

And here is a discovery as I look in the buildV.log. I see mention of:

arch/arm/dts/.bitmain-antminer-s9.dtb
This bears looking into. Indeed, there is a defconfig and a device tree
configs/bitmain_antminer_s9_defconfig
arch/arm/dts/bitmain-antminer-s9.dts
It has settings for the UART, but no baud rate. Also it does not set CONFIG_SPL_MMC_SUPPORT. It does set this:
CONFIG_DEFAULT_DEVICE_TREE="bitmain-antminer-s9"
I also peek at the u-boot-xlnx source tree, and it has this defconfig also. So even though they blended together all the xilinx boards, a simple build for the antminer is available in newer sources.

Start over

So, let's start over with this and rebuild:
make distclean
make bitmain_antminer_s9_defconfig
make
Like the zybo build, this gets warnings, but builds cleanly. We get a boot.bin, but considerably smaller than the Zybo. We get 53180 bytes instead of 81224 bytes. Onto an SD card it goes, and we get:
U-Boot SPL 2020.04 (Jan 21 2025 - 15:59:49 -0700)
mmc boot
Trying to boot from MMC1
spl_load_image_fat: error reading image u-boot.img, err - -2
SPL: failed to boot from all boot devices
### ERROR ### Please RESET the board ###
For fun, we go to JTAG and see:
> halt
zynq.cpu0: MPIDR level2 0, cluster 0, core 0, multi core, no SMT
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x600001d3 pc: 0x00002c38
MMU: disabled, D-Cache: disabled, I-Cache: enabled
This is again in "hang()"

Another pleasant surprise

The spl is looking on FAT for "u-boot.img". For whatever reason I did not expect this, but I should have. I expected actual U-boot to be contained within the BOOT.BIN file. This is much nicer. The build actually produced u-boot.img, so why not put that on the SD card and see what happens.
U-Boot SPL 2020.04 (Jan 21 2025 - 15:59:49 -0700)
mmc boot
Trying to boot from MMC1


U-Boot 2020.04 (Jan 21 2025 - 15:59:49 -0700)

Model: Bitmain Antminer S9 Board
DRAM:  ECC disabled 512 MiB
WDT:   Started without servicing (200s timeout)
NAND:  0 MiB
MMC:   mmc@e0100000: 0
Loading Environment from NAND... *** Warning - readenv() failed, using default environment

In:    serial@e0001000
Out:   serial@e0001000
Err:   serial@e0001000
Net:   ZYNQ GEM: e000b000, phyaddr 1, interface rgmii-id

Warning: ethernet@e000b000 (eth0) using random MAC address - 8a:40:2c:0e:57:bb
eth0: ethernet@e000b000
Hit any key to stop autoboot:  0
antminer>
So, I have my wish -- U-boot built from source and running from an SD card!

For fun, what does JTAG say about this?

Info : zynq.cpu1: hardware has 6 breakpoints, 4 watchpoints
Polling target zynq.cpu0 failed, trying to reexamine
Info : zynq.cpu0: hardware has 6 breakpoints, 4 watchpoints
> halt
target halted in ARM state due to debug-request, current mode: Supervisor
cpsr: 0x600001d3 pc: 0x00002c38
MMU: enabled, D-Cache: enabled, I-Cache: enabled
> reg
===== ARM registers
(0) r0 (/32): 0xffffffe2 (dirty)
(1) r1 (/32): 0x00000000 (dirty)
(2) r2 (/32): 0xe0001000
(3) r3 (/32): 0x00006802
(4) r4 (/32): 0x0000be6c
(5) r5 (/32): 0x001ffef4
(6) r6 (/32): 0x00000001
(7) r7 (/32): 0xdeadbeef
(8) r8 (/32): 0x0000be9c
(9) r9 (/32): 0x001fff30
(10) r10 (/32): 0x0000be6c
(11) r11 (/32): 0x001ffef0
(12) r12 (/32): 0x00000000
(13) sp_usr (/32)
(14) lr_usr (/32)
(15) pc (/32): 0x00002c38
(25) sp_svc (/32): 0x001ffed8
(26) lr_svc (/32): 0x00002c38
(31) cpsr (/32): 0x600001d3
(34) spsr_svc (/32): 0x00000000

An unsolved issue with JTAG

Why can't I set breakpoints? When I try, I get this:
bp 0x400
bp [
[] ['hw'|'hw_ctx']] rbp 'all' | address
It gives me "help" as though I typed something wrong. Well, actually if I parse all of those brackets, it would seem that it wants a "length". (Why would a breakpoint want a length?). But that is what it wants:
> bp 0x400 4
breakpoint set at 0x00000400
> bp
IVA breakpoint: 0x00000400, 0x4, 0x0f
I try all kinds of "length" numbers from 1 to 4096. It seems to take them all. It is even happy with 0.
Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org