bluetooth-next pull request for net-next:

- btusb: Add MediaTek MT7925-B22M support ID 0x13d3:0x3604
  - btusb: Add Realtek RTL8852C support ID 0x0489:0xe122
  - btrtl: Add the support for RTL8922A
  - btusb: Add 2 USB HW IDs for MT7925 (0xe118/e)
  - btnxpuart: Add support for ISO packets
  - btusb: Add Mediatek MT7925 support ID 0x13d3:0x3608
  - btsdio: Do not bind to non-removable CYW4373
  - hci_uart: Add support for Amlogic HCI UART
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmbjX78ZHGx1aXoudm9u
 LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKV52D/kBW6yn3MSXX/pOUz0Hqwrp
 kbsetne4MtGdLOtGe5sSJn5e2Cd8FIPkF25vyEm0q6Xj6mttuLiP+JZJWHM/2DK/
 9U9uK6eYZeiAiSZCa16G0Ql0lJJ4i5tvTLiXwnmWbXEsw6HZPu0YwUGHgLseOU62
 lnL1ujWtiM34vOWXWU0j/4BfIwyNh7gnYCeDwiCWqOa2Lvt7SotYMjYJVkcQ/DNw
 xjU9OUVKjW4XuE+VTtQNeoI3xr0DXXySbho+pUWcUFhUcMtMwdZRLyQQ4709Cv3Y
 4IduIklug2ayRyYifTGzbYGMSF7K5VxRxPbdvI1JfYwnmz/k+fgZ5GVfEmnB7rLl
 9Z5Ekidc1eTF3GB/Bx85T9tiFF3PvZQs+Zbik5Lsh/YHCoZ2RYVciCpCpNVriiMf
 95bdFUCiPTB/dOxYGO81L6mi1HKvrr34B2AXDt4eV12ur7CujASOKpxi7hThbe6u
 exATswFkShB4lSuIRme6JkMy102JiFI18ICaMxN3RVUZWtCIJSs4Nyg187A6HsoV
 0iIDfCAAU2Y0rPaEQ6YnDrJEawBM4vZdfFGlJtgfyA/sZM1lyPA8Ml7MCGYZNMA5
 YFl3ZNz3tbkWyV6v1hRNJ6/bf/FkDqBnT0GBy3jpgW19YsozE6IGzzYkLKgUaCFs
 7OdzSoRfmcShbtxSMFjSwQ==
 =ZAan
 -----END PGP SIGNATURE-----

Merge tag 'for-net-next-2024-09-12' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next

Luiz Augusto von Dentz says:

====================
bluetooth-next pull request for net-next:

 - btusb: Add MediaTek MT7925-B22M support ID 0x13d3:0x3604
 - btusb: Add Realtek RTL8852C support ID 0x0489:0xe122
 - btrtl: Add the support for RTL8922A
 - btusb: Add 2 USB HW IDs for MT7925 (0xe118/e)
 - btnxpuart: Add support for ISO packets
 - btusb: Add Mediatek MT7925 support ID 0x13d3:0x3608
 - btsdio: Do not bind to non-removable CYW4373
 - hci_uart: Add support for Amlogic HCI UART

* tag 'for-net-next-2024-09-12' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next: (27 commits)
  Bluetooth: btintel_pcie: Allocate memory for driver private data
  Bluetooth: btusb: Fix not handling ZPL/short-transfer
  Bluetooth: btusb: Add 2 USB HW IDs for MT7925 (0xe118/e)
  Bluetooth: btsdio: Do not bind to non-removable CYW4373
  Bluetooth: hci_sync: Ignore errors from HCI_OP_REMOTE_NAME_REQ_CANCEL
  Bluetooth: CMTP: Mark BT_CMTP as DEPRECATED
  Bluetooth: replace deprecated strncpy with strscpy_pad
  Bluetooth: hci_core: Fix sending MGMT_EV_CONNECT_FAILED
  Bluetooth: btrtl: Set msft ext address filter quirk for RTL8852B
  Bluetooth: Use led_set_brightness() in LED trigger activate() callback
  Bluetooth: btrtl: Use kvmemdup to simplify the code
  Bluetooth: btusb: Add Mediatek MT7925 support ID 0x13d3:0x3608
  Bluetooth: btrtl: Add the support for RTL8922A
  Bluetooth: hci_ldisc: Use speed set by btattach as oper_speed
  Bluetooth: hci_conn: Remove redundant memset after kzalloc
  Bluetooth: L2CAP: Remove unused declarations
  dt-bindings: bluetooth: bring the HW description closer to reality for wcn6855
  Bluetooth: btnxpuart: Add support for ISO packets
  Bluetooth: hci_h4: Add support for ISO packets in h4_recv.h
  Bluetooth: btusb: Add Realtek RTL8852C support ID 0x0489:0xe122
  ...
====================

Link: https://patch.msgid.link/20240912214317.3054060-1-luiz.dentz@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2024-09-13 19:50:25 -07:00
commit ef17c3d22c
23 changed files with 1037 additions and 205 deletions

View File

@ -0,0 +1,63 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2024 Amlogic, Inc. All rights reserved
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/bluetooth/amlogic,w155s2-bt.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic Bluetooth chips
description:
The W155S2 is an Amlogic Bluetooth and Wi-Fi combo chip. It works on
the standard H4 protocol via a 4-wire UART interface, with baud rates
up to 4 Mbps.
maintainers:
- Yang Li <yang.li@amlogic.com>
properties:
compatible:
oneOf:
- items:
- enum:
- amlogic,w265s1-bt
- amlogic,w265p1-bt
- const: amlogic,w155s2-bt
- enum:
- amlogic,w155s2-bt
- amlogic,w265s2-bt
clocks:
maxItems: 1
description: clock provided to the controller (32.768KHz)
enable-gpios:
maxItems: 1
vddio-supply:
description: VDD_IO supply regulator handle
firmware-name:
maxItems: 1
description: specify the path of firmware bin to load
required:
- compatible
- clocks
- enable-gpios
- vddio-supply
- firmware-name
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
bluetooth {
compatible = "amlogic,w155s2-bt";
clocks = <&extclk>;
enable-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
vddio-supply = <&wcn_3v3>;
firmware-name = "amlogic/aml_w155s2_bt_uart.bin";
};

View File

