Edit page

General full documentation




Android SDK for RK3566

Two Android SDKs are available from Pine64 for RK3566 devices:

QUARTZ64_SDK_android11

Android 11 SDK

For Quartz64 model A SBC and SOQuartz

QUARTZ64-model-A_eink.android11_SDK

Android 11 eink SDK

For PineNote and Quart64 model A SBC

Compiling

Build machine

  • 64 bit Linux (Manjaro tested)
  • At least 16G RAM
  • At least 250G free storage, preferably SSD based
  • Use a POSIX compliant shell such as bash, not zsh (in Manjaro “chsh -s /bin/bash username”)

Manjaro packages

The following packages are needed (install with “sudo pacman -S packagename”):-

  • make
  • gcc
  • python-pip
  • dtc
  • bison
  • flex
  • cpio
  • unzip
  • zip

Once this is done run

  • pip install pyelftools
    • sudo isn’t needed

You will also need libncurses.so.5. The easiest way to install this appears to be using an Arch AUR package.

  • Enable AUR
  • pamac install ncurses5-compat-libs
    • don’t use sudo

Patches

QUARTZ64-model-A_eink.android11_SDK

For QUARTZ64-model-A_eink.android11_SDK the following files will need to be updated:-

  • rk3566_ebook/u-boot/arch/arm/mach-rockchip/decode_bl31.py
  • rk3566_ebook/u-boot/arch/arm/dts/Makefile
  • rk3566_ebook/u-boot/scripts/dtc/dtc-lexer.l
  • rk3566_ebook/u-boot/scripts/dtc/dtc-lexer.lex.c
  • rk3566_ebook/u-boot/scripts/dtc/dtc-lexer.lex.c_shipped
  • Download link QUARTZ64-model-A_eink.android11_SDK.patches.04112021.tar
  • Only the PineNote target has been tested at this time.

Compilation process

  • cd rk3566 (for non eink)
  • cd rk3566_ebook (for eink)
  • source build/envsetup.sh
  • lunch
  • ./build.sh -UCKAu

Cross-compiling

The Pinephone’s triple for cross-compiling is aarch64-unknown-linux-gnu.

C/++

Installing the Toolchain

important

Please add instructions for other distributions to this section if you know them!

First, you’ll need to install the gcc cross-compilation toolchain.

On Arch Linux

$ sudo pacman -S aarch64-linux-gnu-gcc

On Ubuntu/Debian

$ sudo apt install gcc-aarch64-linux-gnu

On Void Linux

$ sudo xbps-install cross-aarch64-linux-gnu

Using the Toolchain

note

If you are trying to build an Arch Linux package with makepkg, also make sure to export CARCH=aarch64.

GNU Make

Kernel Makefile

For each invocation of make, be sure to pass the options ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- like this:

$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-
Other

If you are using a handwritten Makefile (not autogenerated by a meta-buildsystem such as meson, automake, etc.) then simply override CC and LD as you need.

automake

$ ./configure --host=aarch64-linux-gnu

meson

See the official meson documentation on the topic. In general, the introduction is a good read for any cross-compiling novice.

Rust

In order to cross-compile Rust applications for the Pinephone, you need to have a gcc cross-compiler installed and the Rust dependencies, usually the std crate, cross compiled for the target system. A more extensive explanation can be found on https://github.com/japaric/rust-cross. This instruction is based on it’s description.

Installing a GCC Cross-Compiler

The cross-compiler might have a different name depending on the operating system. Further along this instruction the name for the gcc cross-compiler will be used. Replace all occurences of $gcc_name with the name on your distribution.

For how to install the gcc cross-compilation toolchain on your distribution, please see Cross-compiling

Installing Rust Dependencies

The necessary dependencies can easily be installed with rustup:

$ rustup target add aarch64-unknown-linux-gnu

OR it can be installed with multirust [Is this still accurate???]:

$ multirust add-target nightly aarch64-unknown-linux-gnu

Compiling

rustc

When using rustc just add the two flags –target=aarch64-unknown-linux-gnu and -C linker=$gcc_name. Under Arch, this would look like:

$ rustc --target=aarch64-unknown-linux-gnu -C linker=aarch64-linux-gnu-gcc main.rs

To test it, run the program on your Pinephone

$ scp main user@ipadress:/home/user/Downloads
$ ssh user@ipadress /home/user/Downloads/main
Hello, world!

cargo

To cross-compile a project with cargo, open the folder of the project in a terminal. Then create a new folder and a file for cargo.

$ mkdir .cargo
$ cat >.cargo/config <<EOF
> [target.aarch64-unknown-linux-gnu]
> linker = "$gcc_name"
> EOF

Then you can compile it with

$ cargo build --target=aarch64-unknown-linux-gnu

To test it, copy the file on your Pinephone

$ scp target/aarch64-unknown-linux-gnu/debug/main user@ipadress:/home/user/Downloads

Then you can execute it by

$ ssh user@ipadress ./main -h
Hello, world!

Possible Errors

If you encounter an error saying

Cross compilation detected. Use PKG_CONFIG_ALLOW_CROSS=1 to override

just add that variable in front of your command e.g.

PKG_CONFIG_ALLOW_CROSS=1 cargo build --target=aarch64-unknown-linux-gnu

Mainline Hardware Decoding

note

This page is incomplete, you’re welcome to improve it.

Mainline Hardware Decoding refers to video decoding done using hardware accelerators on the mainline Linux kernel (i.e. what sits in Linus’ tree).

On most consumer-oriented SoCs, there is what is referred to as a VPU (Video Processing Unit). The VPU is responsible for power-efficient encoding and decoding of videos. Hardware-accelerated video decoding can be useful to get smoother video playback on your devices, lower power consumption, and lower CPU utilisation. Below is information regarding various hardware PINE64 uses and software that works with it.

Hardware

Here’s a table of the current support for different hardware. “In review” means the patch series to enable support has been posted to the mailing lists but is undergoing review, “linux-next” means it has been accepted and staged for the next Linux merge window.

RK3328RK3399RK3566RK3588
JPEGNoYesNoNo
MPEG-2YesYesYesNo
MPEG-4 Part 2/H.263NoNoNoNo
VP8YesYesYesNo
H.264/AVCYesYesYesÂčNo
H.265/HEVCIn reviewIn reviewNoNo
VP9YesYesNoNo
AVS2N/AN/AN/ANo
AV1N/AN/AN/ANo

Notes

Âč only Hantro, not rkvdec2, so with a maximum resolution of 1080p for now

Cedrus

In 2018, Bootlin launched a crowdfunding campaign to bring a open source Allwinner VPU driver to mainline Linux, which came to be called Cedrus. The Cedrus media driver (For Allwinner SOCs such as A64) supported by mainline Linux supports H.264 and H.265 video decoding as of Linux 5.10, and with 5.11 came VP8 decoding support and a H.264 stateless video decoder interface. For more information refer to the Sunxi wiki.

Hantro

The Hantro media driver supports Rockchip and NXP SoCs including the RK3399 used in the Pinebook Pro and RockPro64. In November 2020 it was announced that Bootlin was working on encoding support for the driver.

rkvdec

rkvdec is the video decoding hardware that’s developed by Rockchip presumably in house. It’s what Rockchip uses for decoding 4K H.264/AVC, VP9 and H.265/HEVC content. The driver in mainline linux for the first generation rkvdec (used in RK3328 and RK3399) supports VP9 and H.264, patches for HEVC support are also in the process of review.

RK3566, RK3568 and likely RK3588 use a second generation of rkvdec called rkvdec2. No mainline driver for this exists yet. The rkvdec instance on RK3588 additionally supports the AVS2 video codec.

rkdjpeg

rkdjpeg is Rockchip’s in-house hardware accelerated JPEG decoder. It can be found on the RK3566 and RK3568 as well as the RK3588.

No mainline driver exists for it so far.

Software

GStreamer

H.264 video decoding is possible when using GStreamer built from source, or an application utilizing it such as Clapper or ”Player. ”Player includes a indicator of when hardware acceleration is properly working and in use.

FFmpeg

Mainline FFmpeg currently lacks the necessary patches to use the v4l2-requests based API, but a fork that can utilise it exists.

With the patched ffmpeg, you can utilise hardware decoding using the -hwaccel drm parameter, e.g.:

ffmpeg -hwaccel drm -i input.mp4 -f null - -benchmark

to measure how fast it decodes.

mpv

mpv v0.35 or later, built against the aforementioned FFmpeg fork, can be used to play back videos with hardware accelerated decoding. The hardware decoder path features interop with the GPU output, saving an expensive copyback operation. You can utilise the hardware decoding with e.g.:

mpv --hwdec=drm [FILE]

In mpv versions prior to 0.35, you can use the copyback hwdec with:

mpv --hwdec=drm-copy [FILE]

More Resources


Mainline Hardware Encoding

Mainline Hardware Encoding of video can be achieved through the V4L2 user-space API, for which currently only GStreamer implements the required code.

SoC Support

The following table shows the current supported codecs for encoding for each SoC. Support for decoding is separate.

RK3328RK3399RK3566RK3588
JPEGN/AYesYesNo
VP8N/AIn reviewNoNo
H.264/AVCNoNoNoNo
H.265/HEVCNoN/ANoNo

Encoding With GStreamer

With GStreamer, in general, any V4L2 control can be set using the extra-controls=foo,name=value syntax after the encode pipeline stage identifier, where foo is any name you wish which GStreamer will promptly ignore, name is the name of the V4L2 control as shown by v4l2-ctl --list-ctrls (make sure to pick the right device with -d), and value is whatever value you want to set it to.

JPEG Encoding

This example converts an input MP4 file to an output MJPEG-inside-MKV file at JPEG quality 95, without any audio.

gst-launch-1.0 filesrc location=input.mp4 ! qtdemux name=demux demux.video_0 ! decodebin ! videoconvert ! v4l2jpegenc extra-controls=s,compression_quality=95 ! matroskamux ! filesink location=output.mkv

VP8 Encoding

tip

This requires a draft GStreamer merge request and the RFC kernel patchset applied.

This example converts an input MP4 file to an output VP8-inside-MKV file with a quantiser between 12 and 28, without any audio. The quantiser value goes from 0 (best quality, biggest filesize) to 63 (worst quality, smallest filesize).

gst-launch-1.0 filesrc location=input.mp4 ! qtdemux name=demux demux.video_0 ! decodebin ! videoconvert ! v4l2slvp8enc min-quality=12 max-quality=28 ! queue ! matroskamux ! filesink location=output.mkv

Alternatively, you can encode in variable bitrate mode with a target bitrate given in bits per second. Do note that Hantro doesn’t seem to do target bitrates below 2 mbit/s. In this example, the file is transcoded at a target bitrate of 3 megabits per second.

gst-launch-1.0 filesrc location=input.mp4 ! qtdemux name=demux demux.video_0 ! decodebin ! videoconvert ! v4l2slvp8enc bitrate=3000000 ! queue ! matroskamux ! filesink location=output.mkv

Mali Driver

Here is the good DRM powerpoint presentation by Free Electron: https://free-electrons.com/pub/conferences/2017/kr/ripard-drm/ripard-drm.pdf

Here is the DRM video presentation by Free Electron: https://www.youtube.com/watch?v=LbDOCJcDRoo

Wayland MALI Driver

X11 MALI Driver

X11 Notice

Attached are the implemented driver and library.

  • lib_x11_r6p0.tar.bz2opengles upper layer library
  • r6p0_kernel_driver.tar.bz2gpu driver code
  • sunxi_arm_video.tar.bz2 dri2 and exa video related accelerator implementation
  • sunxi_drm_0622.tar.bz2drm driver

Usage

Using drm driver not able to coexist with display driverdue to utilize display relate BSP sectionDrm driver able to integrate with sunxi_arm_video apply gem during cache and cache refreshopen cache able to increase performanceDrm driver utilize sunxi_tr BSP rotate sectionnot able to public sharing with sunxi_tr

Known issue

Due to rotate hardware not support crop, and majority exa accelerators operate using cropsunxi_arm_video is reference code (features already verified)this allow familiar with xorg hardware accelation If using web page and character appear vertical strip, this may not related to cache problem and may due to character library. This issue still need to further verified.


