fixed_mode->vdisplay);
 }
 
-void icl_dsi_init(struct drm_i915_private *dev_priv)
+void icl_dsi_init(struct drm_i915_private *dev_priv,
+                 const struct intel_bios_encoder_data *devdata)
 {
        struct intel_dsi *intel_dsi;
        struct intel_encoder *encoder;
        struct drm_connector *connector;
        enum port port;
 
-       if (!intel_bios_is_dsi_present(dev_priv, &port))
+       port = intel_bios_encoder_port(devdata);
+       if (port == PORT_NONE)
                return;
 
        intel_dsi = kzalloc(sizeof(*intel_dsi), GFP_KERNEL);
        intel_dsi->attached_connector = intel_connector;
        connector = &intel_connector->base;
 
+       encoder->devdata = devdata;
+
        /* register DSI encoder with DRM subsystem */
        drm_encoder_init(&dev_priv->drm, &encoder->base, &gen11_dsi_encoder_funcs,
                         DRM_MODE_ENCODER_DSI, "DSI %c", port_name(port));
 
        intel_dsi->panel_power_off_time = ktime_get_boottime();
 
-       encoder->devdata = intel_bios_encoder_data_lookup(dev_priv, port);
        intel_bios_init_panel_late(dev_priv, &intel_connector->panel, encoder->devdata, NULL);
 
        mutex_lock(&dev_priv->drm.mode_config.mutex);
 
 #define __ICL_DSI_H__
 
 struct drm_i915_private;
+struct intel_bios_encoder_data;
 struct intel_crtc_state;
 
-void icl_dsi_init(struct drm_i915_private *i915);
+void icl_dsi_init(struct drm_i915_private *dev_priv,
+                 const struct intel_bios_encoder_data *devdata);
 void icl_dsi_frame_update(struct intel_crtc_state *crtc_state);
 
 #endif /* __ICL_DSI_H__ */
 
        }
 }
 
-static enum port intel_bios_encoder_port(const struct intel_bios_encoder_data *devdata)
+enum port intel_bios_encoder_port(const struct intel_bios_encoder_data *devdata)
 {
        struct drm_i915_private *i915 = devdata->i915;
        const struct child_device_config *child = &devdata->child;
                devdata->child.device_type & DEVICE_TYPE_INTERNAL_CONNECTOR;
 }
 
-static bool
+bool
 intel_bios_encoder_supports_dsi(const struct intel_bios_encoder_data *devdata)
 {
        return devdata->child.device_type & DEVICE_TYPE_MIPI_OUTPUT;
        return true;
 }
 
-static void print_ddi_port(const struct intel_bios_encoder_data *devdata,
-                          enum port port)
+static void print_ddi_port(const struct intel_bios_encoder_data *devdata)
 {
        struct drm_i915_private *i915 = devdata->i915;
        const struct child_device_config *child = &devdata->child;
        bool is_dvi, is_hdmi, is_dp, is_edp, is_dsi, is_crt, supports_typec_usb, supports_tbt;
        int dp_boost_level, dp_max_link_rate, hdmi_boost_level, hdmi_level_shift, max_tmds_clock;
+       enum port port;
+
+       port = intel_bios_encoder_port(devdata);
+       if (port == PORT_NONE)
+               return;
 
        is_dvi = intel_bios_encoder_supports_dvi(devdata);
        is_dp = intel_bios_encoder_supports_dp(devdata);
                return;
        }
 
-       if (i915->display.vbt.ports[port]) {
-               drm_dbg_kms(&i915->drm,
-                           "More than one child device for port %c in VBT, using the first.\n",
-                           port_name(port));
-               return;
-       }
-
        sanitize_device_type(devdata, port);
