199e8f095SMatthias Ringwald /* 299e8f095SMatthias Ringwald * Copyright (C) 2017 BlueKitchen GmbH 399e8f095SMatthias Ringwald * 499e8f095SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 599e8f095SMatthias Ringwald * modification, are permitted provided that the following conditions 699e8f095SMatthias Ringwald * are met: 799e8f095SMatthias Ringwald * 899e8f095SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 999e8f095SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 1099e8f095SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 1199e8f095SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 1299e8f095SMatthias Ringwald * documentation and/or other materials provided with the distribution. 1399e8f095SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 1499e8f095SMatthias Ringwald * contributors may be used to endorse or promote products derived 1599e8f095SMatthias Ringwald * from this software without specific prior written permission. 1699e8f095SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 1799e8f095SMatthias Ringwald * personal benefit and not for any commercial purpose or for 1899e8f095SMatthias Ringwald * monetary gain. 1999e8f095SMatthias Ringwald * 2099e8f095SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 2199e8f095SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2299e8f095SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 242fca4dadSMilanka Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2599e8f095SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2699e8f095SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 2799e8f095SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2899e8f095SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2999e8f095SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 3099e8f095SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3199e8f095SMatthias Ringwald * SUCH DAMAGE. 3299e8f095SMatthias Ringwald * 3399e8f095SMatthias Ringwald * Please inquire about commercial licensing options at 3499e8f095SMatthias Ringwald * [email protected] 3599e8f095SMatthias Ringwald * 3699e8f095SMatthias Ringwald */ 3799e8f095SMatthias Ringwald 38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "btstack_chipset_bcm_download_firmware.c" 3999e8f095SMatthias Ringwald 4099e8f095SMatthias Ringwald // download firmware implementation 4199e8f095SMatthias Ringwald // requires hci_dump 4299e8f095SMatthias Ringwald // supports higher baudrate for patch upload 4399e8f095SMatthias Ringwald 4499e8f095SMatthias Ringwald #include <string.h> 45c6dda3a5SMatthias Ringwald #include <stdio.h> 46*889634f3SMatthias Ringwald 47*889634f3SMatthias Ringwald #ifdef _MSC_VER 48*889634f3SMatthias Ringwald // map sleep() to Sleep() 49*889634f3SMatthias Ringwald #include "Windows.h" 50*889634f3SMatthias Ringwald unsigned int sleep(unsigned int seconds){ 51*889634f3SMatthias Ringwald _Sleep(seconds * 1000); 52*889634f3SMatthias Ringwald return 0; 53*889634f3SMatthias Ringwald } 54*889634f3SMatthias Ringwald #else 550df9df8cSMatthias Ringwald #include <unistd.h> 56*889634f3SMatthias Ringwald #endif 5799e8f095SMatthias Ringwald 5899e8f095SMatthias Ringwald #include "hci_dump.h" 5999e8f095SMatthias Ringwald #include "btstack_chipset_bcm.h" 6099e8f095SMatthias Ringwald #include "btstack_chipset_bcm_download_firmware.h" 6199e8f095SMatthias Ringwald #include "bluetooth.h" 622150e30cSMatthias Ringwald #include "bluetooth_company_id.h" 6399e8f095SMatthias Ringwald #include "btstack_debug.h" 6499e8f095SMatthias Ringwald #include "btstack_chipset.h" 6599e8f095SMatthias Ringwald 6699e8f095SMatthias Ringwald static void bcm_send_hci_baudrate(void); 6799e8f095SMatthias Ringwald static void bcm_send_next_init_script_command(void); 6899e8f095SMatthias Ringwald static void bcm_set_local_baudrate(void); 6999e8f095SMatthias Ringwald static void bcm_w4_command_complete(void); 7099e8f095SMatthias Ringwald 7199e8f095SMatthias Ringwald static const btstack_uart_block_t * uart_driver; 7299e8f095SMatthias Ringwald static const btstack_chipset_t * chipset; 7399e8f095SMatthias Ringwald 7499e8f095SMatthias Ringwald static uint8_t response_buffer[260]; 75e957bdcbSMatthias Ringwald static uint16_t response_buffer_len; 7699e8f095SMatthias Ringwald static uint8_t command_buffer[260]; 7799e8f095SMatthias Ringwald 7899e8f095SMatthias Ringwald static const int hci_command_complete_len = 7; 7986243214SMatthias Ringwald static const int hci_command_complete_read_local_version = 15; 8086243214SMatthias Ringwald static const uint8_t hci_read_local_version_cmd[] = { 0x01, 0x10, 0x00}; 8199e8f095SMatthias Ringwald static const uint8_t hci_reset_cmd[] = { 0x03, 0x0c, 0x00 }; 82e957bdcbSMatthias Ringwald static const uint8_t hci_command_complete_reset[] = { 0x04, 0x0e, 0x04, 0x01, 0x03, 0x0c, 0x00}; 83e957bdcbSMatthias Ringwald 8499e8f095SMatthias Ringwald static void (*download_complete)(int result); 852150e30cSMatthias Ringwald 86e957bdcbSMatthias Ringwald static uint32_t baudrate; 8799e8f095SMatthias Ringwald 8886243214SMatthias Ringwald static inline void bcm_hci_dump_event(void){ 8986243214SMatthias Ringwald uint16_t event_len = 2 + response_buffer[2]; 9086243214SMatthias Ringwald hci_dump_packet(HCI_EVENT_PACKET, 0, &response_buffer[1], event_len); 9199e8f095SMatthias Ringwald } 9299e8f095SMatthias Ringwald 9386243214SMatthias Ringwald static void bcm_send_prepared_command(void){ 9486243214SMatthias Ringwald command_buffer[0] = 1; 9586243214SMatthias Ringwald uint16_t command_len = 3 + command_buffer[3]; 9686243214SMatthias Ringwald hci_dump_packet(HCI_COMMAND_DATA_PACKET, 0, &command_buffer[1], command_len); 9786243214SMatthias Ringwald uart_driver->send_block(command_buffer, command_len + 1); 9886243214SMatthias Ringwald } 9986243214SMatthias Ringwald 1002150e30cSMatthias Ringwald // select controller based on { manufacturer / lmp_subversion } 1012150e30cSMatthias Ringwald static void bcm_detect_controller(uint16_t manufacturer, 1022150e30cSMatthias Ringwald uint16_t lmp_subversion) { 1032150e30cSMatthias Ringwald const char * device_name = NULL; 1042150e30cSMatthias Ringwald switch (manufacturer){ 1052150e30cSMatthias Ringwald case BLUETOOTH_COMPANY_ID_INFINEON_TECHNOLOGIES_AG: 1062150e30cSMatthias Ringwald switch (lmp_subversion){ 1072150e30cSMatthias Ringwald case 0x2257: 1082150e30cSMatthias Ringwald // CYW5557x 1092150e30cSMatthias Ringwald device_name = "CYW55560A1"; 1102150e30cSMatthias Ringwald break; 1112150e30cSMatthias Ringwald default: 1122150e30cSMatthias Ringwald break; 1132150e30cSMatthias Ringwald } 1142150e30cSMatthias Ringwald break; 1152150e30cSMatthias Ringwald default: 1162150e30cSMatthias Ringwald break; 1172150e30cSMatthias Ringwald } 1182150e30cSMatthias Ringwald if (device_name == NULL){ 1192150e30cSMatthias Ringwald printf("Unknown device, please update bcm_detect_controller()\n"); 1202150e30cSMatthias Ringwald printf("in btstack/chipset/bcm/btstack_chipset_bcm_download_firmware.c\n"); 1212150e30cSMatthias Ringwald } else { 1222150e30cSMatthias Ringwald printf("Controller: %s\n", device_name); 1232150e30cSMatthias Ringwald btstack_chipset_bcm_set_device_name(device_name); 1242150e30cSMatthias Ringwald } 1252150e30cSMatthias Ringwald } 1262150e30cSMatthias Ringwald 12786243214SMatthias Ringwald // Send / Receive HCI Read Local Version Information 12886243214SMatthias Ringwald 12986243214SMatthias Ringwald static void bcm_receive_command_command_complete_read_local_version(void){ 13086243214SMatthias Ringwald const uint8_t * packet = &response_buffer[1]; 13186243214SMatthias Ringwald printf("ROM version information:\n"); 13286243214SMatthias Ringwald uint16_t hci_version = packet[6]; 13386243214SMatthias Ringwald uint16_t hci_revision = little_endian_read_16(packet, 7); 13486243214SMatthias Ringwald uint16_t lmp_version = packet[9]; 13586243214SMatthias Ringwald uint16_t manufacturer = little_endian_read_16(packet, 10); 13686243214SMatthias Ringwald uint16_t lmp_subversion = little_endian_read_16(packet, 12); 13786243214SMatthias Ringwald printf("- HCI Version 0x%04x\n", hci_version); 13886243214SMatthias Ringwald printf("- HCI Revision 0x%04x\n", hci_revision); 13986243214SMatthias Ringwald printf("- LMP Version 0x%04x\n", lmp_version); 14086243214SMatthias Ringwald printf("- LMP Subversion 0x%04x\n", lmp_subversion); 14186243214SMatthias Ringwald printf("- Manufacturer 0x%04x\n", manufacturer); 1422150e30cSMatthias Ringwald 1432150e30cSMatthias Ringwald bcm_detect_controller(manufacturer, lmp_subversion); 1442150e30cSMatthias Ringwald 14586243214SMatthias Ringwald bcm_w4_command_complete(); 14686243214SMatthias Ringwald } 14786243214SMatthias Ringwald 14886243214SMatthias Ringwald static void bcm_send_read_local_version(void){ 14986243214SMatthias Ringwald log_info("bcm: send HCI Read Local Version Information"); 15086243214SMatthias Ringwald uart_driver->set_block_received(&bcm_receive_command_command_complete_read_local_version); 15186243214SMatthias Ringwald uart_driver->receive_block(response_buffer, hci_command_complete_read_local_version); 15286243214SMatthias Ringwald memcpy(&command_buffer[1], hci_read_local_version_cmd, sizeof(hci_read_local_version_cmd)); 15386243214SMatthias Ringwald bcm_send_prepared_command(); 15486243214SMatthias Ringwald } 15586243214SMatthias Ringwald 15686243214SMatthias Ringwald // Send / Receive HCI Reset 15786243214SMatthias Ringwald 158e957bdcbSMatthias Ringwald // Although the Controller just has been reset by the user, there might still be HCI data in the UART driver 159e957bdcbSMatthias Ringwald // which we'll ignore in the receive function 160e957bdcbSMatthias Ringwald 161e957bdcbSMatthias Ringwald static void bcm_receive_command_complete_reset(void){ 162e957bdcbSMatthias Ringwald response_buffer_len++; 163e957bdcbSMatthias Ringwald if (response_buffer_len == hci_command_complete_len){ 164e957bdcbSMatthias Ringwald // try to match command complete for HCI Reset 165e957bdcbSMatthias Ringwald if (memcmp(response_buffer, hci_command_complete_reset, hci_command_complete_len) == 0){ 16686243214SMatthias Ringwald bcm_hci_dump_event(); 16786243214SMatthias Ringwald bcm_send_read_local_version(); 168e957bdcbSMatthias Ringwald return; 169e957bdcbSMatthias Ringwald } 170e957bdcbSMatthias Ringwald memmove(&response_buffer[0], &response_buffer[1], response_buffer_len - 1); 171e957bdcbSMatthias Ringwald response_buffer_len--; 172e957bdcbSMatthias Ringwald } 173e957bdcbSMatthias Ringwald uart_driver->receive_block(&response_buffer[response_buffer_len], 1); 174e957bdcbSMatthias Ringwald } 175e957bdcbSMatthias Ringwald 17699e8f095SMatthias Ringwald static void bcm_send_hci_reset(void){ 17799e8f095SMatthias Ringwald log_info("bcm: send HCI Reset"); 178e957bdcbSMatthias Ringwald response_buffer_len = 0; 179e957bdcbSMatthias Ringwald uart_driver->set_block_received(&bcm_receive_command_complete_reset); 180e957bdcbSMatthias Ringwald uart_driver->receive_block(&response_buffer[response_buffer_len], 1); 18199e8f095SMatthias Ringwald memcpy(&command_buffer[1], hci_reset_cmd, sizeof(hci_reset_cmd)); 18286243214SMatthias Ringwald bcm_send_prepared_command(); 18399e8f095SMatthias Ringwald } 18499e8f095SMatthias Ringwald 18586243214SMatthias Ringwald // Other 18686243214SMatthias Ringwald 18799e8f095SMatthias Ringwald static void bcm_send_hci_baudrate(void){ 18886243214SMatthias Ringwald bcm_hci_dump_event(); 18999e8f095SMatthias Ringwald chipset->set_baudrate_command(baudrate, &command_buffer[1]); 19099e8f095SMatthias Ringwald uart_driver->set_block_received(&bcm_set_local_baudrate); 19199e8f095SMatthias Ringwald uart_driver->receive_block(&response_buffer[0], hci_command_complete_len); 1920df9df8cSMatthias Ringwald log_info("bcm: send baud rate command - %u", baudrate); 19399e8f095SMatthias Ringwald bcm_send_prepared_command(); 19499e8f095SMatthias Ringwald } 19599e8f095SMatthias Ringwald 19699e8f095SMatthias Ringwald static void bcm_set_local_baudrate(void){ 19786243214SMatthias Ringwald bcm_hci_dump_event(); 19899e8f095SMatthias Ringwald uart_driver->set_baudrate(baudrate); 19999e8f095SMatthias Ringwald uart_driver->set_block_received(&bcm_w4_command_complete); 20099e8f095SMatthias Ringwald bcm_send_next_init_script_command(); 20199e8f095SMatthias Ringwald } 20299e8f095SMatthias Ringwald 20399e8f095SMatthias Ringwald static void bcm_w4_command_complete(void){ 20486243214SMatthias Ringwald bcm_hci_dump_event(); 205e957bdcbSMatthias Ringwald uart_driver->set_block_received(&bcm_w4_command_complete); 20699e8f095SMatthias Ringwald bcm_send_next_init_script_command(); 20799e8f095SMatthias Ringwald } 20899e8f095SMatthias Ringwald 20999e8f095SMatthias Ringwald static void bcm_send_next_init_script_command(void){ 21099e8f095SMatthias Ringwald int res = chipset->next_command(&command_buffer[1]); 21199e8f095SMatthias Ringwald switch (res){ 21299e8f095SMatthias Ringwald case BTSTACK_CHIPSET_VALID_COMMAND: 21386243214SMatthias Ringwald uart_driver->receive_block(&response_buffer[0], hci_command_complete_len); 21499e8f095SMatthias Ringwald bcm_send_prepared_command(); 21599e8f095SMatthias Ringwald break; 21699e8f095SMatthias Ringwald case BTSTACK_CHIPSET_DONE: 21799e8f095SMatthias Ringwald log_info("bcm: init script done"); 218646a1850SMatthias Ringwald // disable init script for main startup 219646a1850SMatthias Ringwald btstack_chipset_bcm_enable_init_script(0); 2200df9df8cSMatthias Ringwald // reset baudrate to default 22199e8f095SMatthias Ringwald uart_driver->set_baudrate(115200); 222646a1850SMatthias Ringwald // notify main 22399e8f095SMatthias Ringwald download_complete(0); 22499e8f095SMatthias Ringwald break; 22599e8f095SMatthias Ringwald default: 22699e8f095SMatthias Ringwald break; 22799e8f095SMatthias Ringwald } 22899e8f095SMatthias Ringwald } 22999e8f095SMatthias Ringwald 23099e8f095SMatthias Ringwald /** 23199e8f095SMatthias Ringwald * @brief Download firmware via uart_driver 23299e8f095SMatthias Ringwald * @param uart_driver -- already initialized 23399e8f095SMatthias Ringwald * @param done callback. 0 = Success 23499e8f095SMatthias Ringwald */ 23599e8f095SMatthias Ringwald 23678a48aa8SMatthias Ringwald void btstack_chipset_bcm_download_firmware_with_uart(const btstack_uart_t * the_uart_driver, int baudrate_upload, void (*done)(int result)){ 23799e8f095SMatthias Ringwald // 23899e8f095SMatthias Ringwald uart_driver = the_uart_driver; 23999e8f095SMatthias Ringwald chipset = btstack_chipset_bcm_instance(); 24099e8f095SMatthias Ringwald baudrate = baudrate_upload; 24199e8f095SMatthias Ringwald download_complete = done; 2428ac52328SMatthias Ringwald btstack_chipset_bcm_enable_init_script(1); 24399e8f095SMatthias Ringwald 24499e8f095SMatthias Ringwald int res = uart_driver->open(); 24599e8f095SMatthias Ringwald if (res) { 24699e8f095SMatthias Ringwald log_error("uart_block init failed %u", res); 24799e8f095SMatthias Ringwald download_complete(res); 24899e8f095SMatthias Ringwald return; 24999e8f095SMatthias Ringwald } 25099e8f095SMatthias Ringwald 2510df9df8cSMatthias Ringwald // Reset with CTS asserted (low) 2520df9df8cSMatthias Ringwald printf("Please reset Bluetooth Controller, e.g. via RESET button. Firmware download starts in:\n"); 2530df9df8cSMatthias Ringwald uint8_t i; 2540df9df8cSMatthias Ringwald for (i = 3; i > 0; i--){ 2550df9df8cSMatthias Ringwald printf("%u\n", i); 2560df9df8cSMatthias Ringwald sleep(1); 2570df9df8cSMatthias Ringwald } 2580df9df8cSMatthias Ringwald printf("Firmware download started\n"); 2590df9df8cSMatthias Ringwald 26099e8f095SMatthias Ringwald bcm_send_hci_reset(); 26199e8f095SMatthias Ringwald } 2620df9df8cSMatthias Ringwald 26378a48aa8SMatthias Ringwald void btstack_chipset_bcm_download_firmware(const btstack_uart_block_t * the_uart_driver, int baudrate_upload, void (*done)(int result)) { 26478a48aa8SMatthias Ringwald btstack_chipset_bcm_download_firmware_with_uart((const btstack_uart_t *) the_uart_driver, baudrate_upload, done); 26578a48aa8SMatthias Ringwald } 266