@ -172,14 +172,14 @@ allOf:
- qcom,wcn6855-bt
then:
required:
- enable-gpios
- swctrl-gpios
- vddio-supply
- vddbtcxmx-supply
- vddrfacmn-supply
- vddaon-supply
- vddwlcx-supply
- vddwlmx-supply
- vddbtcmx-supply
- vddrfa0p8-supply
- vddrfa1p2-supply
- vddrfa1p7-supply
- vddrfa1p8-supply
- if:
properties:
compatible:

View File

@ -1153,6 +1153,13 @@ S: Supported
F: arch/arm64/boot/dts/amd/amd-seattle-xgbe*.dtsi
F: drivers/net/ethernet/amd/xgbe/
AMLOGIC BLUETOOTH DRIVER
M: Yang Li <yang.li@amlogic.com>
L: linux-bluetooth@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/net/bluetooth/amlogic,w155s2-bt.yaml
F: drivers/bluetooth/hci_aml.c
AMLOGIC DDR PMU DRIVER
M: Jiucheng Xu <jiucheng.xu@amlogic.com>
L: linux-amlogic@lists.infradead.org

View File

@ -274,6 +274,18 @@ config BT_HCIUART_MRVL
Say Y here to compile support for HCI MRVL protocol.
config BT_HCIUART_AML
bool "Amlogic protocol support"
depends on BT_HCIUART
depends on BT_HCIUART_SERDEV
select BT_HCIUART_H4
select FW_LOADER
help
The Amlogic protocol support enables Bluetooth HCI over serial
port interface for Amlogic Bluetooth controllers.
Say Y here to compile support for HCI AML protocol.
config BT_HCIBCM203X
tristate "HCI BCM203x USB driver"
depends on USB

View File

@ -51,4 +51,5 @@ hci_uart-$(CONFIG_BT_HCIUART_BCM) += hci_bcm.o
hci_uart-$(CONFIG_BT_HCIUART_QCA) += hci_qca.o
hci_uart-$(CONFIG_BT_HCIUART_AG6XX) += hci_ag6xx.o
hci_uart-$(CONFIG_BT_HCIUART_MRVL) += hci_mrvl.o
hci_uart-$(CONFIG_BT_HCIUART_AML) += hci_aml.o
hci_uart-objs := $(hci_uart-y)

View File

@ -46,6 +46,7 @@ MODULE_DEVICE_TABLE(pci, btintel_pcie_table);
#define BTINTEL_PCIE_HCI_ACL_PKT 0x00000002
#define BTINTEL_PCIE_HCI_SCO_PKT 0x00000003
#define BTINTEL_PCIE_HCI_EVT_PKT 0x00000004
#define BTINTEL_PCIE_HCI_ISO_PKT 0x00000005
static inline void ipc_print_ia_ring(struct hci_dev *hdev, struct ia *ia,
u16 queue_num)
@ -423,6 +424,18 @@ static int btintel_pcie_recv_frame(struct btintel_pcie_data *data,
goto exit_error;
}
break;
case BTINTEL_PCIE_HCI_ISO_PKT:
if (skb->len >= HCI_ISO_HDR_SIZE) {
plen = HCI_ISO_HDR_SIZE + __le16_to_cpu(hci_iso_hdr(skb)->dlen);
pkt_type = HCI_ISODATA_PKT;
} else {
bt_dev_err(hdev, "ISO packet is too short");
ret = -EILSEQ;
goto exit_error;
}
break;
default:
bt_dev_err(hdev, "Invalid packet type received: 0x%4.4x",
pcie_pkt_type);
@ -1082,6 +1095,9 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev,
type = BTINTEL_PCIE_HCI_SCO_PKT;
hdev->stat.sco_tx++;
break;
case HCI_ISODATA_PKT:
type = BTINTEL_PCIE_HCI_ISO_PKT;
break;
default:
bt_dev_err(hdev, "Unknown HCI packet type");
return -EILSEQ;
@ -1208,7 +1224,7 @@ static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data)
int err;
struct hci_dev *hdev;
hdev = hci_alloc_dev();
hdev = hci_alloc_dev_priv(sizeof(struct btintel_data));
if (!hdev)
return -ENOMEM;

View File

@ -1412,6 +1412,7 @@ static const struct h4_recv_pkt nxp_recv_pkts[] = {
{ H4_RECV_ACL, .recv = hci_recv_frame },
{ H4_RECV_SCO, .recv = hci_recv_frame },
{ H4_RECV_EVENT, .recv = hci_recv_frame },
{ H4_RECV_ISO, .recv = hci_recv_frame },
{ NXP_RECV_CHIP_VER_V1, .recv = nxp_recv_chip_ver_v1 },
{ NXP_RECV_FW_REQ_V1, .recv = nxp_recv_fw_req_v1 },
{ NXP_RECV_CHIP_VER_V3, .recv = nxp_recv_chip_ver_v3 },

View File

@ -30,6 +30,7 @@
#define RTL_ROM_LMP_8822B 0x8822
#define RTL_ROM_LMP_8852A 0x8852
#define RTL_ROM_LMP_8851B 0x8851
#define RTL_ROM_LMP_8922A 0x8922
#define RTL_CONFIG_MAGIC 0x8723ab55
#define RTL_VSC_OP_COREDUMP 0xfcff
@ -69,6 +70,7 @@ enum btrtl_chip_id {
CHIP_ID_8852B = 20,
CHIP_ID_8852C = 25,
CHIP_ID_8851B = 36,
CHIP_ID_8922A = 44,
CHIP_ID_8852BT = 47,
};
@ -309,6 +311,15 @@ static const struct id_table ic_id_table[] = {
.cfg_name = "rtl_bt/rtl8851bu_config",
.hw_info = "rtl8851bu" },
/* 8922A */
{ IC_INFO(RTL_ROM_LMP_8922A, 0xa, 0xc, HCI_USB),
.config_needed = false,
.has_rom_version = true,
.has_msft_ext = true,
.fw_name = "rtl_bt/rtl8922au_fw",
.cfg_name = "rtl_bt/rtl8922au_config",
.hw_info = "rtl8922au" },
/* 8852BT/8852BE-VT */
{ IC_INFO(RTL_ROM_LMP_8852A, 0x87, 0xc, HCI_USB),
.config_needed = false,
@ -655,6 +666,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
{ RTL_ROM_LMP_8852A, 20 }, /* 8852B */
{ RTL_ROM_LMP_8852A, 25 }, /* 8852C */
{ RTL_ROM_LMP_8851B, 36 }, /* 8851B */
{ RTL_ROM_LMP_8922A, 44 }, /* 8922A */
{ RTL_ROM_LMP_8852A, 47 }, /* 8852BT */
};
@ -878,10 +890,8 @@ static int rtl_load_file(struct hci_dev *hdev, const char *name, u8 **buff)
if (ret < 0)
return ret;
ret = fw->size;
*buff = kvmalloc(fw->size, GFP_KERNEL);
if (*buff)
memcpy(*buff, fw->data, ret);
else
*buff = kvmemdup(fw->data, fw->size, GFP_KERNEL);
if (!*buff)
ret = -ENOMEM;
release_firmware(fw);
@ -1255,6 +1265,7 @@ int btrtl_download_firmware(struct hci_dev *hdev,
case RTL_ROM_LMP_8852A:
case RTL_ROM_LMP_8703B:
case RTL_ROM_LMP_8851B:
case RTL_ROM_LMP_8922A:
err = btrtl_setup_rtl8723b(hdev, btrtl_dev);
break;
default:
@ -1286,6 +1297,7 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev)
case CHIP_ID_8852B:
case CHIP_ID_8852C:
case CHIP_ID_8851B:
case CHIP_ID_8922A:
case CHIP_ID_8852BT:
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
@ -1296,6 +1308,7 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev)
btrealtek_set_flag(hdev, REALTEK_ALT6_CONTINUOUS_TX_CHIP);
if (btrtl_dev->project_id == CHIP_ID_8852A ||
btrtl_dev->project_id == CHIP_ID_8852B ||
btrtl_dev->project_id == CHIP_ID_8852C)
set_bit(HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER, &hdev->quirks);
@ -1528,3 +1541,5 @@ MODULE_FIRMWARE("rtl_bt/rtl8852btu_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852cu_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852cu_fw_v2.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852cu_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8922au_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8922au_config.bin");

