From dd7c1f0b5c23bcac5046d77bd5e0631e657003a4 Mon Sep 17 00:00:00 2001 From: Preetesh Parekh Date: Mon, 25 Apr 2016 12:02:45 -0700 Subject: [PATCH] drm: xilinx: crtc: Add crtc set config helper The goal is to be able to synchronize resolution changes between the drm device and emulated fbdev device if both devices are used by an application e.g. in Qt we use both graphics and video layer whereas the former is controlled by fbdev and the latter by drm. This patch propagates resolution changes from the drm device to fbdev. Before setting the new mode, a copy of the old mode is saved locally and restored upon last close. work in progres: If hot-plug events happen while the application is running, the mode pre-application start will be restored instead of the mode set by the last hot-plug event. For example if we switch monitors from 1080p to 4k while the application is running, last close will restore the fbconsole to 1080p on the 4k monitor. Reviewed-by: Hyun Kwon Signed-off-by: Michal Simek --- drivers/gpu/drm/xilinx/xilinx_drm_crtc.c | 12 ++++++- drivers/gpu/drm/xilinx/xilinx_drm_drv.c | 8 +++++ drivers/gpu/drm/xilinx/xilinx_drm_drv.h | 2 ++ drivers/gpu/drm/xilinx/xilinx_drm_fb.c | 42 ++++++++++++++++++++++++ drivers/gpu/drm/xilinx/xilinx_drm_fb.h | 2 ++ 5 files changed, 65 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xilinx/xilinx_drm_crtc.c b/drivers/gpu/drm/xilinx/xilinx_drm_crtc.c index 2e1b1e203db5..5925d11e2466 100644 --- a/drivers/gpu/drm/xilinx/xilinx_drm_crtc.c +++ b/drivers/gpu/drm/xilinx/xilinx_drm_crtc.c @@ -263,6 +263,16 @@ void xilinx_drm_crtc_destroy(struct drm_crtc *base_crtc) xilinx_drm_plane_remove_manager(crtc->plane_manager); } +/* crtc set config helper */ +int xilinx_drm_crtc_helper_set_config(struct drm_mode_set *set) +{ + struct drm_device *drm = set->crtc->dev; + + xilinx_drm_set_config(drm, set); + + return drm_crtc_helper_set_config(set); +} + /* cancel page flip functions */ void xilinx_drm_crtc_cancel_page_flip(struct drm_crtc *base_crtc, struct drm_file *file) @@ -429,7 +439,7 @@ unsigned int xilinx_drm_crtc_get_align(struct drm_crtc *base_crtc) static struct drm_crtc_funcs xilinx_drm_crtc_funcs = { .destroy = xilinx_drm_crtc_destroy, - .set_config = drm_crtc_helper_set_config, + .set_config = xilinx_drm_crtc_helper_set_config, .page_flip = xilinx_drm_crtc_page_flip, }; diff --git a/drivers/gpu/drm/xilinx/xilinx_drm_drv.c b/drivers/gpu/drm/xilinx/xilinx_drm_drv.c index d1b6ef89938c..6797e7839cb4 100644 --- a/drivers/gpu/drm/xilinx/xilinx_drm_drv.c +++ b/drivers/gpu/drm/xilinx/xilinx_drm_drv.c @@ -129,6 +129,14 @@ unsigned int xilinx_drm_get_align(struct drm_device *drm) return xilinx_drm_crtc_get_align(private->crtc); } +void xilinx_drm_set_config(struct drm_device *drm, struct drm_mode_set *set) +{ + struct xilinx_drm_private *private = drm->dev_private; + + if (private && private->fb) + xilinx_drm_fb_set_config(private->fb, set); +} + /* poll changed handler */ static void xilinx_drm_output_poll_changed(struct drm_device *drm) { diff --git a/drivers/gpu/drm/xilinx/xilinx_drm_drv.h b/drivers/gpu/drm/xilinx/xilinx_drm_drv.h index b8c42d0f73e3..223fc80c9b93 100644 --- a/drivers/gpu/drm/xilinx/xilinx_drm_drv.h +++ b/drivers/gpu/drm/xilinx/xilinx_drm_drv.h @@ -57,9 +57,11 @@ static inline void xilinx_drm_set(void __iomem *base, int offset, u32 set) } struct drm_device; +struct drm_mode_set; bool xilinx_drm_check_format(struct drm_device *drm, uint32_t fourcc); uint32_t xilinx_drm_get_format(struct drm_device *drm); unsigned int xilinx_drm_get_align(struct drm_device *drm); +void xilinx_drm_set_config(struct drm_device *drm, struct drm_mode_set *set); #endif /* _XILINX_DRM_H_ */ diff --git a/drivers/gpu/drm/xilinx/xilinx_drm_fb.c b/drivers/gpu/drm/xilinx/xilinx_drm_fb.c index 6a30c589bd72..2da099320738 100644 --- a/drivers/gpu/drm/xilinx/xilinx_drm_fb.c +++ b/drivers/gpu/drm/xilinx/xilinx_drm_fb.c @@ -38,6 +38,8 @@ struct xilinx_drm_fbdev { struct xilinx_drm_fb *fb; unsigned int align; unsigned int vres_mult; + struct drm_display_mode old_mode; + bool mode_backup; }; static inline struct xilinx_drm_fbdev *to_fbdev(struct drm_fb_helper *fb_helper) @@ -166,6 +168,29 @@ int xilinx_drm_fb_helper_pan_display(struct fb_var_screeninfo *var, return ret; } +/** + * xilinx_drm_fb_set_config - synchronize resolution changes with fbdev + * @fb_helper: fb helper structure + * @set: mode set configuration + */ +void xilinx_drm_fb_set_config(struct drm_fb_helper *fb_helper, + struct drm_mode_set *set) +{ + if (fb_helper && set) { + struct xilinx_drm_fbdev *fbdev = to_fbdev(fb_helper); + + if (fbdev && fb_helper->crtc_info && + fb_helper->crtc_info[0].mode_set.mode) { + if (!fbdev->mode_backup) { + fbdev->old_mode = + *fb_helper->crtc_info[0].mode_set.mode; + fbdev->mode_backup = true; + } + *fb_helper->crtc_info[0].mode_set.mode = *set->mode; + } + } +} + int xilinx_drm_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { @@ -414,6 +439,16 @@ void xilinx_drm_fb_fini(struct drm_fb_helper *fb_helper) */ void xilinx_drm_fb_restore_mode(struct drm_fb_helper *fb_helper) { + struct xilinx_drm_fbdev *fbdev = to_fbdev(fb_helper); + + /* restore old display mode */ + if (fb_helper && fbdev && fbdev->mode_backup && + fb_helper->crtc_info && + fb_helper->crtc_info[0].mode_set.mode) { + *fb_helper->crtc_info[0].mode_set.mode = fbdev->old_mode; + fbdev->mode_backup = false; + } + if (fb_helper) drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper); } @@ -506,6 +541,13 @@ err_gem_object_unreference: */ void xilinx_drm_fb_hotplug_event(struct drm_fb_helper *fb_helper) { + if (fb_helper) { + struct xilinx_drm_fbdev *fbdev = to_fbdev(fb_helper); + + if (fbdev) + fbdev->mode_backup = false; + } + if (fb_helper) drm_fb_helper_hotplug_event(fb_helper); } diff --git a/drivers/gpu/drm/xilinx/xilinx_drm_fb.h b/drivers/gpu/drm/xilinx/xilinx_drm_fb.h index ae91ace9a4e5..74b628c8b0e6 100644 --- a/drivers/gpu/drm/xilinx/xilinx_drm_fb.h +++ b/drivers/gpu/drm/xilinx/xilinx_drm_fb.h @@ -34,5 +34,7 @@ struct drm_framebuffer *xilinx_drm_fb_create(struct drm_device *drm, struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd); void xilinx_drm_fb_hotplug_event(struct drm_fb_helper *fb_helper); +void xilinx_drm_fb_set_config(struct drm_fb_helper *fb_helper, + struct drm_mode_set *set); #endif /* _XILINX_DRM_FB_H_ */ -- 2.39.2