<<<<<<<<<< Return to WS 2 Lab Intro >>>>>>>>>>

<<<<<<<<<< Return to WS 2 Lab 2: U-Boot


LAB 3: Building the SoC FPGA Linux Kernel


Next you will download the kernel and build the LTSI kernel for the mach_socfpga architecture. You will build the kernel from the downstream branch on the Altera-Opensource GitHub repo.

Make sure you have the CROSS_COMPILE environment variable which you set in the Workshop Lab U-Boot section to correctly point to the tool chain. If you closed your working shell at any point and began working in a new shell, you will need to re-export the environment variable.

Obtaining, configuring, and compiling the Linux kernel source for SoC FPGA

  • Clone the linux-socfpga repo to your local machine. Be sure to do this from the Workshop 2 working directory.
[WS2-IntroToLinux]$ git clone https://github.com/altera-opensource/linux-socfpga.git

  • Extract the patches archive so we can apply the patches to the kernel later.
[WS2-IntroToLinux]$ tar xvf patches.tgz

  • cd into the linux-socfpga directory
  • Review how GSRD releases are tagged in the linux-socfpga repo.

[WS2-IntroToLinux]$ cd linux-socfpga
[linux-socfpga]$ git tag -l rel*

This shows you all of the tags for the GSRD releases for SoC FPGA by date. These are GSRD releases regression tested as a ACDS, QSys, GHRD, u-boot, & kernel unit with a common data stamp available for each. SoC FPGA Linux commits are also tagged by ACDS (Quartus/QSys) version. You can view these as follows:

[linux-socfpga]$ git tag -l ACDS*

  • For this lab, you will use the 16.04.01 release of the 4.1 LTSI kernel for SoCFPGA. Altera verifies a complete release of the Linux BSP and tags each release to associate verified compatibility between the GHRD, the current ACDS and SoCEDS and ARM Development Studio versions, u-boot, and kernel. To make it easier to remember the tag which you've checked out, you'll create a new downstream branch called ws2_4.1-ltsi_16.04.01.
  • While you may build a different kernel version for your distribution, be sure to checkout the rel_socfpga-4.1-ltsi_16.04.01_pr tag listed below for the Workshop, as the Workshop validator looks specifically for this kernel version.

[linux-socfpga]$ git checkout -b ws2_4.1-ltsi_16.04.01 rel_socfpga-4.1-ltsi_16.04.01_pr

  • Verify that you are on the ws2_4.1-ltsi_16.04.01 branch.

[linux-socfpga]$ git branch
  master
* ws2_4.1-ltsi_16.04.01

  • Verify that you are at the c816eac2b585ced0418ae9d11565825b9489e0c6 commit.

[linux-socfpga]$ git log -n 1 --format=oneline
c816eac2b585ced0418ae9d11565825b9489e0c6 PCI: altera: Fix altera_pcie_link_is_up()

  • Apply the patches to the kernel.

[linux-socfpga]$ patch -p1 < ../patches/socfpga-4.1-ltsi/0003-clean-up-bridges-and-base-region.patch

Now you will configure and build the Linux kernel for SoC FPGA.

  • First copy the workshop kernel configuration into the source tree and name it socfpga_custom_defconfig.

cp ../linux.defconfig.socfpga-4.1-ltsi arch/arm/configs/socfpga_custom_defconfig

  • Next, apply the configuration for the SoC FPGA architecture.

[linux-socfpga]$ make ARCH=arm socfpga_custom_defconfig

The workshop lab will load a pre-built RAM file system. Configure the kernel as follows.

  • Launch the menuconfig kernel configuration utility.

[linux-socfpga]$ make ARCH=arm menuconfig

  • Scroll down to and select "General setup --->"

In the kernel menuconfig utility, when a config setting is highlighted, the space bar will toggle the setting, "Y" will enable it, "N" will disable it, and "M" will modularize it if modularization is supported for the setting. When enabled, an "*" will appear in the menuconfig utility.

  • Scroll down and observe the setting for "Initial RAM filesystem and RAM disk (initramfs/initrd) support"
  • Observe the setting for "(../rootfs.cpio.gz) Initramfs source file(s)"

