105 lines
8.8 KiB
HTML
105 lines
8.8 KiB
HTML
<!DOCTYPE html>
|
||
<html><head>
|
||
<meta http-equiv="content-type" content="text/html; charset=UTF-8"><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="referrer" content="no-referrer"><link rel="stylesheet" href="Modem%20on%20PinePhone_files/style.css"><title>Modem on PinePhone</title></head><body><header><div class="title"><a href="https://xnux.eu/index.html">xnux.eu</a> - <a href="https://xnux.eu/map.html">site map</a> - <a href="https://xnux.eu/news.html">news</a></div></header><main><section><h1 id="toc-modem-on-pinephone">Modem on PinePhone</h1><div style="float:right"><a href="https://xnux.eu/contribute.html"><img src="Modem%20on%20PinePhone_files/contrib.png" style="vertical-align: middle"> Contribute</a></div><p><a href="https://www.quectel.com/product/eg25g.htm" class="external">Quectel
|
||
EG25-G</a> modem in PinePhone handles WWAN, GPS and celular services. It is
|
||
based on <code>Qualcomm MDM 9607</code> chipset, has 256 MiB DRAM, 256 MiB
|
||
NAND, and a single Cortex-A7 CPU clocked up to 1.3GHz.</p><p>The
|
||
modem's firmware is split into two parts:</p><ul><li>Linux kernel + userspace
|
||
runs on an ARM CPU</li><li>Modem's firmware runs on Hexagon
|
||
ADSP</li></ul><p>Most AT commands are run on a separeate DSP processor cores
|
||
(Hexagon QDSP6 V5), with some being forwarded to a Linux userspace program
|
||
called <code>atfwd_daemon</code> running on the ARM CPU.</p><p>Reverse
|
||
engineering the exisintg software for ARM CPU inside the modem is quite easy
|
||
using ghidra. ADB unlocker was made this way.</p><h2 id="toc-modem-power-driver">Modem power driver</h2><p>My kernel is a bit
|
||
special, since it contains a special <a href="https://megous.com/git/linux/commit/?h=modem-5.8&id=9e26fe7200672c64256652b916319873fd602ebf" class="external">modem power manager driver</a> (released 2020–08–03 along
|
||
with Linux 5.8).</p><p>My driver implements several features:</p><ul><li>it
|
||
ensures modem is configured properly for audio and sleep</li><li>it implements
|
||
airplane mode via rfkill interface</li><li>it implements modem
|
||
suspend/resume</li><li>it hides PinePhone variant differences</li><li>it
|
||
implements URC caching on all pinephone variants regardless of AP_READY
|
||
availability</li><li>it makes the modem sleep most of the time</li><li>it
|
||
handles powerup/powerdown errors properly</li><li>it checks for killswitch and
|
||
reports it to userspace/dmesg</li><li>it doesn't waste time during powerdown and
|
||
waits for actual modem powerdown (it doesn't just sleep for a
|
||
fixed time)</li><li>it handles SoC wakeup on RI</li><li>it shuts down the modem
|
||
properly during kernel powerdown/reboot to avoid data loss inside the
|
||
modem's NAND flash</li><li>it reports all errors to dmesg for easy
|
||
troubleshooting/failure detection</li></ul><p>Enabling and disabling the
|
||
power to the modem is as simple as:</p><pre class="hl"><span class="hl
|
||
slc"># request powerup</span>
|
||
<span class="hl kwb">echo</span> <span class="hl
|
||
num">1</span> <span class="hl opt">> /</span>sys<span class="hl
|
||
opt">/</span>class<span class="hl opt">/</span>modem<span class="hl
|
||
kwb">-power</span><span class="hl opt">/</span>modem<span class="hl
|
||
kwb">-power</span><span class="hl opt">/</span>device<span class="hl
|
||
opt">/</span>powered
|
||
<span class="hl slc"># request powerdown</span>
|
||
<span class="hl kwb">echo</span> <span class="hl num">0</span> <span class="hl
|
||
opt">> /</span>sys<span class="hl opt">/</span>class<span class="hl
|
||
opt">/</span>modem<span class="hl kwb">-power</span><span class="hl
|
||
opt">/</span>modem<span class="hl kwb">-power</span><span class="hl
|
||
opt">/</span>device<span class="hl opt">/</span>powered
|
||
<span class="hl
|
||
slc"># read power status (changes only after power state transition is complete)</span>
|
||
<span class="hl kwc">cat</span> <span class="hl opt">/</span>sys<span class="hl
|
||
opt">/</span>class<span class="hl opt">/</span>modem<span class="hl
|
||
kwb">-power</span><span class="hl opt">/</span>modem<span class="hl
|
||
kwb">-power</span><span class="hl opt">/</span>device<span class="hl
|
||
opt">/</span>powered
|
||
</pre><p>So there's no need to mess with gpios via
|
||
sysfs.</p><h2 id="toc-connecting-to-the-modem">Connecting to the
|
||
modem</h2><p>You can connect to the modem once it's powered up via:</p><pre class="hl">screen <span class="hl opt">/</span>dev<span class="hl
|
||
opt">/</span>ttyUSB2 <span class="hl num">115200</span>
|
||
</pre><p>Disconnect by
|
||
<code>CTRL+a k</code>.</p><h2 id="toc-setting-up-the-modem-for-voice-calling">Setting up the modem for voice
|
||
calling</h2><p>Once per a lifetime you have to run
|
||
<code>AT+QDAI=1,0,0,2,0,1,1,1</code> 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.</p><p>To
|
||
setup audio for call use my <a href="https://xnux.eu/devices/feature/audio-pp.html">call audio setup
|
||
program</a>.</p><p>You need to run the program after the call starts twice. Once
|
||
with your desired audio setup without <code>-2</code> option and once with
|
||
<code>-2</code> option.</p><p>To answer a call type <code>ATA</code>, to make a
|
||
call <code>ATDsomenumber;</code>, to hangup <code>ATH</code>.</p><p>That's it.
|
||
;)</p><h2 id="toc-modem-reverse-engineering">Modem reverse
|
||
engineering</h2><p>See <a href="https://xnux.eu/devices/feature/modem-pp-reveng.html">this page for
|
||
details</a>.</p><h2 id="toc-unlock-adb-access">Unlock ADB
|
||
access</h2><p>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).</p><p>It's also
|
||
possible to create your own URCs up to 128B in size by sending them as a
|
||
datagram message to UNIX socket <code>/tmp/.urc_sock</code>. See <a href="https://xnux.eu/devices/feature/urc.c" class="file">urc.c</a>.</p><p>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 <code>/usr/bin</code>. Add your startup script to
|
||
<code>/etc/init.d</code>.</p><p>To get <code>adb</code> access to the
|
||
modem:</p><ul><li>Get adb key via <code>AT+QADBKEY?</code></li><li>Enter the adb
|
||
key to the <a href="https://xnux.eu/devices/feature/qadbkey-unlock.c" class="file">unlocker
|
||
utility</a></li><li>Follow the instructions from the
|
||
<code>qadbkey-unlock</code></li><li>Install or get <code>adb</code> for your
|
||
distribution</li><li><code>adb shell</code> should get you a root shell on
|
||
the modem</li><li><code>adb pull</code> and <code>adb push</code> can be used
|
||
to copy files to/from the modem</li></ul><p>On Arch Linux ARM, adb is no longer
|
||
supported, so you need to compile it from source code. You can use <a href="https://github.com/qhuyduong/arm_adb" class="external">https://github.com/…uong/arm_adb</a> with <a href="https://xnux.eu/devices/feature/0001-Fix-build-on-modern-Arch-Linux.patch" class="file">this patch</a> to
|
||
make it work with current <code>openssl</code>.</p><h2 id="toc-modem-power-management">Modem power management</h2><p>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.</p><p>Power management comes down to:</p><ul><li>letting the modem
|
||
sleep when it's not in use, and waking it up when it's needed for
|
||
something,</li><li>and letting the host sleep, and configure the modem to wake
|
||
the host up, when some important event happens (incomming call,
|
||
sms, …).</li></ul><p>Summay of modem's behavior related to
|
||
powerup/powerdown and power management:</p><ul><li>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</li><li>configuration of the physical UART and ttyUSB2 is shared for
|
||
some reason, so ATE0 issued on UART will turn echo off also on
|
||
ttyUSB2</li><li>modem sleeps when an election process based on the status of USB
|
||
port, DTR pin, etc. results in a positive decision</li><li>modem disables RF
|
||
based on #W_DISABLE only when configured to do so
|
||
via <code>AT+QCFG="airplanecontrol"</code></li><li>modem wakes up the host via
|
||
USB or RI pin based on <code>AT+QCFG="risignaltype"</code></li><li>modem will
|
||
cache URCs based on <code>AP_READY</code> pin's status only when
|
||
<code>AT+QCFG="apready"</code> is configured</li><li>powerdown takes about the
|
||
same time as powerup</li></ul></section></main><footer><p>E-mail: <a href="mailto:x@xnux.eu">x@xnux.eu</a> - <a href="https://xnux.eu/map.html" accesskey="m">site map</a> - <a href="https://xnux.eu/rss.xml">RSS</a></p></footer></body></html> |