BTW, you will probably need a song for this reading:
Mobile modules
These modules exist in different form factors (LGA, PCIe, and PCI-SIG M.2) depending on supported slots and the modularity chosen for the connected object.

A view of a naked module like the EC20 can be observed in the following picture:

Mobile modules include the following components:
- an application processor;
- DRx and PRx frontends with adapted antennas;
- a baseband processor;
- but also a NAND and DDR memories, a PMIC (RTC), I/O interfaces, etc.

The baseband is used to process signals to receive and transmit data over the radio using a specific mobile stack to communicate. In this context, the on-chip application processor provides many features, including the implementation of the USB devices you can see on the host by connecting the module to a PC (e.g: /dev/ttyUSBx). Harald Welte and the Osmocom team showed that an OE based Linux lso runs on some mobile modules, such as the Quectel EC20.
Among the devices exposed by the module, some can be used to communicate with AT command; others can also tell DIAG interface to talk with the baseband (see xgoldmon and diag-parse projects for XGold and Qualcomm modems, respectively).
For further information, please find some interesting resources from Osmocom about Cellular modems like the Quectel EC20.
Firmware Updates
To delight customers with the latest version and new features but also provide fixes to used modules, vendors generally support two types of firmware update methods:
- wireless delivery via FOTA by default;
- through the serial line.
These updates also avoid costly product recalls in case of a severe mobile baseband or a user software defect.
Vendors generally provide customers a utility to update the firmware and link to the latest release binaries for the serial line update. This utility can be run against an exposed USB/USIF interface from the mobile module to the host to update the firmware.
These utilities use a proprietary protocol that generally goes into different steps:
- checking current version;
- restarting the device;
- entering the boot mode;
- then reading the stream and uploading it to update the module.
Here is a sample of these steps from the pseudo-code of one of the disassembled utilities retrieved with Ghidra:
[...]
if (pcVar3 == (char *)0x0) {
dbg_print(1,"Current firmware is up to date. Nothing to do.n");
close(fdStream);
destroyDevice(dev);
/* WARNING: Subroutine does not return */
exit(0);
}
}
}
if (boot_delay != 0) {
setBootDelay(dev,boot_delay);
dbg_print(1,"Forced boot delay %d msn",boot_delay);
}
if ((0 < deviceSpeed) && (usb_flag == 0)) {
setDeviceSpeed(dev,(uint8_t)deviceSpeed);
dbg_print(1,"Setting device speed %dn",deviceSpeed);
}
if (restart_needed != 0) {
if (atDevice[0] == '