]> rtime.felk.cvut.cz Git - zynq/linux.git/commitdiff
drm: xilinx: crtc: Add crtc set config helper xilinx-v2016.1-trd
authorPreetesh Parekh <preetesh.parekh@xilinx.com>
Fri, 3 Jun 2016 02:21:46 +0000 (19:21 -0700)
committerMichal Simek <michal.simek@xilinx.com>
Fri, 3 Jun 2016 13:03:22 +0000 (15:03 +0200)
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.  The framebuffer for the fbdev
emulation is allocated when the driver is initialized, thus hotplug
between monitors with different resolutions
(ex, 2560x1440->1920x1080) wouldn’t work correctly as of now.

Signed-off-by: Preetesh Parekh <preetesh.parekh@xilinx.com>
Tested-by: Hyun Kwon <hyun.kwon@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
drivers/gpu/drm/xilinx/xilinx_drm_crtc.c
drivers/gpu/drm/xilinx/xilinx_drm_drv.c
drivers/gpu/drm/xilinx/xilinx_drm_drv.h
drivers/gpu/drm/xilinx/xilinx_drm_fb.c
drivers/gpu/drm/xilinx/xilinx_drm_fb.h

index 2e1b1e203db5adf626ea014437f4bb5d22ba9d61..5925d11e2466dfdadc04076ca4b85e4de96158f2 100644 (file)
@@ -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,
 };
 
index d1b6ef89938c9df8ff931e71bb18c6ef47bd7561..6797e7839cb469586f4c6690b04952c4bb9934c1 100644 (file)
@@ -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)
 {
index b8c42d0f73e32dd052374a7e4f126d664b7b7d66..223fc80c9b9384f1f4412ee23fab6247a7f7b3c1 100644 (file)
@@ -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_ */
index 6a30c589bd723d7ff3c5f8330bd26eadb901c5f6..65d0b77f90227609f96d463db6d4fd327ff8823b 100644 (file)
@@ -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,30 @@ 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 && set->mode) {
+                       if (!fbdev->mode_backup) {
+                               fbdev->old_mode =
+                                       *fb_helper->crtc_info[0].mode_set.mode;
+                               fbdev->mode_backup = true;
+                       }
+                       drm_mode_copy(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 +440,17 @@ 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) {
+               drm_mode_copy(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 +543,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);
 }
index ae91ace9a4e55e53c0f05418cbe25797e8e11672..74b628c8b0e6c7638b8cdcbeb7fd8c18a35c1e2c 100644 (file)
@@ -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_ */