How to Install Ubuntu and Run a Mainline Kernel on an ODROID-XU4

I recently installed Ubuntu 15.10 on Odroid-XU4 and set out to run the upstream kernel on it. After several trials and errors and being forced to reference various forums, I now have Odroid running the Linux 4.6 Kernel. In this article, I will share how to quickly get from unboxing to running the latest kernel with a short detour to upgrade to the Ubuntu 16.04 release.

Without further ado, let’s get started. First of all, download the Ubuntu 15.10 image. You can find the release notes and self installing image here:

Prepare the microSD Card

Once you’ve downloaded the image from the 2nd link above, follow the following steps to create a bootable microSD card with the image; I used a 32 GB Samsung microSD card. Insert the microSD card in its SD card adapter case in the SD card slot on your host PC or laptop. Please note that SD card will likely be auto-mounted. Check for the device files and unmount all partitions as needed. If this a brand new SD card you don’t have to worry about this step.

Uncompress the image:

$ tar -unxz ubuntu-15.10-mate-odroid-xu3-20160114.img.xz

Prepare microSD – Insert SD Card and look for auto-mounted partitions:

$ df -h
/dev/mmcblk0p2 30G 8.3G 21G 29% /media/shuah/rootfs
/dev/mmcblk0p1 128M 20M 108M 16% /media/shuah/boot

Check device files

$ ls /dev/mmcblk*

First unmount the auto-mounted partitions:

$ umount /dev/mmcblk0p1
$ umount /dev/mmcblk0p2

Erase microSD card (the following writes ~8192 4M blocks to erase the entire disk):

$ dd if=/dev/zero of=/dev/mmcblk0 count=8192 bs=4M

Copy self installing image to microSD Card:

$ dd if=ubuntu-15.10-mate-odroid-xu3-20160114.img of=/dev/mmcblk0

Get Your ODROID-XU4 Up and Running

Now you are ready to use the microSD to boot the self install image. Insert the microSD card in the microSD slot in the Odroid.  Make sure Boot Select Switch is in the correct position to enable microSD as the boot device.

Hopefully you have a the USB-UART Module Kit for the Odroid. If you don’t please get one! It is a must for kernel development. Please refer to the ODroid wiki for instructions on how to connect to Odroid serial console port. An alternative option is to simply connect the device’s HDMI to a monitor and hook up a USB keyboard and mouse.

It is time to give your Odroid boot a try. Power up the Odroid and you should see the ALIVE/Blue Starts LED start out solid while in u-boot and quickly go into flashing mode when kernel starts running. At this point, sit back and relax, the Ubuntu self-install image will boot and complete the instalation. If all goes well, the ALIVE/Blue Status LED continues to flash and you will see boot messages on the console and Odroid login appear on the monitor. During the install, an boot partition will be made with a rootfs being placed on the remaining space. There is ample room in the boot partition for a few kernel images. You will notice that the boot partition is auto-mounted at /media/boot.

The Ubuntu 15.10 image is complete with all the development tools except for the liveboot package. We will talk about this later. Login is odroid and password is odroid. Start the Software Updater and pull in any updates. You will have the opportunity to upgrade to 16.04. If you do upgrade, please keep in mind that you will have to bring in new video driver to get GUI working on 16.04. Please refer to GUI after upgrade to Ubuntu 16.04 on XU4. The following is a distilled list of commands that worked for me.

$ sudo apt-add-repository ppa:canonical-x/x-staging
$ sudo apt-get update
$ sudo apt-get purge xserver-xorg-video-armsoc*
$ sudo apt-get install xserver-xorg-video-armsoc-exynos

Once the above step is done, power down completely (don’t choose restart). Please note that when the HDMI is connected, the HDMI return power supplies enough power for Odroid’s PWR Status LED to stay on. Please disconnect HDMI to ensure the Ordroid is completely powered down before powering it back up. Please don’t insert and/or remove microSD while the PWR Status LED is on. Once the PWR Status is off, it safe to power on the Odroid. At this point with the GUI should be working. Please note: If you have problems with fonts not rendering properly, click “System” in the top left corner of the screen and go to Preferences >> Appearance; then, select the Fonts tab and choose “Subpixel smoothing” in the Rendering section.

