ALSA: hda - Add DP-MST support for non-acomp codecs
[linux-2.6-block.git] / sound / pci / hda / patch_hdmi.c
index 37b4345afdde26b9832823c6de9a9f47fbe9cdb0..0a3045d492975fe0643fa8b0c8fa29d9467df30f 100644 (file)
@@ -80,16 +80,19 @@ struct hdmi_spec_per_pin {
 /* operations used by generic code that can be overridden by patches */
 struct hdmi_ops {
        int (*pin_get_eld)(struct hda_codec *codec, hda_nid_t pin_nid,
-                          unsigned char *buf, int *eld_size);
+                          int dev_id, unsigned char *buf, int *eld_size);
 
        void (*pin_setup_infoframe)(struct hda_codec *codec, hda_nid_t pin_nid,
+                                   int dev_id,
                                    int ca, int active_channels, int conn_type);
 
        /* enable/disable HBR (HD passthrough) */
-       int (*pin_hbr_setup)(struct hda_codec *codec, hda_nid_t pin_nid, bool hbr);
+       int (*pin_hbr_setup)(struct hda_codec *codec, hda_nid_t pin_nid,
+                            int dev_id, bool hbr);
 
        int (*setup_stream)(struct hda_codec *codec, hda_nid_t cvt_nid,
-                           hda_nid_t pin_nid, u32 stream_tag, int format);
+                           hda_nid_t pin_nid, int dev_id, u32 stream_tag,
+                           int format);
 
        void (*pin_cvt_fixup)(struct hda_codec *codec,
                              struct hdmi_spec_per_pin *per_pin,
@@ -636,8 +639,16 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
        return true;
 }
 
+static int hdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid,
+                           int dev_id, unsigned char *buf, int *eld_size)
+{
+       snd_hda_set_dev_select(codec, nid, dev_id);
+
+       return snd_hdmi_get_eld(codec, nid, buf, eld_size);
+}
+
 static void hdmi_pin_setup_infoframe(struct hda_codec *codec,
-                                    hda_nid_t pin_nid,
+                                    hda_nid_t pin_nid, int dev_id,
                                     int ca, int active_channels,
                                     int conn_type)
 {
@@ -667,6 +678,8 @@ static void hdmi_pin_setup_infoframe(struct hda_codec *codec,
                return;
        }
 
+       snd_hda_set_dev_select(codec, pin_nid, dev_id);
+
        /*
         * sizeof(ai) is used instead of sizeof(*hdmi_ai) or
         * sizeof(*dp_ai) to avoid partial match/update problems when
@@ -692,6 +705,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
        struct hdmi_spec *spec = codec->spec;
        struct hdac_chmap *chmap = &spec->chmap;
        hda_nid_t pin_nid = per_pin->pin_nid;
+       int dev_id = per_pin->dev_id;
        int channels = per_pin->channels;
        int active_channels;
        struct hdmi_eld *eld;
@@ -700,6 +714,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
        if (!channels)
                return;
 
+       snd_hda_set_dev_select(codec, pin_nid, dev_id);
+
        /* some HW (e.g. HSW+) needs reprogramming the amp at each time */
        if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
                snd_hda_codec_write(codec, pin_nid, 0,
@@ -725,8 +741,8 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
                                pin_nid, non_pcm, ca, channels,
                                per_pin->chmap, per_pin->chmap_set);
 
-       spec->ops.pin_setup_infoframe(codec, pin_nid, ca, active_channels,
-                                     eld->info.conn_type);
+       spec->ops.pin_setup_infoframe(codec, pin_nid, dev_id,
+                                     ca, active_channels, eld->info.conn_type);
 
        per_pin->non_pcm = non_pcm;
 }
