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