Build the Mainline Kernel

Now we are ready to build, install, and boot mainline kernels. The latest linux-next is a good repo to use. I will describe what I needed to do build, install and run kernel based on this repo.  I would recommend doing a native build on Odroid as it is fast enough and worked well for me. I built kernels with and without CONFIG_EXYNOS_IOMMU enabled. Contiguous Memory Allocation (CMA) is the default  mode for memory allocation. When IOMMU is enabled, non-contiguous memory is allocated using Exynos IOMMU hardware. Both flavors worked for me.

Clone the linux-next git repo (do this on the XU4 if you want to do a native kernel build on the Odroid):

$ git clone git:// linux_odroid

Move into the new linux_odroid directory,  generate the config, prepare modules, and build: (Please note: If you like to enable IOMMU, apply the following patch or edit arch/arm/configs/exynos_defconfig to add the CONFIG_EXYNOS_IOMMU=y , and then run make exynos_defconfig)

diff --git a/arch/arm/configs/exynos_defconfig b/arch/arm/configs/exynos_defconfig
index daf9762..76127dc 100644
--- a/arch/arm/configs/exynos_defconfig
+++ b/arch/arm/configs/exynos_defconfig
@@ -218,6 +218,7 @@ CONFIG_CROS_EC_CHARDEV=y
$ cd linux_odroid
$ make exynos_defconfig
$ make prepare modules_prepare
$ make -j6 bzImage modules dtbs

Copy .dtb to /media/boot – don’t overwrite the old one, if one exists.

sudo cp arch/arm/boot/dts/exynos5422-odroidxu4.dtb /media/boot/exynos5422-odroidxu4_next.dtb

Copy zImage to /media/boot – don’t overwrite the old one.

$ sudo cp arch/arm/boot/zImage /media/boot/zImage_next

Install modules – will be installed under /lib/modules

$ sudo make modules_install

Install live-boot:

Without live-boot, initramfs will not have live support and kernel won’t boot. You have only once when the first kernel is built.

$ sudo apt-get install live-boot

Update Initramfs:

Backup everything in /media/boot to a back-up directory, just in case you run into problems. All of the remaining steps need to be run with super user privileges. Copy the current .config to  /boot, and then run update-initramfs.

Note: you should run cat include/config/kernel.release separately and copy/paste the results where it is used in the next commands.

$ cp .config /boot/config-`cat include/config/kernel.release`
$ update-initramfs -c -k `cat include/config/kernel.release`
$ mkimage -A arm -O linux -T ramdisk -C none -a 0 -e 0 -n uInitrd -d /boot/initrd.img-`cat include/config/kernel.release` /boot/uInitrd-`cat include/config/kernel.release`

Copy new uInitrd to /media/boot:

$ cp /boot/uInitrd-`cat include/config/kernel.release` /media/boot/

Now comes the important step to change the boot.ini to boot the new kernel. Edit /media/boot/boot.ini and comment out the following line:

#setenv bootcmd "fatload mmc 0:1 0x40008000 zImage; fatload mmc 0:1 0x42000000 uInitrd; fatload mmc 0:1 0x44000000 exynos5422-odroidxu3.dtb; bootz 0x40008000 0x42000000 0x44000000"

Past the new bootcmd line point to new zImage, uInitrd, and dtb files after the line you just commented out:

setenv bootcmd "fatload mmc 0:1 0x40008000 zImage_next; fatload mmc 0:1 0x42000000 uInitrd-4.7.0-rc2-next-20160608; fatload mmc 0:1 0x44000000 exynos5422-odroidxu4_next.dtb; bootz 0x40008000 0x42000000 0x44000000"

We are now at the final step. Run sync and then power the device down and power back up. Please remember to disconnect HDMI so it doesn’t continue to supply power.

$ sync; poweroff

