1faa6c1f6SMatthias Ringwald /* 2faa6c1f6SMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH 3faa6c1f6SMatthias Ringwald * 4faa6c1f6SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5faa6c1f6SMatthias Ringwald * modification, are permitted provided that the following conditions 6faa6c1f6SMatthias Ringwald * are met: 7faa6c1f6SMatthias Ringwald * 8faa6c1f6SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9faa6c1f6SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10faa6c1f6SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11faa6c1f6SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12faa6c1f6SMatthias Ringwald * documentation and/or other materials provided with the distribution. 13faa6c1f6SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14faa6c1f6SMatthias Ringwald * contributors may be used to endorse or promote products derived 15faa6c1f6SMatthias Ringwald * from this software without specific prior written permission. 16faa6c1f6SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 17faa6c1f6SMatthias Ringwald * personal benefit and not for any commercial purpose or for 18faa6c1f6SMatthias Ringwald * monetary gain. 19faa6c1f6SMatthias Ringwald * 20faa6c1f6SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21faa6c1f6SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22faa6c1f6SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23faa6c1f6SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24faa6c1f6SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25faa6c1f6SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26faa6c1f6SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27faa6c1f6SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28faa6c1f6SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29faa6c1f6SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30faa6c1f6SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31faa6c1f6SMatthias Ringwald * SUCH DAMAGE. 32faa6c1f6SMatthias Ringwald * 33faa6c1f6SMatthias Ringwald * Please inquire about commercial licensing options at 34faa6c1f6SMatthias Ringwald * [email protected] 35faa6c1f6SMatthias Ringwald * 36faa6c1f6SMatthias Ringwald */ 37faa6c1f6SMatthias Ringwald 38ab2c6ae4SMatthias Ringwald #define __BTSTACK_FILE__ "btstack_chipset_em9301.c" 39ab2c6ae4SMatthias Ringwald 40faa6c1f6SMatthias Ringwald /* 41fb55bd0aSMatthias Ringwald * btstack_chipset_em9301.c 42faa6c1f6SMatthias Ringwald * 43faa6c1f6SMatthias Ringwald * Adapter to use em9301-based chipsets with BTstack 44faa6c1f6SMatthias Ringwald * 45faa6c1f6SMatthias Ringwald * Allows to set public BD ADDR 46faa6c1f6SMatthias Ringwald */ 47faa6c1f6SMatthias Ringwald 48faa6c1f6SMatthias Ringwald #include "btstack_config.h" 49fb55bd0aSMatthias Ringwald #include "btstack_chipset_em9301.h" 50d40c3de0SMatthias Ringwald #include "btstack_debug.h" 51faa6c1f6SMatthias Ringwald 52faa6c1f6SMatthias Ringwald #include <stddef.h> /* NULL */ 53faa6c1f6SMatthias Ringwald #include <string.h> /* memcpy */ 54faa6c1f6SMatthias Ringwald #include "hci.h" 55faa6c1f6SMatthias Ringwald 56faa6c1f6SMatthias Ringwald // should go to some common place 57faa6c1f6SMatthias Ringwald #define OPCODE(ogf, ocf) (ocf | ogf << 10) 58faa6c1f6SMatthias Ringwald 59d080547cSMatthias Ringwald #define HCI_OPCODE_EM_WRITE_PATCH_START (0xFC27) 60d080547cSMatthias Ringwald #define HCI_OPCODE_EM_WRITE_PATCH_CONTINUE (0xFC28) 61d080547cSMatthias Ringwald #define HCI_OPCODE_EM_WRITE_PATCH_ABORT (0xFC29) 62d080547cSMatthias Ringwald #define HCI_OPCODE_EM_CPU_RESET (0xFC32) 63d080547cSMatthias Ringwald #define HCI_OPCODE_EM_PATCH_QUERY (0xFC34) 64d080547cSMatthias Ringwald 65d40c3de0SMatthias Ringwald static const uint32_t baudrates[] = { 66d40c3de0SMatthias Ringwald 0, 67d40c3de0SMatthias Ringwald 0, 68d40c3de0SMatthias Ringwald 0, 69d40c3de0SMatthias Ringwald 9600, 70d40c3de0SMatthias Ringwald 14400, 71d40c3de0SMatthias Ringwald 19200, 72d40c3de0SMatthias Ringwald 28800, 73d40c3de0SMatthias Ringwald 38400, 74d40c3de0SMatthias Ringwald 57600, 75d40c3de0SMatthias Ringwald 76800, 76d40c3de0SMatthias Ringwald 115200, 77d40c3de0SMatthias Ringwald 230400, 78d40c3de0SMatthias Ringwald 460800, 79d40c3de0SMatthias Ringwald 921600, 80d40c3de0SMatthias Ringwald 1843200, 81d40c3de0SMatthias Ringwald }; 82faa6c1f6SMatthias Ringwald 83d080547cSMatthias Ringwald #ifdef HAVE_EM9304_PATCH_CONTAINER 84d080547cSMatthias Ringwald 85d080547cSMatthias Ringwald extern const uint8_t container_blob_data[]; 86d080547cSMatthias Ringwald extern const uint32_t container_blob_size; 87d080547cSMatthias Ringwald 88d080547cSMatthias Ringwald static uint32_t container_blob_offset = 0; 89d080547cSMatthias Ringwald static uint32_t container_end; // current container 90d080547cSMatthias Ringwald static uint16_t patch_sequence_number; 91d080547cSMatthias Ringwald static int em_cpu_reset_sent; 92d080547cSMatthias Ringwald 93d080547cSMatthias Ringwald static enum { 94d080547cSMatthias Ringwald UPLOAD_IDLE, 95d080547cSMatthias Ringwald UPLOAD_ACTIVE, 96d080547cSMatthias Ringwald } upload_state; 97d080547cSMatthias Ringwald 98d080547cSMatthias Ringwald #endif 99d080547cSMatthias Ringwald 100d7587826SMatthias Ringwald // CRC32 implementation using 4-bit lookup table created by pycrc v0.9.1, https://pycrc.org 101d7587826SMatthias Ringwald // ./pycrc.py --model crc-32 --algorithm table-driven --table-idx-width=4 --generate c 1026cee6f09SMatthias Ringwald static const uint32_t crc32_table[16] = { 1036cee6f09SMatthias Ringwald 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 1046cee6f09SMatthias Ringwald 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c 1056cee6f09SMatthias Ringwald }; 1066cee6f09SMatthias Ringwald 1076cee6f09SMatthias Ringwald uint32_t btstack_crc32(const uint8_t *buf, uint16_t size){ 1086cee6f09SMatthias Ringwald uint16_t pos; 109d7587826SMatthias Ringwald uint32_t crc = 0xffffffff; 1106cee6f09SMatthias Ringwald for (pos=0 ; pos<size ; pos++){ 111d7587826SMatthias Ringwald int tbl_idx = crc ^ buf[pos]; 112d7587826SMatthias Ringwald crc = crc32_table[tbl_idx & 0x0f] ^ (crc >> 4); 113d7587826SMatthias Ringwald tbl_idx = crc ^ (buf[pos] >> 4); 114d7587826SMatthias Ringwald crc = crc32_table[tbl_idx & 0x0f] ^ (crc >> 4); 1156cee6f09SMatthias Ringwald } 116d7587826SMatthias Ringwald return ~crc; 1176cee6f09SMatthias Ringwald } 118d080547cSMatthias Ringwald 119faa6c1f6SMatthias Ringwald static void chipset_set_bd_addr_command(bd_addr_t addr, uint8_t *hci_cmd_buffer){ 120f8fbdce0SMatthias Ringwald little_endian_store_16(hci_cmd_buffer, 0, OPCODE(OGF_VENDOR, 0x02)); 121faa6c1f6SMatthias Ringwald hci_cmd_buffer[2] = 0x06; 122a47028edSMatthias Ringwald reverse_bd_addr(addr, &hci_cmd_buffer[3]); 123faa6c1f6SMatthias Ringwald } 124faa6c1f6SMatthias Ringwald 125d40c3de0SMatthias Ringwald static void chipset_set_baudrate_command(uint32_t baudrate, uint8_t *hci_cmd_buffer){ 126d40c3de0SMatthias Ringwald // lookup baudrates 127d40c3de0SMatthias Ringwald int i; 1289ba7722dSMatthias Ringwald int found = 0; 129d40c3de0SMatthias Ringwald for (i=0 ; i < sizeof(baudrates)/sizeof(uint32_t) ; i++){ 130d40c3de0SMatthias Ringwald if (baudrates[i] == baudrate){ 131d40c3de0SMatthias Ringwald found = i; 132d40c3de0SMatthias Ringwald break; 133d40c3de0SMatthias Ringwald } 134d40c3de0SMatthias Ringwald } 135d40c3de0SMatthias Ringwald if (!found){ 136d40c3de0SMatthias Ringwald log_error("Baudrate %u not found in table", baudrate); 137d40c3de0SMatthias Ringwald return; 138d40c3de0SMatthias Ringwald } 139d40c3de0SMatthias Ringwald little_endian_store_16(hci_cmd_buffer, 0, OPCODE(OGF_VENDOR, 0x07)); 140d40c3de0SMatthias Ringwald hci_cmd_buffer[2] = 0x01; 141d40c3de0SMatthias Ringwald hci_cmd_buffer[3] = i; 142d40c3de0SMatthias Ringwald } 143d40c3de0SMatthias Ringwald 144d080547cSMatthias Ringwald #ifdef HAVE_EM9304_PATCH_CONTAINER 145d080547cSMatthias Ringwald static void chipset_init(const void * config){ 146d080547cSMatthias Ringwald UNUSED(config); 147d080547cSMatthias Ringwald container_blob_offset = 0; 148d080547cSMatthias Ringwald em_cpu_reset_sent = 0; 149d080547cSMatthias Ringwald upload_state = UPLOAD_IDLE; 150d080547cSMatthias Ringwald } 151d080547cSMatthias Ringwald 152d080547cSMatthias Ringwald static btstack_chipset_result_t chipset_next_command(uint8_t * hci_cmd_buffer){ 153d080547cSMatthias Ringwald log_info("pos %u, container end %u, blob size %u", container_blob_offset, container_end, container_blob_size); 154d080547cSMatthias Ringwald 155d080547cSMatthias Ringwald if (container_blob_offset >= container_blob_size) { 156d080547cSMatthias Ringwald if (0 == em_cpu_reset_sent){ 157d080547cSMatthias Ringwald // send EM CPU Reset 158d080547cSMatthias Ringwald little_endian_store_16(hci_cmd_buffer, 0, HCI_OPCODE_EM_CPU_RESET); 159d080547cSMatthias Ringwald hci_cmd_buffer[2] = 0; 160d080547cSMatthias Ringwald em_cpu_reset_sent = 1; 161d080547cSMatthias Ringwald return BTSTACK_CHIPSET_VALID_COMMAND; 162d080547cSMatthias Ringwald } else { 163d080547cSMatthias Ringwald return BTSTACK_CHIPSET_DONE; 164d080547cSMatthias Ringwald } 165d080547cSMatthias Ringwald } 166d080547cSMatthias Ringwald 167d080547cSMatthias Ringwald uint32_t tag; 168d080547cSMatthias Ringwald uint16_t bytes_to_upload; 169d080547cSMatthias Ringwald uint32_t crc; 170*1882d12dSMatthias Ringwald uint32_t container_size; 171d080547cSMatthias Ringwald 172d080547cSMatthias Ringwald switch (upload_state){ 173d080547cSMatthias Ringwald case UPLOAD_IDLE: 174d080547cSMatthias Ringwald // check for 'em93' tag 175d080547cSMatthias Ringwald tag = little_endian_read_32(container_blob_data, container_blob_offset); 176d080547cSMatthias Ringwald if (0x656d3933 != tag) { 177*1882d12dSMatthias Ringwald log_error("Expected 0x656d3933 ('em934') but got %08x", (int) tag); 178d080547cSMatthias Ringwald return BTSTACK_CHIPSET_DONE; 179d080547cSMatthias Ringwald } 180d080547cSMatthias Ringwald // fetch info for current container 181*1882d12dSMatthias Ringwald container_size = little_endian_read_32(container_blob_data, container_blob_offset + 4); 182*1882d12dSMatthias Ringwald container_end = container_blob_offset + container_size; 183d080547cSMatthias Ringwald // start uploading (<= 59 bytes) 184d080547cSMatthias Ringwald patch_sequence_number = 1; 185d080547cSMatthias Ringwald bytes_to_upload = btstack_min(59, container_end - container_blob_offset); 1866cee6f09SMatthias Ringwald crc = btstack_crc32(&container_blob_data[container_blob_offset], bytes_to_upload); 187*1882d12dSMatthias Ringwald log_info("Container type 0x%02x, id %u, build nr %u, user build nr %u, size %u", 188*1882d12dSMatthias Ringwald (int) container_blob_data[container_blob_offset+9], 189*1882d12dSMatthias Ringwald (int) container_blob_data[container_blob_offset+10], 190*1882d12dSMatthias Ringwald (int) little_endian_read_16(container_blob_data, container_blob_offset+12), 191*1882d12dSMatthias Ringwald (int) little_endian_read_16(container_blob_data, container_blob_offset+14), 192*1882d12dSMatthias Ringwald (int) container_size); 193d080547cSMatthias Ringwald // build command 194d080547cSMatthias Ringwald little_endian_store_16(hci_cmd_buffer, 0, HCI_OPCODE_EM_WRITE_PATCH_START); 195d080547cSMatthias Ringwald hci_cmd_buffer[2] = 5 + bytes_to_upload; 196d080547cSMatthias Ringwald hci_cmd_buffer[3] = 0; // upload to iRAM1 197d080547cSMatthias Ringwald little_endian_store_32(hci_cmd_buffer, 4, crc); 198d080547cSMatthias Ringwald memcpy(&hci_cmd_buffer[8], &container_blob_data[container_blob_offset], bytes_to_upload); 199d080547cSMatthias Ringwald container_blob_offset += bytes_to_upload; 200d080547cSMatthias Ringwald if (container_blob_offset < container_end){ 201d080547cSMatthias Ringwald upload_state = UPLOAD_ACTIVE; 202d080547cSMatthias Ringwald } 203d080547cSMatthias Ringwald return BTSTACK_CHIPSET_VALID_COMMAND; 204d080547cSMatthias Ringwald case UPLOAD_ACTIVE: 205d080547cSMatthias Ringwald // Upload next segement 206d080547cSMatthias Ringwald bytes_to_upload = btstack_min(58, container_end - container_blob_offset); 2076cee6f09SMatthias Ringwald crc = btstack_crc32(&container_blob_data[container_blob_offset], bytes_to_upload); 208d080547cSMatthias Ringwald // build command 209d080547cSMatthias Ringwald little_endian_store_16(hci_cmd_buffer, 0, HCI_OPCODE_EM_WRITE_PATCH_CONTINUE); 210d080547cSMatthias Ringwald hci_cmd_buffer[2] = 6 + bytes_to_upload; 211d080547cSMatthias Ringwald little_endian_store_16(hci_cmd_buffer, 3, patch_sequence_number++); 212d080547cSMatthias Ringwald little_endian_store_32(hci_cmd_buffer, 5, crc); 213d080547cSMatthias Ringwald memcpy(&hci_cmd_buffer[9], &container_blob_data[container_blob_offset], bytes_to_upload); 214d080547cSMatthias Ringwald container_blob_offset += bytes_to_upload; 215d080547cSMatthias Ringwald if (container_blob_offset >= container_end){ 216d080547cSMatthias Ringwald log_info("container done maybe another one"); 217d080547cSMatthias Ringwald upload_state = UPLOAD_IDLE; 218d080547cSMatthias Ringwald } 219d080547cSMatthias Ringwald return BTSTACK_CHIPSET_VALID_COMMAND; 220d080547cSMatthias Ringwald } 221d080547cSMatthias Ringwald return BTSTACK_CHIPSET_DONE; 222d080547cSMatthias Ringwald } 223d080547cSMatthias Ringwald #endif 224d080547cSMatthias Ringwald 225faa6c1f6SMatthias Ringwald static const btstack_chipset_t btstack_chipset_em9301 = { 226faa6c1f6SMatthias Ringwald "EM9301", 227d080547cSMatthias Ringwald #ifdef HAVE_EM9304_PATCH_CONTAINER 228d080547cSMatthias Ringwald chipset_init, 229d080547cSMatthias Ringwald chipset_next_command, 230d080547cSMatthias Ringwald #else 231d080547cSMatthias Ringwald NULL, 232d080547cSMatthias Ringwald NULL, 233d080547cSMatthias Ringwald #endif 234d40c3de0SMatthias Ringwald chipset_set_baudrate_command, 235faa6c1f6SMatthias Ringwald chipset_set_bd_addr_command, 236faa6c1f6SMatthias Ringwald }; 237faa6c1f6SMatthias Ringwald 238faa6c1f6SMatthias Ringwald // MARK: public API 239faa6c1f6SMatthias Ringwald const btstack_chipset_t * btstack_chipset_em9301_instance(void){ 240faa6c1f6SMatthias Ringwald return &btstack_chipset_em9301; 241faa6c1f6SMatthias Ringwald } 242