diff --git a/boards/arm/cy8cproto_063_ble/Kconfig.defconfig b/boards/arm/cy8cproto_063_ble/Kconfig.defconfig index e19137396a..d6e691e3f0 100644 --- a/boards/arm/cy8cproto_063_ble/Kconfig.defconfig +++ b/boards/arm/cy8cproto_063_ble/Kconfig.defconfig @@ -9,4 +9,8 @@ if BOARD_CY8CPROTO_063_BLE config BOARD default "cy8cproto_063_ble" +choice BT_HCI_BUS_TYPE + default BT_PSOC6_BLESS if BT +endchoice + endif # BOARD_CY8CPROTO_063_BLE diff --git a/boards/arm/cy8cproto_063_ble/cy8cproto_063_ble.dts b/boards/arm/cy8cproto_063_ble/cy8cproto_063_ble.dts index 0003460bbd..331af88942 100644 --- a/boards/arm/cy8cproto_063_ble/cy8cproto_063_ble.dts +++ b/boards/arm/cy8cproto_063_ble/cy8cproto_063_ble.dts @@ -51,7 +51,6 @@ status = "okay"; }; - &gpio_prt5 { status = "okay"; }; @@ -117,3 +116,7 @@ uart5: &scb5 { &clk_peri { clock-div = <1>; }; + +&bluetooth { + status = "okay"; +}; diff --git a/drivers/bluetooth/hci/CMakeLists.txt b/drivers/bluetooth/hci/CMakeLists.txt index 4bf06d3ce1..8aca5f92a7 100644 --- a/drivers/bluetooth/hci/CMakeLists.txt +++ b/drivers/bluetooth/hci/CMakeLists.txt @@ -10,3 +10,4 @@ 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_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 7dde9f94d9..8fee41d9b2 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -88,6 +88,13 @@ config BT_B91 help Telink B91 HCI bluetooth interface +config BT_PSOC6_BLESS + bool "PSOC6 BLESS driver" + select BT_HCI_SETUP + help + PSOC6 BLESS driver with BLE Controller which operates in + Single CPU mode. + config BT_NO_DRIVER bool "No default HCI driver" help diff --git a/drivers/bluetooth/hci/Kconfig.infineon b/drivers/bluetooth/hci/Kconfig.infineon index acbbfe2ed1..d0e4478ac3 100644 --- a/drivers/bluetooth/hci/Kconfig.infineon +++ b/drivers/bluetooth/hci/Kconfig.infineon @@ -135,3 +135,17 @@ config BT_ATT_ENFORCE_FLOW default n endif # BT_CYW43XXX + +if BT_PSOC6_BLESS + +config BT_PSOC6_BLESS_MAX_TX_PAYLOAD + int "Max Tx payload size" + range 27 251 + default 27 + +config BT_PSOC6_BLESS_MAX_RX_PAYLOAD + int "Max Rx payload size" + range 27 251 + default 27 + +endif # BT_PSOC6_BLESS diff --git a/drivers/bluetooth/hci/hci_psoc6_bless.c b/drivers/bluetooth/hci/hci_psoc6_bless.c new file mode 100644 index 0000000000..c001264618 --- /dev/null +++ b/drivers/bluetooth/hci/hci_psoc6_bless.c @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief PSoC 6 BLE (BLESS) driver. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "zephyr/logging/log.h" + +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER) +#define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL +#include +LOG_MODULE_REGISTER(psoc6_bless); + +#include "cy_ble_stack_pvt.h" +#include "cycfg_ble.h" + +#define DT_DRV_COMPAT infineon_cat1_bless_hci + +#define PACKET_TYPE_HCI_COMMAND 0X1 +#define PACKET_TYPE_HCI_ACL_DATA 0x2 +#define PACKET_TYPE_HCI_SYNCHRONOUS 0X3 +#define PACKET_TYPE_HCI_EVENT 0X4 + +#define BLE_LOCK_TMOUT_MS (1000) +#define BLE_THREAD_SEM_TMOUT_MS (1000) + +#define CYBLE_STACK_SIZE (CY_BLE_STACK_RAM_SIZE + 4096) + +#define PSOC6_BLESS_OP_SET_PUBLIC_ADDR BT_OP(BT_OGF_VS, 0x1a0) + +static K_SEM_DEFINE(psoc6_bless_rx_sem, 0, 1); +static K_SEM_DEFINE(psoc6_bless_operation_sem, 1, 1); +static K_KERNEL_STACK_DEFINE(psoc6_bless_rx_thread_stack, CONFIG_BT_RX_STACK_SIZE); +static struct k_thread psoc6_bless_rx_thread_data; +static cy_stc_ble_hci_tx_packet_info_t hci_tx_pkt; + +extern void Cy_BLE_EnableLowPowerMode(void); + +CY_ALIGN(sizeof(uint32_t)) CY_NOINIT uint8_t psoc6_bless_stack_memory[CYBLE_STACK_SIZE]; + +/** BLE Stack parameters */ +static cy_stc_ble_stack_params_t psoc6_bless_stack_param = { + .memoryHeapPtr = psoc6_bless_stack_memory, + .totalHeapSz = CYBLE_STACK_SIZE, + .dleMaxTxCapability = CONFIG_BT_PSOC6_BLESS_MAX_TX_PAYLOAD, + .dleMaxRxCapability = CONFIG_BT_PSOC6_BLESS_MAX_RX_PAYLOAD, + .featureMask = (CY_BLE_DLE_FEATURE | CY_BLE_LL_PRIVACY_FEATURE | + CY_BLE_SECURE_CONN_FEATURE | CY_BLE_PHY_UPDATE_FEATURE | + CY_BLE_STORE_BONDLIST_FEATURE | CY_BLE_STORE_RESOLVING_LIST_FEATURE | + CY_BLE_STORE_WHITELIST_FEATURE | CY_BLE_TX_POWER_CALIBRATION_FEATURE), + .maxConnCount = CY_BLE_CONN_COUNT, + .tx5dbmModeEn = CY_BLE_ENABLE_TX_5DBM, +}; + +static const cy_stc_sysint_t psoc6_bless_isr_cfg = { + .intrSrc = DT_INST_IRQN(0), + .intrPriority = DT_INST_IRQ(0, priority), +}; + +static cy_stc_ble_hw_config_t psoc6_bless_hw_config = { + .blessIsrConfig = &psoc6_bless_isr_cfg, +}; + +static const cy_stc_ble_config_t psoc6_bless_config = { + .stackParam = &psoc6_bless_stack_param, + .hw = &psoc6_bless_hw_config, +}; + +static void psoc6_bless_rx_thread(void *, void *, void *) +{ + while (true) { + k_sem_take(&psoc6_bless_rx_sem, K_MSEC(BLE_THREAD_SEM_TMOUT_MS)); + Cy_BLE_ProcessEvents(); + } +} + +static void psoc6_bless_isr_handler(const struct device *dev) +{ + if (Cy_BLE_HAL_BlessInterruptHandler()) { + k_sem_give(&psoc6_bless_rx_sem); + } +} + +static void psoc6_bless_events_handler(uint32_t eventCode, void *eventParam) +{ + cy_stc_ble_hci_tx_packet_info_t *hci_rx = NULL; + struct net_buf *buf = NULL; + size_t buf_tailroom = 0; + + if (eventCode != CY_BLE_EVT_HCI_PKT_RCVD) { + LOG_DBG("Other EVENT 0x%X", eventCode); + return; + } + + hci_rx = eventParam; + + switch (hci_rx->packetType) { + case PACKET_TYPE_HCI_EVENT: + buf = bt_buf_get_evt(hci_rx->data[0], 0, K_NO_WAIT); + if (!buf) { + LOG_ERR("Failed to allocate the buffer for RX: EVENT "); + return; + } + + break; + case PACKET_TYPE_HCI_ACL_DATA: + buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_NO_WAIT); + if (!buf) { + LOG_ERR("Failed to allocate the buffer for RX: ACL "); + return; + } + bt_buf_set_type(buf, BT_BUF_ACL_IN); + + break; + + default: + LOG_WRN("Unsupported HCI Packet Received"); + return; + } + + buf_tailroom = net_buf_tailroom(buf); + if (buf_tailroom < hci_rx->dataLength) { + LOG_WRN("Not enough space for rx data"); + return; + } + net_buf_add_mem(buf, hci_rx->data, hci_rx->dataLength); + bt_recv(buf); +} + +static int psoc6_bless_open(void) +{ + k_tid_t tid; + + tid = k_thread_create(&psoc6_bless_rx_thread_data, psoc6_bless_rx_thread_stack, + K_KERNEL_STACK_SIZEOF(psoc6_bless_rx_thread_stack), + psoc6_bless_rx_thread, NULL, NULL, NULL, + K_PRIO_COOP(CONFIG_BT_RX_PRIO), 0, K_NO_WAIT); + k_thread_name_set(tid, "psoc6_bless_rx_thread"); + + return 0; +} + +static int psoc6_bless_send(struct net_buf *buf) +{ + cy_en_ble_api_result_t result; + + memset(&hci_tx_pkt, 0, sizeof(cy_stc_ble_hci_tx_packet_info_t)); + + hci_tx_pkt.dataLength = buf->len; + hci_tx_pkt.data = buf->data; + + switch (bt_buf_get_type(buf)) { + case BT_BUF_ACL_OUT: + hci_tx_pkt.packetType = PACKET_TYPE_HCI_ACL_DATA; + break; + case BT_BUF_CMD: + hci_tx_pkt.packetType = PACKET_TYPE_HCI_COMMAND; + break; + default: + net_buf_unref(buf); + return -ENOTSUP; + } + + if (k_sem_take(&psoc6_bless_operation_sem, K_MSEC(BLE_LOCK_TMOUT_MS)) != 0) { + LOG_ERR("Failed to acquire BLE DRV Semaphore"); + net_buf_unref(buf); + return -EIO; + } + + result = Cy_BLE_SoftHciSendAppPkt(&hci_tx_pkt); + if (result != CY_BLE_SUCCESS) { + LOG_ERR("Error in sending packet reason %d\r\n", result); + } + + k_sem_give(&psoc6_bless_operation_sem); + + net_buf_unref(buf); + + return 0; +} + +static int psoc6_bless_setup(void) +{ + struct net_buf *buf; + int err; + uint8_t *addr = (uint8_t *)&SFLASH_BLE_DEVICE_ADDRESS[0]; + uint8_t hci_data[] = { + addr[5], addr[4], addr[3], addr[2], addr[1], addr[0], BT_ADDR_LE_PUBLIC, + }; + + buf = bt_hci_cmd_create(PSOC6_BLESS_OP_SET_PUBLIC_ADDR, sizeof(hci_data)); + if (buf == NULL) { + LOG_ERR("Unable to allocate command buffer"); + return -ENOMEM; + } + + /* Add data part of packet */ + net_buf_add_mem(buf, hci_data, sizeof(hci_data)); + + err = bt_hci_cmd_send_sync(PSOC6_BLESS_OP_SET_PUBLIC_ADDR, buf, NULL); + if (err) { + return err; + } + + return 0; +} + +static int psoc6_bless_hci_init(void) +{ + cy_en_ble_api_result_t result; + static const struct bt_hci_driver drv = { + .name = "PSoC 6 BLESS", + .bus = BT_HCI_DRIVER_BUS_VIRTUAL, + .quirks = BT_QUIRK_NO_RESET, + .open = psoc6_bless_open, + .send = psoc6_bless_send, + .setup = psoc6_bless_setup, + }; + + /* Connect BLE interrupt to ISR */ + IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), psoc6_bless_isr_handler, 0, 0); + + /* Registers the generic callback functions. */ + Cy_BLE_RegisterEventCallback(psoc6_bless_events_handler); + + /* Initializes the PSoC 6 BLESS Controller. */ + result = Cy_BLE_InitController(&psoc6_bless_config); + if (result != CY_BLE_SUCCESS) { + LOG_ERR("Failed to init the BLE Controller"); + return -EIO; + } + + /* Enables the BLESS controller in HCI only mode. */ + result = Cy_BLE_EnableHCIModeController(); + if (result != CY_BLE_SUCCESS) { + LOG_ERR("Failed to enable the BLE Controller in hci mode"); + return -EIO; + } + + /* Enables BLE Low-power mode (LPM)*/ + Cy_BLE_EnableLowPowerMode(); + + /* Register a BLESS HCI driver to the Bluetooth stack. */ + bt_hci_driver_register(&drv); + + return 0; +} + +SYS_INIT(psoc6_bless_hci_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); diff --git a/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi b/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi index ccf2045b50..c33599c0e5 100644 --- a/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi +++ b/dts/arm/infineon/psoc6/psoc6_01/psoc6_01.dtsi @@ -314,5 +314,11 @@ interrupts = <22 6>; status = "disabled"; }; + + bluetooth: bless { + compatible = "infineon,cat1-bless-hci"; + interrupts = <24 1>; + status = "disabled"; + }; }; }; diff --git a/dts/bindings/bluetooth/infineon,cat1-bless-hci.yaml b/dts/bindings/bluetooth/infineon,cat1-bless-hci.yaml new file mode 100644 index 0000000000..0d38855c00 --- /dev/null +++ b/dts/bindings/bluetooth/infineon,cat1-bless-hci.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +description: | + Bluetooth module that uses Infineon's Host Controller Interface + +compatible: "infineon,cat1-bless-hci" + +include: base.yaml + +properties: + interrupts: + required: true diff --git a/modules/hal_infineon/CMakeLists.txt b/modules/hal_infineon/CMakeLists.txt index 523ab72e94..a8ca61ff4e 100644 --- a/modules/hal_infineon/CMakeLists.txt +++ b/modules/hal_infineon/CMakeLists.txt @@ -37,3 +37,7 @@ endif() if (CONFIG_BT_CYW43XXX) add_subdirectory(btstack-integration) endif() + +if (CONFIG_BT_PSOC6_BLESS) +add_subdirectory(bless) +endif() diff --git a/modules/hal_infineon/bless/CMakeLists.txt b/modules/hal_infineon/bless/CMakeLists.txt new file mode 100644 index 0000000000..7dfc69bdc0 --- /dev/null +++ b/modules/hal_infineon/bless/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (c) 2022 Cypress Semiconductor Corporation. +# +# SPDX-License-Identifier: Apache-2.0 + +set(bless_dir ${ZEPHYR_HAL_INFINEON_MODULE_DIR}/bless) +set(bless_blobs_dir ${ZEPHYR_HAL_INFINEON_MODULE_DIR}/zephyr/blobs/img/bluetooth/firmware) + +zephyr_include_directories(${bless_dir}/include) + +zephyr_compile_definitions(COMPONENT_BLESS_CONTROLLER) + +zephyr_library_sources(${bless_dir}/cy_ble.c) +zephyr_library_sources(${bless_dir}/cy_ble_clk.c) +zephyr_library_sources(${bless_dir}/cy_ble_common.c) +zephyr_library_sources(${bless_dir}/cy_ble_controller.c) +zephyr_library_sources(${bless_dir}/cy_ble_event_handler.c) +zephyr_library_sources(${bless_dir}/cy_ble_hal_int.c) +zephyr_library_sources(${bless_dir}/cy_ble_hal_pvt.c) + +zephyr_link_libraries( + ${bless_blobs_dir}/COMPONENT_BLESS_CONTROLLER/cy_ble_stack_controller.a + ${bless_blobs_dir}/COMPONENT_BLESS_CONTROLLER/cy_ble_stack_manager.a +) diff --git a/soc/arm/infineon_cat1/psoc6/CMakeLists.txt b/soc/arm/infineon_cat1/psoc6/CMakeLists.txt index 2279c35b2d..e047fc704b 100644 --- a/soc/arm/infineon_cat1/psoc6/CMakeLists.txt +++ b/soc/arm/infineon_cat1/psoc6/CMakeLists.txt @@ -15,3 +15,5 @@ zephyr_linker_sources_ifdef(CONFIG_SOC_FAMILY_INFINEON_CAT1A ROM_START SORT_KEY zephyr_linker_sources_ifdef(CONFIG_SOC_FAMILY_INFINEON_CAT1A RAM_SECTIONS SORT_KEY 0 ram_cm0image.ld) zephyr_linker_sources_ifdef(CONFIG_SOC_FAMILY_INFINEON_CAT1A RAMFUNC_SECTION SORT_KEY 0 ram_func.ld) + +zephyr_linker_sources_ifdef(CONFIG_SOC_FAMILY_INFINEON_CAT1 RODATA SORT_KEY 0 rom.ld) diff --git a/soc/arm/infineon_cat1/psoc6/rom.ld b/soc/arm/infineon_cat1/psoc6/rom.ld new file mode 100644 index 0000000000..ab667b38ec --- /dev/null +++ b/soc/arm/infineon_cat1/psoc6/rom.ld @@ -0,0 +1,19 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +__cy_ble_1_start = .; +KEEP(*(i.*)) +__cy_ble_1_end = .; + +__arm_vfe_header_start = .; +KEEP(*(.arm_vfe_header)) +__arm_vfe_header_end = .; + +__constdata_start = .; +KEEP(*(.constdata)) +__constdata_end = .; + +__conststring_start = .; +KEEP(*(.conststring)) +__conststring_end = .; diff --git a/west.yml b/west.yml index 9e7de8d341..c1432255da 100644 --- a/west.yml +++ b/west.yml @@ -80,7 +80,7 @@ manifest: groups: - hal - name: hal_infineon - revision: 03d6f5563552022fb53f149640b127889fb3c01f + revision: 0bebc14d8bd1a249ee7fbc70b37db6f01f72544f path: modules/hal/infineon groups: - hal