-
-       i915->display.vbt.ports[port] = devdata;
 }
 
 static bool has_ddi_port_info(struct drm_i915_private *i915)
 static void parse_ddi_ports(struct drm_i915_private *i915)
 {
        struct intel_bios_encoder_data *devdata;
-       enum port port;
 
        if (!has_ddi_port_info(i915))
                return;
        list_for_each_entry(devdata, &i915->display.vbt.display_devices, node)
                parse_ddi_port(devdata);
 
-       for_each_port(port) {
-               if (i915->display.vbt.ports[port])
-                       print_ddi_port(i915->display.vbt.ports[port], port);
-       }
+       list_for_each_entry(devdata, &i915->display.vbt.display_devices, node)
+               print_ddi_port(devdata);
 }
 
 static void
 const struct intel_bios_encoder_data *
 intel_bios_encoder_data_lookup(struct drm_i915_private *i915, enum port port)
 {
-       return i915->display.vbt.ports[port];
+       struct intel_bios_encoder_data *devdata;
+
+       list_for_each_entry(devdata, &i915->display.vbt.display_devices, node) {
+               if (intel_bios_encoder_port(devdata) == port)
+                       return devdata;
+       }
+
+       return NULL;
+}
+
+void intel_bios_for_each_encoder(struct drm_i915_private *i915,
+                                void (*func)(struct drm_i915_private *i915,
+                                             const struct intel_bios_encoder_data *devdata))
+{
+       struct intel_bios_encoder_data *devdata;
+
+       list_for_each_entry(devdata, &i915->display.vbt.display_devices, node)
+               func(i915, devdata);
 }
 
 bool intel_bios_encoder_supports_edp(const struct intel_bios_encoder_data *devdata);
 bool intel_bios_encoder_supports_typec_usb(const struct intel_bios_encoder_data *devdata);
 bool intel_bios_encoder_supports_tbt(const struct intel_bios_encoder_data *devdata);
+bool intel_bios_encoder_supports_dsi(const struct intel_bios_encoder_data *devdata);
 bool intel_bios_encoder_supports_dp_dual_mode(const struct intel_bios_encoder_data *devdata);
 bool intel_bios_encoder_is_lspcon(const struct intel_bios_encoder_data *devdata);
 bool intel_bios_encoder_lane_reversal(const struct intel_bios_encoder_data *devdata);
 bool intel_bios_encoder_hpd_invert(const struct intel_bios_encoder_data *devdata);
+enum port intel_bios_encoder_port(const struct intel_bios_encoder_data *devdata);
 enum aux_ch intel_bios_dp_aux_ch(const struct intel_bios_encoder_data *devdata);
 int intel_bios_dp_boost_level(const struct intel_bios_encoder_data *devdata);
 int intel_bios_dp_max_lane_count(const struct intel_bios_encoder_data *devdata);
 int intel_bios_hdmi_level_shift(const struct intel_bios_encoder_data *devdata);
 int intel_bios_hdmi_max_tmds_clock(const struct intel_bios_encoder_data *devdata);
 
+void intel_bios_for_each_encoder(struct drm_i915_private *i915,
+                                void (*func)(struct drm_i915_private *i915,
+                                             const struct intel_bios_encoder_data *devdata));
+
 #endif /* _INTEL_BIOS_H_ */
 
 
 #include "i915_drv.h"
 #include "i915_reg.h"
+#include "icl_dsi.h"
 #include "intel_audio.h"
 #include "intel_audio_regs.h"
 #include "intel_backlight.h"
        return init_dp || intel_phy_is_tc(i915, phy);
 }
 
