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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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