Commit 5fe14c55 authored by Mark Brown's avatar Mark Brown

Improve SOF support for Steam Deck OLED

Merge series from Cristian Ciocaltea <cristian.ciocaltea@collabora.com>:

This patch series is a continuation of [1] to provide several fixes and
improvements to the SOF drivers targeting the Vangogh platform, as found on
Valve's Steam Deck OLED.  The previous series only handled the legacy ACP
drivers.

Also note that, since v2, this patch series requires an updated SOF
topology to provide a correct DAI link ID for the BT codec.  The binary
file should be located under:

  /usr/lib/firmware/amd/sof-tplg/sof-vangogh-nau8821-max.tplg

Alternatively, as a temporary workaround, patch [2] can be used to adapt
the driver to the broken topology.

Another requirement to get this functional is patch [3] from v1, which has
been dropped from the series to be upstreamed via the SOF development
workflow.

[1]: https://lore.kernel.org/all/20231209203229.878730-1-cristian.ciocaltea@collabora.com/
[2]: https://lore.kernel.org/all/20231209205351.880797-11-cristian.ciocaltea@collabora.com/
[3]: https://lore.kernel.org/all/20231209205351.880797-12-cristian.ciocaltea@collabora.com/
parents be69eae9 d9cacc1a
...@@ -821,8 +821,8 @@ static const struct snd_soc_ops acp_card_maxim_ops = { ...@@ -821,8 +821,8 @@ static const struct snd_soc_ops acp_card_maxim_ops = {
}; };
SND_SOC_DAILINK_DEF(max98388, SND_SOC_DAILINK_DEF(max98388,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ADS8388:00", "max98388-aif1"), DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ADS8388:00", MAX98388_CODEC_DAI),
COMP_CODEC("i2c-ADS8388:01", "max98388-aif1"))); COMP_CODEC("i2c-ADS8388:01", MAX98388_CODEC_DAI)));
static const struct snd_kcontrol_new max98388_controls[] = { static const struct snd_kcontrol_new max98388_controls[] = {
SOC_DAPM_PIN_SWITCH("Left Spk"), SOC_DAPM_PIN_SWITCH("Left Spk"),
...@@ -1273,7 +1273,7 @@ static const struct snd_soc_ops acp_8821_ops = { ...@@ -1273,7 +1273,7 @@ static const struct snd_soc_ops acp_8821_ops = {
SND_SOC_DAILINK_DEF(nau8821, SND_SOC_DAILINK_DEF(nau8821,
DAILINK_COMP_ARRAY(COMP_CODEC("i2c-NVTN2020:00", DAILINK_COMP_ARRAY(COMP_CODEC("i2c-NVTN2020:00",
"nau8821-hifi"))); NAU8821_CODEC_DAI)));
/* Declare DMIC codec components */ /* Declare DMIC codec components */
SND_SOC_DAILINK_DEF(dmic_codec, SND_SOC_DAILINK_DEF(dmic_codec,
......
...@@ -28,7 +28,6 @@ static struct acp_card_drvdata sof_rt5682_rt1019_data = { ...@@ -28,7 +28,6 @@ static struct acp_card_drvdata sof_rt5682_rt1019_data = {
.hs_codec_id = RT5682, .hs_codec_id = RT5682,
.amp_codec_id = RT1019, .amp_codec_id = RT1019,
.dmic_codec_id = DMIC, .dmic_codec_id = DMIC,
.tdm_mode = false,
}; };
static struct acp_card_drvdata sof_rt5682_max_data = { static struct acp_card_drvdata sof_rt5682_max_data = {
...@@ -38,7 +37,6 @@ static struct acp_card_drvdata sof_rt5682_max_data = { ...@@ -38,7 +37,6 @@ static struct acp_card_drvdata sof_rt5682_max_data = {
.hs_codec_id = RT5682, .hs_codec_id = RT5682,
.amp_codec_id = MAX98360A, .amp_codec_id = MAX98360A,
.dmic_codec_id = DMIC, .dmic_codec_id = DMIC,
.tdm_mode = false,
}; };
static struct acp_card_drvdata sof_rt5682s_rt1019_data = { static struct acp_card_drvdata sof_rt5682s_rt1019_data = {
...@@ -48,7 +46,6 @@ static struct acp_card_drvdata sof_rt5682s_rt1019_data = { ...@@ -48,7 +46,6 @@ static struct acp_card_drvdata sof_rt5682s_rt1019_data = {
.hs_codec_id = RT5682S, .hs_codec_id = RT5682S,
.amp_codec_id = RT1019, .amp_codec_id = RT1019,
.dmic_codec_id = DMIC, .dmic_codec_id = DMIC,
.tdm_mode = false,
}; };
static struct acp_card_drvdata sof_rt5682s_max_data = { static struct acp_card_drvdata sof_rt5682s_max_data = {
...@@ -58,7 +55,6 @@ static struct acp_card_drvdata sof_rt5682s_max_data = { ...@@ -58,7 +55,6 @@ static struct acp_card_drvdata sof_rt5682s_max_data = {
.hs_codec_id = RT5682S, .hs_codec_id = RT5682S,
.amp_codec_id = MAX98360A, .amp_codec_id = MAX98360A,
.dmic_codec_id = DMIC, .dmic_codec_id = DMIC,
.tdm_mode = false,
}; };
static struct acp_card_drvdata sof_nau8825_data = { static struct acp_card_drvdata sof_nau8825_data = {
...@@ -69,7 +65,6 @@ static struct acp_card_drvdata sof_nau8825_data = { ...@@ -69,7 +65,6 @@ static struct acp_card_drvdata sof_nau8825_data = {
.amp_codec_id = MAX98360A, .amp_codec_id = MAX98360A,
.dmic_codec_id = DMIC, .dmic_codec_id = DMIC,
.soc_mclk = true, .soc_mclk = true,
.tdm_mode = false,
}; };
static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = { static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = {
...@@ -80,20 +75,15 @@ static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = { ...@@ -80,20 +75,15 @@ static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = {
.amp_codec_id = RT1019, .amp_codec_id = RT1019,
.dmic_codec_id = DMIC, .dmic_codec_id = DMIC,
.soc_mclk = true, .soc_mclk = true,
.tdm_mode = false,
}; };
static struct acp_card_drvdata sof_nau8821_max98388_data = { static struct acp_card_drvdata sof_nau8821_max98388_data = {
.hs_cpu_id = I2S_SP, .hs_cpu_id = I2S_SP,
.amp_cpu_id = I2S_HS, .amp_cpu_id = I2S_HS,
.bt_cpu_id = I2S_BT, .bt_cpu_id = I2S_BT,
.dmic_cpu_id = NONE,
.hs_codec_id = NAU8821, .hs_codec_id = NAU8821,
.amp_codec_id = MAX98388, .amp_codec_id = MAX98388,
.bt_codec_id = NONE,
.dmic_codec_id = NONE,
.soc_mclk = true, .soc_mclk = true,
.tdm_mode = false,
}; };
static int acp_sof_probe(struct platform_device *pdev) static int acp_sof_probe(struct platform_device *pdev)
...@@ -122,16 +112,14 @@ static int acp_sof_probe(struct platform_device *pdev) ...@@ -122,16 +112,14 @@ static int acp_sof_probe(struct platform_device *pdev)
if (dmi_id && dmi_id->driver_data) if (dmi_id && dmi_id->driver_data)
acp_card_drvdata->tdm_mode = dmi_id->driver_data; acp_card_drvdata->tdm_mode = dmi_id->driver_data;
acp_sofdsp_dai_links_create(card); ret = acp_sofdsp_dai_links_create(card);
if (ret)
return dev_err_probe(&pdev->dev, ret, "Failed to create DAI links\n");
ret = devm_snd_soc_register_card(&pdev->dev, card); ret = devm_snd_soc_register_card(&pdev->dev, card);
if (ret) { if (ret)
dev_err(&pdev->dev, return dev_err_probe(&pdev->dev, ret,
"devm_snd_soc_register_card(%s) failed: %d\n", "Failed to register card(%s)\n", card->name);
card->name, ret);
return ret;
}
return 0; return 0;
} }
...@@ -178,7 +166,7 @@ static struct platform_driver acp_asoc_audio = { ...@@ -178,7 +166,7 @@ static struct platform_driver acp_asoc_audio = {
module_platform_driver(acp_asoc_audio); module_platform_driver(acp_asoc_audio);
MODULE_IMPORT_NS(SND_SOC_AMD_MACH); MODULE_IMPORT_NS(SND_SOC_AMD_MACH);
MODULE_DESCRIPTION("ACP chrome SOF audio support"); MODULE_DESCRIPTION("ACP SOF Machine Driver");
MODULE_ALIAS("platform:rt5682-rt1019"); MODULE_ALIAS("platform:rt5682-rt1019");
MODULE_ALIAS("platform:rt5682-max"); MODULE_ALIAS("platform:rt5682-max");
MODULE_ALIAS("platform:rt5682s-max"); MODULE_ALIAS("platform:rt5682s-max");
......
...@@ -267,29 +267,49 @@ int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev) ...@@ -267,29 +267,49 @@ int acp_sof_load_signed_firmware(struct snd_sof_dev *sdev)
{ {
struct snd_sof_pdata *plat_data = sdev->pdata; struct snd_sof_pdata *plat_data = sdev->pdata;
struct acp_dev_data *adata = plat_data->hw_pdata; struct acp_dev_data *adata = plat_data->hw_pdata;
const char *fw_filename;
int ret; int ret;
ret = request_firmware(&sdev->basefw.fw, adata->fw_code_bin, sdev->dev); fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
plat_data->fw_filename_prefix,
adata->fw_code_bin);
if (!fw_filename)
return -ENOMEM;
ret = request_firmware(&sdev->basefw.fw, fw_filename, sdev->dev);
if (ret < 0) { if (ret < 0) {
kfree(fw_filename);
dev_err(sdev->dev, "sof signed firmware code bin is missing\n"); dev_err(sdev->dev, "sof signed firmware code bin is missing\n");
return ret; return ret;
} else { } else {
dev_dbg(sdev->dev, "request_firmware %s successful\n", adata->fw_code_bin); dev_dbg(sdev->dev, "request_firmware %s successful\n", fw_filename);
} }
kfree(fw_filename);
ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_IRAM, 0, ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_IRAM, 0,
(void *)sdev->basefw.fw->data, sdev->basefw.fw->size); (void *)sdev->basefw.fw->data,
sdev->basefw.fw->size);
fw_filename = kasprintf(GFP_KERNEL, "%s/%s",
plat_data->fw_filename_prefix,
adata->fw_data_bin);
if (!fw_filename)
return -ENOMEM;
ret = request_firmware(&adata->fw_dbin, adata->fw_data_bin, sdev->dev); ret = request_firmware(&adata->fw_dbin, fw_filename, sdev->dev);
if (ret < 0) { if (ret < 0) {
kfree(fw_filename);
dev_err(sdev->dev, "sof signed firmware data bin is missing\n"); dev_err(sdev->dev, "sof signed firmware data bin is missing\n");
return ret; return ret;
} else { } else {
dev_dbg(sdev->dev, "request_firmware %s successful\n", adata->fw_data_bin); dev_dbg(sdev->dev, "request_firmware %s successful\n", fw_filename);
} }
kfree(fw_filename);
ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0, ret = snd_sof_dsp_block_write(sdev, SOF_FW_BLK_TYPE_DRAM, 0,
(void *)adata->fw_dbin->data, adata->fw_dbin->size); (void *)adata->fw_dbin->data,
adata->fw_dbin->size);
return ret; return ret;
} }
EXPORT_SYMBOL_NS(acp_sof_load_signed_firmware, SND_SOC_SOF_AMD_COMMON); EXPORT_SYMBOL_NS(acp_sof_load_signed_firmware, SND_SOC_SOF_AMD_COMMON);
...@@ -28,11 +28,10 @@ MODULE_PARM_DESC(enable_fw_debug, "Enable Firmware debug"); ...@@ -28,11 +28,10 @@ MODULE_PARM_DESC(enable_fw_debug, "Enable Firmware debug");
const struct dmi_system_id acp_sof_quirk_table[] = { const struct dmi_system_id acp_sof_quirk_table[] = {
{ {
/* Valve Jupiter device */ /* Steam Deck OLED device */
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Valve"), DMI_MATCH(DMI_SYS_VENDOR, "Valve"),
DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"), DMI_MATCH(DMI_PRODUCT_NAME, "Galileo"),
DMI_MATCH(DMI_PRODUCT_FAMILY, "Sephiroth"),
}, },
.driver_data = (void *)SECURED_FIRMWARE, .driver_data = (void *)SECURED_FIRMWARE,
}, },
...@@ -494,7 +493,6 @@ EXPORT_SYMBOL_NS(amd_sof_acp_resume, SND_SOC_SOF_AMD_COMMON); ...@@ -494,7 +493,6 @@ EXPORT_SYMBOL_NS(amd_sof_acp_resume, SND_SOC_SOF_AMD_COMMON);
int amd_sof_acp_probe(struct snd_sof_dev *sdev) int amd_sof_acp_probe(struct snd_sof_dev *sdev)
{ {
struct pci_dev *pci = to_pci_dev(sdev->dev); struct pci_dev *pci = to_pci_dev(sdev->dev);
struct snd_sof_pdata *plat_data = sdev->pdata;
struct acp_dev_data *adata; struct acp_dev_data *adata;
const struct sof_amd_acp_desc *chip; const struct sof_amd_acp_desc *chip;
const struct dmi_system_id *dmi_id; const struct dmi_system_id *dmi_id;
...@@ -561,17 +559,25 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) ...@@ -561,17 +559,25 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev)
adata->signed_fw_image = false; adata->signed_fw_image = false;
dmi_id = dmi_first_match(acp_sof_quirk_table); dmi_id = dmi_first_match(acp_sof_quirk_table);
if (dmi_id && dmi_id->driver_data) { if (dmi_id && dmi_id->driver_data) {
adata->fw_code_bin = kasprintf(GFP_KERNEL, "%s/sof-%s-code.bin", adata->fw_code_bin = devm_kasprintf(sdev->dev, GFP_KERNEL,
plat_data->fw_filename_prefix, "sof-%s-code.bin",
chip->name); chip->name);
adata->fw_data_bin = kasprintf(GFP_KERNEL, "%s/sof-%s-data.bin", if (!adata->fw_code_bin) {
plat_data->fw_filename_prefix, ret = -ENOMEM;
goto free_ipc_irq;
}
adata->fw_data_bin = devm_kasprintf(sdev->dev, GFP_KERNEL,
"sof-%s-data.bin",
chip->name); chip->name);
adata->signed_fw_image = dmi_id->driver_data; if (!adata->fw_data_bin) {
ret = -ENOMEM;
goto free_ipc_irq;
}
dev_dbg(sdev->dev, "fw_code_bin:%s, fw_data_bin:%s\n", adata->fw_code_bin, adata->signed_fw_image = dmi_id->driver_data;
adata->fw_data_bin);
} }
adata->enable_fw_debug = enable_fw_debug; adata->enable_fw_debug = enable_fw_debug;
acp_memory_init(sdev); acp_memory_init(sdev);
......
...@@ -89,6 +89,12 @@ static int sof_test_topology_file(struct device *dev, ...@@ -89,6 +89,12 @@ static int sof_test_topology_file(struct device *dev,
return ret; return ret;
} }
static bool sof_platform_uses_generic_loader(struct snd_sof_dev *sdev)
{
return (sdev->pdata->desc->ops->load_firmware == snd_sof_load_firmware_raw ||
sdev->pdata->desc->ops->load_firmware == snd_sof_load_firmware_memcpy);
}
static int static int
sof_file_profile_for_ipc_type(struct snd_sof_dev *sdev, sof_file_profile_for_ipc_type(struct snd_sof_dev *sdev,
enum sof_ipc_type ipc_type, enum sof_ipc_type ipc_type,
...@@ -130,7 +136,8 @@ sof_file_profile_for_ipc_type(struct snd_sof_dev *sdev, ...@@ -130,7 +136,8 @@ sof_file_profile_for_ipc_type(struct snd_sof_dev *sdev,
* For default path and firmware name do a verification before * For default path and firmware name do a verification before
* continuing further. * continuing further.
*/ */
if (base_profile->fw_path || base_profile->fw_name) { if ((base_profile->fw_path || base_profile->fw_name) &&
sof_platform_uses_generic_loader(sdev)) {
ret = sof_test_firmware_file(dev, out_profile, &ipc_type); ret = sof_test_firmware_file(dev, out_profile, &ipc_type);
if (ret) if (ret)
return ret; return ret;
...@@ -181,7 +188,8 @@ sof_file_profile_for_ipc_type(struct snd_sof_dev *sdev, ...@@ -181,7 +188,8 @@ sof_file_profile_for_ipc_type(struct snd_sof_dev *sdev,
out_profile->ipc_type = ipc_type; out_profile->ipc_type = ipc_type;
/* Test only default firmware file */ /* Test only default firmware file */
if (!base_profile->fw_path && !base_profile->fw_name) if ((!base_profile->fw_path && !base_profile->fw_name) &&
sof_platform_uses_generic_loader(sdev))
ret = sof_test_firmware_file(dev, out_profile, NULL); ret = sof_test_firmware_file(dev, out_profile, NULL);
if (!ret) if (!ret)
...@@ -267,7 +275,11 @@ static void sof_print_profile_info(struct snd_sof_dev *sdev, ...@@ -267,7 +275,11 @@ static void sof_print_profile_info(struct snd_sof_dev *sdev,
dev_info(dev, "Firmware paths/files for ipc type %d:\n", profile->ipc_type); dev_info(dev, "Firmware paths/files for ipc type %d:\n", profile->ipc_type);
dev_info(dev, " Firmware file: %s/%s\n", profile->fw_path, profile->fw_name); /* The firmware path is only valid when generic loader is used */
if (sof_platform_uses_generic_loader(sdev))
dev_info(dev, " Firmware file: %s/%s\n",
profile->fw_path, profile->fw_name);
if (profile->fw_lib_path) if (profile->fw_lib_path)
dev_info(dev, " Firmware lib path: %s\n", profile->fw_lib_path); dev_info(dev, " Firmware lib path: %s\n", profile->fw_lib_path);
dev_info(dev, " Topology file: %s/%s\n", profile->tplg_path, profile->tplg_name); dev_info(dev, " Topology file: %s/%s\n", profile->tplg_path, profile->tplg_name);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment