{"id":430,"date":"2019-09-15T00:08:26","date_gmt":"2019-09-15T00:08:26","guid":{"rendered":"https:\/\/stikonas.eu\/wordpress\/?p=430"},"modified":"2024-10-20T19:03:07","modified_gmt":"2024-10-20T19:03:07","slug":"blobless-boot-with-rockpro64","status":"publish","type":"post","link":"https:\/\/stikonas.eu\/wordpress\/2019\/09\/15\/blobless-boot-with-rockpro64\/","title":{"rendered":"Blobless boot with RockPro64"},"content":{"rendered":"\n<p>This is a guide for booting RockPro64 computer (<a href=\"https:\/\/www.pine64.org\/rockpro64\/\">https:\/\/www.pine64.org\/rockpro64\/<\/a>) without using any proprietary blobs. RockPro64 is based on Rockchip&#8217;s rk3399 SoC, so if you have some other rk3399 board, you might still find this guide useful.<\/p>\n\n\n\n<p>I&#8217;m using Gentoo GNU\/Linux in this guide but steps should be quite similar on other distributions.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Overview of boot sequence<\/h2>\n\n\n\n<p>Before we proceed with detailed instructions, let us briefly describe how rk3399 boots.<\/p>\n\n\n\n<p>rk3399 chip has two types of internal memory that is inside the chip itself:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>32 KiB BootROM which is read only.<\/li>\n\n\n\n<li>200 KiB <a href=\"https:\/\/en.wikipedia.org\/wiki\/Static_random-access_memory\">SRAM<\/a> (Static RAM).<\/li>\n<\/ul>\n\n\n\n<p>When rk3399 is powered on, CPU loads BootROM code into <a href=\"https:\/\/en.wikipedia.org\/wiki\/Static_random-access_memory\">SRAM<\/a> (at this stage main system RAM is not yet initialized). BootROM is a fairly small program baked into hardware that is responsible for loading initial bootloader. It supports booting from SPI, eMMC, SD and supports downloading next bootloader over USB OTG interface. Since it is quite small and baked onto the chip itself, for the purposes of this guide we will consider it as hardware, not software.<\/p>\n\n\n\n<p>So, BootROM loads U-Boot TPL into SRAM. Since SRAM is quite small, we cannot load the full U-Boot bootloader into it, so only a small part called TPL is loaded. Its main job is to initialize main system RAM (RockPro64 has up to 4 GiB of LPDDR4 based RAM).<\/p>\n\n\n\n<p>Then U-Boot TPL hands control back to BootROM which then loads a slightly bigger part of U-Boot called U-Boot SPL. At this stage SPL loads ATF (Arm Trusted Firmware: https:\/\/github.com\/ARM-software\/arm-trusted-firmware) and U-Boot Proper into memory. Then ATF starts and finally runs U-Boot.<\/p>\n\n\n\n<p>U-Boot can boot payloads from a variety of sources including, eMMC, SD, USB as well as do network boot. Also, U-Boot has support for UEFI booting specification, so it can boot EFI binaries located on ESP partitions. Even though U-Boot can load Linux kernel directly, I personally find it more convenient to first load Grub2 and then load Linux kernel.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Compiling required components<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Toolchain<\/h3>\n\n\n\n<p>First of all you need to install required toolchain. If you are following this guide on RockPro64 itself or other ARM64 system, you can just use <code>gcc<\/code>. If you are not on ARM64, you can use <code>crossdev<\/code> (<a href=\"https:\/\/wiki.gentoo.org\/wiki\/Cross_build_environment\">https:\/\/wiki.gentoo.org\/wiki\/Cross_build_environment<\/a>) to install ARM64 cross-compiler (other distributions often ship cross compiler binaries too, e.g. on Debian GNU\/Linux you can use <a href=\"https:\/\/packages.debian.org\/sid\/gcc-aarch64-linux-gnu\">https:\/\/packages.debian.org\/sid\/gcc-aarch64-linux-gnu<\/a>).<\/p>\n\n\n\n<p>In addition to ARM64 compiler, you also need ARM32 cross-compiler:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>crossdev --target arm-none-eabi -s4<\/code><\/pre>\n\n\n\n<p>At the moment on my system I have <code>cross-arm-none-eabi\/gcc-8.3.0-r1<\/code> with <code>USE=\"cxx graphite jit multilib pgo\"<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Arm Trusted Firmware<\/h2>\n\n\n\n<p>As mentioned before, source code for ATF can be downloaded from <a href=\"https:\/\/github.com\/ARM-software\/arm-trusted-firmware\">https:\/\/github.com\/ARM-software\/arm-trusted-firmware<\/a>. Version 2.7.0 is known to work.<\/p>\n\n\n\n<p>Building ATF is quite easy but you might want to first remove some blobs (alternatively, removal of blobs is available in my git fork https:\/\/git.stikonas.eu\/andrius\/arm-trusted-firmware)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>find . -name '*.bin' -exec rm -rf {} \\;\nmake PLAT=rk3399<\/code><\/pre>\n\n\n\n<p>This should produce <code>build\/rk3399\/release\/bl31\/bl31.elf<\/code> which you&#8217;ll need to copy to u-boot directory.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">U-Boot<\/h3>\n\n\n\n<p>U-Boot only gained support for training LPDDR4 memory in <code>v2019.10<\/code> <s>which is not released yet<\/s>. However, I recommend using newer version (at least <code>v2023.04<\/code>)<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>git clone https:\/\/gitlab.denx.de\/u-boot\/u-boot.git\/\ngit checkout v2023.04<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>cd u-boot\n# Now copy ATF to top level of u-boot directory\ncp path\/to\/arm-trusted-firmware\/build\/rk3399\/release\/bl31\/bl31.elf atf-bl31\nmake rockpro64-rk3399_defconfig\nmake<\/code><\/pre>\n\n\n\n<p>Let&#8217;s use default configuration. I also tried tweaking configuration a bit to enable HDMI display inside U-Boot but so far I was not successful.<\/p>\n\n\n\n<p>This should produce <code>idbloader.img<\/code> which contains U-Boot TPL and SPL and <code>u-boot.itb<\/code> which contains U-Boot Proper. We can install those with the following script<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/sh -e\n\ncd u-boot\nsudo dd if=idbloader.img of=\/dev\/mmcblk1 seek=64\nsudo dd if=u-boot.itb of=\/dev\/mmcblk1 seek=16384<\/code><\/pre>\n\n\n\n<p>Optionally you might want to create two 4 MiB partitions that start at sectors 64 and 16384 and use those with <code>dd<\/code> without <code>seek<\/code>. Before running commands above, make sure that your eMMC or SD card is represented by <code>\/dev\/mmcblk1<\/code> block device. I have only tested booting from eMMC and did not try SD card myself.<\/p>\n\n\n\n<p>At this stage you can use any of the boot methods supported by U-Boot. In this guide I&#8217;ll be using UEFI boot to load GNU GRUB.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">GNU GRUB<\/h3>\n\n\n\n<p>Let&#8217;s get GRUB2 from package manager:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>emerge sys-boot\/grub<\/code><\/pre>\n\n\n\n<p>On my eMMC card I have created EFI System Partition (which should be FAT32 formatted). Then add moutpoint <code>\/boot\/efi<\/code> to <code>\/etc\/fstab<\/code>. GRUB should then be installed to ESP:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/sh\n\n# mount \/boot\/efi # you might needs this if \/boot\/efi is not mounted\ngrub-install \/dev\/mmcblk1 --removable\ngrub-mkconfig -o \/boot\/grub\/grub.cfg\n<\/code><\/pre>\n\n\n\n<p>The script above should have created <code>\/boot\/efi\/EFI\/BOOT\/BOOTAA64.EFI<\/code><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Compiling kernel<\/h2>\n\n\n\n<p>RockPro64 is well supported by the 5.15 LTS kernel.<\/p>\n\n\n\n<p>Configuring kernel is out of scope for this blog post, there are other guides online. You can use my configuration from <a href=\"https:\/\/stikonas.eu\/files\/gentoo-sources\/config-5.2.14-gentoo\">https:\/\/stikonas.eu\/files\/gentoo-sources\/<\/a>. Copy config file into your kernel source directory and rename it to <code>.config<\/code>. However, for UEFI boot as described in this blog, you need to enable <code>CONFIG_EFI_STUB=y<\/code> in your kernel config.<\/p>\n\n\n\n<p>Let&#8217;s download kernel sources. First of all, we&#8217;ll apply a few patches. Download the patches from <a href=\"https:\/\/stikonas.eu\/files\/gentoo-sources\/\">https:\/\/stikonas.eu\/files\/gentoo-sources\/<\/a> and put them to <code>\/etc\/portage\/patches\/gentoo-sources\/<\/code>.  This might only be necessary to fix booting from eMMC (cards sold by pine64 seem to need it, other cards, e.g. from Hardkernel seem to work fine).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>emerge gentoo-sources<\/code><\/pre>\n\n\n\n<p>To achieve fully blobless boot we can deblob the kernel:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cd \/usr\/src\/linux # assuming that is where you unpacked your kernel\nwget https:\/\/linux-libre.fsfla.org\/pub\/linux-libre\/releases\/5.15-gnu\/deblob-5.15\nwget https:\/\/linux-libre.fsfla.org\/pub\/linux-libre\/releases\/5.15-gnu\/deblob-check\nwget https:\/\/linux-libre.fsfla.org\/pub\/linux-libre\/releases\/5.15-gnu\/deblob-main\nchmod +x deblob-5.15 deblob-check\n.\/deblob-5.15\n<\/code><\/pre>\n\n\n\n<p>To compile the kernel, simply run<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>make -j$(nproc)<\/code><\/pre>\n\n\n\n<p>Then kernel can be installed with<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>make zinstall\nmake modules_install\nmake dtbs_install<\/code><\/pre>\n\n\n\n<p>The last command will install device tree files to <code>\/boot\/dtbs\/kernel_version\/rockchip<\/code>. In particular this directory should contain <code>rk3399-rockpro64.dtb<\/code>. Copy this file to ESP partition, so that it is available to U-Boot when it is loading Grub.<\/p>\n\n\n\n<p>Copying this dtb file is in principle optional. If it is missing, then kernel will simply use dtb from U-Boot which is mostly good enough, but kernel usually has slightly more up to date device tree file. At the moment I was not able to get HDMI working if I skip this step. This is possibly related to my failure of getting screen to work in U-Boot itself<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>kernel_version=5.15.41-gentoo-gnu\nmkdir -p \/boot\/efi\/dtb\/rockchip\ncp \/boot\/dtbs\/${kernel_version}\/rockchip\/rk3399-rockpro64.dtb \/boot\/efi\/dtb\/rockchip<\/code><\/pre>\n\n\n\n<p>Don&#8217;t forget to generate initramfs, for example you can use dracut<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>dracut --xz -H \/boot\/initramfs-${kernel_version}.img $kernel_version\ngrub-mkconfig -o \/boot\/grub\/grub.cfg<\/code><\/pre>\n\n\n\n<p>At this stage your can reboot and if everything goes fine, you&#8217;ll hopefully boot into fully free system.<\/p>\n\n\n\n<p>If you grab latest <code>mesa<\/code> package with <code>panfrost<\/code> driver you can even use accelerated KDE Plasma desktop or play some 3D games.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Configuring fan with fancontrol<\/h4>\n\n\n\n<p>The last patch we applied to the kernel exposes fan interface to the kernel. At the moment this makes fan spin at full speed. You can control it with e.g. <code>fancontrol<\/code> from <code>sys-apps\/lm-sensors<\/code> package. I use the following <code>\/etc\/fancontrol<\/code> configuration file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>INTERVAL=10\nDEVPATH=hwmon0=devices\/platform\/pwm-fan\nDEVNAME=hwmon0=pwmfan\nFCTEMPS=hwmon0\/device\/pwm1=..\/thermal\/thermal_zone0\/temp\nMINTEMP=hwmon0\/device\/pwm1=35\nMAXTEMP=hwmon0\/device\/pwm1=60\nMINSTART=hwmon0\/device\/pwm1=100\nMINSTOP=hwmon0\/device\/pwm1=70<\/code><\/pre>\n\n\n\n<p>fancontrol can be started with <code>systemctl enable fancontrol; systemctl start fancontrol<\/code><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Booting from SPI<\/h2>\n\n\n\n<p>U-Boot also supports booting from on-board SPI flash.<\/p>\n\n\n\n<p>You need to enable <code>CONFIG_ROCKCHIP_SPI=y<\/code> or  <code>make menuconfig<\/code> choose <code>ARM architecture -&gt; Build a SPI image for rockchip<\/code><\/p>\n\n\n\n<p>At the end of build process U-Boot version 2023.04 creates <code>idbloader-spi.img<\/code> that contains U-Boot image with TPL and SPL stages.<\/p>\n\n\n\n<p>You can flash U-Boot to SPI by using U-Boot that was written onto sdcard. See <a href=\"https:\/\/wiki.gentoo.org\/wiki\/PINE64_ROCKPro64\/Installing_U-Boot#Installing_on_SPI_flash\">https:\/\/wiki.gentoo.org\/wiki\/PINE64_ROCKPro64\/Installing_U-Boot#Installing_on_SPI_flash<\/a> for more details.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Binaries<\/h2>\n\n\n\n<p>If you prefer to run binaries but do not want to compile them yourself, you can get them from <a href=\"https:\/\/stikonas.eu\/files\/gentoo-sources\/u-boot\/\">https:\/\/stikonas.eu\/files\/gentoo-sources\/u-boot\/<\/a> <\/p>\n\n\n<a href=\"https:\/\/www.patreon.com\/stikonas\"><img decoding=\"async\" src=\"https:\/\/c5.patreon.com\/external\/logo\/become_a_patron_button.png\" alt=\"Become a patron\" \/><\/a>\r\n<a href=\"https:\/\/liberapay.com\/stikonas\/donate\"><img decoding=\"async\" alt=\"Donate using Liberapay\" src=\"https:\/\/liberapay.com\/assets\/widgets\/donate.svg\"><\/a>\r\n Bitcoin: bc1qe2dfqjwgse5v6cl6rhtk352ru90t0hnve45f2c\n","protected":false},"excerpt":{"rendered":"<p>This is a guide for booting RockPro64 computer (https:\/\/www.pine64.org\/rockpro64\/) without using any proprietary blobs. RockPro64 is based on Rockchip&#8217;s rk3399 SoC, so if you have some other rk3399 board, you might still find this guide useful. I&#8217;m using Gentoo GNU\/Linux in this guide but steps should be quite similar on other distributions. Overview of boot &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":4,"footnotes":"","_links_to":"","_links_to_target":""},"categories":[14],"tags":[11,56,57,55,58],"class_list":["post-430","post","type-post","status-publish","format-standard","hentry","category-software","tag-free-software","tag-rk3399","tag-rockchip","tag-rockpro64","tag-u-boot"],"_links":{"self":[{"href":"https:\/\/stikonas.eu\/wordpress\/wp-json\/wp\/v2\/posts\/430","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/stikonas.eu\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/stikonas.eu\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/stikonas.eu\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/stikonas.eu\/wordpress\/wp-json\/wp\/v2\/comments?post=430"}],"version-history":[{"count":52,"href":"https:\/\/stikonas.eu\/wordpress\/wp-json\/wp\/v2\/posts\/430\/revisions"}],"predecessor-version":[{"id":560,"href":"https:\/\/stikonas.eu\/wordpress\/wp-json\/wp\/v2\/posts\/430\/revisions\/560"}],"wp:attachment":[{"href":"https:\/\/stikonas.eu\/wordpress\/wp-json\/wp\/v2\/media?parent=430"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/stikonas.eu\/wordpress\/wp-json\/wp\/v2\/categories?post=430"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/stikonas.eu\/wordpress\/wp-json\/wp\/v2\/tags?post=430"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}