2023-01-18 13:16:15

by Francesco Dolcini

[permalink] [raw]
Subject: [PATCH v1 0/4] Bluetooth: hci_mrvl: Add serdev support for 88W8997

From: Francesco Dolcini <[email protected]>

Add serdev support for the 88W8997 from NXP (previously Marvell). It includes
support for changing the baud rate. The command to change the baud rate is
taken from the user manual UM11483 Rev. 9 in section 7 (Bring-up of Bluetooth
interfaces) from NXP.

Stefan Eichenberger (4):
dt-bindings: bluetooth: marvell: add 88W8997 DT binding
dt-bindings: bluetooth: marvell: add max-speed property
Bluetooth: hci_mrvl: Add serdev support for 88W8997
arm64: dts: imx8mp-verdin: add 88W8997 serdev to uart4

.../bindings/net/marvell-bluetooth.yaml | 20 ++++-
.../dts/freescale/imx8mp-verdin-wifi.dtsi | 5 ++
drivers/bluetooth/hci_mrvl.c | 88 +++++++++++++++++--
3 files changed, 105 insertions(+), 8 deletions(-)

--
2.25.1


2023-01-18 13:16:22

by Francesco Dolcini

[permalink] [raw]
Subject: [PATCH v1 3/4] Bluetooth: hci_mrvl: Add serdev support for 88W8997

From: Stefan Eichenberger <[email protected]>

Add serdev support for the 88W8997 from NXP (previously Marvell). It
includes support for changing the baud rate. The command to change the
baud rate is taken from the user manual UM11483 Rev. 9 in section 7
(Bring-up of Bluetooth interfaces) from NXP.

Signed-off-by: Stefan Eichenberger <[email protected]>
Signed-off-by: Francesco Dolcini <[email protected]>
---
drivers/bluetooth/hci_mrvl.c | 88 +++++++++++++++++++++++++++++++++---
1 file changed, 81 insertions(+), 7 deletions(-)

diff --git a/drivers/bluetooth/hci_mrvl.c b/drivers/bluetooth/hci_mrvl.c
index fbc3f7c3a5c7..86f548998a18 100644
--- a/drivers/bluetooth/hci_mrvl.c
+++ b/drivers/bluetooth/hci_mrvl.c
@@ -27,10 +27,12 @@
#define MRVL_ACK 0x5A
#define MRVL_NAK 0xBF
#define MRVL_RAW_DATA 0x1F
+#define MRVL_SET_BAUDRATE 0xFC09

enum {
STATE_CHIP_VER_PENDING,
STATE_FW_REQ_PENDING,
+ STATE_FW_LOADED,
};

