RK3288 Android 6.0 适配 RTL8821CU wifi&BT 功能

需求背景

项目需求,要求添加蓝牙功能,选择的芯片是WIFI&蓝牙二合一的 RTL8821CU.

为此,需要更新蓝牙和wifi的相关驱动,以及Android系统层的一些配置,同时还要向下兼容旧的wifi芯片 RTL8188EU.

相关文件

# kernel
## config
kernel/arch/arm/configs/rockchip_defconfig
## dts
kernel/arch/arm/boot/dts/rk3288-tb_8846.dts
## wifi
kernel/drivers/net/wireless/rockchip_wlan/rtl8821cu/*
kernel/drivers/net/wireless/rockchip_wlan/rtl8821cu/Makefile
kernel/drivers/net/wireless/rockchip_wlan/wifi_sys/rkwifi_sys_iface.c
kernel/drivers/net/wireless/Kconfig
kernel/drivers/net/wireless/Makefile
kernel/include/linux/rfkill-wlan.h
kernel/net/rfkill/rfkill-wlan.c
## bt
kernel/drivers/bluetooth/rtk_btusb.c
kernel/drivers/bluetooth/rtk_btusb.h

# vendor
## wifi
vendor/rockchip/common/wifi/modules/8188eu.ko
vendor/rockchip/common/wifi/modules/8821cu.ko
## bt
vendor/rockchip/common/bluetooth/bluetooth.mk
vendor/rockchip/common/bluetooth/realtek/firmware/usb/rtl8821c/device-rtl.mk
vendor/rockchip/common/bluetooth/realtek/firmware/usb/rtl8821c/rtl8821c_config
vendor/rockchip/common/bluetooth/realtek/firmware/usb/rtl8821c/rtl8821c_fw
## hci tools
vendor/rockchip/common/rftesttool/broadcom/broadcom.mk
vendor/rockchip/common/rftesttool/rftesttool.mk

# device/rockchip/rk3288
device/rockchip/rk3288/init.rc

kernel

config

在内核配置中启用RTL8821CU.

--- a/arch/arm/configs/rockchip_defconfig
+++ b/arch/arm/configs/rockchip_defconfig
@@ -298,8 +298,9 @@ CONFIG_USB_HSO=y
 CONFIG_USB_NET_INT51X1=y
 CONFIG_USB_IPHETH=y
 CONFIG_USB_SIERRA_NET=y
-CONFIG_RTL8188EU=y
 CONFIG_ESP8089=y
+CONFIG_RTL8188EU=m
+CONFIG_RTL8821CU=m
 CONFIG_RKWIFI=y
 CONFIG_AP6335=y
 # CONFIG_INPUT_MOUSEDEV is not set

dts

在 dts 将wifi_chip_type 改成 RTL8723BU, 注意!是RTL8723BU, 而不是RTL8821CU.

这一步非常关键,RK3288 android 6.0 sdk默认支持RTL8723BU, 但是还不支持RTL8821CU.也就是说明,安卓系统层只支持RTL8723BU, 而不支持RTL8821CU. 如果不修改,那么蓝牙打开时不会触发驱动层去打开蓝牙。

--- a/arch/arm/boot/dts/rk3288-tb_8846.dts
+++ b/arch/arm/boot/dts/rk3288-tb_8846.dts
@@ -15,8 +15,8 @@
 * rtl8188eu, rtl8723bs, rtl8723bu
 * esp8089
 */
-//wifi_chip_type = "rtl8723bu";
-wifi_chip_type = "rtl8188eu";
+wifi_chip_type = "rtl8723bu";
+//wifi_chip_type = "rtl8188eu";

 sdio_vref = <1800>; //1800mv or 3300mv

wifi

wifi 驱动移植相对简单,把RTL8821CU的wifi驱动拷贝到 kernel/drivers/net/wireless/rockchip_wlan/rtl8821cu 目录,然后添加和修改相应的Kconfig, Makefile等即可。

diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 4e3af3d..5213afe 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -45,6 +45,7 @@ choice
     bool "No Realtek WiFi"
 
 source "drivers/net/wireless/rockchip_wlan/rtl8188eu/Kconfig"
