Commit af35e28f authored by Hakan Jansson's avatar Hakan Jansson Committed by Luiz Augusto von Dentz

Bluetooth: hci_bcm: Add support for FW loading in autobaud mode

Use the presence of a DT property, "brcm,requires-autobaud-mode", to enable
startup in autobaud mode. If the property is present, the device is started
in autobaud mode by asserting RTS (BT_UART_CTS_N) prior to powering on the
device.

Also prevent the use of unsupported commands for devices started in
autobaud mode. Only a limited subset of HCI commands are supported in
autobaud mode.

Some devices (e.g. CYW5557x) require autobaud mode to enable FW loading.
Autobaud mode can also be required on some boards where the controller
device is using a non-standard baud rate in normal mode when first powered
on.
Signed-off-by: default avatarHakan Jansson <hakan.jansson@infineon.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 0b4de252
...@@ -403,6 +403,13 @@ static int btbcm_read_info(struct hci_dev *hdev) ...@@ -403,6 +403,13 @@ static int btbcm_read_info(struct hci_dev *hdev)
bt_dev_info(hdev, "BCM: chip id %u", skb->data[1]); bt_dev_info(hdev, "BCM: chip id %u", skb->data[1]);
kfree_skb(skb); kfree_skb(skb);
return 0;
}
static int btbcm_print_controller_features(struct hci_dev *hdev)
{
struct sk_buff *skb;
/* Read Controller Features */ /* Read Controller Features */
skb = btbcm_read_controller_features(hdev); skb = btbcm_read_controller_features(hdev);
if (IS_ERR(skb)) if (IS_ERR(skb))
...@@ -514,7 +521,7 @@ static const char *btbcm_get_board_name(struct device *dev) ...@@ -514,7 +521,7 @@ static const char *btbcm_get_board_name(struct device *dev)
#endif #endif
} }
int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done) int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done, bool use_autobaud_mode)
{ {
u16 subver, rev, pid, vid; u16 subver, rev, pid, vid;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -551,9 +558,16 @@ int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done) ...@@ -551,9 +558,16 @@ int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done)
if (err) if (err)
return err; return err;
} }
err = btbcm_print_local_name(hdev);
if (err) if (!use_autobaud_mode) {
return err; err = btbcm_print_controller_features(hdev);
if (err)
return err;
err = btbcm_print_local_name(hdev);
if (err)
return err;
}
bcm_subver_table = (hdev->bus == HCI_USB) ? bcm_usb_subver_table : bcm_subver_table = (hdev->bus == HCI_USB) ? bcm_usb_subver_table :
bcm_uart_subver_table; bcm_uart_subver_table;
...@@ -636,13 +650,13 @@ int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done) ...@@ -636,13 +650,13 @@ int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done)
} }
EXPORT_SYMBOL_GPL(btbcm_initialize); EXPORT_SYMBOL_GPL(btbcm_initialize);
int btbcm_finalize(struct hci_dev *hdev, bool *fw_load_done) int btbcm_finalize(struct hci_dev *hdev, bool *fw_load_done, bool use_autobaud_mode)
{ {
int err; int err;
/* Re-initialize if necessary */ /* Re-initialize if necessary */
if (*fw_load_done) { if (*fw_load_done) {
err = btbcm_initialize(hdev, fw_load_done); err = btbcm_initialize(hdev, fw_load_done, use_autobaud_mode);
if (err) if (err)
return err; return err;
} }
...@@ -658,15 +672,16 @@ EXPORT_SYMBOL_GPL(btbcm_finalize); ...@@ -658,15 +672,16 @@ EXPORT_SYMBOL_GPL(btbcm_finalize);
int btbcm_setup_patchram(struct hci_dev *hdev) int btbcm_setup_patchram(struct hci_dev *hdev)
{ {
bool fw_load_done = false; bool fw_load_done = false;
bool use_autobaud_mode = false;
int err; int err;
/* Initialize */ /* Initialize */
err = btbcm_initialize(hdev, &fw_load_done); err = btbcm_initialize(hdev, &fw_load_done, use_autobaud_mode);
if (err) if (err)
return err; return err;
/* Re-initialize after loading Patch */ /* Re-initialize after loading Patch */
return btbcm_finalize(hdev, &fw_load_done); return btbcm_finalize(hdev, &fw_load_done, use_autobaud_mode);
} }
EXPORT_SYMBOL_GPL(btbcm_setup_patchram); EXPORT_SYMBOL_GPL(btbcm_setup_patchram);
......
...@@ -62,8 +62,8 @@ int btbcm_write_pcm_int_params(struct hci_dev *hdev, ...@@ -62,8 +62,8 @@ int btbcm_write_pcm_int_params(struct hci_dev *hdev,
int btbcm_setup_patchram(struct hci_dev *hdev); int btbcm_setup_patchram(struct hci_dev *hdev);
int btbcm_setup_apple(struct hci_dev *hdev); int btbcm_setup_apple(struct hci_dev *hdev);
int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done); int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done, bool use_autobaud_mode);
int btbcm_finalize(struct hci_dev *hdev, bool *fw_load_done); int btbcm_finalize(struct hci_dev *hdev, bool *fw_load_done, bool use_autobaud_mode);
#else #else
...@@ -104,12 +104,12 @@ static inline int btbcm_setup_apple(struct hci_dev *hdev) ...@@ -104,12 +104,12 @@ static inline int btbcm_setup_apple(struct hci_dev *hdev)
return 0; return 0;
} }
static inline int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done) static inline int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done, bool use_autobaud_mode)
{ {
return 0; return 0;
} }
static inline int btbcm_finalize(struct hci_dev *hdev, bool *fw_load_done) static inline int btbcm_finalize(struct hci_dev *hdev, bool *fw_load_done, bool use_autobaud_mode)
{ {
return 0; return 0;
} }
......
...@@ -99,6 +99,7 @@ struct bcm_device_data { ...@@ -99,6 +99,7 @@ struct bcm_device_data {
* @no_early_set_baudrate: don't set_baudrate before setup() * @no_early_set_baudrate: don't set_baudrate before setup()
* @drive_rts_on_open: drive RTS signal on ->open() when platform requires it * @drive_rts_on_open: drive RTS signal on ->open() when platform requires it
* @pcm_int_params: keep the initial PCM configuration * @pcm_int_params: keep the initial PCM configuration
* @use_autobaud_mode: start Bluetooth device in autobaud mode
*/ */
struct bcm_device { struct bcm_device {
/* Must be the first member, hci_serdev.c expects this. */ /* Must be the first member, hci_serdev.c expects this. */
...@@ -136,6 +137,7 @@ struct bcm_device { ...@@ -136,6 +137,7 @@ struct bcm_device {
#endif #endif
bool no_early_set_baudrate; bool no_early_set_baudrate;
bool drive_rts_on_open; bool drive_rts_on_open;
bool use_autobaud_mode;
u8 pcm_int_params[5]; u8 pcm_int_params[5];
}; };
...@@ -472,7 +474,9 @@ static int bcm_open(struct hci_uart *hu) ...@@ -472,7 +474,9 @@ static int bcm_open(struct hci_uart *hu)
out: out:
if (bcm->dev) { if (bcm->dev) {
if (bcm->dev->drive_rts_on_open) if (bcm->dev->use_autobaud_mode)
hci_uart_set_flow_control(hu, false); /* Assert BT_UART_CTS_N */
else if (bcm->dev->drive_rts_on_open)
hci_uart_set_flow_control(hu, true); hci_uart_set_flow_control(hu, true);
hu->init_speed = bcm->dev->init_speed; hu->init_speed = bcm->dev->init_speed;
...@@ -564,6 +568,7 @@ static int bcm_setup(struct hci_uart *hu) ...@@ -564,6 +568,7 @@ static int bcm_setup(struct hci_uart *hu)
{ {
struct bcm_data *bcm = hu->priv; struct bcm_data *bcm = hu->priv;
bool fw_load_done = false; bool fw_load_done = false;
bool use_autobaud_mode = (bcm->dev ? bcm->dev->use_autobaud_mode : 0);
unsigned int speed; unsigned int speed;
int err; int err;
...@@ -572,7 +577,7 @@ static int bcm_setup(struct hci_uart *hu) ...@@ -572,7 +577,7 @@ static int bcm_setup(struct hci_uart *hu)
hu->hdev->set_diag = bcm_set_diag; hu->hdev->set_diag = bcm_set_diag;
hu->hdev->set_bdaddr = btbcm_set_bdaddr; hu->hdev->set_bdaddr = btbcm_set_bdaddr;
err = btbcm_initialize(hu->hdev, &fw_load_done); err = btbcm_initialize(hu->hdev, &fw_load_done, use_autobaud_mode);
if (err) if (err)
return err; return err;
...@@ -616,7 +621,7 @@ static int bcm_setup(struct hci_uart *hu) ...@@ -616,7 +621,7 @@ static int bcm_setup(struct hci_uart *hu)
btbcm_write_pcm_int_params(hu->hdev, &params); btbcm_write_pcm_int_params(hu->hdev, &params);
} }
err = btbcm_finalize(hu->hdev, &fw_load_done); err = btbcm_finalize(hu->hdev, &fw_load_done, use_autobaud_mode);
if (err) if (err)
return err; return err;
...@@ -1197,6 +1202,11 @@ static int bcm_acpi_probe(struct bcm_device *dev) ...@@ -1197,6 +1202,11 @@ static int bcm_acpi_probe(struct bcm_device *dev)
static int bcm_of_probe(struct bcm_device *bdev) static int bcm_of_probe(struct bcm_device *bdev)
{ {
bdev->use_autobaud_mode = device_property_read_bool(bdev->dev,
"brcm,requires-autobaud-mode");
if (bdev->use_autobaud_mode)
bdev->no_early_set_baudrate = true;
device_property_read_u32(bdev->dev, "max-speed", &bdev->oper_speed); device_property_read_u32(bdev->dev, "max-speed", &bdev->oper_speed);
device_property_read_u8_array(bdev->dev, "brcm,bt-pcm-int-params", device_property_read_u8_array(bdev->dev, "brcm,bt-pcm-int-params",
bdev->pcm_int_params, 5); bdev->pcm_int_params, 5);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment