drm/exynos: fix display on issue

When crtc_funcs->dpms callback is called, exynos_crtc->dpms
and exynos_encoder->dpms are changed to new mode. But if user
requests dpms mode operation, OFF -> ON, when crtc's dpms callback
is called, exynos_encoder->dpms is also changed to ON. This
makes encoder's dpms callback call be ignored so display power
couldn't become on again.

This patch removes exynos_encoder->dpms changing and adds 'updated'
variable to exynos_drm_encoder structure to avoid duplicated overlay
updating.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
This commit is contained in:
Inki Dae 2012-10-18 18:59:55 +09:00 committed by Inki Dae
parent 4936b172d6
commit 44c91697fb
2 changed files with 18 additions and 16 deletions

View File

@ -374,6 +374,7 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
exynos_connector->encoder_id = encoder->base.id; exynos_connector->encoder_id = encoder->base.id;
exynos_connector->manager = manager; exynos_connector->manager = manager;
exynos_connector->dpms = DRM_MODE_DPMS_OFF; exynos_connector->dpms = DRM_MODE_DPMS_OFF;
connector->dpms = DRM_MODE_DPMS_OFF;
connector->encoder = encoder; connector->encoder = encoder;
err = drm_mode_connector_attach_encoder(connector, encoder); err = drm_mode_connector_attach_encoder(connector, encoder);

View File

@ -43,12 +43,14 @@
* @manager: specific encoder has its own manager to control a hardware * @manager: specific encoder has its own manager to control a hardware
* appropriately and we can access a hardware drawing on this manager. * appropriately and we can access a hardware drawing on this manager.
* @dpms: store the encoder dpms value. * @dpms: store the encoder dpms value.
* @updated: indicate whether overlay data updating is needed or not.
*/ */
struct exynos_drm_encoder { struct exynos_drm_encoder {
struct drm_crtc *old_crtc; struct drm_crtc *old_crtc;
struct drm_encoder drm_encoder; struct drm_encoder drm_encoder;
struct exynos_drm_manager *manager; struct exynos_drm_manager *manager;
int dpms; int dpms;
bool updated;
}; };
static void exynos_drm_connector_power(struct drm_encoder *encoder, int mode) static void exynos_drm_connector_power(struct drm_encoder *encoder, int mode)
@ -85,7 +87,9 @@ static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
switch (mode) { switch (mode) {
case DRM_MODE_DPMS_ON: case DRM_MODE_DPMS_ON:
if (manager_ops && manager_ops->apply) if (manager_ops && manager_ops->apply)
manager_ops->apply(manager->dev); if (!exynos_encoder->updated)
manager_ops->apply(manager->dev);
exynos_drm_connector_power(encoder, mode); exynos_drm_connector_power(encoder, mode);
exynos_encoder->dpms = mode; exynos_encoder->dpms = mode;
break; break;
@ -94,6 +98,7 @@ static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
case DRM_MODE_DPMS_OFF: case DRM_MODE_DPMS_OFF:
exynos_drm_connector_power(encoder, mode); exynos_drm_connector_power(encoder, mode);
exynos_encoder->dpms = mode; exynos_encoder->dpms = mode;
exynos_encoder->updated = false;
break; break;
default: default:
DRM_ERROR("unspecified mode %d\n", mode); DRM_ERROR("unspecified mode %d\n", mode);
@ -205,13 +210,22 @@ static void exynos_drm_encoder_prepare(struct drm_encoder *encoder)
static void exynos_drm_encoder_commit(struct drm_encoder *encoder) static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
{ {
struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
struct exynos_drm_manager *manager = exynos_encoder->manager;
struct exynos_drm_manager_ops *manager_ops = manager->ops; struct exynos_drm_manager_ops *manager_ops = manager->ops;
DRM_DEBUG_KMS("%s\n", __FILE__); DRM_DEBUG_KMS("%s\n", __FILE__);
if (manager_ops && manager_ops->commit) if (manager_ops && manager_ops->commit)
manager_ops->commit(manager->dev); manager_ops->commit(manager->dev);
/*
* this will avoid one issue that overlay data is updated to
* real hardware two times.
* And this variable will be used to check if the data was
* already updated or not by exynos_drm_encoder_dpms function.
*/
exynos_encoder->updated = true;
} }
static void exynos_drm_encoder_disable(struct drm_encoder *encoder) static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
@ -400,19 +414,6 @@ void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
if (manager_ops && manager_ops->dpms) if (manager_ops && manager_ops->dpms)
manager_ops->dpms(manager->dev, mode); manager_ops->dpms(manager->dev, mode);
/*
* set current mode to new one so that data aren't updated into
* registers by drm_helper_connector_dpms two times.
*
* in case that drm_crtc_helper_set_mode() is called,
* overlay_ops->commit() and manager_ops->commit() callbacks
* can be called two times, first at drm_crtc_helper_set_mode()
* and second at drm_helper_connector_dpms().
* so with this setting, when drm_helper_connector_dpms() is called
* encoder->funcs->dpms() will be ignored.
*/
exynos_encoder->dpms = mode;
/* /*
* if this condition is ok then it means that the crtc is already * if this condition is ok then it means that the crtc is already
* detached from encoder and last function for detaching is properly * detached from encoder and last function for detaching is properly