@@ -1773,6 +1773,10 @@ static bool multi_card;
17731773module_param (multi_card , bool , 0444 );
17741774MODULE_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+
17761780struct 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+
19712054int 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
19872073void 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