xref: /btstack/chipset/em9301/btstack_chipset_em9301.c (revision 6cee6f09206f4d96ba4fe7c3e976570600289f0d)
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 
100*6cee6f09SMatthias Ringwald // Quick CRC32 implementation using 4-bit lookup table
101*6cee6f09SMatthias Ringwald static const uint32_t crc32_table[16] = {
102*6cee6f09SMatthias Ringwald 	0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
103*6cee6f09SMatthias Ringwald 	0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
104*6cee6f09SMatthias Ringwald };
105*6cee6f09SMatthias Ringwald 
106*6cee6f09SMatthias Ringwald uint32_t btstack_crc32(const uint8_t *buf, uint16_t size){
107*6cee6f09SMatthias Ringwald 	uint16_t pos;
108*6cee6f09SMatthias Ringwald 	uint32_t crc32 = 0xffffffff;
109*6cee6f09SMatthias Ringwald 	for (pos=0 ; pos<size ; pos++){
110*6cee6f09SMatthias Ringwald 		uint8_t b = buf[pos];
111*6cee6f09SMatthias Ringwald 		crc32 = (crc32 >> 4) ^ crc32_table[(crc32 & 0x0F) ^ (b & 0x0F)];
112*6cee6f09SMatthias Ringwald 		crc32 = (crc32 >> 4) ^ crc32_table[(crc32 & 0x0F) ^ (b >>   4)];
113*6cee6f09SMatthias Ringwald 	}
114*6cee6f09SMatthias Ringwald 	return ~crc32;
115*6cee6f09SMatthias Ringwald }
116d080547cSMatthias Ringwald 
117faa6c1f6SMatthias Ringwald static void chipset_set_bd_addr_command(bd_addr_t addr, uint8_t *hci_cmd_buffer){
118f8fbdce0SMatthias Ringwald     little_endian_store_16(hci_cmd_buffer, 0, OPCODE(OGF_VENDOR, 0x02));
119faa6c1f6SMatthias Ringwald     hci_cmd_buffer[2] = 0x06;
120a47028edSMatthias Ringwald     reverse_bd_addr(addr, &hci_cmd_buffer[3]);
121faa6c1f6SMatthias Ringwald }
122faa6c1f6SMatthias Ringwald 
123d40c3de0SMatthias Ringwald static void chipset_set_baudrate_command(uint32_t baudrate, uint8_t *hci_cmd_buffer){
124d40c3de0SMatthias Ringwald 	// lookup baudrates
125d40c3de0SMatthias Ringwald 	int i;
1269ba7722dSMatthias Ringwald 	int found = 0;
127d40c3de0SMatthias Ringwald 	for (i=0 ; i < sizeof(baudrates)/sizeof(uint32_t) ; i++){
128d40c3de0SMatthias Ringwald 		if (baudrates[i] == baudrate){
129d40c3de0SMatthias Ringwald 			found = i;
130d40c3de0SMatthias Ringwald 			break;
131d40c3de0SMatthias Ringwald 		}
132d40c3de0SMatthias Ringwald 	}
133d40c3de0SMatthias Ringwald 	if (!found){
134d40c3de0SMatthias Ringwald 		log_error("Baudrate %u not found in table", baudrate);
135d40c3de0SMatthias Ringwald 		return;
136d40c3de0SMatthias Ringwald 	}
137d40c3de0SMatthias Ringwald     little_endian_store_16(hci_cmd_buffer, 0, OPCODE(OGF_VENDOR, 0x07));
138d40c3de0SMatthias Ringwald     hci_cmd_buffer[2] = 0x01;
139d40c3de0SMatthias Ringwald     hci_cmd_buffer[3] = i;
140d40c3de0SMatthias Ringwald }
141d40c3de0SMatthias Ringwald 
142d080547cSMatthias Ringwald #ifdef HAVE_EM9304_PATCH_CONTAINER
143d080547cSMatthias Ringwald static void chipset_init(const void * config){
144d080547cSMatthias Ringwald 	UNUSED(config);
145d080547cSMatthias Ringwald 	container_blob_offset = 0;
146d080547cSMatthias Ringwald 	em_cpu_reset_sent = 0;
147d080547cSMatthias Ringwald 	upload_state = UPLOAD_IDLE;
148d080547cSMatthias Ringwald }
149d080547cSMatthias Ringwald 
150d080547cSMatthias Ringwald static btstack_chipset_result_t chipset_next_command(uint8_t * hci_cmd_buffer){
151d080547cSMatthias Ringwald 	log_info("pos %u, container end %u, blob size %u", container_blob_offset, container_end, container_blob_size);
152d080547cSMatthias Ringwald 
153d080547cSMatthias Ringwald     if (container_blob_offset >= container_blob_size) {
154d080547cSMatthias Ringwald     	if (0 == em_cpu_reset_sent){
155d080547cSMatthias Ringwald     		// send EM CPU Reset
156d080547cSMatthias Ringwald 		    little_endian_store_16(hci_cmd_buffer, 0, HCI_OPCODE_EM_CPU_RESET);
157d080547cSMatthias Ringwald 		    hci_cmd_buffer[2] = 0;
158d080547cSMatthias Ringwald 		    em_cpu_reset_sent = 1;
159d080547cSMatthias Ringwald 		    return BTSTACK_CHIPSET_VALID_COMMAND;
160d080547cSMatthias Ringwald     	} else {
161d080547cSMatthias Ringwald 	        return BTSTACK_CHIPSET_DONE;
162d080547cSMatthias Ringwald     	}
163d080547cSMatthias Ringwald     }
164d080547cSMatthias Ringwald 
165d080547cSMatthias Ringwald     uint32_t tag;
166d080547cSMatthias Ringwald     uint16_t bytes_to_upload;
167d080547cSMatthias Ringwald     uint32_t crc;
168d080547cSMatthias Ringwald 
169d080547cSMatthias Ringwald 	switch (upload_state){
170d080547cSMatthias Ringwald 		case UPLOAD_IDLE:
171d080547cSMatthias Ringwald 			// check for 'em93' tag
172d080547cSMatthias Ringwald 			tag = little_endian_read_32(container_blob_data, container_blob_offset);
173d080547cSMatthias Ringwald 			if (0x656d3933 != tag) {
174d080547cSMatthias Ringwald 				log_error("Expected 0x656d3933 ('em934') but got %08x", tag);
175d080547cSMatthias Ringwald 				return BTSTACK_CHIPSET_DONE;
176d080547cSMatthias Ringwald 			}
177d080547cSMatthias Ringwald 			// fetch info for current container
178d080547cSMatthias Ringwald 			container_end = container_blob_offset + little_endian_read_32(container_blob_data, container_blob_offset + 4);
179d080547cSMatthias Ringwald 			// start uploading (<= 59 bytes)
180d080547cSMatthias Ringwald 			patch_sequence_number = 1;
181d080547cSMatthias Ringwald 			bytes_to_upload = btstack_min(59, container_end - container_blob_offset);
182*6cee6f09SMatthias Ringwald 			crc = btstack_crc32(&container_blob_data[container_blob_offset], bytes_to_upload);
183d080547cSMatthias Ringwald 			// build command
184d080547cSMatthias Ringwald 		    little_endian_store_16(hci_cmd_buffer, 0, HCI_OPCODE_EM_WRITE_PATCH_START);
185d080547cSMatthias Ringwald 		    hci_cmd_buffer[2] = 5 + bytes_to_upload;
186d080547cSMatthias Ringwald 		    hci_cmd_buffer[3] = 0;	// upload to iRAM1
187d080547cSMatthias Ringwald 		    little_endian_store_32(hci_cmd_buffer, 4, crc);
188d080547cSMatthias Ringwald 		    memcpy(&hci_cmd_buffer[8], &container_blob_data[container_blob_offset], bytes_to_upload);
189d080547cSMatthias Ringwald 		    container_blob_offset += bytes_to_upload;
190d080547cSMatthias Ringwald 		    if (container_blob_offset < container_end){
191d080547cSMatthias Ringwald 		    	upload_state = UPLOAD_ACTIVE;
192d080547cSMatthias Ringwald 		    }
193d080547cSMatthias Ringwald 		    return BTSTACK_CHIPSET_VALID_COMMAND;
194d080547cSMatthias Ringwald 		case UPLOAD_ACTIVE:
195d080547cSMatthias Ringwald 			// Upload next segement
196d080547cSMatthias Ringwald 			bytes_to_upload = btstack_min(58, container_end - container_blob_offset);
197*6cee6f09SMatthias Ringwald 			crc = btstack_crc32(&container_blob_data[container_blob_offset], bytes_to_upload);
198d080547cSMatthias Ringwald 			// build command
199d080547cSMatthias Ringwald 		    little_endian_store_16(hci_cmd_buffer, 0, HCI_OPCODE_EM_WRITE_PATCH_CONTINUE);
200d080547cSMatthias Ringwald 		    hci_cmd_buffer[2] = 6 + bytes_to_upload;
201d080547cSMatthias Ringwald 		    little_endian_store_16(hci_cmd_buffer, 3, patch_sequence_number++);
202d080547cSMatthias Ringwald 		    little_endian_store_32(hci_cmd_buffer, 5, crc);
203d080547cSMatthias Ringwald 		    memcpy(&hci_cmd_buffer[9], &container_blob_data[container_blob_offset], bytes_to_upload);
204d080547cSMatthias Ringwald 		    container_blob_offset += bytes_to_upload;
205d080547cSMatthias Ringwald 		    if (container_blob_offset >= container_end){
206d080547cSMatthias Ringwald 		    	log_info("container done maybe another one");
207d080547cSMatthias Ringwald 		    	upload_state = UPLOAD_IDLE;
208d080547cSMatthias Ringwald 		    }
209d080547cSMatthias Ringwald 		    return BTSTACK_CHIPSET_VALID_COMMAND;
210d080547cSMatthias Ringwald 	}
211d080547cSMatthias Ringwald 	return BTSTACK_CHIPSET_DONE;
212d080547cSMatthias Ringwald }
213d080547cSMatthias Ringwald #endif
214d080547cSMatthias Ringwald 
215faa6c1f6SMatthias Ringwald static const btstack_chipset_t btstack_chipset_em9301 = {
216faa6c1f6SMatthias Ringwald     "EM9301",
217d080547cSMatthias Ringwald #ifdef HAVE_EM9304_PATCH_CONTAINER
218d080547cSMatthias Ringwald     chipset_init,
219d080547cSMatthias Ringwald     chipset_next_command,
220d080547cSMatthias Ringwald #else
221d080547cSMatthias Ringwald     NULL,
222d080547cSMatthias Ringwald     NULL,
223d080547cSMatthias Ringwald #endif
224d40c3de0SMatthias Ringwald     chipset_set_baudrate_command,
225faa6c1f6SMatthias Ringwald     chipset_set_bd_addr_command,
226faa6c1f6SMatthias Ringwald };
227faa6c1f6SMatthias Ringwald 
228faa6c1f6SMatthias Ringwald // MARK: public API
229faa6c1f6SMatthias Ringwald const btstack_chipset_t * btstack_chipset_em9301_instance(void){
230faa6c1f6SMatthias Ringwald     return &btstack_chipset_em9301;
231faa6c1f6SMatthias Ringwald }
232