linux/sound/soc/amd/acp/acp-sof-mach.c
Guilherme G. Piccoli b0f6f4ac7d
ASoC: amd: acp: Add DMI quirk for Valve Steam Deck OLED
Commit 671dd2ffbd ("ASoC: amd: acp: Add new cpu dai and dailink creation for I2S BT instance")
introduced a change that "broke" Steam Deck's audio probe, in the OLED
model, as observed in the following dmesg snippet:

[...]
snd_sof_amd_vangogh 0000:04:00.5: Topology: ABI 3:26:0 Kernel ABI 3:23:1
sof_mach nau8821-max: ASoC: physical link acp-bt-codec (id 2) not exist
sof_mach nau8821-max: ASoC: topology: could not load header: -22
snd_sof_amd_vangogh 0000:04:00.5: tplg amd/sof-tplg/sof-vangogh-nau8821-max.tplg component load failed -22
snd_sof_amd_vangogh 0000:04:00.5: error: failed to load DSP topology -22
snd_sof_amd_vangogh 0000:04:00.5: ASoC error (-22): at snd_soc_component_probe() on 0000:04:00.5
sof_mach nau8821-max: ASoC: failed to instantiate card -22
sof_mach nau8821-max: error -EINVAL: Failed to register card(sof-nau8821-max)
sof_mach nau8821-max: probe with driver sof_mach failed with error -22
[...]

Notice the quotes in "broke": it's not really a bug in such commit,
but instead a problem with a topology file from Steam Deck OLED. This
was discussed to great extent in [1], and Cristian proposed a pretty
simple and functional change that resolved the issue for the Deck's
issue. That change, though, would break other devices, so it wasn't
accepted upstream. And the proper suggested solution (fix the topology)
was never implemented, so Valve's kernel (and anyone that wants to boot
the mainline on Steam Deck OLED) is carrying that fix downstream.

So, we propose hereby a different approach: a DMI quirk, as many already
present in the sound drivers, to address this issue solely on Steam Deck
OLED, not breaking other devices and as a bonus, allowing simple patch
up in case eventually the topology file gets fixed (we'd just need to
check against any DMI info reflecting that or the topology/FW versions).

The motivation of such upstream quirk is related to users that want
to test latest kernel trees on their devices and get no only non-working
sound device, but seems some games (like Ori and the Blind Forest)
can't properly work without a proper functional audio device.
Example of such report can be seen at [2].

Cc: Mark Brown <broonie@kernel.org>
Cc: Robert Beckett <bob.beckett@collabora.com>
Cc: Umang Jain <uajain@igalia.com>
Fixes: 671dd2ffbd ("ASoC: amd: acp: Add new cpu dai and dailink creation for I2S BT instance")
Link: https://lore.kernel.org/r/20231209205351.880797-11-cristian.ciocaltea@collabora.com/ [1]
Link: https://bugzilla.kernel.org/show_bug.cgi?id=218677 [2]
Reviewed-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
Tested-by: Melissa Wen <mwen@igalia.com>
Signed-off-by: Guilherme G. Piccoli <gpiccoli@igalia.com>
Link: https://patch.msgid.link/20260423183505.116445-1-gpiccoli@igalia.com
Signed-off-by: Mark Brown <broonie@kernel.org>
2026-04-27 06:54:14 +09:00

175 lines
4.2 KiB
C

// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
//
// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc.
//
// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
//
/*
* SOF Machine Driver Support for ACP HW block
*/
#include <sound/core.h>
#include <sound/pcm_params.h>
#include <sound/soc-acpi.h>
#include <sound/soc-dapm.h>
#include <linux/dmi.h>
#include <linux/module.h>
#include "acp-mach.h"
static struct acp_card_drvdata sof_rt5682_rt1019_data = {
.hs_cpu_id = I2S_SP,
.amp_cpu_id = I2S_SP,
.dmic_cpu_id = DMIC,
.hs_codec_id = RT5682,
.amp_codec_id = RT1019,
.dmic_codec_id = DMIC,
};
static struct acp_card_drvdata sof_rt5682_max_data = {
.hs_cpu_id = I2S_SP,
.amp_cpu_id = I2S_SP,
.dmic_cpu_id = DMIC,
.hs_codec_id = RT5682,
.amp_codec_id = MAX98360A,
.dmic_codec_id = DMIC,
};
static struct acp_card_drvdata sof_rt5682s_rt1019_data = {
.hs_cpu_id = I2S_SP,
.amp_cpu_id = I2S_SP,
.dmic_cpu_id = DMIC,
.hs_codec_id = RT5682S,
.amp_codec_id = RT1019,
.dmic_codec_id = DMIC,
};
static struct acp_card_drvdata sof_rt5682s_max_data = {
.hs_cpu_id = I2S_SP,
.amp_cpu_id = I2S_SP,
.dmic_cpu_id = DMIC,
.hs_codec_id = RT5682S,
.amp_codec_id = MAX98360A,
.dmic_codec_id = DMIC,
};
static struct acp_card_drvdata sof_nau8825_data = {
.hs_cpu_id = I2S_HS,
.amp_cpu_id = I2S_HS,
.dmic_cpu_id = DMIC,
.hs_codec_id = NAU8825,
.amp_codec_id = MAX98360A,
.dmic_codec_id = DMIC,
.soc_mclk = true,
};
static struct acp_card_drvdata sof_rt5682s_hs_rt1019_data = {
.hs_cpu_id = I2S_HS,
.amp_cpu_id = I2S_HS,
.dmic_cpu_id = DMIC,
.hs_codec_id = RT5682S,
.amp_codec_id = RT1019,
.dmic_codec_id = DMIC,
.soc_mclk = true,
};
static struct acp_card_drvdata sof_nau8821_max98388_data = {
.hs_cpu_id = I2S_SP,
.amp_cpu_id = I2S_HS,
.bt_cpu_id = I2S_BT,
.hs_codec_id = NAU8821,
.amp_codec_id = MAX98388,
.soc_mclk = true,
};
static int acp_sof_probe(struct platform_device *pdev)
{
struct snd_soc_card *card;
struct device *dev = &pdev->dev;
struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev);
const struct dmi_system_id *dmi_id;
struct acp_card_drvdata *acp_card_drvdata;
int ret;
if (!pdev->id_entry)
return -EINVAL;
card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
if (!card)
return -ENOMEM;
card->dev = dev;
card->owner = THIS_MODULE;
card->name = pdev->id_entry->name;
card->drvdata = (struct acp_card_drvdata *)pdev->id_entry->driver_data;
/* Widgets and controls added per-codec in acp-mach-common.c */
acp_card_drvdata = card->drvdata;
dmi_id = dmi_first_match(acp_quirk_table);
if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE)
acp_card_drvdata->tdm_mode = dmi_id->driver_data;
acp_card_drvdata->acp_rev = mach->mach_params.subsystem_rev;
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);
if (ret)
return dev_err_probe(&pdev->dev, ret,
"Failed to register card(%s)\n", card->name);
return 0;
}
static const struct platform_device_id board_ids[] = {
{
.name = "rt5682-rt1019",
.driver_data = (kernel_ulong_t)&sof_rt5682_rt1019_data
},
{
.name = "rt5682-max",
.driver_data = (kernel_ulong_t)&sof_rt5682_max_data
},
{
.name = "rt5682s-max",
.driver_data = (kernel_ulong_t)&sof_rt5682s_max_data
},
{
.name = "rt5682s-rt1019",
.driver_data = (kernel_ulong_t)&sof_rt5682s_rt1019_data
},
{
.name = "nau8825-max",
.driver_data = (kernel_ulong_t)&sof_nau8825_data
},
{
.name = "rt5682s-hs-rt1019",
.driver_data = (kernel_ulong_t)&sof_rt5682s_hs_rt1019_data
},
{
.name = "nau8821-max",
.driver_data = (kernel_ulong_t)&sof_nau8821_max98388_data
},
{ }
};
MODULE_DEVICE_TABLE(platform, board_ids);
static struct platform_driver acp_asoc_audio = {
.driver = {
.name = "sof_mach",
.pm = &snd_soc_pm_ops,
},
.probe = acp_sof_probe,
.id_table = board_ids,
};
module_platform_driver(acp_asoc_audio);
MODULE_IMPORT_NS("SND_SOC_AMD_MACH");
MODULE_DESCRIPTION("ACP SOF Machine Driver");
MODULE_LICENSE("GPL v2");