Skip to content

Commit 4d87433

Browse files
committed
ASoC: SOF: Intel: hda: add split_hdmi audio-client mode
Add split_hdmi mode to register separate analog and HDMI audio clients when iDisp is present. Keep the analog card on the selected machine configuration with iDisp masked out, and register HDMI as a dedicated generic HDA card using sof-hda-generic-idisp.tplg. Update unregister handling to support split fallback to the legacy single-client path when split registration is not used. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
1 parent ac06cdf commit 4d87433

1 file changed

Lines changed: 116 additions & 12 deletions

File tree

sound/soc/sof/intel/hda.c

Lines changed: 116 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1773,6 +1773,10 @@ static bool multi_card;
17731773
module_param(multi_card, bool, 0444);
17741774
MODULE_PARM_DESC(multi_card, "Split audio into per-function cards. Experimental.");
17751775

1776+
static bool split_hdmi;
1777+
module_param(split_hdmi, bool, 0444);
1778+
MODULE_PARM_DESC(split_hdmi, "Split monolithic audio into analog/HDMI cards.");
1779+
17761780
struct hda_sdw_func_card {
17771781
u32 dai_type_bit;
17781782
const char *card_name;
@@ -1784,6 +1788,28 @@ static const struct hda_sdw_func_card sdw_func_cards[] = {
17841788
{ BIT(SOC_SDW_DAI_TYPE_MIC), "mic" },
17851789
};
17861790

1791+
static int hda_register_hdmi_audio_client(struct snd_sof_dev *sdev,
1792+
const struct snd_soc_acpi_mach *mach,
1793+
int card_idx)
1794+
{
1795+
static const struct snd_soc_acpi_link_adr empty_links[] = { {} };
1796+
struct sof_audio_client_pdata pdata;
1797+
1798+
sof_audio_client_init_pdata(sdev, &pdata);
1799+
memcpy(&pdata.machine, mach, sizeof(pdata.machine));
1800+
pdata.machine.mach_params.links = empty_links;
1801+
pdata.machine.mach_params.link_mask = 0;
1802+
pdata.machine.mach_params.codec_mask = BIT(HDA_IDISP_ADDR);
1803+
pdata.machine.mach_params.dmic_num = 0;
1804+
pdata.machine.mach_params.card_name = "hdmi";
1805+
/* Always use a dedicated HDA generic HDMI card. */
1806+
pdata.machine.get_function_tplg_files = NULL;
1807+
pdata.machine.drv_name = "skl_hda_dsp_generic";
1808+
pdata.machine.sof_tplg_filename = "sof-hda-generic-idisp.tplg";
1809+
1810+
return sof_client_dev_register(sdev, "audio", card_idx, &pdata, sizeof(pdata));
1811+
}
1812+
17871813
/*
17881814
* Group SDW DAI types that share physical codec devices. Types on the
17891815
* same device must be on the same card because ASoC components can only
@@ -1947,14 +1973,7 @@ static int hda_register_audio_client_multi(struct snd_sof_dev *sdev)
19471973

19481974
/* HDMI card */
19491975
if (HDA_IDISP_CODEC(mach->mach_params.codec_mask)) {
1950-
memcpy(&pdata.machine, mach, sizeof(pdata.machine));
1951-
pdata.machine.mach_params.links = empty_links;
1952-
pdata.machine.mach_params.link_mask = 0;
1953-
pdata.machine.mach_params.codec_mask = BIT(HDA_IDISP_ADDR);
1954-
pdata.machine.mach_params.dmic_num = 0;
1955-
pdata.machine.mach_params.card_name = "hdmi";
1956-
ret = sof_client_dev_register(sdev, "audio", card_idx,
1957-
&pdata, sizeof(pdata));
1976+
ret = hda_register_hdmi_audio_client(sdev, mach, card_idx);
19581977
if (ret)
19591978
dev_warn(sdev->dev,
19601979
"multi_card: failed to register card hdmi: %d\n",
@@ -1968,11 +1987,75 @@ static int hda_register_audio_client_multi(struct snd_sof_dev *sdev)
19681987
return 0;
19691988
}
19701989

1990+
static int hda_register_audio_client_split_hdmi(struct snd_sof_dev *sdev)
1991+
{
1992+
const struct snd_soc_acpi_mach *mach = sdev->pdata->machine;
1993+
struct hdac_bus *bus = sof_to_bus(sdev);
1994+
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
1995+
bool function_tplg_enabled;
1996+
bool has_analog_card;
1997+
struct sof_audio_client_pdata pdata;
1998+
int ret;
1999+
2000+
hdev->num_audio_clients = 0;
2001+
2002+
if (!mach)
2003+
return -ENODEV;
2004+
2005+
function_tplg_enabled = !sdev->pdata->disable_function_topology &&
2006+
mach->get_function_tplg_files;
2007+
2008+
if (!HDA_IDISP_CODEC(mach->mach_params.codec_mask))
2009+
return sof_register_audio_client(sdev);
2010+
2011+
has_analog_card = HDA_EXT_CODEC(bus->codec_mask) ||
2012+
mach->mach_params.link_mask ||
2013+
mach->mach_params.dmic_num;
2014+
2015+
if (!function_tplg_enabled && !has_analog_card) {
2016+
dev_info(sdev->dev,
2017+
"split_hdmi is not supported on this machine, using single card\n");
2018+
return sof_register_audio_client(sdev);
2019+
}
2020+
2021+
sof_audio_client_init_pdata(sdev, &pdata);
2022+
2023+
/* Analog card: remove iDisp codec from the base machine configuration */
2024+
memcpy(&pdata.machine, mach, sizeof(pdata.machine));
2025+
pdata.machine.mach_params.codec_mask &= ~BIT(HDA_IDISP_ADDR);
2026+
pdata.machine.mach_params.card_name = NULL;
2027+
if (function_tplg_enabled) {
2028+
pdata.machine.sof_tplg_filename = mach->sof_tplg_filename ?
2029+
mach->sof_tplg_filename : sdev->pdata->tplg_filename;
2030+
} else {
2031+
pdata.machine.get_function_tplg_files = NULL;
2032+
pdata.machine.sof_tplg_filename = NULL;
2033+
}
2034+
ret = sof_client_dev_register(sdev, "audio", 0, &pdata, sizeof(pdata));
2035+
if (ret) {
2036+
dev_warn(sdev->dev,
2037+
"split_hdmi: failed to register analog card: %d\n", ret);
2038+
return sof_register_audio_client(sdev);
2039+
}
2040+
2041+
ret = hda_register_hdmi_audio_client(sdev, mach, 1);
2042+
if (ret) {
2043+
dev_warn(sdev->dev,
2044+
"split_hdmi: failed to register HDMI card: %d, using single card\n", ret);
2045+
sof_client_dev_unregister(sdev, "audio", 0);
2046+
return sof_register_audio_client(sdev);
2047+
}
2048+
2049+
hdev->num_audio_clients = 2;
2050+
2051+
return 0;
2052+
}
2053+
19712054
int hda_register_audio_client(struct snd_sof_dev *sdev)
19722055
{
1973-
if (multi_card) {
1974-
const struct snd_soc_acpi_mach *mach = sdev->pdata->machine;
2056+
const struct snd_soc_acpi_mach *mach = sdev->pdata->machine;
19752057

2058+
if (multi_card) {
19762059
if (mach && !sdev->pdata->disable_function_topology &&
19772060
mach->get_function_tplg_files)
19782061
return hda_register_audio_client_multi(sdev);
@@ -1981,14 +2064,17 @@ int hda_register_audio_client(struct snd_sof_dev *sdev)
19812064
"multi_card is only supported with function topologies, using single card\n");
19822065
}
19832066

2067+
if (split_hdmi)
2068+
return hda_register_audio_client_split_hdmi(sdev);
2069+
19842070
return sof_register_audio_client(sdev);
19852071
}
19862072

19872073
void hda_unregister_audio_client(struct snd_sof_dev *sdev)
19882074
{
1989-
if (multi_card) {
1990-
const struct snd_soc_acpi_mach *mach = sdev->pdata->machine;
2075+
const struct snd_soc_acpi_mach *mach = sdev->pdata->machine;
19912076

2077+
if (multi_card) {
19922078
if (mach && !sdev->pdata->disable_function_topology &&
19932079
mach->get_function_tplg_files) {
19942080
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
@@ -2001,6 +2087,24 @@ void hda_unregister_audio_client(struct snd_sof_dev *sdev)
20012087
}
20022088
}
20032089

2090+
if (split_hdmi && mach && HDA_IDISP_CODEC(mach->mach_params.codec_mask)) {
2091+
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
2092+
int i;
2093+
2094+
/*
2095+
* split_hdmi may fall back to single-card registration. In that case,
2096+
* use the legacy single-client unregister path.
2097+
*/
2098+
if (hdev->num_audio_clients <= 1)
2099+
goto single_client_unregister;
2100+
2101+
for (i = hdev->num_audio_clients - 1; i >= 0; i--)
2102+
sof_client_dev_unregister(sdev, "audio", i);
2103+
hdev->num_audio_clients = 0;
2104+
return;
2105+
}
2106+
2107+
single_client_unregister:
20042108
sof_unregister_audio_client(sdev);
20052109
}
20062110

0 commit comments

Comments
 (0)