-void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
+static bool assert_has_icl_dsi(struct drm_i915_private *i915)
+{
+       return !drm_WARN(&i915->drm, !IS_ALDERLAKE_P(i915) &&
+                        !IS_TIGERLAKE(i915) && DISPLAY_VER(i915) != 11,
+                        "Platform does not support DSI\n");
+}
+
+static bool port_in_use(struct drm_i915_private *i915, enum port port)
+{
+       struct intel_encoder *encoder;
+
+       for_each_intel_encoder(&i915->drm, encoder) {
+               /* FIXME what about second port for dual link DSI? */
+               if (encoder->port == port)
+                       return true;
+       }
+
+       return false;
+}
+
+void intel_ddi_init(struct drm_i915_private *dev_priv,
+                   const struct intel_bios_encoder_data *devdata)
 {
        struct intel_digital_port *dig_port;
        struct intel_encoder *encoder;
-       const struct intel_bios_encoder_data *devdata;
        bool init_hdmi, init_dp;
-       enum phy phy = intel_port_to_phy(dev_priv, port);
+       enum port port;
+       enum phy phy;
+
+       port = intel_bios_encoder_port(devdata);
+       if (port == PORT_NONE)
+               return;
 
        if (!port_strap_detected(dev_priv, port)) {
                drm_dbg_kms(&dev_priv->drm,
        if (!assert_port_valid(dev_priv, port))
                return;
 
+       if (port_in_use(dev_priv, port)) {
+               drm_dbg_kms(&dev_priv->drm,
+                           "Port %c already claimed\n", port_name(port));
+               return;
+       }
+
+       if (intel_bios_encoder_supports_dsi(devdata)) {
+               /* BXT/GLK handled elsewhere, for now at least */
+               if (!assert_has_icl_dsi(dev_priv))
+                       return;
+
+               icl_dsi_init(dev_priv, devdata);
+               return;
+       }
+
+       phy = intel_port_to_phy(dev_priv, port);
+
        /*
         * On platforms with HTI (aka HDPORT), if it's enabled at boot it may
         * have taken over some of the PHYs and made them unavailable to the
                return;
        }
 
-       devdata = intel_bios_encoder_data_lookup(dev_priv, port);
-       if (!devdata) {
-               drm_dbg_kms(&dev_priv->drm,
-                           "VBT says port %c is not present\n",
-                           port_name(port));
-               return;
-       }
-
        init_hdmi = intel_bios_encoder_supports_dvi(devdata) ||
                intel_bios_encoder_supports_hdmi(devdata);
        init_dp = intel_bios_encoder_supports_dp(devdata);
 
 struct drm_connector_state;
 struct drm_i915_private;
 struct intel_atomic_state;
+struct intel_bios_encoder_data;
 struct intel_connector;
 struct intel_crtc;
 struct intel_crtc_state;
                                const struct intel_crtc_state *crtc_state);
 void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv,
                             enum port port);
-void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port);
+void intel_ddi_init(struct drm_i915_private *dev_priv,
+                   const struct intel_bios_encoder_data *devdata);
 bool intel_ddi_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe);
 void intel_ddi_enable_transcoder_func(struct intel_encoder *encoder,
                                      const struct intel_crtc_state *crtc_state);
 
 #include "i915_utils.h"
 #include "i9xx_plane.h"
 #include "i9xx_wm.h"
-#include "icl_dsi.h"
 #include "intel_atomic.h"
 #include "intel_atomic_plane.h"
 #include "intel_audio.h"
                return;
 
        if (HAS_DDI(dev_priv)) {
-               enum port port;
-
                if (intel_ddi_crt_present(dev_priv))
                        intel_crt_init(dev_priv);
 
-               for_each_port_masked(port, DISPLAY_RUNTIME_INFO(dev_priv)->port_mask)
-                       intel_ddi_init(dev_priv, port);
-
-               /* FIXME do something about DSI */
-               if (IS_ALDERLAKE_P(dev_priv) || IS_TIGERLAKE(dev_priv) ||
-                   DISPLAY_VER(dev_priv) == 11)
-                       icl_dsi_init(dev_priv);
+               intel_bios_for_each_encoder(dev_priv, intel_ddi_init);
 
                if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv))
                        vlv_dsi_init(dev_priv);
 
 struct i915_hdcp_arbiter;
 struct intel_atomic_state;
 struct intel_audio_funcs;
-struct intel_bios_encoder_data;
 struct intel_cdclk_funcs;
 struct intel_cdclk_vals;
 struct intel_color_funcs;
        struct list_head display_devices;
        struct list_head bdb_blocks;
 
-       struct intel_bios_encoder_data *ports[I915_MAX_PORTS]; /* Non-NULL if port present. */
        struct sdvo_device_mapping {
                u8 initialized;
                u8 dvo_port;