@@ -868,11 +884,12 @@ static void haswell_verify_D0(struct hda_codec *codec,
        ((format & AC_FMT_TYPE_NON_PCM) && (format & AC_FMT_CHAN_MASK) == 7)
 
 static int hdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
-                             bool hbr)
+                             int dev_id, bool hbr)
 {
        int pinctl, new_pinctl;
 
        if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) {
+               snd_hda_set_dev_select(codec, pin_nid, dev_id);
                pinctl = snd_hda_codec_read(codec, pin_nid, 0,
                                            AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
 
@@ -902,13 +919,15 @@ static int hdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
 }
 
 static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
-                             hda_nid_t pin_nid, u32 stream_tag, int format)
+                             hda_nid_t pin_nid, int dev_id,
+                             u32 stream_tag, int format)
 {
        struct hdmi_spec *spec = codec->spec;
        unsigned int param;
        int err;
 
-       err = spec->ops.pin_hbr_setup(codec, pin_nid, is_hbr_format(format));
+       err = spec->ops.pin_hbr_setup(codec, pin_nid, dev_id,
+                                     is_hbr_format(format));
 
        if (err) {
                codec_dbg(codec, "hdmi_setup_stream: HBR is not supported\n");
@@ -1282,6 +1301,7 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
        struct hdmi_spec *spec = codec->spec;
        struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
        hda_nid_t pin_nid = per_pin->pin_nid;
+       int dev_id = per_pin->dev_id;
 
        if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) {
                codec_warn(codec,
@@ -1290,10 +1310,12 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
                return -EINVAL;
        }
 
+       snd_hda_set_dev_select(codec, pin_nid, dev_id);
+
        /* all the device entries on the same pin have the same conn list */
-       per_pin->num_mux_nids = snd_hda_get_connections(codec, pin_nid,
-                                                       per_pin->mux_nids,
-                                                       HDA_MAX_CONNECTIONS);
+       per_pin->num_mux_nids =
+               snd_hda_get_raw_connections(codec, pin_nid, per_pin->mux_nids,
+                                           HDA_MAX_CONNECTIONS);
 
        return 0;
 }
@@ -1501,6 +1523,7 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
        struct hdmi_spec *spec = codec->spec;
        struct hdmi_eld *eld = &spec->temp_eld;
        hda_nid_t pin_nid = per_pin->pin_nid;
+       int dev_id = per_pin->dev_id;
        /*
         * Always execute a GetPinSense verb here, even when called from
         * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited
@@ -1513,7 +1536,7 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
        bool ret;
        bool do_repoll = false;
 
-       present = snd_hda_jack_pin_sense(codec, pin_nid, per_pin->dev_id);
+       present = snd_hda_jack_pin_sense(codec, pin_nid, dev_id);
 
        mutex_lock(&per_pin->lock);
        eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
@@ -1527,8 +1550,8 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
                codec->addr, pin_nid, eld->monitor_present, eld->eld_valid);
 
        if (eld->eld_valid) {
-               if (spec->ops.pin_get_eld(codec, pin_nid, eld->eld_buffer,
-                                                    &eld->eld_size) < 0)
+               if (spec->ops.pin_get_eld(codec, pin_nid, dev_id,
+                                         eld->eld_buffer, &eld->eld_size) < 0)
                        eld->eld_valid = false;
                else {
                        if (snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer,
@@ -1865,7 +1888,6 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
        struct hdmi_spec *spec = codec->spec;
        int pin_idx;
        struct hdmi_spec_per_pin *per_pin;
-       hda_nid_t pin_nid;
        struct snd_pcm_runtime *runtime = substream->runtime;
        bool non_pcm;
        int pinctl, stripe;
@@ -1889,7 +1911,6 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
                goto unlock;
        }
        per_pin = get_pin(spec, pin_idx);
-       pin_nid = per_pin->pin_nid;
 
        /* Verify pin:cvt selections to avoid silent audio after S3.
         * After S3, the audio driver restores pin:cvt selections
@@ -1904,8 +1925,8 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
        /* Call sync_audio_rate to set the N/CTS/M manually if necessary */
        /* Todo: add DP1.2 MST audio support later */
        if (codec_has_acomp(codec))
-               snd_hdac_sync_audio_rate(&codec->core, pin_nid, per_pin->dev_id,
-                                        runtime->rate);
+               snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid,
+                                        per_pin->dev_id, runtime->rate);
 
        non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
        mutex_lock(&per_pin->lock);
