aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_crtc_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_crtc_helper.c')
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c96
1 files changed, 49 insertions, 47 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index c722c3b5404d..01361aba033b 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -39,6 +39,10 @@
#include <drm/drm_fb_helper.h>
#include <drm/drm_edid.h>
+MODULE_AUTHOR("David Airlie, Jesse Barnes");
+MODULE_DESCRIPTION("DRM KMS helper");
+MODULE_LICENSE("GPL and additional rights");
+
/**
* drm_helper_move_panel_connectors_to_head() - move panels to the front in the
* connector list
@@ -76,7 +80,8 @@ static void drm_mode_validate_flag(struct drm_connector *connector,
{
struct drm_display_mode *mode;
- if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE))
+ if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE |
+ DRM_MODE_FLAG_3D_MASK))
return;
list_for_each_entry(mode, &connector->modes, head) {
@@ -86,6 +91,9 @@ static void drm_mode_validate_flag(struct drm_connector *connector,
if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) &&
!(flags & DRM_MODE_FLAG_DBLSCAN))
mode->status = MODE_NO_DBLESCAN;
+ if ((mode->flags & DRM_MODE_FLAG_3D_MASK) &&
+ !(flags & DRM_MODE_FLAG_3D_MASK))
+ mode->status = MODE_NO_STEREO;
}
return;
@@ -105,9 +113,9 @@ static void drm_mode_validate_flag(struct drm_connector *connector,
* then culled (based on validity and the @maxX, @maxY parameters) and put into
* the normal modes list.
*
- * Intended to be use as a generic implementation of the ->probe() @connector
- * callback for drivers that use the crtc helpers for output mode filtering and
- * detection.
+ * Intended to be use as a generic implementation of the ->fill_modes()
+ * @connector vfunc for drivers that use the crtc helpers for output mode
+ * filtering and detection.
*
* RETURNS:
* Number of modes found on @connector.
@@ -175,6 +183,8 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
mode_flags |= DRM_MODE_FLAG_INTERLACE;
if (connector->doublescan_allowed)
mode_flags |= DRM_MODE_FLAG_DBLSCAN;
+ if (connector->stereo_allowed)
+ mode_flags |= DRM_MODE_FLAG_3D_MASK;
drm_mode_validate_flag(connector, mode_flags);
list_for_each_entry(mode, &connector->modes, head) {
@@ -395,22 +405,25 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
struct drm_framebuffer *old_fb)
{
struct drm_device *dev = crtc->dev;
- struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode;
+ struct drm_display_mode *adjusted_mode, saved_mode;
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
struct drm_encoder_helper_funcs *encoder_funcs;
int saved_x, saved_y;
+ bool saved_enabled;
struct drm_encoder *encoder;
bool ret = true;
+ saved_enabled = crtc->enabled;
crtc->enabled = drm_helper_crtc_in_use(crtc);
if (!crtc->enabled)
return true;
adjusted_mode = drm_mode_duplicate(dev, mode);
- if (!adjusted_mode)
+ if (!adjusted_mode) {
+ crtc->enabled = saved_enabled;
return false;
+ }
- saved_hwmode = crtc->hwmode;
saved_mode = crtc->mode;
saved_x = crtc->x;
saved_y = crtc->y;
@@ -529,7 +542,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
done:
drm_mode_destroy(dev, adjusted_mode);
if (!ret) {
- crtc->hwmode = saved_hwmode;
+ crtc->enabled = saved_enabled;
crtc->mode = saved_mode;
crtc->x = saved_x;
crtc->y = saved_y;
@@ -557,6 +570,14 @@ drm_crtc_helper_disable(struct drm_crtc *crtc)
continue;
connector->encoder = NULL;
+
+ /*
+ * drm_helper_disable_unused_functions() ought to be
+ * doing this, but since we've decoupled the encoder
+ * from the connector above, the required connection
+ * between them is henceforth no longer available.
+ */
+ connector->dpms = DRM_MODE_DPMS_OFF;
}
}
@@ -583,9 +604,8 @@ drm_crtc_helper_disable(struct drm_crtc *crtc)
int drm_crtc_helper_set_config(struct drm_mode_set *set)
{
struct drm_device *dev;
- struct drm_crtc *save_crtcs, *new_crtc, *crtc;
+ struct drm_crtc *new_crtc;
struct drm_encoder *save_encoders, *new_encoder, *encoder;
- struct drm_framebuffer *old_fb = NULL;
bool mode_changed = false; /* if true do a full mode set */
bool fb_changed = false; /* if true and !mode_changed just do a flip */
struct drm_connector *save_connectors, *connector;
@@ -621,38 +641,28 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
dev = set->crtc->dev;
- /* Allocate space for the backup of all (non-pointer) crtc, encoder and
- * connector data. */
- save_crtcs = kzalloc(dev->mode_config.num_crtc *
- sizeof(struct drm_crtc), GFP_KERNEL);
- if (!save_crtcs)
- return -ENOMEM;
-
+ /*
+ * Allocate space for the backup of all (non-pointer) encoder and
+ * connector data.
+ */
save_encoders = kzalloc(dev->mode_config.num_encoder *
sizeof(struct drm_encoder), GFP_KERNEL);
- if (!save_encoders) {
- kfree(save_crtcs);
+ if (!save_encoders)
return -ENOMEM;
- }
save_connectors = kzalloc(dev->mode_config.num_connector *
sizeof(struct drm_connector), GFP_KERNEL);
if (!save_connectors) {
- kfree(save_crtcs);
kfree(save_encoders);
return -ENOMEM;
}
- /* Copy data. Note that driver private data is not affected.
+ /*
+ * Copy data. Note that driver private data is not affected.
* Should anything bad happen only the expected state is
* restored, not the drivers personal bookkeeping.
*/
count = 0;
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- save_crtcs[count++] = *crtc;
- }
-
- count = 0;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
save_encoders[count++] = *encoder;
}
@@ -775,19 +785,17 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
mode_changed = true;
if (mode_changed) {
- set->crtc->enabled = drm_helper_crtc_in_use(set->crtc);
- if (set->crtc->enabled) {
+ if (drm_helper_crtc_in_use(set->crtc)) {
DRM_DEBUG_KMS("attempting to set mode from"
" userspace\n");
drm_mode_debug_printmodeline(set->mode);
- old_fb = set->crtc->fb;
set->crtc->fb = set->fb;
if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
set->x, set->y,
- old_fb)) {
+ save_set.fb)) {
DRM_ERROR("failed to set mode on [CRTC:%d]\n",
set->crtc->base.id);
- set->crtc->fb = old_fb;
+ set->crtc->fb = save_set.fb;
ret = -EINVAL;
goto fail;
}
@@ -802,31 +810,24 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
} else if (fb_changed) {
set->crtc->x = set->x;
set->crtc->y = set->y;
-
- old_fb = set->crtc->fb;
- if (set->crtc->fb != set->fb)
- set->crtc->fb = set->fb;
+ set->crtc->fb = set->fb;
ret = crtc_funcs->mode_set_base(set->crtc,
- set->x, set->y, old_fb);
+ set->x, set->y, save_set.fb);
if (ret != 0) {
- set->crtc->fb = old_fb;
+ set->crtc->x = save_set.x;
+ set->crtc->y = save_set.y;
+ set->crtc->fb = save_set.fb;
goto fail;
}
}
kfree(save_connectors);
kfree(save_encoders);
- kfree(save_crtcs);
return 0;
fail:
/* Restore all previous data. */
count = 0;
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- *crtc = save_crtcs[count++];
- }
-
- count = 0;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
*encoder = save_encoders[count++];
}
@@ -844,7 +845,6 @@ fail:
kfree(save_connectors);
kfree(save_encoders);
- kfree(save_crtcs);
return ret;
}
EXPORT_SYMBOL(drm_crtc_helper_set_config);
@@ -1125,14 +1125,14 @@ void drm_kms_helper_poll_fini(struct drm_device *dev)
}
EXPORT_SYMBOL(drm_kms_helper_poll_fini);
-void drm_helper_hpd_irq_event(struct drm_device *dev)
+bool drm_helper_hpd_irq_event(struct drm_device *dev)
{
struct drm_connector *connector;
enum drm_connector_status old_status;
bool changed = false;
if (!dev->mode_config.poll_enabled)
- return;
+ return false;
mutex_lock(&dev->mode_config.mutex);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
@@ -1157,5 +1157,7 @@ void drm_helper_hpd_irq_event(struct drm_device *dev)
if (changed)
drm_kms_helper_hotplug_event(dev);
+
+ return changed;
}
EXPORT_SYMBOL(drm_helper_hpd_irq_event);