Qualcomm Snapdragon 845/850 (SDM845/SDM850)

From postmarketOS Wiki
Qualcomm SDM845
Manufacturer Qualcomm
Name SDM845
Codenames hoya
Architecture aarch64
CPU 4x 2.8 GHz Kryo 385 Gold (Cortex-A75), 4x 1.8 GHz Kryo 385 Silver (Cortex-A55)
GPU Adreno 630
Year 2018
Process 10nm
Mainline yes
Community Page https://gitlab.com/sdm845-mainline
Components
CPU
Works
UART
Works
Storage
Works
USB
Works
Display
Works
GPU
Works
Pinctrl
Works
I²C
Works
SPI
Audio
Works
Video
Works
Thermal
Works
WiFi
Works
Bluetooth
Works
Modem
Partial
GPS
Works
Camera
Works
NPU
Suspend
Works
Ethernet


SDM845 (or Snapdragon 845) is a Qualcomm SoC released in 2018, with mainline support originally added for the Dragonboard 845c. It is currently one of the fastest mobile SoCs booting Mainline with full support for hardware accelerated graphics, CPU frequency scaling and wifi/bluetooth, with more features on the way.


Devices

SDM845 (Snapdragon 845)

Device Codename Mainline Category
AYN Odin ayn-odin Y testing
Google Pixel 3 google-blueline P testing
Google Pixel 3 XL google-crosshatch testing
LG G7 ThinQ lg-judyln Y testing
LG V35 ThinQ lg-judyp Y testing
Meizu 16th meizu-m1882 Y testing
OnePlus 6 oneplus-enchilada Y community
OnePlus 6T oneplus-fajita Y community
Qualcomm Snapdragon 845 qualcomm-sdm845 Y testing
Samsung Galaxy S9 (SM-G9600/DS) samsung-starqltechn testing
SHIFT SHIFT6mq shift-axolotl Y community
Sony Xperia XZ2 sony-akari P testing
Sony Xperia XZ2 Compact sony-apollo P testing
Sony Xperia XZ3 sony-akatsuki P testing
Thundercomm Dragonboard 845c thundercomm-db845c Y community
Xiaomi Mi 8/Mi 8 Pro/Mi 8 Explorer xiaomi-dipper, xiaomi-equuleus, xiaomi-ursa N testing
Xiaomi Mi Mix 2S xiaomi-polaris Y testing
Xiaomi Mix 3 xiaomi-perseus Y testing
Xiaomi Pocophone F1 / POCO F1 xiaomi-beryllium Y community

SDM850 (Snapdragon 850)

Device Codename Mainline
Huawei MateBook E 2019 huawei-planck Y
Lenovo Yoga C630 lenovo-yoga-c630 Y

UFS internal storage

Icon WARNING: IF YOUR DEVICE IS A SONY XPERIA DO NOT NEVER EVER EVER TRY TO ENABLE UFS ON NON-VENDOR/NON-SODP KERNELS! IT WILL ERASE THE CHIP CLEAN (INCLUDING THE BOOTLOADER!) CONSIDER YOURSELF WARNED

Join Us!

If you own an SDM845 device and want to get postmarketOS & mainline booting, head over to the #mainline:postmarketos.org postmarketOS mainline channel.

We also discuss packaging, other distros and various other non-porting stuff on matrix: #sdm845:postmarketos.org.

Feel free to ping @caleb:postmarketos.org.

Adding yours

If you have an SDM845 based device that isn't in this list you should definitely do something about that, checkout the SDM845 Mainlining Guide for instructions on porting new devices. It is fairly straightforward to get core functionality working on most devices.

Icon-numix-light-system-run.svg
SDM845 Mainlining

Audio

The kernel side audio stuff is mostly functional on SDM845.

Modem

The modem is booted by the Q6V5 MSS Peripheral Image Loader, it is required to boot the WiFi adapter. It is exposed via the QRTR_NET layer, a custom shared memory transport layer developed by Qualcomm. Over this the standard QMI interface is exposed. ModemManager has great support for QRTR and thus it is possible to send/receive SMS, use mobile data and make calls.


References

  • pmaports!1356 Relevant discussion on renaming the msm-modem package as rpmsgexport is not needed on SDM845.

Wakeups

Wakeups are a concept in the Linux kernel referring to a specific device or subdevice that can cause the system to exit suspend, usually via an interrupt. A good example of this is the power button, when pressed it fires an interrupt, and because that interrupt is denoted as a "wakeirq" (an interrupt that when fired _should_ wake the system from suspend) that's exactly what happens.

Context

Qualcomm platforms currently (at least as far back as SDM845) don't have a real suspend mode. The closest we get is suspend to idle (s2idle), this has the kernel freeze all of userspace and almost all kernel threads. In s2idle, peripherals (e.g. the touchscreen) can be powered down, the CPU timers (which usually fire periodic interrupts) are disabled, and the CPUs are able to spend the majority of their time in their lowest idle states. This isn't enough to enable a device to go for days at a time without charging, but it is more than enough to get through a single day at least.

