1*73cd0490STakashi Iwai // SPDX-License-Identifier: GPL-2.0-or-later 2*73cd0490STakashi Iwai /* 3*73cd0490STakashi Iwai * Nvidia HDMI codec support 4*73cd0490STakashi Iwai */ 5*73cd0490STakashi Iwai 6*73cd0490STakashi Iwai #include <linux/init.h> 7*73cd0490STakashi Iwai #include <linux/slab.h> 8*73cd0490STakashi Iwai #include <linux/module.h> 9*73cd0490STakashi Iwai #include <sound/core.h> 10*73cd0490STakashi Iwai #include <sound/tlv.h> 11*73cd0490STakashi Iwai #include <sound/hdaudio.h> 12*73cd0490STakashi Iwai #include <sound/hda_codec.h> 13*73cd0490STakashi Iwai #include "hda_local.h" 14*73cd0490STakashi Iwai #include "hdmi_local.h" 15*73cd0490STakashi Iwai 16*73cd0490STakashi Iwai /* 17*73cd0490STakashi Iwai * NVIDIA codecs ignore ASP mapping for 2ch - confirmed on: 18*73cd0490STakashi Iwai * - 0x10de0015 19*73cd0490STakashi Iwai * - 0x10de0040 20*73cd0490STakashi Iwai */ 21*73cd0490STakashi Iwai static int nvhdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap, 22*73cd0490STakashi Iwai struct hdac_cea_channel_speaker_allocation *cap, int channels) 23*73cd0490STakashi Iwai { 24*73cd0490STakashi Iwai if (cap->ca_index == 0x00 && channels == 2) 25*73cd0490STakashi Iwai return SNDRV_CTL_TLVT_CHMAP_FIXED; 26*73cd0490STakashi Iwai 27*73cd0490STakashi Iwai /* If the speaker allocation matches the channel count, it is OK. */ 28*73cd0490STakashi Iwai if (cap->channels != channels) 29*73cd0490STakashi Iwai return -1; 30*73cd0490STakashi Iwai 31*73cd0490STakashi Iwai /* all channels are remappable freely */ 32*73cd0490STakashi Iwai return SNDRV_CTL_TLVT_CHMAP_VAR; 33*73cd0490STakashi Iwai } 34*73cd0490STakashi Iwai 35*73cd0490STakashi Iwai static int nvhdmi_chmap_validate(struct hdac_chmap *chmap, 36*73cd0490STakashi Iwai int ca, int chs, unsigned char *map) 37*73cd0490STakashi Iwai { 38*73cd0490STakashi Iwai if (ca == 0x00 && (map[0] != SNDRV_CHMAP_FL || map[1] != SNDRV_CHMAP_FR)) 39*73cd0490STakashi Iwai return -EINVAL; 40*73cd0490STakashi Iwai 41*73cd0490STakashi Iwai return 0; 42*73cd0490STakashi Iwai } 43*73cd0490STakashi Iwai 44*73cd0490STakashi Iwai /* map from pin NID to port; port is 0-based */ 45*73cd0490STakashi Iwai /* for Nvidia: assume widget NID starting from 4, with step 1 (4, 5, 6, ...) */ 46*73cd0490STakashi Iwai static int nvhdmi_pin2port(void *audio_ptr, int pin_nid) 47*73cd0490STakashi Iwai { 48*73cd0490STakashi Iwai return pin_nid - 4; 49*73cd0490STakashi Iwai } 50*73cd0490STakashi Iwai 51*73cd0490STakashi Iwai /* reverse-map from port to pin NID: see above */ 52*73cd0490STakashi Iwai static int nvhdmi_port2pin(struct hda_codec *codec, int port) 53*73cd0490STakashi Iwai { 54*73cd0490STakashi Iwai return port + 4; 55*73cd0490STakashi Iwai } 56*73cd0490STakashi Iwai 57*73cd0490STakashi Iwai static const struct drm_audio_component_audio_ops nvhdmi_audio_ops = { 58*73cd0490STakashi Iwai .pin2port = nvhdmi_pin2port, 59*73cd0490STakashi Iwai .pin_eld_notify = snd_hda_hdmi_acomp_pin_eld_notify, 60*73cd0490STakashi Iwai .master_bind = snd_hda_hdmi_acomp_master_bind, 61*73cd0490STakashi Iwai .master_unbind = snd_hda_hdmi_acomp_master_unbind, 62*73cd0490STakashi Iwai }; 63*73cd0490STakashi Iwai 64*73cd0490STakashi Iwai static int patch_nvhdmi(struct hda_codec *codec) 65*73cd0490STakashi Iwai { 66*73cd0490STakashi Iwai struct hdmi_spec *spec; 67*73cd0490STakashi Iwai int err; 68*73cd0490STakashi Iwai 69*73cd0490STakashi Iwai err = snd_hda_hdmi_generic_alloc(codec); 70*73cd0490STakashi Iwai if (err < 0) 71*73cd0490STakashi Iwai return err; 72*73cd0490STakashi Iwai codec->dp_mst = true; 73*73cd0490STakashi Iwai 74*73cd0490STakashi Iwai spec = codec->spec; 75*73cd0490STakashi Iwai 76*73cd0490STakashi Iwai err = snd_hda_hdmi_parse_codec(codec); 77*73cd0490STakashi Iwai if (err < 0) { 78*73cd0490STakashi Iwai snd_hda_hdmi_generic_spec_free(codec); 79*73cd0490STakashi Iwai return err; 80*73cd0490STakashi Iwai } 81*73cd0490STakashi Iwai 82*73cd0490STakashi Iwai snd_hda_hdmi_generic_init_per_pins(codec); 83*73cd0490STakashi Iwai 84*73cd0490STakashi Iwai spec->dyn_pin_out = true; 85*73cd0490STakashi Iwai 86*73cd0490STakashi Iwai spec->chmap.ops.chmap_cea_alloc_validate_get_type = 87*73cd0490STakashi Iwai nvhdmi_chmap_cea_alloc_validate_get_type; 88*73cd0490STakashi Iwai spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate; 89*73cd0490STakashi Iwai spec->nv_dp_workaround = true; 90*73cd0490STakashi Iwai 91*73cd0490STakashi Iwai codec->link_down_at_suspend = 1; 92*73cd0490STakashi Iwai 93*73cd0490STakashi Iwai snd_hda_hdmi_acomp_init(codec, &nvhdmi_audio_ops, nvhdmi_port2pin); 94*73cd0490STakashi Iwai 95*73cd0490STakashi Iwai return 0; 96*73cd0490STakashi Iwai } 97*73cd0490STakashi Iwai 98*73cd0490STakashi Iwai static int patch_nvhdmi_legacy(struct hda_codec *codec) 99*73cd0490STakashi Iwai { 100*73cd0490STakashi Iwai struct hdmi_spec *spec; 101*73cd0490STakashi Iwai int err; 102*73cd0490STakashi Iwai 103*73cd0490STakashi Iwai err = patch_generic_hdmi(codec); 104*73cd0490STakashi Iwai if (err) 105*73cd0490STakashi Iwai return err; 106*73cd0490STakashi Iwai 107*73cd0490STakashi Iwai spec = codec->spec; 108*73cd0490STakashi Iwai spec->dyn_pin_out = true; 109*73cd0490STakashi Iwai 110*73cd0490STakashi Iwai spec->chmap.ops.chmap_cea_alloc_validate_get_type = 111*73cd0490STakashi Iwai nvhdmi_chmap_cea_alloc_validate_get_type; 112*73cd0490STakashi Iwai spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate; 113*73cd0490STakashi Iwai spec->nv_dp_workaround = true; 114*73cd0490STakashi Iwai 115*73cd0490STakashi Iwai codec->link_down_at_suspend = 1; 116*73cd0490STakashi Iwai 117*73cd0490STakashi Iwai return 0; 118*73cd0490STakashi Iwai } 119*73cd0490STakashi Iwai 120*73cd0490STakashi Iwai /* 121*73cd0490STakashi Iwai * patch entries 122*73cd0490STakashi Iwai */ 123*73cd0490STakashi Iwai static const struct hda_device_id snd_hda_id_nvhdmi[] = { 124*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0008, "GPU 08 HDMI/DP", patch_nvhdmi_legacy), 125*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0009, "GPU 09 HDMI/DP", patch_nvhdmi_legacy), 126*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP", patch_nvhdmi_legacy), 127*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP", patch_nvhdmi_legacy), 128*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI", patch_nvhdmi_legacy), 129*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de000d, "GPU 0d HDMI/DP", patch_nvhdmi_legacy), 130*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0010, "GPU 10 HDMI/DP", patch_nvhdmi_legacy), 131*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0011, "GPU 11 HDMI/DP", patch_nvhdmi_legacy), 132*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0012, "GPU 12 HDMI/DP", patch_nvhdmi_legacy), 133*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0013, "GPU 13 HDMI/DP", patch_nvhdmi_legacy), 134*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0014, "GPU 14 HDMI/DP", patch_nvhdmi_legacy), 135*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0015, "GPU 15 HDMI/DP", patch_nvhdmi_legacy), 136*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0016, "GPU 16 HDMI/DP", patch_nvhdmi_legacy), 137*73cd0490STakashi Iwai /* 17 is known to be absent */ 138*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0018, "GPU 18 HDMI/DP", patch_nvhdmi_legacy), 139*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0019, "GPU 19 HDMI/DP", patch_nvhdmi_legacy), 140*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de001a, "GPU 1a HDMI/DP", patch_nvhdmi_legacy), 141*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de001b, "GPU 1b HDMI/DP", patch_nvhdmi_legacy), 142*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de001c, "GPU 1c HDMI/DP", patch_nvhdmi_legacy), 143*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0040, "GPU 40 HDMI/DP", patch_nvhdmi), 144*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP", patch_nvhdmi), 145*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP", patch_nvhdmi), 146*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0043, "GPU 43 HDMI/DP", patch_nvhdmi), 147*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0044, "GPU 44 HDMI/DP", patch_nvhdmi), 148*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0045, "GPU 45 HDMI/DP", patch_nvhdmi), 149*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0050, "GPU 50 HDMI/DP", patch_nvhdmi), 150*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0051, "GPU 51 HDMI/DP", patch_nvhdmi), 151*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0052, "GPU 52 HDMI/DP", patch_nvhdmi), 152*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0060, "GPU 60 HDMI/DP", patch_nvhdmi), 153*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0061, "GPU 61 HDMI/DP", patch_nvhdmi), 154*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0062, "GPU 62 HDMI/DP", patch_nvhdmi), 155*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0070, "GPU 70 HDMI/DP", patch_nvhdmi), 156*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP", patch_nvhdmi), 157*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP", patch_nvhdmi), 158*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0073, "GPU 73 HDMI/DP", patch_nvhdmi), 159*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0074, "GPU 74 HDMI/DP", patch_nvhdmi), 160*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0076, "GPU 76 HDMI/DP", patch_nvhdmi), 161*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de007b, "GPU 7b HDMI/DP", patch_nvhdmi), 162*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de007c, "GPU 7c HDMI/DP", patch_nvhdmi), 163*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP", patch_nvhdmi), 164*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de007e, "GPU 7e HDMI/DP", patch_nvhdmi), 165*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0080, "GPU 80 HDMI/DP", patch_nvhdmi), 166*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0081, "GPU 81 HDMI/DP", patch_nvhdmi), 167*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0082, "GPU 82 HDMI/DP", patch_nvhdmi), 168*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0083, "GPU 83 HDMI/DP", patch_nvhdmi), 169*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0084, "GPU 84 HDMI/DP", patch_nvhdmi), 170*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0090, "GPU 90 HDMI/DP", patch_nvhdmi), 171*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0091, "GPU 91 HDMI/DP", patch_nvhdmi), 172*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0092, "GPU 92 HDMI/DP", patch_nvhdmi), 173*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0093, "GPU 93 HDMI/DP", patch_nvhdmi), 174*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0094, "GPU 94 HDMI/DP", patch_nvhdmi), 175*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0095, "GPU 95 HDMI/DP", patch_nvhdmi), 176*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0097, "GPU 97 HDMI/DP", patch_nvhdmi), 177*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0098, "GPU 98 HDMI/DP", patch_nvhdmi), 178*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de0099, "GPU 99 HDMI/DP", patch_nvhdmi), 179*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de009a, "GPU 9a HDMI/DP", patch_nvhdmi), 180*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de009b, "GPU 9b HDMI/DP", patch_nvhdmi), 181*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de009c, "GPU 9c HDMI/DP", patch_nvhdmi), 182*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de009d, "GPU 9d HDMI/DP", patch_nvhdmi), 183*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de009e, "GPU 9e HDMI/DP", patch_nvhdmi), 184*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de009f, "GPU 9f HDMI/DP", patch_nvhdmi), 185*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00a0, "GPU a0 HDMI/DP", patch_nvhdmi), 186*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00a1, "GPU a1 HDMI/DP", patch_nvhdmi), 187*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00a3, "GPU a3 HDMI/DP", patch_nvhdmi), 188*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00a4, "GPU a4 HDMI/DP", patch_nvhdmi), 189*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00a5, "GPU a5 HDMI/DP", patch_nvhdmi), 190*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00a6, "GPU a6 HDMI/DP", patch_nvhdmi), 191*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00a7, "GPU a7 HDMI/DP", patch_nvhdmi), 192*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00a8, "GPU a8 HDMI/DP", patch_nvhdmi), 193*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00a9, "GPU a9 HDMI/DP", patch_nvhdmi), 194*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00aa, "GPU aa HDMI/DP", patch_nvhdmi), 195*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00ab, "GPU ab HDMI/DP", patch_nvhdmi), 196*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00ad, "GPU ad HDMI/DP", patch_nvhdmi), 197*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00ae, "GPU ae HDMI/DP", patch_nvhdmi), 198*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00af, "GPU af HDMI/DP", patch_nvhdmi), 199*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00b0, "GPU b0 HDMI/DP", patch_nvhdmi), 200*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00b1, "GPU b1 HDMI/DP", patch_nvhdmi), 201*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00c0, "GPU c0 HDMI/DP", patch_nvhdmi), 202*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00c1, "GPU c1 HDMI/DP", patch_nvhdmi), 203*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00c3, "GPU c3 HDMI/DP", patch_nvhdmi), 204*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00c4, "GPU c4 HDMI/DP", patch_nvhdmi), 205*73cd0490STakashi Iwai HDA_CODEC_ENTRY(0x10de00c5, "GPU c5 HDMI/DP", patch_nvhdmi), 206*73cd0490STakashi Iwai {} /* terminator */ 207*73cd0490STakashi Iwai }; 208*73cd0490STakashi Iwai MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_nvhdmi); 209*73cd0490STakashi Iwai 210*73cd0490STakashi Iwai MODULE_LICENSE("GPL"); 211*73cd0490STakashi Iwai MODULE_DESCRIPTION("Nvidia HDMI HD-audio codec"); 212*73cd0490STakashi Iwai MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI"); 213*73cd0490STakashi Iwai 214*73cd0490STakashi Iwai static struct hda_codec_driver nvhdmi_driver = { 215*73cd0490STakashi Iwai .id = snd_hda_id_nvhdmi, 216*73cd0490STakashi Iwai }; 217*73cd0490STakashi Iwai 218*73cd0490STakashi Iwai module_hda_codec_driver(nvhdmi_driver); 219