Patching Kernel in OpenEmbedded

Thursday, January 19, 2017
Linux
Introduction
Despite OpenEmbedded/Yocto being nice tools to generate your image, using the build system to compile and test tiny alterations applied to independent packages, although possible, can become confusing and slow. My suggestion to alter the kernel is to compile it separately, test all the changes made by the end of the project, and add the changes to OpenEmbedded/Yocto.
To illustrate the process, we will add support to the inertial measurement unit mma8653 accelerometer by NXP (formerly Freescale) to the kernel 4.4.14 used by the Toradex computer on module Colibri VF61.
Procedure
The first thing to do is to have OpenEmbedded and its prerequisites installed. You can follow this article's prerequisites and installation sections to do so.
In order to find where and which kernel is being used for your target, you can first find the recipes for the kernels used by different targets. You can also find this information in this post.
cd stuff
find . -wholename "*recipes-kernel/linux*.bb"
Among the results, the ones we are interested in are inside the folder meta-toradex/recipes-kernel/linux/. The result of looking inside the directory is presented in image 1:
Page where a new repo is created
Image 1: looking into the meta-toradex/recipes-kernel/linux/ directory
Notice that there are many kernel versions. To find out which target uses which kernel, do the following command inside the directory. The result is shown in Image 2:
grep -nre "COMPATIBLE_MACHINE" *
Commands for synchronization
Image 2: kernel recipes and their respective targets
Notice that some targets can use more than one kernel recipe. To quickly know which recipe is being used by the target you are working with, go to the build directory and run bitbake for your kernel recipe, which is the linux-toradex recipe for our specific case. Look carefully while it runs and you will see which recipe is being used, as illustrated in image 3 (you might also search for the PREFERRED_PROVIDER_virtual/kernel variable in the recipe for your machine):
bitbake linux-toradex
GitHub repositories tab
Image 3: checking kernel version being used by bitbake, for the current target machine
Now that we know which recipe is being used, let's open it and have a look. Below is the content of the file stuff/meta-toradex/recipes-kernel/linux/linux-toradex_4.4.bb:
require recipes-kernel/linux/linux-imx.inc
require recipes-kernel/linux/linux-dtb.inc
 
SUMMARY = "Linux kernel for Toradex Colibri VFxx Computer on Modules"
 
SRC_URI = "git://git.toradex.com/linux-toradex.git;protocol=git;branch=${SRCBRANCH} \
                      file://defconfig"
 
KERNEL_MODULE_AUTOLOAD += "${@bb.utils.contains('COMBINED_FEATURES', 'usbgadget', ' libcomposite', '',d)}"
 
LOCALVERSION = "-v2.6b2"
SRCBRANCH = "toradex_vf_4.4"
SRCREV = "efe965a5dad66bd14219cdc9474ea75eda783456"
DEPENDS += "lzop-native bc-native"
COMPATIBLE_MACHINE = "(vf)"
We are interested in the SRC_URI, SRCBRANCH and SRCREV variables. The SRC_URI specifies from where the kernel source code should be fetched and which configuration file should be used. The SRCBRANCH is the branch of the git repository pointed in the SRC_URI variable. The SRCREV points to the commit being used for that branch.
Let's clone the same branch to our host machine and then see the last 5 commits made. The result is presented in Image 4:
git clone -b 2015.04-toradex git://git.toradex.com/linux-toradex.git
 
