1 /* -------------------------------------------------------------------------- */
2 /*                           Copyright 2021-2024 NXP                          */
3 /*                            All rights reserved.                            */
4 /*                    SPDX-License-Identifier: BSD-3-Clause                   */
5 /* -------------------------------------------------------------------------- */
6 
7 /* -------------------------------------------------------------------------- */
8 /*                                  Includes                                  */
9 /* -------------------------------------------------------------------------- */
10 
11 #include <stdint.h>
12 #include <stdbool.h>
13 
14 #ifndef CONFIG_PRINTK /* Zephyr already has print support */
15 #include "fsl_debug_console.h"
16 #endif /* CONFIG_PRINTK */
17 
18 #include "fsl_loader.h"
19 #include "fsl_power.h"
20 #include "fsl_adapter_rpmsg.h"
21 #include "fsl_adapter_rfimu.h"
22 #include "fsl_os_abstraction.h"
23 
24 #include "fwk_config.h"
25 #include "fwk_platform_ble.h"
26 #include "fwk_platform_ot.h"
27 #include "fwk_platform_coex.h"
28 
29 #ifdef SERIAL_BTSNOOP
30 #include "sbtsnoop.h"
31 #endif
32 
33 /* -------------------------------------------------------------------------- */
34 /*                               Private macros                               */
35 /* -------------------------------------------------------------------------- */
36 /* By default, wait maximum 1s for the controller to wake up */
37 #ifndef PLATFORM_BLE_WAKE_UP_TIMEOUT_MS
38 #define PLATFORM_BLE_WAKE_UP_TIMEOUT_MS 1000U
39 
40 #endif
41 
42 #define HCI_COMMAND_PACKET              0x01U
43 #define HCI_EVENT_PACKET                0x04U
44 #define HCI_VENDOR_SPECIFIC_DEBUG_EVENT 0xFFU
45 
46 #define HCI_CMD_PACKET_HEADER_LENGTH 3U
47 #define HCI_CMD_VENDOR_OCG           0x3FU
48 
49 #define HCI_CMD_STORE_BT_CAL_DATA_OCF          0x61U
50 #define HCI_CMD_STORE_BT_CAL_DATA_PARAM_LENGTH 32U
51 
52 #define HCI_CMD_STORE_BT_CAL_DATA_ANNEX100_OCF          0xFFU
53 #define HCI_CMD_STORE_BT_CAL_DATA_PARAM_ANNEX100_LENGTH 16U
54 
55 #define HCI_CMD_SET_BT_SLEEP_MODE_OCF          0x23U
56 #define HCI_CMD_SET_BT_SLEEP_MODE_PARAM_LENGTH 3U
57 
58 #define HCI_CMD_BT_HIU_HS_ENABLE_OCF 0x5A
59 
60 #define HCI_CMD_BT_HOST_SLEEP_CONFIG_OCF          0x59U
61 #define HCI_CMD_BT_HOST_SLEEP_CONFIG_PARAM_LENGTH 2U
62 
63 #define HCI_EVT_PS_SLEEP_OCF 0x20U
64 
65 #define get_opcode(ocg, ocf) (((uint16_t)(ocg) & (uint16_t)0x3FU) << 10) | (uint16_t)((ocf)&0x3FFU)
66 
67 /* The wake up done interrupt doesn't make any call to FreeRTOS API so it should
68  * be safe to make it higher priority than configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
69  * so it is not masked in FreeRTOS critical sections */
70 #define MCI_WAKEUP_DONE_PRIORITY (1)
71 
72 #define BLE_POWER_STATUS() (SOCCTRL->BLE_POWER_STATUS & 0x3U)
73 #define BLE_POWER_ON       (0U)
74 #define BLE_POWER_SLP      (2U)
75 #define BLE_POWER_OFF      (3U)
76 
77 #define BLE_SMU_POWER_STATUS() (*((volatile uint32_t *)0x443C0000U))
78 #define BLE_SMU_POWER_OFF      (0x3131312AU)
79 
80 /* Can change the macro BLE_VENDOR_EVENT_HANDLE to false to let HOST handle the Vendor Event,
81  * like PowerSave Vendor Event */
82 #define BLE_VENDOR_EVENT_HANDLE (true)
83 
84 #ifdef CONFIG_PRINTK
85 
86 #ifndef PRINTF
87 #define PRINTF printk
88 #endif
89 
90 #endif /* CONFIG_PRINTK */
91 
92 #define BLE_PS_DBG(...)      \
93     do                       \
94     {                        \
95         PRINTF("[BLE_PS] "); \
96         PRINTF(__VA_ARGS__); \
97     } while (false);
98 
99 /*
100  * a.The following parameters are used in three cases,
101  *    1.For share antenna case or ant2 with external FEM(ble only case).
102  *    2.divesity case(enanble ant3)
103  *    3.divesity case(enanble ant4)
104  */
105 #if defined(gPlatformSetAntDiversity_d) && (gPlatformSetAntDiversity_d == 0)
106 // For share antenna case or ant2 with external FEM(ble only case)
107 #define BT_CAL_DATA_ANNEX_100_EPA_FEM_MASK_LOW_BYTE 0x02U
108 #define BT_CAL_DATA_ANNEX_100_LNA_FEM_MASK_LOW_BYTE 0x02U
109 #elif defined(gPlatformSetAntDiversity_d) && (gPlatformSetAntDiversity_d == 1)
110 // divesity case(enanble ant3)
111 #define BT_CAL_DATA_ANNEX_100_EPA_FEM_MASK_LOW_BYTE 0x0AU
112 #define BT_CAL_DATA_ANNEX_100_LNA_FEM_MASK_LOW_BYTE 0x0AU
113 #elif defined(gPlatformSetAntDiversity_d) && (gPlatformSetAntDiversity_d == 2)
114 // divesity case(enanble ant4)
115 #define BT_CAL_DATA_ANNEX_100_EPA_FEM_MASK_LOW_BYTE 0x06U
116 #define BT_CAL_DATA_ANNEX_100_LNA_FEM_MASK_LOW_BYTE 0x06U
117 #endif
118 
119 /*
120  * The following parameters are used in two cases
121  */
122 #if defined(gPlatformDisableSetBtCalDataAnnex100_d) && (gPlatformDisableSetBtCalDataAnnex100_d == 1)
123 // For dual ant case
124 #define BT_CAL_DATA_ANNEX_FRONT_END_LOSS 0x02U
125 #elif defined(gPlatformDisableSetBtCalDataAnnex100_d) && (gPlatformDisableSetBtCalDataAnnex100_d == 0)
126 // For share antenna case or diversty case(ble only case)
127 #define BT_CAL_DATA_ANNEX_FRONT_END_LOSS 0x03U
128 #endif
129 
130 /*
131  *  After send annex55 to CPU2, CPU2 need reset,
132  *a delay of at least 20ms is required to continue sending annex100
133  */
134 #if defined(gPlatformDisableSetBtCalDataAnnex100_d) && (gPlatformDisableSetBtCalDataAnnex100_d == 0)
135 #define BLE_RESET_DELAY_MS 20U
136 #endif
137 
138 /* -------------------------------------------------------------------------- */
139 /*                                Private types                               */
140 /* -------------------------------------------------------------------------- */
141 
142 /*!
143  * \brief Controller power states enum
144  *
145  */
146 typedef enum
147 {
148     ble_awake_state,
149     ble_asleep_state
150 } ble_ps_t;
151 
152 /*!
153  * \brief Controller power state HCI vendor events
154  *
155  */
156 typedef enum
157 {
158     ble_asleep_event = 0x1U,
159     ble_awake_event  = 0x2U
160 } ble_ps_event_t;
161 
162 /* -------------------------------------------------------------------------- */
163 /*                             Private prototypes                             */
164 /* -------------------------------------------------------------------------- */
165 
166 /*!
167  * \brief Init HCI link with BLE controller
168  *
169  * \return int return status: >=0 for success, <0 for errors
170  */
171 static int PLATFORM_InitHciLink(void);
172 
173 /*!
174  * \brief Terminate HCI link with BLE controller
175  *
176  * \return int return status: >=0 for success, <0 for errors
177  */
178 static int PLATFORM_TerminateHciLink(void);
179 
180 /*!
181  * \brief Return HCI link status
182  *
183  * \return true Link is ready
184  * \return false Link is not ready yet
185  */
186 static bool PLATFORM_IsHciLinkReady(void);
187 
188 /*!
189  * \brief Checks if the BLE controller is awake or asleep
190  *
191  * \return true BLE Controller is awake
192  * \return false BLE Controller is asleep
193  */
194 static bool PLATFORM_IsBleAwake(void);
195 
196 /*!
197  * \brief RPMSG Rx callback used to receive HCI messages from Controller
198  *
199  * \param[in] param Usually NULL
200  * \param[in] data pointer to data buffer
201  * \param[in] len size of the data
202  * \return hal_rpmsg_return_status_t tells RPMSG to free or hold the buffer
203  */
204 static hal_rpmsg_return_status_t PLATFORM_HciRpmsgRxCallback(void *param, uint8_t *data, uint32_t len);
205 
206 /*!
207  * \brief Set BT Cal Data to Controller
208  *
209  * \return int return status: >=0 for success, <0 for errors
210  */
211 static int PLATFORM_SetBtCalData(void);
212 
213 #if !defined(gPlatformDisableSetBtCalDataAnnex100_d) || (gPlatformDisableSetBtCalDataAnnex100_d == 0)
214 /*!
215  * \brief Set BT Cal Data Annex100 to Controller
216  *
217  * \return int return status: >=0 for success, <0 for errors
218  */
219 static int PLATFORM_SetBtCalDataAnnex100(void);
220 #endif /* gPlatformDisableSetBtCalDataAnnex100_d */
221 
222 /*!
223  * \brief Handles supported Vendor Specific events received from Controller
224  *        If the received event is not supported, it will return false, so the
225  *        called can send the packet to upper layers (host stack or application)
226  *
227  * \param[in] eventData Pointer to event data buffer
228  * \param[in] len size of the data
229  * \return true The event has been handled
230  * \return false The event has NOT been handled
231  */
232 static bool PLATFORM_HandleHciVendorEvent(uint8_t *eventData, uint32_t len);
233 
234 /*!
235  * \brief Handle power state event from BLE Controller
236  *
237  * \param[in] psEvent event type received
238  * \return int return status: >=0 for success, <0 for errors
239  */
240 static int PLATFORM_HandleBlePowerStateEvent(ble_ps_event_t psEvent);
241 
242 /*!
243  * \brief Send Host sleep config to Controller
244  *
245  * \return int return status: >=0 for success, <0 for errors
246  */
247 static int PLATFORM_BleSetHostSleepConfig(void);
248 
249 void BLE_MCI_WAKEUP_DONE0_DriverIRQHandler(void);
250 
251 static void PLATFORM_FillInHciCmdMsg(uint8_t *pbuf, uint16_t opcode, uint8_t msg_sz, const uint8_t *msg_payload);
252 
253 /* -------------------------------------------------------------------------- */
254 /*                               Private memory                               */
255 /* -------------------------------------------------------------------------- */
256 
257 static RPMSG_HANDLE_DEFINE(hci_rpmsg_handle);
258 static hal_rpmsg_config_t hci_rpmsg_config = {
259     .local_addr  = 30,
260     .remote_addr = 40,
261     .imuLink     = (uint8_t)kIMU_LinkCpu2Cpu3,
262     .callback    = PLATFORM_HciRpmsgRxCallback,
263     .param       = NULL,
264 };
265 
266 static bool              initialized    = false;
267 static bool              hciInitialized = false;
268 static volatile ble_ps_t blePowerState  = ble_awake_state;
269 
270 static OSA_EVENT_HANDLE_DEFINE(wakeUpEventGroup);
271 static OSA_MUTEX_HANDLE_DEFINE(bleMutexHandle);
272 
273 static void (*hci_rx_callback)(uint8_t packetType, uint8_t *data, uint16_t len);
274 
275 /* -------------------------------------------------------------------------- */
276 /*                                Public memory                               */
277 /* -------------------------------------------------------------------------- */
278 
279 const uint8_t hci_cal_data_params[HCI_CMD_STORE_BT_CAL_DATA_PARAM_LENGTH] = {
280     0x00U,                            //  Sequence Number : 0x00
281     0x00U,                            //  Action : 0x00
282     0x01U,                            //  Type : Not use CheckSum
283     0x1CU,                            //  File Length : 0x1C
284     0x37U,                            //  BT Annex Type : BT CFG
285     0x71U,                            //  Checksum : 0x71
286     0x1CU,                            //  Annex Length LSB: 0x001C
287     0x00U,                            //  Annex Length MSB: 0x001C
288     0xFFU,                            //  Pointer For Next Annex[0] : 0xFFFFFFFF
289     0xFFU,                            //  Pointer For Next Annex[1] : 0xFFFFFFFF
290     0xFFU,                            //  Pointer For Next Annex[2] : 0xFFFFFFFF
291     0xFFU,                            //  Pointer For Next Annex[3] : 0xFFFFFFFF
292     0x01U,                            //  Annex Version : 0x01
293     0x7CU,                            //  External Xtal Calibration Value : 0x7C
294     0x04U,                            //  Initial TX Power : 0x04
295     BT_CAL_DATA_ANNEX_FRONT_END_LOSS, //  Front End Loss : 0x02 or 0x03
296     0x28U,                            //  BT Options :
297                                       //              BIT[0] Force Class 2 operation = 0
298                                       //              BIT[1] Disable Pwr Control for class 2= 0
299                                       //              BIT[2] MiscFlag(to indicagte external XTAL) = 0
300                                       //              BIT[3] Used Internal Sleep Clock = 1
301                                       //              BIT[4] BT AOA localtion support = 0
302                                       //              BIT[5] Force Class 1 mode = 1
303                                       //              BIT[7:6] Reserved
304     0x00U,                            //  AOANumberOfAntennas: 0x00
305     0x00U,                            //  RSSI Golden Low : 0
306     0x00U,                            //  RSSI Golden High : 0
307     0xC0U,                            //  UART Baud Rate[0] : 0x002DC6C0(3000000)
308     0xC6U,                            //  UART Baud Rate[1] : 0x002DC6C0(3000000)
309     0x2DU,                            //  UART Baud Rate[2] : 0x002DC6C0(3000000)
310     0x00U,                            //  UART Baud Rate[3] : 0x002DC6C0(3000000)
311     0x00U,                            //  BdAddress[0] : 0x000000000000
312     0x00U,                            //  BdAddress[1] : 0x000000000000
313     0x00U,                            //  BdAddress[2] : 0x000000000000
314     0x00U,                            //  BdAddress[3] : 0x000000000000
315     0x00U,                            //  BdAddress[4] : 0x000000000000
316     0x00U,                            //  BdAddress[5] : 0x000000000000
317     0xF0U,                            //  Encr_Key_Len[3:0]: MinEncrKeyLen = 0x0
318                                       //  Encr_Key_Len[7:4]: MaxEncrKeyLen = 0xF
319 #if defined(gPlatformEnableTxPowerChangeWithCountry_d) && (gPlatformEnableTxPowerChangeWithCountry_d == 0)
320     0x00U, //  RegionCode : 0x00
321 #else
322     0x00U, //  Reserved : 0x00
323 #endif /* gPlatformEnableTxPowerChangeWithCountry_d */
324 };
325 
326 #if !defined(gPlatformDisableSetBtCalDataAnnex100_d) || (gPlatformDisableSetBtCalDataAnnex100_d == 0)
327 /*
328  * a.The following parameters are used in three cases,
329  *    1.For share antenna case or ant2 with external FEM(ble only case).
330  *    2.diversity case(enable ant3)
331  *    3.diversity case(enable ant4)
332  */
333 const uint8_t hci_cal_data_annex100_params[HCI_CMD_STORE_BT_CAL_DATA_PARAM_ANNEX100_LENGTH] = {
334     /*                   BT_HW_INFO   START              */
335     0x64U, //  Annex Type : 0x64
336     0x00U, //  CheckSum: Annex100 ignores checksum
337     0x10U, //  Length-In-Byte : 0x0010
338     0x00U, //  Length-In-Byte : 0x0010
339     0xFFU, // Pointer for next annex structure : 0xFFFFFFFF
340     0xFFU, // Pointer for next annex structure : 0xFFFFFFFF
341     0xFFU, // Pointer for next annex structure : 0xFFFFFFFF
342     0xFFU, // Pointer for next annex structure : 0xFFFFFFFF
343     0x01U, // Ext_PA Gain : Bit[7:1]   Ext_PA Present : Bit[0]
344 #if defined(gPlatformEnableTxPowerChangeWithCountry_d) && (gPlatformEnableTxPowerChangeWithCountry_d == 0)
345     0x00U, // Ext_Ant Gain : Bit[4:1]   Ext_Ant Present : Bit[0]
346 #else
347     0x00U, // Reserved
348 #endif                                           /* gPlatformEnableTxPowerChangeWithCountry_d */
349     BT_CAL_DATA_ANNEX_100_EPA_FEM_MASK_LOW_BYTE, // BT_HW_INFO_EPA_FEM_Mask
350     0x00U,                                       // BT_HW_INFO_EPA_FEM_Mask
351     0x01U,                                       // Ext_LNA Present : Bit[0]   Ext_LNA Gain : Bit[7:1]
352     0x00U,                                       // multipurpose mask
353     BT_CAL_DATA_ANNEX_100_LNA_FEM_MASK_LOW_BYTE, // BT / LE ext LNA FEM BITMASK
354     0x00U,                                       // BT / LE ext LNA FEM BITMASK
355     /*                   BT_HW_INFO   END              */
356 };
357 #endif
358 /* -------------------------------------------------------------------------- */
359 /*                              Public functions                              */
360 /* -------------------------------------------------------------------------- */
361 
PLATFORM_InitBle(void)362 int PLATFORM_InitBle(void)
363 {
364     int          ret = 0;
365     osa_status_t status;
366 
367     /* PLATFORM_InitBle can be called from OT or Ethermind context in multi mode applications
368      * The 'initialized' variable will be set to true only when the initialization is complete
369      * We have to protect the initialization flow with a mutex to make sure the first task completes the initialization
370      * before the second reads 'initialized' */
371     status = OSA_MutexCreate((osa_mutex_handle_t)bleMutexHandle);
372     assert(status == KOSA_StatusSuccess);
373     status = OSA_MutexLock((osa_mutex_handle_t)bleMutexHandle, osaWaitForever_c);
374     assert(status == KOSA_StatusSuccess);
375 
376     do
377     {
378         if (initialized == true)
379         {
380             break;
381         }
382         status = OSA_EventCreate((osa_event_handle_t)wakeUpEventGroup, 0);
383         assert(status == KOSA_StatusSuccess);
384 
385         /* Initialize BLE controller */
386         ret = PLATFORM_InitControllers(connBle_c);
387         if (ret != 0)
388         {
389             ret = -1;
390             break;
391         }
392 
393         /* Initialize HCI link with BLE CPU */
394         ret = PLATFORM_InitHciLink();
395         if (ret != 0)
396         {
397             ret = -2;
398             break;
399         }
400 
401         /* Configure BLE Wakeup done interrupt */
402         NVIC_SetPriority(BLE_MCI_WAKEUP_DONE0_IRQn, MCI_WAKEUP_DONE_PRIORITY);
403 
404         initialized = true;
405         /* after re-init cpu2, Reset blePowerState to ble_awake_state. */
406         blePowerState = ble_awake_state;
407     } while (false);
408 
409     status = OSA_MutexUnlock((osa_mutex_handle_t)bleMutexHandle);
410     assert(status == KOSA_StatusSuccess);
411     (void)status;
412 
413     return ret;
414 }
415 
PLATFORM_VendorSpecificInit(void)416 void PLATFORM_VendorSpecificInit(void)
417 {
418 #if !defined(gPlatformDisableSetBtCalData_d) || (gPlatformDisableSetBtCalData_d == 0)
419     /* Send the BT Cal Data to Controller */
420     (void)PLATFORM_SetBtCalData();
421 #if !defined(gPlatformDisableSetBtCalDataAnnex100_d) || (gPlatformDisableSetBtCalDataAnnex100_d == 0)
422     /* After send annex55 to CPU2, CPU2 need reset,
423        a delay of at least 20ms is required to continue sending annex100*/
424     OSA_TimeDelay(BLE_RESET_DELAY_MS);
425 
426     /* Send the BT Cal Data annex100 to Controller */
427     (void)PLATFORM_SetBtCalDataAnnex100();
428 #endif
429 #endif
430 
431     (void)PLATFORM_BleSetHostSleepConfig();
432 
433 #if !defined(gPlatformDisableBleLowPower_d) || (gPlatformDisableBleLowPower_d == 0)
434     /* Allow Controller to enter low power */
435     (void)PLATFORM_EnableBleLowPower();
436 #endif
437 }
438 
PLATFORM_TerminateBle(void)439 int PLATFORM_TerminateBle(void)
440 {
441     int ret = 0;
442 
443     do
444     {
445         if (initialized == false)
446         {
447             break;
448         }
449 
450         if (PLATFORM_TerminateHciLink() != 0)
451         {
452             ret = -1;
453             break;
454         }
455 
456         if (PLATFORM_TerminateControllers((uint8_t)connBle_c) != 0) /* MISRA CID 26829044 */
457         {
458             ret = -2;
459             break;
460         }
461 
462         if (OSA_EventDestroy((osa_event_handle_t)wakeUpEventGroup) != KOSA_StatusSuccess)
463         {
464             ret = -3;
465             break;
466         }
467 
468         if (OSA_MutexDestroy((osa_mutex_handle_t)bleMutexHandle) != KOSA_StatusSuccess)
469         {
470             ret = -4;
471             break;
472         }
473 
474         initialized = false;
475         /* after re-init cpu2, Reset hciInitialized to false. */
476         hciInitialized = false;
477     } while (false);
478 
479     return ret;
480 }
481 
PLATFORM_ResetBle(void)482 int PLATFORM_ResetBle(void)
483 {
484     int ret = 0;
485 
486     do
487     {
488         if ((PLATFORM_GetRunningControllers() & conn802_15_4_c) != 0U)
489         {
490             /* Currently the CPU2 is running the combo firmware, so we should reset using this firmware */
491             PLATFORM_ResetOt();
492         }
493         else
494         {
495             if (PLATFORM_TerminateBle() != 0)
496             {
497                 ret = -1;
498                 break;
499             }
500 
501             if (PLATFORM_InitBle() != 0)
502             {
503                 ret = -2;
504                 break;
505             }
506         }
507 
508     } while (false);
509 
510     return ret;
511 }
512 
PLATFORM_StartHci(void)513 int PLATFORM_StartHci(void)
514 {
515     int ret = 0;
516 
517     do
518     {
519         if (hciInitialized == true)
520         {
521             break;
522         }
523 
524         while (PLATFORM_IsHciLinkReady() != true)
525         {
526         }
527 
528 #if !defined(gPlatformDisableVendorSpecificInit) || (gPlatformDisableVendorSpecificInit == 0)
529         /* This function call uses HCI vendor commands to configure the controller,
530          * this can cause troubles with some BLE Host. A host can send the HCI commands
531          * using its own API and then expect the right response from the controller, if the
532          * commands are sent under the hood using the framework, the host may receive anexpected
533          * responses which may lead to issues. In this case enable gPlatformDisableVendorSpecificInit.
534          */
535         PLATFORM_VendorSpecificInit();
536 #endif
537         hciInitialized = true;
538     } while (false);
539 
540     return ret;
541 }
542 
PLATFORM_SetHciRxCallback(void (* callback)(uint8_t packetType,uint8_t * data,uint16_t len))543 int PLATFORM_SetHciRxCallback(void (*callback)(uint8_t packetType, uint8_t *data, uint16_t len))
544 {
545     int ret = 0;
546 
547     hci_rx_callback = callback;
548 
549     return ret;
550 }
551 
PLATFORM_SendHciMessage(uint8_t * msg,uint32_t len)552 int PLATFORM_SendHciMessage(uint8_t *msg, uint32_t len)
553 {
554     int ret = 0;
555 
556 #ifdef SERIAL_BTSNOOP
557     sbtsnoop_write_hci_pkt(msg[0U], 0U, &msg[1], (uint16_t)(len - 1U));
558 #endif
559 
560     do
561     {
562         /* Before sending a HCI message, we have to make sure the Controller is
563          * awake */
564         ret = PLATFORM_RequestBleWakeUp();
565         if (ret != 0)
566         {
567             ret = -1;
568             break;
569         }
570 
571         /* Send HCI Packet through RPMSG channel */
572         if (HAL_RpmsgSend(hci_rpmsg_handle, msg, len) != kStatus_HAL_RpmsgSuccess)
573         {
574             ret = -2;
575             break;
576         }
577 
578         /* Release the wake up request now */
579         ret = PLATFORM_ReleaseBleWakeUp();
580         if (ret != 0)
581         {
582             ret = -3;
583             break;
584         }
585     } while (false);
586 
587     return ret;
588 }
589 
PLATFORM_EnableBleLowPower(void)590 int PLATFORM_EnableBleLowPower(void)
591 {
592     int           ret = 0;
593     uint8_t       buffer[1 + HCI_CMD_PACKET_HEADER_LENGTH + HCI_CMD_SET_BT_SLEEP_MODE_PARAM_LENGTH];
594     uint16_t      opcode = get_opcode(HCI_CMD_VENDOR_OCG, HCI_CMD_SET_BT_SLEEP_MODE_OCF);
595     const uint8_t params[HCI_CMD_SET_BT_SLEEP_MODE_PARAM_LENGTH] = {
596         0x02U, // Auto sleep enable
597         0x00U, // Idle timeout LSB
598         0x00U  // Idle timeout MSB
599     };
600 
601     PLATFORM_FillInHciCmdMsg(&buffer[0], opcode, (uint8_t)sizeof(params), params);
602 
603     ret = PLATFORM_SendHciMessage(buffer, sizeof(buffer));
604     if (ret != 0)
605     {
606         ret = -1;
607     }
608 
609     return ret;
610 }
611 
PLATFORM_DisableBleLowPower(void)612 int PLATFORM_DisableBleLowPower(void)
613 {
614     int           ret = 0;
615     uint8_t       buffer[1 + HCI_CMD_PACKET_HEADER_LENGTH + HCI_CMD_SET_BT_SLEEP_MODE_PARAM_LENGTH];
616     uint16_t      opcode = get_opcode(HCI_CMD_VENDOR_OCG, HCI_CMD_SET_BT_SLEEP_MODE_OCF);
617     const uint8_t params[HCI_CMD_SET_BT_SLEEP_MODE_PARAM_LENGTH] = {
618         0x03U, // Auto sleep disable
619         0x00U, // Idle timeout LSB
620         0x00U  // Idle timeout MSB
621     };
622 
623     PLATFORM_FillInHciCmdMsg(buffer, opcode, (uint8_t)sizeof(params), params);
624 
625     ret = PLATFORM_SendHciMessage(buffer, sizeof(buffer));
626     if (ret != 0)
627     {
628         ret = -1;
629     }
630 
631     return ret;
632 }
633 
PLATFORM_RequestBleWakeUp(void)634 int PLATFORM_RequestBleWakeUp(void)
635 {
636     int               ret = 0;
637     osa_status_t      status;
638     osa_event_flags_t events = 0;
639     /* The request can come from different tasks (BLE or OT), but only one request should be performed at the same
640      * time. The mutex ensures only one task is waking up the CPU2 at a time. */
641 
642     if (OSA_MutexLock((osa_mutex_handle_t)bleMutexHandle, osaWaitForever_c) != KOSA_StatusSuccess)
643     {
644         /* shouldn't happen */
645         assert(0);
646     }
647 
648     if (PLATFORM_IsBleAwake() == false)
649     {
650         /* After operate menu 130, there is a pending interrupt,
651          * before enableIRQ, clear pending interrupt */
652         NVIC_ClearPendingIRQ(BLE_MCI_WAKEUP_DONE0_IRQn);
653 
654         /* Controller is in low power, we need to wake it up with PMU
655          * and wait for the wake up done interrupt to make sure it is
656          * completely awake and ready to receive a message */
657         NVIC_EnableIRQ(BLE_MCI_WAKEUP_DONE0_IRQn);
658 
659         /* Wake up BLE core with PMU BLE_WAKEUP bit
660          * This bit is maintained until we receive a BLE_MCI_WAKEUP_DONE0
661          * interrupt */
662         PMU_EnableBleWakeup(0x1U);
663 
664         /* Suspend the current task waiting for the Controller to be awake */
665         status = OSA_EventWait((osa_event_handle_t)wakeUpEventGroup, (uint32_t)ble_awake_event, 1,
666                                PLATFORM_BLE_WAKE_UP_TIMEOUT_MS, &events);
667         if (((events & (uint32_t)ble_awake_event) == 0U) || (status != KOSA_StatusSuccess))
668         {
669             ret = -1;
670         }
671     }
672 
673     if (OSA_MutexUnlock((osa_mutex_handle_t)bleMutexHandle) != KOSA_StatusSuccess)
674     {
675         ret = -1;
676     }
677 
678     return ret;
679 }
680 
PLATFORM_ReleaseBleWakeUp(void)681 int PLATFORM_ReleaseBleWakeUp(void)
682 {
683     int ret = 0;
684     /* Nothing to do, the BLE controller awakes with a one shot interrupt from PMU
685      * For now, there's no mechanism to force it active for a defined period of time
686      * The only concern is if the CPU2 has time to re-enter sleep while CPU3 still
687      * needs CPU2 power domain ressources such as IMU/SMU
688      * TODO: Use GPIO output from CPU2 to track sleep/active periods and measure
689      * the minimal time before CPU2 re-enters sleep after a wake up */
690     return ret;
691 }
692 
BLE_MCI_WAKEUP_DONE0_DriverIRQHandler(void)693 void BLE_MCI_WAKEUP_DONE0_DriverIRQHandler(void)
694 {
695     /* The Controller is awake, we can clear BLE wake up interrupt */
696     PMU_DisableBleWakeup(0x1U);
697     NVIC_DisableIRQ(BLE_MCI_WAKEUP_DONE0_IRQn);
698 }
699 
PLATFORM_HandleControllerPowerState(void)700 int PLATFORM_HandleControllerPowerState(void)
701 {
702     int ret = 0;
703 
704     /* Controller can send data or event directly to Host without
705      * PS_AWAKE indication, the host needs to update the power state */
706     ret = PLATFORM_HandleBlePowerStateEvent(ble_awake_event);
707 
708     /* Unblock any sending task waiting for wake up */
709     if (OSA_EventSet((osa_event_handle_t)wakeUpEventGroup, (uint32_t)ble_awake_event) != KOSA_StatusSuccess)
710     {
711         ret = -1;
712     }
713 
714     return ret;
715 }
716 
717 /* -------------------------------------------------------------------------- */
718 /*                              Private functions                             */
719 /* -------------------------------------------------------------------------- */
720 
PLATFORM_InitHciLink(void)721 static int PLATFORM_InitHciLink(void)
722 {
723     int ret = 0;
724 
725     do
726     {
727         /* Init RPMSG/IMU Channel */
728         if (HAL_RpmsgInit((hal_rpmsg_handle_t)hci_rpmsg_handle, &hci_rpmsg_config) != kStatus_HAL_RpmsgSuccess)
729         {
730             ret = -1;
731             break;
732         }
733     } while (false);
734 
735     return ret;
736 }
737 
PLATFORM_TerminateHciLink(void)738 static int PLATFORM_TerminateHciLink(void)
739 {
740     int ret = 0;
741 
742     do
743     {
744         /* Force wake up CPU2 before send IMU_MSG_CONTROL_SHUTDOWN in HAL_ImuDeinit() */
745         PMU_EnableBleWakeup(0x1U);
746 
747         /* Deinitialize IMU first
748          * Ignoring return value because kStatus_HAL_RpmsgError means it was already deinitialize */
749         (void)HAL_ImuDeinit(kIMU_LinkCpu2Cpu3, 0);
750 
751         /* Clear CPU2 wake up bit after HAL_ImuDeinit() */
752         PMU_DisableBleWakeup(0x1U);
753 
754         /* Deinitialize RPMSG first */
755         if (HAL_RpmsgDeinit(hci_rpmsg_handle) != kStatus_HAL_RpmsgSuccess)
756         {
757             ret = -2;
758             break;
759         }
760     } while (false);
761 
762     return ret;
763 }
764 
PLATFORM_IsHciLinkReady(void)765 static bool PLATFORM_IsHciLinkReady(void)
766 {
767     return (HAL_ImuLinkIsUp(hci_rpmsg_config.imuLink) == kStatus_HAL_RpmsgSuccess);
768 }
769 
PLATFORM_IsBleAwake(void)770 static bool PLATFORM_IsBleAwake(void)
771 {
772     return (blePowerState != ble_asleep_state);
773 }
774 
PLATFORM_HciRpmsgRxCallback(void * param,uint8_t * data,uint32_t len)775 static hal_rpmsg_return_status_t PLATFORM_HciRpmsgRxCallback(void *param, uint8_t *data, uint32_t len)
776 {
777     bool    handled    = false;
778     uint8_t packetType = data[0];
779 
780     (void)param;
781 
782     (void)PLATFORM_HandleControllerPowerState();
783 
784     /* If the macro BLE_VENDOR_EVENT_HANDLE is set to true, PLATFORM module will check if it can handle Vendor Specific
785      * Events without going through Ethermind's HCI tasks If the packet is not handled, then it is sent to upper layers
786      * This is likely used to handle Controller low power state, so this is
787      * completely transparent to the application. If the macro BLE_VENDOR_EVENT_HANDLE is set false, the Ethermind's HCI
788      * tasks will handle vendor event */
789     if (packetType == HCI_EVENT_PACKET)
790     {
791         uint8_t eventType = data[1];
792 
793         if (eventType == HCI_VENDOR_SPECIFIC_DEBUG_EVENT)
794         {
795             /* Received packet is a Vendor Specific event, check if PLATFORM
796              * can process it, if not, it will be sent to Ethermind */
797             handled = PLATFORM_HandleHciVendorEvent(&data[3], data[2]);
798         }
799     }
800 
801     if ((handled == false) && (hci_rx_callback != NULL))
802     {
803         hci_rx_callback(packetType, &data[1], (uint16_t)(len - 1U));
804     }
805 
806 #ifdef SERIAL_BTSNOOP
807     sbtsnoop_write_hci_pkt(data[0U], 1U, &data[1], (uint16_t)(len - 1U));
808 #endif
809 
810     return kStatus_HAL_RL_RELEASE;
811 }
812 
PLATFORM_SetBtCalData(void)813 static int PLATFORM_SetBtCalData(void)
814 {
815     int      ret = 0;
816     uint8_t  buffer[1 + HCI_CMD_PACKET_HEADER_LENGTH + HCI_CMD_STORE_BT_CAL_DATA_PARAM_LENGTH];
817     uint16_t opcode = get_opcode(HCI_CMD_VENDOR_OCG, HCI_CMD_STORE_BT_CAL_DATA_OCF);
818 
819     PLATFORM_FillInHciCmdMsg(buffer, opcode, (uint8_t)sizeof(hci_cal_data_params), hci_cal_data_params);
820 
821     ret = PLATFORM_SendHciMessage(buffer, sizeof(buffer));
822     if (ret != 0)
823     {
824         ret = -1;
825     }
826 
827     return ret;
828 }
829 
830 #if !defined(gPlatformDisableSetBtCalDataAnnex100_d) || (gPlatformDisableSetBtCalDataAnnex100_d == 0)
PLATFORM_SetBtCalDataAnnex100(void)831 static int PLATFORM_SetBtCalDataAnnex100(void)
832 {
833     int      ret = 0;
834     uint8_t  bufferAnnex100[1 + HCI_CMD_PACKET_HEADER_LENGTH + HCI_CMD_STORE_BT_CAL_DATA_PARAM_ANNEX100_LENGTH];
835     uint16_t opcodeAnnex100 = get_opcode(HCI_CMD_VENDOR_OCG, HCI_CMD_STORE_BT_CAL_DATA_ANNEX100_OCF);
836 
837     PLATFORM_FillInHciCmdMsg(bufferAnnex100, opcodeAnnex100, (uint8_t)sizeof(hci_cal_data_annex100_params),
838                              hci_cal_data_annex100_params);
839 
840     ret = PLATFORM_SendHciMessage(bufferAnnex100, sizeof(bufferAnnex100));
841     if (ret != 0)
842     {
843         ret = -1;
844     }
845 
846     return ret;
847 }
848 #endif /* gPlatformDisableSetBtCalDataAnnex100_d */
849 
PLATFORM_HandleHciVendorEvent(uint8_t * eventData,uint32_t len)850 static bool PLATFORM_HandleHciVendorEvent(uint8_t *eventData, uint32_t len)
851 {
852     uint8_t vEventType = eventData[0];
853     bool    handled    = BLE_VENDOR_EVENT_HANDLE;
854 
855     assert(eventData != NULL);
856     assert(len > 0U);
857 
858     switch (vEventType)
859     {
860         case HCI_CMD_SET_BT_SLEEP_MODE_OCF:
861             break;
862 
863         case HCI_EVT_PS_SLEEP_OCF:
864             (void)PLATFORM_HandleBlePowerStateEvent((ble_ps_event_t)eventData[1]);
865             break;
866 
867         case HCI_CMD_BT_HIU_HS_ENABLE_OCF:
868             break;
869 
870         default:
871             handled = false;
872             break;
873     }
874 
875     return handled;
876 }
877 
PLATFORM_HandleBlePowerStateEvent(ble_ps_event_t psEvent)878 static int PLATFORM_HandleBlePowerStateEvent(ble_ps_event_t psEvent)
879 {
880     int ret = 0;
881 
882     switch (blePowerState)
883     {
884         case ble_awake_state:
885         {
886             switch (psEvent)
887             {
888                 case ble_asleep_event:
889                     blePowerState = ble_asleep_state;
890                     /* Make sure to clear wake up event */
891                     if (OSA_EventClear((osa_event_handle_t)wakeUpEventGroup, (uint32_t)ble_awake_event) !=
892                         KOSA_StatusSuccess)
893                     {
894                         ret = -1;
895                     }
896                     break;
897 
898                 default:
899                     break;
900             }
901         }
902         break;
903 
904         case ble_asleep_state:
905         {
906             switch (psEvent)
907             {
908                 case ble_awake_event:
909                     blePowerState = ble_awake_state;
910                     break;
911 
912                 default:
913                     break;
914             }
915         }
916         break;
917 
918         default:
919             ret = -1;
920             break;
921     }
922 
923     return ret;
924 }
925 
PLATFORM_BleSetHostSleepConfig(void)926 static int PLATFORM_BleSetHostSleepConfig(void)
927 {
928     int ret = 0;
929     /* This command must be sent before sending any power commands, likely
930      * after HCI init  */
931     uint8_t       buffer[1 + HCI_CMD_PACKET_HEADER_LENGTH + HCI_CMD_BT_HOST_SLEEP_CONFIG_PARAM_LENGTH];
932     uint16_t      opcode = get_opcode(HCI_CMD_VENDOR_OCG, HCI_CMD_BT_HOST_SLEEP_CONFIG_OCF);
933     const uint8_t params[HCI_CMD_BT_HOST_SLEEP_CONFIG_PARAM_LENGTH] = {
934         0xFFU, // BT_HIU_WAKEUP_INBAND
935         0xFFU, // BT_HIU_WAKE_GAP_WAIT_FOR_IRQ
936     };
937 
938     PLATFORM_FillInHciCmdMsg(buffer, opcode, (uint8_t)sizeof(params), params);
939 
940     ret = PLATFORM_SendHciMessage(buffer, sizeof(buffer));
941     if (ret != 0)
942     {
943         ret = -1;
944     }
945 
946     return ret;
947 }
948 
PLATFORM_FillInHciCmdMsg(uint8_t * pbuf,uint16_t opcode,uint8_t msg_sz,const uint8_t * msg_payload)949 static void PLATFORM_FillInHciCmdMsg(uint8_t *pbuf, uint16_t opcode, uint8_t msg_sz, const uint8_t *msg_payload)
950 {
951     pbuf[0] = HCI_COMMAND_PACKET;
952     pbuf[1] = (uint8_t)(opcode & 0xff);
953     pbuf[2] = (uint8_t)((uint32_t)(opcode >> 8) & 0xff);
954     pbuf[3] = msg_sz;
955     (void)memcpy(&pbuf[4], msg_payload, msg_sz);
956 }
957