So that the kernel you build will load the kernel modules which are compiled into the pre-built root file system, we will disable some of the kernel version magic checking. This is very useful for development. However caution should be used when actually deploying a distribution so that problems due to unintended mismatches between kernel versions and loadable modules don't occur.

  • While still in the "General setup --->" page of menuconfig, uncheck "Automatically append version information to the version string"

  • Use the right arrow to scroll to Save on the bottom menu and hit enter to save the new configuration
  • Select OK to save the configuration as .config
  • Select Exit in the pop-up menu, the Exit twice on the bottom menu to exit the menuconfig utility
  • Compile the kernel as shown below

Again, for this lab, we will bypass kernel version magic with the "LOCALVERSION" configuration. This eliminates the appended "+" in the kernel version to allow the loadable kernel modules included in the pre-built file system to load.

[linux-socfpga]$ make ARCH=arm LOCALVERSION= zImage

Building the device tree

To build the device tree we are going to reuse the socfpga templates that Altera upstreams into the kernel source tree and build a device tree for our specific development board. To accomplish this we provide you with some board specific top level DTS templates in this lab which look like this example in DE0_NANO_SOC.dts.

/*
 * Copyright Altera Corporation (C) 2015. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "socfpga_cyclone5.dtsi"
/ {
   model = "Terasic DE-0(Atlas)";
   compatible = "altr,socfpga-cyclone5", "altr,socfpga";

   chosen {
      bootargs = "earlyprintk";
      stdout-path = "serial0:115200n8";
   };

   memory {
      name = "memory";
      device_type = "memory";
      reg = <0x0 0x40000000>; /* 1GB */
   };

   aliases {
      ethernet0 = &gmac1;
   };

   regulator_3_3v: 3-3-v-regulator {
      compatible = "regulator-fixed";
      regulator-name = "3.3V";
      regulator-min-microvolt = <3300000>;
      regulator-max-microvolt = <3300000>;
   };

   soc {
      clkmgr@ffd04000 {
         clocks {
            #clock-cells = <0>;

            clk_0: clk_0 {
               #clock-cells = <0>;
               compatible = "fixed-clock";   
               clock-frequency = <50000000>;
               clock-output-names = "clk_0-clk";
            };

            fft_sub_clk_0: fft_sub_clk_0 {
               #clock-cells = <0>;
               compatible = "fixed-clock";
               clock-frequency = <50000000>;
               clock-output-names = "fft_sub_clk_0-clk";
            }; 

         };
      };

      base_fpga_region: base-fpga-region {
         compatible = "fpga-region";
         fpga-mgr = <&fpga_mgr0>;
         fpga-bridges = <&fpga_bridge0>, <&fpga_bridge1>,
               <&fpga_bridge2>, <&fpga_bridge3>;

         #address-cells = <0x2>;
         #size-cells = <0x1>;
         ranges = <0x00000000 0x00000000 0xc0000000 0x20000000>,
            <0x00000001 0x00000000 0xff200000 0x00200000>;
      };

   };

};

&gmac1 {
   status = "okay";
   phy-mode = "rgmii";

   txd0-skew-ps = <0>; /* -420ps */
   txd1-skew-ps = <0>; /* -420ps */
   txd2-skew-ps = <0>; /* -420ps */
   txd3-skew-ps = <0>; /* -420ps */
   rxd0-skew-ps = <420>; /* 0ps */
   rxd1-skew-ps = <420>; /* 0ps */
   rxd2-skew-ps = <420>; /* 0ps */
   rxd3-skew-ps = <420>; /* 0ps */
   txen-skew-ps = <0>; /* -420ps */
   txc-skew-ps = <1860>; /* 960ps */
   rxdv-skew-ps = <420>; /* 0ps */
   rxc-skew-ps = <1680>; /* 780ps */

   max-frame-size = <3800>;
};

&mmc0 {
   vmmc-supply = <&regulator_3_3v>;
   vqmmc-supply = <&regulator_3_3v>;
};

&uart0 {
   status = "okay";
};

&usb1 {
   status = "okay";
};

