Commit 611885bc authored by Anssi Hannula's avatar Anssi Hannula Committed by Takashi Iwai

ALSA: hda - hdmi: Disallow unsupported 2ch remapping on NVIDIA codecs

NVIDIA HDMI codecs do not seem to follow the Audio Sample Packet (ASP)
channel mapping (as set by verb F32h per HDA specification 7.3.3.41)
when playing back 2-channel audio (CEA CA 0x00).

Basically this means that specifying swapped channels for stereo audio
(FR,FL) does not take effect, and e.g. this command plays back on the
wrong channel:
speaker-test -c2 -Dhdmi:CARD=NVidia,DEV=0 -m FR,FL -s1

Multichannel audio is not affected.

This issue has been confirmed to exist on codec 0x10de0015 by me and on
0x10de0040 by Juho Teperi.

Disable 2ch FL/FR channel swapping on all NVIDIA HDMI codecs that use
the standard HDA channel mapping system. Since this is a very minor
functionality loss, we err on the side of disabling it for newer codecs
as well until any future testing confirms that this issue has been
fixed.
Signed-off-by: default avatarAnssi Hannula <anssi.hannula@iki.fi>
Helped-by: default avatarJuho Teperi <juho.teperi@iki.fi>
Cc: Aaron Plattner <aplattner@nvidia.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent fce762ed
...@@ -2786,6 +2786,46 @@ static int patch_nvhdmi_8ch_7x(struct hda_codec *codec) ...@@ -2786,6 +2786,46 @@ static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
return 0; return 0;
} }
/*
* NVIDIA codecs ignore ASP mapping for 2ch - confirmed on:
* - 0x10de0015
* - 0x10de0040
*/
static int nvhdmi_chmap_cea_alloc_validate_get_type(struct cea_channel_speaker_allocation *cap,
int channels)
{
if (cap->ca_index == 0x00 && channels == 2)
return SNDRV_CTL_TLVT_CHMAP_FIXED;
return hdmi_chmap_cea_alloc_validate_get_type(cap, channels);
}
static int nvhdmi_chmap_validate(int ca, int chs, unsigned char *map)
{
if (ca == 0x00 && (map[0] != SNDRV_CHMAP_FL || map[1] != SNDRV_CHMAP_FR))
return -EINVAL;
return 0;
}
static int patch_nvhdmi(struct hda_codec *codec)
{
struct hdmi_spec *spec;
int err;
err = patch_generic_hdmi(codec);
if (err)
return err;
spec = codec->spec;
spec->ops.chmap_cea_alloc_validate_get_type =
nvhdmi_chmap_cea_alloc_validate_get_type;
spec->ops.chmap_validate = nvhdmi_chmap_validate;
return 0;
}
/* /*
* ATI/AMD-specific implementations * ATI/AMD-specific implementations
*/ */
...@@ -3167,30 +3207,30 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = { ...@@ -3167,30 +3207,30 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
{ .id = 0x10de0005, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, { .id = 0x10de0005, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
{ .id = 0x10de0006, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, { .id = 0x10de0006, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x },
{ .id = 0x10de0007, .name = "MCP79/7A HDMI", .patch = patch_nvhdmi_8ch_7x }, { .id = 0x10de0007, .name = "MCP79/7A HDMI", .patch = patch_nvhdmi_8ch_7x },
{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_generic_hdmi }, { .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_nvhdmi },
{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de0015, .name = "GPU 15 HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de0015, .name = "GPU 15 HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de0016, .name = "GPU 16 HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de0016, .name = "GPU 16 HDMI/DP", .patch = patch_nvhdmi },
/* 17 is known to be absent */ /* 17 is known to be absent */
{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de0051, .name = "GPU 51 HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de0051, .name = "GPU 51 HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de0060, .name = "GPU 60 HDMI/DP", .patch = patch_generic_hdmi }, { .id = 0x10de0060, .name = "GPU 60 HDMI/DP", .patch = patch_nvhdmi },
{ .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch },
{ .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch },
{ .id = 0x11069f80, .name = "VX900 HDMI/DP", .patch = patch_via_hdmi }, { .id = 0x11069f80, .name = "VX900 HDMI/DP", .patch = patch_via_hdmi },
......
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