From 36f1768c449c1b3522fd71c5b32723d819c2a781 Mon Sep 17 00:00:00 2001 From: Brent Lu Date: Wed, 5 Jun 2024 18:49:00 +0800 Subject: [PATCH] ASoC: SOF: Intel: hda: add tplg quirk flag for BT audio offload Add an new quirk flag SND_SOC_ACPI_TPLG_INTEL_BT_OFFLOAD to fixup tplg file name with '-bt-sspX' suffix when the support of BT audio offload is found in NHLT table. SSP port mask of BT offload will be sent to machine driver to setup BE dai link with correct SSP port number. Signed-off-by: Brent Lu --- include/sound/soc-acpi.h | 8 ++++++ sound/soc/sof/intel/hda.c | 58 +++++++++++++++++++++++++++++++++++---- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index b6d301946244e6..f367bb7b7a87b3 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -73,6 +73,7 @@ static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) * @subsystem_rev: optional PCI SSID revision value * @subsystem_id_set: true if a value has been written to * subsystem_vendor and subsystem_device. + * @bt_link_mask: BT offload link enabled on the board */ struct snd_soc_acpi_mach_params { u32 acpi_ipc_irq_index; @@ -89,6 +90,7 @@ struct snd_soc_acpi_mach_params { unsigned short subsystem_device; unsigned short subsystem_rev; bool subsystem_id_set; + u32 bt_link_mask; }; /** @@ -165,6 +167,12 @@ struct snd_soc_acpi_link_adr { */ #define SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME BIT(4) +/* + * when set the BT offload name suffix '-bt' will be appended to topology file + * name if the feature is implemented in ACPI NHLT table + */ +#define SND_SOC_ACPI_TPLG_INTEL_BT_OFFLOAD BIT(5) + /** * snd_soc_acpi_mach: ACPI-based machine descriptor. Most of the fields are * related to the hardware, except for the firmware and topology file names. diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index b98b8c41dc0802..77d2cc52977a47 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -444,6 +444,10 @@ static int mclk_id_override = -1; module_param_named(mclk_id, mclk_id_override, int, 0444); MODULE_PARM_DESC(mclk_id, "SOF SSP mclk_id"); +static int bt_link_mask_override = 0x0; +module_param_named(bt_link_mask, bt_link_mask_override, int, 0444); +MODULE_PARM_DESC(bt_link_mask, "SOF BT offload link mask"); + static int hda_init(struct snd_sof_dev *sdev) { struct hda_bus *hbus; @@ -529,7 +533,7 @@ static int check_dmic_num(struct snd_sof_dev *sdev) return dmic_num; } -static int check_nhlt_ssp_mask(struct snd_sof_dev *sdev) +static int check_nhlt_ssp_mask(struct snd_sof_dev *sdev, u8 device_type) { struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; struct nhlt_acpi_table *nhlt; @@ -540,9 +544,10 @@ static int check_nhlt_ssp_mask(struct snd_sof_dev *sdev) return ssp_mask; if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_SSP)) { - ssp_mask = intel_nhlt_ssp_endpoint_mask(nhlt, NHLT_DEVICE_I2S); + ssp_mask = intel_nhlt_ssp_endpoint_mask(nhlt, device_type); if (ssp_mask) - dev_info(sdev->dev, "NHLT_DEVICE_I2S detected, ssp_mask %#x\n", ssp_mask); + dev_info(sdev->dev, "NHLT device %d detected, ssp_mask %#x\n", + device_type, ssp_mask); } return ssp_mask; @@ -1201,6 +1206,7 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) u32 interface_mask = hda_get_interface_mask(sdev); struct snd_sof_pdata *sof_pdata = sdev->pdata; const struct sof_dev_desc *desc = sof_pdata->desc; + const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata); struct hdac_bus *bus = sof_to_bus(sdev); struct snd_soc_acpi_mach *mach = NULL; enum snd_soc_acpi_intel_codec codec_type, amp_type; @@ -1209,6 +1215,8 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) bool amp_name_valid; bool i2s_mach_found = false; bool sdw_mach_found = false; + int ssp_num; + /* Try I2S or DMIC if it is supported */ if (interface_mask & (BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC))) { @@ -1302,19 +1310,57 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) sof_pdata->tplg_filename = tplg_filename; } + /* report BT offload link mask to machine driver */ + mach->mach_params.bt_link_mask = check_nhlt_ssp_mask(sdev, NHLT_DEVICE_BT); + + /* allow for module parameter override */ + if (bt_link_mask_override != 0x00) { + dev_dbg(sdev->dev, + "overriding bt link mask detected in NHLT tables 0x%x by kernel param 0x%x\n", + mach->mach_params.bt_link_mask, + bt_link_mask_override); + mach->mach_params.bt_link_mask = bt_link_mask_override; + } + + if (tplg_fixup && + mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_BT_OFFLOAD && + mach->mach_params.bt_link_mask) { + if (hweight_long(mach->mach_params.bt_link_mask) > 1) { + dev_warn(sdev->dev, "invalid bt link mask 0x%x found\n", + mach->mach_params.bt_link_mask); + return NULL; + } + + /* fls returns 1-based results, SSPs indices are 0-based */ + ssp_num = fls(mach->mach_params.bt_link_mask) - 1; + + if (ssp_num >= chip->ssp_count) { + dev_err(sdev->dev, "invalid SSP %d, max on this platform is %d\n", + ssp_num, chip->ssp_count); + return NULL; + } + + tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, + "%s-bt-ssp%d", + sof_pdata->tplg_filename, + ssp_num); + if (!tplg_filename) + return NULL; + + sof_pdata->tplg_filename = tplg_filename; + } + if (mach->link_mask) { mach->mach_params.links = mach->links; mach->mach_params.link_mask = mach->link_mask; } /* report SSP link mask to machine driver */ - mach->mach_params.i2s_link_mask = check_nhlt_ssp_mask(sdev); + mach->mach_params.i2s_link_mask = check_nhlt_ssp_mask(sdev, NHLT_DEVICE_I2S); if (tplg_fixup && mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER && mach->mach_params.i2s_link_mask) { - const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata); - int ssp_num; int mclk_mask; if (hweight_long(mach->mach_params.i2s_link_mask) > 1 &&