git log -5 --pretty=oneline
GitHub repositories tab
Image 4: kernel source last five commits
You need to go to the branch that has the same commit that OpenEmbedded is using. The commit hash is found in the SRCREV variable (it starts with efe...) is the same as the one in the SRCREV variable of the recipe. You could use a command such as git branch --contains<githash> find it. Make sure you are in the correct branch before proceeding. You can create a new branch to make the changes:
git branch -b toradex_vf_4.4_mydev <githash>
Making changes and adding them to OpenEmbedded
For this article example, the driver for the accelerometer mma8653 will be enabled, as well as the device will be added to the target device tree.
First of all, load the default configuration for the target machine:
export ARCH=arm
make colibri_vf_defconfig
Then, configure the kernel and modify its source code as you wish. In order to enable the accelerometer driver, menuconfig will be used, as illustrated in the command below and in Image 5:
make menuconfig
GitHub repositories tab
Image 5: enabling the kernel driver for the mma8452Q accelerometer (compatible with mma8653)
In order to save the changes to a new file, do the following:
make savedefconfig
The current target configuration will be saved in a file called defconfig. In order to check what has changed between after and before, let's compare the configuration file with the backup we made be-fore. The result is displayed in Image 6:
meld defconfig arch/arm/configs/colibri_vf_defconfig
GitHub repositories tab
Image 6: difference between before and after enabling the mma8452 driver
Notice that the only change is that CONFIG_MMA8452 is now set. Let's save the new defconfig file:
mv defconfig arch/arm/configs/colibri_vf_mma_8653_defconfig
The device tree also needs some changes. Open the file arch/arm/boot/dts/vf-colibri-eval-v3.dtsi and modify the &i2c0 node (line 127) as presented below. Notice that the Red portion is the one to be added to the file:
&i2c0 {
        status = "okay";

        /* TouchRevolution Fusion 7 and 10 multi-touch controller */
        touch: touchrevf0710a@10 {
                compatible = "touchrevolution,fusion-f0710a";
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_gpiotouch>;
                reg = <0x10>;
                gpios = <&gpio0 30 GPIO_ACTIVE_HIGH /* SO-DIMM 28, Pen down interrupt */
                               &gpio0 23 GPIO_ACTIVE_LOW /* SO-DIMM 30, Reset interrupt */
                               >;
                status = "disabled";
        };

        /* M41T0M6 real time clock on carrier board */
        rtc: m41t0m6@68 {
                compatible = "st,m41t00";
                reg = <0x68>;
        };

        mma8453fc@1d {
                compatible = "fsl,mma8653";
                reg = <0x1d>;
                pinctrl-0 = <&pinctrl_mma>;
                interrupt-parent = <&gpio1>;
                interrupts = <9 0>;
        };

};
Also, add the below portion of code. It must be put inside the &iomuxc node, in the end of the file. More information about device-tree customization can be found in this article from the developer website.
pinctrl_mma: mma {
                        fsl,pins = <
                                VF610_PAD_PTB19__GPIO_41        0x22ed
                        > ;
                };
Commit your changes and create a patch file from them:
git commit -m "mma8653 accelerometer"
git format-patch --signoff HEAD~1
If you have multiple commits, create multiple files by changing the number 1 above to the number of commits you made.
In order to add the changes to OpenEmbedded, copy both the patch and the defconfig file to the folder that correspond to your recipe:
cp 0001-mma8653-accelerometer.patch /home/prjs/oe-core/stuff/meta-toradex/recipes-kernel/linux/linux-toradex-4.4/
 
cp arch/arm/configs/colibri_vf_mma8653 /home/prjs/oe-core/stuff/meta-toradex/recipes-kernel/linux/linux-toradex-4.4/defconfig
Edit the recipe to apply the patch, by adding its file to the SRC_URI variable:
SRC_URI = "git://git.toradex.com/linux-toradex.git;protocol=git;branch=${SRCBRANCH} \
                      file://0001-mma8653-accelerometer.patch \
                      file://defconfig"
Then finally compile the kernel:
bitbake -c clean linux-toradex
bitbake virtual/kernel
The kernel image and device tree will be deployed at out-glibc/deploy/images/colibri-vf/, as illustrated in image 7. You may deploy them to the target by following the kernel update section from this article.
GitHub repositories tab
Image 7: kernel image, compiled modules and device tree
Conclusion
As it was said in the introduction, compiling the kernel inside of the build system is possible, although a bit confusing. There are commands that enable it, but it is required good knowledge regarding OpenEmbedded/Yocto to be sure about what is really being made.
The idea of this post is to show that it is possible to isolate the problems by compiling and personalizing the kernel outside of the build system. Hope you found this post useful, see you next time!
Author: Leonardo Graboski Veiga, Toradex Brasil

Comments

Popular posts from this blog

Toradex WinCE Libraries' Evolution: The New Library Approach Explained

Customizable Embedded 3D Surround View Turn-Key Solution on Apalis iMX6 SoM