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.
== Relevant Components ==
=== 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 @caleb ([[ 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.sonyxperiadev commit with device-specific quirk
== A/B partitions #Android_AB_Slots ==
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 fastboot --set-active=[a|b] to change!
For this guide I will be installing Linux to slot a, wherever you see a _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 $HOME/pmos.
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 envkernel.sh 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 make alias, instead of the mm 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:
* &cdsp_pas - a remote processor, requires firmware to boot and not important yet
* &dsi0 - All dsi related nodes are MTP specific and could interfere with the framebuffer.
* &dsi0_phy
* &dsi1
* &dsi1_phy
* &gpu - We want to leave the GPU alone so that it doesn't try and talk to the display.
* &mdss - The MDSS handles display stuff too, we don't want that yet.
* &mdss_mdp
* &mss_pil - this is the modem, will only contribute to dmesg errors for now
* &sdhc_2 - this is the sdcard reader, your device may not have this
* All sd* nodes under &tlmm - 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 0x9D400000), the second value is the size (0x02400000 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 reserved-memory 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 9d400000 address to match the value you got above.
Make sure you update the reserved-memory 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 pmenv.sh 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 .config file in the output directory (.output 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 FB_SIMPLE 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 alias mm in a terminal where you've sourced pmenv.sh, or by looking here.
== Booting ==
With our kernel compiled, you'll find the kernel image at .output/arch/arm64/boot/Image.gz, and your device dtb file at .output/arch/arm64/boot/dts/qcom/sdm845-<device>.dtb.
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-<device>.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
# Or, if you've already fixed the offsets in $HOME/pmos/tools/mkbootimg.sh
mkb -r $HOME/pmos/initramfs.cpio.gz
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 console=ttyMSM0,115200 and earlycon with earlycon=qcom_geni.
= 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 rmtfs_mem 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 CONFIG_ATH10k_SNOC and CONFIG_QRTR 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
Category:Guide
__FORCETOC__