struct mrvl_data {
@@ -254,6 +256,14 @@ static int mrvl_recv(struct hci_uart *hu, const void *data, int count)
if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
return -EUNATCH;

+ /* We might receive some noise when there is no firmware loaded. Therefore,
+ * we drop data if the firmware is not loaded yet and if there is no fw load
+ * request pending.
+ */
+ if (!test_bit(STATE_FW_REQ_PENDING, &mrvl->flags) &&
+ !test_bit(STATE_FW_LOADED, &mrvl->flags))
+ return count;
+
mrvl->rx_skb = h4_recv_buf(hu->hdev, mrvl->rx_skb, data, count,
mrvl_recv_pkts,
ARRAY_SIZE(mrvl_recv_pkts));
@@ -354,6 +364,7 @@ static int mrvl_load_firmware(struct hci_dev *hdev, const char *name)
static int mrvl_setup(struct hci_uart *hu)
{
int err;
+ struct mrvl_data *mrvl = hu->priv;

hci_uart_set_flow_control(hu, true);

@@ -367,9 +378,9 @@ static int mrvl_setup(struct hci_uart *hu)
hci_uart_wait_until_sent(hu);

if (hu->serdev)
- serdev_device_set_baudrate(hu->serdev, 3000000);
+ serdev_device_set_baudrate(hu->serdev, hu->oper_speed);
else
- hci_uart_set_baudrate(hu, 3000000);
+ hci_uart_set_baudrate(hu, hu->oper_speed);

hci_uart_set_flow_control(hu, false);

@@ -377,13 +388,56 @@ static int mrvl_setup(struct hci_uart *hu)
if (err)
return err;

+ set_bit(STATE_FW_LOADED, &mrvl->flags);
+
+ return 0;
+}
+
+static int mrvl_set_baudrate(struct hci_uart *hu, unsigned int speed)
+{
+ int err;
+ struct sk_buff *skb;
+ struct mrvl_data *mrvl = hu->priv;
+ __le32 speed_le = cpu_to_le32(speed);
+
+ /* The firmware might be loaded by the Wifi driver over SDIO. We wait
+ * up to 10s for the CTS to go up. Afterward, we know that the firmware
+ * is ready.
+ */
+ err = serdev_device_wait_for_cts(hu->serdev, true, 10000);
+ if (err) {
+ bt_dev_err(hu->hdev, "Wait for CTS failed with %d\n", err);
+ return err;
+ }
+
+ set_bit(STATE_FW_LOADED, &mrvl->flags);
+
+ skb = __hci_cmd_sync(hu->hdev, MRVL_SET_BAUDRATE,
+ sizeof(speed_le), &speed_le,
+ HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ bt_dev_err(hu->hdev, "send command failed: %ld", PTR_ERR(skb));
+ return PTR_ERR(skb);
+ }
+ kfree_skb(skb);
+
+ serdev_device_set_baudrate(hu->serdev, speed);
+
+ /* We forcefully have to send a command to the bluetooth module so that
+ * the driver detects it after a baudrate change. This is foreseen by
+ * hci_serdev by setting HCI_UART_VND_DETECT which then causes a dummy
+ * local version read.
+ */
+ set_bit(HCI_UART_VND_DETECT, &hu->hdev_flags);
+
return 0;
}

-static const struct hci_uart_proto mrvl_proto = {
+static const struct hci_uart_proto mrvl_proto_8897 = {
.id = HCI_UART_MRVL,
.name = "Marvell",
.init_speed = 115200,
+ .oper_speed = 3000000,
.open = mrvl_open,
.close = mrvl_close,
.flush = mrvl_flush,
@@ -393,18 +447,37 @@ static const struct hci_uart_proto mrvl_proto = {
.dequeue = mrvl_dequeue,
};

+static const struct hci_uart_proto mrvl_proto_8997 = {
+ .id = HCI_UART_MRVL,
+ .name = "Marvell 8997",
+ .init_speed = 115200,
+ .oper_speed = 3000000,
+ .open = mrvl_open,
+ .close = mrvl_close,
+ .flush = mrvl_flush,
+ .set_baudrate = mrvl_set_baudrate,
+ .recv = mrvl_recv,
+ .enqueue = mrvl_enqueue,
+ .dequeue = mrvl_dequeue,
+};
+
static int mrvl_serdev_probe(struct serdev_device *serdev)
{
struct mrvl_serdev *mrvldev;
+ const struct hci_uart_proto *mrvl_proto = device_get_match_data(&serdev->dev);

mrvldev = devm_kzalloc(&serdev->dev, sizeof(*mrvldev), GFP_KERNEL);
if (!mrvldev)
return -ENOMEM;

+ mrvldev->hu.oper_speed = mrvl_proto->oper_speed;
+ if (mrvl_proto->set_baudrate)
+ of_property_read_u32(serdev->dev.of_node, "max-speed", &mrvldev->hu.oper_speed);
+
mrvldev->hu.serdev = serdev;
serdev_device_set_drvdata(serdev, mrvldev);

- return hci_uart_register_device(&mrvldev->hu, &mrvl_proto);
+ return hci_uart_register_device(&mrvldev->hu, mrvl_proto);
}

static void mrvl_serdev_remove(struct serdev_device *serdev)
@@ -416,7 +489,8 @@ static void mrvl_serdev_remove(struct serdev_device *serdev)

#ifdef CONFIG_OF
static const struct of_device_id mrvl_bluetooth_of_match[] = {
- { .compatible = "mrvl,88w8897" },
+ { .compatible = "mrvl,88w8897", .data = &mrvl_proto_8897},
+ { .compatible = "mrvl,88w8997", .data = &mrvl_proto_8997},
{ },
};
MODULE_DEVICE_TABLE(of, mrvl_bluetooth_of_match);
@@ -435,12 +509,12 @@ int __init mrvl_init(void)
{
serdev_device_driver_register(&mrvl_serdev_driver);

- return hci_uart_register_proto(&mrvl_proto);
+ return hci_uart_register_proto(&mrvl_proto_8897);
}

int __exit mrvl_deinit(void)
{
serdev_device_driver_unregister(&mrvl_serdev_driver);

- return hci_uart_unregister_proto(&mrvl_proto);
+ return hci_uart_unregister_proto(&mrvl_proto_8897);
}
--
2.25.1

2023-01-18 13:17:06

by Francesco Dolcini

[permalink] [raw]
Subject: [PATCH v1 4/4] arm64: dts: imx8mp-verdin: add 88W8997 serdev to uart4

From: Stefan Eichenberger <[email protected]>

Use the serdev feature to load the driver for the 88W8997 bluetooth
driver.

Signed-off-by: Stefan Eichenberger <[email protected]>
Signed-off-by: Francesco Dolcini <[email protected]>
---
arch/arm64/boot/dts/freescale/imx8mp-verdin-wifi.dtsi | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin-wifi.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-verdin-wifi.dtsi
index 36289c175e6e..ef94f9a57e20 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-verdin-wifi.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin-wifi.dtsi
@@ -65,6 +65,11 @@ &uart4 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_bt_uart>;
status = "okay";
+
+ bluetooth {
+ compatible = "mrvl,88w8997";
+ max-speed = <921600>;
+ };
};

/* On-module Wi-Fi */
--
2.25.1

2023-01-18 21:14:06

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v1 3/4] Bluetooth: hci_mrvl: Add serdev support for 88W8997

Hi Francesco,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on robh/for-next]
[also build test WARNING on bluetooth-next/master bluetooth/master horms-ipvs/master net/master net-next/master linus/master v6.2-rc4 next-20230118]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/Francesco-Dolcini/dt-bindings-bluetooth-marvell-add-88W8997-DT-binding/20230118-210919
base: https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
patch link: https://lore.kernel.org/r/20230118122817.42466-4-francesco%40dolcini.it
patch subject: [PATCH v1 3/4] Bluetooth: hci_mrvl: Add serdev support for 88W8997
config: i386-randconfig-s002 (https://download.01.org/0day-ci/archive/20230119/[email protected]/config)
compiler: gcc-11 (Debian 11.3.0-8) 11.3.0
reproduce:
# apt-get install sparse
# sparse version: v0.6.4-39-gce1a6720-dirty
# https://github.com/intel-lab-lkp/linux/commit/2ae116c8ad209e0bf11559519915e511c44c28be
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Francesco-Dolcini/dt-bindings-bluetooth-marvell-add-88W8997-DT-binding/20230118-210919
git checkout 2ae116c8ad209e0bf11559519915e511c44c28be
# save the config file
mkdir build_dir && cp config build_dir/.config
make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=i386 olddefconfig
make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=i386 SHELL=/bin/bash drivers/bluetooth/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>

All warnings (new ones prefixed by >>):

>> drivers/bluetooth/hci_mrvl.c:450:36: warning: 'mrvl_proto_8997' defined but not used [-Wunused-const-variable=]
450 | static const struct hci_uart_proto mrvl_proto_8997 = {
| ^~~~~~~~~~~~~~~


vim +/mrvl_proto_8997 +450 drivers/bluetooth/hci_mrvl.c

449
> 450 static const struct hci_uart_proto mrvl_proto_8997 = {
451 .id = HCI_UART_MRVL,
452 .name = "Marvell 8997",
453 .init_speed = 115200,
454 .oper_speed = 3000000,
455 .open = mrvl_open,
456 .close = mrvl_close,
457 .flush = mrvl_flush,
458 .set_baudrate = mrvl_set_baudrate,
459 .recv = mrvl_recv,
460 .enqueue = mrvl_enqueue,
461 .dequeue = mrvl_dequeue,
462 };
463

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests