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