Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Bluetooth: btrtl: add support for the RTL8723CS

The Realtek RTL8723CS is a SDIO WiFi chip. It also contains a Bluetooth
module which is connected via UART to the host.

It shares lmp subversion with 8703B, so Realtek's userspace
initialization tool (rtk_hciattach) differentiates varieties of RTL8723CS
(CG, VF, XX) with RTL8703B using vendor's command to read chip type.

Also this chip declares support for some features it doesn't support
so add a quirk to indicate that these features are broken.

Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
Signed-off-by: Bastian Germann <bage@debian.org>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

authored by

Vasily Khoruzhick and committed by
Luiz Augusto von Dentz
c0123cb6 8194f1ef

+125 -4
+116 -4
drivers/bluetooth/btrtl.c
··· 17 17 18 18 #define VERSION "0.1" 19 19 20 + #define RTL_CHIP_8723CS_CG 3 21 + #define RTL_CHIP_8723CS_VF 4 22 + #define RTL_CHIP_8723CS_XX 5 20 23 #define RTL_EPATCH_SIGNATURE "Realtech" 24 + #define RTL_ROM_LMP_8703B 0x8703 21 25 #define RTL_ROM_LMP_8723A 0x1200 22 26 #define RTL_ROM_LMP_8723B 0x8723 23 27 #define RTL_ROM_LMP_8821A 0x8821 ··· 34 30 #define IC_MATCH_FL_HCIREV (1 << 1) 35 31 #define IC_MATCH_FL_HCIVER (1 << 2) 36 32 #define IC_MATCH_FL_HCIBUS (1 << 3) 33 + #define IC_MATCH_FL_CHIP_TYPE (1 << 4) 37 34 #define IC_INFO(lmps, hcir, hciv, bus) \ 38 35 .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_HCIREV | \ 39 36 IC_MATCH_FL_HCIVER | IC_MATCH_FL_HCIBUS, \ ··· 64 59 __u16 hci_rev; 65 60 __u8 hci_ver; 66 61 __u8 hci_bus; 62 + __u8 chip_type; 67 63 bool config_needed; 68 64 bool has_rom_version; 69 65 bool has_msft_ext; ··· 104 98 .has_rom_version = true, 105 99 .fw_name = "rtl_bt/rtl8723b_fw.bin", 106 100 .cfg_name = "rtl_bt/rtl8723b_config" }, 101 + 102 + /* 8723CS-CG */ 103 + { .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE | 104 + IC_MATCH_FL_HCIBUS, 105 + .lmp_subver = RTL_ROM_LMP_8703B, 106 + .chip_type = RTL_CHIP_8723CS_CG, 107 + .hci_bus = HCI_UART, 108 + .config_needed = true, 109 + .has_rom_version = true, 110 + .fw_name = "rtl_bt/rtl8723cs_cg_fw.bin", 111 + .cfg_name = "rtl_bt/rtl8723cs_cg_config" }, 112 + 113 + /* 8723CS-VF */ 114 + { .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE | 115 + IC_MATCH_FL_HCIBUS, 116 + .lmp_subver = RTL_ROM_LMP_8703B, 117 + .chip_type = RTL_CHIP_8723CS_VF, 118 + .hci_bus = HCI_UART, 119 + .config_needed = true, 120 + .has_rom_version = true, 121 + .fw_name = "rtl_bt/rtl8723cs_vf_fw.bin", 122 + .cfg_name = "rtl_bt/rtl8723cs_vf_config" }, 123 + 124 + /* 8723CS-XX */ 125 + { .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE | 126 + IC_MATCH_FL_HCIBUS, 127 + .lmp_subver = RTL_ROM_LMP_8703B, 128 + .chip_type = RTL_CHIP_8723CS_XX, 129 + .hci_bus = HCI_UART, 130 + .config_needed = true, 131 + .has_rom_version = true, 132 + .fw_name = "rtl_bt/rtl8723cs_xx_fw.bin", 133 + .cfg_name = "rtl_bt/rtl8723cs_xx_config" }, 107 134 108 135 /* 8723D */ 109 136 { IC_INFO(RTL_ROM_LMP_8723B, 0xd, 0x8, HCI_USB), ··· 263 224 }; 264 225 265 226 static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev, 266 - u8 hci_ver, u8 hci_bus) 227 + u8 hci_ver, u8 hci_bus, 228 + u8 chip_type) 267 229 { 268 230 int i; 269 231 ··· 280 240 continue; 281 241 if ((ic_id_table[i].match_flags & IC_MATCH_FL_HCIBUS) && 282 242 (ic_id_table[i].hci_bus != hci_bus)) 243 + continue; 244 + if ((ic_id_table[i].match_flags & IC_MATCH_FL_CHIP_TYPE) && 245 + (ic_id_table[i].chip_type != chip_type)) 283 246 continue; 284 247 285 248 break; ··· 366 323 { RTL_ROM_LMP_8723B, 1 }, 367 324 { RTL_ROM_LMP_8821A, 2 }, 368 325 { RTL_ROM_LMP_8761A, 3 }, 326 + { RTL_ROM_LMP_8703B, 7 }, 369 327 { RTL_ROM_LMP_8822B, 8 }, 370 328 { RTL_ROM_LMP_8723B, 9 }, /* 8723D */ 371 329 { RTL_ROM_LMP_8821A, 10 }, /* 8821C */ ··· 647 603 return ret; 648 604 } 649 605 606 + static bool rtl_has_chip_type(u16 lmp_subver) 607 + { 608 + switch (lmp_subver) { 609 + case RTL_ROM_LMP_8703B: 610 + return true; 611 + default: 612 + break; 613 + } 614 + 615 + return false; 616 + } 617 + 618 + static int rtl_read_chip_type(struct hci_dev *hdev, u8 *type) 619 + { 620 + struct rtl_chip_type_evt *chip_type; 621 + struct sk_buff *skb; 622 + const unsigned char cmd_buf[] = {0x00, 0x94, 0xa0, 0x00, 0xb0}; 623 + 624 + /* Read RTL chip type command */ 625 + skb = __hci_cmd_sync(hdev, 0xfc61, 5, cmd_buf, HCI_INIT_TIMEOUT); 626 + if (IS_ERR(skb)) { 627 + rtl_dev_err(hdev, "Read chip type failed (%ld)", 628 + PTR_ERR(skb)); 629 + return PTR_ERR(skb); 630 + } 631 + 632 + chip_type = skb_pull_data(skb, sizeof(*chip_type)); 633 + if (!chip_type) { 634 + rtl_dev_err(hdev, "RTL chip type event length mismatch"); 635 + kfree_skb(skb); 636 + return -EIO; 637 + } 638 + 639 + rtl_dev_info(hdev, "chip_type status=%x type=%x", 640 + chip_type->status, chip_type->type); 641 + 642 + *type = chip_type->type & 0x0f; 643 + 644 + kfree_skb(skb); 645 + return 0; 646 + } 647 + 650 648 void btrtl_free(struct btrtl_device_info *btrtl_dev) 651 649 { 652 650 kvfree(btrtl_dev->fw_data); ··· 705 619 struct hci_rp_read_local_version *resp; 706 620 char cfg_name[40]; 707 621 u16 hci_rev, lmp_subver; 708 - u8 hci_ver; 622 + u8 hci_ver, chip_type = 0; 709 623 int ret; 710 624 u16 opcode; 711 625 u8 cmd[2]; ··· 731 645 hci_rev = le16_to_cpu(resp->hci_rev); 732 646 lmp_subver = le16_to_cpu(resp->lmp_subver); 733 647 648 + if (rtl_has_chip_type(lmp_subver)) { 649 + ret = rtl_read_chip_type(hdev, &chip_type); 650 + if (ret) 651 + goto err_free; 652 + } 653 + 734 654 btrtl_dev->ic_info = btrtl_match_ic(lmp_subver, hci_rev, hci_ver, 735 - hdev->bus); 655 + hdev->bus, chip_type); 736 656 737 657 if (!btrtl_dev->ic_info) 738 658 btrtl_dev->drop_fw = true; ··· 781 689 lmp_subver = le16_to_cpu(resp->lmp_subver); 782 690 783 691 btrtl_dev->ic_info = btrtl_match_ic(lmp_subver, hci_rev, hci_ver, 784 - hdev->bus); 692 + hdev->bus, chip_type); 785 693 } 786 694 out_free: 787 695 kfree_skb(skb); ··· 863 771 case RTL_ROM_LMP_8761A: 864 772 case RTL_ROM_LMP_8822B: 865 773 case RTL_ROM_LMP_8852A: 774 + case RTL_ROM_LMP_8703B: 866 775 return btrtl_setup_rtl8723b(hdev, btrtl_dev); 867 776 default: 868 777 rtl_dev_info(hdev, "assuming no firmware upload needed"); ··· 902 809 default: 903 810 rtl_dev_dbg(hdev, "Central-peripheral role not enabled."); 904 811 rtl_dev_dbg(hdev, "WBS supported not enabled."); 812 + break; 813 + } 814 + 815 + switch (btrtl_dev->ic_info->lmp_subver) { 816 + case RTL_ROM_LMP_8703B: 817 + /* 8723CS reports two pages for local ext features, 818 + * but it doesn't support any features from page 2 - 819 + * it either responds with garbage or with error status 820 + */ 821 + set_bit(HCI_QUIRK_BROKEN_LOCAL_EXT_FEATURES_PAGE_2, 822 + &hdev->quirks); 823 + break; 824 + default: 905 825 break; 906 826 } 907 827 } ··· 1075 969 MODULE_FIRMWARE("rtl_bt/rtl8723b_config.bin"); 1076 970 MODULE_FIRMWARE("rtl_bt/rtl8723bs_fw.bin"); 1077 971 MODULE_FIRMWARE("rtl_bt/rtl8723bs_config.bin"); 972 + MODULE_FIRMWARE("rtl_bt/rtl8723cs_cg_fw.bin"); 973 + MODULE_FIRMWARE("rtl_bt/rtl8723cs_cg_config.bin"); 974 + MODULE_FIRMWARE("rtl_bt/rtl8723cs_vf_fw.bin"); 975 + MODULE_FIRMWARE("rtl_bt/rtl8723cs_vf_config.bin"); 976 + MODULE_FIRMWARE("rtl_bt/rtl8723cs_xx_fw.bin"); 977 + MODULE_FIRMWARE("rtl_bt/rtl8723cs_xx_config.bin"); 1078 978 MODULE_FIRMWARE("rtl_bt/rtl8723ds_fw.bin"); 1079 979 MODULE_FIRMWARE("rtl_bt/rtl8723ds_config.bin"); 1080 980 MODULE_FIRMWARE("rtl_bt/rtl8761a_fw.bin");
+5
drivers/bluetooth/btrtl.h
··· 14 14 15 15 struct btrtl_device_info; 16 16 17 + struct rtl_chip_type_evt { 18 + __u8 status; 19 + __u8 type; 20 + } __packed; 21 + 17 22 struct rtl_download_cmd { 18 23 __u8 index; 19 24 __u8 data[RTL_FRAG_LEN];
+4
drivers/bluetooth/hci_h5.c
··· 936 936 err = btrtl_download_firmware(h5->hu->hdev, btrtl_dev); 937 937 /* Give the device some time before the hci-core sends it a reset */ 938 938 usleep_range(10000, 20000); 939 + if (err) 940 + goto out_free; 939 941 940 942 btrtl_set_quirks(h5->hu->hdev, btrtl_dev); 941 943 ··· 1101 1099 { .compatible = "realtek,rtl8822cs-bt", 1102 1100 .data = (const void *)&h5_data_rtl8822cs }, 1103 1101 { .compatible = "realtek,rtl8723bs-bt", 1102 + .data = (const void *)&h5_data_rtl8723bs }, 1103 + { .compatible = "realtek,rtl8723cs-bt", 1104 1104 .data = (const void *)&h5_data_rtl8723bs }, 1105 1105 { .compatible = "realtek,rtl8723ds-bt", 1106 1106 .data = (const void *)&h5_data_rtl8723bs },