1 /*
2  * Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <inttypes.h>
8 #include <stddef.h>
9 #include <assert.h>
10 #include <string.h>
11 
12 #include "cyw43_ll.h"
13 #include "cybt_shared_bus_driver.h"
14 
15 // Bluetooth register corruption occurs if both wifi and bluetooth are fully utilised.
16 #define CYBT_CORRUPTION_TEST 1
17 #if CYBT_CORRUPTION_TEST
18 static cybt_fw_membuf_index_t last_buf_index;
19 static uint32_t last_host_ctrl_reg;
20 static uint32_t last_bt_ctrl_reg;
21 
22 #include <stdio.h>
23 
24 #endif
25 
26 #ifndef NDEBUG
27 #define cybt_printf(format, args ...) printf(format,##args)
28 #else
29 #define cybt_printf(...)
30 #endif
31 
32 #ifndef CYBT_DEBUG
33 #define CYBT_DEBUG 0
34 #endif
35 
36 #if CYBT_DEBUG
37 #include <stdio.h>
38 #define cybt_debug(format, args ...) printf(format,##args)
39 #else
40 #define cybt_debug(format, ...) ((void)0)
41 #endif
42 
43 
44 /******************************************************************************
45  *                                Constants
46  ******************************************************************************/
47 #define BTFW_MEM_OFFSET             (0x19000000)
48 
49 /* BIT0 => WLAN Power UP and BIT1=> WLAN Wake */
50 #define BT2WLAN_PWRUP_WAKE          (0x03)
51 #define BT2WLAN_PWRUP_ADDR          (0x640894)/* This address is specific to 43012B0 */
52 
53 #define BTSDIO_OFFSET_HOST2BT_IN    (0x00002000)
54 #define BTSDIO_OFFSET_HOST2BT_OUT   (0x00002004)
55 #define BTSDIO_OFFSET_BT2HOST_IN    (0x00002008)
56 #define BTSDIO_OFFSET_BT2HOST_OUT   (0x0000200C)
57 
58 #define H2B_BUF_ADDR                (buf_info.host2bt_buf_addr)
59 #define H2B_BUF_IN_ADDR             (buf_info.host2bt_in_addr)
60 #define H2B_BUF_OUT_ADDR            (buf_info.host2bt_out_addr)
61 #define B2H_BUF_ADDR                (buf_info.bt2host_buf_addr)
62 #define B2H_BUF_IN_ADDR             (buf_info.bt2host_in_addr)
63 #define B2H_BUF_OUT_ADDR            (buf_info.bt2host_out_addr)
64 
65 static uint32_t wlan_ram_base_addr;
66 volatile uint32_t host_ctrl_cache_reg = 0;
67 #define WLAN_RAM_BASE_ADDR            (wlan_ram_base_addr)
68 
69 // In wifi host driver these are all constants
70 #define BT_CTRL_REG_ADDR            ((uint32_t)0x18000c7c)
71 #define HOST_CTRL_REG_ADDR          ((uint32_t)0x18000d6c)
72 #define WLAN_RAM_BASE_REG_ADDR      ((uint32_t)0x18000d68)
73 
74 typedef struct {
75     uint32_t host2bt_buf_addr;
76     uint32_t host2bt_in_addr;
77     uint32_t host2bt_out_addr;
78     uint32_t bt2host_buf_addr;
79     uint32_t bt2host_in_addr;
80     uint32_t bt2host_out_addr;
81 } cybt_fw_membuf_info_t;
82 
83 cybt_fw_membuf_info_t buf_info;
84 
85 #define BTFW_ADDR_MODE_UNKNOWN      (0)
86 #define BTFW_ADDR_MODE_EXTENDED     (1)
87 #define BTFW_ADDR_MODE_SEGMENT      (2)
88 #define BTFW_ADDR_MODE_LINEAR32     (3)
89 
90 #define BTFW_HEX_LINE_TYPE_DATA                      (0)
91 #define BTFW_HEX_LINE_TYPE_END_OF_DATA               (1)
92 #define BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS  (2)
93 #define BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS          (4)
94 #define BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS    (5)
95 
96 #define  BTSDIO_REG_DATA_VALID_BITMASK         (1 << 1)
97 #define  BTSDIO_REG_WAKE_BT_BITMASK            (1 << 17)
98 #define  BTSDIO_REG_SW_RDY_BITMASK             (1 << 24)
99 
100 #define  BTSDIO_REG_BT_AWAKE_BITMASK           (1 << 8)
101 #define  BTSDIO_REG_FW_RDY_BITMASK             (1 << 24)
102 
103 #define  BTSDIO_OFFSET_HOST_WRITE_BUF          (0)
104 #define  BTSDIO_OFFSET_HOST_READ_BUF           BTSDIO_FWBUF_SIZE
105 
106 #define  BTSDIO_FWBUF_OPER_DELAY_US            (250)
107 
108 #define ROUNDUP(x, a)               ((((x) + ((a) - 1)) / (a)) * (a))
109 #define ROUNDDN(x, a)               ((x) & ~((a) - 1))
110 #define ISALIGNED(a, x)             (((uint32_t)(a) & ((x) - 1)) == 0)
111 
112 typedef struct cybt_fw_cb {
113     const uint8_t *p_fw_mem_start;
114     uint32_t fw_len;
115     const uint8_t *p_next_line_start;
116 } cybt_fw_cb_t;
117 
118 typedef struct hex_file_data {
119     int addr_mode;
120     uint16_t hi_addr;
121     uint32_t dest_addr;
122     uint8_t *p_ds;
123 } hex_file_data_t;
124 
125 static cyw43_ll_t *cyw43_ll = NULL;
126 
127 static cybt_result_t cybt_reg_write(uint32_t reg_addr, uint32_t value);
128 static cybt_result_t cybt_reg_read(uint32_t reg_addr, uint32_t *p_value);
129 static cybt_result_t cybt_mem_write(uint32_t mem_addr, const uint8_t *p_data, uint32_t data_len);
130 static cybt_result_t cybt_mem_read(uint32_t mem_addr, uint8_t *p_data, uint32_t data_len);
131 
132 #if CYW43_USE_HEX_BTFW
strnchr(const char * str,uint32_t len,int character)133 const char *strnchr(const char *str, uint32_t len, int character) {
134     const char *end = str + len;
135     char c = (char)character;
136     do {
137         if (*str == c) {
138             return str;
139         }
140     } while (++str <= end);
141     return NULL;
142 }
143 
cybt_fw_hex_read_line(cybt_fw_cb_t * p_btfw_cb,const char ** p_line_start,int len)144 static uint32_t cybt_fw_hex_read_line(cybt_fw_cb_t *p_btfw_cb,
145     const char **p_line_start,
146     int len
147     ) {
148     uint32_t str_len = 0;
149     const char *p_str_end = NULL;
150 
151     if (NULL == p_btfw_cb || NULL == p_line_start) {
152         return str_len;
153     }
154 
155     *p_line_start = (const char *)p_btfw_cb->p_next_line_start;
156     p_str_end = strnchr(*p_line_start, len, '\n');
157     if (p_str_end == NULL) {
158         return str_len;
159     }
160 
161     str_len = (uint32_t)(p_str_end - *p_line_start);
162 
163     /* Advance file pointer past the string length */
164     p_btfw_cb->p_next_line_start += str_len + 1;
165 
166     return str_len;
167 }
168 
nibble_for_char(char c)169 static inline uint8_t nibble_for_char(char c) {
170     if ((c >= '0') && (c <= '9')) return c - '0';
171     if ((c >= 'A') && (c <= 'F')) return c - 'A' + 10;
172     return -1;
173 }
174 
read_hex_byte(const char * str)175 static inline uint8_t read_hex_byte(const char *str) {
176     return nibble_for_char(*str) << 4 | nibble_for_char(*(str + 1));
177 }
178 
read_hex(const char * str,int nchars)179 static uint32_t read_hex(const char *str, int nchars) {
180     uint32_t result = 0;
181     assert(nchars > 0 && nchars <= 8 && nchars % 2 == 0);
182     for(int pos = 0; pos < nchars; pos += 2) {
183         result <<= 8;
184         result |= read_hex_byte(str + pos);
185     }
186     return result;
187 }
188 
cybt_fw_get_data(cybt_fw_cb_t * p_btfw_cb,hex_file_data_t * hfd)189 static uint32_t cybt_fw_get_data(cybt_fw_cb_t *p_btfw_cb,
190     hex_file_data_t *hfd
191     ) {
192     uint32_t line_len;
193     uint16_t num_bytes, addr, data_pos, type, idx, octet;
194     uint32_t abs_base_addr32 = 0;
195     uint32_t data_len = 0;
196     const char *p_line_start = NULL;
197 
198     if (NULL == p_btfw_cb || NULL == hfd->p_ds) {
199         return data_len;
200     }
201 
202     while (data_len == 0) {
203         line_len = cybt_fw_hex_read_line(p_btfw_cb, &p_line_start, BTFW_MAX_STR_LEN);
204         if (line_len == 0) {
205             break;
206         } else if (line_len > 9) {
207 
208             num_bytes = (uint16_t)read_hex(p_line_start + 1, 2);
209             assert(num_bytes * 2 + 8 + 2 + 1 == line_len);
210 
211             int addr32 = read_hex(p_line_start + 3, 4);
212             assert(addr32 <= 0xffff);
213             addr = (uint16_t)addr32;
214             type = (uint16_t)read_hex(p_line_start + 7, 2);
215             assert(type <= 0xff);
216 
217             data_pos = 9;
218 
219             for (idx = 0; idx < num_bytes; idx++)
220             {
221                 octet = (uint16_t)read_hex(p_line_start + data_pos, 2);
222                 hfd->p_ds[idx] = (uint8_t)(octet & 0x00FF);
223                 data_pos += 2;
224             }
225 
226             if (type == BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS) {
227                 hfd->hi_addr = (hfd->p_ds[0] << 8) | hfd->p_ds[1];
228                 hfd->addr_mode = BTFW_ADDR_MODE_EXTENDED;
229             } else if (type == BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS) {
230                 hfd->hi_addr = (hfd->p_ds[0] << 8) | hfd->p_ds[1];
231                 hfd->addr_mode = BTFW_ADDR_MODE_SEGMENT;
232             } else if (type == BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS) {
233                 abs_base_addr32 = (hfd->p_ds[0] << 24) | (hfd->p_ds[1] << 16) |
234                     (hfd->p_ds[2] << 8) | hfd->p_ds[3];
235                 hfd->addr_mode = BTFW_ADDR_MODE_LINEAR32;
236             } else if (type == BTFW_HEX_LINE_TYPE_DATA) {
237                 hfd->dest_addr = addr;
238 
239                 if (hfd->addr_mode == BTFW_ADDR_MODE_EXTENDED) {
240                     hfd->dest_addr += (hfd->hi_addr << 16);
241                 } else if (hfd->addr_mode == BTFW_ADDR_MODE_SEGMENT) {
242                     hfd->dest_addr += (hfd->hi_addr << 4);
243                 } else if (hfd->addr_mode == BTFW_ADDR_MODE_LINEAR32) {
244                     hfd->dest_addr += abs_base_addr32;
245                 }
246 
247                 data_len = num_bytes;
248             }
249         }
250     }
251 
252     return data_len;
253 }
254 #else
255 
cybt_fw_get_data(cybt_fw_cb_t * p_btfw_cb,hex_file_data_t * hfd)256 static uint32_t cybt_fw_get_data(cybt_fw_cb_t *p_btfw_cb, hex_file_data_t *hfd) {
257     uint32_t abs_base_addr32 = 0;
258     while (true) {
259         // 4 byte header
260         uint8_t num_bytes = *(p_btfw_cb->p_next_line_start)++;
261         uint16_t addr = *(p_btfw_cb->p_next_line_start)++ << 8;
262         addr |= *(p_btfw_cb->p_next_line_start)++;
263         uint8_t type = *(p_btfw_cb->p_next_line_start)++;
264 
265         // No data?
266         if (num_bytes == 0) break;
267 
268         // Copy the data
269         memcpy(hfd->p_ds, p_btfw_cb->p_next_line_start, num_bytes);
270         p_btfw_cb->p_next_line_start += num_bytes;
271 
272         // Adjust address based on type
273         if (type == BTFW_HEX_LINE_TYPE_EXTENDED_ADDRESS) {
274             hfd->hi_addr = (hfd->p_ds[0] << 8) | hfd->p_ds[1];
275             hfd->addr_mode = BTFW_ADDR_MODE_EXTENDED;
276         } else if (type == BTFW_HEX_LINE_TYPE_EXTENDED_SEGMENT_ADDRESS) {
277             hfd->hi_addr = (hfd->p_ds[0] << 8) | hfd->p_ds[1];
278             hfd->addr_mode = BTFW_ADDR_MODE_SEGMENT;
279         } else if (type == BTFW_HEX_LINE_TYPE_ABSOLUTE_32BIT_ADDRESS) {
280             abs_base_addr32 = (hfd->p_ds[0] << 24) | (hfd->p_ds[1] << 16) |
281                               (hfd->p_ds[2] << 8) | hfd->p_ds[3];
282             hfd->addr_mode = BTFW_ADDR_MODE_LINEAR32;
283         } else if (type == BTFW_HEX_LINE_TYPE_DATA) {
284             hfd->dest_addr = addr;
285             if (hfd->addr_mode == BTFW_ADDR_MODE_EXTENDED) {
286                 hfd->dest_addr += (hfd->hi_addr << 16);
287             } else if (hfd->addr_mode == BTFW_ADDR_MODE_SEGMENT) {
288                 hfd->dest_addr += (hfd->hi_addr << 4);
289             } else if (hfd->addr_mode == BTFW_ADDR_MODE_LINEAR32) {
290                 hfd->dest_addr += abs_base_addr32;
291             }
292             return num_bytes;
293         }
294     }
295     return 0;
296 }
297 
298 #endif
299 
cybt_fw_download(const uint8_t * p_bt_firmware,uint32_t bt_firmware_len,uint8_t * p_write_buf,uint8_t * p_hex_buf)300 cybt_result_t cybt_fw_download(const uint8_t *p_bt_firmware,
301                                uint32_t bt_firmware_len,
302                                uint8_t *p_write_buf,
303                                uint8_t *p_hex_buf) {
304     cybt_fw_cb_t btfw_cb;
305     hex_file_data_t hfd = {BTFW_ADDR_MODE_EXTENDED, 0, 0, NULL};
306     uint8_t *p_mem_ptr;
307     uint32_t data_len;
308 
309     if (cyw43_ll == NULL) {
310         return CYBT_ERR_BADARG;
311     }
312 
313     if (NULL == p_bt_firmware || 0 == bt_firmware_len || NULL == p_write_buf || NULL == p_hex_buf) {
314         return CYBT_ERR_BADARG;
315     }
316 
317     // BT firmware starts with length of version string including a null terminator
318 #if !CYW43_USE_HEX_BTFW
319     uint8_t version_len = *p_bt_firmware;
320     assert(*(p_bt_firmware + version_len) == 0);
321 #ifndef NDEBUG
322     cybt_printf("BT FW download, version = %s\n", p_bt_firmware + 1);
323 #endif
324     p_bt_firmware += version_len + 1; // skip over version
325     p_bt_firmware += 1; // skip over record count
326 #endif
327 
328     p_mem_ptr = p_write_buf;
329     if ((uint32_t) (uintptr_t) p_mem_ptr % BTFW_SD_ALIGN) {
330         p_mem_ptr += (BTFW_SD_ALIGN - ((uint32_t) (uintptr_t) p_mem_ptr % BTFW_SD_ALIGN));
331     }
332 
333     hfd.p_ds = p_hex_buf;
334 
335     btfw_cb.p_fw_mem_start = p_bt_firmware;
336     btfw_cb.fw_len = bt_firmware_len;
337     btfw_cb.p_next_line_start = p_bt_firmware;
338 
339     cybt_reg_write(BTFW_MEM_OFFSET + BT2WLAN_PWRUP_ADDR, BT2WLAN_PWRUP_WAKE);
340 
341     while ((data_len = cybt_fw_get_data(&btfw_cb, &hfd)) > 0) {
342         uint32_t fwmem_start_addr, fwmem_start_data, fwmem_end_addr, fwmem_end_data;
343         uint32_t write_data_len, idx, pad;
344 
345         fwmem_start_addr = BTFW_MEM_OFFSET + hfd.dest_addr;
346         write_data_len = 0;
347 
348         /**
349          * Make sure the start address is 4 byte aligned to avoid alignment issues
350          * with SD host controllers
351          */
352         if (!ISALIGNED(fwmem_start_addr, 4)) {
353             pad = fwmem_start_addr % 4;
354             fwmem_start_addr = ROUNDDN(fwmem_start_addr, 4);
355 
356             cybt_mem_read(fwmem_start_addr, (uint8_t *) &fwmem_start_data, sizeof(uint32_t));
357 
358             for (idx = 0; idx < pad; idx++, write_data_len++) {
359                 p_mem_ptr[write_data_len] = (uint8_t) ((uint8_t *) &fwmem_start_data)[idx];
360             }
361         }
362         memcpy(&(p_mem_ptr[write_data_len]), hfd.p_ds, data_len);
363         write_data_len += data_len;
364 
365         /**
366          * Make sure the length is multiple of 4bytes to avoid alignment issues
367          * with SD host controllers
368          */
369         fwmem_end_addr = fwmem_start_addr + write_data_len;
370         if (!ISALIGNED(fwmem_end_addr, 4)) {
371             cybt_mem_read(ROUNDDN(fwmem_end_addr, 4), (uint8_t *) &fwmem_end_data, sizeof(uint32_t));
372             for (idx = (fwmem_end_addr % 4); idx < 4; idx++, write_data_len++) {
373                 p_mem_ptr[write_data_len] = (uint8_t) ((uint8_t *) &fwmem_end_data)[idx];
374             }
375         }
376 
377         /*
378          *  write ram
379          */
380         if (((fwmem_start_addr & 0xFFF) + write_data_len) <= 0x1000) {
381             cybt_mem_write(fwmem_start_addr, p_mem_ptr, write_data_len);
382         } else {
383             uint32_t first_write_len = 0x1000 - (fwmem_start_addr & 0xFFF);
384             cybt_mem_write(fwmem_start_addr, p_mem_ptr, first_write_len);
385             cybt_mem_write(fwmem_start_addr + first_write_len,
386                            p_mem_ptr + first_write_len,
387                            write_data_len - first_write_len);
388         }
389     }
390 
391     return CYBT_SUCCESS;
392 }
393 
cybt_set_host_ready(void)394 cybt_result_t cybt_set_host_ready(void) {
395     uint32_t reg_val;
396 
397     cybt_reg_read(HOST_CTRL_REG_ADDR, &reg_val);
398     reg_val |= BTSDIO_REG_SW_RDY_BITMASK;
399     cybt_reg_write(HOST_CTRL_REG_ADDR, reg_val);
400 #if CYBT_CORRUPTION_TEST
401     last_host_ctrl_reg = reg_val;
402 #endif
403     return CYBT_SUCCESS;
404 }
405 
cybt_toggle_bt_intr(void)406 cybt_result_t cybt_toggle_bt_intr(void) {
407     uint32_t reg_val, new_val;
408 
409     cybt_reg_read(HOST_CTRL_REG_ADDR, &reg_val);
410 #if CYBT_CORRUPTION_TEST
411     if ((reg_val & ~(BTSDIO_REG_SW_RDY_BITMASK | BTSDIO_REG_WAKE_BT_BITMASK | BTSDIO_REG_DATA_VALID_BITMASK)) != 0) {
412         cybt_printf("cybt_toggle_bt_intr read HOST_CTRL_REG_ADDR as 0x%08lx\n", reg_val);
413         cybt_debug_dump();
414         panic("cyw43 btsdio register corruption");
415     }
416     assert((reg_val & ~(BTSDIO_REG_SW_RDY_BITMASK | BTSDIO_REG_WAKE_BT_BITMASK | BTSDIO_REG_DATA_VALID_BITMASK)) == 0);
417 #endif
418     new_val = reg_val ^ BTSDIO_REG_DATA_VALID_BITMASK;
419     cybt_reg_write(HOST_CTRL_REG_ADDR, new_val);
420 #if CYBT_CORRUPTION_TEST
421     last_host_ctrl_reg = new_val;
422 #endif
423     return CYBT_SUCCESS;
424 }
425 
cybt_set_bt_intr(int value)426 cybt_result_t cybt_set_bt_intr(int value) {
427     uint32_t reg_val, new_val;
428 
429     cybt_reg_read(HOST_CTRL_REG_ADDR, &reg_val);
430     if (value) {
431         new_val = reg_val | BTSDIO_REG_DATA_VALID_BITMASK;
432     } else {
433         new_val = reg_val & ~BTSDIO_REG_DATA_VALID_BITMASK;
434     }
435     cybt_reg_write(HOST_CTRL_REG_ADDR, new_val);
436 #if CYBT_CORRUPTION_TEST
437     last_host_ctrl_reg = new_val;
438 #endif
439     return CYBT_SUCCESS;
440 }
441 
cybt_ready(void)442 int cybt_ready(void) {
443     uint32_t reg_val;
444     cybt_reg_read(BT_CTRL_REG_ADDR, &reg_val);
445 #if CYBT_CORRUPTION_TEST
446     if (reg_val & BTSDIO_REG_FW_RDY_BITMASK) {
447         last_bt_ctrl_reg = reg_val;
448     }
449 #endif
450     return (reg_val & BTSDIO_REG_FW_RDY_BITMASK) ? 1 : 0;
451 }
452 
cybt_awake(void)453 int cybt_awake(void) {
454     uint32_t reg_val;
455     cybt_reg_read(BT_CTRL_REG_ADDR, &reg_val);
456 #if CYBT_CORRUPTION_TEST
457     if (reg_val & BTSDIO_REG_BT_AWAKE_BITMASK) {
458         last_bt_ctrl_reg = reg_val;
459     }
460 #endif
461     return (reg_val & BTSDIO_REG_BT_AWAKE_BITMASK) ? 1 : 0;
462 }
463 
cybt_set_bt_awake(int value)464 cybt_result_t cybt_set_bt_awake(int value) {
465     uint32_t reg_val_before;
466     cybt_reg_read(HOST_CTRL_REG_ADDR, &reg_val_before);
467 
468     uint32_t reg_val_after = reg_val_before;
469     if (value)
470         reg_val_after |= BTSDIO_REG_WAKE_BT_BITMASK;
471     else
472         reg_val_after &= ~BTSDIO_REG_WAKE_BT_BITMASK;
473 
474     if (reg_val_before != reg_val_after) {
475         cybt_reg_write(HOST_CTRL_REG_ADDR, reg_val_after);
476 #if CYBT_CORRUPTION_TEST
477         last_host_ctrl_reg = reg_val_after;
478 #endif
479     }
480     return 0;
481 }
482 
cybt_debug_dump(void)483 void cybt_debug_dump(void) {
484 #if CYBT_CORRUPTION_TEST
485     uint32_t reg_val = 0;
486     cybt_fw_membuf_index_t buf_index;
487 
488     cybt_printf("WLAN_RAM_BASE_ADDR: 0x%08lx\n", WLAN_RAM_BASE_ADDR);
489     cybt_printf("H2B_BUF_ADDR: 0x%08lx\n", H2B_BUF_ADDR);
490     cybt_printf("B2H_BUF_ADDR: 0x%08lx\n", B2H_BUF_ADDR);
491 
492     cybt_reg_read(H2B_BUF_IN_ADDR, &buf_index.host2bt_in_val);
493     cybt_printf("H2B_BUF_IN_ADDR: 0x%08lx = 0x%08lx (last 0x%08lx)\n", H2B_BUF_IN_ADDR, buf_index.host2bt_in_val,
494                 last_buf_index.host2bt_in_val);
495 
496     cybt_reg_read(H2B_BUF_OUT_ADDR, &buf_index.host2bt_out_val);
497     cybt_printf("H2B_BUF_OUT_ADDR: 0x%08lx = 0x%08lx (last 0x%08lx)\n", H2B_BUF_OUT_ADDR, buf_index.host2bt_out_val,
498                 last_buf_index.host2bt_out_val);
499 
500     cybt_reg_read(B2H_BUF_IN_ADDR, &buf_index.bt2host_in_val);
501     cybt_printf("B2H_BUF_IN_ADDR: 0x%08lx = 0x%08lx (last 0x%08lx)\n", B2H_BUF_IN_ADDR, buf_index.bt2host_in_val,
502                 last_buf_index.bt2host_in_val);
503 
504     cybt_reg_read(B2H_BUF_OUT_ADDR, &buf_index.bt2host_out_val);
505     cybt_printf("B2H_BUF_OUT_ADDR: 0x%08lx = 0x%08lx (last 0x%08lx)\n", B2H_BUF_OUT_ADDR, buf_index.bt2host_out_val,
506                 last_buf_index.bt2host_out_val);
507 
508     cybt_reg_read(HOST_CTRL_REG_ADDR, &reg_val);
509     cybt_printf("HOST_CTRL_REG_ADDR: 0x%08lx = 0x%08lx (last 0x%08lx)\n", HOST_CTRL_REG_ADDR, reg_val,
510                 last_host_ctrl_reg);
511 
512     cybt_reg_read(BT_CTRL_REG_ADDR, &reg_val);
513     cybt_printf("BT_CTRL_REG_ADDR: 0x%08lx = 0x%08lx (last 0x%08lx)\n", BT_CTRL_REG_ADDR, reg_val, last_bt_ctrl_reg);
514 #endif
515 }
516 
cybt_get_bt_buf_index(cybt_fw_membuf_index_t * p_buf_index)517 cybt_result_t cybt_get_bt_buf_index(cybt_fw_membuf_index_t *p_buf_index) {
518     uint32_t buf[4];
519 
520     cybt_mem_read(H2B_BUF_IN_ADDR, (uint8_t *) buf, sizeof(buf));
521 
522     p_buf_index->host2bt_in_val = buf[0];
523     p_buf_index->host2bt_out_val = buf[1];
524     p_buf_index->bt2host_in_val = buf[2];
525     p_buf_index->bt2host_out_val = buf[3];
526 
527     cybt_debug("cybt_get_bt_buf_index: h2b_in = 0x%08lx, h2b_out = 0x%08lx, b2h_in = 0x%08lx, b2h_out = 0x%08lx\n",
528                p_buf_index->host2bt_in_val,
529                p_buf_index->host2bt_out_val,
530                p_buf_index->bt2host_in_val,
531                p_buf_index->bt2host_out_val);
532 
533 #if CYBT_CORRUPTION_TEST
534     if (p_buf_index->host2bt_in_val >= BTSDIO_FWBUF_SIZE || p_buf_index->host2bt_out_val >= BTSDIO_FWBUF_SIZE ||
535         p_buf_index->bt2host_in_val >= BTSDIO_FWBUF_SIZE || p_buf_index->bt2host_out_val >= BTSDIO_FWBUF_SIZE) {
536         cybt_printf("cybt_get_bt_buf_index invalid buffer value\n");
537         cybt_debug_dump();
538     } else {
539         memcpy((uint8_t *) &last_buf_index, (uint8_t *) p_buf_index, sizeof(cybt_fw_membuf_index_t));
540     }
541 #endif
542 
543     assert(p_buf_index->host2bt_in_val < BTSDIO_FWBUF_SIZE);
544     assert(p_buf_index->host2bt_out_val < BTSDIO_FWBUF_SIZE);
545     assert(p_buf_index->bt2host_in_val < BTSDIO_FWBUF_SIZE);
546     assert(p_buf_index->bt2host_out_val < BTSDIO_FWBUF_SIZE);
547 
548     return CYBT_SUCCESS;
549 }
550 
cybt_reg_write(uint32_t reg_addr,uint32_t value)551 static cybt_result_t cybt_reg_write(uint32_t reg_addr, uint32_t value) {
552     cybt_debug("cybt_reg_write 0x%08lx 0x%08lx\n", reg_addr, value);
553     cyw43_ll_write_backplane_reg(cyw43_ll, reg_addr, value);
554     if (reg_addr == HOST_CTRL_REG_ADDR) {
555         host_ctrl_cache_reg = value;
556     }
557     return CYBT_SUCCESS;
558 }
559 
cybt_reg_read(uint32_t reg_addr,uint32_t * p_value)560 static cybt_result_t cybt_reg_read(uint32_t reg_addr, uint32_t *p_value) {
561     if (reg_addr == HOST_CTRL_REG_ADDR) {
562         *p_value = host_ctrl_cache_reg;
563         return CYBT_SUCCESS;
564     }
565     *p_value = cyw43_ll_read_backplane_reg(cyw43_ll, reg_addr);
566     cybt_debug("cybt_reg_read 0x%08lx == 0x%08lx\n", reg_addr, *p_value);
567     return CYBT_SUCCESS;
568 }
569 
570 #if CYBT_DEBUG
dump_bytes(const uint8_t * bptr,uint32_t len)571 static void dump_bytes(const uint8_t *bptr, uint32_t len) {
572     unsigned int i = 0;
573 
574     for (i = 0; i < len; i++) {
575         if ((i & 0x07) == 0) {
576             cybt_debug("\n        ");
577         }
578         cybt_debug("0x%02x", bptr[i]);
579         if (i != (len - 1)) {
580             cybt_debug(", ");
581         }
582     }
583     cybt_debug("\n");
584 }
585 #define DUMP_BYTES dump_bytes
586 #else
587 #define DUMP_BYTES(...)
588 #endif
589 
cybt_mem_write(uint32_t mem_addr,const uint8_t * p_data,uint32_t data_len)590 static cybt_result_t cybt_mem_write(uint32_t mem_addr, const uint8_t *p_data, uint32_t data_len) {
591     cybt_debug("cybt_mem_write addr 0x%08lx len %ld\n", mem_addr, data_len);
592     do {
593         uint32_t transfer_size = (data_len > CYW43_BUS_MAX_BLOCK_SIZE) ? CYW43_BUS_MAX_BLOCK_SIZE : data_len;
594         if ((mem_addr & 0xFFF) + transfer_size > 0x1000) {
595             transfer_size = 0x1000 - (mem_addr & 0xFFF);
596         }
597         cyw43_ll_write_backplane_mem(cyw43_ll, mem_addr, transfer_size, p_data);
598         cybt_debug("  write_mem addr 0x%08lx len %ld\n", mem_addr, transfer_size);
599         DUMP_BYTES(p_data, transfer_size);
600         data_len -= transfer_size;
601         p_data += transfer_size;
602         mem_addr += transfer_size;
603     } while (data_len > 0);
604     return CYBT_SUCCESS;
605 }
606 
cybt_mem_read(uint32_t mem_addr,uint8_t * p_data,uint32_t data_len)607 static cybt_result_t cybt_mem_read(uint32_t mem_addr, uint8_t *p_data, uint32_t data_len) {
608     assert(data_len >= 4);
609     cybt_debug("cybt_mem_read addr 0x%08lx len %ld\n", mem_addr, data_len);
610     do {
611         uint32_t transfer_size = (data_len > CYW43_BUS_MAX_BLOCK_SIZE) ? CYW43_BUS_MAX_BLOCK_SIZE : data_len;
612         if ((mem_addr & 0xFFF) + transfer_size > 0x1000) {
613             transfer_size = 0x1000 - (mem_addr & 0xFFF);
614         }
615         cyw43_ll_read_backplane_mem(cyw43_ll, mem_addr, transfer_size, p_data);
616         cybt_debug("  read_mem addr 0x%08lx len %ld\n", mem_addr, transfer_size);
617         DUMP_BYTES(p_data, transfer_size);
618         data_len -= transfer_size;
619         p_data += transfer_size;
620         mem_addr += transfer_size;
621     } while (data_len > 0);
622     return CYBT_SUCCESS;
623 }
624 
cybt_get_addr(cybt_addr_idx_t addr_idx)625 static uint32_t cybt_get_addr(cybt_addr_idx_t addr_idx) {
626     uint32_t addr = 0;
627 
628     switch (addr_idx) {
629         case H2B_BUF_ADDR_IDX:
630             addr = H2B_BUF_ADDR;
631             break;
632         case H2B_BUF_IN_ADDR_IDX:
633             addr = H2B_BUF_IN_ADDR;
634             break;
635         case H2B_BUF_OUT_ADDR_IDX:
636             addr = H2B_BUF_OUT_ADDR;
637             break;
638         case B2H_BUF_ADDR_IDX:
639             addr = B2H_BUF_ADDR;
640             break;
641         case B2H_BUF_IN_ADDR_IDX:
642             addr = B2H_BUF_IN_ADDR;
643             break;
644         case B2H_BUF_OUT_ADDR_IDX:
645             addr = B2H_BUF_OUT_ADDR;
646             break;
647         default:
648             assert(0);
649             break;
650     }
651     return addr;
652 }
653 
cybt_reg_write_idx(cybt_addr_idx_t reg_idx,uint32_t value)654 cybt_result_t cybt_reg_write_idx(cybt_addr_idx_t reg_idx, uint32_t value) {
655     assert(reg_idx == H2B_BUF_IN_ADDR_IDX || reg_idx == B2H_BUF_OUT_ADDR_IDX);
656     assert(value < BTSDIO_FWBUF_SIZE); // writing out of bounds register value?
657     if ((reg_idx != H2B_BUF_IN_ADDR_IDX && reg_idx != B2H_BUF_OUT_ADDR_IDX) || value >= BTSDIO_FWBUF_SIZE) {
658         assert(0);
659         return CYBT_ERR_BADARG;
660     }
661     uint32_t reg_addr = cybt_get_addr(reg_idx);
662     return cybt_reg_write(reg_addr, value);
663 }
664 
cybt_mem_write_idx(cybt_addr_idx_t mem_idx,uint32_t offset,const uint8_t * p_data,uint32_t data_len)665 cybt_result_t cybt_mem_write_idx(cybt_addr_idx_t mem_idx, uint32_t offset, const uint8_t *p_data, uint32_t data_len) {
666     assert(mem_idx == H2B_BUF_ADDR_IDX); // caller should only be writing to here?
667     assert(offset + data_len <= BTSDIO_FWBUF_SIZE); // writing out of bounds?
668     if (mem_idx != H2B_BUF_ADDR_IDX || (offset + data_len) > BTSDIO_FWBUF_SIZE) {
669         assert(0);
670         return CYBT_ERR_BADARG;
671     }
672     if (!ISALIGNED(p_data, 4)) {
673         return CYBT_ERR_BADARG;
674     }
675     uint32_t mem_addr = cybt_get_addr(mem_idx) + offset;
676     return cybt_mem_write(mem_addr, p_data, data_len);
677 }
678 
cybt_mem_read_idx(cybt_addr_idx_t mem_idx,uint32_t offset,uint8_t * p_data,uint32_t data_len)679 cybt_result_t cybt_mem_read_idx(cybt_addr_idx_t mem_idx, uint32_t offset, uint8_t *p_data, uint32_t data_len) {
680     assert(mem_idx == B2H_BUF_ADDR_IDX); // caller should only be reading from here?
681     assert(offset + data_len <= BTSDIO_FWBUF_SIZE); // reading out of bounds?
682     if (mem_idx != B2H_BUF_ADDR_IDX || (offset + data_len) > BTSDIO_FWBUF_SIZE) {
683         assert(0);
684         return CYBT_ERR_BADARG;
685     }
686     uint32_t mem_addr = cybt_get_addr(mem_idx) + offset;
687     return cybt_mem_read(mem_addr, p_data, data_len);
688 }
689 
cybt_init_buffer(void)690 cybt_result_t cybt_init_buffer(void) {
691     int result;
692     result = cybt_reg_read(WLAN_RAM_BASE_REG_ADDR, &WLAN_RAM_BASE_ADDR);
693     if (CYBT_SUCCESS != result) {
694         return result;
695     }
696 
697     cybt_debug("hci_open(): btfw ram base = 0x%" PRIx32 "\n", WLAN_RAM_BASE_ADDR);
698 
699     // Fill in reg info
700     // Data buffers
701     H2B_BUF_ADDR = WLAN_RAM_BASE_ADDR + BTSDIO_OFFSET_HOST_WRITE_BUF;
702     B2H_BUF_ADDR = WLAN_RAM_BASE_ADDR + BTSDIO_OFFSET_HOST_READ_BUF;
703 
704     // circular buffer indexes
705     H2B_BUF_IN_ADDR = WLAN_RAM_BASE_ADDR + BTSDIO_OFFSET_HOST2BT_IN;
706     H2B_BUF_OUT_ADDR = WLAN_RAM_BASE_ADDR + BTSDIO_OFFSET_HOST2BT_OUT;
707     B2H_BUF_IN_ADDR = WLAN_RAM_BASE_ADDR + BTSDIO_OFFSET_BT2HOST_IN;
708     B2H_BUF_OUT_ADDR = WLAN_RAM_BASE_ADDR + BTSDIO_OFFSET_BT2HOST_OUT;
709 
710     uint32_t reg_val = 0;
711     cybt_reg_write(H2B_BUF_IN_ADDR, reg_val);
712     cybt_reg_write(H2B_BUF_OUT_ADDR, reg_val);
713     cybt_reg_write(B2H_BUF_IN_ADDR, reg_val);
714     cybt_reg_write(B2H_BUF_OUT_ADDR, reg_val);
715 
716     return CYBT_SUCCESS;
717 }
718 
cybt_sharedbus_driver_init(cyw43_ll_t * driver)719 void cybt_sharedbus_driver_init(cyw43_ll_t *driver) {
720     cyw43_ll = driver;
721 }
722