MSM8996 Mainlining

MSM8996/APQ8096 (Snapdragon 820/820E), as well as MSM8996SG/APQ8096SG (Snapdragon 821, also known as MSM8996 Pro) are Qualcomm SoCs with good support in the mainline Linux kernel. Getting it to boot on them generally does not require a lot of effort.

Status

 * CPU: SMP (bring up secondary CPU cores), CPU frequency scaling, CPU idle
 * Storage: eMMC, SD cards, UFS, ...
 * Video: Hardware-accelerated video codec
 * Modem: Calls, SMS, Mobile data

= First Steps =

SoC Common Kernel
This is a close to mainline fork which is used as a staging area for new devices and code. It has additional patches including fixes for some as well as new drivers that aren't ready for upstream, or haven't been merged there yet. Start off by cloning this kernel tree: git clone https://gitlab.com/msm8996-mainline/linux.git

Compiling the kernel
While it is possible to use to aid in compiling and packaging the kernel, it often causes several issues and can be cumbersome to deal with. It is generally easier to manage editing and compiling the kernel, as well as building boot images entirely outside of the scope of.

Linux uses the GNU Make build system. Usually compiling it would just require running `make`, but since the build machine likely would have a different architecture, some variables will have to be changed to cross-compile for  instead: In order to keep the source tree clean, it would be better to place output files in a separate directory. To do this, the  variable can be used. Finally, the  parameter can be set to use multiple threads for compiling, making the compilation process faster.
 * : This holds a prefix that will be appended to the build tools (, ,  , ...). This could be   or   depending on the host distribution and the toolchains packaged for it.   will be used going forward since it is used in Alpine Linux, the base distribution of postmarketOS.
 * : C compiler to use for compiling the kernel. Should be
 * : C compiler to use for compiling any needed build tools that will run on the host while compiling the kernel. Should be.

Putting everything together results in this command, which will be used for compiling as well as any other make targets: make -j$(nproc) CROSS_COMPILE=aarch64-linux-musl- CC=aarch64-linux-musl-gcc HOSTCC=gcc O=.output

Compiling Linux requires configuring it first, something that can be done using a configuration file. Each architecture has some configuration files in the kernel source tree under. For the  architecture, a single default configuration   that tries to cover most devices of this architecture is available. This file however has many components enabled that are unneeded on MSM8996 devices, resulting in increased compilation time. It is better to use the configuration file included in the  package, which has been optimized for MSM8996 devices.

To apply the configuration, copy the file to, rename it to  , then run: make -j$(nproc) CROSS_COMPILE=aarch64-linux-musl- CC=aarch64-linux-musl-gcc HOSTCC=gcc O=.output msm8996_defconfig

Once done, the previous command can be used to compile the kernel. Resulting files will be found in

Downstream DTS
This will probably be the most useful reference material. You should be able to find it in the downstream kernel somewhere in, or   which should be symlinked to the previous path. A DTB can also be extracted from the device in runtime from, then decompiled with DTC: dtc -I dtb -O dts fdt > fdt.dts This however will be stripped of any comments or labels, so it makes finding things a bit harder, but you can be certain that this is the correct DTS for the device variant you have.

Schematics
Having board schematics will help confirm connections between components, and especially regulators which can sometimes not be clear in downstream DTS. It can also help find UART pads or ports.

Downstream Kernel
This will help when writing drivers. The downstream drivers can be used as reference.

DTS of Other Mainlined Devices
There's a good chance that your device shares some hardware with other mainlined devices. Usually that's the case for WiFi/Bluetooth and Audio. It can help to take a look in device trees of other mainlined devices to see how things are done, or even copy similar parts.

Initial Device Tree
Every device requires a device tree that describes its hardware. Linux reads the device tree to determine what hardware is available, how it's connected, and what drivers are needed to operate it. Device trees in the kernel source tree can be found in. For MSM8996 devices, device trees are placed in.

