Rock64: Porting Arch Linux to a new SBC

Rock64

I was looking for a new Single Board Computer (SBC), since my old Raspberry Pi could no longer run MongoDB after they stopped providing packages for 32 bit Linux systems, and its resources were quite heavily utilised anyway. I looked for something with as much RAM as I could get, and came across the Rock64, made by pine64.org:

  • It’s basically a high-powered Raspberry Pi-like Single Board Computer
  • (up to) 4GB RAM!
  • 64 bit
  • GPIOs
  • USB3
  • eMMC storage (expect fewer SD card issues)
  • Gigabit ethernet
  • Rockchip is committed to open source, including mainline kernel support (4.14 looks good for a headless setup), mainline u-boot.

I did expect some downsides:

  • Less mainstream than a Raspberry Pi, plus at the time it was still very new, so I expected some issues
  • Few “official” Linux builds (most releases are built by ayufan, who is doing awesome work)

… However, I also saw the last point of each list as an opportunity – could I port Arch LinuxARM variant to Rock64, and learn more about SBCs and the lower level technology around Linux in the process, without having to do a full board bring up from scratch?

Note that this blog post is written by someone who is not an expert in this specific field, but rather an explorer finding his way around. If you spot anything that’s not quite right or have any other thoughts or comments, please do leave a comment!

Disclaimer: if you decide to follow any instructions in this blog post, you do so at your own risk. I cannot be held responsible for bricked boards or other undesirable events.

Detour: first steps with the (first) new board

Since there already existed some Linux distributions for the Rock64, I figured I should test the board before starting to experiment, just in case. I’m glad I did, because even trying to flash an image from SD to the eMMC flash storage proved to be quite an issue, resulting in kernel panics. When I reached out to the community and later support, the first suspect was the SD card. This was odd, as I bought a high-quality one in original packaging, and the card appeared to work on my desktop PC, but nevertheless, I figured that the only way to exclude that possibility was to flash the eMMC disk directly, without using an SD card at all. At the time, this procedure was documented for Android, but not for flashing Linux images (the Android images have a different structure).

I eventually managed to flash Linux onto the eMMC card using a USB A-A cable (the Pine64 USB-eMMC adapter wasn’t available yet, and shipping costs for the ODROID SD-eMMC one were a bit high). It required systematically building knowledge and finding new approaches at every setback. I read many pages from the Rockchip open source wiki, Google-translated some Chinese PDFs, compiled u-boot & linux kernels, extracted individual partitions from one of ayufan’s images, built and verified GPT partition tables, and learned about the special Rockchip CPU modes for flashing & booting (see tip later). Eventually, I had Linux flashed onto the eMMC storage, but memtester‘s output wasn’t any better.

It turned out that my board had some faulty RAM, i.e. it was practically dead. Thankfully, the makers shipped me a new one under warranty. Nevertheless, the lessons learned here would come in handy later on.

Porting Arch Linux

The new board worked “out of the box” with the Linux distros that I wasn’t having much luck with previously, and by now version 4.14 of the Linux kernel had been published – which was great, since according to Rockchip’s status matrix this should have everything I need for headless operation.

Based on the boot sequence (which also explains the requirements for certain partitions to be at specific offsets), I could identify the required work for porting Arch Linux to the Rock64. So, my plan was to:

  1. Compile u-boot
  2. Either compile ayufan’s kernel, or use the one that comes with Arch Linux ARM (as it’s > v4.14 I’d expect it to contain enough to make the Rock64 work, even if ayufan’s one might be more optimal/compatible)
  3. Use “generic ARMv8” Arch Linux ARM for the root filesystem
  4. Build an image
  5. Boot!

After some manual experimentation to validate individual parts of the plan, I wrote some code to build an image. It basically builds u-boot using ayufan’s scripts (from his linux-build, and linux-u-boot repos). I would’ve preferred using the upstream u-boot, but that doesn’t currently contain a config for the Rock64, so I figured I might as well use ayufan’s. Then, it use guestfish to create an empty image, partition it as required by the RK3328, format the boot and linux-root partitions, and extract the Arch Linux ARM ARMv8 generic tarball into the image (including the kernel). It then adds the u-boot bootloader, extlinux config (which contains the kernel command line args) and apply some small misc changes to the image (e.g. to fix the serial console).

You can find the code in the rock64-arch-linux-build repo. There’s a downloadable image under releases.

Reflection & lessons learned

This exercise has really shown how amazing mainline kernel (and u-boot) support is. Apart from a couple of minor things – like forgetting to mark the boot partition as bootable (causing u-boot to ignore it) and not realising there’s a distinction between filesystem labels and partition labels (which affected the kernel finding the root partition), the process in hindsight wasn’t too bad. I didn’t actually have to write any C code to port Arch Linux to the Rock64. This is simply amazing. As long as nothing breaks for the Rock64 in the mainline kernel, I can just continue pulling updates from Arch Linux ARM (and probably a variety of other distros), without relying on the manufacturer explicitly supporting it.

