| /**************************************************************************** |
| * arch/arm/src/stm32wb/stm32wb_mbox.c |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| #include <assert.h> |
| #include <debug.h> |
| |
| #include <nuttx/arch.h> |
| #include <nuttx/wqueue.h> |
| |
| #include "arm_internal.h" |
| #include "stm32wb_ipcc.h" |
| #include "stm32wb_mbox.h" |
| #include "hardware/stm32wb_memorymap.h" |
| |
| /**************************************************************************** |
| * Pre-processor Definitions |
| ****************************************************************************/ |
| |
| /* Mailbox shared buffer base address. Normally it is located at |
| * the beginning of SRAM2a. |
| */ |
| |
| #define STM32WB_MBOX_SHARED_BASE STM32WB_SRAM2A_BASE |
| |
| /* Mailbox shared buffer fields */ |
| |
| #define stm32wb_mbox_shared \ |
| (*(struct stm32wb_mbox_shared_buffer_s *)STM32WB_MBOX_SHARED_BASE) |
| |
| #define stm32wb_mbox_ref_table (stm32wb_mbox_shared.ref_table) |
| #define stm32wb_mbox_di_table (stm32wb_mbox_shared.dev_info_table) |
| #define stm32wb_mbox_sys_table (stm32wb_mbox_shared.sys_table) |
| #define stm32wb_mbox_mm_table (stm32wb_mbox_shared.mm_table) |
| #define stm32wb_mbox_ble_table (stm32wb_mbox_shared.ble_table) |
| |
| /* Mailbox buffer sizes */ |
| |
| #define STM32WB_MBOX_CS_BUF_SIZE 16 |
| #define STM32WB_MBOX_CMDPKT_BUF_SIZE 268 |
| #define STM32WB_MBOX_ACLPKT_BUF_SIZE 264 |
| |
| #define STM32WB_MBOX_RX_BUF_SIZE \ |
| (CONFIG_STM32WB_MBOX_RX_EVT_QUEUE_LEN * STM32WB_MBOX_CMDPKT_BUF_SIZE) |
| |
| /**************************************************************************** |
| * Private Types |
| ****************************************************************************/ |
| |
| /* Mailbox shared buffer structures */ |
| |
| begin_packed_struct struct stm32wb_mbox_safe_boot_info_table_s |
| { |
| uint32_t version; |
| } end_packed_struct; |
| |
| begin_packed_struct struct stm32wb_mbox_fus_info_table_s |
| { |
| uint32_t version; |
| uint32_t memory_size; |
| uint32_t fus_info; |
| } end_packed_struct; |
| |
| begin_packed_struct struct stm32wb_mbox_wireless_fw_info_table_s |
| { |
| uint32_t version; |
| uint32_t memory_size; |
| uint32_t info_stack; |
| uint32_t reserved; |
| } end_packed_struct; |
| |
| begin_packed_struct struct stm32wb_mbox_device_info_table_s |
| { |
| struct stm32wb_mbox_safe_boot_info_table_s safe_boot_info_table; |
| struct stm32wb_mbox_fus_info_table_s fus_info_table; |
| struct stm32wb_mbox_wireless_fw_info_table_s wireless_fw_info_table; |
| } end_packed_struct; |
| |
| begin_packed_struct struct stm32wb_mbox_ble_table_s |
| { |
| void *cmd_buffer; |
| void *cs_buffer; |
| void *evt_queue; |
| void *acl_buffer; |
| } end_packed_struct; |
| |
| begin_packed_struct struct stm32wb_mbox_sys_table_s |
| { |
| void *cmd_buffer; |
| void *evt_queue; |
| } end_packed_struct; |
| |
| begin_packed_struct struct stm32wb_mbox_mem_manager_table_s |
| { |
| void *ble_spare_buffer; |
| void *sys_spare_buffer; |
| void *evtpool_buffer; |
| uint32_t evtpool_size; |
| void *evtfree_buffer; |
| void *traces_evtpool_buffer; |
| uint32_t traces_evtpool_size; |
| } end_packed_struct; |
| |
| begin_packed_struct struct stm32wb_mbox_ref_table_s |
| { |
| struct stm32wb_mbox_device_info_table_s *dev_info_table; |
| struct stm32wb_mbox_ble_table_s *ble_table; |
| void *thread_table; |
| struct stm32wb_mbox_sys_table_s *sys_table; |
| struct stm32wb_mbox_mem_manager_table_s *mm_table; |
| void *traces_table; |
| void *mac_802_15_4_table; |
| void *zigbee_table; |
| void *ble_lld_test_table; |
| void *ble_lld_table; |
| } end_packed_struct; |
| |
| /* Mailbox shared buffer memory layout structure */ |
| |
| struct stm32wb_mbox_shared_buffer_s |
| { |
| aligned_data(4) struct stm32wb_mbox_ref_table_s ref_table; |
| |
| aligned_data(4) struct stm32wb_mbox_device_info_table_s dev_info_table; |
| aligned_data(4) struct stm32wb_mbox_ble_table_s ble_table; |
| aligned_data(4) struct stm32wb_mbox_sys_table_s sys_table; |
| aligned_data(4) struct stm32wb_mbox_mem_manager_table_s mm_table; |
| |
| aligned_data(4) stm32wb_mbox_list_t evtfree_buffer; |
| #ifdef CONFIG_STM32WB_BLE |
| aligned_data(4) stm32wb_mbox_list_t ble_evt_queue; |
| #endif |
| aligned_data(4) stm32wb_mbox_list_t sys_evt_queue; |
| |
| #ifdef CONFIG_STM32WB_BLE |
| aligned_data(4) uint8_t ble_cs_buffer[STM32WB_MBOX_CS_BUF_SIZE]; |
| #endif |
| aligned_data(4) uint8_t evtpool_buffer[STM32WB_MBOX_RX_BUF_SIZE]; |
| aligned_data(4) uint8_t sys_cmd_buffer[STM32WB_MBOX_CMDPKT_BUF_SIZE]; |
| aligned_data(4) uint8_t sys_spare_buffer[STM32WB_MBOX_CMDPKT_BUF_SIZE]; |
| #ifdef CONFIG_STM32WB_BLE |
| aligned_data(4) uint8_t ble_spare_buffer[STM32WB_MBOX_CMDPKT_BUF_SIZE]; |
| aligned_data(4) uint8_t ble_cmd_buffer[STM32WB_MBOX_CMDPKT_BUF_SIZE]; |
| aligned_data(4) uint8_t ble_acl_buffer[STM32WB_MBOX_ACLPKT_BUF_SIZE]; |
| #endif |
| }; |
| |
| /* Mailbox channel data type */ |
| |
| struct stm32wb_mbox_channel_s |
| { |
| uint8_t ch_num; |
| stm32wb_mbox_list_t cmd_buf_queue; |
| struct stm32wb_mbox_cmd_s *cmd_buf; |
| bool ack_ready; |
| }; |
| |
| /**************************************************************************** |
| * Private Function prototypes |
| ****************************************************************************/ |
| |
| static void stm32wb_ipcc_rxoisr(int irq, uint32_t *regs, void *arg); |
| static void stm32wb_ipcc_txfisr(int irq, uint32_t *regs, void *arg); |
| |
| static void stm32wb_mbox_rxworker(void *arg); |
| static void stm32wb_mbox_txworker(void *arg); |
| |
| static void stm32wb_mbox_eventfree(stm32wb_mbox_list_t *evt); |
| static void stm32wb_mbox_acksyscmd(void); |
| |
| static int stm32wb_mbox_txdata(struct stm32wb_mbox_channel_s *chan, |
| uint8_t type, void *data, size_t len); |
| static bool stm32wb_mbox_txnext(struct stm32wb_mbox_channel_s *chan); |
| |
| /**************************************************************************** |
| * Private Data |
| ****************************************************************************/ |
| |
| static struct work_s g_rx_evt_work; |
| static struct work_s g_tx_cmd_work; |
| |
| static stm32wb_mbox_list_t g_rx_evt_queue; |
| static stm32wb_mbox_list_t g_tx_evtfree_queue; |
| static uint8_t g_free_buffers[CONFIG_STM32WB_MBOX_TX_CMD_QUEUE_LEN] |
| [STM32WB_MBOX_CMDPKT_BUF_SIZE]; |
| static stm32wb_mbox_list_t g_free_buffers_pool; |
| |
| static struct stm32wb_mbox_channel_s g_syscmd_channel; |
| #ifdef CONFIG_STM32WB_BLE |
| static struct stm32wb_mbox_channel_s g_blecmd_channel; |
| static struct stm32wb_mbox_channel_s g_bleacl_channel; |
| #endif |
| |
| static stm32wb_mbox_evt_handler_t receive_evt_handler; |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: stm32wb_ipcc_rxoisr |
| * |
| * Description: |
| * RX channel occupied interrupt handler (communication data posted |
| * by sending processor). |
| * |
| ****************************************************************************/ |
| |
| static void stm32wb_ipcc_rxoisr(int irq, uint32_t *regs, void *arg) |
| { |
| uint32_t clrmask = 0; |
| |
| /* Pull events from system channel into processing queue */ |
| |
| if (stm32wb_ipcc_rxactive(STM32WB_MBOX_SYSEVT_CHANNEL)) |
| { |
| stm32wb_mbox_list_moveall(&stm32wb_mbox_shared.sys_evt_queue, |
| &g_rx_evt_queue); |
| |
| clrmask |= IPCC_C1SCR_CLR_BIT(STM32WB_MBOX_SYSEVT_CHANNEL); |
| } |
| |
| #ifdef CONFIG_STM32WB_BLE |
| |
| /* Pull events from BLE channel into processing queue */ |
| |
| if (stm32wb_ipcc_rxactive(STM32WB_MBOX_BLEEVT_CHANNEL)) |
| { |
| stm32wb_mbox_list_moveall(&stm32wb_mbox_shared.ble_evt_queue, |
| &g_rx_evt_queue); |
| |
| clrmask |= IPCC_C1SCR_CLR_BIT(STM32WB_MBOX_BLEEVT_CHANNEL); |
| } |
| #endif |
| |
| /* Process collected events in the work queue */ |
| |
| if (work_available(&g_rx_evt_work)) |
| { |
| work_queue(HPWORK, &g_rx_evt_work, stm32wb_mbox_rxworker, NULL, 0); |
| } |
| |
| /* Clear active statuses */ |
| |
| putreg32(clrmask, STM32WB_IPCC_C1SCR); |
| } |
| |
| /**************************************************************************** |
| * Name: stm32wb_ipcc_txfisr |
| * |
| * Description: |
| * TX channel free interrupt handler (communication data retrieved |
| * by receiving processor). |
| * |
| ****************************************************************************/ |
| |
| static void stm32wb_ipcc_txfisr(int irq, uint32_t *regs, void *arg) |
| { |
| uint32_t c1mr = getreg32(STM32WB_IPCC_C1MR); |
| uint32_t txfsrc; |
| |
| /* TXF interrupt can be triggered by not masked channels and active status |
| * of the source channel is cleared by CPU2. So we ignore masked and active |
| * channels and rise other C1MR bits to highlight needed channels. |
| */ |
| |
| txfsrc = ~(c1mr | (getreg32(STM32WB_IPCC_C1TOC2SR) << IPCC_C1MR_FM_SHIFT)) |
| & IPCC_C1MR_FM_MASK; |
| |
| /* Check if the release channel triggered the interrupt */ |
| |
| if (txfsrc & IPCC_C1MR_FM_BIT(STM32WB_MBOX_EVT_RELEASE_CHANNEL)) |
| { |
| /* Move all released events (if any) into transmission mailbox */ |
| |
| if (!stm32wb_mbox_list_is_empty(&g_tx_evtfree_queue)) |
| { |
| stm32wb_mbox_list_moveall(&g_tx_evtfree_queue, |
| &stm32wb_mbox_shared.evtfree_buffer); |
| |
| /* Start release channel transmission */ |
| |
| stm32wb_ipcc_settxactive(STM32WB_MBOX_EVT_RELEASE_CHANNEL); |
| } |
| } |
| |
| /* Check other channels, except the release channel */ |
| |
| if (txfsrc & ~IPCC_C1MR_FM_BIT(STM32WB_MBOX_EVT_RELEASE_CHANNEL)) |
| { |
| /* Check if the system channel triggered the interrupt */ |
| |
| if (txfsrc & IPCC_C1MR_FM_BIT(STM32WB_MBOX_SYSCMD_CHANNEL)) |
| { |
| /* System channel works in 'half-duplex' mode and acks |
| * immediately on each command before TXF, so it needs |
| * to process ack response before sending next command. |
| */ |
| |
| g_syscmd_channel.ack_ready = true; |
| } |
| |
| /* Continue command processing in a work queue */ |
| |
| if (work_available(&g_tx_cmd_work)) |
| { |
| work_queue(HPWORK, &g_tx_cmd_work, stm32wb_mbox_txworker, NULL, 0); |
| } |
| } |
| |
| /* Mask triggered channels */ |
| |
| putreg32(c1mr | txfsrc, STM32WB_IPCC_C1MR); |
| } |
| |
| /**************************************************************************** |
| * Name: stm32wb_mbox_txworker |
| ****************************************************************************/ |
| |
| static void stm32wb_mbox_txworker(void *arg) |
| { |
| bool handled; |
| |
| /* Process all queued commands if a dedicated channel is free */ |
| |
| do |
| { |
| handled = false; |
| |
| if (!stm32wb_ipcc_txactive(STM32WB_MBOX_SYSCMD_CHANNEL)) |
| { |
| /* Process ack response before send new command */ |
| |
| if (g_syscmd_channel.ack_ready) |
| { |
| stm32wb_mbox_acksyscmd(); |
| g_syscmd_channel.ack_ready = false; |
| } |
| |
| handled = stm32wb_mbox_txnext(&g_syscmd_channel); |
| } |
| |
| #ifdef CONFIG_STM32WB_BLE |
| if (!stm32wb_ipcc_txactive(STM32WB_MBOX_BLECMD_CHANNEL)) |
| { |
| handled |= stm32wb_mbox_txnext(&g_blecmd_channel); |
| } |
| |
| if (!stm32wb_ipcc_txactive(STM32WB_MBOX_BLEACL_CHANNEL)) |
| { |
| handled |= stm32wb_mbox_txnext(&g_bleacl_channel); |
| } |
| #endif |
| } |
| while (handled); |
| } |
| |
| /**************************************************************************** |
| * Name: stm32wb_mbox_rxworker |
| ****************************************************************************/ |
| |
| static void stm32wb_mbox_rxworker(void *arg) |
| { |
| stm32wb_mbox_list_t *evt; |
| irqstate_t flags; |
| |
| while (1) |
| { |
| flags = enter_critical_section(); |
| |
| /* Pull an event from the queue */ |
| |
| evt = stm32wb_mbox_list_remove_head(&g_rx_evt_queue); |
| |
| leave_critical_section(flags); |
| |
| if (evt == NULL) |
| { |
| break; |
| } |
| |
| /* Pass event to a callback function without a list header */ |
| |
| receive_evt_handler((struct stm32wb_mbox_evt_s *)(evt + 1)); |
| |
| /* Free completed event. Released event needs to return to CPU2 |
| * via release channel. |
| */ |
| |
| stm32wb_mbox_eventfree((stm32wb_mbox_list_t *)evt); |
| } |
| } |
| |
| /**************************************************************************** |
| * Name: stm32wb_mbox_txdata |
| * |
| * Description: |
| * Send data over specified mailbox channel if possible. If the |
| * channel is busy then add a prepared packet into awaiting queue. |
| * |
| ****************************************************************************/ |
| |
| static int stm32wb_mbox_txdata(struct stm32wb_mbox_channel_s *chan, |
| uint8_t type, void *data, size_t len) |
| { |
| irqstate_t flags; |
| struct stm32wb_mbox_cmd_s *pkt_buf; |
| |
| flags = enter_critical_section(); |
| |
| /* To start transmission the channel needs to be free, there should be |
| * none of other waiting commands and none of unprocessed ack responses. |
| */ |
| |
| if (stm32wb_mbox_list_is_empty(&chan->cmd_buf_queue) && |
| !stm32wb_ipcc_txactive(chan->ch_num) && !chan->ack_ready) |
| { |
| /* Channel is ready, copy command into transmission buffer */ |
| |
| pkt_buf = chan->cmd_buf; |
| } |
| else |
| { |
| /* Otherwise get temp buffer for command */ |
| |
| pkt_buf = (struct stm32wb_mbox_cmd_s *) |
| stm32wb_mbox_list_remove_head(&g_free_buffers_pool); |
| } |
| |
| leave_critical_section(flags); |
| |
| if (pkt_buf == NULL) |
| { |
| return -ENOBUFS; |
| } |
| |
| pkt_buf->type = type; |
| memcpy(&pkt_buf->cmd_hdr, data, len); |
| |
| if (pkt_buf == chan->cmd_buf) |
| { |
| /* Command is ready in mailbox buffer, start transmission now */ |
| |
| stm32wb_ipcc_settxactive(chan->ch_num); |
| |
| if (!stm32wb_mbox_list_is_empty(&chan->cmd_buf_queue) || |
| chan->ch_num == STM32WB_MBOX_SYSCMD_CHANNEL) |
| { |
| /* There are more commands awaiting, so unmask interrupt to get |
| * notified when channel gets ready to process a next one. |
| * And the system channel needs to check ack on completion. |
| */ |
| |
| stm32wb_ipcc_unmasktxf(chan->ch_num); |
| } |
| } |
| else |
| { |
| /* Command is in temp buffer, push it into queue */ |
| |
| flags = enter_critical_section(); |
| stm32wb_mbox_list_add_tail(&chan->cmd_buf_queue, &pkt_buf->list_hdr); |
| leave_critical_section(flags); |
| |
| /* Unmask interrupt to get notified when channel gets free */ |
| |
| stm32wb_ipcc_unmasktxf(chan->ch_num); |
| } |
| |
| return OK; |
| } |
| |
| /**************************************************************************** |
| * Name: stm32wb_mbox_txnext |
| * |
| * Description: |
| * Send next command from the queue. |
| * |
| ****************************************************************************/ |
| |
| static bool stm32wb_mbox_txnext(struct stm32wb_mbox_channel_s *chan) |
| { |
| struct stm32wb_mbox_cmd_s *pkt_buf; |
| |
| pkt_buf = (struct stm32wb_mbox_cmd_s *) |
| stm32wb_mbox_list_remove_head(&chan->cmd_buf_queue); |
| |
| if (pkt_buf != NULL) |
| { |
| chan->cmd_buf->type = pkt_buf->type; |
| |
| if (chan->ch_num == STM32WB_MBOX_BLEACL_CHANNEL) |
| { |
| memcpy(&chan->cmd_buf->acl_hdr, &pkt_buf->acl_hdr, |
| sizeof(pkt_buf->acl_hdr) + pkt_buf->acl_hdr.len); |
| } |
| else |
| { |
| memcpy(&chan->cmd_buf->cmd_hdr, &pkt_buf->cmd_hdr, |
| sizeof(pkt_buf->cmd_hdr) + pkt_buf->cmd_hdr.param_len); |
| } |
| |
| /* Start transmission */ |
| |
| stm32wb_ipcc_settxactive(chan->ch_num); |
| |
| if (!stm32wb_mbox_list_is_empty(&chan->cmd_buf_queue)) |
| { |
| /* Unmask TXF interrupt to get notified when completed */ |
| |
| stm32wb_ipcc_unmasktxf(chan->ch_num); |
| } |
| |
| /* Put back to pool the freed command buffer */ |
| |
| stm32wb_mbox_list_add_tail(&g_free_buffers_pool, &pkt_buf->list_hdr); |
| } |
| |
| return pkt_buf != NULL; |
| } |
| |
| /**************************************************************************** |
| * Name: stm32wb_mbox_eventfree |
| * |
| * Description: |
| * Free handled mailbox event. |
| * |
| ****************************************************************************/ |
| |
| static void stm32wb_mbox_eventfree(stm32wb_mbox_list_t *evt) |
| { |
| irqstate_t flags; |
| |
| flags = enter_critical_section(); |
| |
| /* Collect releasing events in the global list */ |
| |
| stm32wb_mbox_list_add_tail(&g_tx_evtfree_queue, evt); |
| |
| /* Check if release channel is ready to process now */ |
| |
| if (!stm32wb_ipcc_txactive(STM32WB_MBOX_EVT_RELEASE_CHANNEL)) |
| { |
| /* Move all collected events into transmission queue */ |
| |
| stm32wb_mbox_list_moveall(&g_tx_evtfree_queue, |
| &stm32wb_mbox_shared.evtfree_buffer); |
| |
| /* Start transmission */ |
| |
| stm32wb_ipcc_settxactive(STM32WB_MBOX_EVT_RELEASE_CHANNEL); |
| } |
| else |
| { |
| /* Unmask interrupt to get notified when channel gets free */ |
| |
| stm32wb_ipcc_unmasktxf(STM32WB_MBOX_EVT_RELEASE_CHANNEL); |
| } |
| |
| leave_critical_section(flags); |
| } |
| |
| /**************************************************************************** |
| * Name: stm32wb_mbox_acksyscmd |
| * |
| * Description: |
| * Send ACK response event for completed system command. |
| * |
| ****************************************************************************/ |
| |
| static void stm32wb_mbox_acksyscmd(void) |
| { |
| struct stm32wb_mbox_evt_s *evt; |
| |
| /* System command ACK response is placed at the same address as the |
| * processed command but without a list header. |
| */ |
| |
| evt = (struct stm32wb_mbox_evt_s *)(&g_syscmd_channel.cmd_buf); |
| evt->type = STM32WB_MBOX_SYSACK; |
| |
| receive_evt_handler(evt); |
| } |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: stm32wb_mboxinitialize |
| * |
| * Description: |
| * Initialize mailbox driver memory. |
| * |
| * Input Parameters: |
| * evt_handler - the function to call on event receive |
| * |
| ****************************************************************************/ |
| |
| void stm32wb_mboxinitialize(stm32wb_mbox_evt_handler_t evt_handler) |
| { |
| int i; |
| |
| /* Init mailbox shared data */ |
| |
| stm32wb_mbox_list_initialize(&stm32wb_mbox_shared.sys_evt_queue); |
| stm32wb_mbox_list_initialize(&stm32wb_mbox_shared.evtfree_buffer); |
| #ifdef CONFIG_STM32WB_BLE |
| stm32wb_mbox_list_initialize(&stm32wb_mbox_shared.ble_evt_queue); |
| #endif |
| |
| stm32wb_mbox_ref_table.dev_info_table = &stm32wb_mbox_di_table; |
| stm32wb_mbox_ref_table.ble_table = &stm32wb_mbox_ble_table; |
| stm32wb_mbox_ref_table.sys_table = &stm32wb_mbox_sys_table; |
| stm32wb_mbox_ref_table.mm_table = &stm32wb_mbox_mm_table; |
| |
| stm32wb_mbox_sys_table.cmd_buffer = &stm32wb_mbox_shared.sys_cmd_buffer; |
| stm32wb_mbox_sys_table.evt_queue = &stm32wb_mbox_shared.sys_evt_queue; |
| |
| stm32wb_mbox_mm_table.evtpool_buffer = &stm32wb_mbox_shared |
| .evtpool_buffer; |
| stm32wb_mbox_mm_table.evtpool_size = sizeof(stm32wb_mbox_shared |
| .evtpool_buffer); |
| stm32wb_mbox_mm_table.evtfree_buffer = &stm32wb_mbox_shared |
| .evtfree_buffer; |
| stm32wb_mbox_mm_table.sys_spare_buffer = &stm32wb_mbox_shared |
| .sys_spare_buffer; |
| #ifdef CONFIG_STM32WB_BLE |
| stm32wb_mbox_mm_table.ble_spare_buffer = &stm32wb_mbox_shared |
| .ble_spare_buffer; |
| #endif |
| |
| #ifdef CONFIG_STM32WB_BLE |
| stm32wb_mbox_ble_table.cmd_buffer = &stm32wb_mbox_shared.ble_cmd_buffer; |
| stm32wb_mbox_ble_table.acl_buffer = &stm32wb_mbox_shared.ble_acl_buffer; |
| stm32wb_mbox_ble_table.cs_buffer = &stm32wb_mbox_shared.ble_cs_buffer; |
| stm32wb_mbox_ble_table.evt_queue = &stm32wb_mbox_shared.ble_evt_queue; |
| #endif |
| |
| /* Init system channel data */ |
| |
| g_syscmd_channel.ch_num = STM32WB_MBOX_SYSCMD_CHANNEL; |
| g_syscmd_channel.cmd_buf = (struct stm32wb_mbox_cmd_s *) |
| stm32wb_mbox_shared.sys_cmd_buffer; |
| stm32wb_mbox_list_initialize(&g_syscmd_channel.cmd_buf_queue); |
| |
| #ifdef CONFIG_STM32WB_BLE |
| /* Init BLE command channel data */ |
| |
| g_blecmd_channel.ch_num = STM32WB_MBOX_BLECMD_CHANNEL; |
| g_blecmd_channel.cmd_buf = (struct stm32wb_mbox_cmd_s *) |
| stm32wb_mbox_shared.ble_cmd_buffer; |
| stm32wb_mbox_list_initialize(&g_blecmd_channel.cmd_buf_queue); |
| |
| /* Init BLE ACL channel data */ |
| |
| g_bleacl_channel.ch_num = STM32WB_MBOX_BLEACL_CHANNEL; |
| g_bleacl_channel.cmd_buf = (struct stm32wb_mbox_cmd_s *) |
| stm32wb_mbox_shared.ble_acl_buffer; |
| stm32wb_mbox_list_initialize(&g_bleacl_channel.cmd_buf_queue); |
| #endif |
| |
| /* Init local (not shared) queues */ |
| |
| stm32wb_mbox_list_initialize(&g_rx_evt_queue); |
| stm32wb_mbox_list_initialize(&g_tx_evtfree_queue); |
| |
| stm32wb_mbox_list_initialize(&g_free_buffers_pool); |
| for (i = 0; i < CONFIG_STM32WB_MBOX_TX_CMD_QUEUE_LEN; i++) |
| { |
| stm32wb_mbox_list_add_tail(&g_free_buffers_pool, |
| (stm32wb_mbox_list_t *)g_free_buffers[i]); |
| } |
| |
| /* Set event receive function */ |
| |
| receive_evt_handler = evt_handler; |
| } |
| |
| /**************************************************************************** |
| * Name: stm32wb_mboxenable |
| * |
| * Description: |
| * Enable mailbox hardware and start communication. The CPU2 responses |
| * with C2Ready event on success. |
| * |
| ****************************************************************************/ |
| |
| void stm32wb_mboxenable(void) |
| { |
| uint32_t regval; |
| |
| /* Setup RXO and TXF interrupts */ |
| |
| irq_attach(STM32WB_IRQ_IPCCRX, (xcpt_t)stm32wb_ipcc_rxoisr, NULL); |
| up_enable_irq(STM32WB_IRQ_IPCCRX); |
| |
| irq_attach(STM32WB_IRQ_IPCCTX, (xcpt_t)stm32wb_ipcc_txfisr, NULL); |
| up_enable_irq(STM32WB_IRQ_IPCCTX); |
| |
| regval = getreg32(STM32WB_IPCC_C1CR); |
| regval |= IPCC_C1CR_RXOIE | IPCC_C1CR_TXFIE; |
| putreg32(regval, STM32WB_IPCC_C1CR); |
| |
| /* Unmask system channel RXO interrupt. Once CPU2 started we expect |
| * to receive C2READY event via system channel. |
| */ |
| |
| stm32wb_ipcc_unmaskrxo(STM32WB_MBOX_SYSEVT_CHANNEL); |
| |
| /* Enable IPCC hardware and bootup CPU2 */ |
| |
| stm32wb_ipccenable(); |
| } |
| |
| /**************************************************************************** |
| * Name: stm32wb_mbox_syscmd |
| * |
| * Description: |
| * Send command over mailbox system channel. Command data must be |
| * prepended with HCI header. |
| * |
| ****************************************************************************/ |
| |
| int stm32wb_mbox_syscmd(void *data, size_t len) |
| { |
| return stm32wb_mbox_txdata(&g_syscmd_channel, STM32WB_MBOX_SYSCMD, |
| data, len); |
| } |
| |
| #ifdef CONFIG_STM32WB_BLE |
| /**************************************************************************** |
| * Name: stm32wb_mbox_blecmd |
| * |
| * Description: |
| * Send command over mailbox BLE channel. Command data must be |
| * prepended with HCI header. |
| * |
| ****************************************************************************/ |
| |
| int stm32wb_mbox_blecmd(void *data, size_t len) |
| { |
| return stm32wb_mbox_txdata(&g_blecmd_channel, STM32WB_MBOX_HCICMD, |
| data, len); |
| } |
| |
| /**************************************************************************** |
| * Name: stm32wb_mbox_bleacl |
| * |
| * Description: |
| * Send BLE ACL data over mailbox BLE ACL channel. Data must be |
| * prepended with HCI ACL header. |
| * |
| ****************************************************************************/ |
| |
| int stm32wb_mbox_bleacl(void *data, size_t len) |
| { |
| return stm32wb_mbox_txdata(&g_bleacl_channel, STM32WB_MBOX_HCIACL, |
| data, len); |
| } |
| |
| /**************************************************************************** |
| * Name: stm32wb_mbox_bleinit |
| * |
| * Description: |
| * Initialize and start BLE subsystem with provided configuration params. |
| * |
| ****************************************************************************/ |
| |
| void stm32wb_mbox_bleinit(struct stm32wb_shci_ble_init_cfg_s *params) |
| { |
| struct bt_hci_cmd_hdr_s *cmd; |
| |
| /* Just borrow a temporary free buffer for command data */ |
| |
| cmd = (struct bt_hci_cmd_hdr_s *)stm32wb_mbox_shared.sys_spare_buffer; |
| |
| /* Prepare command data */ |
| |
| cmd->opcode = STM32WB_SHCI_BLE_INIT; |
| cmd->param_len = sizeof(*cmd); |
| memcpy(cmd + 1, params, sizeof(*params)); |
| |
| /* Send BLE init command to CPU2 */ |
| |
| stm32wb_mbox_syscmd(cmd, sizeof(*cmd) + sizeof(*params)); |
| |
| /* Unmask BLE event channel RXO interrupt */ |
| |
| stm32wb_ipcc_unmaskrxo(STM32WB_MBOX_BLEEVT_CHANNEL); |
| } |
| #endif /* CONFIG_STM32WB_BLE */ |