+source "drivers/net/wireless/rockchip_wlan/rtl8821cu/Kconfig"
 source "drivers/net/wireless/rockchip_wlan/rtl8189es/Kconfig"
 source "drivers/net/wireless/rockchip_wlan/rtl8192cu/Kconfig"
 source "drivers/net/wireless/rockchip_wlan/rtl8192du/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index c3c8b85..4f18726 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -5,6 +5,7 @@ obj-y += rockchip_wlan/wifi_sys/rkwifi_sys_iface.o
 obj-$(CONFIG_RTL8192CU)        += rockchip_wlan/rtl8192cu/
 obj-$(CONFIG_RTL8192DU)        += rockchip_wlan/rtl8192du/
 obj-$(CONFIG_RTL8188EU)           += rockchip_wlan/rtl8188eu/
+obj-$(CONFIG_RTL8821CU)           += rockchip_wlan/rtl8821cu/
 obj-$(CONFIG_RTL8189ES)           += rockchip_wlan/rtl8189es/
 obj-$(CONFIG_RTL8723AU)           += rockchip_wlan/rtl8723au/
 obj-$(CONFIG_RTL8723BU)           += rockchip_wlan/rtl8723bu/
diff --git a/drivers/net/wireless/rockchip_wlan/rtl8821cu/Makefile b/drivers/net/wireless/rockchip_wlan/rtl8821cu/Makefile
index 850fb5a..3a6bacc 100644
--- a/drivers/net/wireless/rockchip_wlan/rtl8821cu/Makefile
+++ b/drivers/net/wireless/rockchip_wlan/rtl8821cu/Makefile
@@ -92,7 +92,7 @@ CONFIG_RTW_UP_MAPPING_RULE = tos
 CONFIG_RTW_MBO = n
 ########################## Android ###########################
 # CONFIG_RTW_ANDROID - 0: no Android, 4/5/6/7/8/9/10/11 : Android version
-CONFIG_RTW_ANDROID = 0
+CONFIG_RTW_ANDROID = 6
 
 ifeq ($(shell test $(CONFIG_RTW_ANDROID) -gt 0; echo $$?), 0)
 EXTRA_CFLAGS += -DCONFIG_RTW_ANDROID=$(CONFIG_RTW_ANDROID)
@@ -102,7 +102,7 @@ endif
 CONFIG_RTW_DEBUG = y
 # default log level is _DRV_INFO_ = 4,
 # please refer to "How_to_set_driver_debug_log_level.doc" to set the available level.
-CONFIG_RTW_LOG_LEVEL = 4
+CONFIG_RTW_LOG_LEVEL = 2
 
 # enable /proc/net/rtlxxxx/ debug interfaces
 CONFIG_PROC_DEBUG = y
@@ -135,7 +135,7 @@ CONFIG_LAYER2_ROAMING = y
 #bit0: ROAM_ON_EXPIRED, #bit1: ROAM_ON_RESUME, #bit2: ROAM_ACTIVE
 CONFIG_ROAMING_FLAG = 0x3
 ###################### Platform Related #######################
-CONFIG_PLATFORM_I386_PC = y
+CONFIG_PLATFORM_I386_PC = n
 CONFIG_PLATFORM_ANDROID_X86 = n
 CONFIG_PLATFORM_ANDROID_INTEL_X86 = n
 CONFIG_PLATFORM_JB_X86 = n
@@ -161,6 +161,7 @@ CONFIG_PLATFORM_ARM_TCC8930_JB42 = n
 CONFIG_PLATFORM_ARM_RK2818 = n
 CONFIG_PLATFORM_ARM_RK3066 = n
 CONFIG_PLATFORM_ARM_RK3188 = n
+CONFIG_PLATFORM_ARM_RK3288 = y
 CONFIG_PLATFORM_ARM_URBETTER = n
 CONFIG_PLATFORM_ARM_TI_PANDA = n
 CONFIG_PLATFORM_MIPS_JZ4760 = n
@@ -1712,6 +1713,23 @@ KSRC := /home/android_sdk/Rockchip/Rk3188/kernel
 MODULE_NAME := wlan
 endif
 
