RK3568 Android 13 移植 EC20-CE 4G 模块全记录

目录

前言

[一、EC20-CE 模块简介](#一、EC20-CE 模块简介)

[二、Mini PCIe 接口深度解析](#二、Mini PCIe 接口深度解析)

[1. 什么是 Mini PCIe](#1. 什么是 Mini PCIe)

[2. Mini PCIe 的信号定义](#2. Mini PCIe 的信号定义)

[3. Mini PCIe 的三种工作模式](#3. Mini PCIe 的三种工作模式)

[4. 为什么 EC20-CE 走 USB 通道](#4. 为什么 EC20-CE 走 USB 通道)

三、硬件原理与设备树配置

[1. 电源管理设计](#1. 电源管理设计)

[2. Mini PCIe 的 USB 数据线连接](#2. Mini PCIe 的 USB 数据线连接)

[3. 4G 模块节点](#3. 4G 模块节点)

[4. USB Host 节点使能](#4. USB Host 节点使能)

四、内核驱动适配

[1. USB 设备识别](#1. USB 设备识别)

[2. 串口驱动配置](#2. 串口驱动配置)

[3. 替换 QMI_WWAN 驱动](#3. 替换 QMI_WWAN 驱动)

[4. 零包处理](#4. 零包处理)

[5 防止 option 驱动抢占网络接口](#5 防止 option 驱动抢占网络接口)

[五、Android RIL 服务配置](#五、Android RIL 服务配置)

1.移远一键移植脚本配置

[2. FCM 兼容性矩阵配置](#2. FCM 兼容性矩阵配置)

[3. RIL 守护进程配置](#3. RIL 守护进程配置)

[4. SELinux 配置](#4. SELinux 配置)

5.设置→网络和互联网里添加"移动网络"选项

六、调试与验证

[1. 检查设备节点](#1. 检查设备节点)

[2. 检查 RIL 服务状态](#2. 检查 RIL 服务状态)

[3. Radio Log 分析](#3. Radio Log 分析)

总结


前言

最近在 RK3568 Android 13 平台上适配移远 EC20-CE 模块时,遇到了不少细节问题:移远一键脚本能用但不全、FCM 版本不匹配导致 RIL 服务无响应、libril.so 文件冲突编译报错...... 花了不少时间摸索,总算把所有问题都打通了。

本文从硬件原理设备树配置内核驱动适配Android RIL 服务配置,完整复盘这次移植过程,希望能帮到正在做类似工作的朋友。


一、EC20-CE 模块简介

EC20-CE 是移远通信专为 M2M 和 IoT 应用设计的 LTE Cat 4 模块:

  • 网络制式:支持 LTE FDD/TDD、WCDMA、TD-SCDMA、CDMA、GSM

  • 速率:下行 150Mbps,上行 50Mbps

  • 接口:LCC 封装,支持 USB 2.0、UART、GPIO、(U)SIM

  • 特色功能:多星座 GNSS(可选)、DFOTA 远程升级

本项目中,模块通过 Mini PCIe 接口 与 RK3568 主板连接,采用 USB 通信方式,不涉及 GPS 功能。

二、Mini PCIe 接口深度解析

1. 什么是 Mini PCIe

Mini PCIe(Mini Peripheral Component Interconnect Express)是 PCI-SIG 组织为笔记本等紧凑型设备制定的小型化扩展接口标准。它主要用于连接 Wi-Fi、蓝牙、4G/5G 蜂窝模块、SSD 等内部扩展卡。

物理特性

  • 52-Pin 金手指插槽

  • 尺寸约为 30mm × 50.95mm(全高)或 30mm × 26.8mm(半高)

  • 供电电压主要为 3.3V,部分引脚提供 1.5V

2. Mini PCIe 的信号定义

标准的 Mini PCIe 接口包含以下关键信号组:

信号组 引脚 说明
PCIe 数据通道 引脚 23/25(PETp/n)、31/33(PERp/n) 一对发送、一对接收差分信号,提供 2.5Gbps 带宽
USB 数据通道 引脚 36(USB_D+)、38(USB_D-) 全速/高速 USB 2.0 接口
电源 引脚 2(3.3V)、24(3.3V)、52(3.3V)、引脚 50(1.5V) 主供电和辅助供电
控制信号 引脚 20(W_DISABLE#)、引脚 22(PERST#)、引脚 51(WAKE#) 无线禁用、复位、唤醒

3. Mini PCIe 的三种工作模式

在实际的 RK3568 开发板设计中,Mini PCIe 插槽可能存在以下三种模式:

模式一:标准 PCIe 通道

  • 由 RK3568 内置的 Synopsys DesignWare PCIe 控制器驱动

  • 提供 PCIe Gen2 x1 lane(约 500MB/s 带宽)

  • 适用于需高速数据传输的 Wi-Fi 6/5G 模块

模式二:USB 通道(本文场景)

  • 物理上是 Mini PCIe 形状,但实际走的是 USB 总线

  • 使用引脚 36(USB_D+)和 38(USB_D-)传输数据

  • RK3568 的 USB 2.0 Host 控制器直接驱动

  • 适用于 EC20-CE 等仅支持 USB 通信的 4G 模块

模式三:共享 mSATA 功能

  • Mini PCIe 与 mSATA 接口物理定义基本一致(均基于 52-Pin)

  • 部分主板支持将接口配置为 mSATA 硬盘接口

  • 不能同时作为 Mini PCIe 和 mSATA 使用

4. 为什么 EC20-CE 走 USB 通道

EC20-CE 模块的 USB 接口是其主通信接口,承担以下功能:

  • AT 指令通道 :通过 USB 虚拟出的 ttyUSB* 串口设备发送 AT 指令

  • 数据通路 :通过 USB 协议栈实现 QMI(Qualcomm MSM Interface)通信,最终映射为 wwan0 网络接口

  • 固件升级:通过 USB 进行 DFOTA 升级

对于 RK3568 平台,使用 Mini PCIe 的 USB 通道有以下优势:

  1. 简化硬件设计:无需配置复杂的 PCIe 控制器和时钟

  2. 驱动成熟:Linux 内核自带 USB 串口和 QMI 驱动

  3. 兼容性好:移远官方主要基于 USB 接口提供驱动支持

三、硬件原理与设备树配置


1. 电源管理设计

EC20 供电电压范围为 3.3V~4.3V,典型值 3.8V。这里使用 DCDC 将 12V 转为 3.85V 供电,需注意:

  • 模块瞬时发射功耗较高,电源需提供 2A 以上电流裕量

  • 电源使能时序需早于 USB 枚举

在设备树中定义电源节点:

cpp 复制代码
vcc3v3_miniPcie: vcc3v3-miniPcie-regulator {
         compatible = "regulator-fixed";
         regulator-name = "vcc3v3_miniPcie";
         regulator-always-on;
         regulator-boot-on;
         regulator-min-microvolt = <3300000>;
         regulator-max-microvolt = <3300000>;
         enable-active-high;
         gpio = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>;
         startup-delay-us = <5000>;
         vin-supply = <&dc_12v>;
         pinctrl-names = "default";
         pinctrl-0 = <&pwr_en_4g>;
};

&pinctrl {
        net-4g{
            pwr_en_4g: pwr_en_4g {
                rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
            };
        };
};

2. Mini PCIe 的 USB 数据线连接

在原理图中,Mini PCIe 插座的 引脚 36引脚 38 分别连接到 RK3568 USB 2.0 Host 控制器的 DM/DP 信号线上。这种设计使得模块被系统识别为一个 USB 设备。

3. 4G 模块节点

rk-modem 节点用于上层获取复位等 GPIO 信息:

cpp 复制代码
rk_modem: rk-modem {
        compatible="4g-modem-platdata";
        //4G,power-gpio = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>;
        4G,reset-gpio = <&gpio3 RK_PC1 GPIO_ACTIVE_HIGH>;
        status = "okay";
};

4. USB Host 节点使能

确保 EC20 连接的 USB 端口处于 Host 模式:

XML 复制代码
&usb_host0_ehci {
    status = "okay";
};
&usb_host0_ohci {
    status = "okay";
};

四、内核驱动适配

1. USB 设备识别

由于 Mini PCIe 走的是 USB 通道,模块上电后会被系统识别为 USB 设备。通过 lsusb 可看到 EC20 的 VID:PID(移远 USB VID 为 0x2C7C)。

2. 串口驱动配置

RK3568 内核(4.19/5.10)已自带移远 Option 驱动,无需额外添加 VID/PID。确保以下内核选项开启:

cpp 复制代码
CONFIG_USB_SERIAL=y
CONFIG_USB_SERIAL_OPTION=y
CONFIG_USB_ACM=y

上电后,系统会枚举出 ttyUSB0~ttyUSB3 等串口节点。

还需要修改BoardConfig.mk,确保编译系统里打开4G,如下值为true。

XML 复制代码
device/rockchip/common/BoardConfig.mk

BOARD_HAS_RK_4G_MODEM ?= true
BOARD_HAVE_DONGLE ?= true

3. 替换 QMI_WWAN 驱动

这是最关键的一步。内核自带的 qmi_wwan.c 无法满足 EC20 需求,必须替换为移远提供的 qmi_wwan_q.c

  1. qmi_wwan_q.c 放入 kernel/drivers/net/usb/

  2. 修改该目录下 Makefile

XML 复制代码
kernel-5.10/drivers/net/usb/Makefile

//需要把qmi_wwan_q放到qmi_wwan前面
obj-$(CONFIG_USB_NET_QMI_WWAN)  += qmi_wwan_q.o
obj-$(CONFIG_USB_NET_QMI_WWAN)  += qmi_wwan.o

此驱动会将 USB 数据包转换为网络数据包,生成 wwan0 网络节点,这是 4G 数据通路的关键

4. 零包处理

usb_wwan.c 中添加移远 PID 判断,启用 URB_ZERO_PACKET 标志:

cpp 复制代码
kernel-5.10/drivers/usb/serial/usb_wwan.c

static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port,
                                      int endpoint,
                                      int dir, void *ctx, char *buf, int len,
                                      void (*callback) (struct urb *))
{
        struct usb_serial *serial = port->serial;
        struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial);
        struct urb *urb;

        urb = usb_alloc_urb(0, GFP_KERNEL);     /* No ISO */
        if (!urb)
                return NULL;

        usb_fill_bulk_urb(urb, serial->dev,
                          usb_sndbulkpipe(serial->dev, endpoint) | dir,
                          buf, len, callback, ctx);

        if (intfdata->use_zlp && dir == USB_DIR_OUT)
                urb->transfer_flags |= URB_ZERO_PACKET;
        //====================新增=====================
        if (dir == USB_DIR_OUT) {
            struct usb_device_descriptor *desc = &serial->dev->descriptor;
            if (desc->idVendor == cpu_to_le16(0x2C7C))
               urb->transfer_flags |= URB_ZERO_PACKET;
        }
        //=====================
        return urb;
}

5 防止 option 驱动抢占网络接口

EC20-CE 模块是一个复合 USB 设备,内部包含多个功能接口:串口接口(/dev/ttyUSB*)用于 AT 指令通信,网络接口(wwan0)用于数据传输,此外还有诊断、音频等其他接口。

Linux 内核的 option 驱动可能会"过于积极"地绑定所有看起来像串口的 USB 接口。如果不加干预,option 驱动可能会错误地绑定到本该由 qmi_wwan_q 管理的网络接口 ,导致 wwan0 无法正常创建,RIL 层无法通过 QMI 协议进行数据通信。

因此,需要在 option.coption_probe() 函数中添加过滤逻辑,让 option 驱动主动放弃对非串口接口的绑定:

cpp 复制代码
kernel-5.10/drivers/usb/serial/option.c

static struct usb_serial_driver option_1port_device = {
        .driver = {
                .owner =        THIS_MODULE,
                .name =         "option1",
        },
        .description       = "GSM modem (1-port)",
        .id_table          = option_ids,
        .num_ports         = 1,
        .probe             = option_probe,
        .open              = usb_wwan_open,
        .close             = usb_wwan_close,
        .dtr_rts           = usb_wwan_dtr_rts,
        .write             = usb_wwan_write,
        .write_room        = usb_wwan_write_room,
        .chars_in_buffer   = usb_wwan_chars_in_buffer,
        .tiocmget          = usb_wwan_tiocmget,
        .tiocmset          = usb_wwan_tiocmset,
        .get_serial        = usb_wwan_get_serial_info,
        .set_serial        = usb_wwan_set_serial_info,
        .attach            = option_attach,
        .release           = option_release,
        .port_probe        = usb_wwan_port_probe,
        .port_remove       = usb_wwan_port_remove,
        .read_int_callback = option_instat_callback,
#ifdef CONFIG_PM
        .suspend           = usb_wwan_suspend,
        //------------新增--------------
        .reset_resume = usb_wwan_resume,
        //------------------------------
        .resume            = usb_wwan_resume,
#endif
};

static int option_probe(struct usb_serial *serial,
                        const struct usb_device_id *id)
{
        struct usb_interface_descriptor *iface_desc =
                                &serial->interface->cur_altsetting->desc;
        unsigned long device_flags = id->driver_info;

        /* Never bind to the CD-Rom emulation interface */
        if (iface_desc->bInterfaceClass == USB_CLASS_MASS_STORAGE)
                return -ENODEV;

        /*
         * Don't bind reserved interfaces (like network ones) which often have
         * the same class/subclass/protocol as the serial interfaces.  Look at
         * the Windows driver .INF files for reserved interface numbers.
         */
        if (iface_is_reserved(device_flags, iface_desc->bInterfaceNumber))
                return -ENODEV;

        /*
         * Allow matching on bNumEndpoints for devices whose interface numbers
         * can change (e.g. Quectel EP06).
         */
        if (device_flags & NUMEP2 && iface_desc->bNumEndpoints != 2)
                return -ENODEV;
        //=========================新增===========================
        if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C)) {
            __u16 idProduct = le16_to_cpu(serial->dev->descriptor.idProduct);
            struct usb_interface_descriptor *intf = &serial->interface->cur_altsetting->desc;
            if (intf->bInterfaceClass != 0xFF || intf->bInterfaceSubClass == 0x42) {
                return -ENODEV;
            }
            if ((idProduct&0xF000) == 0x0000) {
                if (intf->bInterfaceNumber == 4 && intf->bNumEndpoints == 3
                    && intf->bInterfaceSubClass == 0xFF && intf->bInterfaceProtocol == 0xFF)
                    return -ENODEV;
             }
        }
        //=======================================================

        /* Store the device flags so we can use them during attach. */
        usb_set_serial_data(serial, (void *)device_flags);

        return 0;
}

五、Android RIL 服务配置

1.移远一键移植脚本配置

移远提供了一键移植脚本配置,具体使用是:将quectel目录放到vendor下,将quectel.sh放在源码顶层目录运行。

经过分析它会删除原生 RIL 配置,从 .mk.rc.xml 中清理旧 Radio/GNSS 服务;修改系统源码,调整 hardware/ril/rild/rild.c、system/core/init/devices.cpp以适配移远模组;添加编译兼容性标志,绕过构建系统的严格检查;包含移远 RIL/GNSS 编译配置,将移远库集成到 Android 编译系统中;启用移动数据功能,修改 overlay 配置,使系统支持蜂窝网络;

执行quectel.sh脚本后,它能够将RIL.mk编译配置文件被包含到你的编译文件去,也就是device/rockchip/rk356x/rk3568_t/rk3568_t.mk。

这里我把在移远官网下载的驱动包和库,以及移远的一键移植资源都已打包绑定本篇文章,文章头部链接可下载。

2. FCM 兼容性矩阵配置

移远一键脚本默认只配置了低版本 IRadio。Android 13 上层若感知不到高版本 Radio 接口,RIL 服务无法正常通信。一般在编译阶段就会报错,因此需要修改FCM7的兼容规则,兼容低版本,在 compatibility_matrix.7.xml 中添加 IRadio 1.5/1.6 支持:

XML 复制代码
hardware/interfaces/compatibility_matrices/compatibility_matrix.7.xml

<hal format="hidl" optional="true">
        <name>android.hardware.radio</name>
        <version>1.6</version>
        <version>1.5</version>
        <version>1.4</version>
        <interface>
            <name>IRadio</name>
            <instance>slot1</instance>
            <instance>slot2</instance>
            <instance>slot3</instance>
        </interface>
</hal>

3. RIL 守护进程配置

需要修改 rild.rc,指定加载 libreference-ril.so,删除之前的/vendor/bin/hw/rild

bash 复制代码
hardware/ril/rild/rild.rc

service ril-daemon /vendor/bin/hw/rild -l /vendor/lib64/libquectel-ril.so
     class main
     user radio
     group radio cache inet misc audio sdcard_rw log
     capabilities BLOCK_SUSPEND NET_ADMIN NET_RAW

4. SELinux 配置

配置RIL的SELinux规则

bash 复制代码
device/rockchip/common/rootdir/ueventd.rockchip.rc

#quectel port
/dev/ttyUSB*             0660   radio    radio
/dev/ttyACM*             0660   radio    radio
/dev/cdc-wdm*            0660   radio    radio
/dev/qcqmi*              0660   radio    radio
/dev/cdc-acm*            0660   radio    radio
#PCIe
/dev/mhi_DUN             0660   radio    radio
/dev/mhi_DIAG            0660   radio    radio
/dev/mhi_BHI             0660   radio    radio
/dev/mhi_LOOPBACK        0660   radio    radio
/dev/mhi_QMI0            0660   radio    radio
bash 复制代码
device/rockchip/common/sepolicy/private/file_contexts

#quectel port
/dev/ttyUSB[0-9]    u:object_r:radio_device:s0
/dev/ttyACM[0-9]    u:object_r:radio_device:s0
/dev/cdc-wdm[0-9]   u:object_r:radio_device:s0
/dev/qcqmi[0-9]     u:object_r:radio_device:s0
/vendor/bin/hw/rild     u:object_r:rild_exec:s0
/dev/socket/rildOemHook u:object_r:rild_socket:s0

#pcie
/dev/mhi_DUN    u:object_r:radio_device:s0
/dev/mhi_DIAG   u:object_r:radio_device:s0
/dev/mhi_BHI    u:object_r:radio_device:s0
/dev/mhi_LOOPBACK   u:object_r:radio_device:s0
/dev/mhi_QMI0       u:object_r:radio_device:s0
bash 复制代码
system/sepolicy/vendor/rild.te

allow rild self:packet_socket { create bind write read };

5.设置→网络和互联网里添加"移动网络"选项

XML 复制代码
device/rockchip/rk356x/overlay/frameworks/base/core/res/res/values/config.xml
 
  <string-array translatable="false" name="networkAttributes">
      <item>"wifi,1,1,2,-1,true"</item>
<!-- -------------新增------------------->
      <item>"mobile,0,0,0,-1,true"</item>
      <item>"mobile_mms,2,0,2,60000,false"</item>
      <item>"mobile_supl,3,0,2,60000,true"</item>
      <item>"mobile_dun,4,0,2,60000,true"</item>
      <item>"mobile_hipri,5,0,3,60000,true"</item>
      <item>"mobile_fota,10,0,2,60000,true"</item>
      <item>"mobile_ims,11,0,2,60000,true"</item>
      <item>"mobile_cbs,12,0,2,60000,true"</item>
<!-- ----------------------------------->
      <item>"bluetooth,7,7,0,-1,true"</item>
      <item>"ethernet,9,9,9,-1,true"</item>
  </string-array>

六、调试与验证

1. 检查设备节点

XML 复制代码
ls -l /dev/ttyUSB*

应显示 ttyUSB0~ttyUSB3 等串口节点。

bash 复制代码
ifconfig -a

应显示 wwan0 网络接口。

2. 检查 RIL 服务状态

bash 复制代码
getprop init.svc.ril-daemon

应返回 running

3. Radio Log 分析

bash 复制代码
logcat -b radio

总结

以上为在 RK3568 Android 13 上移植 EC20-CE 模块的完整过程,希望这篇记录能帮助你在 RK3568 平台上的 4G 开发少走弯路。

相关推荐
网安蟹佬霸1 小时前
Android安全攻防实战:从APK逆向到Frida动态Hook全流程详解(附脚本)
android·前端·安全·web安全·逆向·csrf·网安
雨声不在1 小时前
mitmdump Android 抓包
android
心平气和量大福大1 小时前
android-实例2-数据库sqlite(查询)
android·数据库·sqlite
时代分流1 小时前
云手机推荐2026:安卓全能、批量挂机、原生iOS全覆盖
android·ios·智能手机
恋猫de小郭1 小时前
Gradle 9.7.0 将提速 Android 构建,Sync 提升接近一倍
android·前端·flutter
Dovis(誓平步青云)2 小时前
心情日记的安全编辑流程:输入校验、删除确认与状态回收
android·运维·服务器·开发语言·windows·安全
宋拾壹2 小时前
php对接携程验票核销
android·php·android studio
weixin_4038101311 小时前
AI智能体写安卓自动化脚本教程:Cursor/Trae+CLI 实战,自然语言生成代码
android·人工智能·自动化·跨境电商·安卓自动化脚本·多账户运营
呆呆小孩13 小时前
零基础学 MySQL(上):从建库建表到增删改查,一篇搭好 SQL 基础
android·sql·mysql