Skip to content

Commit

Permalink
general-bluetooth-02-add-support-for-RTL8723CS(:1)
Browse files Browse the repository at this point in the history
Original-Subject: Bluetooth: btrtl: add support for the RTL8723CS
The Realtek RTL8723CS is 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: Ondrej Jirman <megous@megous.com>
X-Armbian: Patch-File: general-bluetooth-02-add-support-for-RTL8723CS
X-Armbian: Patch-File-Counter: 1
X-Armbian: Patch-Rel-Directory: patch/kernel/archive/rockchip64-6.1
X-Armbian: Patch-Type: kernel
X-Armbian: Patch-Root-Type: core
X-Armbian: Patch-Sub-Type: common
X-Armbian: Original-Subject: Bluetooth: btrtl: add support for the RTL8723CS
  • Loading branch information
Ondrej Jirman authored and Armbian AutoPatcher committed Jul 1, 2021
1 parent cfb8adc commit cf860d5
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 4 deletions.
121 changes: 117 additions & 4 deletions drivers/bluetooth/btrtl.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@

#define VERSION "0.1"

#define RTL_CHIP_8723CS_CG 3
#define RTL_CHIP_8723CS_VF 4
#define RTL_CHIP_8723CS_XX 5
#define RTL_EPATCH_SIGNATURE "Realtech"
#define RTL_ROM_LMP_3499 0x3499
#define RTL_ROM_LMP_8703B 0x8703
#define RTL_ROM_LMP_8723A 0x1200
#define RTL_ROM_LMP_8723B 0x8723
#define RTL_ROM_LMP_8821A 0x8821
Expand All @@ -30,6 +35,7 @@
#define IC_MATCH_FL_HCIREV (1 << 1)
#define IC_MATCH_FL_HCIVER (1 << 2)
#define IC_MATCH_FL_HCIBUS (1 << 3)
#define IC_MATCH_FL_CHIP_TYPE (1 << 4)
#define IC_INFO(lmps, hcir, hciv, bus) \
.match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_HCIREV | \
IC_MATCH_FL_HCIVER | IC_MATCH_FL_HCIBUS, \
Expand Down Expand Up @@ -59,6 +65,7 @@ struct id_table {
__u16 hci_rev;
__u8 hci_ver;
__u8 hci_bus;
__u8 chip_type;
bool config_needed;
bool has_rom_version;
bool has_msft_ext;
Expand Down Expand Up @@ -99,6 +106,39 @@ static const struct id_table ic_id_table[] = {
.fw_name = "rtl_bt/rtl8723b_fw.bin",
.cfg_name = "rtl_bt/rtl8723b_config" },

/* 8723CS-CG */
{ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE |
IC_MATCH_FL_HCIBUS,
.lmp_subver = RTL_ROM_LMP_8703B,
.chip_type = RTL_CHIP_8723CS_CG,
.hci_bus = HCI_UART,
.config_needed = true,
.has_rom_version = true,
.fw_name = "rtl_bt/rtl8723cs_cg_fw.bin",
.cfg_name = "rtl_bt/rtl8723cs_cg_config" },

/* 8723CS-VF */
{ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE |
IC_MATCH_FL_HCIBUS,
.lmp_subver = RTL_ROM_LMP_8703B,
.chip_type = RTL_CHIP_8723CS_VF,
.hci_bus = HCI_UART,
.config_needed = true,
.has_rom_version = true,
.fw_name = "rtl_bt/rtl8723cs_vf_fw.bin",
.cfg_name = "rtl_bt/rtl8723cs_vf_config" },

/* 8723CS-XX */
{ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_CHIP_TYPE |
IC_MATCH_FL_HCIBUS,
.lmp_subver = RTL_ROM_LMP_8703B,
.chip_type = RTL_CHIP_8723CS_XX,
.hci_bus = HCI_UART,
.config_needed = true,
.has_rom_version = true,
.fw_name = "rtl_bt/rtl8723cs_xx_fw.bin",
.cfg_name = "rtl_bt/rtl8723cs_xx_config" },

/* 8723D */
{ IC_INFO(RTL_ROM_LMP_8723B, 0xd, 0x8, HCI_USB),
.config_needed = true,
Expand Down Expand Up @@ -215,7 +255,8 @@ static const struct id_table ic_id_table[] = {
};

static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev,
u8 hci_ver, u8 hci_bus)
u8 hci_ver, u8 hci_bus,
u8 chip_type)
{
int i;

Expand All @@ -232,6 +273,9 @@ static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev,
if ((ic_id_table[i].match_flags & IC_MATCH_FL_HCIBUS) &&
(ic_id_table[i].hci_bus != hci_bus))
continue;
if ((ic_id_table[i].match_flags & IC_MATCH_FL_CHIP_TYPE) &&
(ic_id_table[i].chip_type != chip_type))
continue;

break;
}
Expand Down Expand Up @@ -314,6 +358,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
{ RTL_ROM_LMP_8723B, 1 },
{ RTL_ROM_LMP_8821A, 2 },
{ RTL_ROM_LMP_8761A, 3 },
{ RTL_ROM_LMP_8703B, 7 },
{ RTL_ROM_LMP_8822B, 8 },
{ RTL_ROM_LMP_8723B, 9 }, /* 8723D */
{ RTL_ROM_LMP_8821A, 10 }, /* 8821C */
Expand Down Expand Up @@ -594,6 +639,48 @@ static int btrtl_setup_rtl8723b(struct hci_dev *hdev,
return ret;
}

