xref: /btstack/chipset/em9301/btstack_chipset_em9301.c (revision 5449042e9fc2fa326f6b29b4b9e34c99c0d61fce)
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
232fca4dadSMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald  * GMBH 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 
38e501bae0SMatthias 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 
6470d74889SMatthias Ringwald /**
6570d74889SMatthias Ringwald  * @param bd_addr
6670d74889SMatthias Ringwald  */
6770d74889SMatthias Ringwald const hci_cmd_t hci_vendor_em_set_public_address = {
6870d74889SMatthias Ringwald     0xFC02, "B"
6970d74889SMatthias Ringwald };
7070d74889SMatthias Ringwald 
7170d74889SMatthias Ringwald /**
7270d74889SMatthias Ringwald  * @param baud_rate_index
7370d74889SMatthias Ringwald  */
7470d74889SMatthias Ringwald const hci_cmd_t hci_vendor_em_set_uart_baudrate = {
7570d74889SMatthias Ringwald     0xFC07, "1"
7670d74889SMatthias Ringwald };
7770d74889SMatthias Ringwald 
7870d74889SMatthias Ringwald /**
7970d74889SMatthias Ringwald  * @param transmitter_test_mode
8070d74889SMatthias Ringwald  * @param channel_number
8170d74889SMatthias Ringwald  * @param packet_length
8270d74889SMatthias Ringwald  * @param packet_payload_type
8370d74889SMatthias Ringwald  */
8470d74889SMatthias Ringwald const hci_cmd_t hci_vendor_em_transmitter_test = {
8570d74889SMatthias Ringwald     0xFC11, "1111"
8670d74889SMatthias Ringwald };
8770d74889SMatthias Ringwald 
8870d74889SMatthias Ringwald /**
8970d74889SMatthias Ringwald  */
9070d74889SMatthias Ringwald const hci_cmd_t hci_vendor_em_transmitter_test_end = {
9170d74889SMatthias Ringwald     0xFC12, ""
9270d74889SMatthias Ringwald };
9370d74889SMatthias Ringwald 
9470d74889SMatthias Ringwald /**
9570d74889SMatthias Ringwald  * @param patch_index
9670d74889SMatthias Ringwald  */
9770d74889SMatthias Ringwald const hci_cmd_t hci_vendor_em_patch_query = {
9870d74889SMatthias Ringwald     0xFC34, "2"
9970d74889SMatthias Ringwald };
10070d74889SMatthias Ringwald 
10170d74889SMatthias Ringwald /**
10270d74889SMatthias Ringwald  * Change the state of the selected memory.
10370d74889SMatthias Ringwald  * @param memory_attribute
10470d74889SMatthias Ringwald  */
10570d74889SMatthias Ringwald const hci_cmd_t hci_vendor_em_set_memory_mode = {
10670d74889SMatthias Ringwald     0xFC2B, "1"
10770d74889SMatthias Ringwald };
10870d74889SMatthias Ringwald 
10970d74889SMatthias Ringwald /**
11070d74889SMatthias Ringwald  * @param sleep_option_settings
11170d74889SMatthias Ringwald  */
11270d74889SMatthias Ringwald const hci_cmd_t hci_vendor_em_set_sleep_options = {
11370d74889SMatthias Ringwald     0xFC2D, "1"
11470d74889SMatthias Ringwald };
11570d74889SMatthias Ringwald 
11670d74889SMatthias Ringwald // baudrate to index for hci_vendor_em_set_uart_baudrate
117d40c3de0SMatthias Ringwald static const uint32_t baudrates[] = {
118d40c3de0SMatthias Ringwald 	      0,
119d40c3de0SMatthias Ringwald 	      0,
120d40c3de0SMatthias Ringwald 	      0,
121d40c3de0SMatthias Ringwald 	   9600,
122d40c3de0SMatthias Ringwald 	  14400,
123d40c3de0SMatthias Ringwald 	  19200,
124d40c3de0SMatthias Ringwald 	  28800,
125d40c3de0SMatthias Ringwald 	  38400,
126d40c3de0SMatthias Ringwald 	  57600,
127d40c3de0SMatthias Ringwald 	  76800,
128d40c3de0SMatthias Ringwald 	 115200,
129d40c3de0SMatthias Ringwald 	 230400,
130d40c3de0SMatthias Ringwald 	 460800,
131d40c3de0SMatthias Ringwald 	 921600,
132d40c3de0SMatthias Ringwald 	1843200,
133d40c3de0SMatthias Ringwald };
134faa6c1f6SMatthias Ringwald 
135d080547cSMatthias Ringwald #ifdef HAVE_EM9304_PATCH_CONTAINER
136d080547cSMatthias Ringwald 
137d080547cSMatthias Ringwald extern const uint8_t   container_blob_data[];
138d080547cSMatthias Ringwald extern const uint32_t  container_blob_size;
139d080547cSMatthias Ringwald 
140d080547cSMatthias Ringwald static uint32_t container_blob_offset  = 0;
141d080547cSMatthias Ringwald static uint32_t container_end;	// current container
142d080547cSMatthias Ringwald static uint16_t patch_sequence_number;
143d080547cSMatthias Ringwald static int      em_cpu_reset_sent;
144d080547cSMatthias Ringwald 
145d080547cSMatthias Ringwald static enum {
146d080547cSMatthias Ringwald 	UPLOAD_IDLE,
147d080547cSMatthias Ringwald 	UPLOAD_ACTIVE,
148d080547cSMatthias Ringwald } upload_state;
149d080547cSMatthias Ringwald 
150d080547cSMatthias Ringwald 
151d7587826SMatthias Ringwald // CRC32 implementation using 4-bit lookup table created by pycrc v0.9.1, https://pycrc.org
152d7587826SMatthias Ringwald // ./pycrc.py --model crc-32 --algorithm table-driven --table-idx-width=4 --generate c
1536cee6f09SMatthias Ringwald static const uint32_t crc32_table[16] = {
1546cee6f09SMatthias Ringwald 	0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
1556cee6f09SMatthias Ringwald 	0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
1566cee6f09SMatthias Ringwald };
1576cee6f09SMatthias Ringwald 
btstack_crc32(const uint8_t * buf,uint16_t size)158946d87baSMatthias Ringwald static uint32_t btstack_crc32(const uint8_t *buf, uint16_t size){
1596cee6f09SMatthias Ringwald 	uint16_t pos;
160d7587826SMatthias Ringwald 	uint32_t crc = 0xffffffff;
1616cee6f09SMatthias Ringwald 	for (pos=0 ; pos<size ; pos++){
162d7587826SMatthias Ringwald         int tbl_idx = crc ^ buf[pos];
163d7587826SMatthias Ringwald         crc = crc32_table[tbl_idx & 0x0f] ^ (crc >> 4);
164d7587826SMatthias Ringwald         tbl_idx = crc ^ (buf[pos] >> 4);
165d7587826SMatthias Ringwald         crc = crc32_table[tbl_idx & 0x0f] ^ (crc >> 4);
1666cee6f09SMatthias Ringwald     }
167d7587826SMatthias Ringwald 	return ~crc;
1686cee6f09SMatthias Ringwald }
169d080547cSMatthias Ringwald 
170946d87baSMatthias Ringwald #endif
171946d87baSMatthias Ringwald 
chipset_set_bd_addr_command(bd_addr_t addr,uint8_t * hci_cmd_buffer)172faa6c1f6SMatthias Ringwald static void chipset_set_bd_addr_command(bd_addr_t addr, uint8_t *hci_cmd_buffer){
173f8fbdce0SMatthias Ringwald     little_endian_store_16(hci_cmd_buffer, 0, OPCODE(OGF_VENDOR, 0x02));
174faa6c1f6SMatthias Ringwald     hci_cmd_buffer[2] = 0x06;
175a47028edSMatthias Ringwald     reverse_bd_addr(addr, &hci_cmd_buffer[3]);
176faa6c1f6SMatthias Ringwald }
177faa6c1f6SMatthias Ringwald 
chipset_set_baudrate_command(uint32_t baudrate,uint8_t * hci_cmd_buffer)178d40c3de0SMatthias Ringwald static void chipset_set_baudrate_command(uint32_t baudrate, uint8_t *hci_cmd_buffer){
179d40c3de0SMatthias Ringwald 	// lookup baudrates
180*5449042eSMatthias Ringwald 	unsigned i;
1819ba7722dSMatthias Ringwald 	int found = 0;
182d40c3de0SMatthias Ringwald 	for (i=0 ; i < sizeof(baudrates)/sizeof(uint32_t) ; i++){
183d40c3de0SMatthias Ringwald 		if (baudrates[i] == baudrate){
184d40c3de0SMatthias Ringwald 			found = i;
185d40c3de0SMatthias Ringwald 			break;
186d40c3de0SMatthias Ringwald 		}
187d40c3de0SMatthias Ringwald 	}
188d40c3de0SMatthias Ringwald 	if (!found){
189d40c3de0SMatthias Ringwald 		log_error("Baudrate %u not found in table", baudrate);
190d40c3de0SMatthias Ringwald 		return;
191d40c3de0SMatthias Ringwald 	}
192d40c3de0SMatthias Ringwald     little_endian_store_16(hci_cmd_buffer, 0, OPCODE(OGF_VENDOR, 0x07));
193d40c3de0SMatthias Ringwald     hci_cmd_buffer[2] = 0x01;
194d40c3de0SMatthias Ringwald     hci_cmd_buffer[3] = i;
195d40c3de0SMatthias Ringwald }
196d40c3de0SMatthias Ringwald 
197d080547cSMatthias Ringwald #ifdef HAVE_EM9304_PATCH_CONTAINER
chipset_init(const void * config)198d080547cSMatthias Ringwald static void chipset_init(const void * config){
199d080547cSMatthias Ringwald 	UNUSED(config);
200d080547cSMatthias Ringwald 	container_blob_offset = 0;
201d080547cSMatthias Ringwald 	em_cpu_reset_sent = 0;
202d080547cSMatthias Ringwald 	upload_state = UPLOAD_IDLE;
203d080547cSMatthias Ringwald }
204d080547cSMatthias Ringwald 
chipset_next_command(uint8_t * hci_cmd_buffer)205d080547cSMatthias Ringwald static btstack_chipset_result_t chipset_next_command(uint8_t * hci_cmd_buffer){
206d080547cSMatthias Ringwald 	log_info("pos %u, container end %u, blob size %u", container_blob_offset, container_end, container_blob_size);
207d080547cSMatthias Ringwald 
208d080547cSMatthias Ringwald     if (container_blob_offset >= container_blob_size) {
209d080547cSMatthias Ringwald     	if (0 == em_cpu_reset_sent){
210d080547cSMatthias Ringwald     		// send EM CPU Reset
211d080547cSMatthias Ringwald 		    little_endian_store_16(hci_cmd_buffer, 0, HCI_OPCODE_EM_CPU_RESET);
212d080547cSMatthias Ringwald 		    hci_cmd_buffer[2] = 0;
213d080547cSMatthias Ringwald 		    em_cpu_reset_sent = 1;
214d080547cSMatthias Ringwald 		    return BTSTACK_CHIPSET_VALID_COMMAND;
215d080547cSMatthias Ringwald     	} else {
216d080547cSMatthias Ringwald 	        return BTSTACK_CHIPSET_DONE;
217d080547cSMatthias Ringwald     	}
218d080547cSMatthias Ringwald     }
219d080547cSMatthias Ringwald 
220d080547cSMatthias Ringwald     uint32_t tag;
221d080547cSMatthias Ringwald     uint16_t bytes_to_upload;
222d080547cSMatthias Ringwald     uint32_t crc;
2231882d12dSMatthias Ringwald     uint32_t container_size;
224d080547cSMatthias Ringwald 
225d080547cSMatthias Ringwald 	switch (upload_state){
226d080547cSMatthias Ringwald 		case UPLOAD_IDLE:
227d080547cSMatthias Ringwald 			// check for 'em93' tag
228d080547cSMatthias Ringwald 			tag = little_endian_read_32(container_blob_data, container_blob_offset);
229d080547cSMatthias Ringwald 			if (0x656d3933 != tag) {
2301882d12dSMatthias Ringwald 				log_error("Expected 0x656d3933 ('em934') but got %08x", (int) tag);
231d080547cSMatthias Ringwald 				return BTSTACK_CHIPSET_DONE;
232d080547cSMatthias Ringwald 			}
233d080547cSMatthias Ringwald 			// fetch info for current container
2341882d12dSMatthias Ringwald 			container_size = little_endian_read_32(container_blob_data, container_blob_offset + 4);
2351882d12dSMatthias Ringwald 			container_end = container_blob_offset + container_size;
236d080547cSMatthias Ringwald 			// start uploading (<= 59 bytes)
237d080547cSMatthias Ringwald 			patch_sequence_number = 1;
238d080547cSMatthias Ringwald 			bytes_to_upload = btstack_min(59, container_end - container_blob_offset);
2396cee6f09SMatthias Ringwald 			crc = btstack_crc32(&container_blob_data[container_blob_offset], bytes_to_upload);
2401882d12dSMatthias Ringwald 			log_info("Container type 0x%02x, id %u, build nr %u, user build nr %u, size %u",
2411882d12dSMatthias Ringwald 				(int) container_blob_data[container_blob_offset+9],
2421882d12dSMatthias Ringwald 				(int) container_blob_data[container_blob_offset+10],
2431882d12dSMatthias Ringwald 				(int) little_endian_read_16(container_blob_data, container_blob_offset+12),
2441882d12dSMatthias Ringwald 				(int) little_endian_read_16(container_blob_data, container_blob_offset+14),
2451882d12dSMatthias Ringwald 				(int) container_size);
246d080547cSMatthias Ringwald 			// build command
247d080547cSMatthias Ringwald 		    little_endian_store_16(hci_cmd_buffer, 0, HCI_OPCODE_EM_WRITE_PATCH_START);
248d080547cSMatthias Ringwald 		    hci_cmd_buffer[2] = 5 + bytes_to_upload;
249d080547cSMatthias Ringwald 		    hci_cmd_buffer[3] = 0;	// upload to iRAM1
250d080547cSMatthias Ringwald 		    little_endian_store_32(hci_cmd_buffer, 4, crc);
251d080547cSMatthias Ringwald 		    memcpy(&hci_cmd_buffer[8], &container_blob_data[container_blob_offset], bytes_to_upload);
252d080547cSMatthias Ringwald 		    container_blob_offset += bytes_to_upload;
253d080547cSMatthias Ringwald 		    if (container_blob_offset < container_end){
254d080547cSMatthias Ringwald 		    	upload_state = UPLOAD_ACTIVE;
255d080547cSMatthias Ringwald 		    }
256d080547cSMatthias Ringwald 		    return BTSTACK_CHIPSET_VALID_COMMAND;
257d080547cSMatthias Ringwald 		case UPLOAD_ACTIVE:
258d080547cSMatthias Ringwald 			// Upload next segement
259d080547cSMatthias Ringwald 			bytes_to_upload = btstack_min(58, container_end - container_blob_offset);
2606cee6f09SMatthias Ringwald 			crc = btstack_crc32(&container_blob_data[container_blob_offset], bytes_to_upload);
261d080547cSMatthias Ringwald 			// build command
262d080547cSMatthias Ringwald 		    little_endian_store_16(hci_cmd_buffer, 0, HCI_OPCODE_EM_WRITE_PATCH_CONTINUE);
263d080547cSMatthias Ringwald 		    hci_cmd_buffer[2] = 6 + bytes_to_upload;
264d080547cSMatthias Ringwald 		    little_endian_store_16(hci_cmd_buffer, 3, patch_sequence_number++);
265d080547cSMatthias Ringwald 		    little_endian_store_32(hci_cmd_buffer, 5, crc);
266d080547cSMatthias Ringwald 		    memcpy(&hci_cmd_buffer[9], &container_blob_data[container_blob_offset], bytes_to_upload);
267d080547cSMatthias Ringwald 		    container_blob_offset += bytes_to_upload;
268d080547cSMatthias Ringwald 		    if (container_blob_offset >= container_end){
269d080547cSMatthias Ringwald 		    	log_info("container done maybe another one");
270d080547cSMatthias Ringwald 		    	upload_state = UPLOAD_IDLE;
271d080547cSMatthias Ringwald 		    }
272d080547cSMatthias Ringwald 		    return BTSTACK_CHIPSET_VALID_COMMAND;
2737bbeb3adSMilanka Ringwald         default:
2747bbeb3adSMilanka Ringwald             btstack_assert(false);
2757bbeb3adSMilanka Ringwald             break;
276d080547cSMatthias Ringwald 	}
277d080547cSMatthias Ringwald 	return BTSTACK_CHIPSET_DONE;
278d080547cSMatthias Ringwald }
279d080547cSMatthias Ringwald #endif
280d080547cSMatthias Ringwald 
281faa6c1f6SMatthias Ringwald static const btstack_chipset_t btstack_chipset_em9301 = {
282faa6c1f6SMatthias Ringwald     "EM9301",
283d080547cSMatthias Ringwald #ifdef HAVE_EM9304_PATCH_CONTAINER
284d080547cSMatthias Ringwald     chipset_init,
285d080547cSMatthias Ringwald     chipset_next_command,
286d080547cSMatthias Ringwald #else
287d080547cSMatthias Ringwald     NULL,
288d080547cSMatthias Ringwald     NULL,
289d080547cSMatthias Ringwald #endif
290d40c3de0SMatthias Ringwald     chipset_set_baudrate_command,
291faa6c1f6SMatthias Ringwald     chipset_set_bd_addr_command,
292faa6c1f6SMatthias Ringwald };
293faa6c1f6SMatthias Ringwald 
294faa6c1f6SMatthias Ringwald // MARK: public API
btstack_chipset_em9301_instance(void)295faa6c1f6SMatthias Ringwald const btstack_chipset_t * btstack_chipset_em9301_instance(void){
296faa6c1f6SMatthias Ringwald     return &btstack_chipset_em9301;
297faa6c1f6SMatthias Ringwald }
298