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