From aa6914dc5636c6b6c8e27d9746f47389ba29db45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Pouiller?= Date: Mon, 3 Feb 2025 14:43:15 +0100 Subject: [PATCH] drivers: bluetooth: Introduce SiWx91x HCI driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Driver was tested with a custom application which enabled the BT_SHELL. Basic functionalities were verified: - Scanning - Advertising - Connecting Configuration needed for the test: - CONFIG_BT=y - CONFIG_BT_PERIPHERAL=y - CONFIG_BT_CENTRAL=y - CONFIG_BT_SHELL=y - CONFIG_SHELL=y Co-authored-by: Tibor Laczko Signed-off-by: Tibor Laczko Signed-off-by: Jérôme Pouiller --- drivers/bluetooth/hci/CMakeLists.txt | 1 + drivers/bluetooth/hci/Kconfig | 10 ++ drivers/bluetooth/hci/hci_silabs_siwx91x.c | 118 ++++++++++++++++++ .../bluetooth/silabs,siwx91x-bt-hci.yaml | 13 ++ modules/hal_silabs/wiseconnect/CMakeLists.txt | 14 +++ soc/silabs/silabs_siwx91x/siwg917/nwp_init.c | 20 +++ 6 files changed, 176 insertions(+) create mode 100644 drivers/bluetooth/hci/hci_silabs_siwx91x.c create mode 100644 dts/bindings/bluetooth/silabs,siwx91x-bt-hci.yaml diff --git a/drivers/bluetooth/hci/CMakeLists.txt b/drivers/bluetooth/hci/CMakeLists.txt index 5f10d6566cb..845c7cd2aa2 100644 --- a/drivers/bluetooth/hci/CMakeLists.txt +++ b/drivers/bluetooth/hci/CMakeLists.txt @@ -40,6 +40,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_STM32WBA hci_stm32wba.c) zephyr_library_sources_ifdef(CONFIG_BT_STM32WB0 hci_stm32wb0.c) zephyr_library_sources_ifdef(CONFIG_BT_USERCHAN userchan.c) zephyr_library_sources_ifdef(CONFIG_BT_SILABS_EFR32 hci_silabs_efr32.c) +zephyr_library_sources_ifdef(CONFIG_BT_SILABS_SIWX91X hci_silabs_siwx91x.c) zephyr_library_sources_ifdef(CONFIG_BT_PSOC6_BLESS hci_ifx_psoc6_bless.c) zephyr_library_sources_ifdef(CONFIG_SOC_NRF5340_CPUAPP nrf53_support.c) zephyr_library_sources_ifdef(CONFIG_BT_AMBIQ_HCI hci_ambiq.c apollox_blue.c) diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index 8eb3a1ff971..3ac7554347c 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -136,8 +136,18 @@ config BT_SILABS_EFR32 help Use Silicon Labs binary Bluetooth library to connect to the controller. + source "drivers/bluetooth/hci/Kconfig.silabs" +config BT_SILABS_SIWX91X + bool "Silabs SiWx91x Bluetooth interface" + default y + depends on DT_HAS_SILABS_SIWX91X_BT_HCI_ENABLED + select WISECONNECT_NETWORK_STACK + select ENTROPY_GENERATOR + help + Use Silicon Labs Wiseconnect 3.x Bluetooth library to connect to the controller. + config BT_USERCHAN bool depends on (BOARD_NATIVE_POSIX || BOARD_NATIVE_SIM) diff --git a/drivers/bluetooth/hci/hci_silabs_siwx91x.c b/drivers/bluetooth/hci/hci_silabs_siwx91x.c new file mode 100644 index 00000000000..3d40a38208a --- /dev/null +++ b/drivers/bluetooth/hci/hci_silabs_siwx91x.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2024 Silicon Laboratories Inc. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#define DT_DRV_COMPAT silabs_siwx91x_bt_hci +#define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL +#include +LOG_MODULE_REGISTER(bt_hci_driver_siwg917); + +#include "rsi_ble.h" + +static void siwx91x_bt_resp_rcvd(uint16_t status, rsi_ble_event_rcp_rcvd_info_t *resp_buf); + +struct hci_data { + bt_hci_recv_t recv; + rsi_data_packet_t rsi_data_packet; +}; + +static int siwx91x_bt_open(const struct device *dev, bt_hci_recv_t recv) +{ + struct hci_data *hci = dev->data; + int status = rsi_ble_enhanced_gap_extended_register_callbacks(RSI_BLE_ON_RCP_EVENT, + (void *)siwx91x_bt_resp_rcvd); + + if (!status) { + hci->recv = recv; + } + return status ? -EIO : 0; +} + +static int siwx91x_bt_send(const struct device *dev, struct net_buf *buf) +{ + struct hci_data *hci = dev->data; + int sc = -EOVERFLOW; + uint8_t packet_type = BT_HCI_H4_NONE; + + switch (bt_buf_get_type(buf)) { + case BT_BUF_ACL_OUT: + packet_type = BT_HCI_H4_ACL; + break; + case BT_BUF_CMD: + packet_type = BT_HCI_H4_CMD; + break; + default: + sc = -EINVAL; + break; + } + + if ((packet_type != BT_HCI_H4_NONE) && (buf->len < sizeof(hci->rsi_data_packet.data))) { + net_buf_push_u8(buf, packet_type); + memcpy(&hci->rsi_data_packet, buf->data, buf->len); + sc = rsi_bt_driver_send_cmd(RSI_BLE_REQ_HCI_RAW, &hci->rsi_data_packet, NULL); + /* TODO SILABS ZEPHYR Convert to errno. A common function from rsi/sl_status should + * be introduced + */ + if (sc) { + LOG_ERR("BT command send failure: %d", sc); + sc = -EIO; + } + } + net_buf_unref(buf); + return sc; +} + +static void siwx91x_bt_resp_rcvd(uint16_t status, rsi_ble_event_rcp_rcvd_info_t *resp_buf) +{ + const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0)); + struct hci_data *hci = dev->data; + uint8_t packet_type = BT_HCI_H4_NONE; + size_t len = 0; + struct net_buf *buf = NULL; + + /* TODO SILABS ZEPHYR This horror expression is from the WiseConnect from the HCI example... + * No workaround have been found until now. + */ + memcpy(&packet_type, (resp_buf->data - 12), 1); + switch (packet_type) { + case BT_HCI_H4_EVT: { + struct bt_hci_evt_hdr *hdr = (void *)resp_buf->data; + + len = hdr->len + sizeof(*hdr); + buf = bt_buf_get_evt(hdr->evt, false, K_FOREVER); + break; + } + case BT_HCI_H4_ACL: { + struct bt_hci_acl_hdr *hdr = (void *)resp_buf->data; + + len = hdr->len + sizeof(*hdr); + buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_FOREVER); + break; + } + default: + LOG_ERR("Unknown/Unhandled HCI type: %d", packet_type); + break; + } + + if (buf && (len <= net_buf_tailroom(buf))) { + net_buf_add_mem(buf, resp_buf->data, len); + hci->recv(dev, buf); + } +} + +static DEVICE_API(bt_hci, siwx91x_api) = { + .open = siwx91x_bt_open, + .send = siwx91x_bt_send, +}; + +#define HCI_DEVICE_INIT(inst) \ + static struct hci_data hci_data_##inst; \ + DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &hci_data_##inst, NULL, POST_KERNEL, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &siwx91x_api) + +/* Only one instance supported right now */ +HCI_DEVICE_INIT(0) diff --git a/dts/bindings/bluetooth/silabs,siwx91x-bt-hci.yaml b/dts/bindings/bluetooth/silabs,siwx91x-bt-hci.yaml new file mode 100644 index 00000000000..082005e9188 --- /dev/null +++ b/dts/bindings/bluetooth/silabs,siwx91x-bt-hci.yaml @@ -0,0 +1,13 @@ +description: Bluetooth HCI on Silabs boards + +compatible: "silabs,siwx91x-bt-hci" + +include: bt-hci.yaml + +properties: + bt-hci-name: + default: "sl:bt:siwx91x" + bt-hci-bus: + default: "virtual" + bt-hci-quirks: + default: ["no-reset"] diff --git a/modules/hal_silabs/wiseconnect/CMakeLists.txt b/modules/hal_silabs/wiseconnect/CMakeLists.txt index 14f03bb2283..05a86f60826 100644 --- a/modules/hal_silabs/wiseconnect/CMakeLists.txt +++ b/modules/hal_silabs/wiseconnect/CMakeLists.txt @@ -62,6 +62,20 @@ zephyr_library_sources_ifdef(CONFIG_DMA_SILABS_SIWX91X ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/rom_driver/src/rsi_rom_table_si91x.c ) +if(CONFIG_BT_SILABS_SIWX91X) + zephyr_compile_definitions( + SLI_SI91X_ENABLE_BLE + ) + zephyr_include_directories( + ${WISECONNECT_DIR}/components/device/silabs/si91x/wireless/ble/inc + ) + zephyr_library_sources( + ${WISECONNECT_DIR}/components/device/silabs/si91x/wireless/ble/src/rsi_bt_ble.c + ${WISECONNECT_DIR}/components/device/silabs/si91x/wireless/ble/src/rsi_common_apis.c + ${WISECONNECT_DIR}/components/device/silabs/si91x/wireless/ble/src/rsi_utils.c + ) +endif() # CONFIG_BT_SILABS_SIWX91X + if(CONFIG_WISECONNECT_NETWORK_STACK) zephyr_compile_definitions( SLI_SI91X_ENABLE_OS diff --git a/soc/silabs/silabs_siwx91x/siwg917/nwp_init.c b/soc/silabs/silabs_siwx91x/siwg917/nwp_init.c index 055c9e1a181..998cfaf77b2 100644 --- a/soc/silabs/silabs_siwx91x/siwg917/nwp_init.c +++ b/soc/silabs/silabs_siwx91x/siwg917/nwp_init.c @@ -14,6 +14,9 @@ #include "sl_wifi.h" #include "sl_wifi_callback_framework.h" +#ifdef CONFIG_BT_SILABS_SIWX91X +#include "rsi_ble_common_config.h" +#endif static int siwg917_nwp_init(void) { @@ -36,6 +39,23 @@ static int siwg917_nwp_init(void) } }; +#ifdef CONFIG_BT_SILABS_SIWX91X + cfg->ext_custom_feature_bit_map |= SL_SI91X_EXT_FEAT_BT_CUSTOM_FEAT_ENABLE; + cfg->bt_feature_bit_map |= SL_SI91X_BT_RF_TYPE | SL_SI91X_ENABLE_BLE_PROTOCOL; + cfg->ble_feature_bit_map |= SL_SI91X_BLE_MAX_NBR_PERIPHERALS(RSI_BLE_MAX_NBR_PERIPHERALS) | + SL_SI91X_BLE_MAX_NBR_CENTRALS(RSI_BLE_MAX_NBR_CENTRALS) | + SL_SI91X_BLE_MAX_NBR_ATT_SERV(RSI_BLE_MAX_NBR_ATT_SERV) | + SL_SI91X_BLE_MAX_NBR_ATT_REC(RSI_BLE_MAX_NBR_ATT_REC) | + SL_SI91X_BLE_PWR_INX(RSI_BLE_PWR_INX) | + SL_SI91X_BLE_PWR_SAVE_OPTIONS(RSI_BLE_PWR_SAVE_OPTIONS) | + SL_SI91X_916_BLE_COMPATIBLE_FEAT_ENABLE | + SL_SI91X_FEAT_BLE_CUSTOM_FEAT_EXTENSION_VALID; + cfg->ble_ext_feature_bit_map |= SL_SI91X_BLE_NUM_CONN_EVENTS(RSI_BLE_NUM_CONN_EVENTS) | + SL_SI91X_BLE_NUM_REC_BYTES(RSI_BLE_NUM_REC_BYTES) | + SL_SI91X_BLE_ENABLE_ADV_EXTN | + SL_SI91X_BLE_AE_MAX_ADV_SETS(RSI_BLE_AE_MAX_ADV_SETS); +#endif + /* TODO: If sl_net_*_profile() functions will be needed for WiFi then call * sl_net_set_profile() here. Currently these are unused. */