xref: /btstack/chipset/nxp/btstack_chipset_nxp.c (revision 5fd6f36099526806c27882ae7a0e3cfa50950641)
1cc528b9dSMatthias Ringwald /*
2cc528b9dSMatthias Ringwald  * Copyright (C) 2023 BlueKitchen GmbH
3cc528b9dSMatthias Ringwald  *
4cc528b9dSMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5cc528b9dSMatthias Ringwald  * modification, are permitted provided that the following conditions
6cc528b9dSMatthias Ringwald  * are met:
7cc528b9dSMatthias Ringwald  *
8cc528b9dSMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9cc528b9dSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10cc528b9dSMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11cc528b9dSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12cc528b9dSMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13cc528b9dSMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14cc528b9dSMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15cc528b9dSMatthias Ringwald  *    from this software without specific prior written permission.
16cc528b9dSMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17cc528b9dSMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18cc528b9dSMatthias Ringwald  *    monetary gain.
19cc528b9dSMatthias Ringwald  *
20cc528b9dSMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21cc528b9dSMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22cc528b9dSMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23cc528b9dSMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24cc528b9dSMatthias Ringwald  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25cc528b9dSMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26cc528b9dSMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27cc528b9dSMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28cc528b9dSMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29cc528b9dSMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30cc528b9dSMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31cc528b9dSMatthias Ringwald  * SUCH DAMAGE.
32cc528b9dSMatthias Ringwald  *
33cc528b9dSMatthias Ringwald  * Please inquire about commercial licensing options at
34cc528b9dSMatthias Ringwald  * [email protected]
35cc528b9dSMatthias Ringwald  *
36cc528b9dSMatthias Ringwald  */
37cc528b9dSMatthias Ringwald 
38cc528b9dSMatthias Ringwald #define BTSTACK_FILE__ "btstack_chipset_nxp.c"
39cc528b9dSMatthias Ringwald 
40cc528b9dSMatthias Ringwald #include "btstack_chipset_nxp.h"
41cc528b9dSMatthias Ringwald #include "btstack_debug.h"
42cc528b9dSMatthias Ringwald #include "btstack_event.h"
43ad03e556SMatthias Ringwald #include "hci_cmd.h"
44cc528b9dSMatthias Ringwald 
45cc528b9dSMatthias Ringwald #include <stdio.h>
46cc528b9dSMatthias Ringwald 
47cc528b9dSMatthias Ringwald #ifdef _MSC_VER
48cc528b9dSMatthias Ringwald // ignore deprecated warning for fopen
49cc528b9dSMatthias Ringwald #pragma warning(disable : 4996)
50cc528b9dSMatthias Ringwald #endif
51cc528b9dSMatthias Ringwald 
52cc528b9dSMatthias Ringwald // Firmware download protocol constants
532364ad0cSMatthias Ringwald #define NXP_V1_FIRMWARE_REQUEST_PACKET	0xa5
542364ad0cSMatthias Ringwald #define NXP_V1_CHIP_VERION_PACKET	0xaa
552364ad0cSMatthias Ringwald #define NXP_V3_FIRMWARE_REQUEST_PACKET	0xa7
562364ad0cSMatthias Ringwald #define NXP_V3_CHIP_VERSION_PACKET	0xab
57cc528b9dSMatthias Ringwald 
58cc528b9dSMatthias Ringwald #define NXP_ACK_V1		0x5a
59cc528b9dSMatthias Ringwald #define NXP_NAK_V1		0xbf
60cc528b9dSMatthias Ringwald #define NXP_ACK_V3		0x7a
61cc528b9dSMatthias Ringwald #define NXP_NAK_V3		0x7b
62cc528b9dSMatthias Ringwald #define NXP_CRC_ERROR_V3	0x7c
63cc528b9dSMatthias Ringwald 
64cc528b9dSMatthias Ringwald // chip ids
65cc528b9dSMatthias Ringwald #define NXP_CHIP_ID_W9098		0x5c03
66cc528b9dSMatthias Ringwald #define NXP_CHIP_ID_IW416		0x7201
67cc528b9dSMatthias Ringwald #define NXP_CHIP_ID_IW612		0x7601
68cc528b9dSMatthias Ringwald 
69f2b175aaSMatthias Ringwald // firmwares
70f2b175aaSMatthias Ringwald #define NXP_FIRMWARE_W9098	"uartuart9098_bt_v1.bin"
71f2b175aaSMatthias Ringwald #define NXP_FIRMWARE_IW416	"uartiw416_bt_v0.bin"
72f2b175aaSMatthias Ringwald #define NXP_FIRMWARE_IW612	"uartspi_n61x_v1.bin.se"
73f2b175aaSMatthias Ringwald 
74cc528b9dSMatthias Ringwald #define NXP_MAX_RESEND_COUNT 5
75cc528b9dSMatthias Ringwald 
76cc528b9dSMatthias Ringwald // prototypes
77cc528b9dSMatthias Ringwald static void nxp_done_with_status(uint8_t status);
782364ad0cSMatthias Ringwald static void nxp_read_uart_handler(void);
796ef12486SMatthias Ringwald static void nxp_send_chunk_v1(void);
806ef12486SMatthias Ringwald static void nxp_send_chunk_v3(void);
812364ad0cSMatthias Ringwald static void nxp_start(void);
82ffa921b1SMatthias Ringwald static void nxp_run(void);
83cc528b9dSMatthias Ringwald 
84cc528b9dSMatthias Ringwald // globals
85ffa921b1SMatthias Ringwald static void (*nxp_download_complete_callback)(uint8_t status);
86cc528b9dSMatthias Ringwald static const btstack_uart_t * nxp_uart_driver;
87bca3f1dbSMatthias Ringwald static btstack_timer_source_t nxp_timer;
88cc528b9dSMatthias Ringwald 
89f2b175aaSMatthias Ringwald static uint16_t nxp_chip_id;
90f2b175aaSMatthias Ringwald 
91cc528b9dSMatthias Ringwald static const uint8_t * nxp_fw_data;
92cc528b9dSMatthias Ringwald static uint32_t        nxp_fw_size;
93cc528b9dSMatthias Ringwald static uint32_t        nxp_fw_offset;
94cc528b9dSMatthias Ringwald 
952364ad0cSMatthias Ringwald static uint8_t       nxp_input_buffer[10];
962364ad0cSMatthias Ringwald static uint16_t      nxp_input_pos;
972364ad0cSMatthias Ringwald static uint16_t      nxp_input_bytes_requested;
982364ad0cSMatthias Ringwald 
992364ad0cSMatthias Ringwald static uint8_t       nxp_output_buffer[2048 + 1];
1002364ad0cSMatthias Ringwald 
101cc528b9dSMatthias Ringwald static const uint8_t nxp_ack_buffer_v1[] = {NXP_ACK_V1 };
102cc528b9dSMatthias Ringwald static const uint8_t nxp_ack_buffer_v3[] = {NXP_ACK_V3, 0x92 };
1032364ad0cSMatthias Ringwald 
104cc528b9dSMatthias Ringwald static uint16_t      nxp_fw_request_len;
105cc528b9dSMatthias Ringwald static uint8_t       nxp_fw_resend_count;
1062364ad0cSMatthias Ringwald 
107ffa921b1SMatthias Ringwald // state / tasks
108ffa921b1SMatthias Ringwald static bool         nxp_have_firmware;
1096ef12486SMatthias Ringwald static bool         nxp_tx_send_ack_v1;
1106ef12486SMatthias Ringwald static bool         nxp_tx_send_ack_v3;
1116ef12486SMatthias Ringwald static bool         nxp_tx_send_chunk_v1;
1126ef12486SMatthias Ringwald static bool         nxp_tx_send_chunk_v3;
1136ef12486SMatthias Ringwald static bool         nxp_tx_active;
114ffa921b1SMatthias Ringwald static bool         nxp_download_done;
115ffa921b1SMatthias Ringwald static uint8_t      nxp_download_statue;
116cc528b9dSMatthias Ringwald 
117cc528b9dSMatthias Ringwald #ifdef HAVE_POSIX_FILE_IO
118cc528b9dSMatthias Ringwald static char   nxp_firmware_path[1000];
119cc528b9dSMatthias Ringwald static FILE * nxp_firmware_file;
120cc528b9dSMatthias Ringwald 
nxp_fw_name_from_chipid(uint16_t chip_id)121f2b175aaSMatthias Ringwald static char *nxp_fw_name_from_chipid(uint16_t chip_id)
122f2b175aaSMatthias Ringwald {
123f2b175aaSMatthias Ringwald     switch (chip_id) {
124f2b175aaSMatthias Ringwald         case NXP_CHIP_ID_W9098:
125f2b175aaSMatthias Ringwald             return NXP_FIRMWARE_W9098;
126f2b175aaSMatthias Ringwald         case NXP_CHIP_ID_IW416:
127f2b175aaSMatthias Ringwald             return NXP_FIRMWARE_IW416;
128f2b175aaSMatthias Ringwald         case NXP_CHIP_ID_IW612:
129f2b175aaSMatthias Ringwald             return NXP_FIRMWARE_IW612;
130f2b175aaSMatthias Ringwald         default:
131f2b175aaSMatthias Ringwald             log_error("Unknown chip id 0x%04x", chip_id);
132f2b175aaSMatthias Ringwald             return NULL;
133f2b175aaSMatthias Ringwald     }
134f2b175aaSMatthias Ringwald }
135f2b175aaSMatthias Ringwald 
nxp_load_firmware(void)136cc528b9dSMatthias Ringwald static void nxp_load_firmware(void) {
137cc528b9dSMatthias Ringwald     if (nxp_firmware_file == NULL){
138ffa921b1SMatthias Ringwald         log_info("open file %s", nxp_firmware_path);
139cc528b9dSMatthias Ringwald         nxp_firmware_file = fopen(nxp_firmware_path, "rb");
140cc528b9dSMatthias Ringwald         if (nxp_firmware_file != NULL){
141ffa921b1SMatthias Ringwald             printf("Open file '%s' failed\n", nxp_firmware_path);
142cc528b9dSMatthias Ringwald             nxp_have_firmware = true;
143cc528b9dSMatthias Ringwald         }
144cc528b9dSMatthias Ringwald     }
145cc528b9dSMatthias Ringwald 
146cc528b9dSMatthias Ringwald }
nxp_read_firmware(uint16_t bytes_to_read,uint8_t * buffer)147cc528b9dSMatthias Ringwald static uint16_t nxp_read_firmware(uint16_t bytes_to_read, uint8_t * buffer) {
148cc528b9dSMatthias Ringwald     size_t bytes_read = fread(buffer, 1, bytes_to_read, nxp_firmware_file);
149cc528b9dSMatthias Ringwald     return bytes_read;
150cc528b9dSMatthias Ringwald }
151cc528b9dSMatthias Ringwald 
nxp_unload_firmware(void)152cc528b9dSMatthias Ringwald static void nxp_unload_firmware(void) {
153cc528b9dSMatthias Ringwald     btstack_assert(nxp_firmware_file != NULL);
154cc528b9dSMatthias Ringwald     fclose(nxp_firmware_file);
155cc528b9dSMatthias Ringwald     nxp_firmware_file = NULL;
156cc528b9dSMatthias Ringwald }
157cc528b9dSMatthias Ringwald #else
nxp_load_firmware(void)158cc528b9dSMatthias Ringwald void nxp_load_firmware(void){
159cc528b9dSMatthias Ringwald     nxp_have_firmware = true;
160cc528b9dSMatthias Ringwald }
161cc528b9dSMatthias Ringwald 
162cc528b9dSMatthias Ringwald // read bytes from firmware file
nxp_read_firmware(uint16_t bytes_to_read,uint8_t * buffer)163cc528b9dSMatthias Ringwald static uint16_t nxp_read_firmware(uint16_t bytes_to_read, uint8_t * buffer){
164cc528b9dSMatthias Ringwald     if (nxp_fw_request_len > nxp_fw_size - nxp_fw_offset){
165cc528b9dSMatthias Ringwald         printf("fw_request_len %u > remaining file len %u\n", nxp_fw_request_len, nxp_fw_size - nxp_fw_offset);
166cc528b9dSMatthias Ringwald         return nxp_fw_size - nxp_fw_offset;
167cc528b9dSMatthias Ringwald     }
168cc528b9dSMatthias Ringwald     memcpy(buffer, &nxp_fw_data[nxp_fw_offset], bytes_to_read);
169cc528b9dSMatthias Ringwald     nxp_fw_offset += nxp_fw_request_len;
170cc528b9dSMatthias Ringwald     return bytes_to_read;
171cc528b9dSMatthias Ringwald }
nxp_unload_firmware(void)172cc528b9dSMatthias Ringwald static void nxp_unload_firmware(void) {
173cc528b9dSMatthias Ringwald }
174cc528b9dSMatthias Ringwald #endif
175cc528b9dSMatthias Ringwald 
nxp_send_ack_v1()1762364ad0cSMatthias Ringwald static void nxp_send_ack_v1() {
1772364ad0cSMatthias Ringwald     printf("SEND: ack v1\n");
1786ef12486SMatthias Ringwald     btstack_assert(nxp_tx_active == false);
1796ef12486SMatthias Ringwald     nxp_tx_active = true;
1802364ad0cSMatthias Ringwald     nxp_uart_driver->send_block(nxp_ack_buffer_v1, sizeof(nxp_ack_buffer_v1));
1812364ad0cSMatthias Ringwald }
1822364ad0cSMatthias Ringwald 
nxp_send_ack_v3()1832364ad0cSMatthias Ringwald static void nxp_send_ack_v3() {
1842364ad0cSMatthias Ringwald     printf("SEND: ack v3\n");
1856ef12486SMatthias Ringwald     btstack_assert(nxp_tx_active == false);
1866ef12486SMatthias Ringwald     nxp_tx_active = true;
1872364ad0cSMatthias Ringwald     nxp_uart_driver->send_block(nxp_ack_buffer_v3, sizeof(nxp_ack_buffer_v3));
1882364ad0cSMatthias Ringwald }
1892364ad0cSMatthias Ringwald 
nxp_valid_packet(void)190cc528b9dSMatthias Ringwald static bool nxp_valid_packet(void){
1912364ad0cSMatthias Ringwald     switch (nxp_input_buffer[0]){
1922364ad0cSMatthias Ringwald         case NXP_V1_FIRMWARE_REQUEST_PACKET:
1932364ad0cSMatthias Ringwald         case NXP_V1_CHIP_VERION_PACKET:
1942364ad0cSMatthias Ringwald             // first two uint16_t should xor to 0xffff
1952364ad0cSMatthias Ringwald             return ((nxp_input_buffer[1] ^ nxp_input_buffer[3]) == 0xff) && ((nxp_input_buffer[2] ^ nxp_input_buffer [4]) == 0xff);
1962364ad0cSMatthias Ringwald         case NXP_V3_CHIP_VERSION_PACKET:
1972364ad0cSMatthias Ringwald         case NXP_V3_FIRMWARE_REQUEST_PACKET:
1982364ad0cSMatthias Ringwald             // TODO: check crc-8
199cc528b9dSMatthias Ringwald             return true;
200cc528b9dSMatthias Ringwald         default:
201cc528b9dSMatthias Ringwald             return false;
202cc528b9dSMatthias Ringwald     }
203cc528b9dSMatthias Ringwald }
204cc528b9dSMatthias Ringwald 
nxp_handle_chip_version_v1(void)2052364ad0cSMatthias Ringwald static void nxp_handle_chip_version_v1(void){
2062364ad0cSMatthias Ringwald     printf("RECV: NXP_V1_CHIP_VER_PKT, id = 0x%x02, revision = 0x%02x\n", nxp_input_buffer[0], nxp_input_buffer[1]);
2076ef12486SMatthias Ringwald     nxp_tx_send_ack_v1 = true;
208ffa921b1SMatthias Ringwald     nxp_run();
209cc528b9dSMatthias Ringwald }
210cc528b9dSMatthias Ringwald 
nxp_handle_chip_version_v3(void)2112364ad0cSMatthias Ringwald static void nxp_handle_chip_version_v3(void){
2122364ad0cSMatthias Ringwald     nxp_chip_id = little_endian_read_16(nxp_input_buffer, 1);
2132364ad0cSMatthias Ringwald     btstack_strcpy(nxp_firmware_path, sizeof(nxp_firmware_path), nxp_fw_name_from_chipid(nxp_chip_id));
2142364ad0cSMatthias Ringwald     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);
2156ef12486SMatthias Ringwald     nxp_tx_send_ack_v3 = true;
216ffa921b1SMatthias Ringwald     nxp_run();
217cc528b9dSMatthias Ringwald }
218cc528b9dSMatthias Ringwald 
nxp_prepare_firmware(void)2192364ad0cSMatthias Ringwald static void nxp_prepare_firmware(void){
220cc528b9dSMatthias Ringwald     // get firmware
221cc528b9dSMatthias Ringwald     if (nxp_have_firmware == false){
222cc528b9dSMatthias Ringwald         nxp_load_firmware();
223cc528b9dSMatthias Ringwald     }
224cc528b9dSMatthias Ringwald     if (nxp_have_firmware == false){
225cc528b9dSMatthias Ringwald         printf("No firmware found, abort\n");
226cc528b9dSMatthias Ringwald     }
2272364ad0cSMatthias Ringwald }
2282364ad0cSMatthias Ringwald 
nxp_send_chunk_v1(void)2292364ad0cSMatthias Ringwald static void nxp_send_chunk_v1(void){
230cc528b9dSMatthias Ringwald     if (nxp_fw_request_len == 0){
231cc528b9dSMatthias Ringwald         printf("last chunk sent!\n");
232cc528b9dSMatthias Ringwald         nxp_unload_firmware();
2332364ad0cSMatthias Ringwald         nxp_done_with_status(ERROR_CODE_SUCCESS);
234cc528b9dSMatthias Ringwald         return;
2352364ad0cSMatthias Ringwald     } else if ((nxp_fw_request_len & 1) == 0){
236cc528b9dSMatthias Ringwald         // update sttate
237cc528b9dSMatthias Ringwald         nxp_fw_offset += nxp_fw_request_len;
238cc528b9dSMatthias Ringwald         nxp_fw_resend_count = 0;
239cc528b9dSMatthias Ringwald         // read next firmware chunk
240cc528b9dSMatthias Ringwald         uint16_t bytes_read = nxp_read_firmware(nxp_fw_request_len, nxp_output_buffer);
241cc528b9dSMatthias Ringwald         if (bytes_read < nxp_fw_request_len){
242cc528b9dSMatthias Ringwald             printf("only %u of %u bytes available, abort.\n", bytes_read, nxp_fw_request_len);
243cc528b9dSMatthias Ringwald             nxp_done_with_status(ERROR_CODE_HARDWARE_FAILURE);
244cc528b9dSMatthias Ringwald             return;
245cc528b9dSMatthias Ringwald         }
246cc528b9dSMatthias Ringwald     } else {
247cc528b9dSMatthias Ringwald         // resend last chunk if request len is odd
248cc528b9dSMatthias Ringwald         if (nxp_fw_resend_count >= NXP_MAX_RESEND_COUNT){
249cc528b9dSMatthias Ringwald             printf("Resent last block %u times, abort.", nxp_fw_resend_count);
250cc528b9dSMatthias Ringwald             nxp_done_with_status(ERROR_CODE_HARDWARE_FAILURE);
251cc528b9dSMatthias Ringwald             return;
252cc528b9dSMatthias Ringwald         }
253cc528b9dSMatthias Ringwald         nxp_fw_resend_count++;
254cc528b9dSMatthias Ringwald     }
255cc528b9dSMatthias Ringwald     printf("SEND: firmware %08x - %u bytes (%u. try)\n", nxp_fw_offset, nxp_fw_request_len, nxp_fw_resend_count + 1);
2566ef12486SMatthias Ringwald     btstack_assert(nxp_tx_active == false);
2576ef12486SMatthias Ringwald     nxp_tx_active = true;
258cc528b9dSMatthias Ringwald     nxp_uart_driver->send_block(nxp_output_buffer, nxp_fw_request_len);
259cc528b9dSMatthias Ringwald }
260cc528b9dSMatthias Ringwald 
nxp_send_chunk_v3(void)2612364ad0cSMatthias Ringwald static void nxp_send_chunk_v3(void){
2622364ad0cSMatthias Ringwald     // update state
2632364ad0cSMatthias Ringwald     nxp_fw_offset += nxp_fw_request_len;
2642364ad0cSMatthias Ringwald     nxp_fw_resend_count = 0;
2652364ad0cSMatthias Ringwald     if (nxp_fw_request_len == 0){
2662364ad0cSMatthias Ringwald         printf("last chunk sent!\n");
2672364ad0cSMatthias Ringwald         nxp_unload_firmware();
2682364ad0cSMatthias Ringwald         nxp_done_with_status(ERROR_CODE_SUCCESS);
2692364ad0cSMatthias Ringwald         return;
2702364ad0cSMatthias Ringwald     }
2712364ad0cSMatthias Ringwald     // read next firmware chunk
2722364ad0cSMatthias Ringwald     uint16_t bytes_read = nxp_read_firmware(nxp_fw_request_len, nxp_output_buffer);
2732364ad0cSMatthias Ringwald     if (bytes_read < nxp_fw_request_len){
2742364ad0cSMatthias Ringwald         printf("only %u of %u bytes available, abort.\n", bytes_read, nxp_fw_request_len);
2752364ad0cSMatthias Ringwald         nxp_done_with_status(ERROR_CODE_HARDWARE_FAILURE);
2762364ad0cSMatthias Ringwald         return;
2772364ad0cSMatthias Ringwald     }
2782364ad0cSMatthias Ringwald     printf("SEND: firmware %08x - %u bytes (%u. try)\n", nxp_fw_offset, nxp_fw_request_len, nxp_fw_resend_count + 1);
2796ef12486SMatthias Ringwald     btstack_assert(nxp_tx_active == false);
2806ef12486SMatthias Ringwald     nxp_tx_active = true;
2812364ad0cSMatthias Ringwald     nxp_uart_driver->send_block(nxp_output_buffer, nxp_fw_request_len);
2822364ad0cSMatthias Ringwald }
2832364ad0cSMatthias Ringwald 
nxp_handle_firmware_request_v1(void)2842364ad0cSMatthias Ringwald static void nxp_handle_firmware_request_v1(void){
2852364ad0cSMatthias Ringwald     nxp_fw_request_len = little_endian_read_16(nxp_input_buffer, 1);
2862364ad0cSMatthias Ringwald     printf("RECV: NXP_V1_FW_REQ_PKT, len %u\n", nxp_fw_request_len);
2872364ad0cSMatthias Ringwald 
2882364ad0cSMatthias Ringwald     nxp_prepare_firmware();
2892364ad0cSMatthias Ringwald     if (nxp_have_firmware == false){
2902364ad0cSMatthias Ringwald         return;
2912364ad0cSMatthias Ringwald     }
2926ef12486SMatthias Ringwald     nxp_tx_send_ack_v1 = true;
2936ef12486SMatthias Ringwald     nxp_tx_send_chunk_v1 = true;
294ffa921b1SMatthias Ringwald     nxp_run();
2952364ad0cSMatthias Ringwald }
2962364ad0cSMatthias Ringwald 
nxp_handle_firmware_request_v3(void)2972364ad0cSMatthias Ringwald static void nxp_handle_firmware_request_v3(void){
2982364ad0cSMatthias Ringwald     nxp_fw_request_len = little_endian_read_16(nxp_input_buffer, 1);
2992364ad0cSMatthias Ringwald     printf("RECV: NXP_V3_FW_REQ_PKT, len %u\n", nxp_fw_request_len);
3002364ad0cSMatthias Ringwald 
3012364ad0cSMatthias Ringwald     nxp_prepare_firmware();
3022364ad0cSMatthias Ringwald     if (nxp_have_firmware == false){
3032364ad0cSMatthias Ringwald         return;
3042364ad0cSMatthias Ringwald     }
3056ef12486SMatthias Ringwald     nxp_tx_send_ack_v3 = true;
3066ef12486SMatthias Ringwald     nxp_tx_send_chunk_v3 = true;
307ffa921b1SMatthias Ringwald     nxp_run();
3082364ad0cSMatthias Ringwald }
3092364ad0cSMatthias Ringwald 
nxp_start_read(uint16_t bytes_to_read)3102364ad0cSMatthias Ringwald static void nxp_start_read(uint16_t bytes_to_read){
3112364ad0cSMatthias Ringwald     nxp_input_bytes_requested = bytes_to_read;
3122364ad0cSMatthias Ringwald     nxp_uart_driver->receive_block(&nxp_input_buffer[nxp_input_pos], bytes_to_read);
3132364ad0cSMatthias Ringwald }
3142364ad0cSMatthias Ringwald 
nxp_read_uart_handler(void)3152364ad0cSMatthias Ringwald static void nxp_read_uart_handler(void){
3162364ad0cSMatthias Ringwald     uint16_t bytes_to_read;
3172364ad0cSMatthias Ringwald     if (nxp_input_pos == 0){
3182364ad0cSMatthias Ringwald         switch (nxp_input_buffer[0]){
3192364ad0cSMatthias Ringwald             case NXP_V1_CHIP_VERION_PACKET:
3202364ad0cSMatthias Ringwald             case NXP_V3_CHIP_VERSION_PACKET:
3212364ad0cSMatthias Ringwald             case NXP_V1_FIRMWARE_REQUEST_PACKET:
3222364ad0cSMatthias Ringwald                 nxp_input_pos++;
3232364ad0cSMatthias Ringwald                 bytes_to_read = 4;
3242364ad0cSMatthias Ringwald                 break;
3252364ad0cSMatthias Ringwald             case NXP_V3_FIRMWARE_REQUEST_PACKET:
3262364ad0cSMatthias Ringwald                 nxp_input_pos++;
3272364ad0cSMatthias Ringwald                 bytes_to_read = 9;
3282364ad0cSMatthias Ringwald                 break;
3292364ad0cSMatthias Ringwald             default:
3302364ad0cSMatthias Ringwald                 // invalid packet type, skip and get next byte
3312364ad0cSMatthias Ringwald                 bytes_to_read = 1;
3322364ad0cSMatthias Ringwald                 break;
3332364ad0cSMatthias Ringwald         }
3342364ad0cSMatthias Ringwald     } else {
3352364ad0cSMatthias Ringwald         nxp_input_pos += nxp_input_bytes_requested;
3362364ad0cSMatthias Ringwald         printf("RECV: ");
3372364ad0cSMatthias Ringwald         printf_hexdump(nxp_input_buffer, nxp_input_pos);
3382364ad0cSMatthias Ringwald         switch (nxp_input_buffer[0]){
3392364ad0cSMatthias Ringwald             case NXP_V1_CHIP_VERION_PACKET:
3402364ad0cSMatthias Ringwald                 nxp_handle_chip_version_v1();
3412364ad0cSMatthias Ringwald                 break;
3422364ad0cSMatthias Ringwald             case NXP_V3_CHIP_VERSION_PACKET:
3432364ad0cSMatthias Ringwald                 nxp_handle_chip_version_v3();
3442364ad0cSMatthias Ringwald                 break;
3452364ad0cSMatthias Ringwald             case NXP_V1_FIRMWARE_REQUEST_PACKET:
3462364ad0cSMatthias Ringwald                 nxp_handle_firmware_request_v1();
3472364ad0cSMatthias Ringwald                 break;
3482364ad0cSMatthias Ringwald             case NXP_V3_FIRMWARE_REQUEST_PACKET:
3492364ad0cSMatthias Ringwald                 nxp_handle_firmware_request_v3();
3502364ad0cSMatthias Ringwald                 break;
3512364ad0cSMatthias Ringwald             default:
3522364ad0cSMatthias Ringwald                 btstack_assert(false);
3532364ad0cSMatthias Ringwald                 break;
3542364ad0cSMatthias Ringwald         }
3552364ad0cSMatthias Ringwald         nxp_input_pos = 0;
3562364ad0cSMatthias Ringwald         bytes_to_read = 1;
357bca3f1dbSMatthias Ringwald 
358bca3f1dbSMatthias Ringwald         // stop timer
359bca3f1dbSMatthias Ringwald         btstack_run_loop_remove_timer(&nxp_timer);
3602364ad0cSMatthias Ringwald     }
3612364ad0cSMatthias Ringwald     nxp_start_read(bytes_to_read);
3622364ad0cSMatthias Ringwald }
3632364ad0cSMatthias Ringwald 
nxp_run(void)364ffa921b1SMatthias Ringwald static void nxp_run(void){
3656ef12486SMatthias Ringwald     if (nxp_tx_active) {
3666ef12486SMatthias Ringwald         return;
3676ef12486SMatthias Ringwald     }
3686ef12486SMatthias Ringwald     if (nxp_tx_send_ack_v1){
3696ef12486SMatthias Ringwald         nxp_tx_send_ack_v1 = false;
3706ef12486SMatthias Ringwald         nxp_send_ack_v1();
3716ef12486SMatthias Ringwald         return;
3726ef12486SMatthias Ringwald     }
3736ef12486SMatthias Ringwald     if (nxp_tx_send_ack_v3){
3746ef12486SMatthias Ringwald         nxp_tx_send_ack_v3 = false;
3756ef12486SMatthias Ringwald         nxp_send_ack_v3();
3766ef12486SMatthias Ringwald         return;
3776ef12486SMatthias Ringwald     }
3786ef12486SMatthias Ringwald     if (nxp_tx_send_chunk_v1){
3796ef12486SMatthias Ringwald         nxp_tx_send_chunk_v1 = false;
3802364ad0cSMatthias Ringwald         nxp_send_chunk_v1();
3816ef12486SMatthias Ringwald         return;
3826ef12486SMatthias Ringwald     }
3836ef12486SMatthias Ringwald     if (nxp_tx_send_chunk_v3){
3846ef12486SMatthias Ringwald         nxp_tx_send_chunk_v3 = false;
3852364ad0cSMatthias Ringwald         nxp_send_chunk_v3();
3866ef12486SMatthias Ringwald         return;
3872364ad0cSMatthias Ringwald     }
388ffa921b1SMatthias Ringwald     if (nxp_download_done){
389ffa921b1SMatthias Ringwald         nxp_download_done = false;
390ffa921b1SMatthias Ringwald         (*nxp_download_complete_callback)(nxp_download_statue);
391ffa921b1SMatthias Ringwald     }
3922364ad0cSMatthias Ringwald }
3932364ad0cSMatthias Ringwald 
nxp_write_uart_handler(void)3946ef12486SMatthias Ringwald static void nxp_write_uart_handler(void){
3956ef12486SMatthias Ringwald     btstack_assert(nxp_tx_active == true);
3966ef12486SMatthias Ringwald     printf("SEND: complete\n");
3976ef12486SMatthias Ringwald     nxp_tx_active = false;
398ffa921b1SMatthias Ringwald     nxp_run();
3996ef12486SMatthias Ringwald }
4006ef12486SMatthias Ringwald 
nxp_start(void)4012364ad0cSMatthias Ringwald static void nxp_start(void){
4022364ad0cSMatthias Ringwald     nxp_fw_resend_count = 0;
4032364ad0cSMatthias Ringwald     nxp_fw_offset = 0;
4042364ad0cSMatthias Ringwald     nxp_have_firmware = false;
4052364ad0cSMatthias Ringwald     nxp_uart_driver->set_block_received(&nxp_read_uart_handler);
4062364ad0cSMatthias Ringwald     nxp_uart_driver->set_block_sent(&nxp_write_uart_handler);
4072364ad0cSMatthias Ringwald     nxp_uart_driver->receive_block(nxp_input_buffer, 1);
4082364ad0cSMatthias Ringwald }
4092364ad0cSMatthias Ringwald 
nxp_done_with_status(uint8_t status)410cc528b9dSMatthias Ringwald static void nxp_done_with_status(uint8_t status){
411ffa921b1SMatthias Ringwald     nxp_download_statue = status;
412ffa921b1SMatthias Ringwald     nxp_download_done = true;
413ffa921b1SMatthias Ringwald     printf("DONE! status 0x%02x\n", status);
414ffa921b1SMatthias Ringwald     nxp_run();
415cc528b9dSMatthias Ringwald }
416cc528b9dSMatthias Ringwald 
btstack_chipset_nxp_set_v1_firmware_path(const char * firmware_path)417cc528b9dSMatthias Ringwald void btstack_chipset_nxp_set_v1_firmware_path(const char * firmware_path){
418cc528b9dSMatthias Ringwald     btstack_strcpy(nxp_firmware_path, sizeof(nxp_firmware_path), firmware_path);
419cc528b9dSMatthias Ringwald }
420cc528b9dSMatthias Ringwald 
btstack_chipset_nxp_set_firmware(const uint8_t * fw_data,uint32_t fw_size)421cc528b9dSMatthias Ringwald void btstack_chipset_nxp_set_firmware(const uint8_t * fw_data, uint32_t fw_size){
422cc528b9dSMatthias Ringwald     nxp_fw_data = fw_data;
423cc528b9dSMatthias Ringwald     nxp_fw_size = fw_size;
424cc528b9dSMatthias Ringwald }
425cc528b9dSMatthias Ringwald 
nxp_timer_handler(btstack_timer_source_t * ts)426bca3f1dbSMatthias Ringwald void nxp_timer_handler(btstack_timer_source_t *ts) {
427bca3f1dbSMatthias Ringwald     printf("No firmware request received, assuming firmware already loaded\n");
428bca3f1dbSMatthias Ringwald     nxp_done_with_status(ERROR_CODE_SUCCESS);
429bca3f1dbSMatthias Ringwald     nxp_run();
430bca3f1dbSMatthias Ringwald }
431bca3f1dbSMatthias Ringwald 
btstack_chipset_nxp_download_firmware_with_uart(const btstack_uart_t * uart_driver,void (* callback)(uint8_t status))432ffa921b1SMatthias Ringwald void btstack_chipset_nxp_download_firmware_with_uart(const btstack_uart_t *uart_driver, void (*callback)(uint8_t status)) {
433cc528b9dSMatthias Ringwald     nxp_uart_driver = uart_driver;
434ffa921b1SMatthias Ringwald     nxp_download_complete_callback = callback;
435cc528b9dSMatthias Ringwald 
436cc528b9dSMatthias Ringwald     int res = nxp_uart_driver->open();
437cc528b9dSMatthias Ringwald 
438cc528b9dSMatthias Ringwald     if (res) {
439cc528b9dSMatthias Ringwald         log_error("uart_block init failed %u", res);
440ffa921b1SMatthias Ringwald         nxp_done_with_status(ERROR_CODE_HARDWARE_FAILURE);
441ffa921b1SMatthias Ringwald         nxp_run();
442ffa921b1SMatthias Ringwald         return;
443cc528b9dSMatthias Ringwald     }
444cc528b9dSMatthias Ringwald 
445bca3f1dbSMatthias Ringwald     // if firmware is loaded, there will be no firmware request
446bca3f1dbSMatthias Ringwald     btstack_run_loop_set_timer(&nxp_timer, 250);
447bca3f1dbSMatthias Ringwald     btstack_run_loop_set_timer_handler(&nxp_timer, &nxp_timer_handler);
448bca3f1dbSMatthias Ringwald     btstack_run_loop_add_timer(&nxp_timer);
449bca3f1dbSMatthias Ringwald 
450cc528b9dSMatthias Ringwald     nxp_start();
451cc528b9dSMatthias Ringwald }
452cc528b9dSMatthias Ringwald 
453d0f26bf0SMatthias Ringwald // init script support
454d0f26bf0SMatthias Ringwald static enum {
455d0f26bf0SMatthias Ringwald     NXP_INIT_SEND_SCO_CONFIG,
456938a5e84SMatthias Ringwald     NXP_INIT_SEND_HOST_CONTROL_ENABLE,
457938a5e84SMatthias Ringwald     NXP_INIT_SEND_WRITE_PCM_SETTINGS,
458938a5e84SMatthias Ringwald     NXP_INIT_SEND_WRITE_PCM_SYNC_SETTINGS,
459938a5e84SMatthias Ringwald     NXP_INIT_SEND_WRITE_PCM_LINK_SETTINGS,
460d0f26bf0SMatthias Ringwald     NXP_INIT_DONE,
461d0f26bf0SMatthias Ringwald } nxp_init_state;
462cc528b9dSMatthias Ringwald 
463ad03e556SMatthias Ringwald #ifdef ENABLE_SCO_OVER_HCI
464ad03e556SMatthias Ringwald // Voice Path: Host
465ad03e556SMatthias Ringwald static const uint8_t nxp_chipset_sco_routing_path = 0;
466ad03e556SMatthias Ringwald #endif
467ad03e556SMatthias Ringwald 
468ad03e556SMatthias Ringwald #ifdef ENABLE_SCO_OVER_PCM
469ad03e556SMatthias Ringwald // Voice Path: PCM/I2S
470ad03e556SMatthias Ringwald static const uint8_t nxp_chipset_sco_routing_path = 1;
471ad03e556SMatthias Ringwald #endif
472ad03e556SMatthias Ringwald 
nxp_init(const void * transport_config)473d0f26bf0SMatthias Ringwald static void nxp_init(const void *transport_config){
474cc528b9dSMatthias Ringwald     UNUSED(transport_config);
475d0f26bf0SMatthias Ringwald     nxp_init_state = NXP_INIT_SEND_SCO_CONFIG;
476d0f26bf0SMatthias Ringwald }
477d0f26bf0SMatthias Ringwald 
nxp_next_command(uint8_t * hci_cmd_buffer)478d0f26bf0SMatthias Ringwald static btstack_chipset_result_t nxp_next_command(uint8_t * hci_cmd_buffer) {
479d0f26bf0SMatthias Ringwald     switch (nxp_init_state){
480d0f26bf0SMatthias Ringwald         case NXP_INIT_SEND_SCO_CONFIG:
481d0f26bf0SMatthias Ringwald #if defined(ENABLE_SCO_OVER_HCI) || defined(ENABLE_SCO_OVER_PCM)
482*5fd6f360SMatthias Ringwald #ifdef ENABLE_NXP_PCM_WBS
483938a5e84SMatthias Ringwald             nxp_init_state = NXP_INIT_SEND_HOST_CONTROL_ENABLE;
484*5fd6f360SMatthias Ringwald #else
485*5fd6f360SMatthias Ringwald             nxp_init_state = NXP_INIT_SEND_WRITE_PCM_SETTINGS;
486*5fd6f360SMatthias Ringwald #endif
487ad03e556SMatthias Ringwald             hci_cmd_create_from_template_with_vargs(hci_cmd_buffer, &hci_nxp_set_sco_data_path, nxp_chipset_sco_routing_path);
488d0f26bf0SMatthias Ringwald             return BTSTACK_CHIPSET_VALID_COMMAND;
489d0f26bf0SMatthias Ringwald #endif
490938a5e84SMatthias Ringwald #ifdef ENABLE_SCO_OVER_PCM
491938a5e84SMatthias Ringwald         case NXP_INIT_SEND_HOST_CONTROL_ENABLE:
492938a5e84SMatthias Ringwald             nxp_init_state = NXP_INIT_SEND_WRITE_PCM_SETTINGS;
493938a5e84SMatthias Ringwald             // Host Control enabled
494938a5e84SMatthias Ringwald             hci_cmd_create_from_template_with_vargs(hci_cmd_buffer, &hci_nxp_host_pcm_i2s_control_enable, 1);
495938a5e84SMatthias Ringwald             return BTSTACK_CHIPSET_VALID_COMMAND;
496938a5e84SMatthias Ringwald         case NXP_INIT_SEND_WRITE_PCM_SETTINGS:
497938a5e84SMatthias Ringwald             nxp_init_state = NXP_INIT_SEND_WRITE_PCM_SYNC_SETTINGS;
498938a5e84SMatthias Ringwald             // PCM/I2S master mode
499938a5e84SMatthias Ringwald             hci_cmd_create_from_template_with_vargs(hci_cmd_buffer, &hci_nxp_write_pcm_i2s_settings, 0x02);
500938a5e84SMatthias Ringwald             return BTSTACK_CHIPSET_VALID_COMMAND;
501938a5e84SMatthias Ringwald         case NXP_INIT_SEND_WRITE_PCM_SYNC_SETTINGS:
502938a5e84SMatthias Ringwald             nxp_init_state = NXP_INIT_SEND_WRITE_PCM_LINK_SETTINGS;
503938a5e84SMatthias Ringwald #ifdef ENABLE_NXP_PCM_WBS
504938a5e84SMatthias Ringwald             // 16 kHz sync, 2048 kHz, data in left channel, DIN sampled on rising edge, DOUT driven on falling edge, I2Sa
505938a5e84SMatthias Ringwald             hci_cmd_create_from_template_with_vargs(hci_cmd_buffer, &hci_nxp_write_pcm_i2s_sync_settings, 0x03, 0x071e);
506938a5e84SMatthias Ringwald #else
507938a5e84SMatthias Ringwald             //  8 kHz sync, 2048 kHz, data in left channel, DIN sampled on rising edge, DOUT driven on falling edge, I2S
508938a5e84SMatthias Ringwald             hci_cmd_create_from_template_with_vargs(hci_cmd_buffer, &hci_nxp_write_pcm_i2s_sync_settings, 0x03, 0x031e);
509938a5e84SMatthias Ringwald #endif
510938a5e84SMatthias Ringwald             return BTSTACK_CHIPSET_VALID_COMMAND;
511938a5e84SMatthias Ringwald         case NXP_INIT_SEND_WRITE_PCM_LINK_SETTINGS:
512938a5e84SMatthias Ringwald             nxp_init_state = NXP_INIT_DONE;
513938a5e84SMatthias Ringwald             // 1st SCO Link PCM Logical Slot 0, PCM start slot 1
514938a5e84SMatthias Ringwald             hci_cmd_create_from_template_with_vargs(hci_cmd_buffer, &hci_nxp_write_pcm_link_settings, 0x0004);
515938a5e84SMatthias Ringwald             return BTSTACK_CHIPSET_VALID_COMMAND;
516938a5e84SMatthias Ringwald #endif
517ad03e556SMatthias Ringwald         default:
518d0f26bf0SMatthias Ringwald             break;
519d0f26bf0SMatthias Ringwald     }
520d0f26bf0SMatthias Ringwald     return BTSTACK_CHIPSET_DONE;
521cc528b9dSMatthias Ringwald }
522cc528b9dSMatthias Ringwald 
523cc528b9dSMatthias Ringwald static btstack_chipset_t btstack_chipset_nxp = {
524cc528b9dSMatthias Ringwald         .name = "NXP",
525d0f26bf0SMatthias Ringwald         .init = nxp_init,
526d0f26bf0SMatthias Ringwald         .next_command = nxp_next_command,
527cc528b9dSMatthias Ringwald         .set_baudrate_command = NULL,
528cc528b9dSMatthias Ringwald         .set_bd_addr_command = NULL
529cc528b9dSMatthias Ringwald };
530cc528b9dSMatthias Ringwald 
btstack_chipset_nxp_instance(void)531cc528b9dSMatthias Ringwald const btstack_chipset_t *btstack_chipset_nxp_instance(void){
532cc528b9dSMatthias Ringwald     return &btstack_chipset_nxp;
533cc528b9dSMatthias Ringwald }
534a57c424fSMatthias Ringwald 
btstack_chipset_nxp_get_initial_baudrate(void)535a57c424fSMatthias Ringwald uint32_t btstack_chipset_nxp_get_initial_baudrate(void){
536a57c424fSMatthias Ringwald     switch (nxp_chip_id){
537a57c424fSMatthias Ringwald         case NXP_CHIP_ID_IW612:
538a57c424fSMatthias Ringwald             return 3000000;
539a57c424fSMatthias Ringwald         default:
540a57c424fSMatthias Ringwald             return 115200;
541a57c424fSMatthias Ringwald     }
542a57c424fSMatthias Ringwald }
543