diff options
Diffstat (limited to 'sound/soc/sof/intel/hda.c')
-rw-r--r-- | sound/soc/sof/intel/hda.c | 299 |
1 files changed, 127 insertions, 172 deletions
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index daf364f773dd..70fc08c8fc99 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; +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; @@ -511,6 +515,8 @@ static int check_dmic_num(struct snd_sof_dev *sdev) if (nhlt) dmic_num = intel_nhlt_get_dmic_geo(sdev->dev, nhlt); + dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num); + /* allow for module parameter override */ if (dmic_num_override != -1) { dev_dbg(sdev->dev, @@ -527,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; @@ -538,9 +544,11 @@ 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 %s(%d) detected, ssp_mask %#x\n", + device_type == NHLT_DEVICE_BT ? "BT" : "I2S", + device_type, ssp_mask); } return ssp_mask; @@ -558,82 +566,6 @@ static int check_nhlt_ssp_mclk_mask(struct snd_sof_dev *sdev, int ssp_num) return intel_nhlt_ssp_mclk_mask(nhlt, ssp_num); } -#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) - -static const char *fixup_tplg_name(struct snd_sof_dev *sdev, - const char *sof_tplg_filename, - const char *idisp_str, - const char *dmic_str) -{ - const char *tplg_filename = NULL; - char *filename, *tmp; - const char *split_ext; - - filename = kstrdup(sof_tplg_filename, GFP_KERNEL); - if (!filename) - return NULL; - - /* this assumes a .tplg extension */ - tmp = filename; - split_ext = strsep(&tmp, "."); - if (split_ext) - tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, - "%s%s%s.tplg", - split_ext, idisp_str, dmic_str); - kfree(filename); - - return tplg_filename; -} - -static int dmic_detect_topology_fixup(struct snd_sof_dev *sdev, - const char **tplg_filename, - const char *idisp_str, - int *dmic_found, - bool tplg_fixup) -{ - const char *dmic_str; - int dmic_num; - - /* first check for DMICs (using NHLT or module parameter) */ - dmic_num = check_dmic_num(sdev); - - switch (dmic_num) { - case 1: - dmic_str = "-1ch"; - break; - case 2: - dmic_str = "-2ch"; - break; - case 3: - dmic_str = "-3ch"; - break; - case 4: - dmic_str = "-4ch"; - break; - default: - dmic_num = 0; - dmic_str = ""; - break; - } - - if (tplg_fixup) { - const char *default_tplg_filename = *tplg_filename; - const char *fixed_tplg_filename; - - fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename, - idisp_str, dmic_str); - if (!fixed_tplg_filename) - return -ENOMEM; - *tplg_filename = fixed_tplg_filename; - } - - dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num); - *dmic_found = dmic_num; - - return 0; -} -#endif - static int hda_init_caps(struct snd_sof_dev *sdev) { u32 interface_mask = hda_get_interface_mask(sdev); @@ -1045,10 +977,7 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev, struct snd_soc_acpi_mach *hda_mach; struct snd_sof_pdata *pdata = sdev->pdata; const char *tplg_filename; - const char *idisp_str; - int dmic_num = 0; int codec_num = 0; - int ret; int i; /* codec detection */ @@ -1071,33 +1000,30 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev, * - one external HDAudio codec */ if (!*mach && codec_num <= 2) { - bool tplg_fixup; + bool tplg_fixup = false; hda_mach = snd_soc_acpi_intel_hda_machines; dev_info(bus->dev, "using HDA machine driver %s now\n", hda_mach->drv_name); - if (codec_num == 1 && HDA_IDISP_CODEC(bus->codec_mask)) - idisp_str = "-idisp"; - else - idisp_str = ""; - - /* topology: use the info from hda_machines */ - if (pdata->tplg_filename) { - tplg_fixup = false; - tplg_filename = pdata->tplg_filename; - } else { + /* + * topology: use the info from hda_machines since tplg file name + * is not overwritten + */ + if (!pdata->tplg_filename) tplg_fixup = true; - tplg_filename = hda_mach->sof_tplg_filename; - } - ret = dmic_detect_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num, - tplg_fixup); - if (ret < 0) - return; - hda_mach->mach_params.dmic_num = dmic_num; - pdata->tplg_filename = tplg_filename; + if (tplg_fixup && + codec_num == 1 && HDA_IDISP_CODEC(bus->codec_mask)) { + tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, + "%s-idisp", + hda_mach->sof_tplg_filename); + if (!tplg_filename) + return; + + hda_mach->sof_tplg_filename = tplg_filename; + } if (codec_num == 2 || (codec_num == 1 && !HDA_IDISP_CODEC(bus->codec_mask))) { @@ -1125,7 +1051,6 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev, if (*mach) { mach_params = &(*mach)->mach_params; mach_params->codec_mask = bus->codec_mask; - mach_params->common_hdmi_codec_drv = true; } } #else @@ -1205,45 +1130,10 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev break; } if (mach && mach->link_mask) { - int dmic_num = 0; - bool tplg_fixup; - const char *tplg_filename; - mach->mach_params.links = mach->links; mach->mach_params.link_mask = mach->link_mask; mach->mach_params.platform = dev_name(sdev->dev); - if (pdata->tplg_filename) { - tplg_fixup = false; - } else { - tplg_fixup = true; - tplg_filename = mach->sof_tplg_filename; - } - - /* - * DMICs use up to 4 pins and are typically pin-muxed with SoundWire - * link 2 and 3, or link 1 and 2, thus we only try to enable dmics - * if all conditions are true: - * a) 2 or fewer links are used by SoundWire - * b) the NHLT table reports the presence of microphones - */ - if (hweight_long(mach->link_mask) <= 2) { - int ret; - - ret = dmic_detect_topology_fixup(sdev, &tplg_filename, "", - &dmic_num, tplg_fixup); - if (ret < 0) - return NULL; - } - if (tplg_fixup) - pdata->tplg_filename = tplg_filename; - mach->mach_params.dmic_num = dmic_num; - - dev_dbg(sdev->dev, - "SoundWire machine driver %s topology %s\n", - mach->drv_name, - pdata->tplg_filename); - return mach; } @@ -1300,6 +1190,19 @@ static int check_tplg_quirk_mask(struct snd_soc_acpi_mach *mach) return 0; } +static char *remove_file_ext(const char *tplg_filename) +{ + char *filename, *tmp; + + filename = kstrdup(tplg_filename, GFP_KERNEL); + if (!filename) + return NULL; + + /* remove file extension if exist */ + tmp = filename; + return strsep(&tmp, "."); +} + struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) { u32 interface_mask = hda_get_interface_mask(sdev); @@ -1307,24 +1210,79 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) const struct sof_dev_desc *desc = sof_pdata->desc; struct hdac_bus *bus = sof_to_bus(sdev); struct snd_soc_acpi_mach *mach = NULL; - enum snd_soc_acpi_intel_codec codec_type; + enum snd_soc_acpi_intel_codec codec_type, amp_type; const char *tplg_filename; const char *tplg_suffix; + bool amp_name_valid; + bool i2s_mach_found = false; + bool sdw_mach_found = false; /* Try I2S or DMIC if it is supported */ - if (interface_mask & (BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC))) + if (interface_mask & (BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC))) { mach = snd_soc_acpi_find_machine(desc->machines); + if (mach) + i2s_mach_found = true; + } + /* + * If I2S fails and no external HDaudio codec is detected, + * try SoundWire if it is supported + */ + if (!mach && !HDA_EXT_CODEC(bus->codec_mask) && + (interface_mask & BIT(SOF_DAI_INTEL_ALH))) { + mach = hda_sdw_machine_select(sdev); + if (mach) + sdw_mach_found = true; + } + + /* + * Choose HDA generic machine driver if mach is NULL. + * Otherwise, set certain mach params. + */ + hda_generic_machine_select(sdev, &mach); + if (!mach) { + dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n"); + return NULL; + } + + /* report BT offload link mask to machine driver */ + mach->mach_params.bt_link_mask = check_nhlt_ssp_mask(sdev, NHLT_DEVICE_BT); + + dev_info(sdev->dev, "BT link detected in NHLT tables: %#x\n", + mach->mach_params.bt_link_mask); + + /* allow for module parameter override */ + if (bt_link_mask_override) { + dev_dbg(sdev->dev, "overriding BT link detected in NHLT tables %#x by kernel param %#x\n", + mach->mach_params.bt_link_mask, bt_link_mask_override); + mach->mach_params.bt_link_mask = bt_link_mask_override; + } + + if (hweight_long(mach->mach_params.bt_link_mask) > 1) { + dev_warn(sdev->dev, "invalid BT link mask %#x found, reset the mask\n", + mach->mach_params.bt_link_mask); + mach->mach_params.bt_link_mask = 0; + } + + /* + * Fixup tplg file name by appending dmic num, ssp num, codec/amplifier + * name string if quirk flag is set. + */ if (mach) { - bool add_extension = false; bool tplg_fixup = false; + bool dmic_fixup = false; /* * If tplg file name is overridden, use it instead of * the one set in mach table */ if (!sof_pdata->tplg_filename) { - sof_pdata->tplg_filename = mach->sof_tplg_filename; + /* remove file extension if it exists */ + tplg_filename = remove_file_ext(mach->sof_tplg_filename); + if (!tplg_filename) + return NULL; + + sof_pdata->tplg_filename = tplg_filename; tplg_fixup = true; } @@ -1342,20 +1300,36 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) /* report to machine driver if any DMICs are found */ mach->mach_params.dmic_num = check_dmic_num(sdev); + if (sdw_mach_found) { + /* + * DMICs use up to 4 pins and are typically pin-muxed with SoundWire + * link 2 and 3, or link 1 and 2, thus we only try to enable dmics + * if all conditions are true: + * a) 2 or fewer links are used by SoundWire + * b) the NHLT table reports the presence of microphones + */ + if (hweight_long(mach->link_mask) <= 2) + dmic_fixup = true; + else + mach->mach_params.dmic_num = 0; + } else { + if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER) + dmic_fixup = true; + } + if (tplg_fixup && - mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER && + dmic_fixup && mach->mach_params.dmic_num) { tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, "%s%s%d%s", sof_pdata->tplg_filename, - "-dmic", + i2s_mach_found ? "-dmic" : "-", mach->mach_params.dmic_num, "ch"); if (!tplg_filename) return NULL; sof_pdata->tplg_filename = tplg_filename; - add_extension = true; } if (mach->link_mask) { @@ -1364,7 +1338,7 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) } /* 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 && @@ -1395,7 +1369,6 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) return NULL; sof_pdata->tplg_filename = tplg_filename; - add_extension = true; mclk_mask = check_nhlt_ssp_mclk_mask(sdev, ssp_num); @@ -1413,15 +1386,16 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) } } - codec_type = snd_soc_acpi_intel_detect_amp_type(sdev->dev); + amp_type = snd_soc_acpi_intel_detect_amp_type(sdev->dev); + codec_type = snd_soc_acpi_intel_detect_codec_type(sdev->dev); + amp_name_valid = amp_type != CODEC_NONE && amp_type != codec_type; - if (tplg_fixup && - mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_AMP_NAME && - codec_type != CODEC_NONE) { - tplg_suffix = snd_soc_acpi_intel_get_amp_tplg_suffix(codec_type); + if (tplg_fixup && amp_name_valid && + mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_AMP_NAME) { + tplg_suffix = snd_soc_acpi_intel_get_amp_tplg_suffix(amp_type); if (!tplg_suffix) { dev_err(sdev->dev, "no tplg suffix found, amp %d\n", - codec_type); + amp_type); return NULL; } @@ -1433,10 +1407,8 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) return NULL; sof_pdata->tplg_filename = tplg_filename; - add_extension = true; } - codec_type = snd_soc_acpi_intel_detect_codec_type(sdev->dev); if (tplg_fixup && mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME && @@ -1456,10 +1428,9 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) return NULL; sof_pdata->tplg_filename = tplg_filename; - add_extension = true; } - if (tplg_fixup && add_extension) { + if (tplg_fixup) { tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, "%s%s", sof_pdata->tplg_filename, @@ -1478,22 +1449,6 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) } } - /* - * If I2S fails and no external HDaudio codec is detected, - * try SoundWire if it is supported - */ - if (!mach && !HDA_EXT_CODEC(bus->codec_mask) && - (interface_mask & BIT(SOF_DAI_INTEL_ALH))) - mach = hda_sdw_machine_select(sdev); - - /* - * Choose HDA generic machine driver if mach is NULL. - * Otherwise, set certain mach params. - */ - hda_generic_machine_select(sdev, &mach); - if (!mach) - dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n"); - return mach; } |