It’s also worth mentioning that one could find a lot of material on the RK3328 and the Rock64; the companies appear to be fairly open with the documentation they publish, which, while by no means perfect, I still greatly benefited from during this exercise. (see the references section at the end). A chip burdened by lots of NDAs would’ve been a lot harder to work with.

It paid off investing in debugging aids: I’m really glad I spent the 1.99$ on the USB-Serial adapter; it would’ve been a nightmare troubleshooting the issues I had with the first board without it. I should’ve also bought the USB A-A cable from the pine64.org store (it’s very reasonably priced there), and if the 4.99$ USB-MMC adapter had existed when I bought my Rock64, I would’ve bought that, too.

I feel I learned a lot about the Rock64’s booting process and how u-boot, the Linux kernel and the root file system work together, resulting in the Linux environment one enjoys working with. It’s amazing how many ways there are to boot Linux under obscure conditions, although thankfully I didn’t have to venture too far into this territory; I suspect you can load the kernel via kermit over the serial port, and then use the root filesystem via NFS…

Lastly, I think it’s fair to say that the experience of buying a less mainstream but more powerful board was roughly in-line with my expectations. It wasn’t exactly a smooth ride, but I got there in the end, and am now looking forward to using those 4GB of RAM :-).

Below I’ll also share some of the methods I learned, before finishing with some thanks and references.

Methods

Tip: another way to get into Rockchip Mask ROM Mode

The Rockchip chips have a clever flashing mode. This is handy for all those cases where whatever-is-in-your-storage-medium isn’t booting up properly, and it allows flashing the eMMC storage without needing an SD card.

There are actually two modes, “Miniloader Rockusb” and “Mask ROM Mode“, which are subtly different. “Miniloader Rockusb” won’t let you flash the first 0x2000 sectors, which is an issue if you want to flash everything you need for a working u-boot bootloader. “Mask ROM Mode” will let you flash everything, but before you can flash your full disk image, you need to send a binary to the board to get into “Usbplug mode” first to ensure the DRAM is fully initialised (this seems to be required for larger files). This is all very confusing, and the only way I found to tell which mode you’re in is by using the rkflashtool‘s n command and checking for the following line (chevrons added for clarity):

rkflashtool n
rkflashtool: info: rkflashtool v5.2
rkflashtool: info: Detected RK3328...
rkflashtool: info: interface claimed
rkflashtool: info: MASK ROM MODE      <<<<<<<
rkflashtool: info: Flash ID: ...

If it’s present, you’re in “Mask ROM Mode” already; if not you need to get there. But how?

One option involves erasing the bootloader and any helpers, e.g. by using “mmc erase” commands in u-boot. However, it turns out there’s another way, using an almost undocumented rkflashtool boot flag: rkflashtool b 3:

# not in MASK ROM Mode:
$ rkflashtool n
rkflashtool: info: rkflashtool v5.2
rkflashtool: info: Detected RK3328...
rkflashtool: info: interface claimed
rkflashtool: info: Flash ID: xx xx xx xx xx
rkflashtool: info: Flash Info:
 Manufacturer: Samsung (0)
 Flash Size: 14800MB
 Block Size: 512KB
 Page Size: 2KB
 ECC Bits: 0
 Access Time: 40
 Flash CS: <0>
# Reboot into Mask ROM Mode:
$ rkflashtool b 3
rkflashtool: info: rkflashtool v5.2
rkflashtool: info: Detected RK3328...
rkflashtool: info: interface claimed
rkflashtool: info: rebooting device...
$ rkflashtool n
rkflashtool: info: rkflashtool v5.2
rkflashtool: info: Detected RK3328...
rkflashtool: info: interface claimed
rkflashtool: info: MASK ROM MODE                 <<<<<<<
rkflashtool: info: Flash ID: 00 00 00 00 00
rkflashtool: info: Flash Info:
 Manufacturer: Samsung (0)
 Flash Size: 0MB
 Block Size: 0KB
 Page Size: 0KB
 ECC Bits: 0
 Access Time: 0
 Flash CS:

You may ask why I use rkflashtool b 3, whereas the enum in the linked email suggests it should be 2? Well, the e-mail also suggests rebooting into Mask ROM Mode is not supported… and in the end I just tried (knowing roughly what the flags might stand for) rkflashtool b 1, rkflashtool b 2, rkflashtool b 3, and 3 worked.

Flashing a full Linux image onto the Rock64

  1. Put Rock64 into Mask ROM Mode
  2. Download helper
  3. Flash image
$ rkdeveloptool db ./path/to/rkbin/rk33/rk3328_loader_ddr786_v1.06.243.bin
Downloading bootloader succeeded.
$ rkdeveloptool wl 0 /arch.img
Write LBA from file (100%)

Extracting partitions from images

See this blog post.

Rockchip parameters file

This file is used by rkdeveloptool to flash gpt partition information onto the eMMC, although the exact way how this is used is not entirely clear to me. It appears that the actual file contents is inserted into several places in the eMMC, and based on one set of instructions (see next step) still requiring the use of u-boot to write the gpt partition table, I suspect the file may be read by some code in Rockchip’s u-boot fork.

This handy PDF (in Chinese), found via Google, describes the parameters file format. Google Translate gives a usable translation when you feed it text one block at a time.

