1 /*
2  * Copyright (c) 2023 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 CYW43xxx HCI extension driver.
10  */
11 
12 #include <errno.h>
13 #include <stddef.h>
14 
15 #include <zephyr/kernel.h>
16 #include <zephyr/device.h>
17 #include <zephyr/bluetooth/bluetooth.h>
18 #include <zephyr/drivers/bluetooth/hci_driver.h>
19 #include <zephyr/drivers/gpio.h>
20 #include <zephyr/drivers/uart.h>
21 
22 #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
23 #define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL
24 #include <zephyr/logging/log.h>
25 LOG_MODULE_REGISTER(cyw43xxx_driver);
26 
27 #include <stdint.h>
28 
29 #define DT_DRV_COMPAT infineon_cyw43xxx_bt_hci
30 
31 /* BT settling time after power on */
32 #define BT_POWER_ON_SETTLING_TIME_MS      (500u)
33 
34 /* Stabilization delay after FW loading */
35 #define BT_STABILIZATION_DELAY_MS         (250u)
36 
37 /* HCI Command packet from Host to Controller */
38 #define HCI_COMMAND_PACKET                (0x01)
39 
40 /* Length of UPDATE BAUD RATE command */
41 #define HCI_VSC_UPDATE_BAUD_RATE_LENGTH   (6u)
42 
43 /* Default BAUDRATE */
44 #define HCI_UART_DEFAULT_BAUDRATE         (115200)
45 
46 /* Externs for CY43xxx controller FW */
47 extern const uint8_t brcm_patchram_buf[];
48 extern const int brcm_patch_ram_length;
49 
50 enum {
51 	BT_HCI_VND_OP_DOWNLOAD_MINIDRIVER       = 0xFC2E,
52 	BT_HCI_VND_OP_WRITE_RAM                 = 0xFC4C,
53 	BT_HCI_VND_OP_LAUNCH_RAM                = 0xFC4E,
54 	BT_HCI_VND_OP_UPDATE_BAUDRATE           = 0xFC18,
55 };
56 
57 /*  bt_h4_vnd_setup function.
58  * This function executes vendor-specific commands sequence to
59  * initialize BT Controller before BT Host executes Reset sequence.
60  * bt_h4_vnd_setup function must be implemented in vendor-specific HCI
61  * extansion module if CONFIG_BT_HCI_SETUP is enabled.
62  */
63 int bt_h4_vnd_setup(const struct device *dev);
64 
bt_hci_uart_set_baudrate(const struct device * bt_uart_dev,uint32_t baudrate)65 static int bt_hci_uart_set_baudrate(const struct device *bt_uart_dev, uint32_t baudrate)
66 {
67 	struct uart_config uart_cfg;
68 	int err;
69 
70 	/* Get current UART configuration */
71 	err = uart_config_get(bt_uart_dev, &uart_cfg);
72 	if (err) {
73 		return err;
74 	}
75 
76 	if (uart_cfg.baudrate != baudrate) {
77 		/* Re-configure UART */
78 		uart_cfg.baudrate = baudrate;
79 		err = uart_configure(bt_uart_dev, &uart_cfg);
80 		if (err) {
81 			return err;
82 		}
83 
84 		/* Revert Interrupt options */
85 		uart_irq_rx_enable(bt_uart_dev);
86 	}
87 	return 0;
88 }
89 
bt_update_controller_baudrate(const struct device * bt_uart_dev,uint32_t baudrate)90 static int bt_update_controller_baudrate(const struct device *bt_uart_dev, uint32_t baudrate)
91 {
92 	/*
93 	 *  NOTE from datasheet for update baudrate:
94 	 *  - To speed up application downloading, the MCU host commands the CYWxxx device
95 	 *    to communicate at a new, higher rate by issuing the following Vendor Specific
96 	 *    UPDATE_BAUDRATE command:
97 	 *      01 18 FC 06 00 00 xx xx xx xx
98 	 *    In the above command, the xx xx xx xx bytes specify the 32-bit little-endian
99 	 *    value of the new rate in bits per second. For example,
100 	 *    115200 is represented as 00 C2 01 00.
101 	 *  The following response to the UPDATE_BAUDRATE command is expected within 100 ms:
102 	 *  04 0E 04 01 18 FC 00
103 	 *  - The host switches to the new baud rate after receiving the response at the old
104 	 *  baud rate.
105 	 */
106 	struct net_buf *buf;
107 	int err;
108 	uint8_t hci_data[HCI_VSC_UPDATE_BAUD_RATE_LENGTH];
109 
110 	/* Baudrate is loaded LittleEndian */
111 	hci_data[0] = 0;
112 	hci_data[1] = 0;
113 	hci_data[2] = (uint8_t)(baudrate & 0xFFUL);
114 	hci_data[3] = (uint8_t)((baudrate >> 8) & 0xFFUL);
115 	hci_data[4] = (uint8_t)((baudrate >> 16) & 0xFFUL);
116 	hci_data[5] = (uint8_t)((baudrate >> 24) & 0xFFUL);
117 
118 	/* Allocate buffer for update uart baudrate command.
119 	 * It will be BT_HCI_OP_RESET with extra parameters.
120 	 */
121 	buf = bt_hci_cmd_create(BT_HCI_VND_OP_UPDATE_BAUDRATE,
122 				HCI_VSC_UPDATE_BAUD_RATE_LENGTH);
123 	if (buf == NULL) {
124 		LOG_ERR("Unable to allocate command buffer");
125 		return -ENOMEM;
126 	}
127 
128 	/* Add data part of packet */
129 	net_buf_add_mem(buf, &hci_data, HCI_VSC_UPDATE_BAUD_RATE_LENGTH);
130 
131 	/* Send update uart baudrate command. */
132 	err = bt_hci_cmd_send_sync(BT_HCI_VND_OP_UPDATE_BAUDRATE, buf, NULL);
133 	if (err) {
134 		return err;
135 	}
136 
137 	/* Re-configure Uart baudrate */
138 	err = bt_hci_uart_set_baudrate(bt_uart_dev, baudrate);
139 	if (err) {
140 		return err;
141 	}
142 
143 	return 0;
144 }
145 
bt_firmware_download(const uint8_t * firmware_image,uint32_t size)146 static int bt_firmware_download(const uint8_t *firmware_image, uint32_t size)
147 {
148 	uint8_t *data = (uint8_t *)firmware_image;
149 	volatile uint32_t remaining_length = size;
150 	struct net_buf *buf;
151 	int err;
152 
153 	LOG_DBG("Executing Fw downloading for CYW43xx device");
154 
155 	/* Send hci_download_minidriver command */
156 	err = bt_hci_cmd_send_sync(BT_HCI_VND_OP_DOWNLOAD_MINIDRIVER, NULL, NULL);
157 	if (err) {
158 		return err;
159 	}
160 
161 	/* The firmware image (.hcd format) contains a collection of hci_write_ram
162 	 * command + a block of the image, followed by a hci_write_ram image at the end.
163 	 * Parse and send each individual command and wait for the response. This is to
164 	 * ensure the integrity of the firmware image sent to the bluetooth chip.
165 	 */
166 	while (remaining_length) {
167 		size_t data_length = data[2]; /* data length from firmware image block */
168 		uint16_t op_code = *(uint16_t *)data;
169 
170 		/* Allocate buffer for hci_write_ram/hci_launch_ram command. */
171 		buf = bt_hci_cmd_create(op_code, data_length);
172 		if (buf == NULL) {
173 			LOG_ERR("Unable to allocate command buffer");
174 			return err;
175 		}
176 
177 		/* Add data part of packet */
178 		net_buf_add_mem(buf, &data[3], data_length);
179 
180 		/* Send hci_write_ram command. */
181 		err = bt_hci_cmd_send_sync(op_code, buf, NULL);
182 		if (err) {
183 			return err;
184 		}
185 
186 		switch (op_code) {
187 		case BT_HCI_VND_OP_WRITE_RAM:
188 			/* Update remaining length and data pointer:
189 			 * content of data length + 2 bytes of opcode and 1 byte of data length.
190 			 */
191 			data += data_length + 3;
192 			remaining_length -= data_length + 3;
193 			break;
194 
195 		case BT_HCI_VND_OP_LAUNCH_RAM:
196 			remaining_length = 0;
197 			break;
198 
199 		default:
200 			return -ENOMEM;
201 		}
202 	}
203 
204 	LOG_DBG("Fw downloading complete");
205 	return 0;
206 }
207 
bt_h4_vnd_setup(const struct device * dev)208 int bt_h4_vnd_setup(const struct device *dev)
209 {
210 	int err;
211 	uint32_t default_uart_speed = DT_PROP(DT_INST_BUS(0), current_speed);
212 	uint32_t hci_operation_speed = DT_INST_PROP_OR(0, hci_operation_speed, default_uart_speed);
213 	uint32_t fw_download_speed = DT_INST_PROP_OR(0, fw_download_speed, default_uart_speed);
214 
215 	/* Check BT Uart instance */
216 	if (!device_is_ready(dev)) {
217 		return -EINVAL;
218 	}
219 
220 #if DT_INST_NODE_HAS_PROP(0, bt_reg_on_gpios)
221 	struct gpio_dt_spec bt_reg_on = GPIO_DT_SPEC_GET(DT_DRV_INST(0), bt_reg_on_gpios);
222 
223 	/* Check BT REG_ON gpio instance */
224 	if (!gpio_is_ready_dt(&bt_reg_on)) {
225 		LOG_ERR("Error: failed to configure bt_reg_on %s pin %d",
226 			bt_reg_on.port->name, bt_reg_on.pin);
227 		return -EIO;
228 	}
229 
230 	/* Configure bt_reg_on as output  */
231 	err = gpio_pin_configure_dt(&bt_reg_on, GPIO_OUTPUT);
232 	if (err) {
233 		LOG_ERR("Error %d: failed to configure bt_reg_on %s pin %d",
234 			err, bt_reg_on.port->name, bt_reg_on.pin);
235 		return err;
236 	}
237 	err = gpio_pin_set_dt(&bt_reg_on, 1);
238 	if (err) {
239 		return err;
240 	}
241 #endif /* DT_INST_NODE_HAS_PROP(0, bt_reg_on_gpios) */
242 
243 	/* BT settling time after power on */
244 	(void)k_msleep(BT_POWER_ON_SETTLING_TIME_MS);
245 
246 	/* Send HCI_RESET */
247 	err = bt_hci_cmd_send_sync(BT_HCI_OP_RESET, NULL, NULL);
248 	if (err) {
249 		return err;
250 	}
251 
252 	/* Re-configure baudrate for BT Controller */
253 	if (fw_download_speed != default_uart_speed) {
254 		err = bt_update_controller_baudrate(dev, fw_download_speed);
255 		if (err) {
256 			return err;
257 		}
258 	}
259 
260 	/* BT firmware download */
261 	err = bt_firmware_download(brcm_patchram_buf, (uint32_t) brcm_patch_ram_length);
262 	if (err) {
263 		return err;
264 	}
265 
266 	/* Stabilization delay */
267 	(void)k_msleep(BT_STABILIZATION_DELAY_MS);
268 
269 	/* When FW launched, HCI UART baudrate should be configured to default */
270 	if (fw_download_speed != default_uart_speed) {
271 		err = bt_hci_uart_set_baudrate(dev, default_uart_speed);
272 		if (err) {
273 			return err;
274 		}
275 	}
276 
277 	/* Send HCI_RESET */
278 	err = bt_hci_cmd_send_sync(BT_HCI_OP_RESET, NULL, NULL);
279 	if (err) {
280 		return err;
281 	}
282 
283 	/* Set host controller functionality to user defined baudrate
284 	 * after fw downloading.
285 	 */
286 	if (hci_operation_speed != default_uart_speed) {
287 		err = bt_update_controller_baudrate(dev, hci_operation_speed);
288 		if (err) {
289 			return err;
290 		}
291 	}
292 
293 	return 0;
294 }
295