Hi Neeraj, On Fri, Feb 28, 2025 at 10:27 AM Neeraj Sanjay Kale <neeraj.sanjaykale@xxxxxxx> wrote: > > This adds support for setting BD address during hci registration. NXP > FW does not allow vendor commands unless it receives a reset command > after FW download and initialization done. > > As a workaround, the .set_bdaddr callback function will first send the > HCI reset command, followed by the actual vendor command to set BD > address. > > The driver checks for the local-bd-address property in device tree, and > if preset, it sets the HCI_QUIRK_USE_BDADDR_PROPERTY quirk. > > With this quirk set, the driver's set_bdaddr callback function is called > after FW download is complete and before HCI initialization, which sends > the hci reset and 3f 22 commands. During initialization, kernel reads > the newly set BD address from the controller. > > Signed-off-by: Loic Poulain <loic.poulain@xxxxxxxxxx> > Signed-off-by: Johan Korsnes <johan.korsnes@xxxxxxxxxxxxx> > Signed-off-by: Kristian Krohn <kristian.krohn@xxxxxxxxxxxxx> > Tested-by: Neeraj Sanjay Kale <neeraj.sanjaykale@xxxxxxx> > Signed-off-by: Neeraj Sanjay Kale <neeraj.sanjaykale@xxxxxxx> > --- > v4: hci0 interface shows RAW mode if 'local-bd-address' not defined and > HCI_QUIRK_USE_BDADDR_PROPERTY is set. Add Quirk only if device tree > property 'local-bd-address' found. (Neeraj) > v5: Initialize local variable ba, update Copywrite year. (Kristian) > v6: Elaborate commit message, add User Manual reference. (Paul Menzel) > --- > drivers/bluetooth/btnxpuart.c | 63 ++++++++++++++++++++++++++++++++--- > 1 file changed, 58 insertions(+), 5 deletions(-) > > diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c > index 1230045d78a5..2eb14b9beb70 100644 > --- a/drivers/bluetooth/btnxpuart.c > +++ b/drivers/bluetooth/btnxpuart.c > @@ -1,7 +1,7 @@ > // SPDX-License-Identifier: GPL-2.0-or-later > /* > * NXP Bluetooth driver > - * Copyright 2023 NXP > + * Copyright 2023-2025 NXP > */ > > #include <linux/module.h> > @@ -98,13 +98,16 @@ > #define PS_STATE_AWAKE 0 > #define PS_STATE_SLEEP 1 > > -/* Bluetooth vendor command : Sleep mode */ > +/* NXP Vendor Commands. Refer user manual UM11628 on nxp.com */ > +/* Set custom BD Address */ > +#define HCI_NXP_SET_BD_ADDR 0xfc22 > +/* Set Auto-Sleep mode */ > #define HCI_NXP_AUTO_SLEEP_MODE 0xfc23 > -/* Bluetooth vendor command : Wakeup method */ > +/* Set Wakeup method */ > #define HCI_NXP_WAKEUP_METHOD 0xfc53 > -/* Bluetooth vendor command : Set operational baudrate */ > +/* Set operational baudrate */ > #define HCI_NXP_SET_OPER_SPEED 0xfc09 > -/* Bluetooth vendor command: Independent Reset */ > +/* Independent Reset (Soft Reset) */ > #define HCI_NXP_IND_RESET 0xfcfc > > /* Bluetooth Power State : Vendor cmd params */ > @@ -310,6 +313,15 @@ union nxp_v3_rx_timeout_nak_u { > u8 buf[6]; > }; > > +union nxp_set_bd_addr_payload { > + struct { > + u8 param_id; > + u8 param_len; > + u8 param[6]; > + } __packed data; > + u8 buf[8]; > +}; > + > static u8 crc8_table[CRC8_TABLE_SIZE]; > > /* Default configurations */ > @@ -1197,6 +1209,38 @@ static int nxp_set_ind_reset(struct hci_dev *hdev, void *data) > return hci_recv_frame(hdev, skb); > } > > +static int nxp_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) > +{ > + union nxp_set_bd_addr_payload pcmd; > + struct sk_buff *skb; > + int err; > + > + pcmd.data.param_id = 0xfe; > + pcmd.data.param_len = 6; > + memcpy(pcmd.data.param, bdaddr, 6); > + > + /* BD address can be assigned only after first reset command. */ > + skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); > + if (IS_ERR(skb)) { > + err = PTR_ERR(skb); > + bt_dev_err(hdev, "Reset before setting local-bd-addr failed (%ld)", > + PTR_ERR(skb)); > + return err; > + } > + kfree_skb(skb); If you don't care about the response, just the status, it is probably better to use __hci_cmd_sync_status, also since the hdev->set_bdaddr comes after hdev->setup doesn't the later do perform a reset anyway? If you end up with 2 resets in a row it problems means you don't need to reset again. > + > + skb = __hci_cmd_sync(hdev, HCI_NXP_SET_BD_ADDR, sizeof(pcmd), > + pcmd.buf, HCI_CMD_TIMEOUT); Ditto. > + if (IS_ERR(skb)) { > + err = PTR_ERR(skb); > + bt_dev_err(hdev, "Changing device address failed (%d)", err); > + return err; > + } > + kfree_skb(skb); > + > + return 0; > +} > + > /* NXP protocol */ > static int nxp_setup(struct hci_dev *hdev) > { > @@ -1500,6 +1544,7 @@ static int nxp_serdev_probe(struct serdev_device *serdev) > { > struct hci_dev *hdev; > struct btnxpuart_dev *nxpdev; > + bdaddr_t ba = {0}; > > nxpdev = devm_kzalloc(&serdev->dev, sizeof(*nxpdev), GFP_KERNEL); > if (!nxpdev) > @@ -1547,8 +1592,16 @@ static int nxp_serdev_probe(struct serdev_device *serdev) > hdev->send = nxp_enqueue; > hdev->hw_error = nxp_hw_err; > hdev->shutdown = nxp_shutdown; > + hdev->set_bdaddr = nxp_set_bdaddr; > + > SET_HCIDEV_DEV(hdev, &serdev->dev); > > + device_property_read_u8_array(&nxpdev->serdev->dev, > + "local-bd-address", > + (u8 *)&ba, sizeof(ba)); > + if (bacmp(&ba, BDADDR_ANY)) > + set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks); > + > if (hci_register_dev(hdev) < 0) { > dev_err(&serdev->dev, "Can't register HCI device\n"); > goto probe_fail; > -- > 2.25.1 > -- Luiz Augusto von Dentz