View File

@ -295,6 +295,7 @@ static int btsdio_probe(struct sdio_func *func,
case SDIO_DEVICE_ID_BROADCOM_4345:
case SDIO_DEVICE_ID_BROADCOM_43455:
case SDIO_DEVICE_ID_BROADCOM_4356:
case SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373:
return -ENODEV;
}
}

View File

@ -59,7 +59,7 @@ static struct usb_driver btusb_driver;
#define BTUSB_CW6622 BIT(19)
#define BTUSB_MEDIATEK BIT(20)
#define BTUSB_WIDEBAND_SPEECH BIT(21)
#define BTUSB_VALID_LE_STATES BIT(22)
#define BTUSB_INVALID_LE_STATES BIT(22)
#define BTUSB_QCA_WCN6855 BIT(23)
#define BTUSB_INTEL_BROKEN_SHUTDOWN_LED BIT(24)
#define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25)
@ -298,115 +298,79 @@ static const struct usb_device_id quirks_table[] = {
/* QCA WCN6855 chipset */
{ USB_DEVICE(0x0cf3, 0xe600), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0cc), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0d6), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0e3), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x10ab, 0x9309), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x10ab, 0x9409), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0d0), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x10ab, 0x9108), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x10ab, 0x9109), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x10ab, 0x9208), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x10ab, 0x9209), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x10ab, 0x9308), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x10ab, 0x9408), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x10ab, 0x9508), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x10ab, 0x9509), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x10ab, 0x9608), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x10ab, 0x9609), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x10ab, 0x9f09), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04ca, 0x3022), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0c7), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0c9), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0ca), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0cb), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0ce), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0de), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0df), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0e1), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0ea), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0ec), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04ca, 0x3023), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04ca, 0x3024), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04ca, 0x3a22), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04ca, 0x3a24), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04ca, 0x3a26), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04ca, 0x3a27), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
/* QCA WCN785x chipset */
{ USB_DEVICE(0x0cf3, 0xe700), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
/* Broadcom BCM2035 */
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
@ -540,6 +504,8 @@ static const struct usb_device_id quirks_table[] = {
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3592), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe122), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
/* Realtek 8852BE Bluetooth devices */
{ USB_DEVICE(0x0cb8, 0xc559), .driver_info = BTUSB_REALTEK |
@ -564,6 +530,17 @@ static const struct usb_device_id quirks_table[] = {
/* Realtek 8852BT/8852BE-VT Bluetooth devices */
{ USB_DEVICE(0x0bda, 0x8520), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
/* Realtek 8922AE Bluetooth devices */
{ USB_DEVICE(0x0bda, 0x8922), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3617), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3616), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe130), .driver_info = BTUSB_REALTEK |
BTUSB_WIDEBAND_SPEECH },
/* Realtek Bluetooth devices */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01),
.driver_info = BTUSB_REALTEK },
@ -571,131 +548,102 @@ static const struct usb_device_id quirks_table[] = {
/* MediaTek Bluetooth devices */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0e8d, 0xe0, 0x01, 0x01),
.driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
/* Additional MediaTek MT7615E Bluetooth devices */
{ USB_DEVICE(0x13d3, 0x3560), .driver_info = BTUSB_MEDIATEK},
/* Additional MediaTek MT7663 Bluetooth devices */
{ USB_DEVICE(0x043e, 0x310c), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04ca, 0x3801), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
/* Additional MediaTek MT7668 Bluetooth devices */
{ USB_DEVICE(0x043e, 0x3109), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
/* Additional MediaTek MT7921 Bluetooth devices */
{ USB_DEVICE(0x0489, 0xe0c8), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0cd), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0e0), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0f2), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04ca, 0x3802), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0e8d, 0x0608), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3563), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3564), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3567), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3578), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3583), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3606), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
/* MediaTek MT7922 Bluetooth devices */
{ USB_DEVICE(0x13d3, 0x3585), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
/* MediaTek MT7922A Bluetooth devices */
{ USB_DEVICE(0x0489, 0xe0d8), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0d9), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0e2), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0e4), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0f1), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0f2), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0f5), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0f6), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe102), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04ca, 0x3804), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04ca, 0x38e4), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3568), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3605), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3607), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3614), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3615), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x35f5, 0x7922), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
/* Additional MediaTek MT7925 Bluetooth devices */
{ USB_DEVICE(0x0489, 0xe113), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe118), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe11e), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3602), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3603), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH |
BTUSB_VALID_LE_STATES },
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3604), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3608), .driver_info = BTUSB_MEDIATEK |
BTUSB_WIDEBAND_SPEECH },
/* Additional Realtek 8723AE Bluetooth devices */
{ USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK },
@ -1397,7 +1345,10 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
if (!urb)
return -ENOMEM;
size = le16_to_cpu(data->intr_ep->wMaxPacketSize);
/* Use maximum HCI Event size so the USB stack handles
* ZPL/short-transfer automatically.
*/
size = HCI_MAX_EVENT_SIZE;
buf = kmalloc(size, mem_flags);
if (!buf) {
@ -3956,7 +3907,7 @@ static int btusb_probe(struct usb_interface *intf,
if (id->driver_info & BTUSB_WIDEBAND_SPEECH)
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
if (!(id->driver_info & BTUSB_VALID_LE_STATES))
if (id->driver_info & BTUSB_INVALID_LE_STATES)
set_bit(HCI_QUIRK_BROKEN_LE_STATES, &hdev->quirks);
if (id->driver_info & BTUSB_DIGIANSWER) {

View File

@ -38,6 +38,13 @@ struct h4_recv_pkt {
.lsize = 1, \
.maxlen = HCI_MAX_EVENT_SIZE
#define H4_RECV_ISO \
.type = HCI_ISODATA_PKT, \
.hlen = HCI_ISO_HDR_SIZE, \
.loff = 2, \
.lsize = 2, \
.maxlen = HCI_MAX_FRAME_SIZE
static inline struct sk_buff *h4_recv_buf(struct hci_dev *hdev,
struct sk_buff *skb,
const unsigned char *buffer,

755
drivers/bluetooth/hci_aml.c Normal file
View File

@ -0,0 +1,755 @@
// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
/*
* Copyright (C) 2024 Amlogic, Inc. All rights reserved
*/
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/property.h>
#include <linux/of.h>
#include <linux/serdev.h>
#include <linux/clk.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/hci.h>
#include "hci_uart.h"
#define AML_EVT_HEAD_SIZE 4
#define AML_BDADDR_DEFAULT (&(bdaddr_t) {{ 0x00, 0xff, 0x00, 0x22, 0x2d, 0xae }})
#define AML_FIRMWARE_OPERATION_SIZE (248)
#define AML_FIRMWARE_MAX_SIZE (512 * 1024)
/* TCI command */
#define AML_TCI_CMD_READ 0xFEF0
#define AML_TCI_CMD_WRITE 0xFEF1
#define AML_TCI_CMD_UPDATE_BAUDRATE 0xFEF2
#define AML_TCI_CMD_HARDWARE_RESET 0xFEF2
#define AML_TCI_CMD_DOWNLOAD_BT_FW 0xFEF3
/* Vendor command */
#define AML_BT_HCI_VENDOR_CMD 0xFC1A
/* TCI operation parameter in controller chip */
#define AML_OP_UART_MODE 0x00A30128
#define AML_OP_EVT_ENABLE 0x00A70014
#define AML_OP_MEM_HARD_TRANS_EN 0x00A7000C
#define AML_OP_RF_CFG 0x00F03040
#define AML_OP_RAM_POWER_CTR 0x00F03050
#define AML_OP_HARDWARE_RST 0x00F03058
#define AML_OP_ICCM_RAM_BASE 0x00000000
#define AML_OP_DCCM_RAM_BASE 0x00D00000
/* UART configuration */
#define AML_UART_XMIT_EN BIT(12)
#define AML_UART_RECV_EN BIT(13)
#define AML_UART_TIMEOUT_INT_EN BIT(14)
#define AML_UART_CLK_SOURCE 40000000
/* Controller event */
#define AML_EVT_EN BIT(24)
/* RAM power control */
#define AML_RAM_POWER_ON (0)
#define AML_RAM_POWER_OFF (1)
/* RF configuration */
#define AML_RF_ANT_SINGLE BIT(28)
#define AML_RF_ANT_DOUBLE BIT(29)
/* Memory transaction */
#define AML_MM_CTR_HARD_TRAS_EN BIT(27)
/* Controller reset */
#define AML_CTR_CPU_RESET BIT(8)
#define AML_CTR_MAC_RESET BIT(9)
#define AML_CTR_PHY_RESET BIT(10)
enum {
FW_ICCM,
FW_DCCM
};
struct aml_fw_len {
u32 iccm_len;
u32 dccm_len;
};
struct aml_tci_rsp {
u8 num_cmd_packet;
u16 opcode;
u8 status;
} __packed;
struct aml_device_data {
int iccm_offset;
int dccm_offset;
bool is_coex;
};
struct aml_serdev {
struct hci_uart serdev_hu;
struct device *dev;
struct gpio_desc *bt_en_gpio;
struct regulator *bt_supply;
struct clk *lpo_clk;
const struct aml_device_data *aml_dev_data;
const char *firmware_name;
};
struct aml_data {
struct sk_buff *rx_skb;
struct sk_buff_head txq;
};
static const struct h4_recv_pkt aml_recv_pkts[] = {
{ H4_RECV_ACL, .recv = hci_recv_frame },
{ H4_RECV_SCO, .recv = hci_recv_frame },
{ H4_RECV_EVENT, .recv = hci_recv_frame },
{ H4_RECV_ISO, .recv = hci_recv_frame },
};
/* The TCI command is a private command, which is for setting baud rate,
* downloading firmware, initiating RAM.
*
* op_code | op_len | op_addr | parameter |
* --------|-----------------------|---------|-------------|
* 2B | 1B len(addr+param) | 4B | len(param) |
*/
static int aml_send_tci_cmd(struct hci_dev *hdev, u16 op_code, u32 op_addr,
u32 *param, u32 param_len)
{
struct aml_tci_rsp *rsp = NULL;
struct sk_buff *skb = NULL;
size_t buf_len = 0;
u8 *buf = NULL;
int err = 0;
buf_len = sizeof(op_addr) + param_len;
buf = kmalloc(buf_len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
memcpy(buf, &op_addr, sizeof(op_addr));
if (param && param_len > 0)
memcpy(buf + sizeof(op_addr), param, param_len);
skb = __hci_cmd_sync_ev(hdev, op_code, buf_len, buf,
HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
bt_dev_err(hdev, "Failed to send TCI cmd (error: %d)", err);
goto exit;
}
rsp = skb_pull_data(skb, sizeof(struct aml_tci_rsp));
if (!rsp)
goto skb_free;
if (rsp->opcode != op_code || rsp->status != 0x00) {
bt_dev_err(hdev, "send TCI cmd (0x%04X), response (0x%04X):(%d)",
op_code, rsp->opcode, rsp->status);
err = -EINVAL;
goto skb_free;
}
skb_free:
kfree_skb(skb);
exit:
kfree(buf);
return err;
}
static int aml_update_chip_baudrate(struct hci_dev *hdev, u32 baud)
{
u32 value;
value = ((AML_UART_CLK_SOURCE / baud) - 1) & 0x0FFF;
value |= AML_UART_XMIT_EN | AML_UART_RECV_EN | AML_UART_TIMEOUT_INT_EN;
return aml_send_tci_cmd(hdev, AML_TCI_CMD_UPDATE_BAUDRATE,
AML_OP_UART_MODE, &value, sizeof(value));
}
static int aml_start_chip(struct hci_dev *hdev)
{
u32 value = 0;
int ret;
value = AML_MM_CTR_HARD_TRAS_EN;
ret = aml_send_tci_cmd(hdev, AML_TCI_CMD_WRITE,
AML_OP_MEM_HARD_TRANS_EN,
&value, sizeof(value));
if (ret)
return ret;
/* controller hardware reset */
value = AML_CTR_CPU_RESET | AML_CTR_MAC_RESET | AML_CTR_PHY_RESET;
ret = aml_send_tci_cmd(hdev, AML_TCI_CMD_HARDWARE_RESET,
AML_OP_HARDWARE_RST,
&value, sizeof(value));
return ret;
}
static int aml_send_firmware_segment(struct hci_dev *hdev,
u8 fw_type,
u8 *seg,
u32 seg_size,
u32 offset)
{
u32 op_addr = 0;
if (fw_type == FW_ICCM)
op_addr = AML_OP_ICCM_RAM_BASE + offset;
else if (fw_type == FW_DCCM)
op_addr = AML_OP_DCCM_RAM_BASE + offset;
return aml_send_tci_cmd(hdev, AML_TCI_CMD_DOWNLOAD_BT_FW,
op_addr, (u32 *)seg, seg_size);
}
static int aml_send_firmware(struct hci_dev *hdev, u8 fw_type,
u8 *fw, u32 fw_size, u32 offset)
{
u32 seg_size = 0;
u32 seg_off = 0;
if (fw_size > AML_FIRMWARE_MAX_SIZE) {
bt_dev_err(hdev,
"Firmware size %d kB is larger than the maximum of 512 kB. Aborting.",
fw_size);
return -EINVAL;
}
while (fw_size > 0) {
seg_size = (fw_size > AML_FIRMWARE_OPERATION_SIZE) ?
AML_FIRMWARE_OPERATION_SIZE : fw_size;
if (aml_send_firmware_segment(hdev, fw_type, (fw + seg_off),
seg_size, offset)) {
bt_dev_err(hdev, "Failed send firmware, type: %d, offset: 0x%x",
fw_type, offset);
return -EINVAL;
}
seg_off += seg_size;
fw_size -= seg_size;
offset += seg_size;
}
return 0;
}
static int aml_download_firmware(struct hci_dev *hdev, const char *fw_name)
{
struct hci_uart *hu = hci_get_drvdata(hdev);
struct aml_serdev *amldev = serdev_device_get_drvdata(hu->serdev);
const struct firmware *firmware = NULL;
struct aml_fw_len *fw_len = NULL;
u8 *iccm_start = NULL, *dccm_start = NULL;
u32 iccm_len, dccm_len;
u32 value = 0;
int ret = 0;
/* Enable firmware download event */
value = AML_EVT_EN;
ret = aml_send_tci_cmd(hdev, AML_TCI_CMD_WRITE,
AML_OP_EVT_ENABLE,
&value, sizeof(value));
if (ret)
goto exit;
/* RAM power on */
value = AML_RAM_POWER_ON;
ret = aml_send_tci_cmd(hdev, AML_TCI_CMD_WRITE,
AML_OP_RAM_POWER_CTR,
&value, sizeof(value));
if (ret)
goto exit;
/* Check RAM power status */
ret = aml_send_tci_cmd(hdev, AML_TCI_CMD_READ,
AML_OP_RAM_POWER_CTR, NULL, 0);
if (ret)
goto exit;
ret = request_firmware(&firmware, fw_name, &hdev->dev);
if (ret < 0) {
bt_dev_err(hdev, "Failed to load <%s>:(%d)", fw_name, ret);
goto exit;
}
fw_len = (struct aml_fw_len *)firmware->data;
/* Download ICCM */
iccm_start = (u8 *)(firmware->data) + sizeof(struct aml_fw_len)
+ amldev->aml_dev_data->iccm_offset;
iccm_len = fw_len->iccm_len - amldev->aml_dev_data->iccm_offset;
ret = aml_send_firmware(hdev, FW_ICCM, iccm_start, iccm_len,
amldev->aml_dev_data->iccm_offset);
if (ret) {
bt_dev_err(hdev, "Failed to send FW_ICCM (%d)", ret);
goto exit;
}
/* Download DCCM */
dccm_start = (u8 *)(firmware->data) + sizeof(struct aml_fw_len) + fw_len->iccm_len;
dccm_len = fw_len->dccm_len;
ret = aml_send_firmware(hdev, FW_DCCM, dccm_start, dccm_len,
amldev->aml_dev_data->dccm_offset);
if (ret) {
bt_dev_err(hdev, "Failed to send FW_DCCM (%d)", ret);
goto exit;
}
/* Disable firmware download event */
value = 0;
ret = aml_send_tci_cmd(hdev, AML_TCI_CMD_WRITE,
AML_OP_EVT_ENABLE,
&value, sizeof(value));
if (ret)
goto exit;
exit:
if (firmware)
release_firmware(firmware);
return ret;
}
static int aml_send_reset(struct hci_dev *hdev)
{
struct sk_buff *skb;
int err;
skb = __hci_cmd_sync_ev(hdev, HCI_OP_RESET, 0, NULL,
HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
bt_dev_err(hdev, "Failed to send hci reset cmd (%d)", err);
return err;
}
kfree_skb(skb);
return 0;
}
static int aml_dump_fw_version(struct hci_dev *hdev)
{
struct aml_tci_rsp *rsp = NULL;
struct sk_buff *skb;
u8 value[6] = {0};
u8 *fw_ver = NULL;
int err = 0;
skb = __hci_cmd_sync_ev(hdev, AML_BT_HCI_VENDOR_CMD, sizeof(value), value,
HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
bt_dev_err(hdev, "Failed to get fw version (error: %d)", err);
return err;
}
rsp = skb_pull_data(skb, sizeof(struct aml_tci_rsp));
if (!rsp)
goto exit;
if (rsp->opcode != AML_BT_HCI_VENDOR_CMD || rsp->status != 0x00) {
bt_dev_err(hdev, "dump version, error response (0x%04X):(%d)",
rsp->opcode, rsp->status);
err = -EINVAL;
goto exit;
}
fw_ver = (u8 *)rsp + AML_EVT_HEAD_SIZE;
bt_dev_info(hdev, "fw_version: date = %02x.%02x, number = 0x%02x%02x",
*(fw_ver + 1), *fw_ver, *(fw_ver + 3), *(fw_ver + 2));
exit:
kfree_skb(skb);
return err;
}
static int aml_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
{
struct aml_tci_rsp *rsp = NULL;
struct sk_buff *skb;
int err = 0;
bt_dev_info(hdev, "set bdaddr (%pM)", bdaddr);
skb = __hci_cmd_sync_ev(hdev, AML_BT_HCI_VENDOR_CMD,
sizeof(bdaddr_t), bdaddr,
HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
bt_dev_err(hdev, "Failed to set bdaddr (error: %d)", err);
return err;
}
rsp = skb_pull_data(skb, sizeof(struct aml_tci_rsp));
if (!rsp)
goto exit;
if (rsp->opcode != AML_BT_HCI_VENDOR_CMD || rsp->status != 0x00) {
bt_dev_err(hdev, "error response (0x%x):(%d)", rsp->opcode, rsp->status);
err = -EINVAL;
goto exit;
}
exit:
kfree_skb(skb);
return err;
}
static int aml_check_bdaddr(struct hci_dev *hdev)
{
struct hci_rp_read_bd_addr *paddr;
struct sk_buff *skb;
int err;
if (bacmp(&hdev->public_addr, BDADDR_ANY))
return 0;
skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL,
HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
err = PTR_ERR(skb);
bt_dev_err(hdev, "Failed to read bdaddr (error: %d)", err);
return err;
}
paddr = skb_pull_data(skb, sizeof(struct hci_rp_read_bd_addr));
if (!paddr)
goto exit;
if (!bacmp(&paddr->bdaddr, AML_BDADDR_DEFAULT)) {
bt_dev_info(hdev, "amlbt using default bdaddr (%pM)", &paddr->bdaddr);
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
}
exit:
kfree_skb(skb);
return 0;
}
static int aml_config_rf(struct hci_dev *hdev, bool is_coex)
{
u32 value = AML_RF_ANT_DOUBLE;
/* Use a single antenna when co-existing with wifi */
if (is_coex)
value = AML_RF_ANT_SINGLE;
return aml_send_tci_cmd(hdev, AML_TCI_CMD_WRITE,
AML_OP_RF_CFG,
&value, sizeof(value));
}
static int aml_parse_dt(struct aml_serdev *amldev)
{
struct device *pdev = amldev->dev;
amldev->bt_en_gpio = devm_gpiod_get(pdev, "enable",
GPIOD_OUT_LOW);
if (IS_ERR(amldev->bt_en_gpio)) {
dev_err(pdev, "Failed to acquire enable gpios");
return PTR_ERR(amldev->bt_en_gpio);
}
if (device_property_read_string(pdev, "firmware-name",
&amldev->firmware_name)) {
dev_err(pdev, "Failed to acquire firmware path");
return -ENODEV;
}
amldev->bt_supply = devm_regulator_get(pdev, "vddio");
if (IS_ERR(amldev->bt_supply)) {
dev_err(pdev, "Failed to acquire regulator");
return PTR_ERR(amldev->bt_supply);
}
amldev->lpo_clk = devm_clk_get(pdev, NULL);
if (IS_ERR(amldev->lpo_clk)) {
dev_err(pdev, "Failed to acquire clock source");
return PTR_ERR(amldev->lpo_clk);
}
return 0;
}
static int aml_power_on(struct aml_serdev *amldev)
{
int err;
err = regulator_enable(amldev->bt_supply);
if (err) {
dev_err(amldev->dev, "Failed to enable regulator: (%d)", err);
return err;
}
err = clk_prepare_enable(amldev->lpo_clk);
if (err) {
dev_err(amldev->dev, "Failed to enable lpo clock: (%d)", err);
return err;
}
gpiod_set_value_cansleep(amldev->bt_en_gpio, 1);
/* Wait 20ms for bluetooth controller power on */
msleep(20);
return 0;
}
static int aml_power_off(struct aml_serdev *amldev)
{
gpiod_set_value_cansleep(amldev->bt_en_gpio, 0);
clk_disable_unprepare(amldev->lpo_clk);
regulator_disable(amldev->bt_supply);
return 0;
}
static int aml_set_baudrate(struct hci_uart *hu, unsigned int speed)
{
/* update controller baudrate */
if (aml_update_chip_baudrate(hu->hdev, speed) != 0) {
bt_dev_err(hu->hdev, "Failed to update baud rate");
return -EINVAL;
}
/* update local baudrate */
serdev_device_set_baudrate(hu->serdev, speed);
return 0;
}
/* Initialize protocol */
static int aml_open(struct hci_uart *hu)
{
struct aml_serdev *amldev = serdev_device_get_drvdata(hu->serdev);
struct aml_data *aml_data;
int err;
err = aml_parse_dt(amldev);
if (err)
return err;
if (!hci_uart_has_flow_control(hu)) {
bt_dev_err(hu->hdev, "no flow control");
return -EOPNOTSUPP;
}
aml_data = kzalloc(sizeof(*aml_data), GFP_KERNEL);
if (!aml_data)
return -ENOMEM;
skb_queue_head_init(&aml_data->txq);
hu->priv = aml_data;
return 0;
}
static int aml_close(struct hci_uart *hu)
{
struct aml_serdev *amldev = serdev_device_get_drvdata(hu->serdev);
struct aml_data *aml_data = hu->priv;
skb_queue_purge(&aml_data->txq);
kfree_skb(aml_data->rx_skb);
kfree(aml_data);
hu->priv = NULL;
return aml_power_off(amldev);
}
static int aml_flush(struct hci_uart *hu)
{
struct aml_data *aml_data = hu->priv;
skb_queue_purge(&aml_data->txq);
return 0;
}
static int aml_setup(struct hci_uart *hu)
{
struct aml_serdev *amldev = serdev_device_get_drvdata(hu->serdev);
struct hci_dev *hdev = amldev->serdev_hu.hdev;
int err;
/* Setup bdaddr */
hdev->set_bdaddr = aml_set_bdaddr;
err = aml_power_on(amldev);
if (err)
return err;
err = aml_set_baudrate(hu, amldev->serdev_hu.proto->oper_speed);
if (err)
return err;
err = aml_download_firmware(hdev, amldev->firmware_name);
if (err)
return err;
err = aml_config_rf(hdev, amldev->aml_dev_data->is_coex);
if (err)
return err;
err = aml_start_chip(hdev);
if (err)
return err;
/* Wait 60ms for controller startup */
msleep(60);
err = aml_dump_fw_version(hdev);
if (err)
return err;
err = aml_send_reset(hdev);
if (err)
return err;
err = aml_check_bdaddr(hdev);
if (err)
return err;
return 0;
}
static int aml_enqueue(struct hci_uart *hu, struct sk_buff *skb)
{
struct aml_data *aml_data = hu->priv;
skb_queue_tail(&aml_data->txq, skb);
return 0;
}
static struct sk_buff *aml_dequeue(struct hci_uart *hu)
{
struct aml_data *aml_data = hu->priv;
struct sk_buff *skb;
skb = skb_dequeue(&aml_data->txq);
/* Prepend skb with frame type */
if (skb)
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
return skb;
}
static int aml_recv(struct hci_uart *hu, const void *data, int count)
{
struct aml_data *aml_data = hu->priv;
int err;
aml_data->rx_skb = h4_recv_buf(hu->hdev, aml_data->rx_skb, data, count,
aml_recv_pkts,
ARRAY_SIZE(aml_recv_pkts));
if (IS_ERR(aml_data->rx_skb)) {
err = PTR_ERR(aml_data->rx_skb);
bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err);
aml_data->rx_skb = NULL;
return err;
}
return count;
}
static const struct hci_uart_proto aml_hci_proto = {
.id = HCI_UART_AML,
.name = "AML",
.init_speed = 115200,
.oper_speed = 4000000,
.open = aml_open,
.close = aml_close,
.setup = aml_setup,
.flush = aml_flush,
.recv = aml_recv,
.enqueue = aml_enqueue,
.dequeue = aml_dequeue,
};
static void aml_device_driver_shutdown(struct device *dev)
{
struct aml_serdev *amldev = dev_get_drvdata(dev);
aml_power_off(amldev);
}
static int aml_serdev_probe(struct serdev_device *serdev)
{
struct aml_serdev *amldev;
int err;
amldev = devm_kzalloc(&serdev->dev, sizeof(*amldev), GFP_KERNEL);
if (!amldev)
return -ENOMEM;
amldev->serdev_hu.serdev = serdev;
amldev->dev = &serdev->dev;
serdev_device_set_drvdata(serdev, amldev);
err = hci_uart_register_device(&amldev->serdev_hu, &aml_hci_proto);
if (err)
return dev_err_probe(amldev->dev, err,
"Failed to register hci uart device");
amldev->aml_dev_data = device_get_match_data(&serdev->dev);
return 0;
}
static void aml_serdev_remove(struct serdev_device *serdev)
{
struct aml_serdev *amldev = serdev_device_get_drvdata(serdev);
hci_uart_unregister_device(&amldev->serdev_hu);
}
static const struct aml_device_data data_w155s2 = {
.iccm_offset = 256 * 1024,
};
static const struct aml_device_data data_w265s2 = {
.iccm_offset = 384 * 1024,
};
static const struct of_device_id aml_bluetooth_of_match[] = {
{ .compatible = "amlogic,w155s2-bt", .data = &data_w155s2 },
{ .compatible = "amlogic,w265s2-bt", .data = &data_w265s2 },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, aml_bluetooth_of_match);
static struct serdev_device_driver aml_serdev_driver = {
.probe = aml_serdev_probe,
.remove = aml_serdev_remove,
.driver = {
.name = "hci_uart_aml",
.of_match_table = aml_bluetooth_of_match,
.shutdown = aml_device_driver_shutdown,
},
};
int __init aml_init(void)
{
serdev_device_driver_register(&aml_serdev_driver);
return hci_uart_register_proto(&aml_hci_proto);
}
int __exit aml_deinit(void)
{
serdev_device_driver_unregister(&aml_serdev_driver);
return hci_uart_unregister_proto(&aml_hci_proto);
}

View File

@ -507,6 +507,9 @@ static int hci_uart_tty_open(struct tty_struct *tty)
hu->alignment = 1;
hu->padding = 0;
/* Use serial port speed as oper_speed */
hu->oper_speed = tty->termios.c_ospeed;
INIT_WORK(&hu->init_ready, hci_uart_init_work);
INIT_WORK(&hu->write_work, hci_uart_write_work);
@ -870,7 +873,9 @@ static int __init hci_uart_init(void)
#ifdef CONFIG_BT_HCIUART_MRVL
mrvl_init();
#endif
#ifdef CONFIG_BT_HCIUART_AML
aml_init();
#endif
return 0;
}
@ -906,7 +911,9 @@ static void __exit hci_uart_exit(void)
#ifdef CONFIG_BT_HCIUART_MRVL
mrvl_deinit();
#endif
#ifdef CONFIG_BT_HCIUART_AML
aml_deinit();
#endif
tty_unregister_ldisc(&hci_uart_ldisc);
}

View File

@ -20,7 +20,7 @@
#define HCIUARTGETFLAGS _IOR('U', 204, int)
/* UART protocols */
#define HCI_UART_MAX_PROTO 12
#define HCI_UART_MAX_PROTO 13
#define HCI_UART_H4 0
#define HCI_UART_BCSP 1
@ -34,6 +34,7 @@
#define HCI_UART_AG6XX 9
#define HCI_UART_NOKIA 10
#define HCI_UART_MRVL 11
#define HCI_UART_AML 12
#define HCI_UART_RAW_DEVICE 0
#define HCI_UART_RESET_ON_INIT 1
@ -209,3 +210,8 @@ int ag6xx_deinit(void);
int mrvl_init(void);
int mrvl_deinit(void);
#endif
#ifdef CONFIG_BT_HCIUART_AML
int aml_init(void);
int aml_deinit(void);
#endif

View File

@ -2901,6 +2901,11 @@ static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)
return (struct hci_sco_hdr *) skb->data;
}
static inline struct hci_iso_hdr *hci_iso_hdr(const struct sk_buff *skb)
{
return (struct hci_iso_hdr *)skb->data;
}
/* Command opcode pack/unpack */
#define hci_opcode_pack(ogf, ocf) ((__u16) ((ocf & 0x03ff)|(ogf << 10)))
#define hci_opcode_ogf(op) (op >> 10)