Overclocking

warning

There is the possibility of damaging your equipment by overclocking. Do so at your own risk!

note

This page is incomplete, you’re welcome to improve it.

note

All information regarding clock speeds, voltages and more are stored in the DTB (Device Tree Blob). You can learn more about it here.

Overclocking is a way to get more performance out of the system by running it at higher clock speeds than the factory default, usually while putting out more heat and using more power (You can also downclock to possibly reduce power consumption and thermals at the cost of performance). It is highly recommended that you avoid overvolting the device, as that has a high risk of damaging the hardware, hence the warning at the beginning of this page. However, just some slight overclocks without the added voltage can not only improve performance, but not carry as much risk (Still: Do at your own risk!). It should be noted however that overclocking can cause instability, so you will need to test and see what values work best with your device (There is a silicon lottery for the Pinephone’s hardware).

A64-based devices

important

These instructions are targeting the PinePhone to simplify the explanation, however they can be used to also overclock other devices such as the Pinetab if you modify the proper DTB files.

Editing the PinePhone DTS

In order to overclock the PinePhone you will have to first convert the DTB file in /boot/dtbs/allwinner/ to a DTS file. You will see sun50i-a64-pinephone-1.2.dtb, and also two other files with different PinePhone mainboard revisions (1.1 and 1.0). You will want to select the correct file for your PinePhone (Only choose 1.1 if you have a Braveheart, As all other consumer PinePhones use the 1.2 DTS).

Once you’ve found the file, you can run the following command to convert the DTB to DTS:

dtc -I dtb -O dts /boot/dtbs/allwinner/sun50i-a64-pinephone-1.2.dtb -o /boot/dtbs/allwinner/sun50i-a64-pinephone-1.2.dts

Finally, modify the newly converted .dts file and change the clockspeeds you wish to modify. You can simply use a text editor to do so.

To convert back to DTB:

dtc -I dts -O dtb /boot/dtbs/allwinner/sun50i-a64-pinephone-1.2.dts -o /boot/dtbs/allwinner/sun50i-a64-pinephone-1.2.dtb

Afterwards you can simply reboot and check with sudo cat /sys/kernel/debug/clk/clk_summary to see if the changes have correctly applied.

important

In the future it is possible that someone may make a driver to adjust clockspeeds of the A64 from userspace (using a config file) without the need to recompile. However, currently the only way to overclock is to either compile your own kernel, or modify just the DTB (instructions above).

GPU

Open /boot/dtbs/allwinner/sun50i-a64-pinephone-1.2.dts (You will have to find the source of the kernel used by your distribution. There is the Pine64 kernel, and Megi’s) in a text editor following the PinePhone overclocking instructions.