+ifeq ($(CONFIG_PLATFORM_ARM_RK3288), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN -DCONFIG_PLATFORM_ANDROID -DCONFIG_PLATFORM_ROCKCHIPS
+# default setting for Android 4.1, 4.2, 4.3, 4.4
+EXTRA_CFLAGS += -DCONFIG_IOCTL_CFG80211 -DRTW_USE_CFG80211_STA_EVENT
+EXTRA_CFLAGS += -DCONFIG_CONCURRENT_MODE
+# default setting for Power control
+EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC
+ifeq ($(CONFIG_SDIO_HCI), y)
+EXTRA_CFLAGS += -DRTW_SUPPORT_PLATFORM_SHUTDOWN
+endif
+# default setting for Special function
+ARCH := arm
+CROSS_COMPILE := /media/hdd1/wugt/rk3288-android6.0-sdk/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-
+KSRC := /media/hdd1/wugt/rk3288-android6.0-sdk/kernel
+MODULE_NAME := wlan
+endif
+
 ifeq ($(CONFIG_PLATFORM_ARM_RK3066), y)
 EXTRA_CFLAGS += -DCONFIG_PLATFORM_ARM_RK3066
 EXTRA_CFLAGS += -DRTW_ENABLE_WIFI_CONTROL_FUNC

除了wifi驱动外,还需要更新rfkill驱动。

diff --git a/drivers/net/wireless/rockchip_wlan/wifi_sys/rkwifi_sys_iface.c b/drivers/net/wireless/rockchip_wlan/wifi_sys/rkwifi_sys_iface.c
index 58112a9..f7245d6 100755
--- a/drivers/net/wireless/rockchip_wlan/wifi_sys/rkwifi_sys_iface.c
+++ b/drivers/net/wireless/rockchip_wlan/wifi_sys/rkwifi_sys_iface.c
@@ -81,6 +81,11 @@ static ssize_t wifi_chip_read(struct class *cls, struct class_attribute *attr, c
            count = sprintf(_buf, "%s", "RTL8188EU");
            printk("Current WiFi chip is RTL8188EU.\n");
        }
+
+       if(type == WIFI_RTL8821CU) {
+           count = sprintf(_buf, "%s", "RTL8821CU");
+           printk("Current WiFi chip is RTL8821CU.\n");
+       }

        if(type == WIFI_RTL8723BS) {
            count = sprintf(_buf, "%s", "RTL8723BS");
diff --git a/include/linux/rfkill-wlan.h b/include/linux/rfkill-wlan.h
index 6015bf4..041353f 100755
--- a/include/linux/rfkill-wlan.h
+++ b/include/linux/rfkill-wlan.h
@@ -57,6 +57,7 @@ enum {
     WIFI_AP6493,
     WIFI_AP6XXX_SERIES,
     WIFI_RTL8188EU,
+    WIFI_RTL8821CU,
     WIFI_RTL8192DU,
     WIFI_RTL8723AS,
     WIFI_RTL8723BS,
diff --git a/net/rfkill/rfkill-wlan.c b/net/rfkill/rfkill-wlan.c
index 55b8b5f..4f5d82c 100755
--- a/net/rfkill/rfkill-wlan.c
+++ b/net/rfkill/rfkill-wlan.c
@@ -126,6 +126,8 @@ int get_wifi_chip_type(void)
         type = WIFI_AP6493;
     } else if (strcmp(wifi_chip_type_string, "rtl8188eu") == 0) {
         type = WIFI_RTL8188EU;
+    } else if (strcmp(wifi_chip_type_string, "rtl8821cu") == 0) {
+        type = WIFI_RTL8821CU;
     } else if (strcmp(wifi_chip_type_string, "rtl8192du") == 0) {
         type = WIFI_RTL8192DU;
     } else if (strcmp(wifi_chip_type_string, "rtl8723as") == 0) {

bt

接下来是蓝牙驱动,由于sdk默认不支持RTL8821CU, 所以需要手动添加相关配置。

--- a/drivers/bluetooth/rtk_btusb.c
+++ b/drivers/bluetooth/rtk_btusb.c
@@ -70,7 +70,7 @@
 #define CMD_HDR_LEN            sizeof(struct hci_command_hdr)
 #define EVT_HDR_LEN            sizeof(struct hci_event_hdr)
 #define CMD_CMP_LEN            sizeof(struct hci_ev_cmd_complete)
-#define RTK_PATCH_LENGTH_MAX 1024*24
+#define RTK_PATCH_LENGTH_MAX 1024*36

 static spinlock_t queue_lock;
 enum rtk_endpoit {
@@ -145,6 +145,8 @@ static patch_info fw_patch_table[] = {

 { 0xb720, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723bu_config", NULL, 0 }, /* RTL8723BU */
 { 0xb72A, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723bu_config", NULL, 0 }, /* RTL8723BU */
+{ 0xB820, 0x8821, 0, 0, "mp_rtl8821c_fw", "rtl8821c_fw", "rtl8821c_config", NULL, 0 }, /* RTL8821CU */
+{ 0xC820, 0x8821, 0, 0, "mp_rtl8821c_fw", "rtl8821c_fw", "rtl8821c_config", NULL, 0 }, /* RTL8821CU */
 { 0xb728, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 }, /* RTL8723BE for LC */
 { 0xb723, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 }, /* RTL8723BE */
 { 0xb72B, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 }, /* RTL8723BE */
diff --git a/drivers/bluetooth/rtk_btusb.h b/drivers/bluetooth/rtk_btusb.h
index 5f5e53a..f71d7b1 100755
--- a/drivers/bluetooth/rtk_btusb.h
+++ b/drivers/bluetooth/rtk_btusb.h
@@ -127,6 +127,7 @@ struct rtk_bt_vendor_config{
 #define ROM_LMP_8723a0x1200
 #define ROM_LMP_8723b0x8723
 #define ROM_LMP_8821a0X8821
+#define ROM_LMP_8821c0X8821
 #define ROM_LMP_8761a0X8761
 #define ROM_LMP_8703a0x8723
 #define ROM_LMP_8763a0x8763
@@ -149,6 +150,8 @@ uint16_t project_id[] = {
     ROM_LMP_8703b,
     ROM_LMP_8723c,
     ROM_LMP_8822b,
+       ROM_LMP_NONE,
+       ROM_LMP_8821c,
        ROM_LMP_NONE
 };
 struct rtk_eversion_evt {

值得注意的是:

  1. rtk_usb 驱动配置的最大fw size为24k, 而 RTL8821CU 的 FW 约 30k, 所以需要修改最大值为 36k
  2. 添加 project_id 时,通过debug信息知道 RTL8821CU 对应的 ID 为 10,所以需要修改枚举列表,将 RTL8821CU 放置到第 10 个位置
  3. 通过设置 DBG_FLAG 可以打开调试信息

vendor

vendor 目录需要添加 RTL8821CU 所需的fw和config文件。

 rockchip/common/bluetooth/bluetooth.mk|   1 +
 rockchip/common/bluetooth/realtek/firmware/usb/rtl8821c/device-rtl.mk   |   4 ++++
 rockchip/common/bluetooth/realtek/firmware/usb/rtl8821c/rtl8821c_config | Bin 0 -> 14 bytes
 rockchip/common/bluetooth/realtek/firmware/usb/rtl8821c/rtl8821c_fw     | Bin 0 -> 50344 bytes
 4 files changed, 5 insertions(+)

diff --git a/rockchip/common/bluetooth/bluetooth.mk b/rockchip/common/bluetooth/bluetooth.mk
index 0f6bde8..1dafdcc 100755
--- a/rockchip/common/bluetooth/bluetooth.mk
+++ b/rockchip/common/bluetooth/bluetooth.mk
@@ -12,6 +12,7 @@ $(call inherit-product-if-exists, $(LOCAL_PATH)/realtek/firmware/usb/rtl8723b/de
 $(call inherit-product-if-exists, $(LOCAL_PATH)/realtek/firmware/usb/rtl8703b/device-rtl.mk)
 $(call inherit-product-if-exists, $(LOCAL_PATH)/realtek/firmware/usb/rtl8761a/device-rtl.mk)
 $(call inherit-product-if-exists, $(LOCAL_PATH)/realtek/firmware/usb/rtl8821a/device-rtl.mk)
+$(call inherit-product-if-exists, $(LOCAL_PATH)/realtek/firmware/usb/rtl8821c/device-rtl.mk)
 $(call inherit-product-if-exists, $(LOCAL_PATH)/realtek/firmware/usb/rtl8822b/device-rtl.mk)

 $(call inherit-product-if-exists, $(LOCAL_PATH)/realtek/firmware/uart/rtlbtfw_cfg.mk)
diff --git a/rockchip/common/bluetooth/realtek/firmware/usb/rtl8821c/device-rtl.mk b/rockchip/common/bluetooth/realtek/firmware/usb/rtl8821c/device-rtl.mk
new file mode 100755
index 0000000..440034c
--- /dev/null
+++ b/rockchip/common/bluetooth/realtek/firmware/usb/rtl8821c/device-rtl.mk
@@ -0,0 +1,4 @@
+RTK_BT_FIRMWARE_DIR := rtl8821c
+PRODUCT_COPY_FILES += \
+       $(LOCAL_PATH)/$(RTK_BT_FIRMWARE_DIR)_fw:system/etc/firmware/rtl8821c_fw \
+       $(LOCAL_PATH)/$(RTK_BT_FIRMWARE_DIR)_config:system/etc/firmware/rtl8821c_config
diff --git a/rockchip/common/bluetooth/realtek/firmware/usb/rtl8821c/rtl8821c_config b/rockchip/common/bluetooth/realtek/firmware/usb/rtl8821c/rtl8821c_config
new file mode 100755
index 0000000..cbec41e
Binary files /dev/null and b/rockchip/common/bluetooth/realtek/firmware/usb/rtl8821c/rtl8821c_config differ
diff --git a/rockchip/common/bluetooth/realtek/firmware/usb/rtl8821c/rtl8821c_fw b/rockchip/common/bluetooth/realtek/firmware/usb/rtl8821c/rtl8821c_fw
new file mode 100755
index 0000000..bc0df07
Binary files /dev/null and b/rockchip/common/bluetooth/realtek/firmware/usb/rtl8821c/rtl8821c_fw differ

此外,还要把 wifi 驱动 RTL8821CU.ko 放置到 rockchip/common/wifi/modules/ 目录。

hci tools

如果要添加 hci 工具,需要添加以下patch. 这样可以将 hciconfig, hcitool, hcidump 等工具集成到安卓系统。

diff --git a/rockchip/common/rftesttool/broadcom/broadcom.mk b/rockchip/common/rftesttool/broadcom/broadcom.mk
index 8819218..4c50604 100644
--- a/rockchip/common/rftesttool/broadcom/broadcom.mk
+++ b/rockchip/common/rftesttool/broadcom/broadcom.mk
@@ -1,8 +1,10 @@
+ifneq ($(strip $(TARGET_BOARD_PLATFORM)), rk3288)
 $(call inherit-product-if-exists, $(LOCAL_PATH)/app/app.mk)

 MFG_FWS := $(shell ls $(LOCAL_PATH)/mfg)
 PRODUCT_COPY_FILES += \
        $(foreach file, $(MFG_FWS), $(LOCAL_PATH)/mfg/$(file):system/etc/firmware/mfg/$(file))
+endif

 EXE_FILES := $(shell ls $(LOCAL_PATH)/bin)
 PRODUCT_COPY_FILES += \
diff --git a/rockchip/common/rftesttool/rftesttool.mk b/rockchip/common/rftesttool/rftesttool.mk
index bed8945..1012e91 100644
--- a/rockchip/common/rftesttool/rftesttool.mk
+++ b/rockchip/common/rftesttool/rftesttool.mk
@@ -3,4 +3,6 @@ PRODUCT_PACKAGES += \
        RFTestTool

 $(call inherit-product-if-exists, $(LOCAL_PATH)/broadcom/broadcom.mk)
+else ifeq ($(strip $(TARGET_BOARD_PLATFORM)), rk3288)
+$(call inherit-product-if-exists, $(LOCAL_PATH)/broadcom/broadcom.mk)
 endif

init.rc

最后,在 device/rockchip/rk3288/init.rc 文件中添加wifi驱动加载的指令。

diff --git a/init.rc b/init.rc
index 90a0b9e..e4285c3 100644
--- a/init.rc
+++ b/init.rc
@@ -463,6 +463,8 @@ on boot
     chown root radio /proc/cmdline

     insmod /drmboot.ko
+    insmod /system/lib/modules/8188eu.ko
+    insmod /system/lib/modules/8821cu.ko

     # export power io of extend screen and set the default value
     write /sys/class/gpio/export 224 

以上修改全部完成后,完整编译固件即可打开wifi和蓝牙了。

注意事项

  1. wifi驱动需要在kernel目录通过 make modules 得到
  2. rtk_usb 驱动使能 DBG_FLAG 可以打印更多调试信息