View File

@ -2257,8 +2257,8 @@ void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
bool mgmt_connected);
void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 link_type, u8 addr_type, u8 status);
void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u8 status);
void mgmt_connect_failed(struct hci_dev *hdev, struct hci_conn *conn,
u8 status);
void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure);
void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 status);

View File

@ -968,10 +968,6 @@ void l2cap_chan_list(struct l2cap_conn *conn, l2cap_chan_func_t func,
void *data);
void l2cap_chan_del(struct l2cap_chan *chan, int err);
void l2cap_send_conn_req(struct l2cap_chan *chan);
void l2cap_move_start(struct l2cap_chan *chan);
void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
u8 status);
void __l2cap_physical_cfm(struct l2cap_chan *chan, int result);
struct l2cap_conn *l2cap_conn_get(struct l2cap_conn *conn);
void l2cap_conn_put(struct l2cap_conn *conn);

View File

@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
config BT_CMTP
tristate "CMTP protocol support"
depends on BT_BREDR && ISDN_CAPI
tristate "CMTP protocol support (DEPRECATED)"
depends on BT_BREDR && ISDN_CAPI && DEPRECATED
help
CMTP (CAPI Message Transport Protocol) is a transport layer
for CAPI messages. CMTP is required for the Bluetooth Common

View File

