SDM845 Mainlining

= Overview = Getting Linux to boot on your phone is a daunting prospect, luckily due to a large push by Google and Linaro, support for more ARM based SOCs is being added to mainline constantly, and the Android kernel is slowly moving closer and closer to upstream. As a result, for a lucky few SOCs (ahem SDM845), it's pretty easy to get a large amount of core functionality working.

This page is meant to serve as a guide for adding support for mainline Linux to your SDM845 based device, the table below shows which features you should expect to have functional once you get mainline Linux booting on your device. The general approach here is the easier it is to add support for new devices, the more devices we will be able to support and in turn the more developers and users we will get :D.

Status
The features marked as Y are confirmed to be functional on at least ONE device, as more devices are supported this number should be increased. Features marked as P generally have some limited functionality but have issues that make them unsuitable for daily use.
 * CPU: SMP (bring up secondary CPU cores), CPU frequency scaling, CPUidle
 * Storage: eMMC, SD cards, UFS, ...
 * Video: Hardware-accelerated video de/encoding
 * Modem: Calls, SMS, Internet

About
SDM845 (or Snapdragon 845) is a Qualcomm SoC released in 2018, with mainline support originally added for the Dragonboard 845c.

SDM845 common kernel
This repo contains branches for the OnePlus 6/T and Xiaomi Pocophone F1 and is where the majority of development currently happens. There are aims to merge into a common branch and minimise the commits so that they can potentially be submitted to the kernel. Once you have your device booting you should contact @kalube ([[ in the postmarketos-mainline

Kernel package
This is the Alpine aports package source for the OnePlus 6 kernel, it is built by pmbootstrap and used to create an android boot image.

SoC common package
This is the generic SDM845 SoC package. It pulls in all common dependencies like tqftpserv, rmtfs and pd-mapper which are used to bringup WLAN and remove processors. It also contains some configuration options, e.g. udev rules for the pmi8998 haptics engine used by most SDM845 devices.

All SDM845 devices should depend on this package.

OnePlus 6 device package
This is the OnePlus 6 specific device package, it can be used as a reference guide for new SDM845 devices.

Required packages
rmtfs, pd-mapper and tqftpserv are all required and are used to communicate with the modem in order to load wifi firmware and perform other tasks. These are included in the common device package.

= Device Quirks =

Xperia UFS
If you phone is a Sony Xperia, DO NOT EVEN TRY TO ADD UFS TO YOUR DEFCONFIG/DTS if you're not running a vendor-based or SODP-based kernel. It needs a workaround without which YOUR UFS WILL BE WIPED CLEAN (INCLUDING THE BOOTLOADER!). You can boot off of a SD Card or a USB drive.

A/B partitions
A/B partitions are both a blessing and a curse. Some SDM845 devices have 2 of system, vendor, boot, xbl and a few other partitions, this means that it's super easy to dual boot with android as only one slot is used at any one time, simply  to change! For this guide I will be installing Linux to slot a, wherever you see a  suffix after a partition, replace it with whichever slot you would like to install for, I recommend using not the one you currently have Android on if you plan on daily driving Android or Halium like I do.

Check your current slot by booting TWRP and going into the reboot menu. Be aware that if you flash OTAs (from within Android or TWRP) they are flashed to the inactive slot, if that slot had Linux on it, it doesn't anymore...

= Starting Off =

pmtools
The pmtools repo contains a few useful scripts:
 * pmenv.sh a collection of aliases and functions, I will reference this script where it can be used.
 * mkbootimg.sh an uncreatively-named wrapper for mkbootimg, edit the offsets to match your device (You can learn how to find these numbers here, you may also want to modify the default paths defined at the top to match your device codename, to avoid manually specifying parameters.

Setting up your build environment
This is still very much WIP, however the process is not too complicated once you understand it.

pmbootstrap
The first thing to set up is pmbootstrap, it does a whole ton of the hard work for us, becoming comfortable with it and the pmaports repo let you create a reproducible build process and allows anybody to start developing for your device.

To get started follow the porting guide up until the kernel package section, then continue below.

Kernel building
This building guide is an alternative to the Mainlining guide. It can also be referred to for help. This guide, and the scripts used in it, will assume that you're working from.

The aim with my tools are to make the early bringup a bit faster, and avoid some of the quirks you can hit while using pmbootstrap. If you're new to kernel development you'd probably be better to follow the general mainlining guide once you're done adding a device tree for your device (see below).

The mainlining guide uses pmbootstrap's  script to do all kernel compilation in a chroot, this allows for a reproducible build environment and removes the need to install extra dependencies to build. However it does come with a performance hit, and can occasionally cause issues due to permissions. This guide will instead build on your host. If you'd rather build using envkernel then refer to the relevant section on the mainlining guide, the only functional difference is running their  alias, instead of the   alias shown below.

Clone the kernel
cd $HOME mkdir -p pmos && cd pmos git clone https://gitlab.com/sdm845-mainline/pmtools tools git clone https://gitlab.com/sdm845-mainline/linux linux

= Initial device support = Getting an initial kernel boot with graphics is relatively simple, it consists of creating a new DTS for your device, and creating a simple framebuffer to output to.

Creating a DTS
The first steps to adding support for your device is creating a new DTS file for your device, the basics for that are covered by the mainlining guide, and should be read before continuing. Use the file as your template.

Preparing the DTS
You should comment out or remove the following nodes as they are either specific to the MTP device, not needed for testing or known to cause issues:
 * - a remote processor, requires firmware to boot and not important yet
 * - All dsi related nodes are MTP specific and could interfere with the framebuffer.
 * - We want to leave the GPU alone so that it doesn't try and talk to the display.
 * - The MDSS handles display stuff too, we don't want that yet.
 * - this is the modem, will only contribute to dmesg errors for now
 * - this is the sdcard reader, your device may not have this
 * All  nodes under   - if you have an SD card you can add these back later.
 * - this is the modem, will only contribute to dmesg errors for now
 * - this is the sdcard reader, your device may not have this
 * All  nodes under   - if you have an SD card you can add these back later.
 * All  nodes under   - if you have an SD card you can add these back later.

To use simplefb as below, you will also need to explicitly disable some nodes to prevent hangs / display going black after a few seconds, to do that add the following to your dts:

&dispcc { status = "disabled"; };

&gpu { status = "disabled"; };

If the display clocks initialise then it will reset the states set up by the bootloader and cause the display to die.

Creating a framebuffer
Luckily for us, there's a neat feature in android that allows the kernel to inherit some SMMU mappings from the bootloader, this means we can be cheeky and reuse the framebuffer that the bootloader setup for us - the one used to render the splash screen you see when you first turn your phone on.

Find the framebuffer address
First you need to find the address of the framebuffer, you can do this by booting into TWRP or rooted android and running: strings /dev/block/bootdevice/by-name/xbl_a | grep "Display Reserved"

The first value is the address (in this case ), the second value is the size (  for us).

Create the framebuffer node
With that value noted down, you can now add this framebuffer node to your DTS file. Don't forget to copy the  node underneath too.

There are a few values that must be changed to match your device, this example is for xiaomi device which has a display width of 1080, and height of 2340, everywhere you see these 2 values they should be changed to match your device. Additionally, you have to change every reference to the  address to match the value you got above. Make sure you update the  node too.

Compiling
With your device now added to the kernel, it's ready to compile.

Source the tools
cd $HOME/pmos/linux source $HOME/pmos/tools/pmenv.sh

I'd recommend you add  to your bashrc/zshrc, it doesn't do anything too heavy :D, I will assume that you have sourced it for the rest of this guide. echo -e "source \$HOME/pmos/tools/pmenv.sh" >> $HOME/.bashrc

Enable simplefb
We use a config fragment for all the kernel config options we need that aren't in the defconfig. It also disables some extra stuff to speed up build times. It's applies on top of the defconfig like this: mm defconfig sdm845.config This will create a  file in the output directory (  that contains every single config option, and either sets or unsets it. In order to make use of the framebuffer device we defined, we need to enable support for the simplefb framebuffer driver. mm menuconfig You can now use  to open a search box, search for   and press  to go to the option, you can now press  to toggle it on.

Press twice to go back, repeat until you are prompted to save and exit.

Building
Finally, we can compile the kernel with: mm You can see what that's doing by running  in a terminal where you've sourced , or by looking here.

Booting
With our kernel compiled, you'll find the kernel image at, and your device dtb file at.

The final step is to make an Android compatible boot image, unfortunately there's one final hitch, the ramdisk...

Getting a ramdisk
Fortunately it doesn't take too long to make a postmarketOS ramdisk, simply do the following: pmbootstrap export cp /tmp/postmarketOS-export/initramfs-qcom-sdm845 $HOME/pmos/initramfs.cpio.gz

Making a boot image
cat .output/arch/arm64/boot/Image.gz .output/arch/arm64/boot/dts/qcom/sdm845- .dtb > /tmp/kernel-dtb mkbootimg \ --base 0x0 \ --kernel_offset 0x8000 \ --ramdisk_offset 0x1000000 \ --tags_offset 0x100 \ --pagesize 4096 \ --second_offset 0xf00000 \ --ramdisk $HOME/pmos/initramfs.cpio.gz \ --kernel /tmp/kernel-dtb -o $HOME/pmos/mainline-boot.img

mkb -r $HOME/pmos/initramfs.cpio.gz
 * Or, if you've already fixed the offsets in $HOME/pmos/tools/mkbootimg.sh

That's it! With a kernel successfully built it's ready for a test run...

The boot procedure
Reboot your device into fastboot mode, unfortunately all treble device launching with Android Oreo (and some Pie devices) have a dtbo partition, this stores a whole bunch of dtb files that the bootloader can go slap on to the kernel, mainline doesn't like this much...

On some devices we need to erase the dtbo partition before we can boot, it's wise to boot into TWRP and take a backup first, or alternatively switch to the opposite slot so as to keep whatever OS you're currently running intact. fastboot erase dtbo fastboot reboot bootloader

You can now boot the kernel with fastboot boot $HOME/pmos/mainline-boot.img

If all has gone to plan, you'll see a few penguins at the top of your screen, and dmesg scrolling on by.

Congrats, you did it :D

UART
If UART is accessible on your device (made available by the devices manufacturer, discovered via trial and error or through leaked schematics) it can make bringup a whole lot easier.

UART can be enabled via the kernel cmdline with  and earlycon with.

= The next step =

Now that you have a booting phone, or if you've bumped into issues along the way, you should hop on to Matrix and talk about your progress, the wonderful folks there will be more than happy to offer guidance and support.

More hardware specific details can be found on the SDM845 page.

= Remote Processors =

SDM845 and similar platforms have remote processors or DSPs (Digital Signal Processors) which are used for various device functionality. SDM845 has an ADSP, responsible for audio processing among others things, and a CDSP (compute DSP) capable or performing compute operations like machine learning. The modem is also exposed as a remote processor.

You can bringup the modem by enabling it and configuring it like done here.

Remote Processor errors
On some devices (OnePlus 6 & Lg V35 at least) the  reserved memory region is assigned to some slightly odd locations on downstream. This must be addressed on Mainline.

The rmtfs memory region is used to transfer data between processors (?), the downstream kernel memory region node doesn't hard code a region and instead uses a driver to allocate the region. Sometimes the region must be guarded to overcome some limitations in the XPU and prevent violations (and crashes) if memory is allocated too close to the region. See this commit for an example.

Getting WIFI
The WLAN chip on SDM845 devices lives on the Modem, this makes getting wifi up and running a bit challenging, however it should work on most devices.

Follow the instruction on the Snapdragon 835 SoC page for enabling WiFi.

The layout
The ath10k driver is used for WLAN on SDM845, it must be enabled along with  and   in the kernel config.

Change Kernel parameters
1, sudo vim /etc/deviceinfo

2, Change cmdline parameters to desired state

3, sudo apk fix linux-postmarketos-qcom-sdm845

Wakeups
Linux kernel 6.2-dev provides a patch to enable wakeups from the modem over QRTR.

echo enabled > /sys/bus/rpmsg/devices/4080000.remoteproc:glink-edge.IPCRTR.-1.-1/power/wakeup

= Maintainers =


 * Caleb

= See also =
 * postmarketOS podcast interview with Caleb about mainlining the OnePlus 6/SDM845