From 112bc6407ea9e570eb91cff8e6b9a5bf0096076e Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 12 Sep 2022 16:56:03 +0200 Subject: [PATCH 1/7] drivers: bluethooth: stm32wba: Add HCI driver for STM32WBA Add HCI Driver for STM32WBA devices. Based on B91 HCI driver. Signed-off-by: Erwan Gouriou --- drivers/bluetooth/hci/CMakeLists.txt | 1 + drivers/bluetooth/hci/Kconfig | 6 + drivers/bluetooth/hci/hci_stm32wba.c | 382 +++++++++++++++++++++++++++ subsys/bluetooth/Kconfig | 2 +- subsys/bluetooth/host/Kconfig | 1 + 5 files changed, 391 insertions(+), 1 deletion(-) create mode 100644 drivers/bluetooth/hci/hci_stm32wba.c diff --git a/drivers/bluetooth/hci/CMakeLists.txt b/drivers/bluetooth/hci/CMakeLists.txt index 6aaf5205b0dd7f..de9f14008a5e14 100644 --- a/drivers/bluetooth/hci/CMakeLists.txt +++ b/drivers/bluetooth/hci/CMakeLists.txt @@ -21,6 +21,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_H5 h5.c) zephyr_library_sources_ifdef(CONFIG_BT_HCI_IPC ipc.c) zephyr_library_sources_ifdef(CONFIG_BT_SPI spi.c) zephyr_library_sources_ifdef(CONFIG_BT_STM32_IPM ipm_stm32wb.c) +zephyr_library_sources_ifdef(CONFIG_BT_STM32WBA hci_stm32wba.c) zephyr_library_sources_ifdef(CONFIG_BT_USERCHAN userchan.c) zephyr_library_sources_ifdef(CONFIG_BT_SILABS_HCI slz_hci.c) zephyr_library_sources_ifdef(CONFIG_BT_PSOC6_BLESS hci_psoc6_bless.c) diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index 86e450c52c2d71..5c07c70f6992a3 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -62,6 +62,12 @@ config BT_STM32_IPM help TODO +config BT_STM32WBA + bool "STM32WBA HCI driver" + select HAS_STM32LIB + help + ST STM32WBA HCI Bluetooth interface + config BT_SILABS_HCI bool "Silicon Labs Bluetooth interface" depends on SOC_SERIES_EFR32BG22 || SOC_SERIES_EFR32MG24 || SOC_SERIES_EFR32BG27 diff --git a/drivers/bluetooth/hci/hci_stm32wba.c b/drivers/bluetooth/hci/hci_stm32wba.c new file mode 100644 index 00000000000000..357c3a8dac43a0 --- /dev/null +++ b/drivers/bluetooth/hci/hci_stm32wba.c @@ -0,0 +1,382 @@ +/* hci_stm32wba.c - HCI driver for stm32wba */ + +/* + * Copyright (c) 2022, Telink Semiconductor (Shanghai) Co., Ltd. + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "blestack.h" +#include "app_conf.h" +#include "ll_sys.h" +/* TODO: Enable Flash Manager once available */ +/* #include "flash_driver.h" */ + +#define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL +#include +LOG_MODULE_REGISTER(hci_wba); + +static K_SEM_DEFINE(hci_sem, 1, 1); + +#define HCI_CMD 0x01 +#define HCI_ACL 0x02 +#define HCI_SCO 0x03 +#define HCI_EVT 0x04 +#define HCI_ISO 0x05 + +#define BLE_CTRLR_STACK_BUFFER_SIZE 300 + +#define MBLOCK_COUNT (BLE_MBLOCKS_CALC(PREP_WRITE_LIST_SIZE, \ + CFG_BLE_ATT_MTU_MAX, \ + CFG_BLE_NUM_LINK) \ + + CFG_BLE_MBLOCK_COUNT_MARGIN) + +#define BLE_DYN_ALLOC_SIZE \ + (BLE_TOTAL_BUFFER_SIZE(CFG_BLE_NUM_LINK, MBLOCK_COUNT)) + +#define DIVC(x, y) (((x)+(y)-1)/(y)) + +static uint32_t buffer[DIVC(BLE_DYN_ALLOC_SIZE, 4)]; + +extern uint8_t ll_state_busy; + +static bool is_hci_event_discardable(const uint8_t *evt_data) +{ + uint8_t evt_type = evt_data[0]; + + switch (evt_type) { +#if defined(CONFIG_BT_BREDR) + case BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI: + case BT_HCI_EVT_EXTENDED_INQUIRY_RESULT: + return true; +#endif + case BT_HCI_EVT_LE_META_EVENT: { + uint8_t subevt_type = evt_data[sizeof(struct bt_hci_evt_hdr)]; + + switch (subevt_type) { + case BT_HCI_EVT_LE_ADVERTISING_REPORT: + return true; + default: + return false; + } + } + default: + return false; + } +} + +static struct net_buf *treat_evt(const uint8_t *data, size_t len) +{ + bool discardable; + struct bt_hci_evt_hdr hdr; + struct net_buf *buf; + size_t buf_tailroom; + + if (len < sizeof(hdr)) { + LOG_ERR("Not enough data for event header"); + return NULL; + } + + discardable = is_hci_event_discardable(data); + + memcpy((void *)&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + len -= sizeof(hdr); + + if (len != hdr.len) { + LOG_ERR("Event payload length is not correct.\n"); + LOG_ERR("len: %d, hdr.len: %d\n", len, hdr.len); + return NULL; + } + LOG_DBG("len %u", hdr.len); + + buf = bt_buf_get_evt(hdr.evt, discardable, discardable ? K_NO_WAIT : K_SECONDS(3)); + if (!buf) { + if (discardable) { + LOG_DBG("Discardable buffer pool full, ignoring event"); + } else { + LOG_ERR("No available event buffers!"); + + } + __ASSERT_NO_MSG(buf); + return buf; + } + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + + buf_tailroom = net_buf_tailroom(buf); + if (buf_tailroom < len) { + LOG_ERR("Not enough space in buffer %zu/%zu", len, buf_tailroom); + net_buf_unref(buf); + return NULL; + } + + net_buf_add_mem(buf, data, len); + + return buf; +} + +static struct net_buf *treat_acl(const uint8_t *data, size_t len, + const uint8_t *ext_data, size_t ext_len) +{ + struct bt_hci_acl_hdr hdr; + struct net_buf *buf; + size_t buf_tailroom; + + if (len < sizeof(hdr)) { + LOG_ERR("Not enough data for ACL header"); + return NULL; + } + + buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_NO_WAIT); + if (buf) { + memcpy((void *)&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + len -= sizeof(hdr); + } else { + LOG_ERR("No available ACL buffers!"); + return NULL; + } + + if (ext_len != sys_le16_to_cpu(hdr.len)) { + LOG_ERR("ACL payload length is not correct"); + net_buf_unref(buf); + return NULL; + } + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + buf_tailroom = net_buf_tailroom(buf); + if (buf_tailroom < len) { + LOG_ERR("Not enough space in buffer %zu/%zu", len, buf_tailroom); + net_buf_unref(buf); + return NULL; + } + + LOG_DBG("ext_len %u", ext_len); + net_buf_add_mem(buf, ext_data, ext_len); + + return buf; +} + +static struct net_buf *treat_iso(const uint8_t *data, size_t len, + const uint8_t *ext_data, size_t ext_len) +{ + struct bt_hci_iso_hdr hdr; + struct net_buf *buf; + size_t buf_tailroom; + + if (len < sizeof(hdr)) { + LOG_ERR("Not enough data for ISO header"); + return NULL; + } + + buf = bt_buf_get_rx(BT_BUF_ISO_IN, K_NO_WAIT); + if (buf) { + memcpy((void *)&hdr, data, sizeof(hdr)); + data += sizeof(hdr); + len -= sizeof(hdr); + } else { + LOG_ERR("No available ISO buffers!"); + return NULL; + } + + if (ext_len != bt_iso_hdr_len(sys_le16_to_cpu(hdr.len))) { + LOG_ERR("ISO payload length is not correct"); + net_buf_unref(buf); + return NULL; + } + + net_buf_add_mem(buf, &hdr, sizeof(hdr)); + buf_tailroom = net_buf_tailroom(buf); + if (buf_tailroom < len) { + LOG_ERR("Not enough space in buffer %zu/%zu", len, buf_tailroom); + net_buf_unref(buf); + return NULL; + } + + LOG_DBG("ext_len %zu", ext_len); + net_buf_add_mem(buf, ext_data, ext_len); + + return buf; +} + +static int receive_data(const uint8_t *data, size_t len, + const uint8_t *ext_data, size_t ext_len) +{ + uint8_t pkt_indicator; + struct net_buf *buf; + int err = 0; + + LOG_HEXDUMP_DBG(data, len, "host packet data:"); + LOG_HEXDUMP_DBG(ext_data, ext_len, "host packet ext_data:"); + + pkt_indicator = *data++; + len -= sizeof(pkt_indicator); + + switch (pkt_indicator) { + case HCI_EVT: + buf = treat_evt(data, len); + break; + case HCI_ACL: + buf = treat_acl(data, len + 1, ext_data, ext_len); + break; + case HCI_ISO: + case HCI_SCO: + buf = treat_iso(data, len + 1, ext_data, ext_len); + break; + default: + buf = NULL; + LOG_ERR("Unknown HCI type %u", pkt_indicator); + } + + if (buf) { + bt_recv(buf); + } else { + err = -ENOMEM; + ll_state_busy = 1; + } + + return err; +} + +uint8_t BLECB_Indication(const uint8_t *data, uint16_t length, + const uint8_t *ext_data, uint16_t ext_length) +{ + int ret = 0; + int err; + + LOG_DBG("length: %d", length); + if (ext_length != 0) { + LOG_DBG("ext_length: %d", ext_length); + } + + k_sem_take(&hci_sem, K_FOREVER); + + err = receive_data(data, (size_t)length - 1, + ext_data, (size_t)ext_length); + + k_sem_give(&hci_sem); + + HostStack_Process(); + + if (err) { + ret = 1; + } + + return ret; +} + +static int bt_hci_stm32wba_send(struct net_buf *buf) +{ + uint16_t event_length; + uint8_t pkt_indicator; + uint8_t tx_buffer[BLE_CTRLR_STACK_BUFFER_SIZE]; + + k_sem_take(&hci_sem, K_FOREVER); + + LOG_DBG("buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len); + + switch (bt_buf_get_type(buf)) { + case BT_BUF_ACL_OUT: + pkt_indicator = HCI_ACL; + break; + case BT_BUF_CMD: + pkt_indicator = HCI_CMD; + break; + case BT_BUF_ISO_OUT: + pkt_indicator = HCI_ISO; + break; + default: + LOG_ERR("Unknown type %u", bt_buf_get_type(buf)); + k_sem_give(&hci_sem); + return -EIO; + } + net_buf_push_u8(buf, pkt_indicator); + + memcpy(&tx_buffer, buf->data, buf->len); + + event_length = BleStack_Request(tx_buffer); + LOG_DBG("event_length: %u", event_length); + + if (event_length) { + receive_data((uint8_t *)&tx_buffer, (size_t)event_length, NULL, 0); + } + + k_sem_give(&hci_sem); + + net_buf_unref(buf); + + return 0; +} + +static int bt_ble_ctlr_init(void) +{ + BleStack_init_t init_params_p = {0}; + + init_params_p.numAttrRecord = CFG_BLE_NUM_GATT_ATTRIBUTES; + init_params_p.numAttrServ = CFG_BLE_NUM_GATT_SERVICES; + init_params_p.attrValueArrSize = CFG_BLE_ATT_VALUE_ARRAY_SIZE; + init_params_p.prWriteListSize = CFG_BLE_ATTR_PREPARE_WRITE_VALUE_SIZE; + init_params_p.attMtu = CFG_BLE_ATT_MTU_MAX; + init_params_p.max_coc_nbr = CFG_BLE_COC_NBR_MAX; + init_params_p.max_coc_mps = CFG_BLE_COC_MPS_MAX; + init_params_p.max_coc_initiator_nbr = CFG_BLE_COC_INITIATOR_NBR_MAX; + init_params_p.numOfLinks = CFG_BLE_NUM_LINK; + init_params_p.mblockCount = CFG_BLE_MBLOCK_COUNT; + init_params_p.bleStartRamAddress = (uint8_t *)buffer; + init_params_p.total_buffer_size = BLE_DYN_ALLOC_SIZE; + init_params_p.bleStartRamAddress_GATT = NULL; + init_params_p.total_buffer_size_GATT = 0; + init_params_p.options = CFG_BLE_OPTIONS; + init_params_p.debug = 0U; + + if (BleStack_Init(&init_params_p) != BLE_STATUS_SUCCESS) { + return -EIO; + } + + return 0; +} + +static int bt_hci_stm32wba_open(void) +{ + int ret = 0; + + link_layer_register_isr(); + + ll_sys_config_params(); + + ret = bt_ble_ctlr_init(); + + /* TODO. Enable Flash manager once available */ + /* FD_SetStatus(FD_FLASHACCESS_RFTS_BYPASS, LL_FLASH_DISABLE); */ + + return ret; +} + +static const struct bt_hci_driver drv = { + .name = "BT IPM", + .bus = BT_HCI_DRIVER_BUS_IPM, + .open = bt_hci_stm32wba_open, + .send = bt_hci_stm32wba_send, +}; + +static int bt_stm32wba_hci_init(void) +{ + bt_hci_driver_register(&drv); + + return 0; +} + +SYS_INIT(bt_stm32wba_hci_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); diff --git a/subsys/bluetooth/Kconfig b/subsys/bluetooth/Kconfig index 912846e4cda16e..c8f71afb2074da 100644 --- a/subsys/bluetooth/Kconfig +++ b/subsys/bluetooth/Kconfig @@ -128,7 +128,7 @@ if BT_CONN config BT_HCI_ACL_FLOW_CONTROL bool "Controller to Host ACL flow control support" # Enable if building a Host-only build - default y if !BT_CTLR && !BT_STM32_IPM && !BT_ESP32 + default y if !BT_CTLR && !BT_STM32_IPM && !BT_ESP32 && !BT_STM32WBA # Enable if building a Controller-only build default y if BT_HCI_RAW select POLL diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index c5c73be39a2f03..fc92ca0c96245c 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -79,6 +79,7 @@ config BT_HCI_RESERVE default 1 if BT_HCI_IPC default 1 if BT_SPI default 1 if BT_STM32_IPM + default 1 if BT_STM32WBA default 1 if BT_USERCHAN default 1 if BT_ESP32 default 0 if BT_B91 From 99713a17e545c56716ab487034326df86c3d434b Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 4 Dec 2023 15:28:09 +0100 Subject: [PATCH 2/7] modules: Kconfig.stm32: Add Kconfig symbol for RAMCFG RAMCFG will be required for STM32WBA BLE support. Signed-off-by: Erwan Gouriou --- modules/Kconfig.stm32 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/Kconfig.stm32 b/modules/Kconfig.stm32 index ad598f6300685d..57749a8ec6b4d7 100644 --- a/modules/Kconfig.stm32 +++ b/modules/Kconfig.stm32 @@ -447,6 +447,11 @@ config USE_STM32_HAL_RAMECC help Enable STM32Cube RAM ECC monitoring (RAMECC) HAL module driver +config USE_STM32_HAL_RAMCFG + bool + help + Enable STM32Cube RAM config (RAMCFG) HAL module driver + config USE_STM32_HAL_RNG bool help From af565581a8b821d7632d080cc92ffe00ea01665f Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Mon, 4 Dec 2023 15:44:58 +0100 Subject: [PATCH 3/7] soc: stm32wba: Implement BLE controller lib APIs over Zephyr In order to enable BLE support on STM32WBA, following APIs are implemented: - HostStack_: BLE Controller scheduling - ll_sys_: Link layer API required for scheduling - UTIL_TIMER_: BLE Controller timer utility - LINKLAYER_PLAT_: BLE controller utilities Signed-off-by: Erwan Gouriou --- soc/arm/st_stm32/stm32wba/CMakeLists.txt | 10 + .../stm32wba/Kconfig.defconfig.series | 26 ++ soc/arm/st_stm32/stm32wba/hci_if/bleplat.c | 100 ++++++ .../st_stm32/stm32wba/hci_if/host_stack_if.c | 82 +++++ .../st_stm32/stm32wba/hci_if/linklayer_plat.c | 304 ++++++++++++++++++ .../stm32wba/hci_if/linklayer_plat_local.h | 13 + soc/arm/st_stm32/stm32wba/hci_if/ll_sys_if.c | 47 +++ .../st_stm32/stm32wba/hci_if/stm32_timer.c | 59 ++++ 8 files changed, 641 insertions(+) create mode 100644 soc/arm/st_stm32/stm32wba/hci_if/bleplat.c create mode 100644 soc/arm/st_stm32/stm32wba/hci_if/host_stack_if.c create mode 100644 soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat.c create mode 100644 soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat_local.h create mode 100644 soc/arm/st_stm32/stm32wba/hci_if/ll_sys_if.c create mode 100644 soc/arm/st_stm32/stm32wba/hci_if/stm32_timer.c diff --git a/soc/arm/st_stm32/stm32wba/CMakeLists.txt b/soc/arm/st_stm32/stm32wba/CMakeLists.txt index 0fd5073770d301..d26c143f8f6e8b 100644 --- a/soc/arm/st_stm32/stm32wba/CMakeLists.txt +++ b/soc/arm/st_stm32/stm32wba/CMakeLists.txt @@ -9,4 +9,14 @@ zephyr_sources_ifdef(CONFIG_PM power.c ) +if(CONFIG_BT_STM32WBA) + zephyr_include_directories(hci_if) + + zephyr_sources(hci_if/linklayer_plat.c) + zephyr_sources(hci_if/bleplat.c) + zephyr_sources(hci_if/host_stack_if.c) + zephyr_sources(hci_if/ll_sys_if.c) + zephyr_sources(hci_if/stm32_timer.c) +endif() + set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series b/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series index e6d57729a09213..a1099228e5f08e 100644 --- a/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series +++ b/soc/arm/st_stm32/stm32wba/Kconfig.defconfig.series @@ -13,4 +13,30 @@ config SOC_SERIES config STM32_LPTIM_TIMER default y if PM +choice BT_HCI_BUS_TYPE + default BT_STM32WBA + depends on BT +endchoice + +config BT_STM32WBA + select DYNAMIC_INTERRUPTS + select DYNAMIC_DIRECT_INTERRUPTS + select ENTROPY_GENERATOR + select USE_STM32_HAL_RAMCFG + +if BT_STM32WBA + +choice LIBC_IMPLEMENTATION + default NEWLIB_LIBC +endchoice + +choice LINKER_ORPHAN_CONFIGURATION + default LINKER_ORPHAN_SECTION_PLACE +endchoice + +config ENTROPY_STM32_CLK_CHECK + default n + +endif + endif # SOC_SERIES_STM32WBAX diff --git a/soc/arm/st_stm32/stm32wba/hci_if/bleplat.c b/soc/arm/st_stm32/stm32wba/hci_if/bleplat.c new file mode 100644 index 00000000000000..7c1ed1aa962cda --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/hci_if/bleplat.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "bleplat.h" +#include "bpka.h" +#include "linklayer_plat.h" + +#define LOG_LEVEL CONFIG_SOC_LOG_LEVEL +LOG_MODULE_REGISTER(ble_plat); + +RAMCFG_HandleTypeDef hramcfg_SRAM1; +const struct device *rng_dev; + +void BLEPLAT_Init(void) +{ + BPKA_Reset(); + + rng_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_entropy)); + if (!device_is_ready(rng_dev)) { + LOG_ERR("error: random device not ready"); + } +} + +void BLEPLAT_RngGet(uint8_t n, uint32_t *val) +{ + LINKLAYER_PLAT_GetRNG((uint8_t *)val, 4 * n); +} + +int BLEPLAT_PkaStartP256Key(const uint32_t *local_private_key) +{ + return BPKA_StartP256Key(local_private_key); +} + +void BLEPLAT_PkaReadP256Key(uint32_t *local_public_key) +{ + BPKA_ReadP256Key(local_public_key); +} + +int BLEPLAT_PkaStartDhKey(const uint32_t *local_private_key, + const uint32_t *remote_public_key) +{ + return BPKA_StartDhKey(local_private_key, remote_public_key); +} + +int BLEPLAT_PkaReadDhKey(uint32_t *dh_key) +{ + return BPKA_ReadDhKey(dh_key); +} + +void BPKACB_Complete(void) +{ + BLEPLATCB_PkaComplete(); +} + +void MX_RAMCFG_Init(void) +{ + /* Initialize RAMCFG SRAM1 */ + hramcfg_SRAM1.Instance = RAMCFG_SRAM1; + if (HAL_RAMCFG_Init(&hramcfg_SRAM1) != HAL_OK) { + LOG_ERR("Could not init RAMCFG"); + } +} + +void *ble_memcpy(void *dst, const void *src, uint8_t n) +{ + memcpy(dst, src, (size_t)n); + + return dst; +} + +void *ble_memset(void *dst, uint8_t c, uint16_t n) +{ + memset((void *)dst, (int)c, (size_t)n); + + return dst; +} + +int8_t ble_memcmp(const void *a, const void *b, uint16_t n) +{ + return (int8_t)memcmp(a, b, (size_t)n); +} + +void Error_Handler(void) +{ + LOG_ERR(""); +} + +/* BLE ctlr should not disable HSI on its own */ +void SCM_HSI_CLK_OFF(void) {} + +/* BLE ctlr should not alter RNG clocks */ +void HW_RNG_DisableClock(uint8_t) {} +void HW_RNG_EnableClock(uint8_t) {} diff --git a/soc/arm/st_stm32/stm32wba/hci_if/host_stack_if.c b/soc/arm/st_stm32/stm32wba/hci_if/host_stack_if.c new file mode 100644 index 00000000000000..6cc224cc60ae54 --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/hci_if/host_stack_if.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "app_conf.h" +#include "blestack.h" +#include "bpka.h" +#include "ll_intf.h" + +K_MUTEX_DEFINE(ble_ctlr_stack_mutex); +struct k_work_q ble_ctlr_work_q, ll_work_q; +struct k_work ble_ctlr_stack_work, bpka_work; + +uint8_t ll_state_busy; + +#define BLE_CTLR_TASK_STACK_SIZE (256 * 7) +#define LL_TASK_STACK_SIZE (256 * 7) +#define BLE_CTLR_TASK_PRIO (14) +#define LL_TASK_PRIO (14) + +K_THREAD_STACK_DEFINE(ble_ctlr_work_area, BLE_CTLR_TASK_STACK_SIZE); +K_THREAD_STACK_DEFINE(ll_work_area, LL_TASK_STACK_SIZE); + +void HostStack_Process(void) +{ + k_work_submit_to_queue(&ble_ctlr_work_q, &ble_ctlr_stack_work); +} + +static void ble_ctlr_stack_handler(struct k_work *work) +{ + uint8_t running = 0x0; + change_state_options_t options; + + k_mutex_lock(&ble_ctlr_stack_mutex, K_FOREVER); + running = BleStack_Process(); + k_mutex_unlock(&ble_ctlr_stack_mutex); + + if (ll_state_busy == 1) { + options.combined_value = 0x0F; + ll_intf_chng_evnt_hndlr_state(options); + ll_state_busy = 0; + } + + if (running == BLE_SLEEPMODE_RUNNING) { + HostStack_Process(); + } +} + +void BPKACB_Process(void) +{ + k_work_submit_to_queue(&ble_ctlr_work_q, &bpka_work); +} + +static void bpka_work_handler(struct k_work *work) +{ + BPKA_BG_Process(); +} + +static int stm32wba_ble_ctlr_init(void) +{ + k_work_queue_init(&ble_ctlr_work_q); + k_work_queue_start(&ble_ctlr_work_q, ble_ctlr_work_area, + K_THREAD_STACK_SIZEOF(ble_ctlr_work_area), + BLE_CTLR_TASK_PRIO, NULL); + + k_work_queue_init(&ll_work_q); + k_work_queue_start(&ll_work_q, ll_work_area, + K_THREAD_STACK_SIZEOF(ll_work_area), + LL_TASK_PRIO, NULL); + + k_work_init(&ble_ctlr_stack_work, &ble_ctlr_stack_handler); + k_work_init(&bpka_work, &bpka_work_handler); + + return 0; +} + +SYS_INIT(stm32wba_ble_ctlr_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat.c b/soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat.c new file mode 100644 index 00000000000000..1e890949147908 --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "scm.h" + +#define LOG_LEVEL CONFIG_SOC_LOG_LEVEL +LOG_MODULE_REGISTER(linklayer_plat); + +#define RADIO_INTR_PRIO_HIGH_Z (RADIO_INTR_PRIO_HIGH + _IRQ_PRIO_OFFSET) +#define RADIO_INTR_PRIO_LOW_Z (RADIO_INTR_PRIO_LOW + _IRQ_PRIO_OFFSET) + +/* 2.4GHz RADIO ISR callbacks */ +typedef void (*radio_isr_cb_t) (void); + +radio_isr_cb_t radio_callback; +radio_isr_cb_t low_isr_callback; + +extern const struct device *rng_dev; + +/* Radio critical sections */ +volatile int32_t prio_high_isr_counter; +volatile int32_t prio_low_isr_counter; +volatile int32_t prio_sys_isr_counter; +volatile int32_t irq_counter; +volatile uint32_t local_basepri_value; + +/* Radio SW low ISR global variable */ +volatile uint8_t radio_sw_low_isr_is_running_high_prio; + +void LINKLAYER_PLAT_ClockInit(void) +{ + LL_PWR_EnableBkUpAccess(); + + /* Select LSE as Sleep CLK */ + __HAL_RCC_RADIOSLPTIM_CONFIG(RCC_RADIOSTCLKSOURCE_LSE); + + LL_PWR_DisableBkUpAccess(); + + /* Enable AHB5ENR peripheral clock (bus CLK) */ + __HAL_RCC_RADIO_CLK_ENABLE(); +} + +void LINKLAYER_PLAT_DelayUs(uint32_t delay) +{ + k_busy_wait(delay); +} + +void LINKLAYER_PLAT_WaitHclkRdy(void) +{ + while (HAL_RCCEx_GetRadioBusClockReadiness() != RCC_RADIO_BUS_CLOCK_READY) { + } +} + +void LINKLAYER_PLAT_AclkCtrl(uint8_t enable) +{ + LOG_DBG("enable: %d", enable); + if (enable) { + /* Enable RADIO baseband clock (active CLK) */ + HAL_RCCEx_EnableRadioBBClock(); + + /* Polling on HSE32 activation */ + while (LL_RCC_HSE_IsReady() == 0) { + } + } else { + /* Disable RADIO baseband clock (active CLK) */ + HAL_RCCEx_DisableRadioBBClock(); + } +} + +void LINKLAYER_PLAT_GetRNG(uint8_t *ptr_rnd, uint32_t len) +{ + int ret; + + /* Read 32-bit random values from HW driver */ + ret = entropy_get_entropy_isr(rng_dev, (char *)ptr_rnd, len, 0); + if (ret < 0) { + LOG_ERR("Error: entropy_get_entropy failed: %d", ret); + } + LOG_DBG("n %d, val: %p", len, (void *)ptr_rnd); +} + +void LINKLAYER_PLAT_SetupRadioIT(void (*intr_cb)()) +{ + radio_callback = intr_cb; +} + +void LINKLAYER_PLAT_SetupSwLowIT(void (*intr_cb)()) +{ + low_isr_callback = intr_cb; +} + +void radio_high_prio_isr(void) +{ + radio_callback(); + + HAL_RCCEx_DisableRequestUponRadioWakeUpEvent(); + + __ISB(); + + ISR_DIRECT_PM(); +} + +void radio_low_prio_isr(void) +{ + irq_disable((IRQn_Type)RADIO_SW_LOW_INTR_NUM); + + low_isr_callback(); + + /* Check if nested SW radio low interrupt has been requested*/ + if (radio_sw_low_isr_is_running_high_prio != 0) { + NVIC_SetPriority((IRQn_Type) RADIO_SW_LOW_INTR_NUM, RADIO_INTR_PRIO_LOW); + radio_sw_low_isr_is_running_high_prio = 0; + } + + /* Re-enable SW radio low interrupt */ + irq_enable((IRQn_Type)RADIO_SW_LOW_INTR_NUM); + + ISR_DIRECT_PM(); +} + + +void link_layer_register_isr(void) +{ + ARM_IRQ_DIRECT_DYNAMIC_CONNECT(RADIO_INTR_NUM, 0, 0, reschedule); + + /* Ensure the IRQ is disabled before enabling it at run time */ + irq_disable((IRQn_Type)RADIO_INTR_NUM); + + irq_connect_dynamic((IRQn_Type)RADIO_INTR_NUM, RADIO_INTR_PRIO_HIGH_Z, + (void (*)(const void *))radio_high_prio_isr, NULL, 0); + + irq_enable((IRQn_Type)RADIO_INTR_NUM); + + ARM_IRQ_DIRECT_DYNAMIC_CONNECT(RADIO_SW_LOW_INTR_NUM, 0, 0, reschedule); + + /* Ensure the IRQ is disabled before enabling it at run time */ + irq_disable((IRQn_Type)RADIO_SW_LOW_INTR_NUM); + + irq_connect_dynamic((IRQn_Type)RADIO_SW_LOW_INTR_NUM, RADIO_SW_LOW_INTR_PRIO, + (void (*)(const void *))radio_low_prio_isr, NULL, 0); + + irq_enable((IRQn_Type)RADIO_SW_LOW_INTR_NUM); +} + + +void LINKLAYER_PLAT_TriggerSwLowIT(uint8_t priority) +{ + uint8_t low_isr_priority = RADIO_INTR_PRIO_LOW_Z; + + LOG_DBG("Priotity: %d", priority); + + /* Check if a SW low interrupt as already been raised. + * Nested call far radio low isr are not supported + **/ + + if (NVIC_GetActive(RADIO_SW_LOW_INTR_NUM) == 0) { + /* No nested SW low ISR, default behavior */ + + if (priority == 0) { + low_isr_priority = RADIO_SW_LOW_INTR_PRIO; + } + + NVIC_SetPriority((IRQn_Type)RADIO_SW_LOW_INTR_NUM, low_isr_priority); + } else { + /* Nested call detected */ + /* No change for SW radio low interrupt priority for the moment */ + + if (priority != 0) { + /* At the end of current SW radio low ISR, this pending SW + * low interrupt will run with RADIO_INTR_PRIO_LOW_Z priority + **/ + radio_sw_low_isr_is_running_high_prio = 1; + } + } + + NVIC_SetPendingIRQ((IRQn_Type)RADIO_SW_LOW_INTR_NUM); +} + +void LINKLAYER_PLAT_EnableIRQ(void) +{ + irq_counter = MAX(0, irq_counter - 1); + + if (irq_counter == 0) { + __enable_irq(); + } +} + +void LINKLAYER_PLAT_DisableIRQ(void) +{ + __disable_irq(); + + irq_counter++; +} + +void LINKLAYER_PLAT_Assert(uint8_t condition) +{ + __ASSERT_NO_MSG(condition); +} + +void LINKLAYER_PLAT_EnableSpecificIRQ(uint8_t isr_type) +{ + + LOG_DBG("isr_type: %d", isr_type); + + if ((isr_type & LL_HIGH_ISR_ONLY) != 0) { + prio_high_isr_counter--; + if (prio_high_isr_counter == 0) { + irq_enable(RADIO_INTR_NUM); + } + } + + if ((isr_type & LL_LOW_ISR_ONLY) != 0) { + prio_low_isr_counter--; + if (prio_low_isr_counter == 0) { + irq_enable(RADIO_SW_LOW_INTR_NUM); + } + } + + if ((isr_type & SYS_LOW_ISR) != 0) { + prio_sys_isr_counter--; + if (prio_sys_isr_counter == 0) { + __set_BASEPRI(local_basepri_value); + } + } +} + +void LINKLAYER_PLAT_DisableSpecificIRQ(uint8_t isr_type) +{ + + LOG_DBG("isr_type: %d", isr_type); + + if ((isr_type & LL_HIGH_ISR_ONLY) != 0) { + prio_high_isr_counter++; + if (prio_high_isr_counter == 1) { + irq_disable(RADIO_INTR_NUM); + } + } + + if ((isr_type & LL_LOW_ISR_ONLY) != 0) { + prio_low_isr_counter++; + if (prio_low_isr_counter == 1) { + irq_disable(RADIO_SW_LOW_INTR_NUM); + } + } + + if ((isr_type & SYS_LOW_ISR) != 0) { + prio_sys_isr_counter++; + if (prio_sys_isr_counter == 1) { + local_basepri_value = __get_BASEPRI(); + __set_BASEPRI_MAX(RADIO_INTR_PRIO_LOW_Z << 4); + } + } +} + +void LINKLAYER_PLAT_EnableRadioIT(void) +{ + irq_enable((IRQn_Type)RADIO_INTR_NUM); +} + +void LINKLAYER_PLAT_DisableRadioIT(void) +{ + irq_disable((IRQn_Type)RADIO_INTR_NUM); +} + +void LINKLAYER_PLAT_StartRadioEvt(void) +{ + __HAL_RCC_RADIO_CLK_SLEEP_ENABLE(); + + NVIC_SetPriority(RADIO_INTR_NUM, RADIO_INTR_PRIO_HIGH_Z); + + scm_notifyradiostate(SCM_RADIO_ACTIVE); +} + +void LINKLAYER_PLAT_StopRadioEvt(void) +{ + __HAL_RCC_RADIO_CLK_SLEEP_DISABLE(); + + NVIC_SetPriority(RADIO_INTR_NUM, RADIO_INTR_PRIO_LOW_Z); + + scm_notifyradiostate(SCM_RADIO_NOT_ACTIVE); +} + +void LINKLAYER_PLAT_RequestTemperature(void) {} + +void LINKLAYER_PLAT_SCHLDR_TIMING_UPDATE_NOT(Evnt_timing_t *p_evnt_timing) {} + +void LINKLAYER_PLAT_EnableOSContextSwitch(void) {} + +void LINKLAYER_PLAT_DisableOSContextSwitch(void) {} diff --git a/soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat_local.h b/soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat_local.h new file mode 100644 index 00000000000000..1cf621b89ded09 --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/hci_if/linklayer_plat_local.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#ifndef _STM32WBA_LINK_LAYER_PLAT_LOCAL_H_ +#define _STM32WBA_LINK_LAYER_PLAT_LOCAL_H_ + +void link_layer_register_isr(void); + +#endif /* _STM32WBA_LINK_LAYER_PLAT_LOCAL_H_ */ diff --git a/soc/arm/st_stm32/stm32wba/hci_if/ll_sys_if.c b/soc/arm/st_stm32/stm32wba/hci_if/ll_sys_if.c new file mode 100644 index 00000000000000..8607cbbafd8dde --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/hci_if/ll_sys_if.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#define LOG_LEVEL CONFIG_SOC_LOG_LEVEL +LOG_MODULE_REGISTER(ll_sys_if); + +#include "ll_intf.h" +#include "ll_sys.h" +#include "linklayer_plat.h" +#include "app_conf.h" + +extern struct k_mutex ble_ctlr_stack_mutex; +extern struct k_work_q ll_work_q; +struct k_work ll_sys_work; + +void ll_sys_schedule_bg_process(void) +{ + k_work_submit_to_queue(&ll_work_q, &ll_sys_work); +} + +void ll_sys_schedule_bg_process_isr(void) +{ + k_work_submit_to_queue(&ll_work_q, &ll_sys_work); +} + +static void ll_sys_bg_process_handler(struct k_work *work) +{ + k_mutex_lock(&ble_ctlr_stack_mutex, K_FOREVER); + ll_sys_bg_process(); + k_mutex_unlock(&ble_ctlr_stack_mutex); +} + +void ll_sys_bg_process_init(void) +{ + k_work_init(&ll_sys_work, &ll_sys_bg_process_handler); +} + +void ll_sys_config_params(void) +{ + ll_intf_config_ll_ctx_params(USE_RADIO_LOW_ISR, NEXT_EVENT_SCHEDULING_FROM_ISR); +} diff --git a/soc/arm/st_stm32/stm32wba/hci_if/stm32_timer.c b/soc/arm/st_stm32/stm32wba/hci_if/stm32_timer.c new file mode 100644 index 00000000000000..45c3f1b378293a --- /dev/null +++ b/soc/arm/st_stm32/stm32wba/hci_if/stm32_timer.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "stm32_timer.h" + +#define TICKS_PER_MS (CONFIG_SYS_CLOCK_TICKS_PER_SEC / MSEC_PER_SEC) + +static struct k_timer timer; + +UTIL_TIMER_Status_t UTIL_TIMER_Create(UTIL_TIMER_Object_t *timer_object, + uint32_t period, UTIL_TIMER_Mode_t mode, + void (*callback)(void *), void *argument) +{ + if (timer_object == NULL) { + return UTIL_TIMER_INVALID_PARAM; + } + + timer_object->ReloadValue = period * TICKS_PER_MS; + timer_object->Mode = mode; + timer_object->Callback = callback; + timer_object->argument = argument; + timer_object->IsRunning = false; + timer_object->IsReloadStopped = false; + timer_object->Next = NULL; + + return UTIL_TIMER_OK; +} + +UTIL_TIMER_Status_t UTIL_TIMER_Start(UTIL_TIMER_Object_t *timer_object) +{ + if (timer_object == NULL) { + return UTIL_TIMER_INVALID_PARAM; + } + + k_timer_user_data_set(&timer, timer_object); + k_timer_start(&timer, K_TICKS(timer_object->ReloadValue), + K_TICKS(timer_object->ReloadValue)); + timer_object->IsRunning = true; + + return UTIL_TIMER_OK; +} + +UTIL_TIMER_Status_t UTIL_TIMER_Stop(UTIL_TIMER_Object_t *timer_object) +{ + if (timer_object == NULL) { + return UTIL_TIMER_INVALID_PARAM; + } + + k_timer_stop(&timer); + timer_object->IsRunning = false; + + return UTIL_TIMER_OK; +} From 61312e696d942cc8b081d31feeb4e38e1df7df56 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Wed, 22 Mar 2023 17:53:50 +0100 Subject: [PATCH 4/7] dts: stm32wba: Define SRAM6 as RAM_NOCACHE SRAM6 is used by RF and should be defined as RAM_NOCACHE to allow unaligned access reads. "IO" might be a better match but is not available on this arch. Signed-off-by: Erwan Gouriou --- dts/arm/st/wba/stm32wba.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index 5e0f67625ee262..84954a5693f318 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -6,6 +6,7 @@ #include +#include #include #include #include @@ -61,6 +62,15 @@ compatible = "mmio-sram"; }; + /* Defining this memory solves unaligned memory access issue */ + sram6: memory@48028000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x48028000 DT_SIZE_K(16)>; + device_type = "memory"; + zephyr,memory-region = "SRAM6"; + zephyr,memory-attr = <( DT_MEM_ARM(ATTR_MPU_RAM_NOCACHE) )>; + }; + clocks { clk_hse: clk-hse { #clock-cells = <0>; From 3e94766a2e713479193df56d5ae683ca84586d4b Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Thu, 23 Mar 2023 09:05:25 +0100 Subject: [PATCH 5/7] dts: wba: configure HSI16 as RNG clk source We might have to do this differently: Configure rng default clock in .dtsi Set board specific config in .dts Signed-off-by: Erwan Gouriou --- dts/arm/st/wba/stm32wba.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dts/arm/st/wba/stm32wba.dtsi b/dts/arm/st/wba/stm32wba.dtsi index 84954a5693f318..27018b71d33836 100644 --- a/dts/arm/st/wba/stm32wba.dtsi +++ b/dts/arm/st/wba/stm32wba.dtsi @@ -443,7 +443,7 @@ reg = <0x520c0800 0x400>; interrupts = <59 0>; clocks = <&rcc STM32_CLOCK_BUS_AHB2 0x00040000>, - <&rcc STM32_SRC_PLL1_Q RNG_SEL(3)>; + <&rcc STM32_SRC_HSI16 RNG_SEL(2)>; nist-config = <0xf00d>; health-test-config = <0xaac7>; status = "disabled"; From 1dd18bee36fa80c3b5d2f61b85342d1bb4d0b851 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 5 Dec 2023 16:45:44 +0100 Subject: [PATCH 6/7] boards: nucleo_wba55cg: Update clock configuration to be BLE compatible To be compatible with BLE operation and BLE Controler configuration, update board clock configuration to work using a fixed core clock at 16MHz. Signed-off-by: Erwan Gouriou --- boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts b/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts index 5f190357a0df7e..268147f1141805 100644 --- a/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts +++ b/boards/arm/nucleo_wba55cg/nucleo_wba55cg.dts @@ -58,24 +58,20 @@ &clk_hse { status = "okay"; + hse-div2; }; -&pll1 { - div-m = <8>; - mul-n = <48>; - div-q = <2>; - div-r = <2>; - clocks = <&clk_hse>; +&clk_hsi { status = "okay"; }; &rcc { - clocks = <&pll1>; - clock-frequency = ; + clocks = <&clk_hse>; + clock-frequency = ; ahb-prescaler = <1>; - ahb5-prescaler = <4>; + ahb5-prescaler = <2>; apb1-prescaler = <1>; - apb2-prescaler = <1>; + apb2-prescaler = <2>; apb7-prescaler = <1>; }; @@ -91,6 +87,8 @@ }; &usart1 { + clocks = <&rcc STM32_CLOCK_BUS_APB2 0x00004000>, + <&rcc STM32_SRC_HSI16 USART1_SEL(2)>; pinctrl-0 = <&usart1_tx_pb12 &usart1_rx_pa8>; pinctrl-names = "default"; current-speed = <115200>; From 43511880e4320f0d116867f170f3cf3d74dde3a8 Mon Sep 17 00:00:00 2001 From: Erwan Gouriou Date: Tue, 5 Dec 2023 17:50:18 +0100 Subject: [PATCH 7/7] west.yml: Point to hal_stm32 version compatible with STM32WBA BLE Update west manifest to point to hal_stm32 PR containing changes which allow to build a zephyr bluetooth application on STM32WBA. Prior building such application, user should run 'west blobs fetch stm32' to install binary blobs providing the BLE controller support. Signed-off-by: Erwan Gouriou --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index e31e126f361e35..1fe33a9d5eb6b2 100644 --- a/west.yml +++ b/west.yml @@ -229,7 +229,7 @@ manifest: groups: - hal - name: hal_stm32 - revision: 39903791f413a944b3ec926276557757ea47a691 + revision: d183c9c9f56dfed04da0b8e150424177ab9ce51e path: modules/hal/stm32 groups: - hal