Mega Petalinux Notes - barawn/verilog-library-barawn GitHub Wiki
Petalinux is just a tad bit underdocumented, so this notes page is an unorganized "WTF is going on" list.
When adding a new device to a device tree, the syntax is
label: name@address {
// stuff
};
The label allows you to reference the node elsewhere (e.g. &label). The most common screwup I do is to put a space between the label and the colon. There is no space allowed between "label" and ":".
The final device tree with all of the includes merged isn't ever included anywhere. There's a hack to preserve it - in project-spec/meta-user/recipes-bsp/device-tree/device-tree.bbappend
, add
do_install:append() {
for PP in *.dts.pp; do
sed -e '/^#/d' < ${B}/${PP} > ${TOPDIR}/${PP}
done
}
You'll then get system-top.dts.pp
in the build/
directory after the build.
Device tree bindings for Zynq Ultrascale (zynqmp) pinctrl are totally bizarre. To select a "pin group" that a function corresponds to you need to dig through the PMU firmware for the definitions here:
So if I2C1 is on MIO16/17, we find PINCTRL_PIN_16/17 and find that it's labelled as PINCTRL_GRP_I2C1_4, so it's i2c1_4_grp in the device tree.
The syntax for the pinctrl stuff is here:
https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842152/ZynqMP+Linux+Pin+Controller+Driver
but you have to include the header which is not shown here, or else the DTC will fail to build at apparently random lines with syntax errors.
#include <dt-bindings/pinctrl/pinctrl-zynqmp.h>
This is shown in the example of the "xlnx,zynqmp-pinctrl.yaml" file but I haven't seen it elsewhere.
In the device tree, if you need to refer to a GPIO, there are usually one of two ways to do it.
-
A single "two-cell" property with the parent, pin, and flags. Like gpio = <&gpio 34 0>. Documentation specifies the flags - they're listed as "optional standard bitfield specifies" but Xilinx follows that standard.
-
For interrupts, two properties specifying parent, then index and type. Like interrupt-parent = <&gpio>, interrupt = <2 IRQ_TYPE_LEVEL_LOW>.
The number specified there is the index. For MIO pins it's just the MIO number. For EMIO pins, you add the max MIO pin
to the EMIO number. To use the macros for IRQ_TYPE_LEVEL_LOW, you need to #include "include/dt-bindings/interrupt-controller/irq.h
The SD card controller in the Zynq can be configured in a number of different ways, and the device tree generator doesn't always detect them all, which means you have to add properties in the device tree to get it to work.
The key to knowing something's wrong is if the Linux kernel boots, but then cannot load the root filesystem and panics: this is because the BootROM and u-boot are okay loading files (since they are always doing simpler SD card accesses) and then when the Linux driver takes over, it can't read things because it's not configured properly.
You will see something like:
[ 4.606910] mmcblk0: mmc0:aaaa SC16G 14.8 GiB (ro)
...
[ 4.765918] driver: mmcblk
[ 4.772742] b301 133120 mmcblk0p1 9df87d5f-01
[ 4.772746]
[ 4.779567] b302 9321816 mmcblk0p2 9df87d5f-02
indicating that the partition is there, but it's mounted read-only (the 'ro' tag) followed by (hi Google users):
[ 4.650845] VFS: Cannot open root device "mmcblk0p2" or unknown-block(179,2): error -30
...
[ 4.865296] ---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(179,2) ]---
The most common things to add are:
&sdhci1 {
disable-wp;
no-1-8-v;
};
If the board is capable of running SD cards at 1.8V, only the first line might be needed.
This link has a cryptic message hidden:
If the user tries to load the un-aligned bit/bin file the PL configuration takes a longer time when compared with aligned(word-aligned) bit/bin files.
without mentioning
- what alignment here means ('word' does not properly specify a size!)
- what longer time means
- how to align it
word typically means the natural unit of size for an architecture, so you might guess maybe it's 64-bit here. Maybe it's 32-bit though, which is what it often is. Or you might guess that it's 16-bit, since words are 16-bit in x86 since that's what the original architecture was (hence word/dword/qword in assembly). It's actually 32-bit because it's the size unit for the MicroBlaze processor in the PMU which actually loads the firmware.
And longer time here means 100x longer!
As far as I know the bin
file should always be aligned, because it's a sequence of 32-bit instructions going to the
configuration engine. But the bit
file is not always aligned, because it has a non fixed length header.
There is a 2023 patch to fix this in the fpga manager framework, and there's a backport of that patch in the
petalinux/
directory.
Because Petalinux hides so much behind BSPs and automatic 'hidden fixes' in Yocto, with a new board it's really hard to figure out WTF you're supposed to do. A BSP tutorial that starts out with "use another BSP close to your board to start with" is a great chicken-and-the-egg paradox.
So this is basically what you need for starting out with a clean Petalinux project.
- Create a minimal Vivado project with a block diagram containing the PS and basically nothing else. Configure the PS as needed, with peripherals, pin support, DDR, etc. Build it and export the hardware (with bitstream if you actually need the PL for anything, even for like EMIO)
- Create a Petalinux project based on that XSA via
petalinux-create -t project -n <name> --template zynqMP
and thenpetalinux-config -p <name> --get-hw-description <path-to-xsa> --silentconfig
. No, you're not done yet, don't try to build it. - Update the system-user.dtsi base device tree and add any platform devices on your board. If you're running Linux it's probably easier to use Linux drivers for I2C devices rather than trying to handle them yourself. Sooo many I2C devices already have kernel drivers. The base system-user.dtsi is in
project-spec/meta-user/recipes-bsp/device-tree/files/
. - For some inane reason, you also have to create the fixed clocks which feed the PS GTRs and hook them up to the PS GTR. IF you don't do this, the DisplayPort driver will die with
[ 5.024603] xilinx-psgtr fd400000.phy: Invalid reference clock number 2
[ 5.031214] zynqmp-display fd4a0000.display: failed to get PHY lane 0
[ 5.037687] zynqmp-display: probe of fd4a0000.display failed with error -22
Fixed clocks go in the root node and look like
ref48: ref48M {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <48000000>;
};
Then you hook them up to the PS GTR like
&psgtr {
status = "okay";
/* usb3, dp */
clocks = <&si5335_0>, <&si5335_1>;
clock-names = "ref0", "ref1";
};
The "ref0", "ref1" names here aren't arbitrary, they refer to which GTR reference clock they're hooked to: ref0, ref1, ref2, or ref3.
5. Actually configure stuff by entering the directory (cd <name>; petalinux-config
). You probably also need to configure the kernel via petalinux-config -c kernel
to make sure you have the drivers for the devices you added in step 3.
The "FPGA manager" framework in Linux requires debugfs support if you want to read back the image, so make sure to enable CONFIG_MGR_DEBUG_FS. See the later section on the dopestick limitations regarding bitstream readback on Zynq devices and the fix.
Zynq devices can readback configuration frames Very Fast through the PCAP interface, but stupidly the PM firmware by default only allows full readback. Which is impressively stupid if all you want to do is read back a specific BRAM (which is amazingly useful), since it will take multiple seconds.
In order to change this in PetaLinux, you need to patch both the PMU firmware and the Xilinx driver for the fpga-mgr framework (as well as enable debugfs for the fpga-mgr). There's the beginning of a patchset here:
https://github.com/barawn/verilog-library-barawn/tree/master/petalinux/partial_readback
You can read the EFUSE values/PS DNA/SoC revision in PetaLinux through the nvmem driver, but you need to enable access to them in the PMU firmware. Patchset here:
https://github.com/barawn/verilog-library-barawn/tree/master/petalinux/efuse-access
petalinux-build -c <component> -x cleansstate
petalinux-devtool modify <component>
(do changes in work directory, git commit to local repo when complete so it can create a patch)
petalinux-devtool finish <component> /absolute/path/to/project-spec/meta-user/
At least in 2022.1, petalinux-devtool does not create a working recipe for FSBL patching! Instead, you need
to go to the project-spec/meta-user/recipes-bsp/embeddedsw/
directory, move the patch from the fsbl-firmware
subdirectory to the files
directory, and make the fsbl-firmware_%.bbappend
file look like the 2022.1+
example here
PetaLinux hides the Yocto tools from you, but you can get them back by copying a bitbake-env
file
under project-spec
and sourcing it when needed. bitbake-env
is located under the petalinux/
directory in this repository.
A lot of boards have a MAC address buried in an EEPROM, since you can just buy them from Microchip. See here for a hack-and-a-half way of doing it via u-boot commands.
The version of PetaLinux in 2022.1 at least requires sf erase to have lengths which are multiples of the sector size, it won't pad them. It'll give you an Error -22 (Invalid Argument) if you try to pass it a length that isn't a multiple.
The sf commands want lengths in hexadecimal! Make sure they are hex - they'll interpret decimal characters as hex and you'll write MUCH MUCH MORE than you wanted.