You will notice that this top level DTS file includes socfpga_cyclone5.dtsi. You can find that file at "arch/arm/boot/dts/socfpga_cyclone5.dtsi" in the kernel source tree. The socfpga_cyclone5.dtsi file is a tiny file that contains only a handful of device tree tweaks, but it further includes socfpga.dtsi. You can find that file at "arch/arm/boot/dts/socfpga.dtsi" in the kernel source tree. The socfpga.dtsi file is a large file that contains the entire definition for the HPS hard peripherals in the Altera SoC device. All of the hard peripherals which may be optionally used in any given design are defined with their "status" property set to "disabled", so if you observe the device tree files that were defined prior to including this fundamental file you will see that they are pretty simple and the one thing that they do is enable the peripherals that they require by setting the "status" properity to "enabled" on the peripherals that are required for that development board. The socfpga.dtsi further includes the skeleton.dtsi file which provides the ultimate top level device tree definition for us. You can find that file at "arch/arm/boot/dts/skeleton.dtsi" in the kernel source tree. So by defining the top level DTS file that we showed above, we easily include all of the well tested and upstreamed contents of the Altera socfpga device tree definitions for the hardend HPS peripheral set.

What's missing from the above template?

What about the FPGA peripherals?

In this release of the SoC Workshop Series we chose to deploy the dynamic device tree overlay functionality and leverage the newly upstreamed support for "FPGA regions". You can find information on the new "FPGA Regions" framework at "Documentation/devicetree/bindings/fpga/fpga-region.txt" in the kernel source tree. FPGA regions allow us to define our FPGA resources in a separate device tree overlay file which gets dynamically appended to the live device tree at run time once our FPGA image has been configured into the FPGA fabric. The DTS file above provides the "base" device tree for our system, and that will be loaded at startup by the kernel. This section of that device tree is where we will dynamically extend the live device tree once the FPGA configuration is complete:

      base_fpga_region: base-fpga-region {
         compatible = "fpga-region";
         fpga-mgr = <&fpga_mgr0>;
         fpga-bridges = <&fpga_bridge0>, <&fpga_bridge1>,
               <&fpga_bridge2>, <&fpga_bridge3>;

         #address-cells = <0x2>;
         #size-cells = <0x1>;
         ranges = <0x00000000 0x00000000 0xc0000000 0x20000000>,
            <0x00000001 0x00000000 0xff200000 0x00200000>;
      };

The definition of our FPGA subsystem is provided in another DTS file that is compiled and placed into the rootfs for our system. In this lab example the rootfs is provided in the "../rootfs.cpio.gz" file that we linked into the kernel above as an initramfs root file system. When the target is running you can see the compiled device tree blob for our FPGA overlay in "/lib/firmware/socfpga_cyclone5_socwks_fpga_overlay.dtb". The firmware blob gets loaded by the init script at "/etc/init.d/S50devicetree_overlay" on the target system. The source for our FPGA DTS looks like this:

