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í
parent 9eedb6d7c8
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 BT_RX_STACK_SIZE if (BT_H4 || BT_HCI_RAW_H4)
default BT_STM32_IPM_RX_STACK_SIZE if BT_STM32_IPM
default HCI_NXP_RX_STACK_SIZE if HCI_NXP_RX_THREAD
default 256
help
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
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
config BT_DIS_MANUF
@ -34,7 +57,8 @@ config BT_HCI_ACL_FLOW_CONTROL
config BT_BUF_EVT_DISCARDABLE_SIZE
default 84
config HEAP_MEM_POOL_SIZE
config HEAP_MEM_POOL_ADD_SIZE_BT_NXP
int
default 256
config FLASH

View File

@ -1,5 +1,5 @@
/*
* Copyright 2023 NXP
* Copyright 2023-2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -30,14 +30,21 @@ struct bt_nxp_data {
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
LOG_MODULE_REGISTER(bt_driver);
#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)
#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_P DT_INST_IRQ_BY_NAME(0, wakeup_int, priority)
#endif
/* Vendor specific commands */
#define HCI_CMD_STORE_BT_CAL_DATA_OCF 0x61U
#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_BT_HOST_SLEEP_CONFIG_OCF 0x59U
#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 */
/* -------------------------------------------------------------------------- */
@ -59,31 +88,31 @@ extern int32_t ble_wakeup_done_handler(void);
/* 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)
{
#if CONFIG_BT_HCI_HOST
struct net_buf *buf;
if (IS_ENABLED(CONFIG_BT_HCI_HOST)) {
struct net_buf *buf;
/* Allocate buffer for the hci command */
buf = bt_hci_cmd_create(opcode, params_len);
if (buf == NULL) {
LOG_ERR("Unable to allocate command buffer");
return -ENOMEM;
/* Allocate buffer for the hci command */
buf = bt_hci_cmd_create(opcode, params_len);
if (buf == NULL) {
LOG_ERR("Unable to allocate command buffer");
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 */
#if CONFIG_HCI_NXP_ENABLE_AUTO_SLEEP
#if defined(CONFIG_HCI_NXP_ENABLE_AUTO_SLEEP)
static int nxp_bt_enable_controller_autosleep(void)
{
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 */
#if CONFIG_HCI_NXP_SET_CAL_DATA
#if defined(CONFIG_HCI_NXP_SET_CAL_DATA)
static int bt_nxp_set_calibration_data(void)
{
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);
}
#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)
{
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 */
#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)
{
bool ret = false;
@ -246,7 +323,7 @@ static struct net_buf *bt_acl_recv(uint8_t *data, size_t len)
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));
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)
{
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)
{
ARG_UNUSED(dev);
ARG_UNUSED(params);
int ret;
int ret = 0;
do {
#if CONFIG_HCI_NXP_SET_CAL_DATA
ret = bt_nxp_set_calibration_data();
if (ret < 0) {
LOG_ERR("Failed to set calibration data");
break;
}
#if CONFIG_HCI_NXP_SET_CAL_DATA_ANNEX100
/* After send annex55 to CPU2, CPU2 need reset,
* a delay of at least 20ms is required to continue sending annex100
*/
k_sleep(Z_TIMEOUT_MS(20));
if (IS_ENABLED(CONFIG_HCI_NXP_SET_CAL_DATA)) {
ret = bt_nxp_set_calibration_data();
if (ret < 0) {
LOG_ERR("Failed to set calibration data");
break;
}
if (IS_ENABLED(CONFIG_HCI_NXP_SET_CAL_DATA_ANNEX100)) {
/* After send annex55 to CPU2, CPU2 need reset,
* a delay of at least 20ms is required to continue sending annex100
*/
k_sleep(Z_TIMEOUT_MS(20));
ret = bt_nxp_set_calibration_data_annex100();
if (ret < 0) {
LOG_ERR("Failed to set calibration data");
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 = bt_nxp_set_calibration_data_annex100();
if (ret < 0) {
LOG_ERR("Failed to set calibration data");
break;
}
}
}
ret = nxp_bt_enable_controller_autosleep();
if (ret < 0) {
LOG_ERR("Failed to configure controller autosleep");
break;
if (IS_ENABLED(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 (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);
return ret;
@ -379,18 +515,18 @@ static int bt_nxp_close(const struct device *dev)
struct bt_nxp_data *hci = dev->data;
int ret = 0;
/* Reset the Controller */
#if CONFIG_BT_HCI_HOST
ret = bt_hci_cmd_send_sync(BT_HCI_OP_RESET, NULL, NULL);
if (ret) {
LOG_ERR("Failed to reset BLE controller");
}
k_sleep(K_SECONDS(1));
if (IS_ENABLED(CONFIG_BT_HCI_HOST)) {
ret = bt_hci_cmd_send_sync(BT_HCI_OP_RESET, NULL, NULL);
if (ret) {
LOG_ERR("Failed to reset BLE controller");
}
k_sleep(K_SECONDS(1));
ret = PLATFORM_TerminateBle();
if (ret < 0) {
LOG_ERR("Failed to shutdown BLE controller");
ret = PLATFORM_TerminateBle();
if (ret < 0) {
LOG_ERR("Failed to shutdown BLE controller");
}
}
#endif
hci->recv = NULL;
return ret;
@ -413,11 +549,11 @@ static int bt_nxp_init(const struct device *dev)
/* HCI Interrupt */
IRQ_CONNECT(HCI_IRQ_N, HCI_IRQ_P, ble_hci_handler, 0, 0);
irq_enable(HCI_IRQ_N);
#if DT_INST_IRQ_HAS_NAME(0, wakeup_int)
/* Wake up done interrupt */
IRQ_CONNECT(HCI_WAKEUP_IRQ_N, HCI_WAKEUP_IRQ_P, ble_wakeup_done_handler, 0, 0);
irq_enable(HCI_WAKEUP_IRQ_N);
#endif
#if (DT_INST_PROP(0, wakeup_source)) && CONFIG_PM
EnableDeepSleepIRQ(HCI_IRQ_N);
#endif

View File

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