When in s2idle, all interrupts are disabled with two exceptions: (enabled) wakeirqs, and irqs with the IRQF_NO_SUSPEND flag. Wakeirqs may not always be enabled, for example if your touchscreen has a double tap to wake feature then the driver would denote its IRQ as "wakeup capable", this associated a "wakeup" with the interrupt. The wakeup can then be enabled via sysfs or in the driver somewhere. If a wakeup capable interrupt doesn't have its wakeup feature enabled then the irq will be disabled during s2idle.

The IRQF_NO_SUSPEND flag enables a driver to run its interrupt handler and process interrupts while the kernel is in s2idle. This is useful for some essential housekeeping duties that have to happen even when the user isn't interacting with the device.

Glink

Glink is a communication mechanism used by Qualcomm SoCs to enable communication between the different processors (e.g. the Modem, Audio/Compute DSPs and Sensor DSP). It is a peer to peer system based on shared memory, every pair of processors (e.g. the AP (Linux) and Modem) have their own glink edge made up of a shared memory region and a pair of interrupts, one on the modem side and one for us. To provide a very simplified explanation: data is sent and received by finding a free "bucket" in the shared memory region, putting your data in the bucket, and then triggering an interrupt on the other side.

Glink is a kind of mesh network where (for the most part) every processor is connected to every other. It represents the "Link Layer".

The Glink driver makes use of the IRQF_NO_SUSPEND flag, meaning that even when in s2idle the kernel will still process interrupts from Glink. This allows for pending messages to be handled and queued up for userspace where they might otherwise be missed.

QRTR

On top of glink is the protocol layer, QRTR (Pronounced Q-Router). QRTR is a socket-based network protocol that allows for a much higher level of communication. Each processor can expose services over the QRTR network, programs on other processors can connect to and utilise these services. For example, the modem provides a Wireless Data Service for configuring a mobile data connection, the Sensor DSP also provides its own service for retreiving sensor data (See Qualcomm_Snapdragon_Sensor_Core).

QRTR represents the "Internet Layer", performing routing and session management.

QMI

QMI is a TLV (Type-Length-Value) binary format. It predates QRTR and is quite common in modems. It serves as the transport layer, however it also defines what messages can be sent/received and how the messages are formatted. QMI is the only mechanism used by ModemManager to communicate with the modem to initiate calls, send SMS, retrieve SIM and signal status information, cell tower information, etc. An incoming call or SMS is signalled by the modem sending a QMI message.

In summary