A valid parameters file can be obtained by e.g. flashing the stock Android image, and using “rkflashtool p >parameters.txt” to fetch the parameters file.

To build the partitions list (mtdparts=…), it’s worth knowing that the format of the partition items is “size@start(name)”, so “0x00001f40@0x00000040(loader1)” means that the partition labelled “loader1” starts at sector 0x40 and is 0x1f40 sectors long. Should you need this for an existing image, you can use “sfdisk -l -uS foo.img” and convert all the numbers from decimal to hex.

Flashing Linux images, one bit at a time

These are adapted from these Rockchip instructions. You’ll need:

  • rkdeveloptool
  • to know and understand your parameters file (see previous section)
  • know desired GPT partition table layout
  • have the u-boot build artifacts handy (if you have a u-boot build that uses SPL you only need idbloader.img, and you can skip u-boot.img and trust.img)
  • extract the boot and linux-root partitions from the desired image
$ cat ./parameter_gpt_mine.txt
FIRMWARE_VER:0.5.12
MACHINE_MODEL:rk3328-box
MACHINE_ID:007
MANUFACTURER:RK30SDK
MAGIC: 0x5041524B
ATAG: 0x60000800
MACHINE: 3228
CHECK_MASK: 0x80
KERNEL_IMG: 0x60408000
#RECOVER_KEY: 1,1,0,20,0
CMDLINE:console=ttyFIQ0 mtdparts=rk29xxnand:0x00001f40@0x00000040(loader1),0x00000080@0x00001f80(reserved1),0x00002000@0x00002000(reserved2),0x00002000@0x00004000(loader2),0x00002000@0x00006000(atf),0x00038000@0x00008000(boot:bootable),-@0x0040000(rootfs)

$ rkdeveloptool gpt ./parameter_gpt_mine.txt
Writing gpt succeeded.

$ rkdeveloptool wl 0x40 ./linux-build/out/u-boot/idbloader.img
Write LBA from file (100%)
$ rkdeveloptool wl 0x4000 ./linux-build/out/u-boot/uboot.img
Write LBA from file (100%)
$ rkdeveloptool wl 0x6000 ./linux-build/out/u-boot/trust.img
Write LBA from file (100%)
$ rkdeveloptool wl 0x8000 /tmp/rock64-parts/boot-0.5.12-126.img
Write LBA from file (100%)
$ rkdeveloptool wl 0x40000 /tmp/rock64-parts/system-0.5.12-126.img
Write LBA from file (100%)
$ rkdeveloptool rd
Reset Device OK.
$ # that didn't work. push reset button instead.

# in u-boot:
=> env print -a
check partitions is as per above.

=> gpt write mmc 0 $partitions
Writing GPT: success!

=> boot

rkflashtool says “The device does not support this operation!”, ARGH

This may be the result of a slightly unfortunate translation. Thankfully, the code is open source, so we can see where this message is generated, and when (for example during rkdeveloptool db). It might mean your device is not in the right mode, e.g. not in Mask ROM Mode when it should be, rather than that your device is doomed/too old/too new, as I read the message initially.

My thanks go out to

  • ayufan, for all his great work on building Rock64 images, patching the kernel and u-boot code.
  • The Rock64 team for building a nice SBC, and for shipping me a new board under warranty to replace my first broken one
  • Rockchip for their open source contributions
  • Everyone in the #rock64 IRC channel on pine64.xyz who’s helped me

References

Full disclosure

The views expressed on this blog are mine and do not necessarily reflect the views of my employer.

I bought the Rock64 and any accessories mentioned in this post with my own money and wrote this on my own initiative.

5 Replies to “Rock64: Porting Arch Linux to a new SBC”

  1. Thanks for this great write up!

    With the latest Arch ARM release I had issues with flaky gigabit ethernet. When I updated the system via pacman -Syu it downloaded a newer kernel (4.15) and locked the eth0 interface to 100mbps. The workaround mentioned in your github repo doesn’t seem to make a difference since it looks like the mainline kernel has explicitly locked the device at 100mbps.

    If I go back to ayufan’s 4.4 kernel, 1000mbps works fine. But I’d like to stay with the mainline kernel if possible.

    Have you found another workaround to re-enable gigabit performance?

    1. Hi Donald,
      Thank you for the feedback!
      Yeah, so what happened is that the Gigabit Ethernet interface was locked to 100MBit/s in the upstream kernel, apparently due to reliability issues: https://patchwork.kernel.org/patch/10094199/; this has been merged into the mainline code, and explains the limitation on the pure mainline kernel. When I found out about this I figured that I’d probably save myself some headache by leaving it as-is, rather than trying to work around it.
      Ayufan has meanwhile figured out what caused these issues – https://lkml.org/lkml/2018/1/23/275, and it looks like this patch is in the current 4.16-rc7 kernel. At this point, I would probably just wait for 4.16 to be released, but if you’re eager, you could of course build that yourself.
      Best regards,
      Michiel

  2. Hi Michael,

    I am having trouble with the usb 3.0 port not even showing up as a usb 3.0 port..my usb 3.0 drive is not even recognized! Any ideas?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.