1 /*******************************************************************************
2 * \file cybt_patchram_download.c
3 *
4 * \brief
5 * Implement the mechanism of BT firmware download during WICED BT stack
6 * initialization.
7 *
8 ********************************************************************************
9 * \copyright
10 * Copyright 2018-2019 Cypress Semiconductor Corporation
11 * SPDX-License-Identifier: Apache-2.0
12 *
13 * Licensed under the Apache License, Version 2.0 (the "License");
14 * you may not use this file except in compliance with the License.
15 * You may obtain a copy of the License at
16 *
17 *     http://www.apache.org/licenses/LICENSE-2.0
18 *
19 * Unless required by applicable law or agreed to in writing, software
20 * distributed under the License is distributed on an "AS IS" BASIS,
21 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 * See the License for the specific language governing permissions and
23 * limitations under the License.
24 *******************************************************************************/
25 
26 #include "cyabs_rtos.h"
27 
28 #include "wiced_bt_dev.h"
29 #include "wiced_bt_stack_platform.h"
30 
31 #include "cybt_prm.h"
32 #include "cybt_platform_config.h"
33 #include "cybt_platform_hci.h"
34 #include "cybt_platform_trace.h"
35 #include "cybt_platform_util.h"
36 
37 
38 /******************************************************************************
39  *                                Constants
40  ******************************************************************************/
41 #define HCI_VSC_UPDATE_BAUDRATE_CMD                (0xFC18)
42 #define HCI_VSC_UPDATE_BAUD_RATE_UNENCODED_LENGTH  (6)
43 
44 
45 /*****************************************************************************
46  *                           Type Definitions
47  *****************************************************************************/
48 typedef enum
49 {
50     BT_POST_RESET_STATE_IDLE = 0x00,
51     BT_POST_RESET_STATE_UPDATE_BAUDRATE_FOR_FW_DL,
52     BT_POST_RESET_STATE_FW_DOWNLOADING,
53     BT_POST_RESET_STATE_FW_DOWNLOAD_COMPLETED,
54     BT_POST_RESET_STATE_UPDATE_BAUDRATE_FOR_FEATURE,
55     BT_POST_RESET_STATE_DONE,
56     BT_POST_RESET_STATE_FAILED
57 } bt_post_reset_state_e;
58 
59 typedef struct
60 {
61     bt_post_reset_state_e  state;
62 } bt_fw_download_cb;
63 
64 /******************************************************************************
65  *                           Variables Definitions
66  ******************************************************************************/
67 bt_fw_download_cb bt_fwdl_cb = {.state = BT_POST_RESET_STATE_IDLE};
68 
69 extern const char    brcm_patch_version[];
70 extern const uint8_t brcm_patchram_buf[];
71 extern const int     brcm_patch_ram_length;
72 extern const uint8_t brcm_patchram_format;
73 
74 /*****************************************************************************
75  *                           Function Declarations
76  *****************************************************************************/
77 static void bt_baudrate_updated_cback (wiced_bt_dev_vendor_specific_command_complete_params_t* p);
78 static void bt_fw_download_complete_cback(cybt_prm_status_t status);
79 void bt_post_reset_cback(void);
80 void cybt_platform_hci_wait_for_boot_fully_up(bool is_from_isr);
81 
82 /******************************************************************************
83  *                           Function Definitions
84  ******************************************************************************/
bt_start_fw_download(void)85 static void bt_start_fw_download(void)
86 {
87     const cybt_platform_config_t *p_bt_platform_cfg = cybt_platform_get_config();
88     bool download_mini_driver = (p_bt_platform_cfg->hci_config.hci_transport == CYBT_HCI_UART) ? true : false;
89     bool status;
90 
91     MAIN_TRACE_DEBUG("bt_start_fw_download(): FW ver = %s", (const char *) brcm_patch_version);
92 
93     bt_fwdl_cb.state = BT_POST_RESET_STATE_FW_DOWNLOADING;
94 
95     // Avoid sleep while downloading firmware
96     cyhal_syspm_lock_deepsleep();
97 
98     status = cybt_prm_download(bt_fw_download_complete_cback,
99                       brcm_patchram_buf,
100                       brcm_patch_ram_length,
101                       0,
102                       CYBT_PRM_FORMAT_HCD,
103                       download_mini_driver
104                       );
105     if (status == false)
106     {
107         cyhal_syspm_unlock_deepsleep();
108     }
109 }
110 
bt_update_platform_baudrate(uint32_t baudrate)111 static void bt_update_platform_baudrate(uint32_t baudrate)
112 {
113     MAIN_TRACE_DEBUG("bt_update_platform_baudrate(): %d", baudrate);
114 
115     cy_rtos_delay_milliseconds(100);
116 
117     cybt_platform_hci_set_baudrate(baudrate);
118 
119     cy_rtos_delay_milliseconds(100);
120 }
121 
bt_update_controller_baudrate(uint32_t baudrate)122 static void bt_update_controller_baudrate(uint32_t baudrate)
123 {
124     uint8_t       hci_data[HCI_VSC_UPDATE_BAUD_RATE_UNENCODED_LENGTH];
125 
126     MAIN_TRACE_DEBUG("bt_update_controller_baudrate(): %d", baudrate);
127 
128     /* Baudrate is loaded LittleEndian */
129     hci_data[0] = 0;
130     hci_data[1] = 0;
131     hci_data[2] = baudrate & 0xFF;
132     hci_data[3] = (baudrate >> 8) & 0xFF;
133     hci_data[4] = (baudrate >> 16) & 0xFF;
134     hci_data[5] = (baudrate >> 24) & 0xFF;
135 
136     /* Send the command to the host controller */
137     wiced_bt_dev_vendor_specific_command(HCI_VSC_UPDATE_BAUDRATE_CMD,
138                                          HCI_VSC_UPDATE_BAUD_RATE_UNENCODED_LENGTH,
139                                          hci_data,
140                                          bt_baudrate_updated_cback
141                                          );
142 }
143 
bt_baudrate_updated_cback(wiced_bt_dev_vendor_specific_command_complete_params_t * p)144 static void bt_baudrate_updated_cback (wiced_bt_dev_vendor_specific_command_complete_params_t* p)
145 {
146     const cybt_platform_config_t *p_bt_platform_cfg = cybt_platform_get_config();
147 
148     switch(bt_fwdl_cb.state)
149     {
150         case BT_POST_RESET_STATE_UPDATE_BAUDRATE_FOR_FW_DL:
151         {
152             MAIN_TRACE_DEBUG("bt_baudrate_updated_cback(): Baudrate is updated for FW downloading");
153             bt_update_platform_baudrate(p_bt_platform_cfg->hci_config.hci.hci_uart.baud_rate_for_fw_download);
154 
155             bt_start_fw_download();
156         }
157             break;
158         case BT_POST_RESET_STATE_UPDATE_BAUDRATE_FOR_FEATURE:
159         {
160             MAIN_TRACE_DEBUG("bt_baudrate_updated_cback(): Baudrate is updated for feature");
161             bt_update_platform_baudrate(p_bt_platform_cfg->hci_config.hci.hci_uart.baud_rate_for_feature);
162 
163             MAIN_TRACE_DEBUG("bt_baudrate_updated_cback(): post-reset process is done");
164             bt_fwdl_cb.state = BT_POST_RESET_STATE_DONE;
165 
166             wiced_bt_continue_reset();
167         }
168             break;
169         default:
170             MAIN_TRACE_ERROR("bt_baudrate_updated_cback(): unknown state(%d)",
171                              bt_fwdl_cb.state
172                              );
173             break;
174     }
175 }
176 
bt_fw_download_complete_cback(cybt_prm_status_t status)177 static void bt_fw_download_complete_cback(cybt_prm_status_t status)
178 {
179     MAIN_TRACE_DEBUG("bt_patch_download_complete_cback(): status = %d", status);
180 
181     if(CYBT_PRM_STS_COMPLETE == status)
182     {
183         const cybt_platform_config_t *p_bt_platform_cfg = cybt_platform_get_config();
184         bt_fwdl_cb.state = BT_POST_RESET_STATE_FW_DOWNLOAD_COMPLETED;
185 
186         if(CYBT_HCI_UART == p_bt_platform_cfg->hci_config.hci_transport)
187         {
188             // After patch ram is launched, the baud rate of BT chip is reset to 115200
189             if( HCI_UART_DEFAULT_BAUDRATE != p_bt_platform_cfg->hci_config.hci.hci_uart.baud_rate_for_fw_download )
190             {
191                 MAIN_TRACE_DEBUG("bt_fw_download_complete_cback(): Reset baudrate to %d",
192                                  HCI_UART_DEFAULT_BAUDRATE);
193                 bt_update_platform_baudrate(HCI_UART_DEFAULT_BAUDRATE);
194             }
195 
196             if( HCI_UART_DEFAULT_BAUDRATE != p_bt_platform_cfg->hci_config.hci.hci_uart.baud_rate_for_feature )
197             {
198                 MAIN_TRACE_DEBUG("bt_fw_download_complete_cback(): Changing baudrate to %d",
199                                  p_bt_platform_cfg->hci_config.hci.hci_uart.baud_rate_for_feature);
200 
201                 bt_fwdl_cb.state = BT_POST_RESET_STATE_UPDATE_BAUDRATE_FOR_FEATURE;
202                 bt_update_controller_baudrate(p_bt_platform_cfg->hci_config.hci.hci_uart.baud_rate_for_feature);
203 
204                 // Unlock sleep which was invoked before starting FW download
205                 cyhal_syspm_unlock_deepsleep();
206                 return;
207             }
208         }
209 
210         MAIN_TRACE_DEBUG("bt_fw_download_complete_cback(): post-reset process is Done");
211 
212         bt_fwdl_cb.state = BT_POST_RESET_STATE_DONE;
213         if(CYBT_HCI_IPC == p_bt_platform_cfg->hci_config.hci_transport)
214             cybt_platform_hci_wait_for_boot_fully_up( false );
215         wiced_bt_continue_reset();
216     }
217     else
218     {
219         MAIN_TRACE_ERROR("bt_patch_download_complete_cback(): Failed (%d)",
220                          status
221                          );
222         bt_fwdl_cb.state = BT_POST_RESET_STATE_FAILED;
223     }
224 
225     // Unlock sleep which was invoked before starting FW download
226     cyhal_syspm_unlock_deepsleep();
227 }
228 
bt_post_reset_cback(void)229 void bt_post_reset_cback(void)
230 {
231     MAIN_TRACE_DEBUG("bt_post_reset_cback()");
232 
233     bt_fwdl_cb.state = BT_POST_RESET_STATE_IDLE;
234     if(0 < brcm_patch_ram_length)
235     {
236         const cybt_platform_config_t *p_bt_platform_cfg = cybt_platform_get_config();
237 
238         if( ( CYBT_HCI_UART == p_bt_platform_cfg->hci_config.hci_transport ) &&
239                 ( p_bt_platform_cfg->hci_config.hci.hci_uart.baud_rate_for_fw_download != HCI_UART_DEFAULT_BAUDRATE ))
240         {
241             MAIN_TRACE_DEBUG("bt_post_reset_cback(): Change baudrate (%d) for FW downloading",
242                              p_bt_platform_cfg->hci_config.hci.hci_uart.baud_rate_for_fw_download);
243             bt_fwdl_cb.state = BT_POST_RESET_STATE_UPDATE_BAUDRATE_FOR_FW_DL;
244             bt_update_controller_baudrate(p_bt_platform_cfg->hci_config.hci.hci_uart.baud_rate_for_fw_download);
245             return;
246         }
247 
248         MAIN_TRACE_DEBUG("bt_post_reset_cback(): Starting FW download...");
249         bt_start_fw_download();
250     }
251     else
252     {
253         MAIN_TRACE_ERROR("bt_post_reset_cback(): invalid length");
254     }
255 }
256 
257