Modem on PinePhone
EG25-G modem in PinePhone handles WWAN, GPS and celular services. It is
Qualcomm MDM 9607 chipset, has 256 MiB DRAM, 256 MiB
NAND, and a single Cortex-A7 CPU clocked up to 1.3GHz.
The modem's firmware is split into two parts:
- Linux kernel + userspace runs on an ARM CPU
- Modem's firmware runs on Hexagon ADSP
Most AT commands are run on a separeate DSP processor cores
(Hexagon QDSP6 V5), with some being forwarded to a Linux userspace program
atfwd_daemon running on the ARM CPU.
Reverse engineering the exisintg software for ARM CPU inside the modem is quite easy using ghidra. ADB unlocker was made this way.
Modem power driver
My kernel is a bit special, since it contains a special modem power manager driver (released 2020–08–03 along with Linux 5.8).
My driver implements several features:
- it ensures modem is configured properly for audio and sleep
- it implements airplane mode via rfkill interface
- it implements modem suspend/resume
- it hides PinePhone variant differences
- it implements URC caching on all pinephone variants regardless of AP_READY availability
- it makes the modem sleep most of the time
- it handles powerup/powerdown errors properly
- it checks for killswitch and reports it to userspace/dmesg
- it doesn't waste time during powerdown and waits for actual modem powerdown (it doesn't just sleep for a fixed time)
- it handles SoC wakeup on RI
- it shuts down the modem properly during kernel powerdown/reboot to avoid data loss inside the modem's NAND flash
- it reports all errors to dmesg for easy troubleshooting/failure detection
Enabling and disabling the power to the modem is as simple as:
# request powerup echo 1 > /sys/class/modem-power/modem-power/device/powered # request powerdown echo 0 > /sys/class/modem-power/modem-power/device/powered # read power status (changes only after power state transition is complete) cat /sys/class/modem-power/modem-power/device/powered
So there's no need to mess with gpios via sysfs.
Connecting to the modem
You can connect to the modem once it's powered up via:
screen /dev/ttyUSB2 115200
Setting up the modem for voice calling
Once per a lifetime you have to run
AT+QDAI=1,0,0,2,0,1,1,1 and reboot the modem. That will configure
audio on the modem side correctly and store the configuration persistently
inside the modem. This is not necessary if you use my modem driver.
To setup audio for call use my call audio setup program.
You need to run the program after the call starts twice. Once
with your desired audio setup without
-2 option and once with
To answer a call type
ATA, to make a
ATDsomenumber;, to hangup
That's it. ;)
Modem reverse engineering
See this page for details.
Unlock ADB access
It's possible to access the Linux side of the modem via adb, or reboot the modem to fastboot mode and boot your own kernel, The modem is rooted by default, and you can install and run your own software inside the modem. It's possible to communicate between A64 and the modem's ARM CPU via USB serial port (ttyGS0 on modem side and ttyUSB1 on A64).
possible to create your own URCs up to 128B in size by sending them as a
datagram message to UNIX socket
/tmp/.urc_sock. See urc.c.
To install your own program on the modem
persistently you need to remount modem's root filesystem read write and install
your program somewhere in
/usr/bin. Add your startup script to
adb access to the
- Get adb key via
- Enter the adb key to the unlocker utility
- Follow the instructions from the
- Install or get
adbfor your distribution
adb shellshould get you a root shell on the modem
adb pushcan be used to copy files to/from the modem
On Arch Linux ARM, adb is no longer
supported, so you need to compile it from source code. You can use https://github.com/…uong/arm_adb with this patch to
make it work with current
Modem power management
Various PinePhone variants have SoC GPIOs routed to the modem differently. So you need to be aware of what PinePhone variant you have, when experimenting with the modem.
Power management comes down to:
- letting the modem sleep when it's not in use, and waking it up when it's needed for something,
- and letting the host sleep, and configure the modem to wake the host up, when some important event happens (incomming call, sms, …).
Summay of modem's behavior related to powerup/powerdown and power management:
- powerup takes about 14s, unless the modem is too hot (>50–60°C), then it may take as long as 22s due to CPU inside the modem being downclocked from 1.3Ghz to 400MHz
- configuration of the physical UART and ttyUSB2 is shared for some reason, so ATE0 issued on UART will turn echo off also on ttyUSB2
- modem sleeps when an election process based on the status of USB port, DTR pin, etc. results in a positive decision
- modem disables RF
based on #W_DISABLE only when configured to do so
- modem wakes up the host via
USB or RI pin based on
- modem will
cache URCs based on
AP_READYpin's status only when
- powerdown takes about the same time as powerup