Creating a DTS file is a crucial step in integrating a custom peripheral with the Linux kernel. Unfortunately, this subject is rather hazy at the present time, and it’s in particular difficult to obtain that initial DTS to boot the system up with for the first time.
It’s important to take the DTS (and the DTB compiled from it) for what it is: A simple data tree (think XML) containing information that is read by the kernel as it boots up. By convention, some standard entries tell it what resources (memory and interrupts) to allocate, and the rest of them can be read by the specific driver to obtain application-specific information (e.g. the clock frequency driving the hardware). Like XML, you’re free to add whatever nodes you want to the tree, as long as you have reason enough to assume their names aren’t used for something else.
As of writing this post, there is no automatic process for generating a DTS that includes custom peripherals for Zynq. On the other hand, it’s not all that difficult to add the entry manually, when all the other hardware peripheral’s nodes are available. The two methods described below take different approaches: The first reverse-engineers the DTS from an existing, running Linux kernel. If custom peripherals are declared in the loaded DTB, they will appear here. The significant drawback of this method is that pointers to other nodes in the tree (e.g. “interrupt-parent”) appear as numeric values, and not by a name reference, which makes the whole thing harder to understand and more fragile to changes. Also note that if there are differences in the processor configuration between the running system and yours, this device tree will not be useful. But it’s an excellent way to verify the small details are in place.
The second method focuses on getting the device tree from a system configuration in Xilinx’ EDK. This ensures a perfect match between the processor configuration and the device tree, but if the driver expects some extra attributes, they may get missed. In theory, these attributes should be generated automatically from the IP core’s attributes, but there is nothing stopping the driver’s author from manually editing the DTS tree to add hints to the driver.
I’ve already written a general post on device trees for Microblaze (and several general info). But the principles are the same for any processor. I should mention, that it was written before kernel 3.3, which seems to have another notation for interrupts.
I’ve also described how to run the process for a Microblaze processor in a previous post, which is the basis for this one.
I assume ISE 14.2, but it’s probably not very relevant.
Method #1: Ask a running kernel
The /proc filesystem has a full outline of the device tree the kernel uses. So after booting the board with Linux, go something like
zynq> mount /dev/mmcblk0p1 /mnt/ zynq> cd /proc/ zynq> tar -czf /mnt/devtree.tar.gz device-tree zynq> poweroff
In this example, I’ve assumed that the system was booted from the SD card, and the data is stored to it.
After the board has powered off, attach the SD card to your computer, and copy the devtree.tar.gz to some Linux kernel source’s root directory. From there, go:
$ tar -xzf devtree.tar.gz $ scripts/dtc/dtc -I fs -O dts -o reverse.dts device-tree/
And the reverse-engineered device tree is now given as reverse.dts. It’s recommended to remove all these files from the Linux source, just to avoid future confusion.
The truth is, that the DTS can be disassembled from the DTB with the same utility with something like
$ scripts/dtc/dtc -I dtb -O dts -o fromdtb.dts boot_with_this.dtb
But I prefer getting it from the running kernel for one simple reason: There’s often a chance for confusion regarding exactly which DTB file is loaded at bootup, with all those contradicting parameters fed into the boot loaders. The kernel just tells us what it got.
Method #2: Using Xilinx’ tools
For the sake of those who skipped the introduction:
The DTS file generated by the procedure described below is not good for direct use. See remarks above.
In fact, peripherals in the PL (that is, implemented in logic fabric) don’t appear in the DTS. I suppose that’s why the Zynq-Linux wiki currenly says that there’s no support for automatic device tree generation.
But the actual configuration parameters appear to be consistent. So if not for direct use, the generated DTS files can at least help with verifying the used DTS file is consistent.
Anyhow, I’m pretty confident that this method will be OK some day, if not already, when the device-tree package gets up-to-date enough.
First create a special directory, and make it the working directory of your shell.
The device tree file is generated automatically with the libgen utility with the help of a Tcl script. As of ISE 14.2, this script needs to be loaded separately with git:
bash> git clone git://git.xilinx.com/device-tree.git
This downloads the entire Git repository, and creates a single directory, ‘bsp’. Change the name of the directory inside it from ‘device-tree_v0_00_x’ to ‘device-tree’.
Another web page explains how to make SDK recognize the script, but I prefer command line for things like this.
Obtaining XML and MSS files
From the XPS, pick Project > Export Hardware Design to SDK. This may launch a full implementation process, but this can be avoided by unchecking “Include bitstream and BMM file” in the dialog box that appears on this request. Once the SDK is open (and just any workspace directory chosen), go File > New > Xilinx Board Support package, and accept the defaults offered in the dialog boxes. That will, among others, produce an MSS file under e.g. standalone_bsp_0/ in the workspace directory. Copy that file (typically system.mss) so it’s alongside with ‘bsp’.
Then copy the XML file (typically system.xml) from the SDK\SDK_Export\hw directory, also alongside with ‘bsp’
Edit the copy you made of system.mss, so that the BEGIN OS to END part reads
BEGIN OS PARAMETER OS_NAME = device-tree PARAMETER PROC_INSTANCE = ps7_cortexa9_0 END
and not “standalone” for OS.
Creating the DTS file
Open a DOS Window or Linux prompt terminal with libgen in its PATH. The easiest way is to launch a “Xilinx shell” from the EDK’s project menu, Xilinx Tools > Launch Shell.
Navigate to the working directory, where the ‘bsp’ directory is. Just to avoid confusions, this is what a plain ‘dir’ command should say (more or less):
C:\experiments>dir Volume in drive C has no label. Volume Serial Number is 83E2-6332 Directory of C:\experiments 07/31/2012 05:04 PM <DIR> . 07/31/2012 05:04 PM <DIR> .. 07/31/2012 04:52 PM <DIR> bsp 07/31/2012 03:55 PM 3,360 system.mss 07/31/2012 12:15 PM 639,484 system.xml 2 File(s) 642,844 bytes 3 Dir(s) 3,239,301,120 bytes free
And then run libgen as follows:
libgen -hw system.xml -lp device-tree -pe ps7_cortexa9_0 -log libgen.log system.mss
Which generates a xilinx.dts in ps7_cortexa9_0\libsrc\device-tree. Copy this file to arch/microblaze/boot/dts/ in the to-be compiled kernel source tree. If you can’t find the file there, and libgen didn’t complain about some error, you may have forgotten to edit system.mss as mentioned just above.