OSDN Git Service

ALSA: hda/tegra: Update scratch reg. communication
authorMohan Kumar <mkumard@nvidia.com>
Wed, 16 Feb 2022 09:22:37 +0000 (14:52 +0530)
committerTakashi Iwai <tiwai@suse.de>
Mon, 21 Feb 2022 10:03:37 +0000 (11:03 +0100)
Tegra234 chip scratch register communication between audio
and hdmi driver differs slightly in the way it triggers the
interrupt compared to legacy chips. Interrupt is triggered
by writing non-zero values to verb 0xF80 instead of 31st bit
of scratch register.

DP MST support changed the NID to be used for scratch register
read/write from audio function group NID to Converter widget NID.

Signed-off-by: Mohan Kumar <mkumard@nvidia.com>
Link: https://lore.kernel.org/r/20220216092240.26464-4-mkumard@nvidia.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/patch_hdmi.c

index a134d91..c85ed7b 100644 (file)
@@ -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);
 }