Yocto
The Yocto / EDF flow (AMD’s Embedded Development Framework) is the announced successor to
PetaLinux. It can be built for the Quad SFP28 FMC (XXV Ethernet) reference designs with the
cross-platform build.py runner at the root of the repository, and produces a Linux image that
exercises the SFP28 ports in the same way as the PetaLinux image.
Note
For 2025.2 both the PetaLinux and Yocto flows are supported and produce an equivalent image. From the next tool version onward, the PetaLinux flow for this repository will be retired and Yocto will be the only supported flow.
The Yocto flow is supported for all of the Zynq UltraScale+ and Versal targets (the same set that has PetaLinux support).
Requirements
To build the Yocto projects you will need:
A physical or virtual machine running one of the supported Linux distributions.
Vivado 2025.2 (to build the XSA) and Vitis 2025.2 — the flow uses
xsct/sdtgen, which ship with Vitis, to generate a System Device Tree from the Vivado XSA. The build runner finds and sources both tools itself.Google’s repo tool on your
PATH.The Yocto host packages. On Ubuntu 22.04 / 24.04:
sudo apt-get install repo gawk wget git diffstat unzip texinfo gcc \ build-essential chrpath socat cpio python3 python3-pip python3-pexpect \ xz-utils debianutils iputils-ping python3-git python3-jinja2 \ python3-subunit zstd liblz4-tool file locales libacl1 bmap-tools
A valid 10G/25G Ethernet MAC/PCS license for the XXV Ethernet IP, to build the XSA (see Licenses).
Disk space: a Yocto workspace takes several tens of GB per target.
Attention
You cannot build the Yocto projects in the Windows operating system. Windows users are advised to use a Linux virtual machine to build the Yocto projects.
How to build
From a command terminal, clone the Git repository and
cdinto it:git clone https://github.com/fpgadeveloper/sfp28-fmc-xxv.git cd sfp28-fmc-xxv
Build the Yocto image for your target by running the following command, replacing
<target>with one of the target design labels listed in the build instructions:./build.sh yocto --target <target>
This command launches the corresponding Vivado build if that project has not already been
built and its hardware exported. The first build of a target downloads several GB of sources
(repo sync) and runs bitbake from scratch, so it takes a while; subsequent builds are
incremental. To also gather the boot files into a zip under bootimages/, run
./build.sh all --target <target> (or ./build.sh package --target <target> after the build).
The build:
generates a System Device Tree from the XSA and creates a Yocto machine (
MACHINE = "sfp-<target>") from it, so the PS configuration and the XXV Ethernet, AXI DMA, AXI IIC and AXI GPIO cores of the design are described automatically;layers the board BSP
Yocto/bsp/<board>/(kernel configuration, kernel patch, device-tree additions, hostname, kernel arguments, extra packages) and the port configurationYocto/bsp/port-configs/<ports-*>/(the SFP28 cage wiring) on top;runs
bitbake edf-linux-disk-image. The bitstream is included inBOOT.BINand is loaded at boot.
See Yocto/README.md in the repository for a detailed description of the flow.
Offline / faster builds
If you have downloaded the AMD sstate-cache mirror (“sstate-cache & Downloads - 2025.2” on the
AMD Embedded Design Tools download page), put the absolute path of the extracted mirror in the
file Yocto/offline.txt. The build then uses the mirror for the aarch64 and microblaze
sstate (and downloads/ as a source mirror, if present).
Output products
The output products are gathered into Yocto/<target>/images/linux/:
File |
Description |
|---|---|
|
Boot image (FSBL/PMU firmware or PLM + bitstream + U-Boot) |
|
U-Boot boot script (Zynq UltraScale+ only; Versal boots Linux through systemd-boot) |
|
Linux kernel |
|
Linux device tree |
|
U-Boot (also contained in |
|
Full SD-card disk image — this is what you write to the SD card |
|
Block map for |
|
Root filesystem tarball |
The zip bootimages/sfp28-fmc-xxv_<target>_yocto-2025-2.zip contains rootfs.wic.xz,
rootfs.wic.bmap, BOOT.BIN, on Versal also BOOTAA64.EFI, and a readme.txt with the SD-card
steps below.
Prepare the SD card
Unlike the PetaLinux flow (which produces separate boot files for a hand-partitioned card), the
Yocto flow produces a full SD-card disk image (rootfs.wic.xz) that already contains all
partitions. You write that image to the SD card’s raw device, then copy the boot files onto the
first partition, because the image does not place them where the boot ROM looks for them:
All targets — copy
BOOT.BINonto the first (FAT) partition. The image installsBOOT.BINon an ext4 partition, which the boot ROM cannot read.Versal — also copy the systemd-boot EFI loader to
EFI/BOOT/BOOTAA64.EFIon the first partition. The image ships an emptyEFI/BOOT/folder; without the loader U-Boot stops at its prompt instead of booting Linux.
Warning
Writing an image to a raw block device cannot be undone. Be absolutely certain you have identified the SD card’s device node before running the commands below — if you use the wrong device you risk destroying data on one of your hard drives.
Identify the SD card device. With the card unplugged, run
lsblk -o NAME,SIZE,RM,TYPE, insert the card, and run it again. The new entry — typically/dev/sdX, withRM=1(removable) and a size matching your card — is your target. ReplacesdXwith that device, and<target>with your target label, below.Unmount any partitions the desktop auto-mounted:
for p in /dev/sdX?*; do sudo umount "$p" 2>/dev/null; done
Write the wic image to the raw device. With
bmaptool(fast — only writes used blocks):sudo bmaptool copy --bmap Yocto/<target>/images/linux/rootfs.wic.bmap \ Yocto/<target>/images/linux/rootfs.wic.xz \ /dev/sdX
Or, as a fallback with
dd:xzcat Yocto/<target>/images/linux/rootfs.wic.xz \ | sudo dd of=/dev/sdX bs=4M status=progress conv=fsync
Copy
BOOT.BINonto the first partition (all targets):sudo partprobe /dev/sdX sudo mkdir -p /mnt/sd_esp sudo mount /dev/sdX1 /mnt/sd_esp sudo cp Yocto/<target>/images/linux/BOOT.BIN /mnt/sd_esp/BOOT.BIN
Versal only: install the systemd-boot loader on the same partition. Use the
BOOTAA64.EFIfrom the boot-image zip, or extract it from the root filesystem tarball:tar -xzf Yocto/<target>/images/linux/rootfs.tar.gz --wildcards -O \ '*usr/lib/systemd/boot/efi/systemd-bootaa64.efi' > BOOTAA64.EFI sudo mkdir -p /mnt/sd_esp/EFI/BOOT sudo cp BOOTAA64.EFI /mnt/sd_esp/EFI/BOOT/BOOTAA64.EFI
Unmount and eject the card cleanly so pending writes flush:
sync sudo umount /mnt/sd_esp && sudo rmdir /mnt/sd_esp sudo eject /dev/sdX
Boot
Plug the SD card into the target board and set it to boot from SD. The boot-mode DIP-switch settings are the same regardless of the Linux flow — see the per-board switch settings under Boot PetaLinux, and the board’s user guide.
Connect the Quad SFP28 FMC to the FMC connector that your target was built for (for example HPC0 for
zcu106_hpc0) and plug SFP+/SFP28 modules into the cages you want to use.Connect the USB-UART to your PC and open a terminal emulator at 115200 baud (8N1) — see UART terminal.
Optionally, connect the board’s own Ethernet port (RJ45) to your network, for SSH access.
Connect and power your hardware.
What to expect on the console
On a Zynq UltraScale+ board the FSBL, U-Boot and the EDF boot script run, and Linux mounts its
root filesystem from partition 3 of the SD card. Excerpts from a zcu104 boot:
Zynq MP First Stage Boot Loader
Release 2025.2 ...
U-Boot 2025.01-...
Bootmode: LVL_SHFT_SD_MODE1
...
Scanning mmc 0:2...
Found U-Boot script /boot.scr
...
[ 0.000000] Kernel command line: earlycon console=ttyPS0,115200 clk_ignore_unused init_fatal_sh=1 root=/dev/mmcblk0p3 ro rootwait uio_pdrv_genirq.of_id=generic-uio cma=1536M
...
[ 2.224768] si5324 6-0068: si5328 probed
[ 2.295101] si5324 6-0068: si5328 probe successful
[ 2.355329] sfp sfp-eth0: Host maximum power 2.0W
[ 2.360048] sfp sfp-eth0: No tx_disable pin: SFP modules will always be emitting.
[ 2.676310] sfp sfp-eth0: module OEM SFP-10G-T rev 02 sn ...
[ 4.619143] systemd[1]: Hostname set to <zcu104-sfp-2025-2>.
...
AMD Embedded Development Framework Linux distribution 25.11.1+release-... zcu104-sfp-2025-2 ttyPS0
zcu104-sfp-2025-2 login:
On a Versal board the PLM loads the boot image, U-Boot first enables the FMC VADJ supply
(on the VCK190, VMK180, VPK120 and VPK180, the line Setting bus to 1 below), then loads
systemd-boot from the first partition, which starts Linux. Excerpts from a vck190_fmcp1 boot:
U-Boot 2025.01-...
Bootmode: LVL_SHFT_SD_MODE1
...
Hit any key to stop autoboot: 0
Setting bus to 1
...
Scanning mmc 0:1...
Booting: mmc 0
EDF Xen EDF Linux Boot in 5 s.
EFI stub: Exiting boot services...
[ 0.000000] Kernel command line: console=ttyAMA0 earlycon=pl011,mmio32,0xFF000000,115200n8 root=PARTUUID=... ro rootwait uio_pdrv_genirq.of_id=generic-uio clk_ignore_unused cma=1536M
...
[ 4.537238] si5324 7-0068: si5328 probed
[ 4.602219] si5324 7-0068: si5328 probe successful
[ 5.298158] sfp sfp-eth0: Host maximum power 2.0W
...
[ 5.683256] sfp sfp-eth0: module OEM SFP-10G-T rev 02 sn ...
[ 6.170796] systemd[1]: Hostname set to <vck190-sfp-2025-2>.
...
vck190-sfp-2025-2 login:
Log in
Log in on the console as amd-edf. On the first login you are asked to choose a new
password immediately (there is no password to enter beforehand):
zcu104-sfp-2025-2 login: amd-edf
You are required to change your password immediately (administrator enforced).
New password:
Retype new password:
The amd-edf user can run commands as root with sudo (it asks for that password). The image
includes an SSH server, so once the board’s own Ethernet port has an address you can also log
in over the network: ssh amd-edf@<board-ip>.
Image settings
Setting |
Value |
|---|---|
Hostname |
|
User |
|
Extra kernel arguments |
Zynq UltraScale+: |
Root filesystem |
partition 3 of the SD card ( |
Network |
every Ethernet interface requests an address over DHCP at boot |
Extra packages |
|
The extra kernel arguments are set by BSP_EXTRA_BOOTARGS and the hostname by
hostname:pn-base-files:forcevariable in Yocto/bsp/<board>/conf/local.conf.append. The board
Ethernet port has a fixed MAC address (local-mac-address in
Yocto/bsp/<board>/meta-user/recipes-bsp/device-tree/files/system-user.dtsi); change it if you
run more than one board of the same type on your network.
Network interface names
The image uses systemd’s predictable interface names. The SFP28 ports (driver xilinx_axienet)
and the board’s own Ethernet port (driver macb) are named as follows:
Targets |
SFP28 port 0 |
SFP28 port 1 |
SFP28 port 2 |
SFP28 port 3 |
Board RJ45 |
|---|---|---|---|---|---|
1-port Zynq UltraScale+ ( |
|
— |
— |
— |
|
4-port Zynq UltraScale+ ( |
|
|
|
|
|
Versal (all) |
|
|
|
|
|
On the 4-port Zynq UltraScale+ targets, ports 1 to 3 keep their kernel names eth1 to eth3
(they are not renamed by systemd); they work the same as the renamed ports. Interface names depend
on the order in which the kernel probes the devices, so if a name differs on your build, identify
the ports by driver and base address:
zcu106-sfp-2025-2:~$ ip -br link
end1 UP 00:0a:35:06:21:07 <BROADCAST,MULTICAST,UP,LOWER_UP>
eth1 DOWN 00:0a:35:00:00:02 <NO-CARRIER,BROADCAST,MULTICAST,UP>
eth2 DOWN 00:0a:35:00:00:03 <NO-CARRIER,BROADCAST,MULTICAST,UP>
eth3 DOWN 00:0a:35:00:00:04 <NO-CARRIER,BROADCAST,MULTICAST,UP>
end0 UP 00:0a:23:00:00:00 <BROADCAST,MULTICAST,UP,LOWER_UP>
zcu106-sfp-2025-2:~$ ls -l /sys/class/net/*/device
xilinx_axienet <address>.ethernet is an SFP28 port and macb ff0e0000.ethernet (Zynq
UltraScale+) or macb ff0c0000.ethernet (Versal) is the board’s own port. The SFP28 ports appear
in port order of their base addresses: on zcu106_hpc0 port 0 to 3 are at 0x80060000,
0x80070000, 0x80080000 and 0x80090000; on vck190_fmcp1 at 0x80000000 to 0x80030000.
The base addresses of your target are in dmesg | grep xilinx_axienet.
Using and testing the SFP28 ports
Once Linux has booted and you have logged in:
Check that the SFP28 cages and the fitted modules are detected, and that every port came out of reset (there must be no
GT reset not completeorDMA reset timeoutlines):dmesg | grep -E 'sfp sfp-eth[0-9]' dmesg | grep -iE 'xilinx_axienet|GT reset|DMA reset'
Connect a port to a link partner running at the target’s rate (see Testing the SFP28 ports) and check the link:
sudo ethtool end0
A 10G link shows
Speed: 10000Mb/sandLink detected: yes, and the kernel logsxilinx_axienet 80060000.ethernet end0: Link is Up - 10Gbps/Full - flow control off. With a 10GBASE-T copper module, the module’s PHY is also reported, for examplePHY [i2c:sfp-eth0:11] driver [Aquantia AQR113C].The port requests an address over DHCP. To use a fixed address instead:
sudo ip addr add 192.168.10.10/24 dev end0 sudo ip link set end0 up
Ping the link partner and measure the throughput with
iperf3— see Testing the SFP28 ports for the commands and the results to expect.
The PetaLinux examples in Example Usage (ifconfig, ip,
ethtool, ping, iperf3) apply to the Yocto image as well; use the interface names from the
table above.
Board support details
The board-specific parts of the Yocto flow live under Yocto/bsp/. The notable ones:
SFP28 cage wiring (
port-config.dtsi). The SFP28 cages and the parts on the FMC (Si5328 clock generator, PCA9548 I2C mux, the modules) are not described by the XSA, so each target applies a port-config overlay that describes the Si5328 (programmed to 156.25 MHz) and wires each active cage to the kernel SFP framework: the I2C-mux channel, ansff,sfpcage node with itsMOD_ABSGPIO, and thesfp = <&...>link on the XXV MAC node. Three overlays exist —ports-0(single-port Zynq UltraScale+:zcu104,zcu106_hpc1),ports-0123(four-port Zynq UltraScale+) andports-versal-0123(four-port Versal).Kernel configuration (
bsp.cfg). Enables the SFP framework (CONFIG_SFP,CONFIG_MDIO_I2C) so that empty cages stay down instead of flapping, and the PHY drivers used by 10GBASE-T copper SFP+ modules (CONFIG_MARVELL_10G_PHY,CONFIG_AQUANTIA_PHY,CONFIG_BCM84881_PHY,CONFIG_MARVELL_88X2222_PHY).QPLL reset kernel patch (Zynq UltraScale+).
0001-xxv-qpllreset-gpio.patchlets thexilinx_axienetdriver pulse the shared QPLL reset of the XXV IP once after the Si5328 has been programmed (see QPLL reset). Versal does not need it.Board Ethernet PHY (device tree). The System Device Tree flow does not describe the TI DP83867 PHY of the board’s Ethernet port, so
system-user.dtsidescribes it with its RGMII delay settings and gives the port a fixed MAC address.FMC VADJ. On the ZCU104, an FSBL patch (
zcu104_vadj_fsbl.patch) makes the FSBL read the VADJ voltage from the FMC card’s EEPROM and enable VADJ. On the VCK190, VMK180, VPK120 and VPK180, the U-Boot boot command programs and enables the VADJ regulator before booting Linux.Machine generated from the XSA. There is no pinned AMD machine;
gen-machineconf parse-sdtderives the machine from each target’s Vivado XSA, which is what lets third-party boards like the Avnet UltraZed-EV build with no AMD machine configuration.