@@ -1923,16 +1944,18 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
        hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
        mutex_unlock(&per_pin->lock);
        if (spec->dyn_pin_out) {
-               pinctl = snd_hda_codec_read(codec, pin_nid, 0,
+               snd_hda_set_dev_select(codec, per_pin->pin_nid,
+                                      per_pin->dev_id);
+               pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
                                            AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-               snd_hda_codec_write(codec, pin_nid, 0,
+               snd_hda_codec_write(codec, per_pin->pin_nid, 0,
                                    AC_VERB_SET_PIN_WIDGET_CONTROL,
                                    pinctl | PIN_OUT);
        }
 
        /* snd_hda_set_dev_select() has been called before */
-       err = spec->ops.setup_stream(codec, cvt_nid, pin_nid,
-                                stream_tag, format);
+       err = spec->ops.setup_stream(codec, cvt_nid, per_pin->pin_nid,
+                                    per_pin->dev_id, stream_tag, format);
  unlock:
        mutex_unlock(&spec->pcm_lock);
        return err;
@@ -1984,6 +2007,8 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
                per_pin = get_pin(spec, pin_idx);
 
                if (spec->dyn_pin_out) {
+                       snd_hda_set_dev_select(codec, per_pin->pin_nid,
+                                              per_pin->dev_id);
                        pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
                                        AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
                        snd_hda_codec_write(codec, per_pin->pin_nid, 0,
@@ -2370,7 +2395,7 @@ static const struct hda_codec_ops generic_hdmi_patch_ops = {
 };
 
 static const struct hdmi_ops generic_standard_hdmi_ops = {
-       .pin_get_eld                            = snd_hdmi_get_eld,
+       .pin_get_eld                            = hdmi_pin_get_eld,
        .pin_setup_infoframe                    = hdmi_pin_setup_infoframe,
        .pin_hbr_setup                          = hdmi_pin_hbr_setup,
        .setup_stream                           = hdmi_setup_stream,
@@ -2568,7 +2593,8 @@ static void intel_haswell_fixup_connect_list(struct hda_codec *codec,
        hda_nid_t conns[4];
        int nconns;
 
-       nconns = snd_hda_get_connections(codec, nid, conns, ARRAY_SIZE(conns));
+       nconns = snd_hda_get_raw_connections(codec, nid, conns,
+                                            ARRAY_SIZE(conns));
        if (nconns == spec->num_cvts &&
            !memcmp(conns, spec->cvt_nids, spec->num_cvts * sizeof(hda_nid_t)))
                return;
@@ -2744,10 +2770,12 @@ static void register_i915_notifier(struct hda_codec *codec)
 
 /* setup_stream ops override for HSW+ */
 static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
-                                hda_nid_t pin_nid, u32 stream_tag, int format)
+                                hda_nid_t pin_nid, int dev_id, u32 stream_tag,
+                                int format)
 {
        haswell_verify_D0(codec, cvt_nid, pin_nid);
-       return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
+       return hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
+                                stream_tag, format);
 }
 
 /* pin_cvt_fixup ops override for HSW+ and VLV+ */
@@ -3713,16 +3741,19 @@ static int patch_tegra_hdmi(struct hda_codec *codec)
 #define ATI_HBR_ENABLE 0x10
 
 static int atihdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid,
-                          unsigned char *buf, int *eld_size)
+                              int dev_id, unsigned char *buf, int *eld_size)
 {
+       WARN_ON(dev_id != 0);
        /* call hda_eld.c ATI/AMD-specific function */
        return snd_hdmi_get_eld_ati(codec, nid, buf, eld_size,
                                    is_amdhdmi_rev3_or_later(codec));
 }
 
-static void atihdmi_pin_setup_infoframe(struct hda_codec *codec, hda_nid_t pin_nid, int ca,
+static void atihdmi_pin_setup_infoframe(struct hda_codec *codec,
+                                       hda_nid_t pin_nid, int dev_id, int ca,
                                        int active_channels, int conn_type)
 {
+       WARN_ON(dev_id != 0);
        snd_hda_codec_write(codec, pin_nid, 0, ATI_VERB_SET_CHANNEL_ALLOCATION, ca);
 }
 
@@ -3913,10 +3944,12 @@ static void atihdmi_paired_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap,
 }
 
 static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
-                                bool hbr)
+                                int dev_id, bool hbr)
 {
        int hbr_ctl, hbr_ctl_new;
 
+       WARN_ON(dev_id != 0);
+
        hbr_ctl = snd_hda_codec_read(codec, pin_nid, 0, ATI_VERB_GET_HBR_CONTROL, 0);
        if (hbr_ctl >= 0 && (hbr_ctl & ATI_HBR_CAPABLE)) {
                if (hbr)
@@ -3942,9 +3975,9 @@ static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
 }
 
 static int atihdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
-                               hda_nid_t pin_nid, u32 stream_tag, int format)
+                               hda_nid_t pin_nid, int dev_id,
+                               u32 stream_tag, int format)
 {
-
        if (is_amdhdmi_rev3_or_later(codec)) {
                int ramp_rate = 180; /* default as per AMD spec */
                /* disable ramp-up/down for non-pcm as per AMD spec */
@@ -3954,7 +3987,8 @@ static int atihdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
                snd_hda_codec_write(codec, cvt_nid, 0, ATI_VERB_SET_RAMP_RATE, ramp_rate);
        }
 
-       return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
+       return hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
+                                stream_tag, format);
 }