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