1 /* 2 * Copyright (C) 2023 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 #define BTSTACK_FILE__ "btstack_chipset_nxp.c" 39 40 #include "btstack_chipset_nxp.h" 41 #include "btstack_debug.h" 42 #include "btstack_event.h" 43 44 #include <stdio.h> 45 46 #ifdef _MSC_VER 47 // ignore deprecated warning for fopen 48 #pragma warning(disable : 4996) 49 #endif 50 51 // Firmware download protocol constants 52 #define NXP_V1_FIRMWARE_REQUEST_PACKET 0xa5 53 #define NXP_V1_CHIP_VERION_PACKET 0xaa 54 #define NXP_V3_FIRMWARE_REQUEST_PACKET 0xa7 55 #define NXP_V3_CHIP_VERSION_PACKET 0xab 56 57 #define NXP_ACK_V1 0x5a 58 #define NXP_NAK_V1 0xbf 59 #define NXP_ACK_V3 0x7a 60 #define NXP_NAK_V3 0x7b 61 #define NXP_CRC_ERROR_V3 0x7c 62 63 // chip ids 64 #define NXP_CHIP_ID_W9098 0x5c03 65 #define NXP_CHIP_ID_IW416 0x7201 66 #define NXP_CHIP_ID_IW612 0x7601 67 68 // firmwares 69 #define NXP_FIRMWARE_W9098 "uartuart9098_bt_v1.bin" 70 #define NXP_FIRMWARE_IW416 "uartiw416_bt_v0.bin" 71 #define NXP_FIRMWARE_IW612 "uartspi_n61x_v1.bin.se" 72 73 #define NXP_MAX_RESEND_COUNT 5 74 75 // vendor commands 76 #define NXP_OPCODE_SET_SCO_DATA_PATH 0xFC1D 77 #define NXP_OPCODE_SET_BDADDR 0xFC22 78 79 // prototypes 80 static void nxp_send_chunk_v1(void); 81 static void nxp_done_with_status(uint8_t status); 82 static void nxp_send_chunk_v3(void); 83 static void nxp_read_uart_handler(void); 84 static void nxp_start(void); 85 86 // globals 87 static void (*nxp_download_complete)(uint8_t status); 88 static const btstack_uart_t * nxp_uart_driver; 89 static bool nxp_have_firmware; 90 91 static uint16_t nxp_chip_id; 92 93 static const uint8_t * nxp_fw_data; 94 static uint32_t nxp_fw_size; 95 static uint32_t nxp_fw_offset; 96 97 static uint8_t nxp_input_buffer[10]; 98 static uint16_t nxp_input_pos; 99 static uint16_t nxp_input_bytes_requested; 100 101 static uint8_t nxp_output_buffer[2048 + 1]; 102 103 static const uint8_t nxp_ack_buffer_v1[] = {NXP_ACK_V1 }; 104 static const uint8_t nxp_ack_buffer_v3[] = {NXP_ACK_V3, 0x92 }; 105 106 static uint16_t nxp_fw_request_len; 107 static uint8_t nxp_fw_resend_count; 108 109 static enum { 110 NXP_TX_IDLE, 111 NXP_TX_SEND_CHUNK_V1, 112 NXP_TX_SEND_CHUNK_V3, 113 } nxp_tx_state; 114 115 #ifdef HAVE_POSIX_FILE_IO 116 static char nxp_firmware_path[1000]; 117 static FILE * nxp_firmware_file; 118 119 static char *nxp_fw_name_from_chipid(uint16_t chip_id) 120 { 121 switch (chip_id) { 122 case NXP_CHIP_ID_W9098: 123 return NXP_FIRMWARE_W9098; 124 case NXP_CHIP_ID_IW416: 125 return NXP_FIRMWARE_IW416; 126 case NXP_CHIP_ID_IW612: 127 return NXP_FIRMWARE_IW612; 128 default: 129 log_error("Unknown chip id 0x%04x", chip_id); 130 return NULL; 131 } 132 } 133 134 static void nxp_load_firmware(void) { 135 if (nxp_firmware_file == NULL){ 136 log_info("chipset-bcm: open file %s", nxp_firmware_path); 137 nxp_firmware_file = fopen(nxp_firmware_path, "rb"); 138 if (nxp_firmware_file != NULL){ 139 nxp_have_firmware = true; 140 } 141 } 142 143 } 144 static uint16_t nxp_read_firmware(uint16_t bytes_to_read, uint8_t * buffer) { 145 size_t bytes_read = fread(buffer, 1, bytes_to_read, nxp_firmware_file); 146 return bytes_read; 147 } 148 149 static void nxp_unload_firmware(void) { 150 btstack_assert(nxp_firmware_file != NULL); 151 fclose(nxp_firmware_file); 152 nxp_firmware_file = NULL; 153 } 154 #else 155 void nxp_load_firmware(void){ 156 nxp_have_firmware = true; 157 } 158 159 // read bytes from firmware file 160 static uint16_t nxp_read_firmware(uint16_t bytes_to_read, uint8_t * buffer){ 161 if (nxp_fw_request_len > nxp_fw_size - nxp_fw_offset){ 162 printf("fw_request_len %u > remaining file len %u\n", nxp_fw_request_len, nxp_fw_size - nxp_fw_offset); 163 return nxp_fw_size - nxp_fw_offset; 164 } 165 memcpy(buffer, &nxp_fw_data[nxp_fw_offset], bytes_to_read); 166 nxp_fw_offset += nxp_fw_request_len; 167 return bytes_to_read; 168 } 169 static void nxp_unload_firmware(void) { 170 } 171 #endif 172 173 static void nxp_dummy(void){ 174 } 175 176 static void nxp_send_ack_v1() { 177 printf("SEND: ack v1\n"); 178 nxp_uart_driver->send_block(nxp_ack_buffer_v1, sizeof(nxp_ack_buffer_v1)); 179 } 180 181 static void nxp_send_ack_v3() { 182 printf("SEND: ack v3\n"); 183 nxp_uart_driver->send_block(nxp_ack_buffer_v3, sizeof(nxp_ack_buffer_v3)); 184 } 185 186 static bool nxp_valid_packet(void){ 187 switch (nxp_input_buffer[0]){ 188 case NXP_V1_FIRMWARE_REQUEST_PACKET: 189 case NXP_V1_CHIP_VERION_PACKET: 190 // first two uint16_t should xor to 0xffff 191 return ((nxp_input_buffer[1] ^ nxp_input_buffer[3]) == 0xff) && ((nxp_input_buffer[2] ^ nxp_input_buffer [4]) == 0xff); 192 case NXP_V3_CHIP_VERSION_PACKET: 193 case NXP_V3_FIRMWARE_REQUEST_PACKET: 194 // TODO: check crc-8 195 return true; 196 default: 197 return false; 198 } 199 } 200 201 static void nxp_handle_chip_version_v1(void){ 202 printf("RECV: NXP_V1_CHIP_VER_PKT, id = 0x%x02, revision = 0x%02x\n", nxp_input_buffer[0], nxp_input_buffer[1]); 203 nxp_tx_state = NXP_TX_IDLE; 204 nxp_send_ack_v1(); 205 } 206 207 static void nxp_handle_chip_version_v3(void){ 208 nxp_chip_id = little_endian_read_16(nxp_input_buffer, 1); 209 btstack_strcpy(nxp_firmware_path, sizeof(nxp_firmware_path), nxp_fw_name_from_chipid(nxp_chip_id)); 210 printf("RECV: NXP_V3_CHIP_VER_PKT, id = 0x%04x, loader 0x%02x -> firmware '%s'\n", nxp_chip_id, nxp_input_buffer[3], nxp_firmware_path); 211 nxp_tx_state = NXP_TX_IDLE; 212 nxp_send_ack_v3(); 213 } 214 215 static void nxp_prepare_firmware(void){ 216 // get firmware 217 if (nxp_have_firmware == false){ 218 nxp_load_firmware(); 219 } 220 if (nxp_have_firmware == false){ 221 printf("No firmware found, abort\n"); 222 } 223 } 224 225 static void nxp_send_chunk_v1(void){ 226 if (nxp_fw_request_len == 0){ 227 printf("last chunk sent!\n"); 228 nxp_unload_firmware(); 229 nxp_done_with_status(ERROR_CODE_SUCCESS); 230 return; 231 } else if ((nxp_fw_request_len & 1) == 0){ 232 // update sttate 233 nxp_fw_offset += nxp_fw_request_len; 234 nxp_fw_resend_count = 0; 235 // read next firmware chunk 236 uint16_t bytes_read = nxp_read_firmware(nxp_fw_request_len, nxp_output_buffer); 237 if (bytes_read < nxp_fw_request_len){ 238 printf("only %u of %u bytes available, abort.\n", bytes_read, nxp_fw_request_len); 239 nxp_done_with_status(ERROR_CODE_HARDWARE_FAILURE); 240 return; 241 } 242 } else { 243 // resend last chunk if request len is odd 244 if (nxp_fw_resend_count >= NXP_MAX_RESEND_COUNT){ 245 printf("Resent last block %u times, abort.", nxp_fw_resend_count); 246 nxp_done_with_status(ERROR_CODE_HARDWARE_FAILURE); 247 return; 248 } 249 nxp_fw_resend_count++; 250 } 251 printf("SEND: firmware %08x - %u bytes (%u. try)\n", nxp_fw_offset, nxp_fw_request_len, nxp_fw_resend_count + 1); 252 nxp_tx_state = NXP_TX_IDLE; 253 nxp_uart_driver->send_block(nxp_output_buffer, nxp_fw_request_len); 254 } 255 256 static void nxp_send_chunk_v3(void){ 257 // update state 258 nxp_fw_offset += nxp_fw_request_len; 259 nxp_fw_resend_count = 0; 260 if (nxp_fw_request_len == 0){ 261 printf("last chunk sent!\n"); 262 nxp_unload_firmware(); 263 nxp_done_with_status(ERROR_CODE_SUCCESS); 264 return; 265 } 266 // read next firmware chunk 267 uint16_t bytes_read = nxp_read_firmware(nxp_fw_request_len, nxp_output_buffer); 268 if (bytes_read < nxp_fw_request_len){ 269 printf("only %u of %u bytes available, abort.\n", bytes_read, nxp_fw_request_len); 270 nxp_done_with_status(ERROR_CODE_HARDWARE_FAILURE); 271 return; 272 } 273 printf("SEND: firmware %08x - %u bytes (%u. try)\n", nxp_fw_offset, nxp_fw_request_len, nxp_fw_resend_count + 1); 274 nxp_tx_state = NXP_TX_IDLE; 275 nxp_uart_driver->send_block(nxp_output_buffer, nxp_fw_request_len); 276 } 277 278 static void nxp_handle_firmware_request_v1(void){ 279 nxp_fw_request_len = little_endian_read_16(nxp_input_buffer, 1); 280 printf("RECV: NXP_V1_FW_REQ_PKT, len %u\n", nxp_fw_request_len); 281 282 nxp_prepare_firmware(); 283 if (nxp_have_firmware == false){ 284 return; 285 } 286 nxp_tx_state = NXP_TX_SEND_CHUNK_V1; 287 nxp_send_ack_v1(); 288 } 289 290 static void nxp_handle_firmware_request_v3(void){ 291 nxp_fw_request_len = little_endian_read_16(nxp_input_buffer, 1); 292 printf("RECV: NXP_V3_FW_REQ_PKT, len %u\n", nxp_fw_request_len); 293 294 nxp_prepare_firmware(); 295 if (nxp_have_firmware == false){ 296 return; 297 } 298 nxp_tx_state = NXP_TX_SEND_CHUNK_V3; 299 nxp_send_ack_v3(); 300 } 301 302 static void nxp_start_read(uint16_t bytes_to_read){ 303 nxp_input_bytes_requested = bytes_to_read; 304 nxp_uart_driver->receive_block(&nxp_input_buffer[nxp_input_pos], bytes_to_read); 305 } 306 307 static void nxp_read_uart_handler(void){ 308 uint16_t bytes_to_read; 309 if (nxp_input_pos == 0){ 310 switch (nxp_input_buffer[0]){ 311 case NXP_V1_CHIP_VERION_PACKET: 312 case NXP_V3_CHIP_VERSION_PACKET: 313 case NXP_V1_FIRMWARE_REQUEST_PACKET: 314 nxp_input_pos++; 315 bytes_to_read = 4; 316 break; 317 case NXP_V3_FIRMWARE_REQUEST_PACKET: 318 nxp_input_pos++; 319 bytes_to_read = 9; 320 break; 321 default: 322 // invalid packet type, skip and get next byte 323 bytes_to_read = 1; 324 break; 325 } 326 nxp_start_read(bytes_to_read); 327 } else { 328 nxp_input_pos += nxp_input_bytes_requested; 329 printf("RECV: "); 330 printf_hexdump(nxp_input_buffer, nxp_input_pos); 331 switch (nxp_input_buffer[0]){ 332 case NXP_V1_CHIP_VERION_PACKET: 333 nxp_handle_chip_version_v1(); 334 break; 335 case NXP_V3_CHIP_VERSION_PACKET: 336 nxp_handle_chip_version_v3(); 337 break; 338 case NXP_V1_FIRMWARE_REQUEST_PACKET: 339 nxp_handle_firmware_request_v1(); 340 break; 341 case NXP_V3_FIRMWARE_REQUEST_PACKET: 342 nxp_handle_firmware_request_v3(); 343 break; 344 default: 345 btstack_assert(false); 346 break; 347 } 348 nxp_input_pos = 0; 349 bytes_to_read = 1; 350 } 351 nxp_start_read(bytes_to_read); 352 } 353 354 static void nxp_write_uart_handler(void){ 355 switch (nxp_tx_state){ 356 case NXP_TX_IDLE: 357 break; 358 case NXP_TX_SEND_CHUNK_V1: 359 nxp_send_chunk_v1(); 360 break; 361 case NXP_TX_SEND_CHUNK_V3: 362 nxp_send_chunk_v3(); 363 break; 364 default: 365 break; 366 } 367 } 368 369 static void nxp_start(void){ 370 nxp_tx_state = NXP_TX_IDLE; 371 nxp_fw_resend_count = 0; 372 nxp_fw_offset = 0; 373 nxp_have_firmware = false; 374 nxp_uart_driver->set_block_received(&nxp_read_uart_handler); 375 nxp_uart_driver->set_block_sent(&nxp_write_uart_handler); 376 nxp_uart_driver->receive_block(nxp_input_buffer, 1); 377 } 378 379 static void nxp_done_with_status(uint8_t status){ 380 printf("DONE!\n"); 381 (*nxp_download_complete)(status); 382 } 383 384 static void nxp_done(void){ 385 nxp_done_with_status(ERROR_CODE_SUCCESS); 386 } 387 388 void btstack_chipset_nxp_set_v1_firmware_path(const char * firmware_path){ 389 btstack_strcpy(nxp_firmware_path, sizeof(nxp_firmware_path), firmware_path); 390 } 391 392 void btstack_chipset_nxp_set_firmware(const uint8_t * fw_data, uint32_t fw_size){ 393 nxp_fw_data = fw_data; 394 nxp_fw_size = fw_size; 395 } 396 397 void btstack_chipset_nxp_download_firmware_with_uart(const btstack_uart_t *uart_driver, void (*done)(uint8_t status)) { 398 nxp_uart_driver = uart_driver; 399 nxp_download_complete = done; 400 401 int res = nxp_uart_driver->open(); 402 403 if (res) { 404 log_error("uart_block init failed %u", res); 405 nxp_download_complete(res); 406 } 407 408 nxp_start(); 409 } 410 411 // init script support 412 static enum { 413 NXP_INIT_SEND_SCO_CONFIG, 414 NXP_INIT_DONE, 415 } nxp_init_state; 416 417 static void nxp_init(const void *transport_config){ 418 UNUSED(transport_config); 419 nxp_init_state = NXP_INIT_SEND_SCO_CONFIG; 420 } 421 422 static btstack_chipset_result_t nxp_next_command(uint8_t * hci_cmd_buffer) { 423 switch (nxp_init_state){ 424 case NXP_INIT_SEND_SCO_CONFIG: 425 #if defined(ENABLE_SCO_OVER_HCI) || defined(ENABLE_SCO_OVER_PCM) 426 little_endian_store_16(hci_cmd_buffer, 0, NXP_OPCODE_SET_SCO_DATA_PATH); 427 hci_cmd_buffer[2] = 1; 428 #ifdef ENABLE_SCO_OVER_HCI 429 // Voice Path: Host 430 hci_cmd_buffer[3] = 0; 431 #else 432 // Voice Path: PCM/I2S 433 hci_cmd_buffer[3] = 1; 434 #endif 435 nxp_init_state = NXP_INIT_DONE; 436 return BTSTACK_CHIPSET_VALID_COMMAND; 437 #endif 438 break; 439 case NXP_INIT_DONE: 440 break; 441 } 442 return BTSTACK_CHIPSET_DONE; 443 } 444 445 static btstack_chipset_t btstack_chipset_nxp = { 446 .name = "NXP", 447 .init = nxp_init, 448 .next_command = nxp_next_command, 449 .set_baudrate_command = NULL, 450 .set_bd_addr_command = NULL 451 }; 452 453 const btstack_chipset_t *btstack_chipset_nxp_instance(void){ 454 return &btstack_chipset_nxp; 455 } 456