@ -248,18 +248,10 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
break;
case CAPI_FUNCTION_GET_MANUFACTURER:
if (skb->len < CAPI_MSG_BASELEN + 15)
break;
if (!info && ctrl) {
int len = min_t(uint, CAPI_MANUFACTURER_LEN,
if (!info && ctrl && skb->len > CAPI_MSG_BASELEN + 14)
strscpy_pad(ctrl->manu,
skb->data + CAPI_MSG_BASELEN + 15,
skb->data[CAPI_MSG_BASELEN + 14]);
memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN);
strncpy(ctrl->manu,
skb->data + CAPI_MSG_BASELEN + 15, len);
}
break;
case CAPI_FUNCTION_GET_VERSION:
@ -276,18 +268,10 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
break;
case CAPI_FUNCTION_GET_SERIAL_NUMBER:
if (skb->len < CAPI_MSG_BASELEN + 17)
break;
if (!info && ctrl) {
int len = min_t(uint, CAPI_SERIAL_LEN,
if (!info && ctrl && skb->len > CAPI_MSG_BASELEN + 16)
strscpy_pad(ctrl->serial,
skb->data + CAPI_MSG_BASELEN + 17,
skb->data[CAPI_MSG_BASELEN + 16]);
memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
strncpy(ctrl->serial,
skb->data + CAPI_MSG_BASELEN + 17, len);
}
break;
}

