zephyr/drivers/bluetooth/hci/hci_ambiq.c
Aaron Ye 3f56baa295 drivers: bluetooth: hci: add retry mechanism for Apollo SPI busy scenario
The controller may be unavailable to receive packets because it is busy
on processing something or have packets to send to host. Need to free the
SPI bus and wait some moment to try again.

Signed-off-by: Aaron Ye <aye@ambiq.com>
2024-05-27 03:27:43 -07:00

419 lines
9.4 KiB
C

/*
* Copyright (c) 2023 Ambiq Micro Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief Ambiq SPI based Bluetooth HCI driver.
*/
#define DT_DRV_COMPAT ambiq_bt_hci_spi
#include <zephyr/init.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/drivers/bluetooth/hci_driver.h>
#include <zephyr/bluetooth/hci.h>
#define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(bt_hci_driver);
#include "apollox_blue.h"
#define HCI_SPI_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(ambiq_bt_hci_spi)
#define SPI_DEV_NODE DT_BUS(HCI_SPI_NODE)
/* Offset of special item */
#define PACKET_TYPE 0
#define PACKET_TYPE_SIZE 1
#define EVT_HEADER_TYPE 0
#define EVT_CMD_COMP_OP_LSB 3
#define EVT_CMD_COMP_OP_MSB 4
#define EVT_CMD_COMP_DATA 5
#define EVT_OK 0
#define EVT_DISCARD 1
#define EVT_NOP 2
#define BT_FEAT_SET_BIT(feat, octet, bit) (feat[octet] |= BIT(bit))
#define BT_FEAT_SET_NO_BREDR(feat) BT_FEAT_SET_BIT(feat, 4, 5)
#define BT_FEAT_SET_LE(feat) BT_FEAT_SET_BIT(feat, 4, 6)
/* Max SPI buffer length for transceive operations.
* The maximum TX packet number is 512 bytes data + 12 bytes header.
* The maximum RX packet number is 255 bytes data + 3 header.
*/
#define SPI_MAX_TX_MSG_LEN 524
#define SPI_MAX_RX_MSG_LEN 258
/* The controller may be unavailable to receive packets because it is busy
* on processing something or have packets to send to host. Need to free the
* SPI bus and wait some moment to try again.
*/
#define SPI_BUSY_WAIT_INTERVAL_MS 25
#define SPI_BUSY_TX_ATTEMPTS 200
static uint8_t __noinit rxmsg[SPI_MAX_RX_MSG_LEN];
static const struct device *spi_dev = DEVICE_DT_GET(SPI_DEV_NODE);
static struct spi_config spi_cfg = {
.operation = SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_MODE_CPOL | SPI_MODE_CPHA |
SPI_WORD_SET(8),
};
static K_KERNEL_STACK_DEFINE(spi_rx_stack, CONFIG_BT_DRV_RX_STACK_SIZE);
static struct k_thread spi_rx_thread_data;
static struct spi_buf spi_tx_buf;
static struct spi_buf spi_rx_buf;
static const struct spi_buf_set spi_tx = {.buffers = &spi_tx_buf, .count = 1};
static const struct spi_buf_set spi_rx = {.buffers = &spi_rx_buf, .count = 1};
static K_SEM_DEFINE(sem_irq, 0, 1);
static K_SEM_DEFINE(sem_spi_available, 1, 1);
void bt_packet_irq_isr(const struct device *unused1, struct gpio_callback *unused2,
uint32_t unused3)
{
bt_apollo_rcv_isr_preprocess();
k_sem_give(&sem_irq);
}
static inline int bt_spi_transceive(void *tx, uint32_t tx_len, void *rx, uint32_t rx_len)
{
spi_tx_buf.buf = tx;
spi_tx_buf.len = (size_t)tx_len;
spi_rx_buf.buf = rx;
spi_rx_buf.len = (size_t)rx_len;
return spi_transceive(spi_dev, &spi_cfg, &spi_tx, &spi_rx);
}
static int spi_send_packet(uint8_t *data, uint16_t len)
{
int ret;
uint16_t fail_count = 0;
do {
/* Wait for SPI bus to be available */
k_sem_take(&sem_spi_available, K_FOREVER);
/* Send the SPI packet to controller */
ret = bt_apollo_spi_send(data, len, bt_spi_transceive);
/* Free the SPI bus */
k_sem_give(&sem_spi_available);
if (ret) {
/* Give some chance to controller to complete the processing or
* packets sending.
*/
k_sleep(K_MSEC(SPI_BUSY_WAIT_INTERVAL_MS));
} else {
break;
}
} while (fail_count++ < SPI_BUSY_TX_ATTEMPTS);
return ret;
}
static int spi_receive_packet(uint8_t *data, uint16_t *len)
{
int ret;
/* Wait for SPI bus to be available */
k_sem_take(&sem_spi_available, K_FOREVER);
/* Receive the SPI packet from controller */
ret = bt_apollo_spi_rcv(data, len, bt_spi_transceive);
/* Free the SPI bus */
k_sem_give(&sem_spi_available);
return ret;
}
static int hci_event_filter(const uint8_t *evt_data)
{
uint8_t evt_type = evt_data[EVT_HEADER_TYPE];
switch (evt_type) {
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 EVT_DISCARD;
default:
return EVT_OK;
}
}
case BT_HCI_EVT_CMD_COMPLETE: {
uint16_t opcode = (uint16_t)(evt_data[EVT_CMD_COMP_OP_LSB] +
(evt_data[EVT_CMD_COMP_OP_MSB] << 8));
switch (opcode) {
case BT_OP_NOP:
return EVT_NOP;
case BT_HCI_OP_READ_LOCAL_FEATURES: {
/* The BLE controller of some Ambiq Apollox Blue SOC may have issue to
* report the expected supported features bitmask successfully, thought the
* features are actually supportive. Need to correct them before going to
* the host stack.
*/
struct bt_hci_rp_read_local_features *rp =
(void *)&evt_data[EVT_CMD_COMP_DATA];
if (rp->status == 0) {
BT_FEAT_SET_NO_BREDR(rp->features);
BT_FEAT_SET_LE(rp->features);
}
return EVT_OK;
}
default:
return EVT_OK;
}
}
default:
return EVT_OK;
}
}
static struct net_buf *bt_hci_evt_recv(uint8_t *data, size_t len)
{
int evt_filter;
bool discardable = false;
struct bt_hci_evt_hdr hdr = {0};
struct net_buf *buf;
size_t buf_tailroom;
if (len < sizeof(hdr)) {
LOG_ERR("Not enough data for event header");
return NULL;
}
evt_filter = hci_event_filter(data);
if (evt_filter == EVT_NOP) {
/* The controller sends NOP event when wakes up based on
* hardware specific requirement, do not post this event to
* host stack.
*/
return NULL;
} else if (evt_filter == EVT_DISCARD) {
discardable = true;
}
memcpy((void *)&hdr, data, sizeof(hdr));
data += sizeof(hdr);
len -= sizeof(hdr);
if (len != hdr.len) {
LOG_ERR("Event payload length is not correct");
return NULL;
}
buf = bt_buf_get_evt(hdr.evt, discardable, K_NO_WAIT);
if (!buf) {
if (discardable) {
LOG_DBG("Discardable buffer pool full, ignoring event");
} else {
LOG_ERR("No available event buffers!");
}
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 *bt_hci_acl_recv(uint8_t *data, size_t len)
{
struct bt_hci_acl_hdr hdr = {0};
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 (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;
}
net_buf_add_mem(buf, data, len);
return buf;
}
static void bt_spi_rx_thread(void *p1, void *p2, void *p3)
{
ARG_UNUSED(p1);
ARG_UNUSED(p2);
ARG_UNUSED(p3);
struct net_buf *buf;
int ret;
uint16_t len = 0;
while (true) {
/* Wait for controller interrupt */
k_sem_take(&sem_irq, K_FOREVER);
do {
/* Recevive the HCI packet via SPI */
ret = spi_receive_packet(&rxmsg[0], &len);
if (ret) {
break;
}
/* Check if needs to handle the vendor specific events which are
* incompatible with the standard Bluetooth HCI format.
*/
if (bt_apollo_vnd_rcv_ongoing(&rxmsg[0], len)) {
break;
}
switch (rxmsg[PACKET_TYPE]) {
case BT_HCI_H4_EVT:
buf = bt_hci_evt_recv(&rxmsg[PACKET_TYPE + PACKET_TYPE_SIZE],
(len - PACKET_TYPE_SIZE));
break;
case BT_HCI_H4_ACL:
buf = bt_hci_acl_recv(&rxmsg[PACKET_TYPE + PACKET_TYPE_SIZE],
(len - PACKET_TYPE_SIZE));
break;
default:
buf = NULL;
LOG_WRN("Unknown BT buf type %d", rxmsg[PACKET_TYPE]);
break;
}
/* Post the RX message to host stack to process */
if (buf) {
bt_recv(buf);
}
} while (0);
}
}
static int bt_hci_send(struct net_buf *buf)
{
int ret = 0;
/* Buffer needs an additional byte for type */
if (buf->len >= SPI_MAX_TX_MSG_LEN) {
LOG_ERR("Message too long");
return -EINVAL;
}
switch (bt_buf_get_type(buf)) {
case BT_BUF_ACL_OUT:
net_buf_push_u8(buf, BT_HCI_H4_ACL);
break;
case BT_BUF_CMD:
net_buf_push_u8(buf, BT_HCI_H4_CMD);
break;
default:
LOG_ERR("Unsupported type");
net_buf_unref(buf);
return -EINVAL;
}
/* Send the SPI packet */
ret = spi_send_packet(buf->data, buf->len);
net_buf_unref(buf);
return ret;
}
static int bt_hci_open(void)
{
int ret;
ret = bt_hci_transport_setup(spi_dev);
if (ret) {
return ret;
}
/* Start RX thread */
k_thread_create(&spi_rx_thread_data, spi_rx_stack, K_KERNEL_STACK_SIZEOF(spi_rx_stack),
(k_thread_entry_t)bt_spi_rx_thread, NULL, NULL, NULL,
K_PRIO_COOP(CONFIG_BT_DRIVER_RX_HIGH_PRIO), 0, K_NO_WAIT);
ret = bt_apollo_controller_init(spi_send_packet);
return ret;
}
static int bt_spi_setup(const struct bt_hci_setup_params *params)
{
ARG_UNUSED(params);
int ret;
ret = bt_apollo_vnd_setup();
return ret;
}
static const struct bt_hci_driver drv = {
.name = "ambiq hci",
.bus = BT_HCI_DRIVER_BUS_SPI,
.open = bt_hci_open,
.send = bt_hci_send,
.setup = bt_spi_setup,
};
static int bt_hci_init(void)
{
int ret;
if (!device_is_ready(spi_dev)) {
LOG_ERR("SPI device not ready");
return -ENODEV;
}
ret = bt_apollo_dev_init();
if (ret) {
return ret;
}
bt_hci_driver_register(&drv);
LOG_DBG("BT HCI initialized");
return 0;
}
SYS_INIT(bt_hci_init, POST_KERNEL, CONFIG_BT_HCI_INIT_PRIORITY);