Booting a recent U-boot and Linux kernel on
ARM Versatile Juno Development Platform
as per 2015-12-03 (Kernel 4.4)

Juno Versatile Express box

Preparations

Terminology: uploading in this article goes from your development host (PC, laptop whatever) to the target system/board. Some people talk about "downloading to the target" and such silly stuff, I find that totally confusing especially since the terminal (minicom) will have all its terminology reversed, as it is equipped for downloading and uploading to other servers. The target system can be imagined as some server if it helps you. We will upload to it. Enough said, live with it.

Create a directory for your aarch64 work if you wanna clone my setup:

mkdir aarch64

Getting a Cross Compiler for AArch64

For compiling the U-Boot, kernel and root filesystem you can just use the latest Linaro AArch64 GCC toolchain I'm using linaro-toolchain-binaries 4.9 2014.11 (Aarch64 little-endian) for Linux as of writing.

Serial Terminal

Install minicom. In Fedora it's simply dnf -y install minicom and you're done with it.

Setup minicom, I just use this terminal program out of habit:

U-boot

Compiling U-Boot

  1. Clone a u-boot from the upstream U-Boot git (all changes needed to make U-Boot work on the Juno are now upstream on the master branch):
    cd /home/user/aarch64
    git clone git://git.denx.de/u-boot.git
    cd u-boot
    
  2. Configure and build the shebang for Juno, use my juno-uboot.mak makefile (download and save it in the u-boot dir) to build it like this: make -f juno-uboot.mak build if you're not doing this then you can just see what my makefile does and replicate the setup with a script or manually or whatever suit you, this is just what I prefer to do. Makefiles are nice. Bonus: if you like to use the FVP fastmodel, there is also a fvp-uboot.mak
  3. Make sure that u-boot-juno.bin appears in your output directory (in my makefile that is /home/user/aarch64)

Bonus: my patch to get low-level debug prints akin to Linux' earlyprints helped me debug and get Juno U-Boot in shape.

Precompiled U-Boot

To skip all U-boot business just download my pre-compiled U-Boot: and use it. It's usually pretty up-to-date, else push me about it. These are compiled to be started from SDRAM memory at 0xe0000000

Building an fip.bin with U-Boot in it

First: make sure you can rebuild ARM Trusted Firmware as described in the ARM Trusted Firmware user guide. This is not optional if you want to do U-Boot development, you have to have this setup to create flash images that boot on the Juno. I usually just clone the ARM open firmware git into my /home/user/aarch64 working directory and work from there.

What you want to do is to create bl1.bin and fip.bin files where the latter contains a U-Boot image rather than (U)EFI as is common. Do this by specifying the u-boot-juno.bin file as BL33 (boot level 3, step 3) executable.

My build-tf.mak makefile usually does this when used inside the arm trusted firmware tree. If it doesn't work for you, hack the build until it works.

As a bonus, the Juno contains a power management firmware, SCP. This needs to be kept in sync with the ARM Trusted Firmware, or they will refuse to boot. Thes SCP firmwares are found in Ryan Harkins GIT repository.

Precompiled BL1 and FIP

These are sporadically updated bl1 and fip images that can be used as reference, or if you "just wanna run U-boot". If flashed onto the Juno as described below they should work.

Flashing U-Boot to the Juno board

Kernel

A stock Linux kernel v3.19-rc6 or later should boot just fine on the Juno board.

When I build kernels I use this aarch64.mak makefile, like this: make -f aarch64.mak config && make -f aarch64.mak build - it is mainly a way to automate things. It may try (and may fail) to build an experimental U-Boot type uImage as well but disregard that if it doesn't work.

You need an external root filesystem or my homebrew initramfs root filesystem to attach to the kernel when building it if you wanna get to prompt. See below.

Root Filesystem

By default, the kernel is built without a root file system. It is assumed on boot that the USB stick on the flip side of the Juno board will contain a root filesystem. U-Boot will instruct the kernel to mount and boot using this root filesystem by passing the command line switch root=/dev/sda1 rw rootwait. In later U-Boots this may be set to /dev/sda2 as that is custom with many distributions that assume the machine has no flash, so they put the kernel and device tree (or similar) on the first partition.

If you rather prefer to bake the root filesystem into the kernel using the initramfs mechanism (which means the root filesystem is attached at the end of the kernel) my Aarch64 initramfs rootfs image is downloadable from the link. This should be put in the apropriate place to be attached to the kernel image, I just put it in my /home/user/aarch64 directory.

Notice that when you use an initramfs, the kernel will become quite big, around 14MiB, which means the the resulting raw Image will not fit in the internal flash of the Juno, so you probably only want to use this method if you're booting over TFTP.

If you're interested, here is the script I actually use to generate that root filesystem. It's a bit tricky to use and require some extra files.

It is possible to put the Busybox-based initramfs on a USB stick if you prefer, boot the kernel and mount root from it. Then do like this:

Creating an ArchLinux root filesystem

I use this simple distribution to quickly get some prebuilt software to test. There is a sparse support page over at ARM ArchLinux. I prepare it on a USB stick like this:

Prebuilt kernel Image

The version number indicates the version of the Linux kernel used on each build.

Prebuilt device tree

This is basically just the latest device tree compiled from the upstream Linux kernel arch/arm64/boot/dts/arm/juno.dts.

juno.dtb

Uploading and booting a Linux kernel

Default boot from NOR Flash

This is the default boot procedure and what will happen if you do nothing when U-Boot comes up. Juno U-Boot is pre-configured to load the kernel and DTB files from NOR flash on the Juno board and put them into DRAM memory.

The layout of the NOR flash is determined from the AFS image format, and images are loaded by name. The uncompressed kernel image named Image will be loaded to address 0x80000000 in DRAM, and the device tree image named juno will be loaded to address 0x83000000 in DRAM and it will then be booted using the command booti 0x80000000 - 0x83000000.

Using serial port

To upload a kernel using the now running U-boot using ymodem on the serial port only:

  1. Interrupt the default boot process by hitting ENTER when the U-Boot boot delay is seen
  2. Type loady 0x80000000 at the U-Boot prompt to start the ymodem protocol parser in U-Boot and upload a file to 0x80000000
  3. In minicom type Control-AS to access the upload feature
  4. Select ymodem
  5. Select your compiled Image file with arrow keys and hit space
  6. Hit Enter on Okay
  7. Wait for a long time while the kernel uploads to target...
  8. Hit Enter to return to the U-Boot prompt
  9. Type loady 0x83000000 at the U-Boot prompt to start the ymodem protocol parser and upload a second file to 0x83000000
  10. In minicom type Control-AS to access the upload feature
  11. Select your compiled juno.dtb file with arrow keys and hit space
  12. Hit Enter on Okay
  13. Wait for a short time while the kernel uploads the little device tree blob to target...
  14. Hit Enter to return to the U-Boot prompt
  15. Type booti 0x80000000 - 0x83000000 (boot from memory) as you can see giving the Image and device tree blob as arguments and hope for the best...

Using TFTP over Ethernet

  1. Set up a TFTP server
  2. Put the Image and juno.dtb file in the TFTP server base directory
  3. Get an IP number on you local network for the system
  4. Interrupt the default boot process by hitting ENTER when the U-Boot boot delay is seen
  5. Issue the following command line, substituting the right IP numbers for your local network server and system IP:
    set serverip 192.168.1.32 ; set ipaddr 192.168.1.35 ; tftpboot 0x80000000 Image ; tftpboot 0x83000000 juno.dtb ; booti 0x80000000 - 0x83000000