-
Notifications
You must be signed in to change notification settings - Fork 140
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
base: topic/sof-dev
Are you sure you want to change the base?
Changes from all commits
77371f2
a0fbb5f
03f7694
0cd2c08
0637a33
1af3d92
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_MAX | ||
| }; | ||
|
|
||
|
|
@@ -27,25 +31,88 @@ 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); | ||
| if (ret != 1) { | ||
| dev_err(card->dev, "Invalid platform name %s of tplg %s\n", | ||
| platform, mach->sof_tplg_filename); | ||
| return -EINVAL; | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| static bool all_tplg_files_exist(struct device *dev, const char ***tplg_files, int tplg_num) | ||
| { | ||
| const struct firmware *fw; | ||
| int ret; | ||
| int i; | ||
|
|
||
| for (i = 0; i < tplg_num; i++) { | ||
| ret = firmware_request_nowarn(&fw, (*tplg_files)[i], dev); | ||
| if (!ret) { | ||
| release_firmware(fw); | ||
| } else { | ||
| dev_warn(dev, | ||
| "Failed to open topology file: %s, you might need to\n", | ||
| (*tplg_files)[i]); | ||
| dev_warn(dev, | ||
| "download it from https://github.com/thesofproject/sof-bin/\n"); | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| 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; | ||
| /* | ||
| * The tplg file naming rule is sof-<platform>-<function>-id<BE id number>.tplg | ||
| * where <platform> is only required for the devices that need NHLT blob like DMIC | ||
| * 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: | ||
| 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; | ||
| } | ||
|
|
||
| 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) | ||
| { | ||
| struct snd_soc_acpi_mach_params mach_params = 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; | ||
| 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; | ||
|
|
@@ -81,7 +148,45 @@ int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_ | |
| } else if (strstr(dai_link->name, "iDisp")) { | ||
| tplg_dev = TPLG_DEVICE_HDMI; | ||
| tplg_dev_name = "hdmi-pcm5"; | ||
| } else if (strstr(dai_link->name, "SSP")) { | ||
| unsigned int ssp_port; | ||
|
|
||
| if (sscanf(dai_link->name, "SSP%d", &ssp_port) != 1) { | ||
| dev_err(card->dev, "Invalid SSP port %d\n", ssp_port); | ||
| return -EINVAL; | ||
| } | ||
| if (strstr(dai_link->name, "Codec")) { | ||
| /* | ||
| * Assume DAI link 0 is jack which is true in all existing | ||
| * machine driver | ||
| */ | ||
| if (dai_link->id == 0) { | ||
| tplg_dev = TPLG_DEVICE_SSP_JACK; | ||
| tplg_dev_name = devm_kasprintf(card->dev, GFP_KERNEL, | ||
| "ssp%d-jack", ssp_port); | ||
| } else { | ||
| tplg_dev = TPLG_DEVICE_SSP_AMP; | ||
| tplg_dev_name = devm_kasprintf(card->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(card->dev, GFP_KERNEL, | ||
| "ssp%d-bt", ssp_port); | ||
| } else if (strstr(dai_link->name, "HDMI")) { | ||
| hdmi_in_mask |= BIT(ssp_port); | ||
| /* The number of HDMI in dai link is always 2 right now */ | ||
| if (hweight16(hdmi_in_mask) != 2) | ||
| continue; | ||
|
|
||
| tplg_dev = TPLG_DEVICE_SSP_HDMI_IN; | ||
| tplg_dev_name = devm_kasprintf(card->dev, GFP_KERNEL, | ||
| "ssp%x-hdmiin", hdmi_in_mask); | ||
| } else { | ||
| dev_warn(card->dev, | ||
| "unsupported SSP link %s\n", dai_link->name); | ||
| continue; | ||
| } | ||
| } else { | ||
| /* The dai link is not supported by separated tplg yet */ | ||
| dev_dbg(card->dev, | ||
|
|
@@ -97,25 +202,9 @@ int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_ | |
|
|
||
| tplg_mask |= BIT(tplg_dev); | ||
|
|
||
| /* | ||
| * 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; | ||
| } | ||
| (*tplg_files)[tplg_num] = get_tplg_filename(card->dev, prefix, platform, | ||
| tplg_dev_name, dai_link->id, | ||
| tplg_dev); | ||
| if (!(*tplg_files)[tplg_num]) | ||
| return -ENOMEM; | ||
| tplg_num++; | ||
|
|
@@ -124,20 +213,122 @@ int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_ | |
| 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); | ||
| if (all_tplg_files_exist(card->dev, tplg_files, tplg_num)) | ||
| return tplg_num; | ||
|
|
||
| /* return 0 to use monolithic topology */ | ||
| return 0; | ||
| } | ||
| 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) | ||
|
Collaborator
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. do you plan to support the best_effort with SSP machines?
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. Yes, sure |
||
| { | ||
| struct snd_soc_acpi_mach_params mach_params = mach->mach_params; | ||
| struct snd_soc_dai_link *dai_link; | ||
| char platform[SOF_INTEL_PLATFORM_NAME_MAX]; | ||
| unsigned long tplg_mask = 0; | ||
| u16 hdmi_in_mask = 0; | ||
| int tplg_num = 0; | ||
| 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")) { | ||
| unsigned int ssp_port; | ||
|
|
||
| if (sscanf(dai_link->name, "SSP%d", &ssp_port) != 1) { | ||
| dev_err(card->dev, "Invalid SSP port %d\n", ssp_port); | ||
| return -EINVAL; | ||
| } | ||
| if (strstr(dai_link->name, "Codec")) { | ||
| /* | ||
| * Assume DAI link 0 is jack which is true in all existing | ||
| * machine driver | ||
| */ | ||
| if (dai_link->id == 0) { | ||
| tplg_dev = TPLG_DEVICE_SSP_JACK; | ||
| tplg_dev_name = devm_kasprintf(card->dev, GFP_KERNEL, | ||
| "ssp%d-jack", ssp_port); | ||
| } else { | ||
| tplg_dev = TPLG_DEVICE_SSP_AMP; | ||
| tplg_dev_name = devm_kasprintf(card->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(card->dev, GFP_KERNEL, | ||
| "ssp%d-bt", ssp_port); | ||
| } else if (strstr(dai_link->name, "HDMI")) { | ||
| hdmi_in_mask |= BIT(ssp_port); | ||
| /* The number of HDMI in dai link is always 2 right now */ | ||
| if (hweight16(hdmi_in_mask) != 2) | ||
| continue; | ||
|
|
||
| tplg_dev = TPLG_DEVICE_SSP_HDMI_IN; | ||
| tplg_dev_name = devm_kasprintf(card->dev, GFP_KERNEL, | ||
| "ssp%x-hdmiin", hdmi_in_mask); | ||
| } else { | ||
| dev_warn(card->dev, | ||
| "unsupported SSP link %s\n", dai_link->name); | ||
| continue; | ||
| } | ||
| } 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); | ||
| 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 { | ||
| 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_mask |= BIT(tplg_dev); | ||
|
|
||
| (*tplg_files)[tplg_num] = get_tplg_filename(card->dev, prefix, platform, | ||
| tplg_dev_name, dai_link->id, | ||
| tplg_dev); | ||
| if (!(*tplg_files)[tplg_num]) | ||
| return -ENOMEM; | ||
| tplg_num++; | ||
| } | ||
|
Collaborator
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. To my untrained eyes this looks like identical to what
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. Yeah, I thought about it. And yes, they look quite similar, but the existing topologies may use different PCM IDs for different machines. I think it would be better to use separated function to keep the flexibility to have different function topology names for different machines. |
||
|
|
||
| return tplg_num; | ||
| dev_dbg(card->dev, "tplg_mask %#lx tplg_num %d\n", tplg_mask, tplg_num); | ||
|
|
||
| /* Check presence of sub-topologies */ | ||
| if (all_tplg_files_exist(card->dev, tplg_files, tplg_num)) | ||
| return tplg_num; | ||
|
|
||
| /* return 0 to use monolithic topology */ | ||
| return 0; | ||
| } | ||
| EXPORT_SYMBOL_GPL(sof_sdw_get_tplg_files); | ||
| EXPORT_SYMBOL_GPL(sof_i2s_get_tplg_files); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can remove the extra line on front