-
Notifications
You must be signed in to change notification settings - Fork 150
ASoC: Intel: add I2S function topology support #5657
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
08d9a6f
454ee3b
067f57c
fa4f3e1
3ea688a
5dacb58
2a4bfb7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,10 @@ enum tplg_device_id { | |
| TPLG_DEVICE_SDCA_MIC, | ||
| TPLG_DEVICE_INTEL_PCH_DMIC, | ||
| TPLG_DEVICE_HDMI, | ||
| TPLG_DEVICE_SSP_JACK, | ||
| TPLG_DEVICE_SSP_AMP, | ||
| TPLG_DEVICE_SSP_BT, | ||
| TPLG_DEVICE_SSP_HDMI_IN, | ||
| TPLG_DEVICE_LOOPBACK_VIRTUAL, | ||
| TPLG_DEVICE_MAX | ||
| }; | ||
|
|
@@ -28,6 +32,138 @@ enum tplg_device_id { | |
|
|
||
| #define SOF_INTEL_PLATFORM_NAME_MAX 4 | ||
|
|
||
| static int get_platform_name(struct snd_soc_card *card, | ||
| const struct snd_soc_acpi_mach *mach, char *platform) | ||
| { | ||
| int ret; | ||
|
|
||
| ret = sscanf(mach->sof_tplg_filename, "sof-%3s-*.tplg", platform); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @bardliao valid ?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, the 'tplg' suffix will be added in run time. I replied to Copilot, but it always raises the same comment whenever I updated the PR. |
||
| if (ret != 1) { | ||
| dev_err(card->dev, "Invalid platform name of tplg %s\n", | ||
| mach->sof_tplg_filename); | ||
| return -EINVAL; | ||
| } | ||
|
bardliao marked this conversation as resolved.
bardliao marked this conversation as resolved.
|
||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| static bool tplg_files_exist(struct device *dev, const char *tplg_files) | ||
| { | ||
| const struct firmware *fw; | ||
| int ret; | ||
|
|
||
| ret = firmware_request_nowarn(&fw, tplg_files, dev); | ||
| if (!ret) { | ||
| release_firmware(fw); | ||
| return true; | ||
| } | ||
|
|
||
| dev_warn(dev, | ||
| "Failed to open topology file: %s, you might need to\n", | ||
| tplg_files); | ||
| dev_warn(dev, | ||
| "download it from https://github.com/thesofproject/sof-bin/\n"); | ||
| return false; | ||
|
|
||
| } | ||
|
|
||
| static char *get_tplg_filename(struct device *dev, const char *prefix, | ||
| const char *platform, const char *tplg_dev_name, | ||
| int dai_link_id, int tplg_dev) | ||
| { | ||
| char *filename = NULL; | ||
|
|
||
| /* | ||
|
ranj063 marked this conversation as resolved.
|
||
| * The tplg file naming rule is sof-<platform>-<function>-id<BE id number>.tplg | ||
| * where <platform> is required for functions that depend on NHLT blobs (e.g. DMIC/SSP) | ||
| * as the nhlt blob is platform dependent. | ||
| */ | ||
| switch (tplg_dev) { | ||
| case TPLG_DEVICE_INTEL_PCH_DMIC: | ||
| case TPLG_DEVICE_SSP_JACK: | ||
| case TPLG_DEVICE_SSP_AMP: | ||
| case TPLG_DEVICE_SSP_BT: | ||
| case TPLG_DEVICE_SSP_HDMI_IN: | ||
|
ranj063 marked this conversation as resolved.
|
||
| filename = devm_kasprintf(dev, GFP_KERNEL, "%s/sof-%s-%s-id%d.tplg", | ||
| prefix, platform, tplg_dev_name, dai_link_id); | ||
| break; | ||
| default: | ||
| filename = devm_kasprintf(dev, GFP_KERNEL, "%s/sof-%s-id%d.tplg", | ||
| prefix, tplg_dev_name, dai_link_id); | ||
| break; | ||
| } | ||
|
|
||
| return filename; | ||
| } | ||
|
|
||
| static int get_dmic_tplg_dev(struct device *dev, int dmic_num, | ||
| int *tplg_dev, char **tplg_dev_name) | ||
| { | ||
| switch (dmic_num) { | ||
| case 2: | ||
| *tplg_dev_name = "dmic-2ch"; | ||
| break; | ||
| case 4: | ||
| *tplg_dev_name = "dmic-4ch"; | ||
| break; | ||
| default: | ||
| dev_warn(dev, | ||
| "unsupported number of dmics: %d\n", | ||
| dmic_num); | ||
| return -EINVAL; | ||
| } | ||
| *tplg_dev = TPLG_DEVICE_INTEL_PCH_DMIC; | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| static int get_ssp_tplg_dev(struct device *dev, struct snd_soc_dai_link *dai_link, | ||
| u16 *hdmi_in_mask, int *tplg_dev, char **tplg_dev_name) | ||
| { | ||
| unsigned int ssp_port; | ||
|
|
||
| if (sscanf(dai_link->name, "SSP%d", &ssp_port) != 1) { | ||
| dev_err(dev, "Can't get SSP port from dai_link->name %s\n", dai_link->name); | ||
| return -EINVAL; | ||
| } | ||
| if (strstr(dai_link->name, "Codec")) { | ||
| /* | ||
| * Assume DAI link 0 is jack which is true in all existing | ||
| * machine drivers | ||
| */ | ||
| if (dai_link->id == 0) { | ||
| *tplg_dev = TPLG_DEVICE_SSP_JACK; | ||
| *tplg_dev_name = devm_kasprintf(dev, GFP_KERNEL, | ||
| "ssp%d-jack", ssp_port); | ||
| } else { | ||
| *tplg_dev = TPLG_DEVICE_SSP_AMP; | ||
| *tplg_dev_name = devm_kasprintf(dev, GFP_KERNEL, | ||
| "ssp%d-amp", ssp_port); | ||
| } | ||
| } else if (strstr(dai_link->name, "BT")) { | ||
| *tplg_dev = TPLG_DEVICE_SSP_BT; | ||
| *tplg_dev_name = devm_kasprintf(dev, GFP_KERNEL, | ||
| "ssp%d-bt", ssp_port); | ||
| } else if (strstr(dai_link->name, "HDMI")) { | ||
|
bardliao marked this conversation as resolved.
|
||
| *hdmi_in_mask |= BIT(ssp_port); | ||
| /* The number of HDMI in dai link is always 2 right now */ | ||
| if (hweight16(*hdmi_in_mask) != 2) | ||
| return -EINVAL; | ||
|
|
||
| *tplg_dev = TPLG_DEVICE_SSP_HDMI_IN; | ||
| *tplg_dev_name = devm_kasprintf(dev, GFP_KERNEL, | ||
| "ssp%x-hdmiin", *hdmi_in_mask); | ||
| } else { | ||
| dev_warn(dev, | ||
| "unsupported SSP link %s\n", dai_link->name); | ||
| return -EINVAL; | ||
| } | ||
|
bardliao marked this conversation as resolved.
|
||
| if (!*tplg_dev_name) | ||
| return -ENOMEM; | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_mach *mach, | ||
| const char *prefix, const char ***tplg_files, bool best_effort) | ||
| { | ||
|
|
@@ -38,20 +174,18 @@ int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_ | |
| */ | ||
| struct snd_soc_acpi_mach_params mach_params = card_mach->mach_params; | ||
| struct snd_soc_dai_link *dai_link; | ||
| const struct firmware *fw; | ||
| char platform[SOF_INTEL_PLATFORM_NAME_MAX]; | ||
| unsigned long tplg_mask = 0; | ||
| u16 hdmi_in_mask = 0; | ||
| int tplg_num = 0; | ||
| char *tplg_file; | ||
| int tplg_dev; | ||
| int ret; | ||
| int i; | ||
|
|
||
| ret = sscanf(mach->sof_tplg_filename, "sof-%3s-*.tplg", platform); | ||
| if (ret != 1) { | ||
| dev_err(card->dev, "Invalid platform name %s of tplg %s\n", | ||
| platform, mach->sof_tplg_filename); | ||
| return -EINVAL; | ||
| } | ||
| ret = get_platform_name(card, mach, platform); | ||
| if (ret < 0) | ||
| return ret; | ||
|
|
||
| for_each_card_prelinks(card, i, dai_link) { | ||
| char *tplg_dev_name; | ||
|
|
@@ -70,23 +204,16 @@ int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_ | |
| tplg_dev = TPLG_DEVICE_SDCA_MIC; | ||
| tplg_dev_name = "sdca-mic"; | ||
| } else if (strstr(dai_link->name, "dmic")) { | ||
| switch (mach_params.dmic_num) { | ||
| case 2: | ||
| tplg_dev_name = "dmic-2ch"; | ||
| break; | ||
| case 4: | ||
| tplg_dev_name = "dmic-4ch"; | ||
| break; | ||
| default: | ||
| dev_warn(card->dev, | ||
| "unsupported number of dmics: %d\n", | ||
| mach_params.dmic_num); | ||
| if (get_dmic_tplg_dev(card->dev, mach_params.dmic_num, | ||
| &tplg_dev, &tplg_dev_name) < 0) | ||
| continue; | ||
| } | ||
| tplg_dev = TPLG_DEVICE_INTEL_PCH_DMIC; | ||
| } else if (strstr(dai_link->name, "iDisp")) { | ||
| tplg_dev = TPLG_DEVICE_HDMI; | ||
| tplg_dev_name = "hdmi-pcm5"; | ||
| } else if (strstr(dai_link->name, "SSP")) { | ||
|
ranj063 marked this conversation as resolved.
ranj063 marked this conversation as resolved.
|
||
| if (get_ssp_tplg_dev(card->dev, dai_link, &hdmi_in_mask, | ||
| &tplg_dev, &tplg_dev_name) < 0) | ||
| continue; | ||
| } else if (strstr(dai_link->name, "Loopback_Virtual")) { | ||
| tplg_dev = TPLG_DEVICE_LOOPBACK_VIRTUAL; | ||
| /* | ||
|
|
@@ -109,49 +236,100 @@ int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_ | |
| if (tplg_mask & BIT(tplg_dev)) | ||
| continue; | ||
|
|
||
| tplg_mask |= BIT(tplg_dev); | ||
| tplg_file = get_tplg_filename(card->dev, prefix, platform, tplg_dev_name, | ||
| dai_link->id, tplg_dev); | ||
| if (!tplg_file) | ||
| return -ENOMEM; | ||
|
|
||
| /* | ||
| * The tplg file naming rule is sof-<platform>-<function>-id<BE id number>.tplg | ||
| * where <platform> is only required for the DMIC function as the nhlt blob | ||
| * is platform dependent. | ||
| */ | ||
| switch (tplg_dev) { | ||
| case TPLG_DEVICE_INTEL_PCH_DMIC: | ||
| (*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL, | ||
| "%s/sof-%s-%s-id%d.tplg", | ||
| prefix, platform, | ||
| tplg_dev_name, dai_link->id); | ||
| break; | ||
| default: | ||
| (*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL, | ||
| "%s/sof-%s-id%d.tplg", | ||
| prefix, tplg_dev_name, | ||
| dai_link->id); | ||
| break; | ||
| /* Check presence of sub-topologies */ | ||
| if (!tplg_files_exist(card->dev, tplg_file)) { | ||
| devm_kfree(card->dev, tplg_file); | ||
| if (best_effort) | ||
| continue; | ||
|
|
||
| return 0; | ||
| } | ||
| if (!(*tplg_files)[tplg_num]) | ||
| return -ENOMEM; | ||
|
|
||
| tplg_mask |= BIT(tplg_dev); | ||
|
|
||
| (*tplg_files)[tplg_num] = tplg_file; | ||
| tplg_num++; | ||
| } | ||
|
|
||
| dev_dbg(card->dev, "tplg_mask %#lx tplg_num %d\n", tplg_mask, tplg_num); | ||
|
|
||
| /* Check presence of sub-topologies */ | ||
| for (i = 0; i < tplg_num; i++) { | ||
| ret = firmware_request_nowarn(&fw, (*tplg_files)[i], card->dev); | ||
| if (!ret) { | ||
| release_firmware(fw); | ||
| return tplg_num; | ||
| } | ||
| EXPORT_SYMBOL_GPL(sof_sdw_get_tplg_files); | ||
|
|
||
| int sof_i2s_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_mach *mach, | ||
| const char *prefix, const char ***tplg_files, bool best_effort) | ||
|
ujfalusi marked this conversation as resolved.
|
||
| { | ||
| struct snd_soc_acpi_mach_params mach_params = mach->mach_params; | ||
| struct snd_soc_dai_link *dai_link; | ||
|
Comment on lines
+265
to
+269
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sof_sdw_get_tplg_files() get the mach params from the card because it will modify in the machine driver. But the |
||
| char platform[SOF_INTEL_PLATFORM_NAME_MAX]; | ||
| unsigned long tplg_mask = 0; | ||
| u16 hdmi_in_mask = 0; | ||
| int tplg_num = 0; | ||
| char *tplg_file; | ||
| int tplg_dev; | ||
| int ret; | ||
| int i; | ||
|
|
||
| ret = get_platform_name(card, mach, platform); | ||
| if (ret < 0) | ||
| return ret; | ||
|
|
||
| for_each_card_prelinks(card, i, dai_link) { | ||
| char *tplg_dev_name; | ||
|
|
||
| dev_dbg(card->dev, "dai_link %s id %d\n", dai_link->name, dai_link->id); | ||
| if (strstr(dai_link->name, "SSP")) { | ||
| if (get_ssp_tplg_dev(card->dev, dai_link, &hdmi_in_mask, | ||
| &tplg_dev, &tplg_dev_name) < 0) | ||
| continue; | ||
| } else if (strstr(dai_link->name, "dmic")) { | ||
| if (get_dmic_tplg_dev(card->dev, mach_params.dmic_num, | ||
| &tplg_dev, &tplg_dev_name) < 0) | ||
| continue; | ||
| } else if (strstr(dai_link->name, "iDisp")) { | ||
| tplg_dev = TPLG_DEVICE_HDMI; | ||
| tplg_dev_name = "hdmi-pcm5"; | ||
| } else { | ||
| dev_warn(card->dev, | ||
| "Failed to open topology file: %s, you might need to\n", | ||
| (*tplg_files)[i]); | ||
| dev_warn(card->dev, | ||
| "download it from https://github.com/thesofproject/sof-bin/\n"); | ||
| /* The dai link is not supported by separated tplg yet */ | ||
| dev_dbg(card->dev, | ||
| "dai_link %s is not supported by separated tplg yet\n", | ||
| dai_link->name); | ||
| if (best_effort) | ||
| continue; | ||
|
|
||
| return 0; | ||
| } | ||
| if (tplg_mask & BIT(tplg_dev)) | ||
| continue; | ||
|
|
||
| tplg_file = get_tplg_filename(card->dev, prefix, platform, tplg_dev_name, | ||
| dai_link->id, tplg_dev); | ||
| if (!tplg_file) | ||
| return -ENOMEM; | ||
|
|
||
| /* Check presence of sub-topologies */ | ||
| if (!tplg_files_exist(card->dev, tplg_file)) { | ||
| devm_kfree(card->dev, tplg_file); | ||
| if (best_effort) | ||
| continue; | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| tplg_mask |= BIT(tplg_dev); | ||
|
|
||
| (*tplg_files)[tplg_num] = tplg_file; | ||
| tplg_num++; | ||
| } | ||
|
|
||
| dev_dbg(card->dev, "tplg_mask %#lx tplg_num %d\n", tplg_mask, tplg_num); | ||
|
|
||
| return tplg_num; | ||
| } | ||
| EXPORT_SYMBOL_GPL(sof_sdw_get_tplg_files); | ||
| EXPORT_SYMBOL_GPL(sof_i2s_get_tplg_files); | ||
Uh oh!
There was an error while loading. Please reload this page.