# Linux Kernel and Boot Loader

To the extent possible, the NDI examples attempt to follow the vendor specific boot flow and methods for building a Linux kernel and U-Boot boot-loader. The following sections detail specific customizations made to enable the otherwise standard vendor boot-loader and kernel to work with the NDI FPGA examples.

### Altera

The Altera U-Boot bootloader and Linux kernel are built from git repositories provided by altera-opensource on github. See RocketBoards.org for full details.

#### Directory Structure

The following Altera project subdirectories can be found in the `fpga_reference_design/linux_kernel` directory:

| Directory | Target Development Board           |
| --------- | ---------------------------------- |
| agilex7   | DK-SI-AGI027FA Agilex-7 SoC DevKit |
| a10-socdk | Arria-10 SoC Development Kit       |
| SoCKit    | Arrow/Terasic SoCKit               |

#### Build Requirements

Building the Linux kernel and U-Boot bootloader requires an appropriate cross compiler for the target archiecture. On Debian and similar systems, this can be accomplished by installing the appropriate packages:

```
sudo apt-get install cpp-aarch64-linux-gnu
sudo apt-get install gcc-arm-linux-gnueabihf
```

Alternately an appropriate 3rd party cross compiler can be used, or a toolchain can be built directly from source.

#### Building an Existing Project

The build instructions from Altera involve quite a few manual steps:

<https://www.rocketboards.org/foswiki/Documentation/BuildingBootloaderCycloneVAndArria10>\
<https://altera-fpga.github.io/rel-25.1/embedded-designs/agilex-7/f-series/soc/boot-examples/ug-linux-boot-agx7-soc/>

These steps have mostly been automated via a Makefile, with some additional changes to customize the kernel as needed for the NDI Advanced SDK (enable UIO devices and create custom device-tree nodes).

The Makefile will checkout the source directories, patch and configure as required, then build the files required to boot and create a uSD image. Warnings about watchdog and timer drivers are expected while building U-Boot from the Altera released sources and can be ignored.

The configuration snippet `uio.fragment` enables the required uio kernel modules.

The patch file `0001-NewTek-Altera-NDI-device-tree-entries.patch` adds the required device-tree nodes for logic in the FPGA fabric. See the instructions from Altera for full details:

<https://www.rocketboards.org/foswiki/Documentation/HOWTOCreateADeviceTree>

**Note:**

If you follow the RocketBoards instructions for generating the Cyclone-V boot files, the FPGA will not be programmed by default. The provided Makefile builds a u-boot.scr file which is executed by the default Altera U-Boot bootcmd. This script programs the FPGA prior to loading the Linux kernel and device-tree.

### Xilinx

The following boards and NDI configurations are supported. For a full list of available targets run `make help` in the `fpga_reference_design/linux_kernel` directory.

| Configuration       | Contents                                                  |
| ------------------- | --------------------------------------------------------- |
| Arty-Z7-20-Enc      | NDI encoder for the Digilent Arty Z7-20                   |
| Zybo-Z7-20-Enc      | NDI encoder for the Digilent Zybo Z7-20                   |
| Zybo-Z7-20-Enc-Lite | NDI encoder for the Digilent Zybo Z7-20 with 16-bit SDRAM |
| Zybo-Z7-20-Dec      | NDI decoder for the Digilent Zybo Z7-20                   |
| ZCU104-Enc          | NDI encoder for the Xilinx ZCU104                         |
| ZCU104-Dec          | NDI decoder for the Xilinx ZCU104                         |

Xilinx offers at least two different approaches to generating the bootloaders, device tree, and Linux kernel.

* [Open Source Linux (OSL)](https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/460653138/Xilinx+Open+Source+Linux) flow
* [PetaLinux](https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842250/PetaLinux) flow

#### Open Source Linux (OSL) Flow

The OSL flow essentially builds each component required to boot the example design independently and then packages them together in a `BOOT.BIN` file along with a kernel, kernel modules, kernel headers, and a device tree. It offers the highest degree of transparency and control to the user and avoids the need to deal with the vagaries of alternate methods like Yocto or PetaLinux. It requires only that the user have installed the appropriate version of Vitis, which provides the ARM cross-compilers, XSCT, `bootgen`, and other supporting tools.

