1 /*
2  * Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <stdlib.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include <inttypes.h>
11 
12 #include "cyw43_btbus.h"
13 #include "cyw43_ll.h"
14 #include "cyw43_config.h"
15 #include "cybt_shared_bus_driver.h"
16 
17 #include "cyw43_btfw_43439.h"
18 
19 #if CYW43_USE_HEX_BTFW
20 extern const char    brcm_patch_version[];
21 extern const uint8_t brcm_patchram_buf[];
22 extern const int     brcm_patch_ram_length;
23 #endif
24 
25 #define  BTSDIO_FW_READY_POLLING_INTERVAL_MS   (1)
26 #define  BTSDIO_BT_AWAKE_POLLING_INTERVAL_MS   (1)
27 
28 #define  BTSDIO_FW_READY_POLLING_RETRY_COUNT   (300)
29 #define  BTSDIO_FW_AWAKE_POLLING_RETRY_COUNT   (300)
30 
31 #define  BTSDIO_FWBUF_OPER_DELAY_US            (250)
32 #define  BTFW_WAIT_TIME_MS                     (150)
33 
34 #define CYBT_DEBUG 0
35 #define CYBT_VDEBUG 0
36 
37 #if CYBT_DEBUG
38 #define cybt_debug(format,args...) printf("%d.%d: " format, (int)cyw43_hal_ticks_ms() / 1000, (int)cyw43_hal_ticks_ms() % 1000, ## args)
39 #else
40 #define cybt_debug(format, ...) ((void)0)
41 #endif
42 #define cybt_printf(format, args...) printf("%d.%d: " format, (int)cyw43_hal_ticks_ms() / 1000, (int)cyw43_hal_ticks_ms() % 1000, ## args)
43 
44 #define ROUNDUP(x, a)               ((((x) + ((a) - 1)) / (a)) * (a))
45 #define ROUNDDN(x, a)               ((x) & ~((a) - 1))
46 #define ISALIGNED(a, x)             (((uint32_t)(a) & ((x) - 1)) == 0)
47 
48 #define  CIRC_BUF_CNT(in, out)  (((in) - (out)) & ((BTSDIO_FWBUF_SIZE)-1))
49 #define  CIRC_BUF_SPACE(in, out)  CIRC_BUF_CNT((out), ((in) + 4))
50 
51 typedef enum {
52     HCI_PACKET_TYPE_IGNORE = 0x00,
53     HCI_PACKET_TYPE_COMMAND = 0x01,
54     HCI_PACKET_TYPE_ACL = 0x02,
55     HCI_PACKET_TYPE_SCO = 0x03,
56     HCI_PACKET_TYPE_EVENT = 0x04,
57     HCI_PACKET_TYPE_DIAG = 0x07,
58     HCI_PACKET_TYPE_LOOPBACK = 0xFF
59 } hci_packet_type_t;
60 
cybt_fw_download_prepare(uint8_t ** p_write_buf,uint8_t ** p_hex_buf)61 static cybt_result_t cybt_fw_download_prepare(uint8_t **p_write_buf, uint8_t **p_hex_buf) {
62     *p_write_buf = NULL;
63     *p_hex_buf = NULL;
64 
65     *p_write_buf = cyw43_malloc(BTFW_DOWNLOAD_BLK_SIZE + BTFW_SD_ALIGN);
66     if (NULL == *p_write_buf) {
67         return CYBT_ERR_OUT_OF_MEMORY;
68     }
69 
70     *p_hex_buf = cyw43_malloc(BTFW_MAX_STR_LEN);
71     if (NULL == *p_hex_buf) {
72         cyw43_free(*p_write_buf);
73         return CYBT_ERR_OUT_OF_MEMORY;
74     }
75 
76     return CYBT_SUCCESS;
77 }
78 
cybt_fw_download_finish(uint8_t * p_write_buf,uint8_t * p_hex_buf)79 static cybt_result_t cybt_fw_download_finish(uint8_t *p_write_buf, uint8_t *p_hex_buf) {
80     if (p_write_buf) {
81         cyw43_free(p_write_buf);
82     }
83 
84     if (p_hex_buf) {
85         cyw43_free(p_hex_buf);
86     }
87 
88     return CYBT_SUCCESS;
89 }
90 
cybt_wait_bt_ready(uint32_t max_polling_times)91 static cybt_result_t cybt_wait_bt_ready(uint32_t max_polling_times) {
92     cyw43_delay_ms(BTFW_WAIT_TIME_MS);
93     do {
94         if (cybt_ready()) {
95             return CYBT_SUCCESS;
96         }
97         cyw43_delay_ms(BTSDIO_FW_READY_POLLING_INTERVAL_MS);
98     } while (max_polling_times--);
99     return CYBT_ERR_TIMEOUT;
100 }
101 
cybt_wait_bt_awake(uint32_t max_polling_times)102 static cybt_result_t cybt_wait_bt_awake(uint32_t max_polling_times) {
103     do {
104         if (cybt_awake()) {
105             return CYBT_SUCCESS;
106         }
107         cyw43_delay_ms(BTSDIO_BT_AWAKE_POLLING_INTERVAL_MS);
108     } while (max_polling_times--);
109     return CYBT_ERR_TIMEOUT;
110 }
111 
cyw43_btbus_init(cyw43_ll_t * self)112 int cyw43_btbus_init(cyw43_ll_t *self) {
113     cybt_result_t ret;
114 
115     uint8_t *p_write_buf = NULL;
116     uint8_t *p_hex_buf = NULL;
117 
118     cybt_sharedbus_driver_init(self);
119 
120     ret = cybt_fw_download_prepare(&p_write_buf, &p_hex_buf);
121     if (CYBT_SUCCESS != ret) {
122         cybt_printf("Could not allocate memory\n");
123         return ret;
124     }
125 
126     cybt_debug("cybt_fw_download\n");
127     const uint8_t *fw_data_buf;
128     uint32_t fw_data_len;
129 #if CYW43_USE_HEX_BTFW
130     cybt_printf("CYW43_USE_HEX_BTFW is true\n");
131 #ifndef NDEBUG
132     cybt_printf("BT FW download, version = %s\n", brcm_patch_version);
133 #endif
134     fw_data_len = brcm_patch_ram_length;
135     fw_data_buf = brcm_patchram_buf;
136 #else
137     fw_data_len = cyw43_btfw_43439_len;
138     fw_data_buf = cyw43_btfw_43439;
139 #endif
140     ret = cybt_fw_download(fw_data_buf,
141                            fw_data_len,
142                            p_write_buf,
143                            p_hex_buf
144     );
145 
146     cybt_debug("cybt_fw_download_finish\n");
147     cybt_fw_download_finish(p_write_buf, p_hex_buf);
148 
149     if (CYBT_SUCCESS != ret) {
150         cybt_printf("hci_open(): FW download failed (0x%x)\n", ret);
151         return CYBT_ERR_HCI_INIT_FAILED;
152     }
153 
154     cybt_debug("// cybt_wait_bt_ready\n");
155     ret = cybt_wait_bt_ready(BTSDIO_FW_READY_POLLING_RETRY_COUNT);
156     assert(ret == CYBT_SUCCESS);
157     if (CYBT_SUCCESS == ret) {
158         cybt_debug("hci_open(): FW download successfully\n");
159     } else {
160         cybt_printf("hci_open(): Failed to download FW\n");
161         return CYBT_ERR_HCI_INIT_FAILED;
162     }
163 
164     ret = cybt_init_buffer();
165     assert(ret == 0);
166     if (ret != 0) {
167         return ret;
168     }
169     ret = cybt_wait_bt_awake(BTSDIO_FW_AWAKE_POLLING_RETRY_COUNT);
170     assert(ret == 0);
171     if (ret != 0) {
172         return ret;
173     }
174 
175     cybt_set_host_ready();
176     cybt_toggle_bt_intr();
177 
178     return CYBT_SUCCESS;
179 }
180 
181 #if CYBT_VDEBUG
dump_bytes(const uint8_t * bptr,uint32_t len)182 static void dump_bytes(const uint8_t *bptr, uint32_t len) {
183     unsigned int i = 0;
184 
185     for (i = 0; i < len; i++) {
186         if ((i & 0x07) == 0) {
187             printf("\n        ");
188         }
189         printf("0x%02x", bptr[i]);
190         if (i != (len-1)) {
191             printf(", ");
192         } else {
193         }
194     }
195     printf("\n");
196 }
197 #endif
198 
cybt_hci_write_buf(const uint8_t * p_data,uint32_t length)199 static cybt_result_t cybt_hci_write_buf(const uint8_t *p_data, uint32_t length) {
200     cybt_result_t ret_result = CYBT_SUCCESS;
201     cybt_fw_membuf_index_t fw_membuf_info = {0};
202 
203     assert(ISALIGNED(p_data, 4));
204     if (!ISALIGNED(p_data, 4)) {
205         cybt_printf("cybt_hci_write_hdr: buffer not aligned\n");
206         return CYBT_ERR_BADARG;
207     }
208 
209     // total length including header
210     length = ROUNDUP(length, 4);
211     cybt_get_bt_buf_index(&fw_membuf_info);
212     uint32_t buf_space = CIRC_BUF_SPACE(fw_membuf_info.host2bt_in_val, fw_membuf_info.host2bt_out_val);
213     assert(length <= buf_space); // queue full?
214     if (length > buf_space) {
215         return CYBT_ERR_QUEUE_FULL;
216     }
217 
218     if (fw_membuf_info.host2bt_in_val + length <= BTSDIO_FWBUF_SIZE) {
219         // Don't need to wrap circular buf
220         cybt_debug("cybt_hci_write_hdr: 1-round write, len = %" PRId32 "\n", length);
221         cybt_mem_write_idx(H2B_BUF_ADDR_IDX, fw_membuf_info.host2bt_in_val, p_data, length);
222         fw_membuf_info.host2bt_in_val += length;
223     } else {
224         // Need to wrap circular buf
225         uint32_t first_write_len = BTSDIO_FWBUF_SIZE - fw_membuf_info.host2bt_in_val;
226         if (first_write_len >= 4) {
227             cybt_mem_write_idx(H2B_BUF_ADDR_IDX, fw_membuf_info.host2bt_in_val, p_data, first_write_len);
228             fw_membuf_info.host2bt_in_val += first_write_len;
229         } else {
230             first_write_len = 0;
231         }
232         uint32_t second_write_len = length - first_write_len;
233         cybt_debug("cybt_hci_write_hdr: 2-round write, 1st_len = %" PRId32 ", 2nd_len = %" PRId32 "\n", first_write_len,
234                    second_write_len);
235         if (second_write_len > 0) {
236             cybt_mem_write_idx(H2B_BUF_ADDR_IDX, 0, p_data + first_write_len, second_write_len);
237             fw_membuf_info.host2bt_in_val += second_write_len;
238         }
239     }
240 
241     // Update circular buf pointer
242     const uint32_t new_h2b_in_val = fw_membuf_info.host2bt_in_val & (BTSDIO_FWBUF_SIZE - 1);
243     cybt_reg_write_idx(H2B_BUF_IN_ADDR_IDX, new_h2b_in_val);
244 
245     cybt_toggle_bt_intr();
246     return ret_result;
247 }
248 
cybt_hci_read(uint8_t * p_data,uint32_t * p_length)249 static cybt_result_t cybt_hci_read(uint8_t *p_data, uint32_t *p_length) {
250     cybt_result_t ret_result = CYBT_SUCCESS;
251     uint32_t fw_b2h_buf_count;
252     uint32_t new_b2h_out_val;
253     cybt_fw_membuf_index_t fw_membuf_info = {0};
254     static uint32_t available = 0;
255 
256     assert(ISALIGNED(p_data, 4));
257     if (!ISALIGNED(p_data, 4)) {
258         assert(false);
259         cybt_printf("cybt_hci_read: buffer not aligned\n");
260         return CYBT_ERR_BADARG;
261     }
262 
263     uint32_t read_len = ROUNDUP(*p_length, 4);
264 
265     cybt_get_bt_buf_index(&fw_membuf_info);
266     fw_b2h_buf_count = CIRC_BUF_CNT(fw_membuf_info.bt2host_in_val,
267                                     fw_membuf_info.bt2host_out_val);
268     cybt_debug("cybt_hci_read: bt2host_in_val=%lu bt2host_out_val=%lu fw_b2h_buf_count=%ld\n",
269                fw_membuf_info.bt2host_in_val, fw_membuf_info.bt2host_out_val, fw_b2h_buf_count);
270     if (fw_b2h_buf_count < available) {
271         cybt_printf("error: cybt_hci_read buffer overflow fw_b2h_buf_count=%ld available=%lu\n", fw_b2h_buf_count,
272                     available);
273         cybt_printf("error: cybt_hci_read bt2host_in_val=%lu bt2host_out_val=%lu\n", fw_membuf_info.bt2host_in_val,
274                     fw_membuf_info.bt2host_out_val);
275         panic("cyw43 buffer overflow");
276     }
277 
278     // No space in buffer
279     if (fw_b2h_buf_count == 0) {
280         *p_length = 0;
281     } else {
282         if (read_len > fw_b2h_buf_count) {
283             read_len = fw_b2h_buf_count;
284         }
285 
286         if (fw_membuf_info.bt2host_out_val + read_len <= BTSDIO_FWBUF_SIZE) {
287             // Don't need to wrap the circular buf
288             cybt_debug("cybt_hci_read: 1-round read, len = %" PRId32 "\n", read_len);
289             cybt_mem_read_idx(B2H_BUF_ADDR_IDX, fw_membuf_info.bt2host_out_val, p_data, read_len);
290             fw_membuf_info.bt2host_out_val += read_len;
291         } else {
292             // Need to wrap the circular buf
293             uint32_t first_read_len = BTSDIO_FWBUF_SIZE - fw_membuf_info.bt2host_out_val;
294             if (first_read_len >= 4) {
295                 cybt_mem_read_idx(B2H_BUF_ADDR_IDX, fw_membuf_info.bt2host_out_val, p_data, first_read_len);
296                 fw_membuf_info.bt2host_out_val += first_read_len;
297             } else {
298                 first_read_len = 0;
299             }
300             uint32_t second_read_len = read_len - first_read_len;
301             cybt_debug("cybt_hci_read: 2-round read, 1st_len = %" PRId32 ", 2nd_len = %" PRId32 "\n", first_read_len,
302                        second_read_len);
303             if (second_read_len > 0) {
304                 cybt_mem_read_idx(B2H_BUF_ADDR_IDX, 0, p_data + first_read_len, second_read_len);
305                 fw_membuf_info.bt2host_out_val += second_read_len;
306             }
307         }
308         available = fw_b2h_buf_count - read_len; // remember amount available to check for buffer overflow
309 
310         // Update pointer
311         new_b2h_out_val = fw_membuf_info.bt2host_out_val & (BTSDIO_FWBUF_SIZE - 1);
312         cybt_debug("cybt_hci_read new b2h_out = %" PRId32 "\n", new_b2h_out_val);
313         cybt_reg_write_idx(B2H_BUF_OUT_ADDR_IDX, new_b2h_out_val);
314 
315         // in case the real length is less than the requested one
316         *p_length = read_len;
317     }
318     cybt_toggle_bt_intr();
319     return ret_result;
320 }
321 
cybt_bus_request(void)322 static void cybt_bus_request(void) {
323     CYW43_THREAD_ENTER
324     // todo: Handle failure
325     cybt_result_t err = cybt_set_bt_awake(true);
326     assert(err == 0);
327     err = cybt_wait_bt_awake(BTSDIO_FW_AWAKE_POLLING_RETRY_COUNT);
328     assert(err == 0);
329     (void) err;
330 }
331 
cybt_bus_release(void)332 static void cybt_bus_release(void) {
333     // mutex if using wifi
334     CYW43_THREAD_EXIT
335 }
336 
337 // Send the buffer which includes space for a 4 byte header at the start
338 // The last byte of the header should already be set to the packet type
cyw43_btbus_write(uint8_t * buf,uint32_t size)339 int cyw43_btbus_write(uint8_t *buf, uint32_t size) {
340     uint16_t cmd_len = 0;
341 
342     // The size of the buffer should include a 4 byte header at the start
343     cmd_len = size - 4; //in BTSDIO, cmd_len does not include header length
344 
345     // Create payload starting with required headers
346     // Format: Cmd Len B0, Cmd Len B1, Cmd Len B2, HCI pckt type, Data
347     buf[0] = (uint8_t) (cmd_len & 0xFF);
348     buf[1] = (uint8_t) ((cmd_len & 0xFF00) >> 8);
349     buf[2] = 0;
350 
351     cybt_bus_request();
352 
353     cybt_debug("cyw43_btbus_write: %d\n", cmd_len);
354 #if CYBT_VDEBUG
355     dump_bytes(buf, size); // dump header and data
356 #endif
357 
358     cybt_hci_write_buf(buf, size);
359     cybt_bus_release();
360 
361     return 0;
362 }
363 
cybt_hci_read_packet(uint8_t * buf,uint32_t max_buf_size,uint32_t * size)364 static bool cybt_hci_read_packet(uint8_t *buf, uint32_t max_buf_size, uint32_t *size) {
365     uint32_t total_read_len = 0;
366     uint32_t read_len = 0;
367     cybt_result_t bt_result;
368 
369     // Read the header into the first 4 bytes of the buffer
370     read_len = 4; //3 bytes BTSDIO packet length + 1 bytes PTI
371     bt_result = cybt_hci_read(buf, &read_len);
372 
373     if (bt_result != CYBT_SUCCESS) {
374         *size = 0;
375         cybt_printf("cybt_hci_read_packet: error %d", bt_result);
376         return true;
377     }
378 
379     if (read_len == 0) {
380         // No data is read from SPI
381         *size = 0;
382         cybt_debug("cybt_hci_read_packet: no data\n");
383         return true;
384     }
385 
386     uint32_t hci_read_len = ((buf[2] << 16) & 0xFFFF00) | ((buf[1] << 8) & 0xFF00) | (buf[0] & 0xFF);
387     if (hci_read_len > max_buf_size - 4) {
388         *size = 0;
389         cybt_printf("cybt_hci_read_packet: too much data len %" PRId32"\n", hci_read_len);
390         assert(false);
391         return false;
392     }
393     total_read_len = hci_read_len;
394 
395     // Read the packet data after the header
396     cybt_debug("cybt_hci_read_packet: packet type 0x%" PRIx8 " len %" PRId32 "\n", buf[3], hci_read_len);
397     bt_result = cybt_hci_read(buf + 4, &total_read_len);
398     if (bt_result != CYBT_SUCCESS) {
399         *size = 0;
400         cybt_printf("cybt_hci_read_packet: read failed\n");
401         assert(false);
402         return false;
403     }
404 
405     // Might read more because of alignment
406     if (total_read_len >= hci_read_len) {
407         assert(total_read_len == ROUNDUP(hci_read_len, 4)); // check if we're losing data?
408         *size = hci_read_len + 4;
409     } else {
410         assert(total_read_len > 0);
411         *size = total_read_len + 4;
412         cybt_printf("cybt_hci_read_packet: failed to read all data %lu < %lu\n", total_read_len, hci_read_len);
413         //assert(false);
414         return true;
415     }
416 
417     cybt_debug("cybt_hci_read_packet: %ld\n", *size);
418 #if CYBT_VDEBUG
419     dump_bytes(buf, *size);
420 #endif
421 
422     return true;
423 }
424 
425 // Reads the hci packet prepended with 4 byte header. The last header byte is the packet type
cyw43_btbus_read(uint8_t * buf,uint32_t max_buf_size,uint32_t * size)426 int cyw43_btbus_read(uint8_t *buf, uint32_t max_buf_size, uint32_t *size) {
427     cybt_bus_request();
428     bool result = cybt_hci_read_packet(buf, max_buf_size, size);
429     cybt_bus_release();
430     return result ? 0 : -1;
431 }
432