drivers: hci: Update NXP HCI driver

Add updates to support MCXW71
Add support if RX data are received in ISR context
Add support to set BT address using Vendor command

Signed-off-by: Yassine El Aissaoui <yassine.elaissaoui@nxp.com>
This commit is contained in:
Yassine El Aissaoui 2024-09-24 15:03:40 +02:00 committed by Carles Cufí
commit 89709ee382
4 changed files with 229 additions and 68 deletions

View file

@ -256,6 +256,7 @@ config BT_DRV_RX_STACK_SIZE
default 640 if (BT_SPI || BT_AMBIQ_HCI) default 640 if (BT_SPI || BT_AMBIQ_HCI)
default BT_RX_STACK_SIZE if (BT_H4 || BT_HCI_RAW_H4) default BT_RX_STACK_SIZE if (BT_H4 || BT_HCI_RAW_H4)
default BT_STM32_IPM_RX_STACK_SIZE if BT_STM32_IPM default BT_STM32_IPM_RX_STACK_SIZE if BT_STM32_IPM
default HCI_NXP_RX_STACK_SIZE if HCI_NXP_RX_THREAD
default 256 default 256
help help
Stack size for the HCI driver's RX thread. Stack size for the HCI driver's RX thread.

View file

@ -23,6 +23,29 @@ config HCI_NXP_SET_CAL_DATA_ANNEX100
If enabled, the Host will send calibration data annex 100 to the BLE Controller during HCI If enabled, the Host will send calibration data annex 100 to the BLE Controller during HCI
init. init.
config HCI_NXP_RX_THREAD
bool "Process RX buffers in a dedicated thread"
help
Some platforms receive the HCI RX buffers in ISR context.
If enabled, the HCI RX message is queued by the ISR, and the message is processed
in a dedicated thread.
if HCI_NXP_RX_THREAD
config HCI_NXP_RX_STACK_SIZE
int "HCI RX stack size"
default 512
config HCI_NXP_RX_MSG_QUEUE_SIZE
int "HCI RX message queue size"
default 4
config HEAP_MEM_POOL_ADD_SIZE_BT_NXP_RX_THREAD
int
default 768
endif
if BT_NXP if BT_NXP
config BT_DIS_MANUF config BT_DIS_MANUF
@ -34,7 +57,8 @@ config BT_HCI_ACL_FLOW_CONTROL
config BT_BUF_EVT_DISCARDABLE_SIZE config BT_BUF_EVT_DISCARDABLE_SIZE
default 84 default 84
config HEAP_MEM_POOL_SIZE config HEAP_MEM_POOL_ADD_SIZE_BT_NXP
int
default 256 default 256
config FLASH config FLASH

View file