**Required Xilinx Tools**

Building the Xilinx example designs requires that the user have installed the AMD Vitis Unified Software Platform version 2024.2. Xilinx has recently merged Vivado and Vitis together and they generally should be installed concurrently. Vitis provides example design source code, the SDK, bare-metal libraries, as well as the cross-compilers, XSCT, `bootgen` and other supporting tools.

Installation instructions, supported platforms, and other details can be found in "UG1742, Vitis Release Notes and Installation Guide". After installation, users should prepare their environment by sourcing the appropriate settings script, found at `<install_dir>/Vitis/2024.2/settings64.sh` before attempting to build any of the example designs.

**Generating Example Designs**

The steps required for building the bootloaders and kernel are described to some degree on the Xilinx wiki and forums and have generally been automated via a top-level Makefile. To build one of the example designs, run `make all` with the following variables set accordingly:

* `XSA_BOARD` - The target board: `ZCU104`, `Zybo-Z7-20`, or `Arty-Z7-20`
* `XSA_BOARD_PROJ` - The design to build: `Enc`, `Dec`, or `Enc-lite` (Zybo only)

Note that case is significant and that the combination matches the project names in `../src/fpga` as well as the device tree snippets in `device-tree/`.

**Configuration Files**

Each Xilinx board has a corresponding entry in `boards/` which contains configuration settings used by the make process. The appropriate file to use is determined by the value of the `XSA_BOARD` variable and determines the flags to use for compiling the bootloader, the kernel, and other settings. Refer to the Makefile and fragments in `mk/` for more details.

Each Xilinx project has a corresponding entry in `device-tree/` which contains a device tree include file that will be included in the device tree source and ultimately compiled during the build process. The appropriate file to use is determined by the value of the `XSA_BOARD_PROJ` variable. Refer to the Makefile and fragments in `mk/` for more details.

**Output Products**

There are many ways to boot Xilinx devices, this discussion is limited to what is done here. The build process produces several artifacts required for booting the system:

* `BOOT.BIN` - The initial binary used to boot the system prior to loading the kernel
* `system.dtb` - The flattened device tree passed to the kernel by U-boot
* `Image` or `zImage` - The Linux kernel loaded by U-boot
* Kernel modules and headers

**Bootloaders and BOOT.BIN**

The `BOOT.BIN` file created for the example designs contains the following content:

* First-stage bootloader (FSBL)
* U-boot ELF
* Minimal U-boot device tree (used by U-Boot before loading the kernel)
* Bitstream

Ultrascale+ devices also contain:

* ARM Trusted Firmware (ATF)
* Platform management unit (PMU) firmware

The origins of each component of the `BOOT.BIN` are the following:

* The FSBL source code is exported by XSCT using the contents of the associated Xilinx support archive. After export, the source code and linker script are cross compiled for the target platform. Build flags for the FSBL are controlled by variables set in the appropriate board specific file in the `boards/` directory. The FSBL ELF is staged for later packaging.
* The Makefile fetches the specified tag of the Xilinx U-boot fork, applies the defconfig from the file defined by `XSA_BOARD` and cross-compiles it for the target platform. The U-boot ELF and a minimal device tree are staged for later packaging. It is worth noting that the Xilinx platforms used for NDI Advanced SDK example designs all have some level of support by U-boot and the device tree that is created is sufficient to boot a kernel from the SD card.
* The bitstream is extracted from the provided Xilinx support archive (XSA) file and staged for later packaging.
* The PMU firmware (ZCU104 only) source code is exported by XSCT using the contents of the XSA file. The PMUFW is cross-compiled in the same was as the FSBL, with PMUFW specific build variables that can be useful for debugging. The user is referred to the Xilinx wiki and especially UG1137, the Zynq MPSoC Software Developers Guide, for more details regarding PMU use and configuration.
* The Makefile fetches the specified tag of the ARM trusted firmware (ATF) and builds it for the target platform. The `bl31.elf` it creates is then staged for later packaging.
* Once the FSBL and U-boot binaries, minimal U-boot device tree, bitstream, and PMUFW and ATF are staged, the appropriate `.bif` file is installed alongside them and `bootgen` is run construct the `BOOT.BIN` that will eventually be transferred to `/boot` of an SD card. An MD5 hash is computed for each component as well as the final product. See UG1283 for more information on the use of `bootgen` to create and dump `BOOT.BIN` files.
* Once `bootgen` has finished assembling the `BOOT.BIN` file, it is copied to a project specific location in the `output` directory.