/*
 * Copyright Altera Corporation (C) 2015. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

 /dts-v1/ /plugin/;
/ {

   fragment@0 {
      target-path = "/soc/base-fpga-region";

      #address-cells = <2>;
      #size-cells = <1>;
      __overlay__ {
         #address-cells = <2>;
         #size-cells = <1>;

         external-fpga-config;         

         sysid_qsys: sysid@0x100001000 {
            compatible = "altr,sysid-16.0", "altr,sysid-1.0";
            reg = <0x00000001 0x00001000 0x00000008>;
            clocks = <&clk_0>;
            id = <2899645442>;
            timestamp = <1460474164>;
         };

         validator_subsys_0: validator@0x100010000 {
            compatible = "demo,validator-1.0", "demo,validator-1.0";
            reg = <0x00000001 0x00010000 0x00000400>;
            clocks = <&clk_0>;
         };

         demo_driver_subsys_0: driver@0x100030000 {
            compatible = "demo,driver-1.0", "demo,driver-1.0";
            reg = <0x00000001 0x00030000 0x00001000>;
            interrupts = <0 48 4>;
            clocks = <&clk_0>;
         }; 

         fft_sub_sgdma_from_fft: msgdma@0x1000a0000 {
            compatible = "altr,msgdma-16.0", "altr,msgdma-1.0";
            reg = <0x00000001 0x000a0000 0x00000020>,
               <0x00000001 0x000b0000 0x00000010>;
            reg-names = "csr", "descriptor_slave";
            interrupts = <0 43 4>;
            clocks = <&fft_sub_clk_0>;
         };

         fft_sub_sgdma_to_fft: msgdma@0x100080000 {
            compatible = "altr,msgdma-16.0", "altr,msgdma-1.0";
            reg = <0x00000001 0x00080000 0x00000020>,
               <0x00000001 0x00090000 0x00000010>;
            reg-names = "csr", "descriptor_slave";
            interrupts = <0 44 4>;
            clocks = <&fft_sub_clk_0>;
         }; 

         fft_sub_FFT_STadapter_0: fft_stadapter@0x1000d0000 {
            compatible = "altr,fft_stadapter-1.1", "altr,fft_stadapter";
            reg = <0x00000001 0x000d0000 0x00000010>;
            clocks = <&fft_sub_clk_0>;
         };          

         memcpy_msgdma: msgdma@0x100020000 {
            compatible = "demo,memcpy_msgdma";
            reg = <0x00000001 0x00020000 0x00000020>,
               <0x00000001 0x00020020 0x00000010>;
            reg-names = "csr", "descriptor_slave";
            interrupts = <0 47 4>;
            clocks = <&clk_0>;
         };    

         fifo_0: fifo@0x100040020 {
            compatible = "ALTR,fifo-16.0", "ALTR,fifo-1.0";
            reg = <0x00000001 0x00040020 0x00000004>,
               <0x00000001 0x00040030 0x00000004>,
               <0x00000001 0x00040000 0x00000020>;
            reg-names = "in", "out", "in_csr";
            clocks = <&clk_0>;
         }; 

         fifo_1: fifo@0x100044020 {
            compatible = "ALTR,fifo-16.0", "ALTR,fifo-1.0";
            reg = <0x00000001 0x00044020 0x00000004>,
               <0x00000001 0x00044030 0x00000004>,
               <0x00000001 0x00044000 0x00000020>;
            reg-names = "in", "out", "in_csr";
            clocks = <&clk_0>;
         }; 

         fifo_2: fifo@0x100048020 {
            compatible = "ALTR,fifo-16.0", "ALTR,fifo-1.0";
            reg = <0x00000001 0x00048020 0x00000004>,
               <0x00000001 0x00048030 0x00000004>,
               <0x00000001 0x00048000 0x00000020>;
            reg-names = "in", "out", "in_csr";
            clocks = <&clk_0>;
         };          

      };

   };
};

For more information on the device tree overlay framework please refer to the documentation at "Documentation/devicetree/configfs-overlays.txt" and "Documentation/devicetree/overlay-notes.txt" in the kernel source tree.

OK, now let's build the device tree...

  • Locate the device tree template for your specific development board in the devicetree directory in the WS2-IntroToLinux directory
WS2-Lab3-3.png

  • Copy your device tree template into the kernel source tree

[linux-socfpga]$ cp ../devicetrees/<your-dev-board>.dts arch/arm/boot/dts/

  • Now make the device tree blob

[linux-socfpga]$ make ARCH=arm CONFIG_DTB_SOURCE=arch/arm/boot/dts/<your-dev-board>.dts <your-dev-board>.dtb

Once you have successfully compiled the kernel and device tree, copy them both onto the SD card.

  • Insert SD card into your PC
  • Copy the compressed kernel image, arch/arm/boot/zImage, to the top of the FAT partition on your SD card
  • Copy the device tree blob, arch/arm/boot/dts/.dtb, to the top of the FAT partition on your SD card
    • You must name the DTB file soc_system.dtb on the SD card
WS2-Lab3-4.png

  • Return the SD card to your board and power up the board

You should see the kernel boot to the Linux prompt. Next you will bring this all together by building your own SD card image.

Proceed to Workshop 2 Lab 4: Building an SD Card >>>>>>>>>>

<<<<<<<<<< Return to WS 2 Lab 2: U-Boot

© 1999-2024 RocketBoards.org by the contributing authors. All material on this collaboration platform is the property of the contributing authors.

Privacy Policy - Terms Of Use

This website is using cookies. More info. That's Fine