Look for mali: gpu@1c4000 { and within that block search for assigned-clock-rates = <432000000>;

The assigned-clock-rates line should be set to 432000000, this means that the GPU is clocked at 432MHz by default. So if you want 500MHz, set the value to 500000000.

Save the DTS file, and recompile the DTB. In order to check if the overclock was successfully applied you can run: sudo cat /sys/kernel/debug/clk/clk_summary.

important

The file may be slightly different and you may need to enter the values as hexadecimals

note

The GPU appears to run stable overclocked to 540 Mhz, however more testing with a wider group of devices is needed.

note

Remember to run a benchmark tool (such as glmark2-es2) to help check stability.

CPU

The stock speed of the A64 is 1.152 GHz. The A64 can be overclocked significantly, it is highly advisable not to do this unless you can also drop the voltage at the same time.

If the CPU is undervolted and overclocked at the same time, it is possible to reach similar thermals and power consumption to the stock configuration but with better performance.

Power consumption at different voltages and frequencies:

ConfigurationFrequencyVoltagePower (Screen 50%)
Stock1.152GHz1.30v~4.35w
Stock + Undervolt1.152GHz1.18v~3.65w
Overclock + Undervolt1.344Ghz1.28v~4.60w

The table above contains measurements created in postmarketOS (SWMO/SXMO - postmarketOS 21.12 SP1) with the screen on (set to 50% brightness) under a threaded load.

AXP803 PMIC voltage steps on DCDC2:

Voltage rangeStep size
0.50V-1.20V10mV
1.22V-1.30V20mV

The table above shows the valid voltages provided by the AXP803 PMIC on DCDC2 (used to power the cores). For example, setting the voltage to 0.60V is valid, but setting it to 1.23V is not. When overclocking, ensure that you only use valid voltages at each operation point (otherwise it will simply be dropped and ignored). You can use (after installing) cpupower to display all valid frequencies after boot.

important

The user somefoo was able to undervolt the PinePhone at each frequency operation point by at least -100mv. The A64 set to 1.152Ghz runs at 1.18v instead of the standard 1.3v, dropping the power usage by ~0.7w under full single threaded load|The silicon lottery will dictate how well you can undervolt.

note

The exact voltages and frequencies that you can achieve will depend on your device. Make sure to run stress tests (such as stress-ng) to ensure stability.

DRAM

warning

It is not recommended to exceed 667 MHz clockspeed on the DRAM. 648MHz is likely the upper limit.

note

Make sure to set your DRAM to a multiple of 24.

note

The current frequency your DRAM is running at can be found using this command: cat /proc/device-tree/memory/ram_freq

When overclocking the GPU, it is a good idea to also overclock the DRAM, as the main bottleneck of the A64 SOC is the memory. The A64’s maximum ram clockspeed falls just short of 667MHz. This may be unstable on your device however.

Around 600 MHz (PC-1200) should work fine, however some people have reported instability at lower clockspeeds. Arch Linux Arm uses a default clockspeed of 552MHz, with U-Boot builds available to easily switch out for a higher (624) or lower (492) DRAM clockspeed.

It is possible that by reverse engineering the DRAM driver from Allwinner that auto tuning can be accomplished to get the best performance.

Setting the DRAM clock is accomplished by modifying pinephone_defconfig in U-Boot (https://gitlab.com/pine64-org/u-boot/-/blob/crust/configs/pinephone_defconfig)

You can find simple instructions on doing so here: U-Boot

VPU

In order to allocate more VRAM for the GPU you can add cma=256 to your kernel (or use kconfig with CONFIG_CMA_SIZE_MBYTES=256) cmdline in boot.scr which you will have to compile using mkimage. By default the kernel allocates only 64MB, and the maximum value is 256MB.

In order to compile boot.scr you can run mkimage -C none -A arm64 -T script -d boot.cmd boot.scr

important

You may not have a boot.cmd file in your boot directory and instead you may instead have a boot.txt

Cedrus

Overclocking cedrus is achieved by modifying the kernel source code: https://elixir.bootlin.com/linux/latest/source/drivers/staging/media/sunxi/cedrus/cedrus.c#L507

important

User 33yn2 is not particularly sure if this makes any difference, or if it might in fact have a negative impact. Probably not worth messing with.

RK3399-based devices

The RK3399 clocks are found in arch/arm64/boot/dts/rockchip/rk3399-opp.dtsi

More optimised voltages and clocks can be found in arch/arm64/boot/dts/rockchip/rk3399-op1-opp.dtsi These include a slight overclock and undervolt, they are intended for the OP1 CPU found in many Chromebooks but have worked fine in all recorded cases on regular RK3399 SoCs in other devices.

GPU

Any clock speeds can be added for the GPU in gpu_opp_table

The highest recommended voltage for the GPU is 1.2V as specified in the RK3399 schematic from Rockchip.

Segfault has found that the RK3399 in his Pinebook Pro can reach 950MHz on the GPU while being stable.

The stock speed for the GPU is 800Mhz.

Note that the GPU in the RK3399 is already bottlenecked by the memory bandwidth available to it, so overclocking generally yields no improvements.

CPU

A set of available clock speeds that can be added to the CPU clusters can be found in drivers/clk/rockchip/clk-rk3399.c under rk3399_cpuclkl_rates for the little cores and rk3399_cpuclkb_rates for the big cores.

These clock speeds can be added to cluster0_opp for the small cores and cluster1_opp for the big cores respectively.

The maximum limit is 1.8GHz on the little cores and 2.2GHz on the big cores.

The highest recommended voltage for the little cores is 1.2V and for the big cores is 1.25V.

Segfault has found that the RK3399 in his Pinebook Pro can reach 1.7GHz on the little cores and 2.08GHz on the big ones.

The stock speed for the little cores is 1.4GHz and on the big cores it is 1.8GHz, the OP1 speeds default to 1.5GHz and 2.0GHz instead.

ROCK64

DTB is in /boot/dtbs/rockchip/rk3328-rock64.dtb. CPU clock rates are inside opp_table0 as hexadecimal numbers in the opp-hz field.

Check the achieved clock speed with sudo cat /sys/kernel/debug/clk/clk_summary | grep armclk.

Thanks to Ayufan’s work (with their overclocking recipe), we know we can add a 1.392GHz operating point, and a 1.512GHz operating point (you should ensure you have a large heatsink for this last one). You can do so by adding the following in the opp_table0 object, after the opp-1296000000 operating point:

opp-1392000000 {
        opp-hz = <0x00 0x52f83c00>;
        opp-microvolt = <0x149970>;
        clock-latency-ns = <0x9c40>;
};

opp-1512000000 {
        opp-hz = <0x00 0x5a1f4a00>;
        opp-microvolt = <0x162010>;
        clock-latency-ns = <0x9c40>;
};

GPU needs investigating, but current mainline device tree does not try to clock up the GPU at all.


PineModems

PINE64 position on alternative firmware

PINE64 ships the PinePhone with a stock version of the Quectel EG25-G modem’s firmware. Some administrative regions, in the EU and Asia in particular, require the entirety of the modem’s firmware to be licensed. Therefore, the PinePhone cannot ship with an unlicensed firmware, and the PINE64 project cannot, officially encourage its userbase to use alternative modem firmware.

Quectel EG25-G Modem

Quectel EG25-G is an LTE Cat 4 module optimized specially for M2M and IoT applications. It is used in the PinePhone.

Specifications

Processor FamilyQualcomm MDM9607
CPUQualcomm MDM9207
Cores1 ACPU Core, Qualcomm Hexagon DSP
Total RAM256Mb
Total flash space256Mb
Available RAM for the ACPU160Mb

NAND Partition table layout

IndexNameDescription
MTD0SBLSecondary Bootloader, called from the BootROM. Used to start the TrustZone kernel and the Application Bootloader (LK). Also used to enter Quectel’s recovery mode
MTD1mibibNAND Partition table
MTD2EFS2IMEI and settings used by the ADSP are stored here
MTD3sys_revUnexplored
MTD4rawdataThis is where FOTA update data exists before being commited to system or recoveryfs partitions
MTD5tzTrustZone kernel
MTD6rpmResource / Power Manager
MTD7cust_infoUnexplored
MTD8abootApplication Bootloader. Uses LK (LittleKernel, LK embedded kernel) as the bootloader. By default it allows flashing unsigned images but won’t allow booting them, soft-bricking the modem until you enter EDL mode
MTD9bootOpenEmbedded boot kernel + DTB
MTD10recoveryRecovery kernel (used for FOTA updates)
MTD11modemADSP firmware blobs
MTD12miscSome settings are stored here, along with commands that need to be picked by LK on next boot (to reboot to fastboot or recovery mode)
MTD13recoveryfsRecovery filesystem image (FOTA updates)
MTD14usr_dataUser data partition (/data when mounted by OpenEmbedded)
MTD15secUsed to blow fuses in the mdm9207 from images generated by Qualcomm Sectools
MTD16systemLinux OpenEmbedded root image, formatted in UBIFS (Unsorted Block Image File System, Wikipedia)

Firmware Recovery

warning

The following instructions are directed towards expert-level users and developers!

The System partition is mounted as read-only mode, but the data partition is writable. It might be possible, if there’s an unexpected reset or power is lost while running, that the data partition gets corrupt and thus unable to boot.

PinePhone USB_BOOT test points

The modem has 4 different boot modes:

  • Normal boot
  • Recovery mode (used by the modem usually to install a FOTA update)
  • Fastboot mode
  • Qualcomm EDL Mode

If the modem is unable to boot, depending on the type of crash, it might:

  • not show anywhere (USB device missing)
  • or malfunction (no radio but USB working)
  • or enter EDL mode, if the entire flash is corrupt.

Boot the device in EDL mode

To check if the device is booted in EDL mode, run lsusb (a part of the usbutils package) in a terminal and inspect the output. You should see the following device listed:

Bus 003 Device 003: ID 05c6:9008 Qualcomm, Inc. Gobi Wireless Modem (QDL mode)

In any scenario, the modem can be triggered to enter EDL mode by shorting two test pins on the PinePhone motherboard.

  1. Power off the phone
  2. short the two test points
  3. boot the phone while keeping the test points shorted until fully booted up, at least until you hear the camera clicking twice (which is normally when the modem is powered).

Get the Firmware Recovery Package

The Firmware Recovery Package is at: https://github.com/Biktorgj/quectel_eg25_recovery

Either clone its repo with git, or download its archive & unzip it.

As you should have no access to the Internet on PinePhone when its modem need a Recovery, you can fetch it on other devices and copy it to the Pinephone.

Execute the Quectel QFirehose utility

Once in EDL mode, open a terminal, navigate to the root directory of the recovery package, and run:

  • If you use an ARM64 distribution (most likely): sudo ./qfirehose -f ./ or sudo ./qfirehose_arm64 -f ./
  • If you use an ARMHF (32 bit) distribution: sudo ./qfirehose_armhf -f ./

It will reboot the modem after finished. After about 30 seconds, it will get back up and running. To check the firmware version after that, use an AT command AT+QGMR like at PinePhone.

Bootloader unlocking

warning

The following instructions are directed towards expert-level users and developers!

The Modem has a locked bootloader. It won’t allow to boot unsigned Kernel images, but will allow to flash them, making it easy to brick the modem. To fix this, you can flash an unlocked bootloader, which will then allow you to do as you please with the hardware.

Unlocked bootloader:

Custom Kernels and system images

warning

The following instructions are directed towards expert-level users and developers!

Custom kernel builds and system images can be created for the modem, though they require a couple of things to be correctly built and be bootable.

  • The source code release for the kernel provided by the manufacturer is incomplete and won’t build
  • Common Android tools like mkbootimg and dtbtool won’t build a bootable image, even if the kernel is correctly compiled and all the DTBs attached.
  • Further, there’s no source for the OpenEmbedded parts, so building a new system image must be done from scratch, and retrieving the mandatory binary blobs to use the ADSP part of the modem.

There’s a work in progress SDK to allow creating custom kernels and system images, which can be downloaded from the following repository: https://github.com/Biktorgj/pinephone_modem_sdk

See its readme for infomations and instructions. Once downloaded, you should run the init.sh script, which will create all the base directories and download all the different repositories required to build. After the initial setup is complete, runmake without arguments to list the available options.

Upgrade/switch firmware via fwupd

https://fwupd.org/ is an open-source tool for managing the installation of firmware on Linux systems.

fwupd >= 1.7.6 (with the ModemManager plugin) supports writing/upgrading the https://github.com/Biktorgj/pinephone_modem_sdk firmware on the Quectel EG25-G modem.

https://wiki.postmarketos.org/wiki/Fwupd discusses how to use fwupd to do this.

More context:

Modem management

To allow PinePhones to receive calls while the PinePhone is suspended, the modem should be kept running. ModemManager and a eg25-specific manager must be used for the eg25-manager to work correctly.

ModemManager

ModemManager “is a DBus-activated daemon which controls mobile broadband (2G/3G/4G) devices and connections”. Distributions should enable the --test-quick-suspend-resume flag, per https://gitlab.com/linux-mobile/tracker/-/issues/12.

Context: https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/issues/321

eg25-specific manager

Some functionality is not built into ModemManager, and is instead managed via eg25-specific software. There are two variants of this, but only one should be used.

Testing

When a distribution makes a significant change to their modem management setup, they should consider testing the following:

  • Modem is recognized by ModemManager on boot.
  • Can make a call
  • Can receive a call
  • Can receive a call when asleep: systemctl suspend

See also


RK3399 boot sequence

This article describes the boot sequence of the RK3399, the SoC on which the ROCKPro64 single board computer, Pinebook Pro laptop and the PinePhone Pro are based.

Boot ROM operation

After a hardware reset, the SoC’s boot ROM (BROM) starts running on CPU0, one of the Cortex-A53s on the chip. This code is stored on a block of read-only memory, likely hard-wired into the chip.

It employs 5 strategies, in order, to load a bootloader from off-chip:

  1. loading from NOR flash on SPI1
  2. loading from NAND flash on SPI1
  3. loading from eMMC
  4. loading from SD on the SDMMC controller
  5. bringing up the OTG0 USB controller in device mode and accepting control transfers to load programs

Loading a bootloader from storage is done in 4 steps:

  1. Probing the boot device
  2. Finding the ID block
  3. Loading the first stage of the bootloader to main SRAM and running it
  4. (if the first stage returned to BROM) Loading the second stage to low DRAM and running it

ID block

The ID block is a 512-byte block at one of several well-known locations (depending on boot device type) scrambled using RC4 with a well-known key, which begins with the bytes 0x3b 8c dc fc (ciphertext; plaintext: 0x55 aa f0 0f).

In addition to the magic number, it contains (all fields little-endian):

  • a flag to RC4-scramble the bootloader images too (32b at offset 8)
  • offset (in 512 B-sectors) of the first bootloader stage (16b at offset 12)
  • the size (in 2 KiB blocks) of the first bootloader stage (16b at offset 506)
  • the size (in 2 KiB blocks) of the second bootloader stage (16b at offset 508)

These fields can be seen in U-Boot tools/rkcommon.c.

SPI boot

The boot ROM tries to probe the device on SPI1 by issuing the SPI-NOR 0x9f (Read Identification) command.

If the type and capacity bytes are all-ones or all-zeroes, probe fails. If the first byte (manufacturer ID) is all-ones, the BROM uses NAND protocol, otherwise NOR protocol.

NOR protocol uses command 0x03 (low-frequency read without turnaround cycles) to read blocks, NAND protocol uses command 0x13.

The ID block is searched by loading the 32 bytes at the start of flash (TODO other load offsets) and testing for the magic number at any offset within those 32 bytes.

The SPI code has a bug that means that the 2 KiB blocks in which the bootloader is loaded have a stride of 4KiB, leaving the 2KiB inbetween as unused padding.

eMMC/SD boot

The boot ROM probes for eMMC on the eMMC controller using the normal MMC enumeration sequence (CMD0/1/2/3) at 375 kHz and runs the bus at 24 MHz, in 8-wide mode. The BROM does not support using the standard option for eMMC boot partitions.

SD is probed on the SDMMC (not the functionally equivalent SDIO) controller, using the normal SD enumeration sequence at 375 kHz and then runs the card at 12 MHz (TODO confirm) in 4-wide mode.

After initialization, eMMC and SD behave much the same. The ID block is searched by loading the blocks at sector 64 + 1024*n for n from 0 to 4 (inclusive) and checking for the magic number at the start of that sector. The BROM handles both byte- and block-addressed SD/MMC cards.

Hardware root of trust

The BROM theoretically supports SHA256/RSA2048 authentication with rollback protection.

The relevant data is stored in Secure eFuses: an enable flag, a SHA256 hash of the public key (which is stored on the boot medium) and a range of bits that are sequentially set for rollback protection.

In practice, the BROM does not verify the full length of the public key against the hash in eFuses, which means that it is most likely broken (expert review would be appreciated).

TOOD details

USB gadget boot

If no ID block is found on SPI, eMMC or SD, the BROM sets up the OTG0 USB controller to act as a USB high-speed (480 Mb/s) device with Vendor/Product ID of 2207:330c. In this state it supports most standard control requests, as well as 2 vendor control requests:

0x0471

The code is loaded to main SRAM. When the transfer is done, it does a function call to the load address.

0x0472

The code is loaded to low DRAM. When the transfer is done, USB is torn down and BROM jumps to the load address.

Transfer is performed by doing the requests on 4 KiB blocks. BROM considers the transfer complete as soon as a request supplies a block not 4096B long. (This means images a multiple of 4096 bytes long must be padded to achieve this condition.

U-Boot boot sequence

Bootloaders based on U-Boot (including Tow-Boot) run in 4 stages on the RK3399:

  1. TPL, loaded by the BROM into main SRAM. Its job is to initialize DRAM (main system memory). It returns to BROM. This job can alternatively be performed by proprietary Rockchip DDR blobs.
  2. SPL, loaded by the BROM into low DRAM. It loads the respective parts of TF-A BL31 into DRAM, main and PMU SRAM, and U-Boot proper into DRAM.
  3. TF-A BL31. It sets up EL2 to run U-Boot and stays resident until system shutdown.
  4. U-Boot proper. It can load EFI binaries (Grub, systemd-boot, 
) from a variety of block devices (SD, eMMC, NVMe, USB Mass Storage, 
).

For mainline-based U-Boots, these stages usually come in 2 images:

idbloader.img

contains TPL and SPL.

u-boot.itb

contains TF-A and U-Boot.

Load offsets

important

This section applies to BSP U-Boot. Mainline-based U-Boots pack TF-A into u-boot.itb.

There are 3 sections for the boot loader. They are in order, without gap, though their is no need to use all the space in each section.

Here are the details:

Start in sectorsSize in sectorsNameDescription
6416320IDBLoaderSoC initialization code
163848192OS loaderGenerally U-Boot
245768192TrustedFirmware-A 

General maintenance

If a new U-Boot is supplied, it is generally installed similar to this:

# dd if=/boot/idbloader.img conv=notrunc seek=64 of=/dev/mmcblkX
# dd if=/boot/u-boot.itb conv=notrunc seek=16384 of=/dev/mmcblkX

Different devices

The RK3399 boots to multiple devices. Boot device selection is done in the following order, and it cannot be changed.

If a device is blank / unused, the SoC code moves on to the next device in the list.

  • SPI
  • eMMC
  • SD card

However, whence the user boot code runs, it can then give priority to other devices, if available. The following devices are not directly bootable:

  • NVMe
  • USB 3
  • WiFi

They can be made bootable by using one of the other devices as an initial bootloader. For example, several people have gotten their NVMe drives to be bootable with “/boot” and “/” on the NMVe. This either entails using the SPI or eMMC as the initial bootloader, with code to support PCIe NVMe devices.

Grub as the target of the bootloader

It is possible to use Grub as the target of U-Boot. This would allow;

  • Selecting a different boot device
  • Choosing a partition on a boot device for booting
  • Different kernels
  • Changes in kernel command line options

However, at present, Grub does not support the video & keyboard of the Pinebook Pro. So, any selection is done through the serial console.

Boot loader development

There are several projects that have their own versions of U-Boot, with different features. Here are some of the more common ones at present, 2020/06/14:

  • Rockchip
  • The original default Debian
  • Manjaro
  • U-Boot mainline

Bootloaders not based on U-Boot:

  • coreboot runs on RK3399-based Chromebooks, it has not been ported to Pine64 boards yet.
  • levinboot is a bootloader developed by CrystalGamma in the Pine64 community. It runs on RockPro64 and Pinebook Pro. Its development is on hiatus as of April 2022, but a fork porting it to the PinePhone Pro exists.

RK3566 EBC Reverse-Engineering

The RK3566 SoC, used in the Quartz64 SBC by PINE64, contains an eInk interface. This is referred to as ebc by Rockchip apparently.

Unfortunately, the driver published for this eInk interface within the BSP kernel is an assembly dump produced by gcc. Fortunately, it contains quite a bit of debug information, which we can use to reverse engineer it.

Sources

Downstream

The ebc driver source is available from the quartz-bsp repository.

The files of interest are ebc_dev_v8.S, which implements a DRM (Direct Rendering Manager) driver for the eInk panel, and the waveform files in the epdlut subdirectory.

There’s also a simple driver for u-boot: drivers/video/rk_eink at JeffyCN/rockchip_mirrors

These two drivers show the two different programming interfaces exposed by the TCON. The U-Boot driver operates in “LUT mode”: it writes the waveform LUT to registers in the TCON’s MMIO space, and passes buffers of pixel data to the TCON. The Linux driver operates in “direct mode” uses the LUTs to compute waveforms in software, and passes buffers of waveform data to the TCON.

Some reversing of the downstream Linux driver has been done here: https://github.com/Ralim/ebc-dev-reverse-engineering

Reimplementation

A human-readable C reimplementation of the LUT and pixel data path is available from smaeul here. This provides everything needed to convert a framebuffer and a waveform data file into a series of “frames” for the panel. The new implementation includes a test suite to verify its output matches the output from the BSP assembly code. It is based on the downstream Linux driver.

In-Development Driver

rk356x-ebc-dev is the branch used for developing an upstreamable DRM driver based on mainline kernel sources. The driver currently functions well enough to get a virtual console and Xorg running, but it does not support features like multiple waveforms.

Documentation

Datasheets

EBC

The EBC TCON is documented in part 2 of the RK356x TRM.

TI TPS65185x

This is the PMIC used to drive the e-Ink panel, for which the downstream sources also implement a driver.

https://www.ti.com/lit/ds/symlink/tps65185.pdf

Waveform

The format of the waveform file is documented here:

https://www.waveshare.net/w/upload/c/c4/E-paper-mode-declaration.pdf

https://www.waveshare.net/w/upload/archive/c/c4/20190611032540!E-paper-mode-declaration.pdf

Utilities

The inkwave program is designed to parse waveform files. Currently it cannot fully handle the waveform files shipped with the PineNote. Adding support for this to the tool would be helpful.

Assembly Syntax and Semantics

The Syntax is GNU Assembler (GAS) syntax. This modexp article provides a good introduction to the syntax, calling convention, semantics and some often used instructions.

The ARM Architecture Reference Manual for ARMv8 should be used as reference for any instructions.

At the very least, you should read up on the registers and calling convention used.

Various Findings

The driver isn’t really something that can be mainlined as-is once reversed, as it makes a number of questionable design decisions.

  • It’s technically a DRM subsystem driver, but doesn’t really utilise what DRM provides at all.
  • It seems to register a new ioctl to set buffer attributes like width and height, despite DRM more than likely having a way for clients to tell a driver what size the framebuffer should be.
  • It directly interacts with the PMIC instead of going through regulators/hwmon.

However, reverse engineering to know how it works provides a good baseline from which we can rewrite it in a more sensible manner.

Debug Information

Quite a bit of debug info is left in the assembly dump, including function names, file names and line numbers. We can take this to our advantage.

.file _file-number_ _file-path_

Specifies a number to reference a file by, and its path. All following code until the next .file or .loc statement are to be understood as originating from this file. This is particularly useful to understand which code has been inlined from other files, for which the source is available.

.loc _file-number_ _line-number_ 0

Specifies that the following code is generated from _line-number_ stemming from file number _file-number_. See the .file directive for this file number to understand which source file it came from.

.type _function-name_, %function

This tells us that the following code belongs to function _function-name_. You’ll usually see a .cfi_startproc, which signifies the start of the function code, until the matching .cfi_endproc.

A quick grep for %function shows that we are dealing with 30 functions in this file.

.type _struct-name_, %object

This seems to signify a definition of a C struct named _struct-name_.

A quick grep for %object shows that we are dealing with around 27 structs in this file.

.Ldebug_info0:

TODO: This seems to contain the main bulk of the DWARF debug information, including enough info to reverse full structs and function signatures.

Finding Structs and Function Signatures

First, we’ll need to assemble the file:

aarch64-linux-gnu-gcc -c -o ebc_dev_v8.o ebc_dev_v8.S

This gives us a ebc_dev_v8.o which we can feed into analysis tools.

For both of these, keep in mind that we’re only interested in stuff from ebc_dev.c, or any other files for which we don’t have the source. There’s no point in getting the struct description or reverse-engineering a function that we have the source code for. A lot more than ebc_dev will be in the object file due to inlining and such.

Also make sure that if you are looking up known struct accesses, that you use struct definitions from the BSP kernel, not from mainline. The kernel has no internal ABI for drivers!

Faster and Easier - Ghidra

Import the file into Ghidra, open the code browser. After analysis, you should be able to find structs in the “Data Type Manager” marked with an S icon. You’ll also find functions in the symbol tree.

Slow and Painful - readelf/objdump

Use this if you want to manually look up dwarf symbols for some reason.

readelf --debug-dump ebc_dev_v8.o

This will produce a lot of output, but we’re mainly concerned with the start of the dump. We’ll find things like:

<2><101f8>: Abbrev Number: 0 <1><101f9>: Abbrev Number: 79 (DW_TAG_subprogram) <101fa> DW_AT_name : (indirect string, offset: 0xa2b4): ebc_open <101fe> DW_AT_decl_file : 1 <101ff> DW_AT_decl_line : 1377 <10201> DW_AT_prototyped : 1 <10201> DW_AT_type : <0xc6> <10205> DW_AT_low_pc : 0x0 <1020d> DW_AT_high_pc : 0xc <10215> DW_AT_frame_base : 1 byte block: 9c (DW_OP_call_frame_cfa) <10217> DW_AT_GNU_all_call_sites: 1 <10217> DW_AT_sibling : <0x1023a> <2><1021b>: Abbrev Number: 88 (DW_TAG_formal_parameter) <1021c> DW_AT_name : (indirect string, offset: 0x1153): inode <10220> DW_AT_decl_file : 1 <10221> DW_AT_decl_line : 1377 <10223> DW_AT_type : <0x1c54> <10227> DW_AT_location : 0xd63 (location list) <2><1022b>: Abbrev Number: 106 (DW_TAG_formal_parameter) <1022c> DW_AT_name : (indirect string, offset: 0x8b06): file <10230> DW_AT_decl_file : 1 <10231> DW_AT_decl_line : 1377 <10233> DW_AT_type : <0x551f> <10237> DW_AT_location : 1 byte block: 51 (DW_OP_reg1 (x1))

This essentially tells us the full function signature of ebc_open:

DW_TAG_subprogram tells us of a function, with DW_AT_name letting us know that this is ebc_open. DW_AT_type of 0xc6 let’s us know, once we jump to <c6>, that this function’s return type is a signed 32-bit integer.

The DW_TAG_formal_parameter that follow tell us of each of the parameter the function takes. The first one is called inode and is of type 0x1c54. Referencing what this type is, we find:

<1><1c54>: Abbrev Number: 7 (DW_TAG_pointer_type)
   <1c55>   DW_AT_byte_size   : 8
   <1c56>   DW_AT_type        : <0x1970>

which in of itself goes on to reference 0x1970, and looking this one up, we’ll find a struct definition:

<1><1970>: Abbrev Number: 26 (DW_TAG_structure_type)
   <1971>   DW_AT_name        : (indirect string, offset: 0x1153): inode
   <1975>   DW_AT_byte_size   : 672
   <1977>   DW_AT_decl_file   : 31
   <1978>   DW_AT_decl_line   : 611
   <197a>   DW_AT_sibling     : <0x1c4f>
<2><197e>: Abbrev Number: 27 (DW_TAG_member)
   <197f>   DW_AT_name        : (indirect string, offset: 0x7d00): i_mode

etc.

Reverse-Engineered Stuff

Structs

ebc_info

See https://gitlab.com/smaeul/ebc-dev/-/blob/main/auto_image.h#L124, which is based on the v1.04 BSP Linux driver.

ebc

See https://gitlab.com/smaeul/ebc-dev/-/blob/main/auto_image.h#L200, which is based on the v1.04 BSP Linux driver.

rkf_waveform

note

all known waveform data files are the “PVI” variant, not the “RKF” variant.

struct rkf_waveform {
    int length,
    char[16] format,
    char[16] version,
    char[16] timeandday,
    char[16] panel_name,
    char[16] panel_info,
    char[64] full_version,
    char[64] reset_temp_list,
    char[64] gc16_temp_list,
    char[64] gl16_temp_list,
    char[64] glr16_temp_list,
    char[64] gld16_temp_list,
    char[64] du_temp_list,
    char[64] a2_temp_list,
    uint[64] reset_list,
    uint[64] gc16_list,
    uint[64] gl16_list,
    uint[64] glr16_list,
    uint[64] gld16_list,
    uint[64] du_list,
    uint[64] a2_list
}

Enums

rkf_waveform_type

enum rkf_waveform_type {
    RKF_WF_RESET = 0,
    RKF_WF_DU    = 1,
    RKF_WF_GC16  = 2,
    RKF_WF_GL16  = 3,
    RKF_WF_GLR16 = 4,
    RKF_WF_GLD16 = 5,
    RKF_WF_A2    = 6
}

U-Boot

tip

It is helpful to have a debugging serial cable for this.

Building U-Boot manually

Prerequisites

These instructions are written with a host Arch Linux desktop system in mind.

This guide will be especially useful if you are looking to overclock the ram on your PinePhone following the information found here.

You must have these packages installed: dtc swig bc aarch64-linux-gnu-gcc

If you are using a different system such as Ubuntu, there are plenty of cross compilation instructions available online with which you can grab the needed package names from, however you should be able to follow these instructions with these packages installed: build-essential bison flex swig gcc-aarch64-linux-gnu

Compilation

tip

This guide is written with the PinePhone in mind. On other devices you will need to set a different platform variable and likely use a different U-Boot source with patches oriented towards your device.

Note by default these instructions utilize all of your computers cores to compile thanks to the -j and $(nproc) parameters. If you wish to only use one core to compile, or change the number of cores used for example to only two cores, then you can either completely remove the -j$(nproc) parameter from the make commands, or just take off $(nproc) and add the number of threads you want used in it’s place: -j4

First, You need to compile the ATF (Arm Trusted Firmware):

git clone https://github.com/crust-firmware/arm-trusted-firmware/
cd arm-trusted-firmware
export CROSS_COMPILE=aarch64-linux-gnu-
export ARCH=arm64
make PLAT=sun50i_a64 -j$(nproc) bl31
cd ..

After the ATF is compiled clone u-boot and copy the bl31.bin file into the u-boot directory.

git clone https://gitlab.com/pine64-org/u-boot.git
cd arm-trusted-firmware
cp build/sun50i_a64/release/bl31.bin ../u-boot/
cd ..

tip

You cannot build Crust if you do not have the or1k musl toolchain installed. This toolchain is not usually available in distribution repositories and will have to be manually installed to the system. The following text will show a simple way to install the toolchain.

Download the toolchain’s archive: https://musl.cc/or1k-linux-musl-cross.tgz

Extract the compressed archive: tar zxvf or1k-linux-musl-cross.tgz

Move the extracted archive to wherever you would like to install the toolchain to. In these instructions it will simply be installed to the users documents folder.

The final step is to edit your .bashrc and add the following to the end:

# Path for or1k toolchain
export PATH="$PATH:/home/USER/Documents/or1k-linux-musl-cross/bin/"

After you’ve completed that you can close out the terminal and reopen it and proceed to the following instructions.

git clone https://github.com/crust-firmware/crust
cd crust
export CROSS_COMPILE=or1k-linux-musl-
make pinephone_defconfig
make -j$(nproc) scp
cp build/scp/scp.bin ../u-boot/
cd ..

tip

If you do not wish to have Crust in your U-Boot build, then you can skip exporting SCP

cd u-boot/
git checkout crust
export CROSS_COMPILE=aarch64-linux-gnu-
export BL3bl31.bin
export ARCH=arm64
export SCP=scp.bin
make distclean
make pinephone_defconfig
make all -j$(nproc)

U-Boot installation

Once successfully compiled you can proceed to flash the device

warning

Replace [CHANGE THIS] with the location of your SD card and make sure you are using the proper location. Failure to do so can result in data loss.

sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/[CHANGE THIS] bs=1024 seek=8

tip

If you are compiling U-Boot in order to overclock your DRAM you can check if it was successful by reading the values of /sys/kernel/debug/clk/clk_summary

p-boot multi-bootloader

One of the smallest and fastest PinePhone bootloaders, it was developed by Ondrej Jirman with the ability of booting multiple distributions on the PinePhone in mind.

More information can be found here

Sunxi U-Boot Wiki

U-Boot build instructions

or1k toolchain download