From: Paulo Zanoni <paulo.r.zanoni at intel.com> Now intel_ddi_init is just like intel_hdmi_init and intel_dp_init: it inits the encoder and then calls the proper init_connector functions. Notice that for non-eDP ports we call both HDMI and DP connector init, so we have 2 connectors attached to each DDI encoder. We had to add some wrappers to choose which function we need to call based on the connector connected, so a few HDMI/DP functions had to become non-static. And since the drm_encoder_{,helper_}funcs are now inside intel_ddi.c we also made some DDI functions become static. Besides this, the only change is that now when we detect a connector we write intel_encoder->type with the detected type. This should not break older code because on this case we will just rewrite the value that's already written there. Now we can finally use both DP and HDMI on the same port on Haswell. Signed-off-by: Paulo Zanoni <paulo.r.zanoni at intel.com> --- drivers/gpu/drm/i915/intel_ddi.c | 155 +++++++++++++++++++++++++++++--------- drivers/gpu/drm/i915/intel_dp.c | 32 +++----- drivers/gpu/drm/i915/intel_drv.h | 20 +++-- drivers/gpu/drm/i915/intel_hdmi.c | 28 +++---- 4 files changed, 155 insertions(+), 80 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index c884b5c..458ebbd 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -221,38 +221,6 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) DRM_DEBUG_KMS("FDI train done.\n"); } -/* For DDI connections, it is possible to support different outputs over the - * same DDI port, such as HDMI or DP or even VGA via FDI. So we don't know by - * the time the output is detected what exactly is on the other end of it. This - * function aims at providing support for this detection and proper output - * configuration. - */ -void intel_ddi_init(struct drm_device *dev, enum port port) -{ - /* For now, we don't do any proper output detection and assume that we - * handle HDMI only */ - - switch(port){ - case PORT_A: - /* We don't handle eDP and DP yet */ - DRM_DEBUG_DRIVER("Found digital output on DDI port A\n"); - intel_dp_init(dev, DDI_BUF_CTL_A, PORT_A); - break; - /* Assume that the ports B, C and D are working in HDMI mode for now */ - case PORT_B: - intel_dp_init(dev, DDI_BUF_CTL(port), port); - break; - case PORT_C: - case PORT_D: - intel_hdmi_init(dev, DDI_BUF_CTL(port), port); - break; - default: - DRM_DEBUG_DRIVER("No handlers defined for port %d, skipping DDI initialization\n", - port); - break; - } -} - /* WRPLL clock dividers */ struct wrpll_tmds_clock { u32 clock; @@ -897,9 +865,9 @@ static void intel_ddi_enable_pipe(struct intel_encoder *intel_encoder) } } -void intel_ddi_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static void intel_ddi_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { struct drm_crtc *crtc = encoder->crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -949,7 +917,7 @@ static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, DRM_ERROR("Timeout waiting for DDI BUF %c idle bit\n", port_name(port)); } -void intel_ddi_dpms(struct drm_encoder *encoder, int mode) +static void intel_ddi_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -957,6 +925,11 @@ void intel_ddi_dpms(struct drm_encoder *encoder, int mode) int port = intel_dig_port->port; u32 temp; + if (intel_dig_port->base.type != INTEL_OUTPUT_HDMI) { + intel_dp_dpms(encoder, mode); + return; + } + temp = I915_READ(DDI_BUF_CTL(port)); if (mode != DRM_MODE_DPMS_ON) { @@ -976,7 +949,7 @@ void intel_ddi_dpms(struct drm_encoder *encoder, int mode) intel_wait_ddi_buf_idle(dev_priv, port); } -void intel_ddi_commit(struct drm_encoder *encoder) +static void intel_ddi_commit(struct drm_encoder *encoder) { struct intel_encoder *intel_encoder = to_intel_encoder(encoder); @@ -1176,3 +1149,111 @@ void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder) intel_ddi_enable_pipe(intel_encoder); (*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_ON); } + +static void intel_ddi_hot_plug(struct intel_encoder *intel_encoder) +{ + struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base); + + if (intel_encoder->type != INTEL_OUTPUT_HDMI) + intel_dp_check_link_status(intel_dp); +} + +static void intel_ddi_destroy(struct drm_encoder *encoder) +{ + /* HDMI has nothing special to destroy, so we can go with this. */ + intel_dp_encoder_destroy(encoder); +} + +static bool intel_ddi_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct intel_encoder *intel_encoder = to_intel_encoder(encoder); + + if (intel_encoder->type == INTEL_OUTPUT_UNKNOWN) + WARN(1, "mode_fixup() on unknown output!\n"); + + if (intel_encoder->type == INTEL_OUTPUT_HDMI) + return intel_hdmi_mode_fixup(encoder, mode, adjusted_mode); + else + return intel_dp_mode_fixup(encoder, mode, adjusted_mode); +} + +static void intel_ddi_prepare(struct drm_encoder *encoder) +{ + struct intel_encoder *intel_encoder = to_intel_encoder(encoder); + + if (intel_encoder->type == INTEL_OUTPUT_UNKNOWN) + WARN(1, "ddi_prepare_fixup() on unknown output!\n"); + + if (intel_encoder->type == INTEL_OUTPUT_HDMI) + intel_encoder_prepare(encoder); + else + intel_dp_prepare(encoder); +} + +static const struct drm_encoder_funcs intel_ddi_funcs = { + .destroy = intel_ddi_destroy, +}; + +static const struct drm_encoder_helper_funcs intel_ddi_helper_funcs = { + .dpms = intel_ddi_dpms, + .mode_fixup = intel_ddi_mode_fixup, + .prepare = intel_ddi_prepare, + .mode_set = intel_ddi_mode_set, + .commit = intel_ddi_commit, + .disable = intel_ddi_disable, +}; + +void intel_ddi_init(struct drm_device *dev, enum port port) +{ + struct intel_digital_port *intel_dig_port; + struct intel_encoder *intel_encoder; + struct drm_encoder *encoder; + struct intel_connector *hdmi_connector = NULL; + struct intel_connector *dp_connector = NULL; + + intel_dig_port = kzalloc(sizeof(struct intel_digital_port), GFP_KERNEL); + if (!intel_dig_port) + return; + + if (port != PORT_A) { + hdmi_connector = kzalloc(sizeof(struct intel_connector), + GFP_KERNEL); + if (!hdmi_connector) { + kfree(intel_dig_port); + return; + } + } + + dp_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); + if (!dp_connector) { + kfree(intel_dig_port); + if (hdmi_connector) + kfree(hdmi_connector); + return; + } + + intel_encoder = &intel_dig_port->base; + encoder = &intel_encoder->base; + + drm_encoder_init(dev, encoder, &intel_ddi_funcs, + DRM_MODE_ENCODER_TMDS); + drm_encoder_helper_add(encoder, &intel_ddi_helper_funcs); + + intel_dig_port->port = port; + if (hdmi_connector) + intel_dig_port->hdmi.sdvox_reg = DDI_BUF_CTL(port); + else + intel_dig_port->hdmi.sdvox_reg = 0; + intel_dig_port->dp.output_reg = DDI_BUF_CTL(port); + + intel_encoder->type = INTEL_OUTPUT_UNKNOWN; + intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); + intel_encoder->cloneable = false; + intel_encoder->hot_plug = intel_ddi_hot_plug; + + if (hdmi_connector) + intel_hdmi_init_connector(intel_dig_port, hdmi_connector); + intel_dp_init_connector(intel_dig_port, dp_connector); +} diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6cf3123..f0559d9 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -699,7 +699,7 @@ intel_dp_i2c_init(struct intel_dp *intel_dp, return ret; } -static bool +bool intel_dp_mode_fixup(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -1294,7 +1294,7 @@ static void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode) } } -static void intel_dp_prepare(struct drm_encoder *encoder) +void intel_dp_prepare(struct drm_encoder *encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); @@ -1328,7 +1328,7 @@ void intel_dp_commit(struct drm_encoder *encoder) intel_cpt_verify_modeset(dev, intel_crtc->pipe); } -static void +void intel_dp_dpms(struct drm_encoder *encoder, int mode) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); @@ -2159,7 +2159,7 @@ intel_dp_handle_test_request(struct intel_dp *intel_dp) * 4. Check link status on receipt of hot-plug interrupt */ -static void +void intel_dp_check_link_status(struct intel_dp *intel_dp) { struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base; @@ -2313,6 +2313,8 @@ static enum drm_connector_status intel_dp_detect(struct drm_connector *connector, bool force) { struct intel_dp *intel_dp = intel_attached_dp(connector); + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct intel_encoder *intel_encoder = &intel_dig_port->base; struct drm_device *dev = connector->dev; enum drm_connector_status status; struct edid *edid = NULL; @@ -2345,6 +2347,8 @@ intel_dp_detect(struct drm_connector *connector, bool force) } } + if (intel_encoder->type != INTEL_OUTPUT_EDP) + intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT; return connector_status_connected; } @@ -2482,7 +2486,7 @@ intel_dp_destroy(struct drm_connector *connector) kfree(connector); } -static void intel_dp_encoder_destroy(struct drm_encoder *encoder) +void intel_dp_encoder_destroy(struct drm_encoder *encoder) { struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); struct intel_dp *intel_dp = &intel_dig_port->dp; @@ -2497,15 +2501,6 @@ static void intel_dp_encoder_destroy(struct drm_encoder *encoder) kfree(intel_dig_port); } -static const struct drm_encoder_helper_funcs intel_dp_helper_funcs_hsw = { - .dpms = intel_dp_dpms, - .mode_fixup = intel_dp_mode_fixup, - .prepare = intel_dp_prepare, - .mode_set = intel_ddi_mode_set, - .commit = intel_ddi_commit, - .disable = intel_ddi_disable, -}; - static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = { .dpms = intel_dp_dpms, .mode_fixup = intel_dp_mode_fixup, @@ -2586,7 +2581,7 @@ intel_dp_add_properties(struct drm_connector *connector) intel_attach_broadcast_rgb_property(connector); } -static void +void intel_dp_init_connector(struct intel_digital_port *intel_dig_port, struct intel_connector *intel_connector) { @@ -2610,7 +2605,6 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, intel_encoder->type = INTEL_OUTPUT_EDP; } else { type = DRM_MODE_CONNECTOR_DisplayPort; - intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT; } drm_connector_init(dev, connector, &intel_dp_connector_funcs, type); @@ -2779,10 +2773,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) drm_encoder_init(dev, encoder, &intel_dp_enc_funcs, DRM_MODE_ENCODER_TMDS); - if (IS_HASWELL(dev)) - drm_encoder_helper_add(encoder, &intel_dp_helper_funcs_hsw); - else - drm_encoder_helper_add(encoder, &intel_dp_helper_funcs); + drm_encoder_helper_add(encoder, &intel_dp_helper_funcs); intel_dig_port->port = port; intel_dig_port->hdmi.sdvox_reg = 0; @@ -2790,6 +2781,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); intel_encoder->cloneable = false; + intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT; intel_encoder->hot_plug = intel_dp_hot_plug; intel_dp_init_connector(intel_dig_port, intel_connector); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d096d4d..4428d5f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -90,6 +90,7 @@ #define INTEL_OUTPUT_HDMI 6 #define INTEL_OUTPUT_DISPLAYPORT 7 #define INTEL_OUTPUT_EDP 8 +#define INTEL_OUTPUT_UNKNOWN 9 #define INTEL_DVO_CHIP_NONE 0 #define INTEL_DVO_CHIP_LVDS 1 @@ -371,6 +372,11 @@ extern void intel_crt_init(struct drm_device *dev); extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port); extern struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder); +extern void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, + struct intel_connector *intel_connector); +extern bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); extern void intel_dip_infoframe_csum(struct dip_infoframe *avi_if); extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob); @@ -389,6 +395,15 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, extern void intel_dp_init_link_config(struct intel_dp *intel_dp); extern void intel_dp_commit(struct drm_encoder *encoder); extern bool intel_dpd_is_edp(struct drm_device *dev); +extern void intel_dp_dpms(struct drm_encoder *encoder, int mode); +extern void intel_dp_check_link_status(struct intel_dp *intel_dp); +extern void intel_dp_encoder_destroy(struct drm_encoder *encoder); +extern bool intel_dp_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +extern void intel_dp_prepare(struct drm_encoder *encoder); +extern void intel_dp_init_connector(struct intel_digital_port *intel_dig_port, + struct intel_connector *intel_connector); extern void intel_edp_link_config(struct intel_encoder *, int *, int *); extern int intel_edp_target_clock(struct intel_encoder *, struct drm_display_mode *mode); @@ -550,14 +565,9 @@ extern void intel_disable_gt_powersave(struct drm_device *dev); extern void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv); extern void ironlake_teardown_rc6(struct drm_device *dev); -extern void intel_ddi_dpms(struct drm_encoder *encoder, int mode); extern bool intel_ddi_pll_mode_set(struct drm_crtc *crtc); -extern void intel_ddi_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); extern void intel_ddi_pll_init(struct drm_device *dev); extern void intel_ddi_disable(struct drm_encoder *encoder); -extern void intel_ddi_commit(struct drm_encoder *encoder); extern void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder); #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 5a78deb..5a29fda 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -691,9 +691,9 @@ static int intel_hdmi_mode_valid(struct drm_connector *connector, return MODE_OK; } -static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +bool intel_hdmi_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { return true; } @@ -723,6 +723,9 @@ static enum drm_connector_status intel_hdmi_detect(struct drm_connector *connector, bool force) { struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); + struct intel_digital_port *intel_dig_port = + hdmi_to_dig_port(intel_hdmi); + struct intel_encoder *intel_encoder = &intel_dig_port->base; struct drm_i915_private *dev_priv = connector->dev->dev_private; struct edid *edid; enum drm_connector_status status = connector_status_disconnected; @@ -752,6 +755,7 @@ intel_hdmi_detect(struct drm_connector *connector, bool force) if (intel_hdmi->force_audio != HDMI_AUDIO_AUTO) intel_hdmi->has_audio = (intel_hdmi->force_audio == HDMI_AUDIO_ON); + intel_encoder->type = INTEL_OUTPUT_HDMI; } return status; @@ -857,15 +861,6 @@ static void intel_hdmi_destroy(struct drm_connector *connector) kfree(connector); } -static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = { - .dpms = intel_ddi_dpms, - .mode_fixup = intel_hdmi_mode_fixup, - .prepare = intel_encoder_prepare, - .mode_set = intel_ddi_mode_set, - .commit = intel_ddi_commit, - .disable = intel_ddi_disable, -}; - static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = { .dpms = intel_hdmi_dpms, .mode_fixup = intel_hdmi_mode_fixup, @@ -899,8 +894,8 @@ intel_hdmi_add_properties(struct drm_connector *connector) intel_attach_broadcast_rgb_property(connector); } -static void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, - struct intel_connector *intel_connector) +void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, + struct intel_connector *intel_connector) { struct drm_connector *connector = &intel_connector->base; struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; @@ -991,10 +986,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg, enum port port) drm_encoder_init(dev, encoder, &intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS); - if (IS_HASWELL(dev)) - drm_encoder_helper_add(encoder, &intel_hdmi_helper_funcs_hsw); - else - drm_encoder_helper_add(encoder, &intel_hdmi_helper_funcs); + drm_encoder_helper_add(encoder, &intel_hdmi_helper_funcs); intel_dig_port->port = port; intel_dig_port->hdmi.sdvox_reg = sdvox_reg; -- 1.7.11.2