**Flattened Device Tree**

Generating the device tree source code and the flattened device tree requires several steps:

* The Makefile fetches the indicated tag of the Xilinx device-tree source generator which is a large collection of Tcl scripts and board specific details for Xilinx IP and development boards. The DTS generator uses the XSA to infer IP settings and connections.
* The path to that repo is used together with the project XSA file to create a directory containing all the files required to build a device tree for the specific Vivado project.
* The files in the device tree source directory then undergo some modifications (see `mk/dtb.mk` for details) prior to compilation.
* The appropriate `.dtsi` file in `device-tree/` is included at this stage before the final device tree source is compiled into the flattened device tree.
* The flattened device tree and the top level source code are copied into the same project-specific location in the `output` directory that the `BOOT.BIN` was.

**Kernel and Modules**

The Linux kernel follows a much more familiar set of steps:

* The Makefile fetches the indicated tag of the Xilinx fork of the Linux kernel source tree. To save space and time, this is a limited clone of the tree.
* The kernel is built using an external build directory (using the `O=` option), which allows the same source tree to be used to build multiple architectures.
* Default kernel configurations are used for both ARM and ARM64 kernels.
* The kernel, modules, and headers are installed into `output/$(ARCH)/`.

**Rebuilding Example Designs after Modification**

Rebuilding example designs after modifications to the FPGA projects is straightforward as long as a couple of caveats are followed:

* The project naming conventions need to remain the same in order for device tree include files to be properly included
* In principle, any new IP added that the kernel needs to be aware of will be automatically included by the device tree source generator. In practice, some manual modifications via the `.dtsi` file may be required.
* Run `make clean` which will remove the staging area and output directories but preserve the git repos that were downloaded to `extern/`. Then run `make all` with the `XSA_BOARD` and `XSA_BOARD_PROJ` set appropriately.

#### Petalinux Flow

The PetaLinux design flow is an alternative to the OSL flow that the NDI Advanced SDK uses. No PetaLinux projects are provided.

**Suggested Steps for PetaLinux Projects**

The PetaLinux commands and recommended work flow have changed in recent revisions of the tools and the following steps should only be used as a guide. For more detailed information, including the most recent commands and arguments, refer to "UG1144 PetaLinux Tools Documentation: Reference Guide" and other documents, in particular the Xilinx wiki.

The general approach to building a PetaLinux project based on the NDI Advanced SDK would be the following:

* Export the hardware platform from Vivado and make sure that the bitstream is included in the exported Xilinx support archive (XSA)
* Create a PetaLinux project

  `$ petalinux-create -t project <project_name>`
* Import the new hardware definition and configure the project

  `$ cd <project_name>` `$ petalinux-config --get-hw-description <path-to-vivado-project>`
* Configure the project, kernel, U-boot, and rootfs

  `$ petalinux-config -c u-boot` `$ petalinux-config -c kernel` `$ petalinux-config -c rootfs`
* Add device tree include files from `device-tree/` for the target platform to the PetaLinux project. This has typically been done by copying it to a location with the `project-meta` directory, but this may vary by version. If the design to be built includes additional IP or other modifications that affect the device tree, these need to be made as well, typically by hand.
* Build the project.

  `$ petalinux-build`
* Package the system for deployment (note that there are likely many options that will need to be included for this command)

  `$ petalinux-package <options>`

Once the project has been completed, boot images are typically located in the project tree at `images/linux`. The kernel and kernel modules will need to be extracted from the project along with the device tree and `BOOT.BIN` for transfer to an SD card. Various kernel images are usually generated during the build process. Kernel modules can be extracted from the rootfs tarball that is created during the build.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.ndi.video/all/developing-with-ndi/advanced-sdk/ndi-advanced-sdk-fpga-example-reference-design/ndi-advanced-sdk-fpga-ip/linux-kernel-and-boot-loader.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