@ -1,5 +1,5 @@
/* /*
* Copyright 2023 NXP * Copyright 2023-2024 NXP
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -30,14 +30,21 @@ struct bt_nxp_data {
bt_hci_recv_t recv; bt_hci_recv_t recv;
}; };
struct hci_data {
uint8_t packetType;
uint8_t *data;
uint16_t len;
};
#define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL #define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL
LOG_MODULE_REGISTER(bt_driver); LOG_MODULE_REGISTER(bt_driver);
#define HCI_IRQ_N DT_INST_IRQ_BY_NAME(0, hci_int, irq) #define HCI_IRQ_N DT_INST_IRQ_BY_NAME(0, hci_int, irq)
#define HCI_IRQ_P DT_INST_IRQ_BY_NAME(0, hci_int, priority) #define HCI_IRQ_P DT_INST_IRQ_BY_NAME(0, hci_int, priority)
#if DT_INST_IRQ_HAS_NAME(0, wakeup_int)
#define HCI_WAKEUP_IRQ_N DT_INST_IRQ_BY_NAME(0, wakeup_int, irq) #define HCI_WAKEUP_IRQ_N DT_INST_IRQ_BY_NAME(0, wakeup_int, irq)
#define HCI_WAKEUP_IRQ_P DT_INST_IRQ_BY_NAME(0, wakeup_int, priority) #define HCI_WAKEUP_IRQ_P DT_INST_IRQ_BY_NAME(0, wakeup_int, priority)
#endif
/* Vendor specific commands */ /* Vendor specific commands */
#define HCI_CMD_STORE_BT_CAL_DATA_OCF 0x61U #define HCI_CMD_STORE_BT_CAL_DATA_OCF 0x61U
#define HCI_CMD_STORE_BT_CAL_DATA_PARAM_LENGTH 32U #define HCI_CMD_STORE_BT_CAL_DATA_PARAM_LENGTH 32U
@ -47,7 +54,29 @@ LOG_MODULE_REGISTER(bt_driver);
#define HCI_CMD_SET_BT_SLEEP_MODE_PARAM_LENGTH 3U #define HCI_CMD_SET_BT_SLEEP_MODE_PARAM_LENGTH 3U
#define HCI_CMD_BT_HOST_SLEEP_CONFIG_OCF 0x59U #define HCI_CMD_BT_HOST_SLEEP_CONFIG_OCF 0x59U
#define HCI_CMD_BT_HOST_SLEEP_CONFIG_PARAM_LENGTH 2U #define HCI_CMD_BT_HOST_SLEEP_CONFIG_PARAM_LENGTH 2U
#define HCI_CMD_BT_HOST_SET_MAC_ADDR_PARAM_LENGTH 8U
#define HCI_SET_MAC_ADDR_CMD 0x0022U
#define BT_USER_BD 254
#define BD_ADDR_OUI 0x37U, 0x60U, 0x00U
#define BD_ADDR_OUI_PART_SIZE 3U
#define BD_ADDR_UUID_PART_SIZE 3U
#if !defined(CONFIG_HCI_NXP_SET_CAL_DATA)
#define bt_nxp_set_calibration_data() 0
#endif
#if !defined(CONFIG_HCI_NXP_SET_CAL_DATA_ANNEX100)
#define bt_nxp_set_calibration_data_annex100() 0
#endif
#if !defined(CONFIG_HCI_NXP_ENABLE_AUTO_SLEEP)
#define nxp_bt_set_host_sleep_config() 0
#define nxp_bt_enable_controller_autosleep() 0
#endif
#if !defined(CONFIG_BT_HCI_SET_PUBLIC_ADDR)
#define bt_nxp_set_mac_address(public_addr) 0
#endif
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* Public prototypes */ /* Public prototypes */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
@ -59,31 +88,31 @@ extern int32_t ble_wakeup_done_handler(void);
/* Private functions */ /* Private functions */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
#if CONFIG_HCI_NXP_ENABLE_AUTO_SLEEP || CONFIG_HCI_NXP_SET_CAL_DATA #if defined(CONFIG_HCI_NXP_ENABLE_AUTO_SLEEP) || defined(CONFIG_HCI_NXP_SET_CAL_DATA)
static int nxp_bt_send_vs_command(uint16_t opcode, const uint8_t *params, uint8_t params_len) static int nxp_bt_send_vs_command(uint16_t opcode, const uint8_t *params, uint8_t params_len)
{ {
#if CONFIG_BT_HCI_HOST if (IS_ENABLED(CONFIG_BT_HCI_HOST)) {
struct net_buf *buf; struct net_buf *buf;
/* Allocate buffer for the hci command */ /* Allocate buffer for the hci command */
buf = bt_hci_cmd_create(opcode, params_len); buf = bt_hci_cmd_create(opcode, params_len);
if (buf == NULL) { if (buf == NULL) {
LOG_ERR("Unable to allocate command buffer"); LOG_ERR("Unable to allocate command buffer");
return -ENOMEM; return -ENOMEM;
}
/* Add data part of packet */
net_buf_add_mem(buf, params, params_len);
/* Send the command */
return bt_hci_cmd_send_sync(opcode, buf, NULL);
} else {
return 0;
} }
/* Add data part of packet */
net_buf_add_mem(buf, params, params_len);
/* Send the command */
return bt_hci_cmd_send_sync(opcode, buf, NULL);
#else
return 0;
#endif
} }
#endif /* CONFIG_HCI_NXP_ENABLE_AUTO_SLEEP || CONFIG_HCI_NXP_SET_CAL_DATA */ #endif /* CONFIG_HCI_NXP_ENABLE_AUTO_SLEEP || CONFIG_HCI_NXP_SET_CAL_DATA */
#if CONFIG_HCI_NXP_ENABLE_AUTO_SLEEP #if defined(CONFIG_HCI_NXP_ENABLE_AUTO_SLEEP)
static int nxp_bt_enable_controller_autosleep(void) static int nxp_bt_enable_controller_autosleep(void)
{ {
uint16_t opcode = BT_OP(BT_OGF_VS, HCI_CMD_SET_BT_SLEEP_MODE_OCF); uint16_t opcode = BT_OP(BT_OGF_VS, HCI_CMD_SET_BT_SLEEP_MODE_OCF);
@ -110,7 +139,7 @@ static int nxp_bt_set_host_sleep_config(void)
} }
#endif /* CONFIG_HCI_NXP_ENABLE_AUTO_SLEEP */ #endif /* CONFIG_HCI_NXP_ENABLE_AUTO_SLEEP */
#if CONFIG_HCI_NXP_SET_CAL_DATA #if defined(CONFIG_HCI_NXP_SET_CAL_DATA)
static int bt_nxp_set_calibration_data(void) static int bt_nxp_set_calibration_data(void)
{ {
uint16_t opcode = BT_OP(BT_OGF_VS, HCI_CMD_STORE_BT_CAL_DATA_OCF); uint16_t opcode = BT_OP(BT_OGF_VS, HCI_CMD_STORE_BT_CAL_DATA_OCF);
@ -121,7 +150,7 @@ static int bt_nxp_set_calibration_data(void)
HCI_CMD_STORE_BT_CAL_DATA_PARAM_LENGTH); HCI_CMD_STORE_BT_CAL_DATA_PARAM_LENGTH);
} }
#if CONFIG_HCI_NXP_SET_CAL_DATA_ANNEX100 #if defined(CONFIG_HCI_NXP_SET_CAL_DATA_ANNEX100)
static int bt_nxp_set_calibration_data_annex100(void) static int bt_nxp_set_calibration_data_annex100(void)
{ {
uint16_t opcode = BT_OP(BT_OGF_VS, HCI_CMD_STORE_BT_CAL_DATA_ANNEX100_OCF); uint16_t opcode = BT_OP(BT_OGF_VS, HCI_CMD_STORE_BT_CAL_DATA_ANNEX100_OCF);
@ -137,6 +166,54 @@ static int bt_nxp_set_calibration_data_annex100(void)
#endif /* CONFIG_HCI_NXP_SET_CAL_DATA */ #endif /* CONFIG_HCI_NXP_SET_CAL_DATA */
#if defined(CONFIG_BT_HCI_SET_PUBLIC_ADDR)
/* Currently, we cannot use nxp_bt_send_vs_command because the controller
* fails to send the command complete event expected by Zephyr Host stack.
* To workaround it, we directly send the message using our PLATFORM API.
* This will be reworked once it is fixed on the controller side.
*/
static int bt_nxp_set_mac_address(const bt_addr_t *public_addr)
{
uint8_t bleDeviceAddress[BT_ADDR_SIZE] = {0};
uint16_t opcode = BT_OP(BT_OGF_VS, HCI_SET_MAC_ADDR_CMD);
uint8_t addrOUI[BD_ADDR_OUI_PART_SIZE] = {BD_ADDR_OUI};
uint8_t uid[16] = {0};
uint8_t uuidLen;
uint8_t hciBuffer[12];
/* If no public address is provided by the user, use a unique address made
* from the device's UID (unique ID)
*/
if (bt_addr_eq(public_addr, BT_ADDR_ANY) || bt_addr_eq(public_addr, BT_ADDR_NONE)) {
PLATFORM_GetMCUUid(uid, &uuidLen);
/* Set 3 LSB of MAC address from UUID */
if (uuidLen > BD_ADDR_UUID_PART_SIZE) {
memcpy((void *)bleDeviceAddress,
(void *)(uid + uuidLen - (BD_ADDR_UUID_PART_SIZE + 1)),
BD_ADDR_UUID_PART_SIZE);
}
/* Set 3 MSB of MAC address from OUI */
memcpy((void *)(bleDeviceAddress + BD_ADDR_UUID_PART_SIZE), (void *)addrOUI,
BD_ADDR_OUI_PART_SIZE);
} else {
bt_addr_copy((bt_addr_t *)bleDeviceAddress, public_addr);
}
hciBuffer[0] = BT_HCI_H4_CMD;
memcpy((void *)&hciBuffer[1], (const void *)&opcode, 2U);
/* Set HCI parameter length */
hciBuffer[3] = HCI_CMD_BT_HOST_SET_MAC_ADDR_PARAM_LENGTH;
/* Set command parameter ID */
hciBuffer[4] = BT_USER_BD;
/* Set command parameter length */
hciBuffer[5] = (uint8_t)6U;
memcpy(hciBuffer + 6U, (const void *)bleDeviceAddress,
BD_ADDR_UUID_PART_SIZE + BD_ADDR_OUI_PART_SIZE);
/* Send the command */
return PLATFORM_SendHciMessage(hciBuffer, 12U);
}
#endif /* CONFIG_BT_HCI_SET_PUBLIC_ADDR */
static bool is_hci_event_discardable(const uint8_t *evt_data) static bool is_hci_event_discardable(const uint8_t *evt_data)
{ {
bool ret = false; bool ret = false;
@ -246,7 +323,7 @@ static struct net_buf *bt_acl_recv(uint8_t *data, size_t len)
return buf; return buf;
} }
static void hci_rx_cb(uint8_t packetType, uint8_t *data, uint16_t len) static void process_rx(uint8_t packetType, uint8_t *data, uint16_t len)
{ {
const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0)); const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0));
struct bt_nxp_data *hci = dev->data; struct bt_nxp_data *hci = dev->data;
@ -272,6 +349,58 @@ static void hci_rx_cb(uint8_t packetType, uint8_t *data, uint16_t len)
} }
} }
#if defined(CONFIG_HCI_NXP_RX_THREAD)
K_MSGQ_DEFINE(rx_msgq, sizeof(struct hci_data), CONFIG_HCI_NXP_RX_MSG_QUEUE_SIZE, 4);
static void bt_rx_thread(void *p1, void *p2, void *p3)
{
ARG_UNUSED(p1);
ARG_UNUSED(p2);
ARG_UNUSED(p3);
struct hci_data hci_rx_frame;
while (true) {
if (k_msgq_get(&rx_msgq, &hci_rx_frame, K_FOREVER) < 0) {
LOG_ERR("Failed to get RX data from message queue");
continue;
}
process_rx(hci_rx_frame.packetType, hci_rx_frame.data, hci_rx_frame.len);
k_free(hci_rx_frame.data);
}
}
K_THREAD_DEFINE(nxp_hci_rx_thread, CONFIG_BT_DRV_RX_STACK_SIZE, bt_rx_thread, NULL, NULL, NULL,
K_PRIO_COOP(CONFIG_BT_DRIVER_RX_HIGH_PRIO), 0, 0);
static void hci_rx_cb(uint8_t packetType, uint8_t *data, uint16_t len)
{
struct hci_data hci_rx_frame;
hci_rx_frame.packetType = packetType;
hci_rx_frame.data = k_malloc(len);
if (!hci_rx_frame.data) {
LOG_ERR("Failed to allocate RX buffer");
}
memcpy(hci_rx_frame.data, data, len);
hci_rx_frame.len = len;
if (k_msgq_put(&rx_msgq, &hci_rx_frame, K_NO_WAIT) < 0) {
LOG_ERR("Failed to push RX data to message queue");
}
}
#else /* CONFIG_HCI_NXP_RX_THREAD */
static void hci_rx_cb(uint8_t packetType, uint8_t *data, uint16_t len)
{
process_rx(packetType, data, len);
}
#endif /* CONFIG_HCI_NXP_RX_THREAD */
static int bt_nxp_send(const struct device *dev, struct net_buf *buf) static int bt_nxp_send(const struct device *dev, struct net_buf *buf)
{ {
uint8_t packetType; uint8_t packetType;
@ -331,44 +460,51 @@ static int bt_nxp_open(const struct device *dev, bt_hci_recv_t recv)
int bt_nxp_setup(const struct device *dev, const struct bt_hci_setup_params *params) int bt_nxp_setup(const struct device *dev, const struct bt_hci_setup_params *params)
{ {
ARG_UNUSED(dev); ARG_UNUSED(dev);
ARG_UNUSED(params);
int ret; int ret = 0;
do { do {
#if CONFIG_HCI_NXP_SET_CAL_DATA if (IS_ENABLED(CONFIG_HCI_NXP_SET_CAL_DATA)) {
ret = bt_nxp_set_calibration_data(); ret = bt_nxp_set_calibration_data();
if (ret < 0) { if (ret < 0) {
LOG_ERR("Failed to set calibration data"); LOG_ERR("Failed to set calibration data");
break; break;
} }
#if CONFIG_HCI_NXP_SET_CAL_DATA_ANNEX100 if (IS_ENABLED(CONFIG_HCI_NXP_SET_CAL_DATA_ANNEX100)) {
/* After send annex55 to CPU2, CPU2 need reset, /* After send annex55 to CPU2, CPU2 need reset,
* a delay of at least 20ms is required to continue sending annex100 * a delay of at least 20ms is required to continue sending annex100
*/ */
k_sleep(Z_TIMEOUT_MS(20)); k_sleep(Z_TIMEOUT_MS(20));
ret = bt_nxp_set_calibration_data_annex100(); ret = bt_nxp_set_calibration_data_annex100();
if (ret < 0) { if (ret < 0) {
LOG_ERR("Failed to set calibration data"); LOG_ERR("Failed to set calibration data");
break; break;
} }
#endif /* CONFIG_HCI_NXP_SET_CAL_DATA_ANNEX100 */ }
#endif /* CONFIG_HCI_NXP_SET_CAL_DATA */
#if CONFIG_HCI_NXP_ENABLE_AUTO_SLEEP
ret = nxp_bt_set_host_sleep_config();
if (ret < 0) {
LOG_ERR("Failed to set host sleep config");
break;
} }
ret = nxp_bt_enable_controller_autosleep(); if (IS_ENABLED(CONFIG_HCI_NXP_ENABLE_AUTO_SLEEP)) {
if (ret < 0) { ret = nxp_bt_set_host_sleep_config();
LOG_ERR("Failed to configure controller autosleep"); if (ret < 0) {
break; LOG_ERR("Failed to set host sleep config");
break;
}
ret = nxp_bt_enable_controller_autosleep();
if (ret < 0) {
LOG_ERR("Failed to configure controller autosleep");
break;
}
}
if (IS_ENABLED(CONFIG_BT_HCI_SET_PUBLIC_ADDR)) {
ret = bt_nxp_set_mac_address(&(params->public_addr));
if (ret < 0) {
LOG_ERR("Failed to set MAC address");
break;
}
} }
#endif /* CONFIG_HCI_NXP_ENABLE_AUTO_SLEEP */
} while (false); } while (false);
return ret; return ret;
@ -379,18 +515,18 @@ static int bt_nxp_close(const struct device *dev)
struct bt_nxp_data *hci = dev->data; struct bt_nxp_data *hci = dev->data;
int ret = 0; int ret = 0;
/* Reset the Controller */ /* Reset the Controller */
#if CONFIG_BT_HCI_HOST if (IS_ENABLED(CONFIG_BT_HCI_HOST)) {
ret = bt_hci_cmd_send_sync(BT_HCI_OP_RESET, NULL, NULL); ret = bt_hci_cmd_send_sync(BT_HCI_OP_RESET, NULL, NULL);
if (ret) { if (ret) {
LOG_ERR("Failed to reset BLE controller"); LOG_ERR("Failed to reset BLE controller");
} }
k_sleep(K_SECONDS(1)); k_sleep(K_SECONDS(1));
ret = PLATFORM_TerminateBle(); ret = PLATFORM_TerminateBle();
if (ret < 0) { if (ret < 0) {
LOG_ERR("Failed to shutdown BLE controller"); LOG_ERR("Failed to shutdown BLE controller");
}
} }
#endif
hci->recv = NULL; hci->recv = NULL;
return ret; return ret;
@ -413,11 +549,11 @@ static int bt_nxp_init(const struct device *dev)
/* HCI Interrupt */ /* HCI Interrupt */
IRQ_CONNECT(HCI_IRQ_N, HCI_IRQ_P, ble_hci_handler, 0, 0); IRQ_CONNECT(HCI_IRQ_N, HCI_IRQ_P, ble_hci_handler, 0, 0);
irq_enable(HCI_IRQ_N); irq_enable(HCI_IRQ_N);
#if DT_INST_IRQ_HAS_NAME(0, wakeup_int)
/* Wake up done interrupt */ /* Wake up done interrupt */
IRQ_CONNECT(HCI_WAKEUP_IRQ_N, HCI_WAKEUP_IRQ_P, ble_wakeup_done_handler, 0, 0); IRQ_CONNECT(HCI_WAKEUP_IRQ_N, HCI_WAKEUP_IRQ_P, ble_wakeup_done_handler, 0, 0);
irq_enable(HCI_WAKEUP_IRQ_N); irq_enable(HCI_WAKEUP_IRQ_N);
#endif
#if (DT_INST_PROP(0, wakeup_source)) && CONFIG_PM #if (DT_INST_PROP(0, wakeup_source)) && CONFIG_PM
EnableDeepSleepIRQ(HCI_IRQ_N); EnableDeepSleepIRQ(HCI_IRQ_N);
#endif #endif

View file

@ -198,7 +198,7 @@ manifest:
groups: groups:
- hal - hal
- name: hal_nxp - name: hal_nxp
revision: 9702923eeb6f4a9ca063ca3b200324b118d3e843 revision: c42b8ee2912d1b9f7c6ae1a989232a790db0f79d
path: modules/hal/nxp path: modules/hal/nxp
groups: groups:
- hal - hal