Walking back down the stack, when you receive a phone call, the modem will check that you have an active QRTR session with it (this will be the case if ModemManager hasn't explicitly closed the connection) which is subscribed to incoming calls. It will send a QMI message to notify ModemManager. It goes roughly as follows:

1. The message is transported over QRTR and sent via Glink.
2. The Glink interrupt will fire and run the interrupt handler in the kernel.
3. The interrupt handler reads the message and passes it on the QRTR protocol implementation in the kernel.
4. The QRTR net code queues it up to be received by userspace on the next poll()

This is all well and good, however when we're in s2idle, userspace is frozen, there's no way to handle the message, figure out that it's a call, and make the phone ring.

Waking up for calls and SMS

Without a way to properly differentiate between a signal strength change and an incoming call, it isn't possible for the kernel to know which messages from the modem should cause a wakeup, and which should not. All we have is a global switch.

The ideal solution here is that ModemManager becomes capable of disabling all non-essential notifications from the modem before the device suspends. While currently ModemManager is not able to do this, there is a patch for 1.22.0 available here: disable_3gpp_unsolicited_1.22.0.patch. When issue MM!927 is resolved an MR will be made to make this standard, hopefully in time for 1.23. However, this only works when wlan is not connected, as the ath10k driver is heavily hitting the QIPCRTR irq as well.

For now, you can make sure that you never miss a call by waking up for every incoming message from the modem. This would be acceptable if it were possible to do this without immediately turning on the display, and if the message isn't a call or SMS, automatically suspending again. For Phosh, I believe this requires support to be added to GNOME session daemon to wake up without turning on the display. Figuring out why the device woke up (maybe it was a power button press or USB cable insertion) requires keeping track of all the counts in /sys/class/wakeup/wakeup*/wakeup_count and then having a look up table for each wakeup (to know that e.g. wakeup /sys/devices/platform/soc@0/c440000.spmi/spmi-0/0-00/c440000.spmi:pmic@0:pon@800/c440000.spmi:pmic@0:pon@800:pwrkey/wakeup is associated with the power button)

You can enable this wakeup for yourself by running the following command as root:

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

This will cause the device to wake up for all incoming data from the modem.

Waking up for notifications

When on a mobile data connection, the IPA (Qualcomm dedicated network packet routing hardware) will wake up the device by default for any incoming data, this usually has no effect as most TCP connections have a relatively short TCP keepalive time. However the plan is to disable it by default for now (see pmaports!4122) to avoid any confusion.

The IPA has the ability to maintain a TCP connection and perform some arbitrary filtering to avoid waking up the device for things that aren't notifications, e.g. matching on source IP or specific magic bytes in the packet. Unfortunately the mainline kernel driver doesn't yet implement any of these features.

The Wifi on SDM845 is ath10k and includes full Wake-On-WLAN (WoWLAN) support! Using the iw utility it's possible to enable waking up on actions like wifi disconnect, specific SSIDs becoming available, or via packet matching based on source/destination IP, magic bytes, etc.

Ath10k hardware supports offloading station keepalive, where it will send null packets to whatever AP your device is connected to in order to ensure that it doesn't get dropped. However this feature is explicitly disabled (via This patch) in favour of software polling, perhaps worth reinvestigating!

A notification push client service could be taught how to utilise WoWLAN and the IPA to maintain a persistent TCP connection with the server and cause the device to wake up for incoming notifications. It should be possible to also implement automatic switching between mobile data and wifi, between wifi networks, and between mobile cell towers. WoWLAN can wake up on wifi disconnect, and the modem can wake up when switching cell tower, allowing the connection to be re-established. A very long keepalive time will ensure that it doesn't drop for some other reason.

WiFi

Wifi is functional! Firmware for the modem and ath10k module must be loaded in order to have functional wifi.

3 packages are required for functional wifi:

rmtfs, pd-mapper and tqftpserv can be installed with

apk add rmtfs pd-mapper tqftpserv

(pmaports!1080).

This readme can then be followed to fixup the firmware.

Some devices need this quirk enabled for ath10k probe to succeed.

More details may also be found on the Snapdragon 835 SoC page.

Display

The Adreno 630 is relatively easy to work with, after adding a driver for your panel, obtain the firmware from your device and either compile into the kernel (in addition to enabling CONFIG_DRM_FBDEV_EMULATION for early dmesg)) or add to the right subdirectory under /lib/firmware.


I2C

I2C and the Geni hardware is functional and supported, however it is missing a driver for special GPI DMA mode used by a few devices (e.g. touchscreen on Enchilada). As of 5.11-rc1 geni is capable of DMA, however not through the GPI hardware. The issues previously discussed here no longer apply.

Sensors

Typically you would interact with sensors via iio-sensor-proxy, However on sdm845 sensors you need to use hexagonrpcd and libssc.

Hexagonrpcd

Sensor registry:

in version 0.1 /var/lib/qcom/sensors (Postmarket OS)
in version 0.3 /usr/share/qcom/sensors (Latest)

Note:

release build is non functional at the moment, use debug build instead.

git clone https://gitlab.com/flamingradian/sensh/
cd sensh
meson build
ninja -C build

cd fastrpc
meson build
ninja -C build

Then run (As root)

build/hexagonrpcd/hexagonrpcd -f /dev/fastrpc-sdsp -s

Libssc

git clone https://codeberg.org/DylanVanAssche/libssc.git
cd libssc
meson build
ninja -C build

Then you can run

build/src/ssccli --sensor=light

If all goes well you should see the light sensor's value.

Bluetooth

There are 2 firmwares installed on the system:
/lib/firmware/qca/crbtfw21.tlv and /lib/firmware/postmarketos/qca/crbtfw21.tlv


The firmware needs to be overwritten in order for the driver to load properly

echo -n /lib/firmware/postmarketos > /sys/module/firmware_class/parameters/path


Otherwise it will fail to load and show up in dmesg with:

Bluetooth: hci0: QCA TLV with error stat 0x0 rtype 0x4 (0x5)
Bluetooth: hci0: Opcode 0x0c03 failed: -110


In addition you must set a proper mac address otherwise the BT adapter will be in a broken state.
In postmarketOS this is handled by /usr/bin/bootmac which can be simplified down to this:

#!/bin/sh
SERIAL=$(grep -o "serialno.*" /proc/cmdline | cut -d" " -f1)
BT_MAC=$(echo "$SERIAL-BT" | sha256sum | awk -v prefix=0200 '{printf("%s%010s\n", prefix, $1)}')
BT_MAC=$(echo "$BT_MAC" | cut -c1-12 | sed 's/\(..\)/\1:/g' | sed '$s/:$//')

btmgmt -i hci0 power off
btmgmt -i hci0 public-addr "$BT_MAC"

Haptics

Haptics is supported! See Haptics for more details.

Bootloaders

Renegade Project

Renegade Project support some sdm845 device

uboot

In progress u-boot port exists

See also

Who's working on it

Icon TODO: add more devs :D