View File

@ -106,8 +106,7 @@ void hci_connect_le_scan_cleanup(struct hci_conn *conn, u8 status)
* where a timeout + cancel does indicate an actual failure.
*/
if (status && status != HCI_ERROR_UNKNOWN_CONN_ID)
mgmt_connect_failed(hdev, &conn->dst, conn->type,
conn->dst_type, status);
mgmt_connect_failed(hdev, conn, status);
/* The connection attempt was doing scan for new RPA, and is
* in scan phase. If params are not associated with any other
@ -778,7 +777,6 @@ static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *c
if (!d)
return -ENOMEM;
memset(d, 0, sizeof(*d));
d->big = big;
d->sync_handle = conn->sync_handle;
@ -1250,8 +1248,7 @@ void hci_conn_failed(struct hci_conn *conn, u8 status)
hci_le_conn_failed(conn, status);
break;
case ACL_LINK:
mgmt_connect_failed(hdev, &conn->dst, conn->type,
conn->dst_type, status);
mgmt_connect_failed(hdev, conn, status);
break;
}

View File

@ -5380,7 +5380,10 @@ int hci_stop_discovery_sync(struct hci_dev *hdev)
if (!e)
return 0;
return hci_remote_name_cancel_sync(hdev, &e->data.bdaddr);
/* Ignore cancel errors since it should interfere with stopping
* of the discovery.
*/
hci_remote_name_cancel_sync(hdev, &e->data.bdaddr);
}
return 0;

View File

@ -48,7 +48,7 @@ static int power_activate(struct led_classdev *led_cdev)
htrig = to_hci_basic_led_trigger(led_cdev->trigger);
powered = test_bit(HCI_UP, &htrig->hdev->flags);
led_trigger_event(led_cdev->trigger, powered ? LED_FULL : LED_OFF);
led_set_brightness(led_cdev, powered ? LED_FULL : LED_OFF);
return 0;
}

View File

@ -9779,13 +9779,18 @@ void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
mgmt_pending_remove(cmd);
}
void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u8 status)
void mgmt_connect_failed(struct hci_dev *hdev, struct hci_conn *conn, u8 status)
{
struct mgmt_ev_connect_failed ev;
bacpy(&ev.addr.bdaddr, bdaddr);
ev.addr.type = link_to_bdaddr(link_type, addr_type);
if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) {
mgmt_device_disconnected(hdev, &conn->dst, conn->type,
conn->dst_type, status, true);
return;
}
bacpy(&ev.addr.bdaddr, &conn->dst);
ev.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
ev.status = mgmt_status(status);
mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);