1 /*
2  * Copyright (c) 2024 Cypress Semiconductor Corporation (an Infineon company) or
3  * an affiliate of Cypress Semiconductor Corporation
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8  /**
9   * @brief Zephyr CYW20829 driver.
10   *
11   *  This driver uses btstack-integration asset as hosts platform adaptation layer
12   *  (porting layer) for CYW20829. btstack-integration layer implements/
13   *  invokes the interfaces defined by BTSTACK to enable communication
14   *  with the BT controller by using IPC_BTSS (IPC Bluetooth sub-system interface).
15   *  Zephyr CYW20829 driver implements wiced_bt_**** functions requreds for
16   *  btstack-integration asset and Zephyr Bluetooth driver interface
17   *  (defined in struct bt_hci_driver).
18   *
19   *                                               CM33 (application core)
20   *                                   |=========================================|
21   *                                   |            |-------------------------|  |
22   *                                   |            |     Zephyr application  |  |
23   *                                   |            |-------------------------|  |
24   *                                   |                               |         |
25   *                                   |                         |------------|  |
26   *                                   |                         |  Zephyr    |  |
27   *                                   |                         |  Bluetooth |  |
28   *      CM33 (BTSS core)             |                         |  Host      |  |
29   *  |=====================|          |                         |------------|  |
30   *  |                     |          |                               |         |
31   *  |  |---------------|  |          |   |--------------|      | -----------|  |
32   *  |  | Bluetooth     |  | IPC_BTSS |   | btstack-     |      |  Zephyr    |  |
33   *  |  | Controller FW |  | <--------|-> | integration  | ---- |  CYW20829  |  |
34   *  |  |---------------|  |          |   | asset        |      |  driver    |  |
35   *  |                     |          |   |--------------|      |------------|  |
36   *  |=====================|          |                                         |
37   *            |                      |=========================================|
38   *  |====================|
39   *  |     CYW20829       |
40   *  |     Bluetooth      |
41   *  |====================|
42   *
43   *  NOTE:
44   *   cyw920829 requires fetch binary files of Bluetooth controller firmware.
45   *   To fetch Binary Blobs:  west blobs fetch hal_infineon
46   *
47   */
48 
49 #include <errno.h>
50 #include <stddef.h>
51 #include <string.h>
52 
53 #include <zephyr/arch/cpu.h>
54 #include <zephyr/bluetooth/bluetooth.h>
55 #include <zephyr/bluetooth/hci.h>
56 #include <zephyr/drivers/bluetooth.h>
57 #include <zephyr/drivers/uart.h>
58 #include <zephyr/init.h>
59 #include <zephyr/sys/byteorder.h>
60 #include <zephyr/sys/util.h>
61 #include <zephyr/logging/log.h>
62 
63 #include <wiced_bt_stack_platform.h>
64 #include <cybt_platform_config.h>
65 #include <cybt_platform_trace.h>
66 #include <cybt_platform_hci.h>
67 #include <cybt_platform_task.h>
68 
69 #include <cyabs_rtos.h>
70 #include <cybt_result.h>
71 
72 #define LOG_LEVEL  CONFIG_BT_HCI_DRIVER_LOG_LEVEL
73 #include <zephyr/logging/log.h>
74 LOG_MODULE_REGISTER(cyw208xx);
75 
76 #define DT_DRV_COMPAT infineon_cyw208xx_hci
77 
78 struct cyw208xx_data {
79 	bt_hci_recv_t recv;
80 };
81 
82 enum {
83 	BT_HCI_VND_OP_DOWNLOAD_MINIDRIVER = 0xFC2E,
84 	BT_HCI_VND_OP_WRITE_RAM = 0xFC4C,
85 	BT_HCI_VND_OP_LAUNCH_RAM = 0xFC4E,
86 	BT_HCI_VND_OP_UPDATE_BAUDRATE = 0xFC18,
87 	BT_HCI_VND_OP_SET_LOCAL_DEV_ADDR = 0xFC01,
88 };
89 
90 /* Externs for CY43xxx controller FW */
91 extern const uint8_t brcm_patchram_buf[];
92 extern const int brcm_patch_ram_length;
93 
94 #define CYBSP_BT_PLATFORM_CFG_SLEEP_MODE_LP_ENABLED (0)
95 #define BTM_SET_LOCAL_DEV_ADDR_LENGTH 6
96 
97 static K_SEM_DEFINE(hci_sem, 1, 1);
98 static K_SEM_DEFINE(cybt_platform_task_init_sem, 0, 1);
99 
100 
101 /******************************************************************************
102  *                          Function Declarations
103  ******************************************************************************/
104 extern void host_stack_platform_interface_init(void);
105 extern void cybt_platform_hci_wait_for_boot_fully_up(bool is_from_isr);
106 extern uint8_t *host_stack_get_acl_to_lower_buffer(wiced_bt_transport_t transport, uint32_t size);
107 extern wiced_result_t host_stack_send_acl_to_lower(wiced_bt_transport_t transport,
108 						   uint8_t *data, uint16_t len);
109 extern wiced_result_t host_stack_send_cmd_to_lower(uint8_t *cmd, uint16_t cmd_len);
110 extern wiced_result_t host_stack_send_iso_to_lower(uint8_t *data, uint16_t len);
111 extern cybt_result_t cybt_platform_msg_to_bt_task(const uint16_t msg, bool is_from_isr);
112 extern void cybt_bttask_deinit(void);
113 
cyw208xx_bt_firmware_download(const uint8_t * firmware_image,uint32_t size)114 static int cyw208xx_bt_firmware_download(const uint8_t *firmware_image, uint32_t size)
115 {
116 	uint8_t *data = (uint8_t *)firmware_image;
117 	volatile uint32_t remaining_length = size;
118 	struct net_buf *buf;
119 	int err;
120 
121 	LOG_DBG("Executing Fw downloading for CYW208xx device");
122 
123 	/* The firmware image (.hcd format) contains a collection of hci_write_ram
124 	 * command + a block of the image, followed by a hci_write_ram image at the end.
125 	 * Parse and send each individual command and wait for the response. This is to
126 	 * ensure the integrity of the firmware image sent to the bluetooth chip.
127 	 */
128 	while (remaining_length) {
129 		size_t data_length = data[2]; /* data length from firmware image block */
130 		uint16_t op_code = *(uint16_t *)data;
131 
132 		/* Allocate buffer for hci_write_ram/hci_launch_ram command. */
133 		buf = bt_hci_cmd_create(op_code, data_length);
134 		if (buf == NULL) {
135 			LOG_ERR("Unable to allocate command buffer");
136 			return err;
137 		}
138 
139 		/* Add data part of packet */
140 		net_buf_add_mem(buf, &data[3], data_length);
141 
142 		/* Send hci_write_ram command. */
143 		err = bt_hci_cmd_send_sync(op_code, buf, NULL);
144 		if (err) {
145 			return err;
146 		}
147 
148 		switch (op_code) {
149 		case BT_HCI_VND_OP_WRITE_RAM:
150 			/* Update remaining length and data pointer:
151 			 * content of data length + 2 bytes of opcode and 1 byte of data length.
152 			 */
153 			data += data_length + 3;
154 			remaining_length -= data_length + 3;
155 			break;
156 
157 		case BT_HCI_VND_OP_LAUNCH_RAM:
158 			remaining_length = 0;
159 			break;
160 
161 		default:
162 			return -ENOMEM;
163 		}
164 	}
165 
166 	LOG_DBG("Fw downloading complete");
167 	return 0;
168 }
169 
cyw208xx_setup(const struct device * dev,const struct bt_hci_setup_params * params)170 static int cyw208xx_setup(const struct device *dev, const struct bt_hci_setup_params *params)
171 {
172 	ARG_UNUSED(dev);
173 
174 	int err;
175 	struct net_buf *buf;
176 
177 	/* Send HCI_RESET */
178 	err = bt_hci_cmd_send_sync(BT_HCI_OP_RESET, NULL, NULL);
179 	if (err) {
180 		return err;
181 	}
182 
183 	/* BT firmware download */
184 	err = cyw208xx_bt_firmware_download(brcm_patchram_buf, (uint32_t)brcm_patch_ram_length);
185 	if (err) {
186 		return err;
187 	}
188 
189 	/* Waiting when BLE up after firmware launch */
190 	cybt_platform_hci_wait_for_boot_fully_up(false);
191 
192 	/* Set public address */
193 	buf = bt_hci_cmd_create(BT_HCI_VND_OP_SET_LOCAL_DEV_ADDR, BTM_SET_LOCAL_DEV_ADDR_LENGTH);
194 	if (buf == NULL) {
195 		LOG_ERR("Unable to allocate command buffer");
196 		return -ENOMEM;
197 	}
198 
199 	bt_addr_t *data = net_buf_add(buf, BTM_SET_LOCAL_DEV_ADDR_LENGTH);
200 
201 	bt_addr_copy(data, &(params->public_addr));
202 
203 	/* NOTE: By default, the CYW208xx controller sets some hard-coded static address.
204 	 * To avoid address duplication, let's always override the default address by using
205 	 * the HCI command BT_HCI_VND_OP_SET_LOCAL_DEV_ADDR. So
206 	 *
207 	 * 1. when cyw208xx_setup gets BT_ADDR_ANY from the host, it will overwrite the
208 	 *    default address, and the host will switch to using a random address (set in
209 	 *    the hci_init function).
210 	 *
211 	 * 2. If user set the static address (by using bt_id_create) before bt_enable,
212 	 *    cyw208xx_setup will set user defined static address.
213 	 */
214 
215 	err = bt_hci_cmd_send_sync(BT_HCI_VND_OP_SET_LOCAL_DEV_ADDR, buf, NULL);
216 	if (err) {
217 		LOG_ERR("Failed to set public address (%d)", err);
218 		return err;
219 	}
220 
221 	return 0;
222 }
223 
cyw208xx_open(const struct device * dev,bt_hci_recv_t recv)224 static int cyw208xx_open(const struct device *dev, bt_hci_recv_t recv)
225 {
226 	int err;
227 	struct cyw208xx_data *hci = dev->data;
228 
229 	hci->recv = recv;
230 
231 	/* Initialize Bluetooth platform related OS tasks. */
232 	err = cybt_platform_task_init((void *)NULL);
233 	if (err) {
234 		return err;
235 	}
236 
237 	/* Wait until cybt platform task starts */
238 	k_sem_take(&cybt_platform_task_init_sem, K_FOREVER);
239 
240 	return 0;
241 }
242 
cyw208xx_close(const struct device * dev)243 static int cyw208xx_close(const struct device *dev)
244 {
245 	struct cyw208xx_data *hci = dev->data;
246 
247 	/* Send SHUTDOWN event, BT task will release resources and tervinate task */
248 	cybt_platform_msg_to_bt_task(BT_EVT_TASK_SHUTDOWN, false);
249 
250 	cybt_bttask_deinit();
251 
252 	k_sem_reset(&cybt_platform_task_init_sem);
253 	hci->recv = NULL;
254 
255 	return 0;
256 }
257 
cyw208xx_send(const struct device * dev,struct net_buf * buf)258 static int cyw208xx_send(const struct device *dev, struct net_buf *buf)
259 {
260 	ARG_UNUSED(dev);
261 
262 	int ret = 0;
263 
264 	k_sem_take(&hci_sem, K_FOREVER);
265 
266 	LOG_DBG("buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len);
267 
268 	switch (bt_buf_get_type(buf)) {
269 	case BT_BUF_ACL_OUT:
270 		uint8_t *bt_msg = host_stack_get_acl_to_lower_buffer(BT_TRANSPORT_LE, buf->len);
271 
272 		memcpy(bt_msg, buf->data, buf->len);
273 		ret = host_stack_send_acl_to_lower(BT_TRANSPORT_LE, bt_msg, buf->len);
274 		break;
275 
276 	case BT_BUF_CMD:
277 		ret = host_stack_send_cmd_to_lower(buf->data, buf->len);
278 		break;
279 
280 	case BT_BUF_ISO_OUT:
281 		ret = host_stack_send_iso_to_lower(buf->data, buf->len);
282 		break;
283 
284 	default:
285 		LOG_ERR("Unknown type %u", bt_buf_get_type(buf));
286 		ret = EIO;
287 		goto done;
288 	}
289 
290 	LOG_HEXDUMP_DBG(buf->data, buf->len, "Final HCI buffer:");
291 
292 	if (ret) {
293 		LOG_ERR("SPI write error %d", ret);
294 	}
295 
296 done:
297 	k_sem_give(&hci_sem);
298 	net_buf_unref(buf);
299 	return ret ? -EIO : 0;
300 }
301 
302 static DEVICE_API(bt_hci, drv) = {
303 	.open = cyw208xx_open,
304 	.close = cyw208xx_close,
305 	.send = cyw208xx_send,
306 	.setup = cyw208xx_setup
307 };
308 
cyw208xx_hci_init(const struct device * dev)309 static int cyw208xx_hci_init(const struct device *dev)
310 {
311 	ARG_UNUSED(dev);
312 
313 	const cybt_platform_config_t cybsp_bt_platform_cfg = {
314 		.hci_config = {
315 			.hci_transport = CYBT_HCI_IPC,
316 		},
317 
318 		.controller_config = {
319 			.sleep_mode = {
320 				.sleep_mode_enabled = CYBSP_BT_PLATFORM_CFG_SLEEP_MODE_LP_ENABLED,
321 			},
322 		}
323 	};
324 
325 	/* Configure platform specific settings for the BT device */
326 	cybt_platform_config_init(&cybsp_bt_platform_cfg);
327 
328 	return 0;
329 }
330 
331 /* Implements wiced_bt_**** functions requreds for the btstack-integration asset */
332 
wiced_bt_dev_vendor_specific_command(uint16_t opcode,uint8_t param_len,uint8_t * param_buf,wiced_bt_dev_vendor_specific_command_complete_cback_t cback)333 wiced_result_t wiced_bt_dev_vendor_specific_command(uint16_t opcode, uint8_t param_len,
334 	uint8_t *param_buf, wiced_bt_dev_vendor_specific_command_complete_cback_t cback)
335 
336 {
337 	/*
338 	 * This function is using only by btstack-integration asset
339 	 * for enable LPM.
340 	 */
341 	struct net_buf *buf = NULL;
342 
343 	/* Allocate a HCI command buffer */
344 	buf = bt_hci_cmd_create(opcode, param_len);
345 	if (!buf) {
346 		LOG_ERR("Unable to allocate buffer");
347 		return WICED_NO_MEMORY;
348 	}
349 
350 	/* Add data part of packet */
351 	net_buf_add_mem(buf, param_buf, param_len);
352 	bt_hci_cmd_send(opcode, buf);
353 
354 	return WICED_BT_SUCCESS;
355 }
356 
wiced_bt_process_hci(hci_packet_type_t pti,uint8_t * data,uint32_t length)357 void wiced_bt_process_hci(hci_packet_type_t pti, uint8_t *data, uint32_t length)
358 {
359 	const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0));
360 	struct cyw208xx_data *hci = dev->data;
361 	struct net_buf *buf = NULL;
362 	size_t buf_tailroom = 0;
363 
364 	switch (pti) {
365 	case HCI_PACKET_TYPE_EVENT:
366 		buf = bt_buf_get_evt(data[0], 0, K_NO_WAIT);
367 		if (!buf) {
368 			LOG_ERR("Failed to allocate the buffer for RX: EVENT ");
369 			return;
370 		}
371 		break;
372 
373 	case HCI_PACKET_TYPE_ACL:
374 		buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_NO_WAIT);
375 		if (!buf) {
376 			LOG_ERR("Failed to allocate the buffer for RX: ACL ");
377 			return;
378 		}
379 		bt_buf_set_type(buf, BT_BUF_ACL_IN);
380 		break;
381 
382 	case HCI_PACKET_TYPE_SCO:
383 		/* NA */
384 		break;
385 
386 	case HCI_PACKET_TYPE_ISO:
387 		buf = bt_buf_get_rx(BT_BUF_ISO_IN, K_NO_WAIT);
388 		if (!buf) {
389 			LOG_ERR("Failed to allocate the buffer for RX: ISO ");
390 			return;
391 		}
392 		break;
393 
394 	default:
395 		return;
396 
397 	}
398 
399 	buf_tailroom = net_buf_tailroom(buf);
400 	if (buf_tailroom < length) {
401 		LOG_WRN("Not enough space for rx data");
402 		return;
403 	}
404 	net_buf_add_mem(buf, data, length);
405 
406 	/* Provide the buffer to the host */
407 	hci->recv(dev, buf);
408 }
409 
wiced_bt_process_hci_events(uint8_t * data,uint32_t length)410 void wiced_bt_process_hci_events(uint8_t *data, uint32_t length)
411 {
412 	wiced_bt_process_hci(HCI_PACKET_TYPE_EVENT, data, length);
413 }
414 
wiced_bt_process_acl_data(uint8_t * data,uint32_t length)415 void wiced_bt_process_acl_data(uint8_t *data, uint32_t length)
416 {
417 	wiced_bt_process_hci(HCI_PACKET_TYPE_ACL, data, length);
418 }
419 
wiced_bt_process_isoc_data(uint8_t * data,uint32_t length)420 void wiced_bt_process_isoc_data(uint8_t *data, uint32_t length)
421 {
422 	wiced_bt_process_hci(HCI_PACKET_TYPE_ISO, data, length);
423 }
424 
wiced_bt_stack_init_internal(wiced_bt_management_cback_t mgmt_cback,wiced_bt_internal_post_stack_init_cb post_stack_cb,wiced_bt_internal_stack_evt_handler_cb evt_handler_cb)425 void wiced_bt_stack_init_internal(wiced_bt_management_cback_t mgmt_cback,
426 				  wiced_bt_internal_post_stack_init_cb post_stack_cb,
427 				  wiced_bt_internal_stack_evt_handler_cb evt_handler_cb)
428 {
429 	k_sem_give(&cybt_platform_task_init_sem);
430 }
431 
432 /* Keep below empty functions, used in the btstack_integration assets for Wiced BT stack. */
wiced_bt_stack_indicate_lower_tx_complete(void)433 void wiced_bt_stack_indicate_lower_tx_complete(void)
434 {
435 	/* NA for Zephyr */
436 }
437 
wiced_bt_stack_shutdown(void)438 void wiced_bt_stack_shutdown(void)
439 {
440 	/* NA for Zephyr */
441 }
442 
wiced_bt_process_timer(void)443 void wiced_bt_process_timer(void)
444 {
445 	/* NA for Zephyr */
446 }
447 
448 #define CYW208XX_DEVICE_INIT(inst) \
449 	static struct cyw208xx_data cyw208xx_data_##inst = { \
450 	}; \
451 	DEVICE_DT_INST_DEFINE(inst, cyw208xx_hci_init, NULL, &cyw208xx_data_##inst, NULL, \
452 			      POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &drv)
453 
454 /* Only one instance supported */
455 CYW208XX_DEVICE_INIT(0)
456