Creating the DTS
Create a new file there named  using this template: // SPDX-License-Identifier: BSD-3-Clause / { 	model = "Device Name"; compatible = "vendor,codename", "qcom,msm8996"; };
 * 1) include "msm8996.dtsi"
 * 2) include "pm8994.dtsi"
 * 3) include "pmi8994.dtsi"

Then add it to the Makefile in the same directory, respecting alphabetical order: dtb-$(CONFIG_ARCH_QCOM)	+= msm8996-vendor-codename.dtb

Adding
The bootloader on devices with Qualcomm SoCs uses a set of device tree properties to pick a suitable DTB for the device variant it's running on: This allows vendors to pack multiple DTBs for several variants of their device into a single image and use it for all of them, instead of having to create an image for each variant. Setting those properties is necessary to make the bootloader pick our device tree. You should be able to find those in the downstream DTS. Once you find them, put them in the root node: / { 	model = "Device Name"; compatible = "vendor,codename", "qcom,msm8996"; qcom,msm-id = ; qcom,pmic-id = ; qcom,board-id = ; }; This device tree should be enough to boot, but so far there is no way of getting any sort of feedback.

= Getting Kernel Output = Getting any kind of output from the kernel is necessary to confirm that it boots, and to know if anything is not working as expected. There are a few methods to get kernel logs:

Simple Framebuffer
Perhaps the easiest one to get working, provided you have suitable hardware and a nice bootloader.

It's a fbdev driver that makes use of the framebuffer configured by the bootloader for boot splash. We can use it to draw a console on the screen with little effort. All it takes is to know the memory region where the bootloader configures the framebuffer, and fortunately that should be the same across all MSM8996 devices. Unfortunately however, it usually only works on video-mode panels and doesn't work on command-mode panels due to many bootloaders not enabling auto-refresh in MDP. To find out what type of panel you have, check the downstream cmdline (on Android or TWRP for example). This example is taken from a Xiaomi Mi Note 2: sched_enable_hmp=1 sched_enable_power_aware=1 app_setting.use_32bit_app_setting_pro=1 kpti=1 androidboot.hardware=qcom ehci-hcd.park=3 lpm_levels.sleep_disabled=1 cma=32M@0-0xffffffff loop.max_part=7 buildvariant=userdebug androidboot.bootdevice=624000.ufshc androidboot.verifiedbootstate=orange androidboot.veritymode=eio androidboot.keymaster=1 androidboot.serialno=91000201 androidboot.secureboot=1 androidboot.hwversion=4.5.0 androidboot.baseband=msm mdss_mdp.panel=1:dsi:0:qcom,mdss_dsi_lgd_sw43101_fhd_video:1:none:cfg:single_dsi fpsimd.fpsimd_settings=0 app_setting.use_app_setting=0
 * 1) cat /proc/cmdline

This argument is what we're looking for: mdss_mdp.panel=1:dsi:0:qcom,mdss_dsi_lgd_sw43101_fhd_video:1:none:cfg:single_dsi In this case the panel name is. What's important here is  at the end of the name. This tells us that this panel is video-mode. Command-mode panels would have  in the panel name.

Once you confirm that you have a suitable panel, you can proceed with enabling simplefb. You just have to add these nodes to the root node of your device tree, replacing  and   with the dimensions of your panel: / { 	... 	chosen { #address-cells = <2>; #size-cells = <2>; ranges; framebuffer0: framebuffer@83401000 { compatible = "simple-framebuffer"; reg = <0x00 0x83401000 0x00 (height * width * 3)>; width = ; height = ; stride = <(height * 3)>; format = "r8g8b8"; }; 	}; 	reserved-memory { cont_splash_mem: memory@83401000 { reg = <0x0 0x83401000 0x0 (height * width * 3)>; no-map; }; 	}; 	... }; Once done, build and flash/boot the kernel. If all went well, you should get some penguins on your screen!