Message ID | 1345197059-25583-11-git-send-email-inki.dae@samsung.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 08/17/2012 06:50 PM, Inki Dae wrote: > if old_crtc isn't same as encoder->crtc then it means that > user changed crtc id to another one so a plane to old_crtc > should be disabled so that current plane can be updated safely > and plane->crtc should be set to new crtc(encoder->crtc) > > Signed-off-by: Inki Dae <inki.dae@samsung.com> > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> > --- > drivers/gpu/drm/exynos/exynos_drm_encoder.c | 59 +++++++++++++++++++++++++- > 1 files changed, 56 insertions(+), 3 deletions(-) > > diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c > index a562a94..7bcace8 100644 > --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c > +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c > @@ -44,6 +44,7 @@ > * @dpms: store the encoder dpms value. > */ > struct exynos_drm_encoder { > + struct drm_crtc *old_crtc; > struct drm_encoder drm_encoder; > struct exynos_drm_manager *manager; > int dpms; > @@ -106,22 +107,74 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder, > return true; > } > > +static void disable_plane_to_crtc(struct drm_device *dev, > + struct drm_crtc *old_crtc, > + struct drm_crtc *new_crtc) > +{ > + struct drm_plane *plane; > + > + /* > + * if old_crtc isn't same as encoder->crtc then it means that > + * user changed crtc id to another one so the plane to old_crtc > + * should be disabled and plane->crtc should be set to new_crtc > + * (encoder->crtc) > + */ > + list_for_each_entry(plane, &dev->mode_config.plane_list, head) { > + if (plane->crtc == old_crtc) { > + /* > + * do not change below call order. > + * > + * plane->funcs->disable_plane call checks > + * if encoder->crtc is same as plane->crtc and if same > + * then overlay_ops->disable callback will be called > + * to diasble current hw overlay so plane->crtc should > + * have new_crtc because new_crtc was set to > + * encoder->crtc in advance. > + */ > + plane->crtc = new_crtc; > + plane->funcs->disable_plane(plane); > + } > + } > +} > + > static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder, > struct drm_display_mode *mode, > struct drm_display_mode *adjusted_mode) > { > struct drm_device *dev = encoder->dev; > struct drm_connector *connector; > - struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); > - struct exynos_drm_manager_ops *manager_ops = manager->ops; > + struct exynos_drm_manager *manager; > + struct exynos_drm_manager_ops *manager_ops; > > DRM_DEBUG_KMS("%s\n", __FILE__); > > list_for_each_entry(connector, &dev->mode_config.connector_list, head) { > - if (connector->encoder == encoder) > + if (connector->encoder == encoder) { > + struct exynos_drm_encoder *exynos_encoder; > + > + exynos_encoder = to_exynos_encoder(encoder); Does needs to do this in for statement? > + > + if (exynos_encoder->old_crtc != encoder->crtc && > + exynos_encoder->old_crtc) { > + > + /* > + * disable a plane to old crtc and change > + * crtc of the plane to new one. > + */ > + disable_plane_to_crtc(dev, > + exynos_encoder->old_crtc, > + encoder->crtc); > + } > + > + manager = exynos_drm_get_manager(encoder); > + manager_ops = manager->ops; Does needs to do this in for statement? > + > if (manager_ops && manager_ops->mode_set) > manager_ops->mode_set(manager->dev, > adjusted_mode); > + > + exynos_encoder->old_crtc = encoder->crtc; > + } > } > } >
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c index a562a94..7bcace8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c @@ -44,6 +44,7 @@ * @dpms: store the encoder dpms value. */ struct exynos_drm_encoder { + struct drm_crtc *old_crtc; struct drm_encoder drm_encoder; struct exynos_drm_manager *manager; int dpms; @@ -106,22 +107,74 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder, return true; } +static void disable_plane_to_crtc(struct drm_device *dev, + struct drm_crtc *old_crtc, + struct drm_crtc *new_crtc) +{ + struct drm_plane *plane; + + /* + * if old_crtc isn't same as encoder->crtc then it means that + * user changed crtc id to another one so the plane to old_crtc + * should be disabled and plane->crtc should be set to new_crtc + * (encoder->crtc) + */ + list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + if (plane->crtc == old_crtc) { + /* + * do not change below call order. + * + * plane->funcs->disable_plane call checks + * if encoder->crtc is same as plane->crtc and if same + * then overlay_ops->disable callback will be called + * to diasble current hw overlay so plane->crtc should + * have new_crtc because new_crtc was set to + * encoder->crtc in advance. + */ + plane->crtc = new_crtc; + plane->funcs->disable_plane(plane); + } + } +} + static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; struct drm_connector *connector; - struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); - struct exynos_drm_manager_ops *manager_ops = manager->ops; + struct exynos_drm_manager *manager; + struct exynos_drm_manager_ops *manager_ops; DRM_DEBUG_KMS("%s\n", __FILE__); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) + if (connector->encoder == encoder) { + struct exynos_drm_encoder *exynos_encoder; + + exynos_encoder = to_exynos_encoder(encoder); + + if (exynos_encoder->old_crtc != encoder->crtc && + exynos_encoder->old_crtc) { + + /* + * disable a plane to old crtc and change + * crtc of the plane to new one. + */ + disable_plane_to_crtc(dev, + exynos_encoder->old_crtc, + encoder->crtc); + } + + manager = exynos_drm_get_manager(encoder); + manager_ops = manager->ops; + if (manager_ops && manager_ops->mode_set) manager_ops->mode_set(manager->dev, adjusted_mode); + + exynos_encoder->old_crtc = encoder->crtc; + } } }