Configure and run a qemu zynq.
#Configrue repo
curl https://storage.googleapis.com/git-repo-downloads/repo > repo
chmod a+x repo
mkdir -p ~/bin
mv repo ~/bin/
PATH=~/bin:$PATH
repo --help
mkdir -p yocto/latest
cd yocto/latest
#Configure your git access e.g. create an access token
#Init repo
repo init -u https://github.com/Xilinx/yocto-manifests.git -b HEAD -m default-edf.xml
repo sync
#default-edf.xml is the embedded development framework manifest which extends the base manifest default.xml.
#By successfull repo sync the folder content should be like this
# .repo
# edf-init-build-env
# sources
source edf-init-build-env
bitbake qemu-helper-native
#Bitbake is the build engine for yocto and openembedded. *.bb files and meta-layers are parsed among others by bitbake.
#https://www.digikey.bg/en/maker/projects/intro-to-embedded-linux-part-4-create-custom-layer-and-image-in-yocto/aac0ab17e0c64ae482675abea00b328d
Blink a led on zynq 7000 emulation
For that we add a new layer to the yocto project:
sources/meta-zynq-qemu-led/
├── conf
│ └── layer.conf
└── recipes-kernel
├── linux
│ ├── linux-xlnx
│ │ ├── 0001-ARM-dts-xilinx-Add-zynq-qemu-pl-led.dtb.patch
│ │ └── zynq-qemu-pl-led.dts
│ └── linux-xlnx_%.bbappend
└── qemu-zynq-pl-led
├── files
│ ├── Makefile
│ └── qemu-zynq-pl-led.c
└── qemu-zynq-pl-led_0.1.bb
The layer.conf is as following:
# SPDX-License-Identifier: MIT
BBPATH .= ":${LAYERDIR}"
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
${LAYERDIR}/recipes-*/*/*.bbappend"
BBFILE_COLLECTIONS += "zynq-qemu-led"
BBFILE_PATTERN_zynq-qemu-led := "^${LAYERDIR}/"
BBFILE_PRIORITY_zynq-qemu-led = "8"
LAYERSERIES_COMPAT_zynq-qemu-led = "scarthgap"
WE need a device tree source to emulate a minimal PL in QEMU. The file zynq-qemu-pl-led.dts describes a mininal board layout. For that we create a new layer and save the file to it: ~/yocto/latest/sources/meta-zynq-qemu-led/recipes-kernel/linux/linux-xlnx/zynq-qemu-pl-led.dts. The file content is:
// SPDX-License-Identifier: GPL-2.0
/*
* Zynq-7000 minimal DT for QEMU (arm-generic-fdt-7series) + synthetic PL MMIO LED.
* - 0x40000000: typical GP0 PL window start (below first DRAM byte on 1GiB maps).
* - compatible "qemu:memory-region" lets Xilinx QEMU map real RAM for MMIO R/W.
*/
/dts-v1/; //required dtb version marker
/include/ "zynq-7000.dtsi" // common device tree
/ {
model = "Zynq QEMU PL LED demo";//Human-readable name (shown in /proc/device-tree/model)
//Identifies the board; the fallback xlnx,zynq-7000 matches the SoC so generic drivers and expectations remain valid
compatible = "xlnx,zynq-qemu-pl-led", "xlnx,zynq-7000";
aliases {
ethernet0 = &gem0;
serial0 = &uart1;
};
//Declare DRAM starting from phy. 0 for 1GB
memory@0 {
device_type = "memory";
reg = <0x0 0x40000000>;
};
/*stdout-path — Kernel console on serial0 at 115200 baud (must match QEMU serial wiring and SERIAL_CONSOLES in the machine config).
earlycon — Early print before the full UART driver probes (helpful in bring-up).*/
chosen {
bootargs = "earlycon";
stdout-path = "serial0:115200n8";
};
//dummy usb transceiver
usb_phy0: phy0 {
compatible = "usb-nop-xceiv";
#phy-cells = <0>;
};
/*
* Backing store in QEMU for PL-style register block. Trying to emulate an fpga register.
* Linux matches the second compatible with module qemu-zynq-pl-led.
*/
pl_fpga_mmio: pl-fpga-mmio@40000000 {
compatible = "qemu:memory-region", "qemu,zynq-pl-led";
reg = <0x40000000 0x1000>;
qemu,ram = <1>;
};
};
&clkc {
ps-clk-frequency = <33333333>;
};
//Ethernet MAC enabled; simple PHY node for QEMU’s GEM model
&gem0 {
status = "okay";
phy-mode = "rgmii-id";
phy-handle = <ðernet_phy>;
ethernet_phy: ethernet-phy@0 {
reg = <0>;
};
};
//SD/MMC — required for wic.qemu-sd style images under zynq-generic.
&sdhci0 {
status = "okay";
};
&uart1 {
status = "okay";
};
&usb0 {
status = "okay";
dr_mode = "host";
usb-phy = <&usb_phy0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usb0_default>;
};
&pinctrl0 {
pinctrl_usb0_default: usb0-default {
mux {
groups = "usb0_0_grp";
function = "usb0";
};
conf {
groups = "usb0_0_grp";
slew-rate = <0>;
io-standard = <1>;
};
conf-rx {
pins = "MIO29", "MIO31", "MIO36";
bias-high-impedance;
};
conf-tx {
pins = "MIO28", "MIO30", "MIO32", "MIO33", "MIO34",
"MIO35", "MIO37", "MIO38", "MIO39";
bias-disable;
};
};
};
A patch is required to inform the kernel about our device tree extension. in the patch stage of bitbake the patch will be integrated. The patch is in 0001-ARM-dts-xilinx-Add-zynq-qemu-pl-led.dtb.patch:
From: meta-zynq-qemu-led
Subject: ARM: dts: xilinx: build zynq-qemu-pl-led.dtb
---
arch/arm/boot/dts/xilinx/Makefile | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/xilinx/Makefile b/arch/arm/boot/dts/xilinx/Makefile
--- a/arch/arm/boot/dts/xilinx/Makefile
+++ b/arch/arm/boot/dts/xilinx/Makefile
@@ -15,3 +15,4 @@
zynq-zturn-v5.dtb \
zynq-zybo.dtb \
- zynq-zybo-z7.dtb
+ zynq-zybo-z7.dtb \
+ zynq-qemu-pl-led.dtb
Now we add a kernel module to write the pl register. Path is ~/yocto/latest/sources/meta-zynq-qemu-led/recipes-kernel/qemu-zynq-pl-led/files/qemu-zynq-pl-led.c. Below is the content:
// SPDX-License-Identifier: GPL-2.0-only
/*
* Demo: one-bit "PL" register at DT reg (default 0x40000000) exposed as
* /sys/class/leds/fpga_pl/brightness (Linux LED class).
*/
#include <linux/io.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
struct pl_led {
struct led_classdev cdev;
void __iomem *regs;
};
static void pl_led_set(struct led_classdev *led, enum led_brightness b)
{
struct pl_led *p = container_of(led, struct pl_led, cdev);
writel(b ? 1U : 0U, p->regs);
}
static int pl_led_probe(struct platform_device *pdev)
{
struct pl_led *priv;
struct resource *res;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->regs))
return PTR_ERR(priv->regs);
priv->cdev.name = "fpga_pl";
priv->cdev.brightness = LED_OFF;
priv->cdev.max_brightness = 1;
priv->cdev.brightness_set = pl_led_set;
priv->cdev.flags = LED_CORE_SUSPENDRESUME;
return devm_led_classdev_register(&pdev->dev, &priv->cdev);
}
static const struct of_device_id pl_led_match[] = {
{ .compatible = "qemu,zynq-pl-led" },
{}
};
MODULE_DEVICE_TABLE(of, pl_led_match);
static struct platform_driver pl_led_driver = {
.probe = pl_led_probe,
.driver = {
.name = "qemu_zynq_pl_led",
.of_match_table = pl_led_match,
},
};
module_platform_driver(pl_led_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("LED on synthetic Zynq PL MMIO (QEMU demo)");
A make file to build and install the kernel module, ~/yocto/latest/sources/meta-zynq-qemu-led/recipes-kernel/qemu-zynq-pl-led/files/Makefile
obj-m := qemu-zynq-pl-led.o
SRC := $(shell pwd)
all:
$(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules
modules_install:
$(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install
clean:
rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c
rm -f Module.markers Module.symvers modules.order
rm -rf .tmp_versions Modules.symvers
To build and package the module, a bitbake file is added ~/yocto/latest/sources/meta-zynq-qemu-led/recipes-kernel/qemu-zynq-pl-led/qemu-zynq-pl-led_0.1.bb
SUMMARY = "Kernel module: sysfs LED backed by synthetic PL MMIO (QEMU Zynq-7000 demo)"
LICENSE = "GPL-2.0-only"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0-only;md5=801f80980d171dd6425610833a22dbe6"
inherit module
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI = "file://Makefile \
file://qemu-zynq-pl-led.c \
"
S = "${WORKDIR}"
MAKE_TARGETS = "modules"
MODULES_INSTALL_TARGET = "modules_install"
COMPATIBLE_MACHINE = "^zynq-generic$"
RPROVIDES:${PN} += "kernel-module-qemu-zynq-pl-led"
do_install:append() {
install -d ${D}${sysconfdir}/modules-load.d
echo qemu-zynq-pl-led > ${D}${sysconfdir}/modules-load.d/qemu-pl-led.conf
}
FILES:${PN} += "${sysconfdir}/modules-load.d"
a bb append file ~/yocto/latest/sources/meta-zynq-qemu-led/recipes-kernel/linux/linux-xlnx_%.bbappend to customize the xilinx kernel with our device tree.
FILESEXTRAPATHS:prepend := "${THISDIR}/linux-xlnx:"
SRC_URI += "file://zynq-qemu-pl-led.dts;subdir=git/arch/arm/boot/dts/xilinx \
file://0001-ARM-dts-xilinx-Add-zynq-qemu-pl-led.dtb.patch \
"
KERNEL_DEVICETREE:zynq-generic = "zynq-qemu-pl-led.dtb"
Build and test
~/yocto/latest/build$ source edf-init-build-env
~/yocto/latest/build$ bitbake core-image-minimal
~/yocto/latest/build$ runqemu zynq-generic core-image-minimal
# LED API (writes physical word at 0x40000000)
echo 1 > /sys/class/leds/fpga_pl/brightness
echo 0 > /sys/class/leds/fpga_pl/brightness

Subscribe to get last updates.