Re: [PATCH v1 3/3] Bluetooth: btqca: Add QCA6698 support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Nov 29, 2024 at 10:05:30AM +0800, Cheng Jiang (IOE) wrote:
> Hi Dmitry,
> 
> On 11/28/2024 9:02 PM, Dmitry Baryshkov wrote:
> > On Thu, Nov 28, 2024 at 08:09:22PM +0800, Cheng Jiang wrote:
> >> Add support for the QCA6698 Bluetooth chip, which shares the same IP core
> >> as the WCN6855. However, it has different RF components and RAM sizes,
> >> requiring new firmware files. This patch adds support for loading QCA6698
> >> rampatch and NVM from a different directory.
> >>
> >> Due to variations in RF performance of QCA6698 chips from different
> >> foundries, different NVM configurations are used based on board ID.
> >>
> >> Signed-off-by: Cheng Jiang <quic_chejiang@xxxxxxxxxxx>
> >> ---
> >>  drivers/bluetooth/btqca.c   | 47 ++++++++++++++++++++++++++++++++++++-
> >>  drivers/bluetooth/btqca.h   |  1 +
> >>  drivers/bluetooth/hci_qca.c | 36 ++++++++++++++++++++++++++--
> >>  3 files changed, 81 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
> >> index dfbbac922..24bf00cac 100644
> >> --- a/drivers/bluetooth/btqca.c
> >> +++ b/drivers/bluetooth/btqca.c
> >> @@ -700,6 +700,21 @@ static int qca_check_bdaddr(struct hci_dev *hdev, const struct qca_fw_config *co
> >>  	return 0;
> >>  }
> >>  
> >> +int qca_check_firmware_exists(const char *name, struct hci_dev *hdev)
> >> +{
> >> +	const struct firmware *fw;
> >> +	int ret;
> >> +
> >> +	ret = firmware_request_nowarn(&fw, name, &hdev->dev);
> >> +	if (ret) {
> >> +		bt_dev_warn(hdev, "Firmware %s does not exist. Use default", name);
> > 
> > No useless warnings
> Ack.
> > 
> >> +		return 0;
> >> +	}
> >> +
> >> +	release_firmware(fw);
> >> +	return 1;
> >> +}
> >> +
> >>  static void qca_generate_hsp_nvm_name(char *fwname, size_t max_size,
> >>  		struct qca_btsoc_version ver, u8 rom_ver, u16 bid)
> >>  {
> >> @@ -730,6 +745,26 @@ static inline void qca_get_nvm_name_generic(struct qca_fw_config *cfg,
> >>  			 "qca/%snv%02x.b%02x", stem, rom_ver, bid);
> >>  }
> >>  
> >> +static void qca_get_qca6698_nvm_name(struct hci_dev *hdev, char *fwname,
> >> +		size_t max_size, struct qca_btsoc_version ver, u8 rom_ver, u16 bid)
> >> +{
> >> +	const char *variant;
> >> +
> >> +	/* hsp gf chip */
> >> +	if ((le32_to_cpu(ver.soc_id) & QCA_HSP_GF_SOC_MASK) == QCA_HSP_GF_SOC_ID)
> >> +		variant = "g";
> >> +	else
> >> +		variant = "";
> >> +
> >> +	if (bid != 0x0)
> >> +		snprintf(fwname, max_size, "qca/QCA6698/hpnv%02x%s.b%04x", rom_ver,
> >> +			 variant, bid);
> >> +
> >> +	/* if board id is 0 or the nvm file doesn't exisit, use the default */
> >> +	if (bid == 0x0 || !qca_check_firmware_exists(fwname, hdev))
> >> +		snprintf(fwname, max_size, "qca/QCA6698/hpnv%02x%s.bin", rom_ver, variant);
> > 
> > So, do you want to load the same firmware twice? You've asked for it
> > already, if it is present, use it.
> This is only used to check the nvm exists or not. Yes, it's loaded twice if the nvm exist.
> It's just to avoid too much changes of the firmware download on the current driver. 
> > 
> > Anyway, if you have followed previous discussions, you'd have known that
> > it has been recommended to use DT's firmware-name instead of pushing
> > everything to the driver.
> Sorry, I misunderstand the comment here. I thought it was to add a compact string. 
> "qcom,qca6698-bt", since both the meothods can solve our requriment. If use DT's
> firmware-name is perfered, I can provide a change based on it. 
> 
> "
> Need because of the product needs or need because of the existing
> firmware not working with the chip?
> Wait... your WiFi colleagues were more helpful and they wrote that "it
> has different RF,
> IPA, thermal, RAM size and etc, so new firmware files used." ([1]).
> Please include that information in your commit messages too to let
> reviewers understand  what is going on.
> 
> [1] https://lore.kernel.org/linux-arm-msm/20241024002514.92290-1-quic_miaoqing@xxxxxxxxxxx/
> 
> > Let me check if using
> > "firmware-name" allows us to omit the new soc type.
> > From the driver's perspective, the only change is the need to load a
> > different firmware.
> 
> If you want to emphasise that it is not just WCN6855, extend schema to
> use fallback compatibles:
> compat = "qcom,qca6698-bt", "qcom,wcn6855-bt"; No driver changes are
> necessary with this approach.
> "

Please learn how to quote messages. Anyway, it clearly says to use
firmware-name and two compat strings. If you have questions, please ask
them _before_  sending new iteration, not after.

> > 
> >> +}
> >> +
> >>  int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
> >>  		   enum qca_btsoc_type soc_type, struct qca_btsoc_version ver,
> >>  		   const char *firmware_name)
> >> @@ -796,6 +831,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
> >>  		snprintf(config.fwname, sizeof(config.fwname),
> >>  			 "qca/hmtbtfw%02x.tlv", rom_ver);
> >>  		break;
> >> +	case QCA_QCA6698:
> >> +		snprintf(config.fwname, sizeof(config.fwname),
> >> +			 "qca/QCA6698/hpbtfw%02x.tlv", rom_ver);
> >> +		break;
> >>  	default:
> >>  		snprintf(config.fwname, sizeof(config.fwname),
> >>  			 "qca/rampatch_%08x.bin", soc_ver);
> >> @@ -810,7 +849,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
> >>  	/* Give the controller some time to get ready to receive the NVM */
> >>  	msleep(10);
> >>  
> >> -	if (soc_type == QCA_QCA2066 || soc_type == QCA_WCN7850)
> >> +	if (soc_type == QCA_QCA2066 || soc_type == QCA_QCA6698)
> >>  		qca_read_fw_board_id(hdev, &boardid);
> >>  
> >>  	/* Download NVM configuration */
> >> @@ -854,6 +893,10 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
> >>  		case QCA_WCN7850:
> >>  			qca_get_nvm_name_generic(&config, "hmt", rom_ver, boardid);
> >>  			break;
> >> +		case QCA_QCA6698:
> >> +			qca_get_qca6698_nvm_name(hdev, config.fwname,
> >> +				sizeof(config.fwname), ver, rom_ver, boardid);
> >> +			break;
> >>  
> >>  		default:
> >>  			snprintf(config.fwname, sizeof(config.fwname),
> >> @@ -874,6 +917,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
> >>  	case QCA_WCN6750:
> >>  	case QCA_WCN6855:
> >>  	case QCA_WCN7850:
> >> +	case QCA_QCA6698:
> >>  		err = qca_disable_soc_logging(hdev);
> >>  		if (err < 0)
> >>  			return err;
> >> @@ -909,6 +953,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
> >>  	case QCA_WCN6750:
> >>  	case QCA_WCN6855:
> >>  	case QCA_WCN7850:
> >> +	case QCA_QCA6698:
> >>  		/* get fw build info */
> >>  		err = qca_read_fw_build_info(hdev);
> >>  		if (err < 0)
> >> diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h
> >> index bb5207d7a..67c16d8f2 100644
> >> --- a/drivers/bluetooth/btqca.h
> >> +++ b/drivers/bluetooth/btqca.h
> >> @@ -151,6 +151,7 @@ enum qca_btsoc_type {
> >>  	QCA_WCN3991,
> >>  	QCA_QCA2066,
> >>  	QCA_QCA6390,
> >> +	QCA_QCA6698,
> >>  	QCA_WCN6750,
> >>  	QCA_WCN6855,
> >>  	QCA_WCN7850,
> >> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> >> index 37129e6cb..70bdc046c 100644
> >> --- a/drivers/bluetooth/hci_qca.c
> >> +++ b/drivers/bluetooth/hci_qca.c
> >> @@ -1361,6 +1361,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
> >>  	case QCA_WCN6750:
> >>  	case QCA_WCN6855:
> >>  	case QCA_WCN7850:
> >> +	case QCA_QCA6698:
> >>  		usleep_range(1000, 10000);
> >>  		break;
> >>  
> >> @@ -1447,6 +1448,7 @@ static int qca_check_speeds(struct hci_uart *hu)
> >>  	case QCA_WCN6750:
> >>  	case QCA_WCN6855:
> >>  	case QCA_WCN7850:
> >> +	case QCA_QCA6698:
> >>  		if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
> >>  		    !qca_get_speed(hu, QCA_OPER_SPEED))
> >>  			return -EINVAL;
> >> @@ -1489,6 +1491,7 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
> >>  		case QCA_WCN6750:
> >>  		case QCA_WCN6855:
> >>  		case QCA_WCN7850:
> >> +		case QCA_QCA6698:
> >>  			hci_uart_set_flow_control(hu, true);
> >>  			break;
> >>  
> >> @@ -1523,6 +1526,7 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
> >>  		case QCA_WCN6750:
> >>  		case QCA_WCN6855:
> >>  		case QCA_WCN7850:
> >> +		case QCA_QCA6698:
> >>  			hci_uart_set_flow_control(hu, false);
> >>  			break;
> >>  
> >> @@ -1803,6 +1807,7 @@ static int qca_power_on(struct hci_dev *hdev)
> >>  	case QCA_WCN6855:
> >>  	case QCA_WCN7850:
> >>  	case QCA_QCA6390:
> >> +	case QCA_QCA6698:
> >>  		ret = qca_regulator_init(hu);
> >>  		break;
> >>  
> >> @@ -1878,6 +1883,10 @@ static int qca_setup(struct hci_uart *hu)
> >>  		soc_name = "qca2066";
> >>  		break;
> >>  
> >> +	case QCA_QCA6698:
> >> +		soc_name = "qca6698";
> >> +		break;
> >> +
> >>  	case QCA_WCN3988:
> >>  	case QCA_WCN3990:
> >>  	case QCA_WCN3991:
> >> @@ -1919,6 +1928,7 @@ static int qca_setup(struct hci_uart *hu)
> >>  	case QCA_WCN6750:
> >>  	case QCA_WCN6855:
> >>  	case QCA_WCN7850:
> >> +	case QCA_QCA6698:
> >>  		qcadev = serdev_device_get_drvdata(hu->serdev);
> >>  		if (qcadev->bdaddr_property_broken)
> >>  			set_bit(HCI_QUIRK_BDADDR_PROPERTY_BROKEN, &hdev->quirks);
> >> @@ -1952,6 +1962,7 @@ static int qca_setup(struct hci_uart *hu)
> >>  	case QCA_WCN6750:
> >>  	case QCA_WCN6855:
> >>  	case QCA_WCN7850:
> >> +	case QCA_QCA6698:
> >>  		break;
> >>  
> >>  	default:
> >> @@ -2089,6 +2100,20 @@ static const struct qca_device_data qca_soc_data_qca6390 __maybe_unused = {
> >>  	.num_vregs = 0,
> >>  };
> >>  
> >> +static const struct qca_device_data qca_soc_data_qca6698 __maybe_unused = {
> >> +	.soc_type = QCA_QCA6698,
> > 
> > No. It's the same as WCN6855. You don't need extra SoC type for it.
> > 
> >> +	.vregs = (struct qca_vreg []) {
> >> +		{ "vddio", 5000 },
> >> +		{ "vddbtcxmx", 126000 },
> >> +		{ "vddrfacmn", 12500 },
> >> +		{ "vddrfa0p8", 102000 },
> >> +		{ "vddrfa1p7", 302000 },
> >> +		{ "vddrfa1p2", 257000 },
> >> +	},
> >> +	.num_vregs = 6,
> >> +	.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
> >> +};
> >> +
> >>  static const struct qca_device_data qca_soc_data_wcn6750 __maybe_unused = {
> >>  	.soc_type = QCA_WCN6750,
> >>  	.vregs = (struct qca_vreg []) {
> >> @@ -2179,6 +2204,7 @@ static void qca_power_shutdown(struct hci_uart *hu)
> >>  
> >>  	case QCA_WCN6750:
> >>  	case QCA_WCN6855:
> >> +	case QCA_QCA6698:
> >>  		gpiod_set_value_cansleep(qcadev->bt_en, 0);
> >>  		msleep(100);
> >>  		qca_regulator_disable(qcadev);
> >> @@ -2333,6 +2359,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
> >>  	case QCA_WCN6855:
> >>  	case QCA_WCN7850:
> >>  	case QCA_QCA6390:
> >> +	case QCA_QCA6698:
> >>  		qcadev->bt_power = devm_kzalloc(&serdev->dev,
> >>  						sizeof(struct qca_power),
> >>  						GFP_KERNEL);
> >> @@ -2346,6 +2373,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
> >>  	switch (qcadev->btsoc_type) {
> >>  	case QCA_WCN6855:
> >>  	case QCA_WCN7850:
> >> +	case QCA_QCA6698:
> >>  		if (!device_property_present(&serdev->dev, "enable-gpios")) {
> >>  			/*
> >>  			 * Backward compatibility with old DT sources. If the
> >> @@ -2380,7 +2408,8 @@ static int qca_serdev_probe(struct serdev_device *serdev)
> >>  					       GPIOD_OUT_LOW);
> >>  		if (IS_ERR(qcadev->bt_en) &&
> >>  		    (data->soc_type == QCA_WCN6750 ||
> >> -		     data->soc_type == QCA_WCN6855)) {
> >> +		     data->soc_type == QCA_WCN6855 ||
> >> +		     data->soc_type == QCA_QCA6698)) {
> >>  			dev_err(&serdev->dev, "failed to acquire BT_EN gpio\n");
> >>  			return PTR_ERR(qcadev->bt_en);
> >>  		}
> >> @@ -2393,7 +2422,8 @@ static int qca_serdev_probe(struct serdev_device *serdev)
> >>  		if (IS_ERR(qcadev->sw_ctrl) &&
> >>  		    (data->soc_type == QCA_WCN6750 ||
> >>  		     data->soc_type == QCA_WCN6855 ||
> >> -		     data->soc_type == QCA_WCN7850)) {
> >> +		     data->soc_type == QCA_WCN7850 ||
> >> +		     data->soc_type == QCA_QCA6698)) {
> >>  			dev_err(&serdev->dev, "failed to acquire SW_CTRL gpio\n");
> >>  			return PTR_ERR(qcadev->sw_ctrl);
> >>  		}
> >> @@ -2475,6 +2505,7 @@ static void qca_serdev_remove(struct serdev_device *serdev)
> >>  	case QCA_WCN6750:
> >>  	case QCA_WCN6855:
> >>  	case QCA_WCN7850:
> >> +	case QCA_QCA6698:
> >>  		if (power->vregs_on)
> >>  			qca_power_shutdown(&qcadev->serdev_hu);
> >>  		break;
> >> @@ -2669,6 +2700,7 @@ static const struct of_device_id qca_bluetooth_of_match[] = {
> >>  	{ .compatible = "qcom,qca2066-bt", .data = &qca_soc_data_qca2066},
> >>  	{ .compatible = "qcom,qca6174-bt" },
> >>  	{ .compatible = "qcom,qca6390-bt", .data = &qca_soc_data_qca6390},
> >> +	{ .compatible = "qcom,qca6698-bt", .data = &qca_soc_data_qca6698},
> >>  	{ .compatible = "qcom,qca9377-bt" },
> >>  	{ .compatible = "qcom,wcn3988-bt", .data = &qca_soc_data_wcn3988},
> >>  	{ .compatible = "qcom,wcn3990-bt", .data = &qca_soc_data_wcn3990},
> >> -- 
> >> 2.25.1
> >>
> > 
> 

-- 
With best wishes
Dmitry




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [Linux for Sparc]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux