June 27, 2024

Antminer S9 board - building the FSBL

I made a massive project out of extracting and rearranging the FSBL sources to suit my preferences. I get a clean build, but I have never actually tested it!

I want to build it again with two changes. One is that I want it to print out my name and identification. Not that I am eager to make myself famous, but I want to avoid confusion about what FSBL is actually running.

The other change is that I want to include the NAND driver. The build "out of the box" does not include NAND support.

cd /u1/Projects/Zynq/Git_zynq/fsbl
cd fsbl
vi main.c
I add a line like so:
fsbl_printf(DEBUG_GENERAL,"\n\rXilinx First Stage Boot Loader \n\r");
fsbl_printf(DEBUG_GENERAL,"Tom Trebisky  6-27-2024\n\r");

Adding NAND support

We obtained sources for a Zedboard build. Zed has Qspi, not NAND flash on board, so it did not include a NAND driver. Among other things, we need to add definitions for these things to include/xparameters.h
XPAR_PS7_NAND_0_BASEADDR
XPAR_XNANDPS_0_FLASHBASE
We can define either of these and it will trigger code in fsbl/nand.c to add the support we want. The way the original package handled this was that in the misc/zed directory was a file "drivers.txt" with lines like:
emacps
gpiops
qspips
Here the line "qspips" hauled in the Qspi driver. In that same directory, there was also a file "xparameters.h" that would have the lines we want. For the Qspi driver it had these:
/* Definitions for driver QSPIPS */
#define XPAR_XQSPIPS_NUM_INSTANCES 1

/* Definitions for peripheral PS7_QSPI_0 */
#define XPAR_PS7_QSPI_0_DEVICE_ID 0
#define XPAR_PS7_QSPI_0_BASEADDR 0xE000D000
#define XPAR_PS7_QSPI_0_HIGHADDR 0xE000DFFF
#define XPAR_PS7_QSPI_0_QSPI_CLK_FREQ_HZ 200000000
#define XPAR_PS7_QSPI_0_QSPI_MODE 0
#define XPAR_PS7_QSPI_0_QSPI_BUS_WIDTH 2

/* Canonical definitions for peripheral PS7_QSPI_0 */
#define XPAR_XQSPIPS_0_DEVICE_ID XPAR_PS7_QSPI_0_DEVICE_ID
#define XPAR_XQSPIPS_0_BASEADDR 0xE000D000
#define XPAR_XQSPIPS_0_HIGHADDR 0xE000DFFF
#define XPAR_XQSPIPS_0_QSPI_CLK_FREQ_HZ 200000000
#define XPAR_XQSPIPS_0_QSPI_MODE 0
#define XPAR_XQSPIPS_0_QSPI_BUS_WIDTH 2
A search through the entire "embeddedsw" collection fails to turn up a nice example of what might be required for the NAND driver. This being the case, we are faced with making a study of the NAND driver we find in "embeddedsw/XilinxProcessorIPLib/drivers/nandps".

Note that there is also a directory "nandpsu". A comment in xnandpsu.h lets us know that his is clearly nothing of interest to us.

"a driver to support Arasan NAND controller present in Zynq Ultrascale Mp"
Looking at the driver in "nandps", I see these references to XPAR stuff:
xnandps_g.c:XNandPs_Config XNandPs_ConfigTable[XPAR_XNANDPS_NUM_INSTANCES] = {
xnandps_g.c:		XPAR_XNANDPS_0_DEVICE_ID,
xnandps_g.c:		XPAR_XPARPORTPS_CTRL_BASEADDR,	/**< SMC Base address
xnandps_g.c:		XPAR_XNANDPS_0_BASEADDR,	/**< NAND flash Base address
xnandps_g.c:		XPAR_XNANDPS_0_FLASH_WIDTH	/**< Flash data width */
xnandps_sinit.c:	for (Index = 0; Index < XPAR_XNANDPS_NUM_INSTANCES; Index++) {
Let's just roll up our sleeves and dig in. We want:
#define	XPAR_XNANDPS_NUM_INSTANCES	1
#define XPAR_XNANDPS_0_DEVICE_ID	0

#define XPAR_XPARPORTPS_CTRL_BASEADDR		0xE000E000
#define XPAR_XNANDPS_0_BASEADDR			0xE1000000
#define XPAR_XNANDPS_0_FLASH_WIDTH		8

#define XPAR_PS7_NAND_0_BASEADDR		0xE1000000
Note that none of this provided either of the following "triggers", so I added the last line just for that purpose
XPAR_PS7_NAND_0_BASEADDR
XPAR_XNANDPS_0_FLASHBASE
The Micron 29F2G08 part on our board is 8 bits wide (the 08 in the part number indicates that -- it would be "16" if the part was 16 bit wide.

The SMC is the "static memory controller". See the TRM page 331 (chapter 11). It can be used for NAND, NOR, or be a parallel port.

The 0xE100_0000 address is an address range set apart for NAND memory managed by the SMC

We add these definitions to include/xparameters.h

We compile the nand driver files, but when we try to link the whole thing we get:

fsbl.elf section `.bss' will not fit in region `ps7_ram_0_S_AXI_BASEADDR'
region `ps7_ram_0_S_AXI_BASEADDR' overflowed by 41712 bytes
The deal here is that the FSBL needs to fit into 192K of OCM sram. We are now overboard by 42K. Maybe this explains why the NAND driver was not included by default. What should we do?

A logical thing (for my purposes) would be to ditch the qspi driver and see what that buys us. Just like the NAND driver, if we look at fsbl/qspi.c we see:

#if defined(XPAR_PS7_QSPI_LINEAR_0_S_AXI_BASEADDR)
  || defined(XPAR_PS7_QSPI_LINEAR_0_BASEADDR)
I go to include/xparamters.h and find the first of these and comment it out. I also comment out those drivers in drivers/Makefile. It is an improvement, but more is needed:
region `ps7_ram_0_S_AXI_BASEADDR' overflowed by 21168 bytes
We could also get rid of the NOR driver. This does not look so promising. There are no driver files in the "drivers" directory.

One clear option is to build two versions of the FSBL. One with the SD driver to put on the SD card and another with the NAND driver to put on the board.

Apparently the NAND driver is the pig. The Zed build can include both the Qspi driver and the SD driver.

Use the optimizer

We kicked out the Qspi driver and reduced our excess from 41712 to 21168 bytes. My next idea is to turn on -Os for gcc and rebuild the fsbl. This works! I get:
-rwxr-xr-x 1 tom tom 131080 Jun 29 13:42 fsbl.bin
We are allowed 3*64K = 196608 bytes. We are now 65628 bytes under our quota. So the optimizer reduced the image size by 86,696 bytes.

The next thing will be to put this on an SD card and see if it works.


Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org