static bool rtl_has_chip_type(u16 lmp_subver)
{
switch (lmp_subver) {
case RTL_ROM_LMP_8703B:
return true;
default:
break;
}

return false;
}

static int rtl_read_chip_type(struct hci_dev *hdev, u8 *type)
{
struct rtl_chip_type_evt *chip_type;
struct sk_buff *skb;
const unsigned char cmd_buf[] = {0x00, 0x94, 0xa0, 0x00, 0xb0};

/* Read RTL chip type command */
skb = __hci_cmd_sync(hdev, 0xfc61, 5, cmd_buf, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
rtl_dev_err(hdev, "Read chip type failed (%ld)",
PTR_ERR(skb));
return PTR_ERR(skb);
}

if (skb->len != sizeof(*chip_type)) {
rtl_dev_err(hdev, "RTL chip type event length mismatch");
kfree_skb(skb);
return -EIO;
}

chip_type = (struct rtl_chip_type_evt *)skb->data;
rtl_dev_info(hdev, "chip_type status=%x type=%x",
chip_type->status, chip_type->type);

*type = chip_type->type & 0x0f;

kfree_skb(skb);
return 0;
}

void btrtl_free(struct btrtl_device_info *btrtl_dev)
{
kvfree(btrtl_dev->fw_data);
Expand All @@ -610,7 +697,7 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
struct hci_rp_read_local_version *resp;
char cfg_name[40];
u16 hci_rev, lmp_subver;
u8 hci_ver;
u8 hci_ver, chip_type = 0;
int ret;
u16 opcode;
u8 cmd[2];
Expand All @@ -636,8 +723,14 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
hci_rev = le16_to_cpu(resp->hci_rev);
lmp_subver = le16_to_cpu(resp->lmp_subver);

if (rtl_has_chip_type(lmp_subver)) {
ret = rtl_read_chip_type(hdev, &chip_type);
if (ret)
goto err_free;
}

btrtl_dev->ic_info = btrtl_match_ic(lmp_subver, hci_rev, hci_ver,
hdev->bus);
hdev->bus, chip_type);

if (!btrtl_dev->ic_info)
btrtl_dev->drop_fw = true;
Expand Down Expand Up @@ -680,7 +773,7 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
lmp_subver = le16_to_cpu(resp->lmp_subver);

btrtl_dev->ic_info = btrtl_match_ic(lmp_subver, hci_rev, hci_ver,
hdev->bus);
hdev->bus, chip_type);
}
out_free:
kfree_skb(skb);
Expand Down Expand Up @@ -762,6 +855,7 @@ int btrtl_download_firmware(struct hci_dev *hdev,
case RTL_ROM_LMP_8761A:
case RTL_ROM_LMP_8822B:
case RTL_ROM_LMP_8852A:
case RTL_ROM_LMP_8703B:
return btrtl_setup_rtl8723b(hdev, btrtl_dev);
default:
rtl_dev_info(hdev, "assuming no firmware upload needed");
Expand Down Expand Up @@ -795,6 +889,19 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev)
rtl_dev_dbg(hdev, "WBS supported not enabled.");
break;
}

switch (btrtl_dev->ic_info->lmp_subver) {
case RTL_ROM_LMP_8703B:
/* 8723CS reports two pages for local ext features,
* but it doesn't support any features from page 2 -
* it either responds with garbage or with error status
*/
set_bit(HCI_QUIRK_BROKEN_LOCAL_EXT_FTR_MAX_PAGE,
&hdev->quirks);
break;
default:
break;
}
}
EXPORT_SYMBOL_GPL(btrtl_set_quirks);

Expand Down Expand Up @@ -953,6 +1060,12 @@ MODULE_FIRMWARE("rtl_bt/rtl8723b_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8723b_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8723bs_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8723bs_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8723cs_cg_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8723cs_cg_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8723cs_vf_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8723cs_vf_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8723cs_xx_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8723cs_xx_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8723ds_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8723ds_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8761a_fw.bin");
Expand Down
5 changes: 5 additions & 0 deletions drivers/bluetooth/btrtl.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@

struct btrtl_device_info;

struct rtl_chip_type_evt {
__u8 status;
__u8 type;
} __packed;

struct rtl_download_cmd {
__u8 index;
__u8 data[RTL_FRAG_LEN];
Expand Down

0 comments on commit cf860d5

Please sign in to comment.