RK Android11 WiFi模组 AIC8800 驱动移植流程

06-02 1368阅读

RK Android WiFi模组 AIC8800 驱动移植流程

  • 作者:Witheart
  • 更新时间:20250220

    概要:本文介绍了基于 AIC8800D40 芯片的 WiFi6 模组 BL-M8800DS2-40 在 RK3568 平台上的驱动移植流程。主要涉及环境搭建、驱动代码分析、设备树修改、驱动编译配置、蓝牙库集成、wpa_supplicant 配置及 WiFi HAL 适配等内容,并提供详细的移植步骤和注意事项。

    问题调试在另一篇文章:https://blog.csdn.net/Beihai_Van/article/details/145772085


    1. 环境

    • WiFi 模组:BL-M8800DS2-40(基于 AIC8800D40 芯片)
    • CPU:RK3568
    • OS:Android

      2. WiFi芯片与WiFi模组的区别

      • WiFi 芯片:核心部件,集成射频前端、基带处理器、数字信号处理等功能。
      • WiFi 模组:基于 WiFi 芯片的完整无线通信组件,包含天线、外围电路、接口等。

        AIC8800 属于 WiFi 芯片,而本次移植的 WiFi 模组是 BL-M8800DS2-40(基于 AIC8800D40)。

        WiFi6 模组_必联(LB-LINK)官方网站

        RK Android11 WiFi模组 AIC8800 驱动移植流程

        3. AIC8800 驱动代码包详解

        3.1 驱动代码包结构

        厂家送样后,需要获取最新的驱动代码包,并确保版本与模组匹配。驱动代码版本错误可能引发诸多问题。

        RK Android11 WiFi模组 AIC8800 驱动移植流程

        3.2 Patch 注意事项

        在 SDIO\patch\for_Rockchip\3566\Android11 目录下,提供了 Rockchip 平台的移植补丁(更像是移植成功的参考案例,不同wifi芯片还要具体配置),移植过程中需对比 mod 和 orig 文件夹的区别,可利用 git 进行差异分析。

        在移植过程中需要注意一个问题:patch 仅仅指示了需要修改哪些文件以及具体的修改方法,但其中的驱动可能并不适用于你手头的模组。原因在于,官方提供的驱动包适用于多款模组,而 patch 仅是其中某款模组的案例,并且官方更新驱动时,并不会同步更新 patch 中的驱动。

        因此,在移植时可以参考 patch 进行修改,但对于驱动适配系统的相关配置,一般无需更改。而对于新增的驱动文件,应在 driver_fw 文件夹中查找正确的驱动文件进行添加,而不是直接使用 patch 中的文件。

        3.3 Patch 使用方法

        在使用 patch 进行移植时,主要是对比 mod 文件夹和 orig 文件夹的区别,然后在你的源码中进行相应的配置修改。直接手动对比可能比较繁琐,因此可以借助 Git 进行对比分析。


        3.3.1. 初始化 Git 仓库

        首先,在 orig 文件夹中初始化一个 Git 仓库.

        接着,找到 mod 相比 orig 新增的文件,通常包含以下三部分:

        1. 模组固件:
          • 主要是厂家编译好的二进制 .bin 文件以及 .txt 配置文件。
          • 模组驱动:
            • 用于与内核交互,主要是 .c 源码文件,编译后生成 .ko 驱动文件。
            • 模组库:
              • 例如 libbt 之类的库,编译后生成 .so 共享库文件。

        3.3.2. 删除 mod 中的新增文件

        由于我们只关心 源码的修改内容,而这些新增的二进制文件、驱动和库文件无需对比修改,仅需直接复制,所以应当先删除 mod 中的新增文件

        原因:

        • 这些新增文件会导致 Git 对比时产生大量无关内容,影响分析。
        • 厂商在更新驱动时,不会同步更新 patch 中的驱动,直接使用 patch 提供的驱动可能会导致 bug。

          (别问为什么知道的,踩坑经验)


          3.3.3. 进行 Git 对比

          删除新增文件后,将 mod 文件夹的内容 覆盖 orig,然后使用 Git 进行对比:


          ⚠ VSCode 的 Git 对比 Bug

          坑点提醒:

          VSCode 的 Git 对比窗口 在路径长度超过 219 个字符 时,不会显示差异,容易导致遗漏修改。

          参考 Issue:

          Git diff does not show files with long paths in Source Control View (Windows) #240770

          4 设备树(DTS)修改

          此处主要是参考RK官方文档去修改

          01、Linux\Linux\Wifibt\Rockchip_Developer_Guide_Linux_WIFI_BT_CN.pdf

          02、Android\android\wifi\Rockchip_Introduction_WIFI_Configuration_CN&EN.pdf

          02、Android\common\MMC\Rockchip_Developer_Guide_SDMMC_SDIO_eMMC_CN.pdf

          4.1 蓝牙部分

          &wireless_bluetooth {
          	compatible = "bluetooth-platdata";
          	clocks = ;
          	clock-names = "ext_clock";
          	uart_rts_gpios = ;
          	pinctrl-names = "default", "rts_gpio";
          	pinctrl-0 = ;
          	pinctrl-1 = ;
          	BT,reset_gpio    = ;
          	status = "okay";
          };
          wireless-bluetooth {
              uart8_gpios: uart8-gpios {
                  rockchip,pins = ;
              };
          };
          
          • 这里比较重要的是BT,reset_gpio,这个模块的34脚,PWR_BT,根据描述来看,高电平时蓝牙部分关闭,低电平时蓝牙部分开启
          • 但是此部分的配置不一定是最终生效的版本,最终还要看驱动里是怎么处理的,有的驱动会对电平作反相处理,所以这部分可以GPIO_ACTIVE_LOW和GPIO_ACTIVE_HIGH都试试看
          • UART 配置: 确保蓝牙与 CPU 通过 UART8 进行通信。

            4.2 WiFi 部分

            sdio_pwrseq: sdio-pwrseq {
                compatible = "mmc-pwrseq-simple";
                clocks = ;
                clock-names = "ext_clock";
                pinctrl-names = "default";
                pinctrl-0 = ;
                /*
                    * On the module itself this is one of these (depending
                    * on the actual card populated):
                    * - SDIO_RESET_L_WL_REG_ON
                    * - PDN (power down when low)
                    */
                post-power-on-delay-ms = ;
                reset-gpios = ;
            };
            

            重点配置 WiFi reset-gpios,确保正确的电源控制。

            wireless_wlan: wireless-wlan {
                compatible = "wlan-platdata";
                rockchip,grf = ;
                wifi_chip_type = "AIC8800";
                status = "okay";
            };
            

            此处的WiFi芯片名称的配置,应该和frameworks\opt\net\wifi\libwifi_hal\rk_wifi_ctrl.cpp

            这个文件中的

            static wifi_device supported_wifi_devices[]中配置的名称一致(至少前三个字符要为AIC)

            &sdmmc2 {
                    max-frequency = ;
                    supports-sdio;
                    bus-width = ;
                    disable-wp;
                    cap-sd-highspeed;
                    cap-sdio-irq;
                    keep-power-in-suspend;
                    mmc-pwrseq = ;
                    non-removable;
                    pinctrl-names = "default";
                    pinctrl-0 = ;
                    sd-uhs-sdr104;
                    status = "okay";
            };
            
            • sd-uhs-sdr104表示支持sdio3.0

              5. 驱动部分

              • 添加驱动文件,也就是SDIO\driver_fw\driver\aic8800下所有文件添加到

                kernel\drivers\net\wireless\aic8800

              • 然后在同级目录下的mk文件中添加编译选项,通过CONFIG_AIC_WLAN_SUPPORT宏定义控制是否编译aic8800/目录下的内容

                kernel\drivers\net\wireless\Makefile
                obj-$(CONFIG_AIC_WLAN_SUPPORT) += aic8800/
                
                • 并且在同级目录下的kconfig中,引用aic8800/目录下的Kconfig文件,用于增加menuconfig中的aic8800驱动编译选项
                  source "drivers/net/wireless/aic8800/Kconfig"
                  
                  • 配置内核编译配置文件kernel\arch\arm64\configs\rockchip_defconfig,请修改你实际上应用的内核编译配置文件
                    CONFIG_AIC_WLAN_SUPPORT=y
                    CONFIG_AIC_FW_PATH="/vendor/etc/firmware"
                    CONFIG_AIC8800_WLAN_SUPPORT=m
                    
                      • CONFIG_AIC_WLAN_SUPPORT用于控制编译这个驱动
                      • CONFIG_AIC_FW_PATH用于配置模组固件存放的位置,固件最后会被复制到配置的这个位置
                      • CONFIG_AIC8800_WLAN_SUPPORT说明驱动将不会被编译进内核,而是以模块的形式动态插入(如果是以模块的形式动态插入,内核将根据sdio读到的vid和pid匹配不同的模块进行加载)
                      • 在vendor\rockchip\common\wifi\wifi.mk文件中,添加编译出来的ko文件的路径,因为是动态加载ko文件的,所以ko文件编译出来后,将被复制到/vendor/lib/modules路径下进行动态加载

                        AIC_WIFI_KO_FILES := $(shell find $(TOPDIR)kernel/drivers/net/wireless/aic8800 -name "*.ko" -type f)
                        BOARD_VENDOR_KERNEL_MODULES += \
                        $(foreach file, $(AIC_WIFI_KO_FILES), $(file))
                        

                        此处的配置用于找到编译出的ko文件

                        • 配置Android 启动时用于加载内核模块(.ko) 的配置文件

                          device\rockchip\common\init.insmod.cfg

                          加入

                          insmod /vendor/lib/modules/aic8800_bsp.ko
                          
                          • 最终会编译出三个ko文件,分别是

                            aic8800_bsp.ko aic8800_btlpm.ko aic8800_fdrv.ko

                            • aic8800_bsp用于模组的初始化等基础功能
                            • aic8800_fdrv用于WiFi
                            • aic8800_btlpm用于蓝牙
                            • 移植到RK Android平台时,实际上只加载aic8800_bsp.ko,aic8800_fdrv.ko

                              6. 蓝牙库 libbt

                              RK Android11 WiFi模组 AIC8800 驱动移植流程

                              libbt用于完成对蓝牙模块硬件初始化与控制。

                              6.1 添加蓝牙库文件

                              将 driver_fw\aic\libbt\8800 目录下所有文件添加到 hardware\aic\aicbt\libbt 目录。

                              6.2 配置编译 libbt

                              • 在libbt同级目录下添加Android.mk,如果BOARD_HAVE_BLUETOOTH_AIC被配置了,那么子目录下所有makefile都生效
                                ifeq ($(BOARD_HAVE_BLUETOOTH_AIC),true)
                                LOCAL_PATH := $(call my-dir)
                                include $(call all-subdir-makefiles)
                                endif
                                

                                而BOARD_HAVE_BLUETOOTH_AIC在device\rockchip\common\wifi_bt_common.mk这个mk文件中定义

                                BOARD_HAVE_BLUETOOTH_AIC := true
                                

                                • 同样的,在libbt同级目录下添加aicbt.mk文件
                                  CUR_PATH := hardware/aic/aicbt
                                  BOARD_HAVE_BLUETOOTH := true
                                  PRODUCT_PACKAGES += \
                                  	libbt-vendor-aic
                                  

                                  PRODUCT_PACKAGES += libbt-vendor-aic 定义了 libbt-vendor-aic 这个包,用于指定需要编译并包含到最终镜像

                                  注意,此处有一个坑点,需要保证libbt中Android.mk中的LOCAL_MODULE与PRODUCT_PACKAGES一致,原厂的patch由于没有更新,这两者不一致

                                  hardware\aic\aicbt\libbt\Android.mk
                                  LOCAL_MODULE := libbt-vendor-aic
                                  LOCAL_MODULE_TAGS := optional
                                  LOCAL_MODULE_CLASS := SHARED_LIBRARIES
                                  LOCAL_MODULE_OWNER := aic
                                  LOCAL_PROPRIETARY_MODULE := true
                                  

                                  LOCAL_MODULE 是用于定义模块名称,也就是最终会编译出libbt-vendor-aic.so这个模块。

                                  7. wpa_supplicant 配置

                                  7.1 wpa_supplicant 概念

                                  wpa_supplicant 是一个用于管理 WiFi 连接的用户空间守护进程,主要负责:

                                  • 处理 WPA/WPA2 认证
                                  • 管理 WiFi 连接(扫描、连接、断开)
                                  • 支持 WiFi Direct(P2P)
                                  • 通过 socket 接口与 Android WiFi 框架交互

                                    7.2 wpa_supplicant 具体配置

                                    配置aic模块的wpa配置,设置aic模块的启动参数

                                    device\rockchip\common\wpa_config.txt

                                    添加

                                    [aic]
                                    /vendor/bin/hw/wpa_supplicant
                                    -O/data/vendor/wifi/wpa/sockets
                                    -puse_p2p_group_interface=1
                                    -g@android:wpa_wlan0
                                    
                                      • [aic]:表示该配置适用于 AIC WiFi 模块。
                                      • /vendor/bin/hw/wpa_supplicant:指定 wpa_supplicant 的可执行文件路径。
                                      • -O/data/vendor/wifi/wpa/sockets:指定 wpa_supplicant 使用的 socket 目录,通常用于与其他组件(如 hostapd 或 Android WiFi 框架)通信。
                                      • -puse_p2p_group_interface=1:启用 P2P 组接口支持,允许 WiFi Direct 功能。
                                      • -g@android:wpa_wlan0:定义全局控制接口,@android:wpa_wlan0 允许 Android 通过 wpa_supplicant 进行 WiFi 控制

                                        设置加载wpa_config.txt中的配置

                                        external\wpa_supplicant_8\wpa_supplicant\main.c

                                        #define AIC_MODULE_NAME "[aic]"
                                        else if (0 == strncmp(wifi_type, "AIC", 3)) {
                                                wpa_printf(MSG_INFO,"Start aic_wpa_supplicant\n");
                                                ret = read_wpa_param_config(AIC_MODULE_NAME,argv[1]);
                                        }
                                        

                                        WiFi芯片类型前缀为AIC时,加载对应的aic的wpa_supplicant参数。

                                        8. WiFi HAL 配置

                                        这部分主要是通过配置vid:pid,选择加载不同的库。

                                        8.1 动态加载原理

                                        sdio握手成功后,就会读到vid:pid,将读到的数值与已经配置vid:pid比较,动态加载不同的库

                                        8.2 具体配置

                                        vid:pid配置

                                        frameworks\opt\net\wifi\libwifi_hal\rk_wifi_ctrl.cpp

                                        supported_wifi_devices 结构体数组中添加WiFi名称以及对应的vid:pid

                                        {"AIC8800",	"5449:0145"},
                                        
                                        • 这里又有一个坑点,patch中提供的这个vid:pid不适用于我这个模组,需要具体配置。
                                        • 获取真正的vid:pid有两种方式,一种是如果WiFi模组正常上电且sdio握手成功,那么是可以通过读/sys/bus/sdio/devices下的设备目录下的uevent文件得到的
                                          rk3568_HW:/ # cat /sys/bus/sdio/devices/
                                          mmc3:390b:1/   mmc3:390b:2/
                                          rk3568_HW:/ # cat /sys/bus/sdio/devices/mmc3\:390b\:1/uevent
                                          DRIVER=aicwf_sdio
                                          SDIO_CLASS=07
                                          SDIO_ID=C8A1:0082
                                          MODALIAS=sdio:c07vC8A1d0082
                                          rk3568_HW:/ # cat /sys/bus/sdio/devices/mmc3\:390b\:2/uevent
                                          DRIVER=aicbsp_sdio
                                          SDIO_CLASS=07
                                          SDIO_ID=C8A1:0182
                                          MODALIAS=sdio:c07vC8A1d0182
                                          

                                          这个WiFi模组扫卡成功后可以读到两个mmc设备,分别是mmc3:390b:1/ mmc3:390b:2/,

                                          读取到的mmc3:390b:1设备的vid:pid为C8A1:0082,那么增加这个vid:pid到rk_wifi_ctrl.cpp中即可。

                                          • 二是直接向厂家询问,或在驱动包中寻找

                                            接下来是检测流程,调用check_wifi_chip_type_string(wifi_type)函数,尝试获取wifi芯片类型,保存到wifi_type

                                            frameworks\opt\net\wifi\libwifi_hal\rk_wifi_ctrl.cpp

                                            int check_wifi_chip_type_string(char *type)
                                            {
                                            	if (identify_sucess == -1) {
                                            		if (get_wifi_device_id(SDIO_DIR, PREFIX_SDIO) == 0)
                                            			PLOG(DEBUG) 
                                            			PLOG(DEBUG) 
                                                {"AIC8800",         AIC8800_DRIVER_MODULE_NAME,   AIC8800_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG},
                                            }
                                            
                                                ALOGE("%s try to open %s \n", __func__, VENDOR_AIC_LIBRARY_NAME);
                                                strcpy(vendor_lib_name, VENDOR_AIC_LIBRARY_NAME);
                                            } 
                                            
                                                std::array
                                            	    check_wifi_chip_type_string(wifi_type);
                                                }
                                                if (0 == strncmp(wifi_type, "AP", 2) || 0 == strncmp(wifi_type, "AIC", 3)) {
                                            		property_set("vendor.wifi.direct.interface", "p2p-dev-wlan0");
                                            		property_get("wifi.direct.interface", buffer.data(), "p2p-dev-wlan0");
                                                } else {
                                            		property_set("vendor.wifi.direct.interface", "p2p0");
                                            		property_get("wifi.direct.interface", buffer.data(), "p2p0");
                                            	}
                                                return buffer.data();
                                            }
                                            
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码