MSM8996 Mainlining
![]() |
This page is WIP. |
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
SoC | Arch | Year | CPU | UART | Storage | USB | Display | GPU | Pinctrl | I²C | Audio | Video | Thermal | Modem | Camera |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Qualcomm MSM8996 | aarch64 | 2016 | P | Y | P | Y | Y | Y | Y | Y | Y | Y | Y | P | P |
First Steps
Kernel
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
References
Downstream DTS
This will probably be the most useful reference material. You should be able to find it in the downstream kernel somewhere in arch/arm/boot/dts/qcom
, or arch/arm64/boot/dts/qcom
which should be symlinked to the previous path.
A DTB can also be extracted from the device in runtime from /sys/firmware/fdt
, 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 arch/*/boot/dts
. For MSM8996 devices, device trees are placed in arch/arm64/boot/dts/qcom
.
Creating the DTS
Create a new file there named msm8996-<vendor>-<codename>.dts
using this template:
// SPDX-License-Identifier: Your-License /* * Copyright (c) YYYY, Your Name <address@mail.xyz> */ #include "msm8996.dtsi" #include "pm8994.dtsi" #include "pmi8994.dtsi" / { model = "Device Name"; compatible = "vendor,codename", "qcom,msm8996"; };
Then add it to the Makefile in the same directory, respecting alphabetical order:
dtb-$(CONFIG_ARCH_QCOM) += msm8996-vendor-codename.dtb
Adding qcom,*-id
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:
qcom,msm-id
qcom,pmic-id
qcom,board-id
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 = <0x131 0x10000>; qcom,pmic-id = <0x20009 0x10013 0 0>; qcom,board-id = <34 0>; };
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. 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:
# cat /proc/cmdline 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
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 qcom,mdss_dsi_lgd_sw43101_fhd_video
. What's important here is video
at the end of the name. This tells us that this panel is video-mode. Command-mode panels would have cmd
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 height
and width
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 = <width>; height = <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!
UART
Notes
- Some discussion about mainline status on this platform occurs in the #msm8996-mainline:matrix.org chat room on Matrix