diff options
Diffstat (limited to 'sound/pci/hda')
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 64 |
1 files changed, 48 insertions, 16 deletions
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index a134d91db5ff..c85ed7bc121e 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -168,6 +168,8 @@ struct hdmi_spec { bool dyn_pin_out; bool dyn_pcm_assign; bool dyn_pcm_no_legacy; + /* hdmi interrupt trigger control flag for Nvidia codec */ + bool hdmi_intr_trig_ctrl; bool intel_hsw_fixup; /* apply Intel platform-specific fixups */ /* * Non-generic VIA/NVIDIA specific @@ -3797,8 +3799,11 @@ static int patch_nvhdmi_legacy(struct hda_codec *codec) * +-----------------------------------| * * Note that for the trigger bit to take effect it needs to change value - * (i.e. it needs to be toggled). + * (i.e. it needs to be toggled). The trigger bit is not applicable from + * TEGRA234 chip onwards, as new verb id 0xf80 will be used for interrupt + * trigger to hdmi. */ +#define NVIDIA_SET_HOST_INTR 0xf80 #define NVIDIA_GET_SCRATCH0 0xfa6 #define NVIDIA_SET_SCRATCH0_BYTE0 0xfa7 #define NVIDIA_SET_SCRATCH0_BYTE1 0xfa8 @@ -3817,25 +3822,38 @@ static int patch_nvhdmi_legacy(struct hda_codec *codec) * The format parameter is the HDA audio format (see AC_FMT_*). If set to 0, * the format is invalidated so that the HDMI codec can be disabled. */ -static void tegra_hdmi_set_format(struct hda_codec *codec, unsigned int format) +static void tegra_hdmi_set_format(struct hda_codec *codec, + hda_nid_t cvt_nid, + unsigned int format) { unsigned int value; + unsigned int nid = NVIDIA_AFG_NID; + struct hdmi_spec *spec = codec->spec; + + /* + * Tegra HDA codec design from TEGRA234 chip onwards support DP MST. + * This resulted in moving scratch registers from audio function + * group to converter widget context. So CVT NID should be used for + * scratch register read/write for DP MST supported Tegra HDA codec. + */ + if (codec->dp_mst) + nid = cvt_nid; /* bits [31:30] contain the trigger and valid bits */ - value = snd_hda_codec_read(codec, NVIDIA_AFG_NID, 0, + value = snd_hda_codec_read(codec, nid, 0, NVIDIA_GET_SCRATCH0, 0); value = (value >> 24) & 0xff; /* bits [15:0] are used to store the HDA format */ - snd_hda_codec_write(codec, NVIDIA_AFG_NID, 0, + snd_hda_codec_write(codec, nid, 0, NVIDIA_SET_SCRATCH0_BYTE0, (format >> 0) & 0xff); - snd_hda_codec_write(codec, NVIDIA_AFG_NID, 0, + snd_hda_codec_write(codec, nid, 0, NVIDIA_SET_SCRATCH0_BYTE1, (format >> 8) & 0xff); /* bits [16:24] are unused */ - snd_hda_codec_write(codec, NVIDIA_AFG_NID, 0, + snd_hda_codec_write(codec, nid, 0, NVIDIA_SET_SCRATCH0_BYTE2, 0); /* @@ -3847,15 +3865,28 @@ static void tegra_hdmi_set_format(struct hda_codec *codec, unsigned int format) else value |= NVIDIA_SCRATCH_VALID; - /* - * Whenever the trigger bit is toggled, an interrupt is raised in the - * HDMI codec. The HDMI driver will use that as trigger to update its - * configuration. - */ - value ^= NVIDIA_SCRATCH_TRIGGER; + if (spec->hdmi_intr_trig_ctrl) { + /* + * For Tegra HDA Codec design from TEGRA234 onwards, the + * Interrupt to hdmi driver is triggered by writing + * non-zero values to verb 0xF80 instead of 31st bit of + * scratch register. + */ + snd_hda_codec_write(codec, nid, 0, + NVIDIA_SET_SCRATCH0_BYTE3, value); + snd_hda_codec_write(codec, nid, 0, + NVIDIA_SET_HOST_INTR, 0x1); + } else { + /* + * Whenever the 31st trigger bit is toggled, an interrupt is raised + * in the HDMI codec. The HDMI driver will use that as trigger + * to update its configuration. + */ + value ^= NVIDIA_SCRATCH_TRIGGER; - snd_hda_codec_write(codec, NVIDIA_AFG_NID, 0, - NVIDIA_SET_SCRATCH0_BYTE3, value); + snd_hda_codec_write(codec, nid, 0, + NVIDIA_SET_SCRATCH0_BYTE3, value); + } } static int tegra_hdmi_pcm_prepare(struct hda_pcm_stream *hinfo, @@ -3872,7 +3903,7 @@ static int tegra_hdmi_pcm_prepare(struct hda_pcm_stream *hinfo, return err; /* notify the HDMI codec of the format change */ - tegra_hdmi_set_format(codec, format); + tegra_hdmi_set_format(codec, hinfo->nid, format); return 0; } @@ -3882,7 +3913,7 @@ static int tegra_hdmi_pcm_cleanup(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { /* invalidate the format in the HDMI codec */ - tegra_hdmi_set_format(codec, 0); + tegra_hdmi_set_format(codec, hinfo->nid, 0); return generic_hdmi_playback_pcm_cleanup(hinfo, codec, substream); } @@ -3982,6 +4013,7 @@ static int patch_tegra234_hdmi(struct hda_codec *codec) spec = codec->spec; spec->dyn_pin_out = true; spec->dyn_pcm_assign = true; + spec->hdmi_intr_trig_ctrl = true; return tegra_hdmi_init(codec); } |