@@ -8223,11 +8223,11 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
for_each_intel_encoder(dev, encoder) {
switch (encoder->type) {
case INTEL_OUTPUT_LVDS:
- has_panel = true;
+ has_panel = intel_lvds_has_panel(encoder);
has_lvds = true;
break;
case INTEL_OUTPUT_EDP:
- has_panel = true;
+ has_panel = intel_edp_has_panel(encoder);
if (enc_to_dig_port(&encoder->base)->port == PORT_A)
has_cpu_edp = true;
break;
@@ -14478,15 +14478,44 @@ intel_user_framebuffer_create(struct drm_device *dev,
return intel_framebuffer_create(dev, mode_cmd, obj);
}
-#ifndef CONFIG_DRM_I915_FBDEV
-static inline void intel_fbdev_output_poll_changed(struct drm_device *dev)
+static void intel_output_poll_changed(struct drm_device *dev)
{
-}
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_connector *intel_connector;
+
+ /* Reprobe LVDS and eDP as long as no EDID was retrieved from panel */
+ for_each_intel_connector(dev, intel_connector) {
+ struct drm_connector *connector = &intel_connector->base;
+
+ if ((connector->connector_type != DRM_MODE_CONNECTOR_LVDS &&
+ connector->connector_type != DRM_MODE_CONNECTOR_eDP) ||
+ !IS_ERR_OR_NULL(intel_connector->edid))
+ continue;
+
+ if ((connector->connector_type == DRM_MODE_CONNECTOR_LVDS &&
+ !intel_lvds_probe_modes(connector)) ||
+ (connector->connector_type == DRM_MODE_CONNECTOR_eDP &&
+ !intel_edp_init_connector(
+ enc_to_intel_dp(&intel_connector->encoder->base),
+ intel_connector)))
+ continue;
+
+ intel_init_pch_refclk(dev);
+ drm_helper_move_panel_connectors_to_head(dev);
+ mutex_lock(&dev_priv->backlight_lock);
+ if (intel_connector->panel.backlight.device == NULL)
+ intel_backlight_device_register(intel_connector);
+ mutex_unlock(&dev_priv->backlight_lock);
+ }
+
+#ifdef CONFIG_DRM_I915_FBDEV
+ intel_fbdev_output_poll_changed(dev);
#endif
+}
static const struct drm_mode_config_funcs intel_mode_funcs = {
.fb_create = intel_user_framebuffer_create,
- .output_poll_changed = intel_fbdev_output_poll_changed,
+ .output_poll_changed = intel_output_poll_changed,
.atomic_check = intel_atomic_check,
.atomic_commit = intel_atomic_commit,
.atomic_state_alloc = intel_atomic_state_alloc,
@@ -1998,6 +1998,15 @@ void intel_edp_panel_off(struct intel_dp *intel_dp)
pps_unlock(intel_dp);
}
+bool intel_edp_has_panel(struct intel_encoder *intel_encoder)
+{
+ struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base);
+ struct intel_connector *intel_connector = intel_dp->attached_connector;
+
+ return intel_dp->dpcd[DP_DPCD_REV] != 0 &&
+ intel_connector->panel.fixed_mode != NULL;
+}
+
/* Enable backlight in the panel power control. */
static void _intel_edp_backlight_on(struct intel_dp *intel_dp)
{
@@ -4338,6 +4347,9 @@ edp_detect(struct intel_dp *intel_dp)
struct drm_device *dev = intel_dp_to_dev(intel_dp);
enum drm_connector_status status;
+ if (!intel_edp_has_panel(intel_dp->attached_connector->encoder))
+ return connector_status_disconnected;
+
status = intel_panel_detect(dev);
if (status == connector_status_unknown)
status = connector_status_connected;
@@ -5599,8 +5611,8 @@ intel_dp_drrs_init(struct intel_connector *intel_connector,
return downclock_mode;
}
-static bool intel_edp_init_connector(struct intel_dp *intel_dp,
- struct intel_connector *intel_connector)
+bool intel_edp_init_connector(struct intel_dp *intel_dp,
+ struct intel_connector *intel_connector)
{
struct drm_connector *connector = &intel_connector->base;
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
@@ -5614,9 +5626,6 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
struct edid *edid;
enum pipe pipe = INVALID_PIPE;
- if (!is_edp(intel_dp))
- return true;
-
pps_lock(intel_dp);
intel_edp_panel_vdd_sanitize(intel_dp);
pps_unlock(intel_dp);
@@ -5630,8 +5639,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
intel_dp->dpcd[DP_MAX_DOWNSPREAD] &
DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
} else {
- /* if this fails, presume the device is a ghost */
- DRM_INFO("failed to retrieve link info, disabling eDP\n");
+ DRM_INFO("failed to retrieve eDP link info\n");
return false;
}
@@ -5676,8 +5684,12 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
mutex_unlock(&dev->mode_config.mutex);
if (IS_VALLEYVIEW(dev)) {
- intel_dp->edp_notifier.notifier_call = edp_notify_handler;
- register_reboot_notifier(&intel_dp->edp_notifier);
+ if (intel_dp->edp_notifier.notifier_call == NULL) {
+ intel_dp->edp_notifier.notifier_call =
+ edp_notify_handler;
+ if (register_reboot_notifier(&intel_dp->edp_notifier))
+ intel_dp->edp_notifier.notifier_call = NULL;
+ }
/*
* Figure out the current pipe for the initial backlight setup.
@@ -5817,9 +5829,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
intel_dp_mst_encoder_init(intel_dig_port,
intel_connector->base.base.id);
- if (!intel_edp_init_connector(intel_dp, intel_connector)) {
- drm_dp_aux_unregister(&intel_dp->aux);
- if (is_edp(intel_dp)) {
+ if (is_edp(intel_dp)) {
+ if (!intel_edp_init_connector(intel_dp, intel_connector)) {
cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
/*
* vdd might still be enabled do to the delayed vdd off.
@@ -5829,9 +5840,6 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
edp_panel_vdd_off_sync(intel_dp);
pps_unlock(intel_dp);
}
- drm_connector_unregister(connector);
- drm_connector_cleanup(connector);
- return false;
}
intel_dp_add_properties(intel_dp, connector);
@@ -1171,11 +1171,14 @@ bool intel_dp_compute_config(struct intel_encoder *encoder,
bool intel_dp_is_edp(struct drm_device *dev, enum port port);
enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port,
bool long_hpd);
+bool intel_edp_init_connector(struct intel_dp *intel_dp,
+ struct intel_connector *intel_connector);
void intel_edp_backlight_on(struct intel_dp *intel_dp);
void intel_edp_backlight_off(struct intel_dp *intel_dp);
void intel_edp_panel_vdd_on(struct intel_dp *intel_dp);
void intel_edp_panel_on(struct intel_dp *intel_dp);
void intel_edp_panel_off(struct intel_dp *intel_dp);
+bool intel_edp_has_panel(struct intel_encoder *intel_encoder);
void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector);
void intel_dp_mst_suspend(struct drm_device *dev);
void intel_dp_mst_resume(struct drm_device *dev);
@@ -1258,6 +1261,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
/* intel_lvds.c */
void intel_lvds_init(struct drm_device *dev);
+bool intel_lvds_probe_modes(struct drm_connector *connector);
+bool intel_lvds_has_panel(struct intel_encoder *intel_encoder);
bool intel_is_dual_link_lvds(struct drm_device *dev);
@@ -1307,6 +1312,7 @@ extern struct drm_display_mode *intel_find_panel_downclock(
struct drm_connector *connector);
void intel_backlight_register(struct drm_device *dev);
void intel_backlight_unregister(struct drm_device *dev);
+int intel_backlight_device_register(struct intel_connector *connector);
/* intel_psr.c */
@@ -359,7 +359,7 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
/**
* Detect the LVDS connection.
*
- * Since LVDS doesn't have hotlug, we use the lid as a proxy. Open means
+ * Since LVDS doesn't have hotplug, we use the lid as a proxy. Open means
* connected and closed means disconnected. We also send hotplug events as
* needed, using lid status notification from the input layer.
*/
@@ -372,6 +372,9 @@ intel_lvds_detect(struct drm_connector *connector, bool force)
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
connector->base.id, connector->name);
+ if (!intel_lvds_has_panel(to_intel_connector(connector)->encoder))
+ return connector_status_disconnected;
+
status = intel_panel_detect(dev);
if (status != connector_status_unknown)
return status;
@@ -936,13 +939,6 @@ void intel_lvds_init(struct drm_device *dev)
struct intel_connector *intel_connector;
struct drm_connector *connector;
struct drm_encoder *encoder;
- struct drm_display_mode *scan; /* *modes, *bios_mode; */
- struct drm_display_mode *fixed_mode = NULL;
- struct drm_display_mode *downclock_mode = NULL;
- struct edid *edid;
- struct drm_crtc *crtc;
- u32 lvds;
- int pipe;
u8 pin;
/*
@@ -1052,6 +1048,29 @@ void intel_lvds_init(struct drm_device *dev)
dev->mode_config.scaling_mode_property,
DRM_MODE_SCALE_ASPECT);
intel_connector->panel.fitting_mode = DRM_MODE_SCALE_ASPECT;
+
+ drm_connector_register(connector);
+ intel_lvds_probe_modes(connector);
+}
+
+bool intel_lvds_probe_modes(struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_connector *intel_connector = to_intel_connector(connector);
+ struct intel_lvds_connector *lvds_connector = to_lvds_connector(connector);
+ struct intel_encoder *intel_encoder = intel_connector->encoder;
+ struct drm_encoder *encoder = &intel_encoder->base;
+ struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(encoder);
+ struct drm_display_mode *scan;
+ struct drm_display_mode *fixed_mode = NULL;
+ struct drm_display_mode *downclock_mode = NULL;
+ struct edid *edid;
+ struct drm_crtc *crtc;
+ u32 lvds;
+ int pipe;
+ u8 pin = GMBUS_PIN_PANEL;
+
/*
* LVDS discovery:
* 1) check for EDID on DDC
@@ -1079,7 +1098,7 @@ void intel_lvds_init(struct drm_device *dev)
} else {
edid = ERR_PTR(-ENOENT);
}
- lvds_connector->base.edid = edid;
+ intel_connector->edid = edid;
if (IS_ERR_OR_NULL(edid)) {
/* Didn't get an EDID, so
@@ -1155,24 +1174,30 @@ out:
lvds_encoder->a3_power = I915_READ(lvds_encoder->reg) &
LVDS_A3_POWER_MASK;
- lvds_connector->lid_notifier.notifier_call = intel_lid_notify;
- if (acpi_lid_notifier_register(&lvds_connector->lid_notifier)) {
- DRM_DEBUG_KMS("lid notifier registration failed\n");
- lvds_connector->lid_notifier.notifier_call = NULL;
+ if (lvds_connector->lid_notifier.notifier_call == NULL) {
+ lvds_connector->lid_notifier.notifier_call = intel_lid_notify;
+ if (acpi_lid_notifier_register(&lvds_connector->lid_notifier)) {
+ DRM_DEBUG_KMS("lid notifier registration failed\n");
+ lvds_connector->lid_notifier.notifier_call = NULL;
+ }
}
- drm_connector_register(connector);
intel_panel_setup_backlight(connector, INVALID_PIPE);
- return;
+ return true;
failed:
mutex_unlock(&dev->mode_config.mutex);
- DRM_DEBUG_KMS("No LVDS modes found, disabling.\n");
- drm_connector_cleanup(connector);
- drm_encoder_cleanup(encoder);
- kfree(lvds_encoder);
- kfree(lvds_connector);
- return;
+ DRM_DEBUG_KMS("No LVDS modes found\n");
+ return false;
+}
+
+bool intel_lvds_has_panel(struct intel_encoder *intel_encoder)
+{
+ struct intel_lvds_connector *lvds_connector =
+ to_lvds_encoder(&intel_encoder->base)->attached_connector;
+ struct intel_connector *intel_connector = &lvds_connector->base;
+
+ return intel_connector->panel.fixed_mode != NULL;
}
@@ -1139,7 +1139,7 @@ static const struct backlight_ops intel_backlight_device_ops = {
.get_brightness = intel_backlight_device_get_brightness,
};
-static int intel_backlight_device_register(struct intel_connector *connector)
+int intel_backlight_device_register(struct intel_connector *connector)
{
struct intel_panel *panel = &connector->panel;
struct backlight_properties props;
@@ -1202,7 +1202,7 @@ static void intel_backlight_device_unregister(struct intel_connector *connector)
}
}
#else /* CONFIG_BACKLIGHT_CLASS_DEVICE */
-static int intel_backlight_device_register(struct intel_connector *connector)
+int intel_backlight_device_register(struct intel_connector *connector)
{
return 0;
}