You should have the newly built zImage running when Odroid boots up. uname -a should show that the Linux odroid 4.7.0-rc2-next-20160608 is running.

Please watch out for the following in the dmesg:

FAT-fs (mmcblk1p1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.

Adding new kernel files (zImage, uInitrd, and exynos5422-odroidxu4.dtb), and changing boot.ini work just fine on the boot partition /dev/mmcblk1p1. If you were to remove files, please make sure to run fsck on this device. Run the following as root, if you don’t the system won’t boot and it will hang, unable to load the uInitrd.

umount /dev/mmcblk1p1
fsck /dev/mmcblk1p1
mount /dev/mmcblk1p1 /media/boot

There are a few issues I’m still working to solve. Chromium included in the Ubuntu 16.04 release doesn’t work and needs to be downgraded to rev 48.0. After the downgrade, Chromium starts, but dies right away. This is a work in progress at the moment. Otherwise, configuring and getting mainline kernel booting on Odroid-xu4 has been fun, and I hope you find this guide to be valuable.

Author: Shuah Khan

Shuah contributes to multiple aspects of the Linux Kernel, and she maintains the Kernel Selftest framework.

21 thoughts on “How to Install Ubuntu and Run a Mainline Kernel on an ODROID-XU4”

  1. Shuah,
    thanks for this great guide -your comments regarding many issues, like power off without HDMI and so on- are really apreciated. I was aware of some of these, but is nice to hear that someone else confirmed it.

    @wildcats_paris from ARMBIAN forum told me to check your guide, affter the short one posted in tweter by your friend @Luisbg didn’t work -let’s say for me-. We will be very happy if you share with the community your advantages on this matter.

    Hopefully we get more such interesting XU4 feedbacks!


  2. What a wonderful HowTo. I tried building my own kernel several times, but some keys-points were missing. Now it worked right out of the box. Thank you !

  3. If you go to mainline kernel and 16.04, is the OpenGL ES acceleration working ? And ideally working better than in default image ? (OpenGL ES windowed mode is abysmal …)

    1. I haven’t tried OpenGL ES acceleration on Odroid-xu4 yet. Please feel free elaborate on what you have tried so far. Is it worse than Oxroid-xu3?

      1. I only tried the official kernel from odroid so far.

        wrt to OpenGL-ES perf, this was a general comment. The problem is that there is a missing link between the 3D (Mali) and the actual display on-screen. The 3D engine only outputs the image to an offscreen buffer and then that buffer has to actually be copied to the displayed framebuffer to show it. Ideally on the Exynos, you’d want that copy to be HW accelerated using the G2D, unfortunately there is no code that does that. So you end up with a fast 3D engine that renders off-screen quickly and is then blitted on the frame buffer via a ‘memcpy’ at incredibly slow speeds …

        ARM provides the skeleton xf86-video-armsoc but that driver is only a skeleton that doesn’t accelerate anything and must be “filled-in” by the SoC vendor to use whatever 2D acceleration they have on the chip (the G2D here), but nobody has done that. The one used in the odroid is purely relying on software blitting / filling. ( don’t be fooled by the package name xserver-xorg-video-armsoc-exynos the exynos here is purely how to drive the DRM/KMS but doesn’t do any acceleration )

        I’ve actually just found an effort to write such a G2D accelerated xf86-video-armsoc ( ) but it’s currently targeted at the “older” U3 and the author has his own updated 4.5 kernel tree because this driver depends on newer code / interfaces / bug fixes in the G2D DRM driver that are not on the XU4 3.10 tree from hardkernel.

        So being able to run a recent kernel with all those DRM improvements to the G2D driver would potentially allow to use that G2D accelerated armsoc driver and provide a great perf boost ( glmark2 Score: 258 with accel vs 53 without during a preliminary test ! ).

        But that implies having mali driver … which is not in mainline and so needs to be patched in. Question is does that patch exist ?
        Same question for other features : what are the limitation of mainline ? Is BIG.little / HMP working ?

      2. Well there you go … no mali support at all in mainline and the “source” published by ARM are not complete, you need some SoC / platform code and AFAIK that just doesn’t exist for mainline kernel. So no mali makes it a bit useless …

  4. Your guide was pretty great, explanations were great :) Definitely learned a few things, thanks for taking the time to make this.

    At that, after following your guide I lost HDMI output, I’m using this one Other than your guide I also enabled DisplayLink support with make menuconfig. I also changed a few settings in the boot.ini file but no dice.

    Any ideas on what might be causing an issue?

  5. Hi, Thank you very much for this useful guide. I was wondering if MFC encoder and I2C work using this kernel. And what are the advantages of this kernel versus the official 3.10 kernel provided by odroid?

    1. I haven’t played with MFC encoder on it. As per advantages over 3.10, it depends on your use-case. I am using the Odroid XU4 for kernel development. Depending on your use-case, you might be just fine with 3.10 kernel.

  6. after I followed the instruction here and rebooted the odroid would be stuck at this line on boot

    random: crng init done

    Do you know what could be the issue here?

    1. Looks like it can’t mount the rootfs. Please see dmesg from a good boot.

      [ 4.773544] r8152 5-1:1.0 eth0: v1.08.6
      [ 5.203080] r8152 5-1:1.0 enx001e0630385e: renamed from eth0
      [ 5.281049] random: crng init done
      [ 5.336678] EXT4-fs (mmcblk1p2): mounted filesystem without journal. Opts: (null)

      Please check to see if your /media/boot/boot.ini –
      setenv bootrootfs
      setenv bootcmd

      are correct. You don’t have to touch the setenv bootrootfs and have to update setenv bootcmd to point to the right uInitrd. Also, run fsck to make sure there are no errors on the MicroSD.

  7. Dear Shuah Khan,
    Fuirst of all thanks a lot for the wonderful documentation.
    I am using ODROID XU4 and I followed each and every instructions you have written for Kernle compilation. Unfortunately after the kernel update, my ODROID XU4 is not booting at all. but nothing comes up after complete power down and power up but The blue light is flashing. My humble request to help me in this reagrd.
    Thanks in advance for your help!!

  8. one more thing to share:
    If i switch my setenv bootcmd to old one… odroid boots but then it will get stuck at “freeing unsued kernel” then after sometime

    1. Do you have serial console connected? It is possible, your boot partition git corrupted. Running fsck will help. Stating the obvious, you will have to run fsck on a different system. I think you are running into an early boot issue, it will be lot easier to debug if you have serial console.

      1. Dear Shuah Khan,
        Thanks a ton for your guidence :)
        As you said, with serial console, the new kernel is running and it’s good.
        But it doesnt work with HDMI. I request you to give any suggestions as to how can proceed for a solution to work with HDMI.
        Thanks a lot again :)

  9. am following your description to produce a bootable SD-Card (it’s a 8 GB Class 10).
    dd if=/dev/zero of=/dev/sdj1 count=8192 bs=4M
    dd if=ubuntu-15.10-mate-odroid-xu3-20160114.img of=/dev/sdj1
    Now calling fdisk /dev/sdj1 and what I see is that :
    /dev/sdj1 8192 15597567 15589376 7,4G b W95 FAT32
    I cannot see a linux-Partition. Is anything wrong here ? Or how I have to prepair the microSD-Card ?
    Would be very grateful do help.
    Thank you very much

    1. hans, the “of” you’ve selected is the first partition of sdj – presumably the SD-card you want to write to. However, you need to write to the SD-card directly (you will loose ALL data on that device!). So, assuming that your sd-card is on /dev/sdj, “dd if=ubuntu-15.10-mate-odroid-xu3-20160114.img of=/dev/sdj” should do the trick. By the way, the zeroing you did is just to wipe any previously written data, also, you’ve supplied dd with a count and a blocksize … so it’ll copy 8192 blocks of 4mbyte size, so that’s 32gbyte. with sdj1 being apparently 8gbyte in size, that command should have produced an error.

Comments are closed.