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