SM7150 Mainlining

The Qualcomm SM7150 series of chips are premium mid-range SoCs released in 2019 and 2020, with mainline support originally added to the Xiaomi POCO X3 NFC

Status
An overview of this SoCs features can be seen on its page here.

Requirements

 * SM7150-based device
 * Extracted device tree from (preferably) stock Android or TWRP
 * pmbootstrap (from git)
 * Basic knowledge about Linux, Git, C, Device Trees, ...
 * Willingness to learn about "mainlining" and to figure out things on your own

Extracting downstream device tree blob
The device tree blob (dtb) will help you find out which hardware your device has, how the regulators have been setup, where the memory regions are and much more. It is not possible to copy the downstream dtb and use it in mainline, therefore you have to write your own device tree source (dts) for the mainline kernel.

In order to extract the dtb, you will have to boot up the downstream kernel. Preferably you would extract it from the stock Android ROM that came with your phone so it would include the device tree blob overlays (dtbo). Using something like TWRP will also work in case you can't boot your stock ROM anymore.

To extract it, run  with root from an ADB shell and pull the file to your computer with.

Since this file is a compiled blob of the device tree, you will have to decompile it into a human-readable format next. You can do that with the device tree compiler (dtc). Simply install it from your package manager and run

Now you can read the full source code of the device tree from your device. Keep this file saved somewhere, as you will need it in your mainlining adventure.

Device Package
Before you can build the mainline kernel for your device, you need to setup the postmarketOS device package. Avoid creating the device/kernel package directly through pmbootstrap, because that will result in a package for a downstream kernel. You can start with the following examples from :
 * :
 * :

To find the correct values for deviceinfo use  on a boot.img file from the firmware of your device. You can most likely copy the values from the example as they are pretty much the same for most devices.

After modifying the deviceinfo file, run  to generate the checksums.

Build Kernel
To build the kernel, use, a script for pmbootstrap that will make compiling and packaging the kernel easier. You can only find this script in the git version of pmbootstrap, so follow the instructions from here if you use a pre-packaged version.

This is how you can build and test local changes for the kernel from now on. Now we will continue setting up an initial device tree for your device.

Later on, if you want to change the config, for example to build a new display driver as a module, you can run.

Initial device tree
Your initial device tree does not need much for your device to boot. A minimal device tree needs:
 * property for your bootloader to find the dtb
 * Memory regions
 * Some way of output (SimpleFB, ramoops or UART)
 * Protected GPIO pins (Fingerprint and NFC pins, should be the same for most devices)

Make sure the properties with  are correct for your device. You can find the corresponding values in the device tree you extracted, but beware that decimal numbers have been converted into hexadecimal numbers.

The root node of your device tree should look like this:

Save this file as  inside   and add your device tree to the makefile at.

Reserved memory regions
Reserved memory regions are important to make the hypervisor happy (not crash the phone) and to have SimpleFB working. This part is tricky, since you have to compare every memory region in the extracted device tree with  in the mainline kernel.

Look for the  node in the extracted device tree and   in the mainline kernel and compare every address and size inside the   property with each other. In case you find differences, delete the offending node and add this piece of code below the header includes in your device tree:

And set the new reserved memory region inside the root node:

Keep the reserved memory tidy by sorting them after the length of the address

A full example can be seen here. Don't copy-paste this, as your reserved memory regions are probably different.

Protected GPIO pins
The fingerprint sensor and NFC are hooked up to secured GPIO pins, which are being observed and controlled by the TrustZone. This is to allow secure authentication and wireless payments.

Usually, the protected pins are not defined in the device tree (except for Pixel 4a), but this does not matter because most devices share the same protected GPIO pins. If you have schematics for your or a similar device you can verify the protected pins and if you don't, you can just try these out:
 * (from Google Pixel 4a)
 * (from Xiaomi Redmi Note 10 Pro)

Add this to the bottom your mainline device tree: 59 is the starting GPIO of the range and 4 is the range. This means that pins 59, 60, 61, 62 are not being touched by Linux.

Getting output
You can chose either of these methods to get output from the kernel. Using SimpleFB is recommended, as it is the easiest to set up.

SimpleFB
You can use simple framebuffer to reuse the frambuffer which the bootloader politely left set up. The bootloader does this to display the splash continuously throughout the boot process.

Look for a memory region called  in your downstream device tree. It should look like this:

Here we can see that  is the address for the framebuffer.

Now add the node for SimpleFB with the right address and resolution for your device in the mainline device tree:

And add a reserved memory region for your address. You don't have to delete any node beforehand because the framebuffer is not specified in.

Ramoops
Ramoops saves the logs into RAM using the persistant storage (pstore) backend. Make sure your recovery (e.g. TWRP) has the necessary kernel configs enabled, because otherwise you won't be able to see the kernel log. You can check your current kernel config with  from ADB shell, it should have these configs enabled: If your recovery does not have these configs enabled, you will need to build your own recovery with them enabled.

Search for the  node in the downstream device tree. It will tell you the address and the different sizes that are needed. You can copy-paste this node under the  node in mainline after deleting the   property.

The mainline kernel has the necessary configs already enabled, so after booting mainline and rebooting into recovery by forcefully holding down the key combination you should have the kernel log saved in. You can output the log with  from ADB shell.

The ramoops method can be unreliable, since the logs can disappear if your RAM looses power during the rebooting process.

Remote Filesystem memory
Remote Filesystem, also know as RMTFS is used for allocating and exposing regions of shared memory with remote processors. This memory region is needed by the IPA remote processor to get the modem working.

Even though the device tree defines this region as dynamically allocated, it always has the same address. You can find out the address and size by checking the output of the commands below in Android or TWRP. This example has been taken from Xiaomi Mi 9T.

This tells us that the region begins at  with the size of. The node in the mainline device tree should look like this based on the output above:

Building
Now that you have your initial device tree, build the kernel again. It shouldn't take as long as before. If you get errors regarding your device tree, go to the corresponding line and correct it.

Booting
Because new Android versions use dtbos, which the stock bootloader will merge with the mainline dtb and therefore corrupt it, you will have to erase it first. It is recommended to take a backup of the dtbo partition in case you want to boot Android again.

Boot into recovery mode and take a backup of the dtbo partition with. Afterwards pull the file to your computer to a safe place with. If your device uses A/B partitioning scheme you can switch to an inactive slot and erase dtbo there without taking a backup.

Unless your device is from Samsung, you should be able to just boot the kernel without flashing it:.

If this does not work or you have a device that does not use fastboot, flash the kernel with  (If you want to boot Android again, take a back up of the boot partition).

Assuming everything went well, you should see logs on the screen or in ramoops! The next steps are to get regulators, USB and UFS working so you can get a shell on your device through telnet/ssh.

Contributing
Once you feel like your device tree is ready, you can submit a pull request to sm7150-mainline/linux on GitHub. Make sure your commit titles are named correctly to clearly understand what has been added/changed. You can look at previous commits as a reference.

Have questions?
Join us over at #sm7150-mainline:matrix.org on Matrix. We're happy to help :)