Browse Source

Merge tag 'drm-misc-next-2017-12-14' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

drm-misc-next for 4.16:

Cross-subsystem Changes:

 - Documentation for amlogic dt dt-bindings

Core Changes:

 - Update edid-derived drm_display_info fields at edid property set

Driver Changes:

 - A bunch of clean up from Noralf, including the last patches to reduce
 fbdev emulation footprint.

* tag 'drm-misc-next-2017-12-14' of git://anongit.freedesktop.org/drm/drm-misc: (30 commits)
  drm/atomic-helper: Make zpos property kerneldoc less misleading
  drm: Update edid-derived drm_display_info fields at edid property set [v2]
  MAINTAINERS: Remove Jani as drm-misc co-maintainer
  drm/tinydrm: Use drm_fb_cma_fbdev_init_with_funcs/fini()
  drm/arm/mali: Use drm_fb_cma_fbdev_init/fini()
  drm/zte: Use drm_fb_cma_fbdev_init/fini()
  drm/vc4: Use drm_fb_cma_fbdev_init/fini()
  drm/tve200: Use drm_fb_cma_fbdev_init/fini()
  drm/tilcdc: Use drm_fb_cma_fbdev_init/fini()
  drm/sun4i: Use drm_fb_cma_fbdev_init/fini()
  drm/stm: Use drm_fb_cma_fbdev_init/fini()
  drm/sti: Use drm_fb_cma_fbdev_init/fini()
  drm/pl111: Use drm_fb_cma_fbdev_init/fini()
  drm/imx: Use drm_fb_cma_fbdev_init/fini()
  drm/atmel-hlcdc: Use drm_fb_cma_fbdev_init/fini()
  drm/cma-helper: Add drm_fb_cma_fbdev_init/fini()
  drm/gem-fb-helper: drm_gem_fbdev_fb_create() make funcs optional
  drm/tegra: Use drm_fb_helper_lastclose() and _poll_changed()
  drm/rockchip: Use drm_fb_helper_lastclose() and _poll_changed()
  drm/omap: Use drm_fb_helper_lastclose() and _poll_changed()
  ...
Dave Airlie 7 years ago
parent
commit
a942b3c2cd
66 changed files with 319 additions and 530 deletions
  1. 4 0
      Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt
  2. 4 0
      Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt
  3. 0 5
      Documentation/gpu/todo.rst
  4. 0 1
      MAINTAINERS
  5. 7 32
      drivers/gpu/drm/arm/malidp_drv.c
  6. 0 1
      drivers/gpu/drm/arm/malidp_drv.h
  7. 0 1
      drivers/gpu/drm/armada/armada_drm.h
  8. 2 6
      drivers/gpu/drm/armada/armada_drv.c
  9. 1 10
      drivers/gpu/drm/armada/armada_fb.c
  10. 0 8
      drivers/gpu/drm/armada/armada_fbdev.c
  11. 4 22
      drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
  12. 1 1
      drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
  13. 5 3
      drivers/gpu/drm/drm_blend.c
  14. 13 0
      drivers/gpu/drm/drm_connector.c
  15. 39 14
      drivers/gpu/drm/drm_edid.c
  16. 116 3
      drivers/gpu/drm/drm_fb_cma_helper.c
  17. 5 1
      drivers/gpu/drm/drm_gem_framebuffer_helper.c
  18. 3 0
      drivers/gpu/drm/drm_mode_config.c
  19. 2 6
      drivers/gpu/drm/exynos/exynos_drm_drv.c
  20. 1 1
      drivers/gpu/drm/exynos/exynos_drm_fb.c
  21. 0 18
      drivers/gpu/drm/exynos/exynos_drm_fbdev.c
  22. 0 2
      drivers/gpu/drm/exynos/exynos_drm_fbdev.h
  23. 1 8
      drivers/gpu/drm/gma500/framebuffer.c
  24. 1 14
      drivers/gpu/drm/gma500/psb_drv.c
  25. 6 27
      drivers/gpu/drm/imx/imx-drm-core.c
  26. 0 1
      drivers/gpu/drm/imx/imx-drm.h
  27. 9 0
      drivers/gpu/drm/meson/meson_drv.c
  28. 13 0
      drivers/gpu/drm/meson/meson_dw_hdmi.c
  29. 4 0
      drivers/gpu/drm/meson/meson_registers.h
  30. 2 16
      drivers/gpu/drm/msm/msm_drv.c
  31. 2 1
      drivers/gpu/drm/nouveau/nouveau_display.c
  32. 0 8
      drivers/gpu/drm/nouveau/nouveau_fbcon.c
  33. 0 2
      drivers/gpu/drm/nouveau/nouveau_fbcon.h
  34. 2 1
      drivers/gpu/drm/nouveau/nouveau_vga.c
  35. 1 1
      drivers/gpu/drm/nouveau/nv50_display.c
  36. 2 32
      drivers/gpu/drm/omapdrm/omap_drv.c
  37. 0 1
      drivers/gpu/drm/pl111/pl111_drm.h
  38. 4 12
      drivers/gpu/drm/pl111/pl111_drv.c
  39. 1 8
      drivers/gpu/drm/rockchip/rockchip_drm_drv.c
  40. 1 8
      drivers/gpu/drm/rockchip/rockchip_drm_fb.c
  41. 5 22
      drivers/gpu/drm/sti/sti_drv.c
  42. 0 1
      drivers/gpu/drm/sti/sti_drv.h
  43. 6 32
      drivers/gpu/drm/stm/drv.c
  44. 0 1
      drivers/gpu/drm/stm/ltdc.h
  45. 3 11
      drivers/gpu/drm/sun4i/sun4i_drv.c
  46. 0 2
      drivers/gpu/drm/sun4i/sun4i_drv.h
  47. 5 13
      drivers/gpu/drm/sun4i/sun4i_framebuffer.c
  48. 1 1
      drivers/gpu/drm/sun4i/sun4i_framebuffer.h
  49. 2 11
      drivers/gpu/drm/tegra/drm.c
  50. 0 4
      drivers/gpu/drm/tegra/drm.h
  51. 0 14
      drivers/gpu/drm/tegra/fb.c
  52. 5 21
      drivers/gpu/drm/tilcdc/tilcdc_drv.c
  53. 0 2
      drivers/gpu/drm/tilcdc/tilcdc_drv.h
  54. 5 32
      drivers/gpu/drm/tinydrm/core/tinydrm-core.c
  55. 2 1
      drivers/gpu/drm/tinydrm/ili9225.c
  56. 2 1
      drivers/gpu/drm/tinydrm/mi0283qt.c
  57. 2 1
      drivers/gpu/drm/tinydrm/st7586.c
  58. 0 1
      drivers/gpu/drm/tve200/tve200_drm.h
  59. 4 12
      drivers/gpu/drm/tve200/tve200_drv.c
  60. 2 11
      drivers/gpu/drm/vc4/vc4_drv.c
  61. 0 2
      drivers/gpu/drm/vc4/vc4_drv.h
  62. 4 14
      drivers/gpu/drm/vc4/vc4_kms.c
  63. 6 42
      drivers/gpu/drm/zte/zx_drm_drv.c
  64. 2 0
      include/drm/drm_edid.h
  65. 7 0
      include/drm/drm_fb_cma_helper.h
  66. 0 3
      include/drm/tinydrm/tinydrm.h

+ 4 - 0
Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt

@@ -48,6 +48,10 @@ Required properties:
   Documentation/devicetree/bindings/reset/reset.txt,
   Documentation/devicetree/bindings/reset/reset.txt,
   the reset-names should be "hdmitx_apb", "hdmitx", "hdmitx_phy"
   the reset-names should be "hdmitx_apb", "hdmitx", "hdmitx_phy"
 
 
+Optional properties:
+- hdmi-supply: Optional phandle to an external 5V regulator to power the HDMI
+  logic, as described in the file ../regulator/regulator.txt
+
 Required nodes:
 Required nodes:
 
 
 The connections to the HDMI ports are modeled using the OF graph
 The connections to the HDMI ports are modeled using the OF graph

+ 4 - 0
Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt

@@ -64,6 +64,10 @@ Required properties:
 - reg-names: should contain the names of the previous memory regions
 - reg-names: should contain the names of the previous memory regions
 - interrupts: should contain the VENC Vsync interrupt number
 - interrupts: should contain the VENC Vsync interrupt number
 
 
+Optional properties:
+- power-domains: Optional phandle to associated power domain as described in
+	the file ../power/power_domain.txt
+
 Required nodes:
 Required nodes:
 
 
 The connections to the VPU output video ports are modeled using the OF graph
 The connections to the VPU output video ports are modeled using the OF graph

+ 0 - 5
Documentation/gpu/todo.rst

@@ -395,11 +395,6 @@ those drivers as simple as possible, so lots of room for refactoring:
   one of the ideas for having a shared dsi/dbi helper, abstracting away the
   one of the ideas for having a shared dsi/dbi helper, abstracting away the
   transport details more.
   transport details more.
 
 
-- tinydrm_lastclose could be drm_fb_helper_lastclose. Only thing we need
-  for that is to store the drm_fb_helper pointer somewhere in
-  drm_device->mode_config. And then we could roll that out to all the
-  drivers.
-
 - tinydrm_gem_cma_prime_import_sg_table should probably go into the cma
 - tinydrm_gem_cma_prime_import_sg_table should probably go into the cma
   helpers, as a _vmapped variant (since not every driver needs the vmap).
   helpers, as a _vmapped variant (since not every driver needs the vmap).
   And tinydrm_gem_cma_free_object could the be merged into
   And tinydrm_gem_cma_free_object could the be merged into

+ 0 - 1
MAINTAINERS

@@ -4592,7 +4592,6 @@ F:	include/linux/vga*
 
 
 DRM DRIVERS AND MISC GPU PATCHES
 DRM DRIVERS AND MISC GPU PATCHES
 M:	Daniel Vetter <daniel.vetter@intel.com>
 M:	Daniel Vetter <daniel.vetter@intel.com>
-M:	Jani Nikula <jani.nikula@linux.intel.com>
 M:	Gustavo Padovan <gustavo@padovan.org>
 M:	Gustavo Padovan <gustavo@padovan.org>
 M:	Sean Paul <seanpaul@chromium.org>
 M:	Sean Paul <seanpaul@chromium.org>
 W:	https://01.org/linuxgraphics/gfx-docs/maintainer-tools/drm-misc.html
 W:	https://01.org/linuxgraphics/gfx-docs/maintainer-tools/drm-misc.html

+ 7 - 32
drivers/gpu/drm/arm/malidp_drv.c

@@ -13,7 +13,6 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/clk.h>
 #include <linux/clk.h>
 #include <linux/component.h>
 #include <linux/component.h>
-#include <linux/console.h>
 #include <linux/of_device.h>
 #include <linux/of_device.h>
 #include <linux/of_graph.h>
 #include <linux/of_graph.h>
 #include <linux/of_reserved_mem.h>
 #include <linux/of_reserved_mem.h>
@@ -24,6 +23,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
@@ -183,13 +183,6 @@ static int malidp_set_and_wait_config_valid(struct drm_device *drm)
 	return (ret > 0) ? 0 : -ETIMEDOUT;
 	return (ret > 0) ? 0 : -ETIMEDOUT;
 }
 }
 
 
-static void malidp_output_poll_changed(struct drm_device *drm)
-{
-	struct malidp_drm *malidp = drm->dev_private;
-
-	drm_fbdev_cma_hotplug_event(malidp->fbdev);
-}
-
 static void malidp_atomic_commit_hw_done(struct drm_atomic_state *state)
 static void malidp_atomic_commit_hw_done(struct drm_atomic_state *state)
 {
 {
 	struct drm_pending_vblank_event *event;
 	struct drm_pending_vblank_event *event;
@@ -252,7 +245,7 @@ static const struct drm_mode_config_helper_funcs malidp_mode_config_helpers = {
 
 
 static const struct drm_mode_config_funcs malidp_mode_config_funcs = {
 static const struct drm_mode_config_funcs malidp_mode_config_funcs = {
 	.fb_create = drm_gem_fb_create,
 	.fb_create = drm_gem_fb_create,
-	.output_poll_changed = malidp_output_poll_changed,
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_commit = drm_atomic_helper_commit,
 	.atomic_commit = drm_atomic_helper_commit,
 };
 };
@@ -317,19 +310,12 @@ static int malidp_irq_init(struct platform_device *pdev)
 	return 0;
 	return 0;
 }
 }
 
 
-static void malidp_lastclose(struct drm_device *drm)
-{
-	struct malidp_drm *malidp = drm->dev_private;
-
-	drm_fbdev_cma_restore_mode(malidp->fbdev);
-}
-
 DEFINE_DRM_GEM_CMA_FOPS(fops);
 DEFINE_DRM_GEM_CMA_FOPS(fops);
 
 
 static struct drm_driver malidp_driver = {
 static struct drm_driver malidp_driver = {
 	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC |
 	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC |
 			   DRIVER_PRIME,
 			   DRIVER_PRIME,
-	.lastclose = malidp_lastclose,
+	.lastclose = drm_fb_helper_lastclose,
 	.gem_free_object_unlocked = drm_gem_cma_free_object,
 	.gem_free_object_unlocked = drm_gem_cma_free_object,
 	.gem_vm_ops = &drm_gem_cma_vm_ops,
 	.gem_vm_ops = &drm_gem_cma_vm_ops,
 	.dumb_create = drm_gem_cma_dumb_create,
 	.dumb_create = drm_gem_cma_dumb_create,
@@ -623,14 +609,9 @@ static int malidp_bind(struct device *dev)
 
 
 	drm_mode_config_reset(drm);
 	drm_mode_config_reset(drm);
 
 
-	malidp->fbdev = drm_fbdev_cma_init(drm, 32,
-					   drm->mode_config.num_connector);
-
-	if (IS_ERR(malidp->fbdev)) {
-		ret = PTR_ERR(malidp->fbdev);
-		malidp->fbdev = NULL;
+	ret = drm_fb_cma_fbdev_init(drm, 32, 0);
+	if (ret)
 		goto fbdev_fail;
 		goto fbdev_fail;
-	}
 
 
 	drm_kms_helper_poll_init(drm);
 	drm_kms_helper_poll_init(drm);
 
 
@@ -641,10 +622,7 @@ static int malidp_bind(struct device *dev)
 	return 0;
 	return 0;
 
 
 register_fail:
 register_fail:
-	if (malidp->fbdev) {
-		drm_fbdev_cma_fini(malidp->fbdev);
-		malidp->fbdev = NULL;
-	}
+	drm_fb_cma_fbdev_fini(drm);
 	drm_kms_helper_poll_fini(drm);
 	drm_kms_helper_poll_fini(drm);
 fbdev_fail:
 fbdev_fail:
 	pm_runtime_get_sync(dev);
 	pm_runtime_get_sync(dev);
@@ -681,10 +659,7 @@ static void malidp_unbind(struct device *dev)
 	struct malidp_drm *malidp = drm->dev_private;
 	struct malidp_drm *malidp = drm->dev_private;
 
 
 	drm_dev_unregister(drm);
 	drm_dev_unregister(drm);
-	if (malidp->fbdev) {
-		drm_fbdev_cma_fini(malidp->fbdev);
-		malidp->fbdev = NULL;
-	}
+	drm_fb_cma_fbdev_fini(drm);
 	drm_kms_helper_poll_fini(drm);
 	drm_kms_helper_poll_fini(drm);
 	pm_runtime_get_sync(dev);
 	pm_runtime_get_sync(dev);
 	malidp_se_irq_fini(drm);
 	malidp_se_irq_fini(drm);

+ 0 - 1
drivers/gpu/drm/arm/malidp_drv.h

@@ -20,7 +20,6 @@
 
 
 struct malidp_drm {
 struct malidp_drm {
 	struct malidp_hw_device *dev;
 	struct malidp_hw_device *dev;
-	struct drm_fbdev_cma *fbdev;
 	struct drm_crtc crtc;
 	struct drm_crtc crtc;
 	wait_queue_head_t wq;
 	wait_queue_head_t wq;
 	atomic_t config_valid;
 	atomic_t config_valid;

+ 0 - 1
drivers/gpu/drm/armada/armada_drm.h

@@ -84,7 +84,6 @@ void armada_drm_queue_unref_work(struct drm_device *,
 extern const struct drm_mode_config_funcs armada_drm_mode_config_funcs;
 extern const struct drm_mode_config_funcs armada_drm_mode_config_funcs;
 
 
 int armada_fbdev_init(struct drm_device *);
 int armada_fbdev_init(struct drm_device *);
-void armada_fbdev_lastclose(struct drm_device *);
 void armada_fbdev_fini(struct drm_device *);
 void armada_fbdev_fini(struct drm_device *);
 
 
 int armada_overlay_plane_create(struct drm_device *, unsigned long);
 int armada_overlay_plane_create(struct drm_device *, unsigned long);

+ 2 - 6
drivers/gpu/drm/armada/armada_drv.c

@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/of_graph.h>
 #include <linux/of_graph.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_of.h>
 #include <drm/drm_of.h>
 #include "armada_crtc.h"
 #include "armada_crtc.h"
 #include "armada_drm.h"
 #include "armada_drm.h"
@@ -54,15 +55,10 @@ static struct drm_ioctl_desc armada_ioctls[] = {
 	DRM_IOCTL_DEF_DRV(ARMADA_GEM_PWRITE, armada_gem_pwrite_ioctl, 0),
 	DRM_IOCTL_DEF_DRV(ARMADA_GEM_PWRITE, armada_gem_pwrite_ioctl, 0),
 };
 };
 
 
-static void armada_drm_lastclose(struct drm_device *dev)
-{
-	armada_fbdev_lastclose(dev);
-}
-
 DEFINE_DRM_GEM_FOPS(armada_drm_fops);
 DEFINE_DRM_GEM_FOPS(armada_drm_fops);
 
 
 static struct drm_driver armada_drm_driver = {
 static struct drm_driver armada_drm_driver = {
-	.lastclose		= armada_drm_lastclose,
+	.lastclose		= drm_fb_helper_lastclose,
 	.gem_free_object_unlocked = armada_gem_free_object,
 	.gem_free_object_unlocked = armada_gem_free_object,
 	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
 	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
 	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
 	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,

+ 1 - 10
drivers/gpu/drm/armada/armada_fb.c

@@ -154,16 +154,7 @@ static struct drm_framebuffer *armada_fb_create(struct drm_device *dev,
 	return ERR_PTR(ret);
 	return ERR_PTR(ret);
 }
 }
 
 
-static void armada_output_poll_changed(struct drm_device *dev)
-{
-	struct armada_private *priv = dev->dev_private;
-	struct drm_fb_helper *fbh = priv->fbdev;
-
-	if (fbh)
-		drm_fb_helper_hotplug_event(fbh);
-}
-
 const struct drm_mode_config_funcs armada_drm_mode_config_funcs = {
 const struct drm_mode_config_funcs armada_drm_mode_config_funcs = {
 	.fb_create		= armada_fb_create,
 	.fb_create		= armada_fb_create,
-	.output_poll_changed	= armada_output_poll_changed,
+	.output_poll_changed	= drm_fb_helper_output_poll_changed,
 };
 };

+ 0 - 8
drivers/gpu/drm/armada/armada_fbdev.c

@@ -159,14 +159,6 @@ int armada_fbdev_init(struct drm_device *dev)
 	return ret;
 	return ret;
 }
 }
 
 
-void armada_fbdev_lastclose(struct drm_device *dev)
-{
-	struct armada_private *priv = dev->dev_private;
-
-	if (priv->fbdev)
-		drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev);
-}
-
 void armada_fbdev_fini(struct drm_device *dev)
 void armada_fbdev_fini(struct drm_device *dev)
 {
 {
 	struct armada_private *priv = dev->dev_private;
 	struct armada_private *priv = dev->dev_private;

+ 4 - 22
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c

@@ -461,13 +461,6 @@ static struct drm_framebuffer *atmel_hlcdc_fb_create(struct drm_device *dev,
 	return drm_gem_fb_create(dev, file_priv, mode_cmd);
 	return drm_gem_fb_create(dev, file_priv, mode_cmd);
 }
 }
 
 
-static void atmel_hlcdc_fb_output_poll_changed(struct drm_device *dev)
-{
-	struct atmel_hlcdc_dc *dc = dev->dev_private;
-
-	drm_fbdev_cma_hotplug_event(dc->fbdev);
-}
-
 struct atmel_hlcdc_dc_commit {
 struct atmel_hlcdc_dc_commit {
 	struct work_struct work;
 	struct work_struct work;
 	struct drm_device *dev;
 	struct drm_device *dev;
@@ -563,7 +556,7 @@ error:
 
 
 static const struct drm_mode_config_funcs mode_config_funcs = {
 static const struct drm_mode_config_funcs mode_config_funcs = {
 	.fb_create = atmel_hlcdc_fb_create,
 	.fb_create = atmel_hlcdc_fb_create,
-	.output_poll_changed = atmel_hlcdc_fb_output_poll_changed,
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_commit = atmel_hlcdc_dc_atomic_commit,
 	.atomic_commit = atmel_hlcdc_dc_atomic_commit,
 };
 };
@@ -665,10 +658,7 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev)
 
 
 	platform_set_drvdata(pdev, dev);
 	platform_set_drvdata(pdev, dev);
 
 
-	dc->fbdev = drm_fbdev_cma_init(dev, 24,
-			dev->mode_config.num_connector);
-	if (IS_ERR(dc->fbdev))
-		dc->fbdev = NULL;
+	drm_fb_cma_fbdev_init(dev, 24, 0);
 
 
 	drm_kms_helper_poll_init(dev);
 	drm_kms_helper_poll_init(dev);
 
 
@@ -688,8 +678,7 @@ static void atmel_hlcdc_dc_unload(struct drm_device *dev)
 {
 {
 	struct atmel_hlcdc_dc *dc = dev->dev_private;
 	struct atmel_hlcdc_dc *dc = dev->dev_private;
 
 
-	if (dc->fbdev)
-		drm_fbdev_cma_fini(dc->fbdev);
+	drm_fb_cma_fbdev_fini(dev);
 	flush_workqueue(dc->wq);
 	flush_workqueue(dc->wq);
 	drm_kms_helper_poll_fini(dev);
 	drm_kms_helper_poll_fini(dev);
 	drm_mode_config_cleanup(dev);
 	drm_mode_config_cleanup(dev);
@@ -705,13 +694,6 @@ static void atmel_hlcdc_dc_unload(struct drm_device *dev)
 	destroy_workqueue(dc->wq);
 	destroy_workqueue(dc->wq);
 }
 }
 
 
-static void atmel_hlcdc_dc_lastclose(struct drm_device *dev)
-{
-	struct atmel_hlcdc_dc *dc = dev->dev_private;
-
-	drm_fbdev_cma_restore_mode(dc->fbdev);
-}
-
 static int atmel_hlcdc_dc_irq_postinstall(struct drm_device *dev)
 static int atmel_hlcdc_dc_irq_postinstall(struct drm_device *dev)
 {
 {
 	struct atmel_hlcdc_dc *dc = dev->dev_private;
 	struct atmel_hlcdc_dc *dc = dev->dev_private;
@@ -744,7 +726,7 @@ static struct drm_driver atmel_hlcdc_dc_driver = {
 	.driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM |
 	.driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM |
 			   DRIVER_MODESET | DRIVER_PRIME |
 			   DRIVER_MODESET | DRIVER_PRIME |
 			   DRIVER_ATOMIC,
 			   DRIVER_ATOMIC,
-	.lastclose = atmel_hlcdc_dc_lastclose,
+	.lastclose = drm_fb_helper_lastclose,
 	.irq_handler = atmel_hlcdc_dc_irq_handler,
 	.irq_handler = atmel_hlcdc_dc_irq_handler,
 	.irq_preinstall = atmel_hlcdc_dc_irq_uninstall,
 	.irq_preinstall = atmel_hlcdc_dc_irq_uninstall,
 	.irq_postinstall = atmel_hlcdc_dc_irq_postinstall,
 	.irq_postinstall = atmel_hlcdc_dc_irq_postinstall,

+ 1 - 1
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h

@@ -32,6 +32,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
@@ -374,7 +375,6 @@ struct atmel_hlcdc_dc {
 	const struct atmel_hlcdc_dc_desc *desc;
 	const struct atmel_hlcdc_dc_desc *desc;
 	struct dma_pool *dscrpool;
 	struct dma_pool *dscrpool;
 	struct atmel_hlcdc *hlcdc;
 	struct atmel_hlcdc *hlcdc;
-	struct drm_fbdev_cma *fbdev;
 	struct drm_crtc *crtc;
 	struct drm_crtc *crtc;
 	struct atmel_hlcdc_layer *layers[ATMEL_HLCDC_MAX_LAYERS];
 	struct atmel_hlcdc_layer *layers[ATMEL_HLCDC_MAX_LAYERS];
 	struct workqueue_struct *wq;
 	struct workqueue_struct *wq;

+ 5 - 3
drivers/gpu/drm/drm_blend.c

@@ -214,9 +214,11 @@ EXPORT_SYMBOL(drm_rotation_simplify);
  * This function initializes generic mutable zpos property and enables support
  * This function initializes generic mutable zpos property and enables support
  * for it in drm core. Drivers can then attach this property to planes to enable
  * for it in drm core. Drivers can then attach this property to planes to enable
  * support for configurable planes arrangement during blending operation.
  * support for configurable planes arrangement during blending operation.
- * Once mutable zpos property has been enabled, the DRM core will automatically
- * calculate &drm_plane_state.normalized_zpos values. Usually min should be set
- * to 0 and max to maximal number of planes for given crtc - 1.
+ * Drivers that attach a mutable zpos property to any plane should call the
+ * drm_atomic_normalize_zpos() helper during their implementation of
+ * &drm_mode_config_funcs.atomic_check(), which will update the normalized zpos
+ * values and store them in &drm_plane_state.normalized_zpos. Usually min
+ * should be set to 0 and max to maximal number of planes for given crtc - 1.
  *
  *
  * If zpos of some planes cannot be changed (like fixed background or
  * If zpos of some planes cannot be changed (like fixed background or
  * cursor/topmost planes), driver should adjust min/max values and assign those
  * cursor/topmost planes), driver should adjust min/max values and assign those

+ 13 - 0
drivers/gpu/drm/drm_connector.c

@@ -1229,6 +1229,19 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
 	if (edid)
 	if (edid)
 		size = EDID_LENGTH * (1 + edid->extensions);
 		size = EDID_LENGTH * (1 + edid->extensions);
 
 
+	/* Set the display info, using edid if available, otherwise
+	 * reseting the values to defaults. This duplicates the work
+	 * done in drm_add_edid_modes, but that function is not
+	 * consistently called before this one in all drivers and the
+	 * computation is cheap enough that it seems better to
+	 * duplicate it rather than attempt to ensure some arbitrary
+	 * ordering of calls.
+	 */
+	if (edid)
+		drm_add_display_info(connector, edid);
+	else
+		drm_reset_display_info(connector);
+
 	drm_object_property_set_value(&connector->base,
 	drm_object_property_set_value(&connector->base,
 				      dev->mode_config.non_desktop_property,
 				      dev->mode_config.non_desktop_property,
 				      connector->display_info.non_desktop);
 				      connector->display_info.non_desktop);

+ 39 - 14
drivers/gpu/drm/drm_edid.c

@@ -1731,7 +1731,7 @@ EXPORT_SYMBOL(drm_edid_duplicate);
  *
  *
  * Returns true if @vendor is in @edid, false otherwise
  * Returns true if @vendor is in @edid, false otherwise
  */
  */
-static bool edid_vendor(struct edid *edid, const char *vendor)
+static bool edid_vendor(const struct edid *edid, const char *vendor)
 {
 {
 	char edid_vendor[3];
 	char edid_vendor[3];
 
 
@@ -1749,7 +1749,7 @@ static bool edid_vendor(struct edid *edid, const char *vendor)
  *
  *
  * This tells subsequent routines what fixes they need to apply.
  * This tells subsequent routines what fixes they need to apply.
  */
  */
-static u32 edid_get_quirks(struct edid *edid)
+static u32 edid_get_quirks(const struct edid *edid)
 {
 {
 	const struct edid_quirk *quirk;
 	const struct edid_quirk *quirk;
 	int i;
 	int i;
@@ -2813,7 +2813,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
 /*
 /*
  * Search EDID for CEA extension block.
  * Search EDID for CEA extension block.
  */
  */
-static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
+static u8 *drm_find_edid_extension(const struct edid *edid, int ext_id)
 {
 {
 	u8 *edid_ext = NULL;
 	u8 *edid_ext = NULL;
 	int i;
 	int i;
@@ -2835,12 +2835,12 @@ static u8 *drm_find_edid_extension(struct edid *edid, int ext_id)
 	return edid_ext;
 	return edid_ext;
 }
 }
 
 
-static u8 *drm_find_cea_extension(struct edid *edid)
+static u8 *drm_find_cea_extension(const struct edid *edid)
 {
 {
 	return drm_find_edid_extension(edid, CEA_EXT);
 	return drm_find_edid_extension(edid, CEA_EXT);
 }
 }
 
 
-static u8 *drm_find_displayid_extension(struct edid *edid)
+static u8 *drm_find_displayid_extension(const struct edid *edid)
 {
 {
 	return drm_find_edid_extension(edid, DISPLAYID_EXT);
 	return drm_find_edid_extension(edid, DISPLAYID_EXT);
 }
 }
@@ -4378,7 +4378,7 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db)
 }
 }
 
 
 static void drm_parse_cea_ext(struct drm_connector *connector,
 static void drm_parse_cea_ext(struct drm_connector *connector,
-			      struct edid *edid)
+			      const struct edid *edid)
 {
 {
 	struct drm_display_info *info = &connector->display_info;
 	struct drm_display_info *info = &connector->display_info;
 	const u8 *edid_ext;
 	const u8 *edid_ext;
@@ -4412,11 +4412,34 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
 	}
 	}
 }
 }
 
 
-static void drm_add_display_info(struct drm_connector *connector,
-				 struct edid *edid, u32 quirks)
+/* A connector has no EDID information, so we've got no EDID to compute quirks from. Reset
+ * all of the values which would have been set from EDID
+ */
+void
+drm_reset_display_info(struct drm_connector *connector)
+{
+	struct drm_display_info *info = &connector->display_info;
+
+	info->width_mm = 0;
+	info->height_mm = 0;
+
+	info->bpc = 0;
+	info->color_formats = 0;
+	info->cea_rev = 0;
+	info->max_tmds_clock = 0;
+	info->dvi_dual = false;
+	info->has_hdmi_infoframe = false;
+
+	info->non_desktop = 0;
+}
+EXPORT_SYMBOL_GPL(drm_reset_display_info);
+
+u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid)
 {
 {
 	struct drm_display_info *info = &connector->display_info;
 	struct drm_display_info *info = &connector->display_info;
 
 
+	u32 quirks = edid_get_quirks(edid);
+
 	info->width_mm = edid->width_cm * 10;
 	info->width_mm = edid->width_cm * 10;
 	info->height_mm = edid->height_cm * 10;
 	info->height_mm = edid->height_cm * 10;
 
 
@@ -4430,11 +4453,13 @@ static void drm_add_display_info(struct drm_connector *connector,
 
 
 	info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP);
 	info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP);
 
 
+	DRM_DEBUG_KMS("non_desktop set to %d\n", info->non_desktop);
+
 	if (edid->revision < 3)
 	if (edid->revision < 3)
-		return;
+		return quirks;
 
 
 	if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
 	if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
-		return;
+		return quirks;
 
 
 	drm_parse_cea_ext(connector, edid);
 	drm_parse_cea_ext(connector, edid);
 
 
@@ -4454,7 +4479,7 @@ static void drm_add_display_info(struct drm_connector *connector,
 
 
 	/* Only defined for 1.4 with digital displays */
 	/* Only defined for 1.4 with digital displays */
 	if (edid->revision < 4)
 	if (edid->revision < 4)
-		return;
+		return quirks;
 
 
 	switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
 	switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
 	case DRM_EDID_DIGITAL_DEPTH_6:
 	case DRM_EDID_DIGITAL_DEPTH_6:
@@ -4489,7 +4514,9 @@ static void drm_add_display_info(struct drm_connector *connector,
 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
 	if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
 	if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
 		info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
+	return quirks;
 }
 }
+EXPORT_SYMBOL_GPL(drm_add_display_info);
 
 
 static int validate_displayid(u8 *displayid, int length, int idx)
 static int validate_displayid(u8 *displayid, int length, int idx)
 {
 {
@@ -4645,8 +4672,6 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
 		return 0;
 		return 0;
 	}
 	}
 
 
-	quirks = edid_get_quirks(edid);
-
 	drm_edid_to_eld(connector, edid);
 	drm_edid_to_eld(connector, edid);
 
 
 	/*
 	/*
@@ -4654,7 +4679,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
 	 * To avoid multiple parsing of same block, lets parse that map
 	 * To avoid multiple parsing of same block, lets parse that map
 	 * from sink info, before parsing CEA modes.
 	 * from sink info, before parsing CEA modes.
 	 */
 	 */
-	drm_add_display_info(connector, edid, quirks);
+	quirks = drm_add_display_info(connector, edid);
 
 
 	/*
 	/*
 	 * EDID spec says modes should be preferred in this order:
 	 * EDID spec says modes should be preferred in this order:

+ 116 - 3
drivers/gpu/drm/drm_fb_cma_helper.c

@@ -23,6 +23,7 @@
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_print.h>
 #include <linux/module.h>
 #include <linux/module.h>
 
 
 #define DEFAULT_FBDEFIO_DELAY_MS 50
 #define DEFAULT_FBDEFIO_DELAY_MS 50
@@ -42,7 +43,7 @@ struct drm_fbdev_cma {
  * callback function to create a cma backed framebuffer.
  * callback function to create a cma backed framebuffer.
  *
  *
  * An fbdev framebuffer backed by cma is also available by calling
  * An fbdev framebuffer backed by cma is also available by calling
- * drm_fbdev_cma_init(). drm_fbdev_cma_fini() tears it down.
+ * drm_fb_cma_fbdev_init(). drm_fb_cma_fbdev_fini() tears it down.
  * If the &drm_framebuffer_funcs.dirty callback is set, fb_deferred_io will be
  * If the &drm_framebuffer_funcs.dirty callback is set, fb_deferred_io will be
  * set up automatically. &drm_framebuffer_funcs.dirty is called by
  * set up automatically. &drm_framebuffer_funcs.dirty is called by
  * drm_fb_helper_deferred_io() in process context (&struct delayed_work).
  * drm_fb_helper_deferred_io() in process context (&struct delayed_work).
@@ -68,7 +69,7 @@ struct drm_fbdev_cma {
  *
  *
  * Initialize::
  * Initialize::
  *
  *
- *     fbdev = drm_fbdev_cma_init_with_funcs(dev, 16,
+ *     fbdev = drm_fb_cma_fbdev_init_with_funcs(dev, 16,
  *                                           dev->mode_config.num_crtc,
  *                                           dev->mode_config.num_crtc,
  *                                           dev->mode_config.num_connector,
  *                                           dev->mode_config.num_connector,
  *                                           &driver_fb_funcs);
  *                                           &driver_fb_funcs);
@@ -256,7 +257,7 @@ drm_fbdev_cma_create(struct drm_fb_helper *helper,
 	fbi->screen_size = size;
 	fbi->screen_size = size;
 	fbi->fix.smem_len = size;
 	fbi->fix.smem_len = size;
 
 
-	if (fbdev_cma->fb_funcs->dirty) {
+	if (fb->funcs->dirty) {
 		ret = drm_fbdev_cma_defio_init(fbi, obj);
 		ret = drm_fbdev_cma_defio_init(fbi, obj);
 		if (ret)
 		if (ret)
 			goto err_cma_destroy;
 			goto err_cma_destroy;
@@ -277,6 +278,118 @@ static const struct drm_fb_helper_funcs drm_fb_cma_helper_funcs = {
 	.fb_probe = drm_fbdev_cma_create,
 	.fb_probe = drm_fbdev_cma_create,
 };
 };
 
 
+/**
+ * drm_fb_cma_fbdev_init_with_funcs() - Allocate and initialize fbdev emulation
+ * @dev: DRM device
+ * @preferred_bpp: Preferred bits per pixel for the device.
+ *                 @dev->mode_config.preferred_depth is used if this is zero.
+ * @max_conn_count: Maximum number of connectors.
+ *                  @dev->mode_config.num_connector is used if this is zero.
+ * @funcs: Framebuffer functions, in particular a custom dirty() callback.
+ *         Can be NULL.
+ *
+ * Returns:
+ * Zero on success or negative error code on failure.
+ */
+int drm_fb_cma_fbdev_init_with_funcs(struct drm_device *dev,
+	unsigned int preferred_bpp, unsigned int max_conn_count,
+	const struct drm_framebuffer_funcs *funcs)
+{
+	struct drm_fbdev_cma *fbdev_cma;
+	struct drm_fb_helper *fb_helper;
+	int ret;
+
+	if (!preferred_bpp)
+		preferred_bpp = dev->mode_config.preferred_depth;
+	if (!preferred_bpp)
+		preferred_bpp = 32;
+
+	if (!max_conn_count)
+		max_conn_count = dev->mode_config.num_connector;
+
+	fbdev_cma = kzalloc(sizeof(*fbdev_cma), GFP_KERNEL);
+	if (!fbdev_cma)
+		return -ENOMEM;
+
+	fbdev_cma->fb_funcs = funcs;
+	fb_helper = &fbdev_cma->fb_helper;
+
+	drm_fb_helper_prepare(dev, fb_helper, &drm_fb_cma_helper_funcs);
+
+	ret = drm_fb_helper_init(dev, fb_helper, max_conn_count);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev->dev, "Failed to initialize fbdev helper.\n");
+		goto err_free;
+	}
+
+	ret = drm_fb_helper_single_add_all_connectors(fb_helper);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev->dev, "Failed to add connectors.\n");
+		goto err_drm_fb_helper_fini;
+	}
+
+	ret = drm_fb_helper_initial_config(fb_helper, preferred_bpp);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev->dev, "Failed to set fbdev configuration.\n");
+		goto err_drm_fb_helper_fini;
+	}
+
+	return 0;
+
+err_drm_fb_helper_fini:
+	drm_fb_helper_fini(fb_helper);
+err_free:
+	kfree(fbdev_cma);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(drm_fb_cma_fbdev_init_with_funcs);
+
+/**
+ * drm_fb_cma_fbdev_init() - Allocate and initialize fbdev emulation
+ * @dev: DRM device
+ * @preferred_bpp: Preferred bits per pixel for the device.
+ *                 @dev->mode_config.preferred_depth is used if this is zero.
+ * @max_conn_count: Maximum number of connectors.
+ *                  @dev->mode_config.num_connector is used if this is zero.
+ *
+ * Returns:
+ * Zero on success or negative error code on failure.
+ */
+int drm_fb_cma_fbdev_init(struct drm_device *dev, unsigned int preferred_bpp,
+			  unsigned int max_conn_count)
+{
+	return drm_fb_cma_fbdev_init_with_funcs(dev, preferred_bpp,
+						max_conn_count, NULL);
+}
+EXPORT_SYMBOL_GPL(drm_fb_cma_fbdev_init);
+
+/**
+ * drm_fb_cma_fbdev_fini() - Teardown fbdev emulation
+ * @dev: DRM device
+ */
+void drm_fb_cma_fbdev_fini(struct drm_device *dev)
+{
+	struct drm_fb_helper *fb_helper = dev->fb_helper;
+
+	if (!fb_helper)
+		return;
+
+	/* Unregister if it hasn't been done already */
+	if (fb_helper->fbdev && fb_helper->fbdev->dev)
+		drm_fb_helper_unregister_fbi(fb_helper);
+
+	if (fb_helper->fbdev)
+		drm_fbdev_cma_defio_fini(fb_helper->fbdev);
+
+	if (fb_helper->fb)
+		drm_framebuffer_remove(fb_helper->fb);
+
+	drm_fb_helper_fini(fb_helper);
+	kfree(to_fbdev_cma(fb_helper));
+}
+EXPORT_SYMBOL_GPL(drm_fb_cma_fbdev_fini);
+
 /**
 /**
  * drm_fbdev_cma_init_with_funcs() - Allocate and initializes a drm_fbdev_cma struct
  * drm_fbdev_cma_init_with_funcs() - Allocate and initializes a drm_fbdev_cma struct
  * @dev: DRM device
  * @dev: DRM device

+ 5 - 1
drivers/gpu/drm/drm_gem_framebuffer_helper.c

@@ -272,7 +272,8 @@ EXPORT_SYMBOL_GPL(drm_gem_fb_prepare_fb);
  * @sizes: fbdev size description
  * @sizes: fbdev size description
  * @pitch_align: Optional pitch alignment
  * @pitch_align: Optional pitch alignment
  * @obj: GEM object backing the framebuffer
  * @obj: GEM object backing the framebuffer
- * @funcs: vtable to be used for the new framebuffer object
+ * @funcs: Optional vtable to be used for the new framebuffer object when the
+ *         dirty callback is needed.
  *
  *
  * This function creates a framebuffer from a &drm_fb_helper_surface_size
  * This function creates a framebuffer from a &drm_fb_helper_surface_size
  * description for use in the &drm_fb_helper_funcs.fb_probe callback.
  * description for use in the &drm_fb_helper_funcs.fb_probe callback.
@@ -300,6 +301,9 @@ drm_gem_fbdev_fb_create(struct drm_device *dev,
 	if (obj->size < mode_cmd.pitches[0] * mode_cmd.height)
 	if (obj->size < mode_cmd.pitches[0] * mode_cmd.height)
 		return ERR_PTR(-EINVAL);
 		return ERR_PTR(-EINVAL);
 
 
+	if (!funcs)
+		funcs = &drm_gem_fb_funcs;
+
 	return drm_gem_fb_alloc(dev, &mode_cmd, &obj, 1, funcs);
 	return drm_gem_fb_alloc(dev, &mode_cmd, &obj, 1, funcs);
 }
 }
 EXPORT_SYMBOL(drm_gem_fbdev_fb_create);
 EXPORT_SYMBOL(drm_gem_fbdev_fb_create);

+ 3 - 0
drivers/gpu/drm/drm_mode_config.c

@@ -467,6 +467,9 @@ void drm_mode_config_cleanup(struct drm_device *dev)
 	 */
 	 */
 	WARN_ON(!list_empty(&dev->mode_config.fb_list));
 	WARN_ON(!list_empty(&dev->mode_config.fb_list));
 	list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
 	list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
+		struct drm_printer p = drm_debug_printer("[leaked fb]");
+		drm_printf(&p, "framebuffer[%u]:\n", fb->base.id);
+		drm_framebuffer_print_info(&p, 1, fb);
 		drm_framebuffer_free(&fb->base.refcount);
 		drm_framebuffer_free(&fb->base.refcount);
 	}
 	}
 
 

+ 2 - 6
drivers/gpu/drm/exynos/exynos_drm_drv.c

@@ -16,6 +16,7 @@
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
 
 
 #include <linux/component.h>
 #include <linux/component.h>
 
 
@@ -89,11 +90,6 @@ static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
 	file->driver_priv = NULL;
 	file->driver_priv = NULL;
 }
 }
 
 
-static void exynos_drm_lastclose(struct drm_device *dev)
-{
-	exynos_drm_fbdev_restore_mode(dev);
-}
-
 static const struct vm_operations_struct exynos_drm_gem_vm_ops = {
 static const struct vm_operations_struct exynos_drm_gem_vm_ops = {
 	.fault = exynos_drm_gem_fault,
 	.fault = exynos_drm_gem_fault,
 	.open = drm_gem_vm_open,
 	.open = drm_gem_vm_open,
@@ -140,7 +136,7 @@ static struct drm_driver exynos_drm_driver = {
 	.driver_features	= DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME
 	.driver_features	= DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME
 				  | DRIVER_ATOMIC | DRIVER_RENDER,
 				  | DRIVER_ATOMIC | DRIVER_RENDER,
 	.open			= exynos_drm_open,
 	.open			= exynos_drm_open,
-	.lastclose		= exynos_drm_lastclose,
+	.lastclose		= drm_fb_helper_lastclose,
 	.postclose		= exynos_drm_postclose,
 	.postclose		= exynos_drm_postclose,
 	.gem_free_object_unlocked = exynos_drm_gem_free_object,
 	.gem_free_object_unlocked = exynos_drm_gem_free_object,
 	.gem_vm_ops		= &exynos_drm_gem_vm_ops,
 	.gem_vm_ops		= &exynos_drm_gem_vm_ops,

+ 1 - 1
drivers/gpu/drm/exynos/exynos_drm_fb.c

@@ -205,7 +205,7 @@ static struct drm_mode_config_helper_funcs exynos_drm_mode_config_helpers = {
 
 
 static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
 static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
 	.fb_create = exynos_user_fb_create,
 	.fb_create = exynos_user_fb_create,
-	.output_poll_changed = exynos_drm_output_poll_changed,
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
 	.atomic_check = exynos_atomic_check,
 	.atomic_check = exynos_atomic_check,
 	.atomic_commit = drm_atomic_helper_commit,
 	.atomic_commit = drm_atomic_helper_commit,
 };
 };

+ 0 - 18
drivers/gpu/drm/exynos/exynos_drm_fbdev.c

@@ -270,24 +270,6 @@ void exynos_drm_fbdev_fini(struct drm_device *dev)
 	private->fb_helper = NULL;
 	private->fb_helper = NULL;
 }
 }
 
 
-void exynos_drm_fbdev_restore_mode(struct drm_device *dev)
-{
-	struct exynos_drm_private *private = dev->dev_private;
-
-	if (!private || !private->fb_helper)
-		return;
-
-	drm_fb_helper_restore_fbdev_mode_unlocked(private->fb_helper);
-}
-
-void exynos_drm_output_poll_changed(struct drm_device *dev)
-{
-	struct exynos_drm_private *private = dev->dev_private;
-	struct drm_fb_helper *fb_helper = private->fb_helper;
-
-	drm_fb_helper_hotplug_event(fb_helper);
-}
-
 void exynos_drm_fbdev_suspend(struct drm_device *dev)
 void exynos_drm_fbdev_suspend(struct drm_device *dev)
 {
 {
 	struct exynos_drm_private *private = dev->dev_private;
 	struct exynos_drm_private *private = dev->dev_private;

+ 0 - 2
drivers/gpu/drm/exynos/exynos_drm_fbdev.h

@@ -19,8 +19,6 @@
 
 
 int exynos_drm_fbdev_init(struct drm_device *dev);
 int exynos_drm_fbdev_init(struct drm_device *dev);
 void exynos_drm_fbdev_fini(struct drm_device *dev);
 void exynos_drm_fbdev_fini(struct drm_device *dev);
-void exynos_drm_fbdev_restore_mode(struct drm_device *dev);
-void exynos_drm_output_poll_changed(struct drm_device *dev);
 void exynos_drm_fbdev_suspend(struct drm_device *drm);
 void exynos_drm_fbdev_suspend(struct drm_device *drm);
 void exynos_drm_fbdev_resume(struct drm_device *drm);
 void exynos_drm_fbdev_resume(struct drm_device *drm);
 
 

+ 1 - 8
drivers/gpu/drm/gma500/framebuffer.c

@@ -576,13 +576,6 @@ static void psb_fbdev_fini(struct drm_device *dev)
 	dev_priv->fbdev = NULL;
 	dev_priv->fbdev = NULL;
 }
 }
 
 
-static void psbfb_output_poll_changed(struct drm_device *dev)
-{
-	struct drm_psb_private *dev_priv = dev->dev_private;
-	struct psb_fbdev *fbdev = (struct psb_fbdev *)dev_priv->fbdev;
-	drm_fb_helper_hotplug_event(&fbdev->psb_fb_helper);
-}
-
 /**
 /**
  *	psb_user_framebuffer_create_handle - add hamdle to a framebuffer
  *	psb_user_framebuffer_create_handle - add hamdle to a framebuffer
  *	@fb: framebuffer
  *	@fb: framebuffer
@@ -623,7 +616,7 @@ static void psb_user_framebuffer_destroy(struct drm_framebuffer *fb)
 
 
 static const struct drm_mode_config_funcs psb_mode_funcs = {
 static const struct drm_mode_config_funcs psb_mode_funcs = {
 	.fb_create = psb_user_framebuffer_create,
 	.fb_create = psb_user_framebuffer_create,
-	.output_poll_changed = psbfb_output_poll_changed,
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
 };
 };
 
 
 static void psb_setup_outputs(struct drm_device *dev)
 static void psb_setup_outputs(struct drm_device *dev)

+ 1 - 14
drivers/gpu/drm/gma500/psb_drv.c

@@ -107,19 +107,6 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
 static const struct drm_ioctl_desc psb_ioctls[] = {
 static const struct drm_ioctl_desc psb_ioctls[] = {
 };
 };
 
 
-static void psb_driver_lastclose(struct drm_device *dev)
-{
-	int ret;
-	struct drm_psb_private *dev_priv = dev->dev_private;
-	struct psb_fbdev *fbdev = dev_priv->fbdev;
-
-	ret = drm_fb_helper_restore_fbdev_mode_unlocked(&fbdev->psb_fb_helper);
-	if (ret)
-		DRM_DEBUG("failed to restore crtc mode\n");
-
-	return;
-}
-
 static int psb_do_init(struct drm_device *dev)
 static int psb_do_init(struct drm_device *dev)
 {
 {
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	struct drm_psb_private *dev_priv = dev->dev_private;
@@ -479,7 +466,7 @@ static struct drm_driver driver = {
 			   DRIVER_MODESET | DRIVER_GEM,
 			   DRIVER_MODESET | DRIVER_GEM,
 	.load = psb_driver_load,
 	.load = psb_driver_load,
 	.unload = psb_driver_unload,
 	.unload = psb_driver_unload,
-	.lastclose = psb_driver_lastclose,
+	.lastclose = drm_fb_helper_lastclose,
 
 
 	.num_ioctls = ARRAY_SIZE(psb_ioctls),
 	.num_ioctls = ARRAY_SIZE(psb_ioctls),
 	.irq_preinstall = psb_irq_preinstall,
 	.irq_preinstall = psb_irq_preinstall,

+ 6 - 27
drivers/gpu/drm/imx/imx-drm-core.c

@@ -38,7 +38,6 @@
 struct imx_drm_device {
 struct imx_drm_device {
 	struct drm_device			*drm;
 	struct drm_device			*drm;
 	unsigned int				pipes;
 	unsigned int				pipes;
-	struct drm_fbdev_cma			*fbhelper;
 	struct drm_atomic_state			*state;
 	struct drm_atomic_state			*state;
 };
 };
 
 
@@ -47,13 +46,6 @@ static int legacyfb_depth = 16;
 module_param(legacyfb_depth, int, 0444);
 module_param(legacyfb_depth, int, 0444);
 #endif
 #endif
 
 
-static void imx_drm_driver_lastclose(struct drm_device *drm)
-{
-	struct imx_drm_device *imxdrm = drm->dev_private;
-
-	drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
-}
-
 DEFINE_DRM_GEM_CMA_FOPS(imx_drm_driver_fops);
 DEFINE_DRM_GEM_CMA_FOPS(imx_drm_driver_fops);
 
 
 void imx_drm_connector_destroy(struct drm_connector *connector)
 void imx_drm_connector_destroy(struct drm_connector *connector)
@@ -69,13 +61,6 @@ void imx_drm_encoder_destroy(struct drm_encoder *encoder)
 }
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
 EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
 
 
-static void imx_drm_output_poll_changed(struct drm_device *drm)
-{
-	struct imx_drm_device *imxdrm = drm->dev_private;
-
-	drm_fbdev_cma_hotplug_event(imxdrm->fbhelper);
-}
-
 static int imx_drm_atomic_check(struct drm_device *dev,
 static int imx_drm_atomic_check(struct drm_device *dev,
 				struct drm_atomic_state *state)
 				struct drm_atomic_state *state)
 {
 {
@@ -107,7 +92,7 @@ static int imx_drm_atomic_check(struct drm_device *dev,
 
 
 static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
 static const struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
 	.fb_create = drm_gem_fb_create,
 	.fb_create = drm_gem_fb_create,
-	.output_poll_changed = imx_drm_output_poll_changed,
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
 	.atomic_check = imx_drm_atomic_check,
 	.atomic_check = imx_drm_atomic_check,
 	.atomic_commit = drm_atomic_helper_commit,
 	.atomic_commit = drm_atomic_helper_commit,
 };
 };
@@ -186,7 +171,7 @@ static const struct drm_ioctl_desc imx_drm_ioctls[] = {
 static struct drm_driver imx_drm_driver = {
 static struct drm_driver imx_drm_driver = {
 	.driver_features	= DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
 	.driver_features	= DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
 				  DRIVER_ATOMIC,
 				  DRIVER_ATOMIC,
-	.lastclose		= imx_drm_driver_lastclose,
+	.lastclose		= drm_fb_helper_lastclose,
 	.gem_free_object_unlocked = drm_gem_cma_free_object,
 	.gem_free_object_unlocked = drm_gem_cma_free_object,
 	.gem_vm_ops		= &drm_gem_cma_vm_ops,
 	.gem_vm_ops		= &drm_gem_cma_vm_ops,
 	.dumb_create		= drm_gem_cma_dumb_create,
 	.dumb_create		= drm_gem_cma_dumb_create,
@@ -298,12 +283,9 @@ static int imx_drm_bind(struct device *dev)
 		dev_warn(dev, "Invalid legacyfb_depth.  Defaulting to 16bpp\n");
 		dev_warn(dev, "Invalid legacyfb_depth.  Defaulting to 16bpp\n");
 		legacyfb_depth = 16;
 		legacyfb_depth = 16;
 	}
 	}
-	imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth, MAX_CRTC);
-	if (IS_ERR(imxdrm->fbhelper)) {
-		ret = PTR_ERR(imxdrm->fbhelper);
-		imxdrm->fbhelper = NULL;
+	ret = drm_fb_cma_fbdev_init(drm, legacyfb_depth, MAX_CRTC);
+	if (ret)
 		goto err_unbind;
 		goto err_unbind;
-	}
 #endif
 #endif
 
 
 	drm_kms_helper_poll_init(drm);
 	drm_kms_helper_poll_init(drm);
@@ -317,8 +299,7 @@ static int imx_drm_bind(struct device *dev)
 err_fbhelper:
 err_fbhelper:
 	drm_kms_helper_poll_fini(drm);
 	drm_kms_helper_poll_fini(drm);
 #if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
 #if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
-	if (imxdrm->fbhelper)
-		drm_fbdev_cma_fini(imxdrm->fbhelper);
+	drm_fb_cma_fbdev_fini(drm);
 err_unbind:
 err_unbind:
 #endif
 #endif
 	component_unbind_all(drm->dev, drm);
 	component_unbind_all(drm->dev, drm);
@@ -333,14 +314,12 @@ err_unref:
 static void imx_drm_unbind(struct device *dev)
 static void imx_drm_unbind(struct device *dev)
 {
 {
 	struct drm_device *drm = dev_get_drvdata(dev);
 	struct drm_device *drm = dev_get_drvdata(dev);
-	struct imx_drm_device *imxdrm = drm->dev_private;
 
 
 	drm_dev_unregister(drm);
 	drm_dev_unregister(drm);
 
 
 	drm_kms_helper_poll_fini(drm);
 	drm_kms_helper_poll_fini(drm);
 
 
-	if (imxdrm->fbhelper)
-		drm_fbdev_cma_fini(imxdrm->fbhelper);
+	drm_fb_cma_fbdev_fini(drm);
 
 
 	drm_mode_config_cleanup(drm);
 	drm_mode_config_cleanup(drm);
 
 

+ 0 - 1
drivers/gpu/drm/imx/imx-drm.h

@@ -8,7 +8,6 @@ struct drm_connector;
 struct drm_device;
 struct drm_device;
 struct drm_display_mode;
 struct drm_display_mode;
 struct drm_encoder;
 struct drm_encoder;
-struct drm_fbdev_cma;
 struct drm_framebuffer;
 struct drm_framebuffer;
 struct drm_plane;
 struct drm_plane;
 struct imx_drm_crtc;
 struct imx_drm_crtc;

+ 9 - 0
drivers/gpu/drm/meson/meson_drv.c

@@ -151,6 +151,14 @@ static struct regmap_config meson_regmap_config = {
 	.max_register   = 0x1000,
 	.max_register   = 0x1000,
 };
 };
 
 
+static void meson_vpu_init(struct meson_drm *priv)
+{
+	writel_relaxed(0x210000, priv->io_base + _REG(VPU_RDARB_MODE_L1C1));
+	writel_relaxed(0x10000, priv->io_base + _REG(VPU_RDARB_MODE_L1C2));
+	writel_relaxed(0x900000, priv->io_base + _REG(VPU_RDARB_MODE_L2C1));
+	writel_relaxed(0x20000, priv->io_base + _REG(VPU_WRARB_MODE_L2C1));
+}
+
 static int meson_drv_bind_master(struct device *dev, bool has_components)
 static int meson_drv_bind_master(struct device *dev, bool has_components)
 {
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct platform_device *pdev = to_platform_device(dev);
@@ -222,6 +230,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
 
 
 	/* Hardware Initialization */
 	/* Hardware Initialization */
 
 
+	meson_vpu_init(priv);
 	meson_venc_init(priv);
 	meson_venc_init(priv);
 	meson_vpp_init(priv);
 	meson_vpp_init(priv);
 	meson_viu_init(priv);
 	meson_viu_init(priv);

+ 13 - 0
drivers/gpu/drm/meson/meson_dw_hdmi.c

@@ -23,6 +23,7 @@
 #include <linux/of_graph.h>
 #include <linux/of_graph.h>
 #include <linux/reset.h>
 #include <linux/reset.h>
 #include <linux/clk.h>
 #include <linux/clk.h>
+#include <linux/regulator/consumer.h>
 
 
 #include <drm/drmP.h>
 #include <drm/drmP.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_edid.h>
@@ -137,6 +138,7 @@ struct meson_dw_hdmi {
 	struct reset_control *hdmitx_phy;
 	struct reset_control *hdmitx_phy;
 	struct clk *hdmi_pclk;
 	struct clk *hdmi_pclk;
 	struct clk *venci_clk;
 	struct clk *venci_clk;
+	struct regulator *hdmi_supply;
 	u32 irq_stat;
 	u32 irq_stat;
 };
 };
 #define encoder_to_meson_dw_hdmi(x) \
 #define encoder_to_meson_dw_hdmi(x) \
@@ -751,6 +753,17 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
 	dw_plat_data = &meson_dw_hdmi->dw_plat_data;
 	dw_plat_data = &meson_dw_hdmi->dw_plat_data;
 	encoder = &meson_dw_hdmi->encoder;
 	encoder = &meson_dw_hdmi->encoder;
 
 
+	meson_dw_hdmi->hdmi_supply = devm_regulator_get_optional(dev, "hdmi");
+	if (IS_ERR(meson_dw_hdmi->hdmi_supply)) {
+		if (PTR_ERR(meson_dw_hdmi->hdmi_supply) == -EPROBE_DEFER)
+			return -EPROBE_DEFER;
+		meson_dw_hdmi->hdmi_supply = NULL;
+	} else {
+		ret = regulator_enable(meson_dw_hdmi->hdmi_supply);
+		if (ret)
+			return ret;
+	}
+
 	meson_dw_hdmi->hdmitx_apb = devm_reset_control_get_exclusive(dev,
 	meson_dw_hdmi->hdmitx_apb = devm_reset_control_get_exclusive(dev,
 						"hdmitx_apb");
 						"hdmitx_apb");
 	if (IS_ERR(meson_dw_hdmi->hdmitx_apb)) {
 	if (IS_ERR(meson_dw_hdmi->hdmitx_apb)) {

+ 4 - 0
drivers/gpu/drm/meson/meson_registers.h

@@ -1363,6 +1363,10 @@
 #define VPU_PROT3_STAT_1 0x277a
 #define VPU_PROT3_STAT_1 0x277a
 #define VPU_PROT3_STAT_2 0x277b
 #define VPU_PROT3_STAT_2 0x277b
 #define VPU_PROT3_REQ_ONOFF 0x277c
 #define VPU_PROT3_REQ_ONOFF 0x277c
+#define VPU_RDARB_MODE_L1C1 0x2790
+#define VPU_RDARB_MODE_L1C2 0x2799
+#define VPU_RDARB_MODE_L2C1 0x279d
+#define VPU_WRARB_MODE_L2C1 0x27a2
 
 
 /* osd super scale */
 /* osd super scale */
 #define OSDSR_HV_SIZEIN 0x3130
 #define OSDSR_HV_SIZEIN 0x3130

+ 2 - 16
drivers/gpu/drm/msm/msm_drv.c

@@ -37,16 +37,9 @@
 #define MSM_VERSION_MINOR	3
 #define MSM_VERSION_MINOR	3
 #define MSM_VERSION_PATCHLEVEL	0
 #define MSM_VERSION_PATCHLEVEL	0
 
 
-static void msm_fb_output_poll_changed(struct drm_device *dev)
-{
-	struct msm_drm_private *priv = dev->dev_private;
-	if (priv->fbdev)
-		drm_fb_helper_hotplug_event(priv->fbdev);
-}
-
 static const struct drm_mode_config_funcs mode_config_funcs = {
 static const struct drm_mode_config_funcs mode_config_funcs = {
 	.fb_create = msm_framebuffer_create,
 	.fb_create = msm_framebuffer_create,
-	.output_poll_changed = msm_fb_output_poll_changed,
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_commit = msm_atomic_commit,
 	.atomic_commit = msm_atomic_commit,
 	.atomic_state_alloc = msm_atomic_state_alloc,
 	.atomic_state_alloc = msm_atomic_state_alloc,
@@ -551,13 +544,6 @@ static void msm_postclose(struct drm_device *dev, struct drm_file *file)
 	context_close(ctx);
 	context_close(ctx);
 }
 }
 
 
-static void msm_lastclose(struct drm_device *dev)
-{
-	struct msm_drm_private *priv = dev->dev_private;
-	if (priv->fbdev)
-		drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev);
-}
-
 static irqreturn_t msm_irq(int irq, void *arg)
 static irqreturn_t msm_irq(int irq, void *arg)
 {
 {
 	struct drm_device *dev = arg;
 	struct drm_device *dev = arg;
@@ -866,7 +852,7 @@ static struct drm_driver msm_driver = {
 				DRIVER_MODESET,
 				DRIVER_MODESET,
 	.open               = msm_open,
 	.open               = msm_open,
 	.postclose           = msm_postclose,
 	.postclose           = msm_postclose,
-	.lastclose          = msm_lastclose,
+	.lastclose          = drm_fb_helper_lastclose,
 	.irq_handler        = msm_irq,
 	.irq_handler        = msm_irq,
 	.irq_preinstall     = msm_irq_preinstall,
 	.irq_preinstall     = msm_irq_preinstall,
 	.irq_postinstall    = msm_irq_postinstall,
 	.irq_postinstall    = msm_irq_postinstall,

+ 2 - 1
drivers/gpu/drm/nouveau/nouveau_display.c

@@ -29,6 +29,7 @@
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
 
 
 #include <nvif/class.h>
 #include <nvif/class.h>
 
 
@@ -292,7 +293,7 @@ nouveau_user_framebuffer_create(struct drm_device *dev,
 
 
 static const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
 static const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
 	.fb_create = nouveau_user_framebuffer_create,
 	.fb_create = nouveau_user_framebuffer_create,
-	.output_poll_changed = nouveau_fbcon_output_poll_changed,
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
 };
 };
 
 
 
 

+ 0 - 8
drivers/gpu/drm/nouveau/nouveau_fbcon.c

@@ -413,14 +413,6 @@ out:
 	return ret;
 	return ret;
 }
 }
 
 
-void
-nouveau_fbcon_output_poll_changed(struct drm_device *dev)
-{
-	struct nouveau_drm *drm = nouveau_drm(dev);
-	if (drm->fbcon)
-		drm_fb_helper_hotplug_event(&drm->fbcon->helper);
-}
-
 static int
 static int
 nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon)
 nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon)
 {
 {

+ 0 - 2
drivers/gpu/drm/nouveau/nouveau_fbcon.h

@@ -68,8 +68,6 @@ void nouveau_fbcon_set_suspend(struct drm_device *dev, int state);
 void nouveau_fbcon_accel_save_disable(struct drm_device *dev);
 void nouveau_fbcon_accel_save_disable(struct drm_device *dev);
 void nouveau_fbcon_accel_restore(struct drm_device *dev);
 void nouveau_fbcon_accel_restore(struct drm_device *dev);
 
 
-void nouveau_fbcon_output_poll_changed(struct drm_device *dev);
-
 extern int nouveau_nofbaccel;
 extern int nouveau_nofbaccel;
 
 
 #endif /* __NV50_FBCON_H__ */
 #endif /* __NV50_FBCON_H__ */

+ 2 - 1
drivers/gpu/drm/nouveau/nouveau_vga.c

@@ -4,6 +4,7 @@
 
 
 #include <drm/drmP.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
 
 
 #include "nouveau_drv.h"
 #include "nouveau_drv.h"
 #include "nouveau_acpi.h"
 #include "nouveau_acpi.h"
@@ -61,7 +62,7 @@ static void
 nouveau_switcheroo_reprobe(struct pci_dev *pdev)
 nouveau_switcheroo_reprobe(struct pci_dev *pdev)
 {
 {
 	struct drm_device *dev = pci_get_drvdata(pdev);
 	struct drm_device *dev = pci_get_drvdata(pdev);
-	nouveau_fbcon_output_poll_changed(dev);
+	drm_fb_helper_output_poll_changed(dev);
 }
 }
 
 
 static bool
 static bool

+ 1 - 1
drivers/gpu/drm/nouveau/nv50_display.c

@@ -4311,7 +4311,7 @@ nv50_disp_atomic_state_alloc(struct drm_device *dev)
 static const struct drm_mode_config_funcs
 static const struct drm_mode_config_funcs
 nv50_disp_func = {
 nv50_disp_func = {
 	.fb_create = nouveau_user_framebuffer_create,
 	.fb_create = nouveau_user_framebuffer_create,
-	.output_poll_changed = nouveau_fbcon_output_poll_changed,
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
 	.atomic_check = nv50_disp_atomic_check,
 	.atomic_check = nv50_disp_atomic_check,
 	.atomic_commit = nv50_disp_atomic_commit,
 	.atomic_commit = nv50_disp_atomic_commit,
 	.atomic_state_alloc = nv50_disp_atomic_state_alloc,
 	.atomic_state_alloc = nv50_disp_atomic_state_alloc,

+ 2 - 32
drivers/gpu/drm/omapdrm/omap_drv.c

@@ -46,14 +46,6 @@
  *                 devices
  *                 devices
  */
  */
 
 
-static void omap_fb_output_poll_changed(struct drm_device *dev)
-{
-	struct omap_drm_private *priv = dev->dev_private;
-	DBG("dev=%p", dev);
-	if (priv->fbdev)
-		drm_fb_helper_hotplug_event(priv->fbdev);
-}
-
 static void omap_atomic_wait_for_completion(struct drm_device *dev,
 static void omap_atomic_wait_for_completion(struct drm_device *dev,
 					    struct drm_atomic_state *old_state)
 					    struct drm_atomic_state *old_state)
 {
 {
@@ -132,7 +124,7 @@ static const struct drm_mode_config_helper_funcs omap_mode_config_helper_funcs =
 
 
 static const struct drm_mode_config_funcs omap_mode_config_funcs = {
 static const struct drm_mode_config_funcs omap_mode_config_funcs = {
 	.fb_create = omap_framebuffer_create,
 	.fb_create = omap_framebuffer_create,
-	.output_poll_changed = omap_fb_output_poll_changed,
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_commit = drm_atomic_helper_commit,
 	.atomic_commit = drm_atomic_helper_commit,
 };
 };
@@ -467,28 +459,6 @@ static int dev_open(struct drm_device *dev, struct drm_file *file)
 	return 0;
 	return 0;
 }
 }
 
 
-/**
- * lastclose - clean up after all DRM clients have exited
- * @dev: DRM device
- *
- * Take care of cleaning up after all DRM clients have exited.  In the
- * mode setting case, we want to restore the kernel's initial mode (just
- * in case the last client left us in a bad state).
- */
-static void dev_lastclose(struct drm_device *dev)
-{
-	struct omap_drm_private *priv = dev->dev_private;
-	int ret;
-
-	DBG("lastclose: dev=%p", dev);
-
-	if (priv->fbdev) {
-		ret = drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev);
-		if (ret)
-			DBG("failed to restore crtc mode");
-	}
-}
-
 static const struct vm_operations_struct omap_gem_vm_ops = {
 static const struct vm_operations_struct omap_gem_vm_ops = {
 	.fault = omap_gem_fault,
 	.fault = omap_gem_fault,
 	.open = drm_gem_vm_open,
 	.open = drm_gem_vm_open,
@@ -511,7 +481,7 @@ static struct drm_driver omap_drm_driver = {
 	.driver_features = DRIVER_MODESET | DRIVER_GEM  | DRIVER_PRIME |
 	.driver_features = DRIVER_MODESET | DRIVER_GEM  | DRIVER_PRIME |
 		DRIVER_ATOMIC | DRIVER_RENDER,
 		DRIVER_ATOMIC | DRIVER_RENDER,
 	.open = dev_open,
 	.open = dev_open,
-	.lastclose = dev_lastclose,
+	.lastclose = drm_fb_helper_lastclose,
 #ifdef CONFIG_DEBUG_FS
 #ifdef CONFIG_DEBUG_FS
 	.debugfs_init = omap_debugfs_init,
 	.debugfs_init = omap_debugfs_init,
 #endif
 #endif

+ 0 - 1
drivers/gpu/drm/pl111/pl111_drm.h

@@ -53,7 +53,6 @@ struct pl111_drm_dev_private {
 	struct drm_panel *panel;
 	struct drm_panel *panel;
 	struct drm_bridge *bridge;
 	struct drm_bridge *bridge;
 	struct drm_simple_display_pipe pipe;
 	struct drm_simple_display_pipe pipe;
-	struct drm_fbdev_cma *fbdev;
 
 
 	void *regs;
 	void *regs;
 	u32 ienb;
 	u32 ienb;

+ 4 - 12
drivers/gpu/drm/pl111/pl111_drv.c

@@ -64,6 +64,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_of.h>
 #include <drm/drm_of.h>
 #include <drm/drm_bridge.h>
 #include <drm/drm_bridge.h>
@@ -137,8 +138,7 @@ static int pl111_modeset_init(struct drm_device *dev)
 
 
 	drm_mode_config_reset(dev);
 	drm_mode_config_reset(dev);
 
 
-	priv->fbdev = drm_fbdev_cma_init(dev, 32,
-					 dev->mode_config.num_connector);
+	drm_fb_cma_fbdev_init(dev, 32, 0);
 
 
 	drm_kms_helper_poll_init(dev);
 	drm_kms_helper_poll_init(dev);
 
 
@@ -155,17 +155,10 @@ finish:
 
 
 DEFINE_DRM_GEM_CMA_FOPS(drm_fops);
 DEFINE_DRM_GEM_CMA_FOPS(drm_fops);
 
 
-static void pl111_lastclose(struct drm_device *dev)
-{
-	struct pl111_drm_dev_private *priv = dev->dev_private;
-
-	drm_fbdev_cma_restore_mode(priv->fbdev);
-}
-
 static struct drm_driver pl111_drm_driver = {
 static struct drm_driver pl111_drm_driver = {
 	.driver_features =
 	.driver_features =
 		DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC,
 		DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC,
-	.lastclose = pl111_lastclose,
+	.lastclose = drm_fb_helper_lastclose,
 	.ioctls = NULL,
 	.ioctls = NULL,
 	.fops = &drm_fops,
 	.fops = &drm_fops,
 	.name = "pl111",
 	.name = "pl111",
@@ -281,8 +274,7 @@ static int pl111_amba_remove(struct amba_device *amba_dev)
 	struct pl111_drm_dev_private *priv = drm->dev_private;
 	struct pl111_drm_dev_private *priv = drm->dev_private;
 
 
 	drm_dev_unregister(drm);
 	drm_dev_unregister(drm);
-	if (priv->fbdev)
-		drm_fbdev_cma_fini(priv->fbdev);
+	drm_fb_cma_fbdev_fini(drm);
 	if (priv->panel)
 	if (priv->panel)
 		drm_panel_bridge_remove(priv->bridge);
 		drm_panel_bridge_remove(priv->bridge);
 	drm_mode_config_cleanup(drm);
 	drm_mode_config_cleanup(drm);

+ 1 - 8
drivers/gpu/drm/rockchip/rockchip_drm_drv.c

@@ -207,13 +207,6 @@ static void rockchip_drm_unbind(struct device *dev)
 	drm_dev_unref(drm_dev);
 	drm_dev_unref(drm_dev);
 }
 }
 
 
-static void rockchip_drm_lastclose(struct drm_device *dev)
-{
-	struct rockchip_drm_private *priv = dev->dev_private;
-
-	drm_fb_helper_restore_fbdev_mode_unlocked(&priv->fbdev_helper);
-}
-
 static const struct file_operations rockchip_drm_driver_fops = {
 static const struct file_operations rockchip_drm_driver_fops = {
 	.owner = THIS_MODULE,
 	.owner = THIS_MODULE,
 	.open = drm_open,
 	.open = drm_open,
@@ -228,7 +221,7 @@ static const struct file_operations rockchip_drm_driver_fops = {
 static struct drm_driver rockchip_drm_driver = {
 static struct drm_driver rockchip_drm_driver = {
 	.driver_features	= DRIVER_MODESET | DRIVER_GEM |
 	.driver_features	= DRIVER_MODESET | DRIVER_GEM |
 				  DRIVER_PRIME | DRIVER_ATOMIC,
 				  DRIVER_PRIME | DRIVER_ATOMIC,
-	.lastclose		= rockchip_drm_lastclose,
+	.lastclose		= drm_fb_helper_lastclose,
 	.gem_vm_ops		= &drm_gem_cma_vm_ops,
 	.gem_vm_ops		= &drm_gem_cma_vm_ops,
 	.gem_free_object_unlocked = rockchip_gem_free_object,
 	.gem_free_object_unlocked = rockchip_gem_free_object,
 	.dumb_create		= rockchip_gem_dumb_create,
 	.dumb_create		= rockchip_gem_dumb_create,

+ 1 - 8
drivers/gpu/drm/rockchip/rockchip_drm_fb.c

@@ -167,20 +167,13 @@ err_gem_object_unreference:
 	return ERR_PTR(ret);
 	return ERR_PTR(ret);
 }
 }
 
 
-static void rockchip_drm_output_poll_changed(struct drm_device *dev)
-{
-	struct rockchip_drm_private *private = dev->dev_private;
-
-	drm_fb_helper_hotplug_event(&private->fbdev_helper);
-}
-
 static const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = {
 static const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = {
 	.atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
 	.atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
 };
 };
 
 
 static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
 static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
 	.fb_create = rockchip_user_fb_create,
 	.fb_create = rockchip_user_fb_create,
-	.output_poll_changed = rockchip_drm_output_poll_changed,
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_commit = drm_atomic_helper_commit,
 	.atomic_commit = drm_atomic_helper_commit,
 };
 };

+ 5 - 22
drivers/gpu/drm/sti/sti_drv.c

@@ -17,6 +17,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_of.h>
 #include <drm/drm_of.h>
 
 
@@ -138,16 +139,9 @@ static int sti_atomic_check(struct drm_device *dev,
 	return ret;
 	return ret;
 }
 }
 
 
-static void sti_output_poll_changed(struct drm_device *ddev)
-{
-	struct sti_private *private = ddev->dev_private;
-
-	drm_fbdev_cma_hotplug_event(private->fbdev);
-}
-
 static const struct drm_mode_config_funcs sti_mode_config_funcs = {
 static const struct drm_mode_config_funcs sti_mode_config_funcs = {
 	.fb_create = drm_gem_fb_create,
 	.fb_create = drm_gem_fb_create,
-	.output_poll_changed = sti_output_poll_changed,
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
 	.atomic_check = sti_atomic_check,
 	.atomic_check = sti_atomic_check,
 	.atomic_commit = drm_atomic_helper_commit,
 	.atomic_commit = drm_atomic_helper_commit,
 };
 };
@@ -230,11 +224,7 @@ static void sti_cleanup(struct drm_device *ddev)
 {
 {
 	struct sti_private *private = ddev->dev_private;
 	struct sti_private *private = ddev->dev_private;
 
 
-	if (private->fbdev) {
-		drm_fbdev_cma_fini(private->fbdev);
-		private->fbdev = NULL;
-	}
-
+	drm_fb_cma_fbdev_fini(ddev);
 	drm_kms_helper_poll_fini(ddev);
 	drm_kms_helper_poll_fini(ddev);
 	component_unbind_all(ddev->dev, ddev);
 	component_unbind_all(ddev->dev, ddev);
 	kfree(private);
 	kfree(private);
@@ -244,8 +234,6 @@ static void sti_cleanup(struct drm_device *ddev)
 static int sti_bind(struct device *dev)
 static int sti_bind(struct device *dev)
 {
 {
 	struct drm_device *ddev;
 	struct drm_device *ddev;
-	struct sti_private *private;
-	struct drm_fbdev_cma *fbdev;
 	int ret;
 	int ret;
 
 
 	ddev = drm_dev_alloc(&sti_driver, dev);
 	ddev = drm_dev_alloc(&sti_driver, dev);
@@ -266,15 +254,10 @@ static int sti_bind(struct device *dev)
 
 
 	drm_mode_config_reset(ddev);
 	drm_mode_config_reset(ddev);
 
 
-	private = ddev->dev_private;
 	if (ddev->mode_config.num_connector) {
 	if (ddev->mode_config.num_connector) {
-		fbdev = drm_fbdev_cma_init(ddev, 32,
-					   ddev->mode_config.num_connector);
-		if (IS_ERR(fbdev)) {
+		ret = drm_fb_cma_fbdev_init(ddev, 32, 0);
+		if (ret)
 			DRM_DEBUG_DRIVER("Warning: fails to create fbdev\n");
 			DRM_DEBUG_DRIVER("Warning: fails to create fbdev\n");
-			fbdev = NULL;
-		}
-		private->fbdev = fbdev;
 	}
 	}
 
 
 	return 0;
 	return 0;

+ 0 - 1
drivers/gpu/drm/sti/sti_drv.h

@@ -24,7 +24,6 @@ struct sti_private {
 	struct sti_compositor *compo;
 	struct sti_compositor *compo;
 	struct drm_property *plane_zorder_property;
 	struct drm_property *plane_zorder_property;
 	struct drm_device *drm_dev;
 	struct drm_device *drm_dev;
-	struct drm_fbdev_cma *fbdev;
 };
 };
 
 
 extern struct platform_driver sti_tvout_driver;
 extern struct platform_driver sti_tvout_driver;

+ 6 - 32
drivers/gpu/drm/stm/drv.c

@@ -14,6 +14,7 @@
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
@@ -23,35 +24,19 @@
 #define STM_MAX_FB_WIDTH	2048
 #define STM_MAX_FB_WIDTH	2048
 #define STM_MAX_FB_HEIGHT	2048 /* same as width to handle orientation */
 #define STM_MAX_FB_HEIGHT	2048 /* same as width to handle orientation */
 
 
-static void drv_output_poll_changed(struct drm_device *ddev)
-{
-	struct ltdc_device *ldev = ddev->dev_private;
-
-	drm_fbdev_cma_hotplug_event(ldev->fbdev);
-}
-
 static const struct drm_mode_config_funcs drv_mode_config_funcs = {
 static const struct drm_mode_config_funcs drv_mode_config_funcs = {
 	.fb_create = drm_gem_fb_create,
 	.fb_create = drm_gem_fb_create,
-	.output_poll_changed = drv_output_poll_changed,
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_commit = drm_atomic_helper_commit,
 	.atomic_commit = drm_atomic_helper_commit,
 };
 };
 
 
-static void drv_lastclose(struct drm_device *ddev)
-{
-	struct ltdc_device *ldev = ddev->dev_private;
-
-	DRM_DEBUG("%s\n", __func__);
-
-	drm_fbdev_cma_restore_mode(ldev->fbdev);
-}
-
 DEFINE_DRM_GEM_CMA_FOPS(drv_driver_fops);
 DEFINE_DRM_GEM_CMA_FOPS(drv_driver_fops);
 
 
 static struct drm_driver drv_driver = {
 static struct drm_driver drv_driver = {
 	.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
 	.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
 			   DRIVER_ATOMIC,
 			   DRIVER_ATOMIC,
-	.lastclose = drv_lastclose,
+	.lastclose = drm_fb_helper_lastclose,
 	.name = "stm",
 	.name = "stm",
 	.desc = "STMicroelectronics SoC DRM",
 	.desc = "STMicroelectronics SoC DRM",
 	.date = "20170330",
 	.date = "20170330",
@@ -78,7 +63,6 @@ static struct drm_driver drv_driver = {
 static int drv_load(struct drm_device *ddev)
 static int drv_load(struct drm_device *ddev)
 {
 {
 	struct platform_device *pdev = to_platform_device(ddev->dev);
 	struct platform_device *pdev = to_platform_device(ddev->dev);
-	struct drm_fbdev_cma *fbdev;
 	struct ltdc_device *ldev;
 	struct ltdc_device *ldev;
 	int ret;
 	int ret;
 
 
@@ -111,14 +95,9 @@ static int drv_load(struct drm_device *ddev)
 	drm_kms_helper_poll_init(ddev);
 	drm_kms_helper_poll_init(ddev);
 
 
 	if (ddev->mode_config.num_connector) {
 	if (ddev->mode_config.num_connector) {
-		ldev = ddev->dev_private;
-		fbdev = drm_fbdev_cma_init(ddev, 16,
-					   ddev->mode_config.num_connector);
-		if (IS_ERR(fbdev)) {
+		ret = drm_fb_cma_fbdev_init(ddev, 16, 0);
+		if (ret)
 			DRM_DEBUG("Warning: fails to create fbdev\n");
 			DRM_DEBUG("Warning: fails to create fbdev\n");
-			fbdev = NULL;
-		}
-		ldev->fbdev = fbdev;
 	}
 	}
 
 
 	platform_set_drvdata(pdev, ddev);
 	platform_set_drvdata(pdev, ddev);
@@ -131,14 +110,9 @@ err:
 
 
 static void drv_unload(struct drm_device *ddev)
 static void drv_unload(struct drm_device *ddev)
 {
 {
-	struct ltdc_device *ldev = ddev->dev_private;
-
 	DRM_DEBUG("%s\n", __func__);
 	DRM_DEBUG("%s\n", __func__);
 
 
-	if (ldev->fbdev) {
-		drm_fbdev_cma_fini(ldev->fbdev);
-		ldev->fbdev = NULL;
-	}
+	drm_fb_cma_fbdev_fini(ddev);
 	drm_kms_helper_poll_fini(ddev);
 	drm_kms_helper_poll_fini(ddev);
 	ltdc_unload(ddev);
 	ltdc_unload(ddev);
 	drm_mode_config_cleanup(ddev);
 	drm_mode_config_cleanup(ddev);

+ 0 - 1
drivers/gpu/drm/stm/ltdc.h

@@ -20,7 +20,6 @@ struct ltdc_caps {
 };
 };
 
 
 struct ltdc_device {
 struct ltdc_device {
-	struct drm_fbdev_cma *fbdev;
 	void __iomem *regs;
 	void __iomem *regs;
 	struct clk *pixel_clk;	/* lcd pixel clock */
 	struct clk *pixel_clk;	/* lcd pixel clock */
 	struct mutex err_lock;	/* protecting error_status */
 	struct mutex err_lock;	/* protecting error_status */

+ 3 - 11
drivers/gpu/drm/sun4i/sun4i_drv.c

@@ -26,20 +26,13 @@
 #include "sun4i_framebuffer.h"
 #include "sun4i_framebuffer.h"
 #include "sun4i_tcon.h"
 #include "sun4i_tcon.h"
 
 
-static void sun4i_drv_lastclose(struct drm_device *dev)
-{
-	struct sun4i_drv *drv = dev->dev_private;
-
-	drm_fbdev_cma_restore_mode(drv->fbdev);
-}
-
 DEFINE_DRM_GEM_CMA_FOPS(sun4i_drv_fops);
 DEFINE_DRM_GEM_CMA_FOPS(sun4i_drv_fops);
 
 
 static struct drm_driver sun4i_drv_driver = {
 static struct drm_driver sun4i_drv_driver = {
 	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC,
 	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC,
 
 
 	/* Generic Operations */
 	/* Generic Operations */
-	.lastclose		= sun4i_drv_lastclose,
+	.lastclose		= drm_fb_helper_lastclose,
 	.fops			= &sun4i_drv_fops,
 	.fops			= &sun4i_drv_fops,
 	.name			= "sun4i-drm",
 	.name			= "sun4i-drm",
 	.desc			= "Allwinner sun4i Display Engine",
 	.desc			= "Allwinner sun4i Display Engine",
@@ -126,10 +119,9 @@ static int sun4i_drv_bind(struct device *dev)
 	sun4i_remove_framebuffers();
 	sun4i_remove_framebuffers();
 
 
 	/* Create our framebuffer */
 	/* Create our framebuffer */
-	drv->fbdev = sun4i_framebuffer_init(drm);
-	if (IS_ERR(drv->fbdev)) {
+	ret = sun4i_framebuffer_init(drm);
+	if (ret) {
 		dev_err(drm->dev, "Couldn't create our framebuffer\n");
 		dev_err(drm->dev, "Couldn't create our framebuffer\n");
-		ret = PTR_ERR(drv->fbdev);
 		goto cleanup_mode_config;
 		goto cleanup_mode_config;
 	}
 	}
 
 

+ 0 - 2
drivers/gpu/drm/sun4i/sun4i_drv.h

@@ -20,8 +20,6 @@
 struct sun4i_drv {
 struct sun4i_drv {
 	struct list_head	engine_list;
 	struct list_head	engine_list;
 	struct list_head	tcon_list;
 	struct list_head	tcon_list;
-
-	struct drm_fbdev_cma	*fbdev;
 };
 };
 
 
 #endif /* _SUN4I_DRV_H_ */
 #endif /* _SUN4I_DRV_H_ */

+ 5 - 13
drivers/gpu/drm/sun4i/sun4i_framebuffer.c

@@ -11,6 +11,7 @@
  */
  */
 
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drmP.h>
 #include <drm/drmP.h>
@@ -18,21 +19,14 @@
 #include "sun4i_drv.h"
 #include "sun4i_drv.h"
 #include "sun4i_framebuffer.h"
 #include "sun4i_framebuffer.h"
 
 
-static void sun4i_de_output_poll_changed(struct drm_device *drm)
-{
-	struct sun4i_drv *drv = drm->dev_private;
-
-	drm_fbdev_cma_hotplug_event(drv->fbdev);
-}
-
 static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = {
 static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = {
-	.output_poll_changed	= sun4i_de_output_poll_changed,
+	.output_poll_changed	= drm_fb_helper_output_poll_changed,
 	.atomic_check		= drm_atomic_helper_check,
 	.atomic_check		= drm_atomic_helper_check,
 	.atomic_commit		= drm_atomic_helper_commit,
 	.atomic_commit		= drm_atomic_helper_commit,
 	.fb_create		= drm_gem_fb_create,
 	.fb_create		= drm_gem_fb_create,
 };
 };
 
 
-struct drm_fbdev_cma *sun4i_framebuffer_init(struct drm_device *drm)
+int sun4i_framebuffer_init(struct drm_device *drm)
 {
 {
 	drm_mode_config_reset(drm);
 	drm_mode_config_reset(drm);
 
 
@@ -41,12 +35,10 @@ struct drm_fbdev_cma *sun4i_framebuffer_init(struct drm_device *drm)
 
 
 	drm->mode_config.funcs = &sun4i_de_mode_config_funcs;
 	drm->mode_config.funcs = &sun4i_de_mode_config_funcs;
 
 
-	return drm_fbdev_cma_init(drm, 32, drm->mode_config.num_connector);
+	return drm_fb_cma_fbdev_init(drm, 32, 0);
 }
 }
 
 
 void sun4i_framebuffer_free(struct drm_device *drm)
 void sun4i_framebuffer_free(struct drm_device *drm)
 {
 {
-	struct sun4i_drv *drv = drm->dev_private;
-
-	drm_fbdev_cma_fini(drv->fbdev);
+	drm_fb_cma_fbdev_fini(drm);
 }
 }

+ 1 - 1
drivers/gpu/drm/sun4i/sun4i_framebuffer.h

@@ -13,7 +13,7 @@
 #ifndef _SUN4I_FRAMEBUFFER_H_
 #ifndef _SUN4I_FRAMEBUFFER_H_
 #define _SUN4I_FRAMEBUFFER_H_
 #define _SUN4I_FRAMEBUFFER_H_
 
 
-struct drm_fbdev_cma *sun4i_framebuffer_init(struct drm_device *drm);
+int sun4i_framebuffer_init(struct drm_device *drm);
 void sun4i_framebuffer_free(struct drm_device *drm);
 void sun4i_framebuffer_free(struct drm_device *drm);
 
 
 #endif /* _SUN4I_FRAMEBUFFER_H_ */
 #endif /* _SUN4I_FRAMEBUFFER_H_ */

+ 2 - 11
drivers/gpu/drm/tegra/drm.c

@@ -120,7 +120,7 @@ static int tegra_atomic_commit(struct drm_device *drm,
 static const struct drm_mode_config_funcs tegra_drm_mode_funcs = {
 static const struct drm_mode_config_funcs tegra_drm_mode_funcs = {
 	.fb_create = tegra_fb_create,
 	.fb_create = tegra_fb_create,
 #ifdef CONFIG_DRM_FBDEV_EMULATION
 #ifdef CONFIG_DRM_FBDEV_EMULATION
-	.output_poll_changed = tegra_fb_output_poll_changed,
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
 #endif
 #endif
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_commit = tegra_atomic_commit,
 	.atomic_commit = tegra_atomic_commit,
@@ -286,15 +286,6 @@ static void tegra_drm_context_free(struct tegra_drm_context *context)
 	kfree(context);
 	kfree(context);
 }
 }
 
 
-static void tegra_drm_lastclose(struct drm_device *drm)
-{
-#ifdef CONFIG_DRM_FBDEV_EMULATION
-	struct tegra_drm *tegra = drm->dev_private;
-
-	tegra_fbdev_restore_mode(tegra->fbdev);
-#endif
-}
-
 static struct host1x_bo *
 static struct host1x_bo *
 host1x_bo_lookup(struct drm_file *file, u32 handle)
 host1x_bo_lookup(struct drm_file *file, u32 handle)
 {
 {
@@ -1100,7 +1091,7 @@ static struct drm_driver tegra_drm_driver = {
 	.unload = tegra_drm_unload,
 	.unload = tegra_drm_unload,
 	.open = tegra_drm_open,
 	.open = tegra_drm_open,
 	.postclose = tegra_drm_postclose,
 	.postclose = tegra_drm_postclose,
-	.lastclose = tegra_drm_lastclose,
+	.lastclose = drm_fb_helper_lastclose,
 
 
 #if defined(CONFIG_DEBUG_FS)
 #if defined(CONFIG_DEBUG_FS)
 	.debugfs_init = tegra_debugfs_init,
 	.debugfs_init = tegra_debugfs_init,

+ 0 - 4
drivers/gpu/drm/tegra/drm.h

@@ -188,10 +188,6 @@ int tegra_drm_fb_init(struct drm_device *drm);
 void tegra_drm_fb_exit(struct drm_device *drm);
 void tegra_drm_fb_exit(struct drm_device *drm);
 void tegra_drm_fb_suspend(struct drm_device *drm);
 void tegra_drm_fb_suspend(struct drm_device *drm);
 void tegra_drm_fb_resume(struct drm_device *drm);
 void tegra_drm_fb_resume(struct drm_device *drm);
-#ifdef CONFIG_DRM_FBDEV_EMULATION
-void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev);
-void tegra_fb_output_poll_changed(struct drm_device *drm);
-#endif
 
 
 extern struct platform_driver tegra_dc_driver;
 extern struct platform_driver tegra_dc_driver;
 extern struct platform_driver tegra_hdmi_driver;
 extern struct platform_driver tegra_hdmi_driver;

+ 0 - 14
drivers/gpu/drm/tegra/fb.c

@@ -361,20 +361,6 @@ static void tegra_fbdev_exit(struct tegra_fbdev *fbdev)
 	drm_fb_helper_fini(&fbdev->base);
 	drm_fb_helper_fini(&fbdev->base);
 	tegra_fbdev_free(fbdev);
 	tegra_fbdev_free(fbdev);
 }
 }
-
-void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev)
-{
-	if (fbdev)
-		drm_fb_helper_restore_fbdev_mode_unlocked(&fbdev->base);
-}
-
-void tegra_fb_output_poll_changed(struct drm_device *drm)
-{
-	struct tegra_drm *tegra = drm->dev_private;
-
-	if (tegra->fbdev)
-		drm_fb_helper_hotplug_event(&tegra->fbdev->base);
-}
 #endif
 #endif
 
 
 int tegra_drm_fb_prepare(struct drm_device *drm)
 int tegra_drm_fb_prepare(struct drm_device *drm)

+ 5 - 21
drivers/gpu/drm/tilcdc/tilcdc_drv.c

@@ -69,12 +69,6 @@ static struct drm_framebuffer *tilcdc_fb_create(struct drm_device *dev,
 	return drm_gem_fb_create(dev, file_priv, mode_cmd);
 	return drm_gem_fb_create(dev, file_priv, mode_cmd);
 }
 }
 
 
-static void tilcdc_fb_output_poll_changed(struct drm_device *dev)
-{
-	struct tilcdc_drm_private *priv = dev->dev_private;
-	drm_fbdev_cma_hotplug_event(priv->fbdev);
-}
-
 static int tilcdc_atomic_check(struct drm_device *dev,
 static int tilcdc_atomic_check(struct drm_device *dev,
 			       struct drm_atomic_state *state)
 			       struct drm_atomic_state *state)
 {
 {
@@ -146,7 +140,7 @@ static int tilcdc_commit(struct drm_device *dev,
 
 
 static const struct drm_mode_config_funcs mode_config_funcs = {
 static const struct drm_mode_config_funcs mode_config_funcs = {
 	.fb_create = tilcdc_fb_create,
 	.fb_create = tilcdc_fb_create,
-	.output_poll_changed = tilcdc_fb_output_poll_changed,
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
 	.atomic_check = tilcdc_atomic_check,
 	.atomic_check = tilcdc_atomic_check,
 	.atomic_commit = tilcdc_commit,
 	.atomic_commit = tilcdc_commit,
 };
 };
@@ -198,8 +192,7 @@ static void tilcdc_fini(struct drm_device *dev)
 
 
 	drm_kms_helper_poll_fini(dev);
 	drm_kms_helper_poll_fini(dev);
 
 
-	if (priv->fbdev)
-		drm_fbdev_cma_fini(priv->fbdev);
+	drm_fb_cma_fbdev_fini(dev);
 
 
 	drm_irq_uninstall(dev);
 	drm_irq_uninstall(dev);
 	drm_mode_config_cleanup(dev);
 	drm_mode_config_cleanup(dev);
@@ -405,12 +398,9 @@ static int tilcdc_init(struct drm_driver *ddrv, struct device *dev)
 
 
 	drm_mode_config_reset(ddev);
 	drm_mode_config_reset(ddev);
 
 
-	priv->fbdev = drm_fbdev_cma_init(ddev, bpp,
-					 ddev->mode_config.num_connector);
-	if (IS_ERR(priv->fbdev)) {
-		ret = PTR_ERR(priv->fbdev);
+	ret = drm_fb_cma_fbdev_init(ddev, bpp, 0);
+	if (ret)
 		goto init_failed;
 		goto init_failed;
-	}
 
 
 	drm_kms_helper_poll_init(ddev);
 	drm_kms_helper_poll_init(ddev);
 
 
@@ -427,12 +417,6 @@ init_failed:
 	return ret;
 	return ret;
 }
 }
 
 
-static void tilcdc_lastclose(struct drm_device *dev)
-{
-	struct tilcdc_drm_private *priv = dev->dev_private;
-	drm_fbdev_cma_restore_mode(priv->fbdev);
-}
-
 static irqreturn_t tilcdc_irq(int irq, void *arg)
 static irqreturn_t tilcdc_irq(int irq, void *arg)
 {
 {
 	struct drm_device *dev = arg;
 	struct drm_device *dev = arg;
@@ -537,7 +521,7 @@ DEFINE_DRM_GEM_CMA_FOPS(fops);
 static struct drm_driver tilcdc_driver = {
 static struct drm_driver tilcdc_driver = {
 	.driver_features    = (DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET |
 	.driver_features    = (DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET |
 			       DRIVER_PRIME | DRIVER_ATOMIC),
 			       DRIVER_PRIME | DRIVER_ATOMIC),
-	.lastclose          = tilcdc_lastclose,
+	.lastclose          = drm_fb_helper_lastclose,
 	.irq_handler        = tilcdc_irq,
 	.irq_handler        = tilcdc_irq,
 	.gem_free_object_unlocked = drm_gem_cma_free_object,
 	.gem_free_object_unlocked = drm_gem_cma_free_object,
 	.gem_print_info     = drm_gem_cma_print_info,
 	.gem_print_info     = drm_gem_cma_print_info,

+ 0 - 2
drivers/gpu/drm/tilcdc/tilcdc_drv.h

@@ -79,8 +79,6 @@ struct tilcdc_drm_private {
 
 
 	struct workqueue_struct *wq;
 	struct workqueue_struct *wq;
 
 
-	struct drm_fbdev_cma *fbdev;
-
 	struct drm_crtc *crtc;
 	struct drm_crtc *crtc;
 
 
 	unsigned int num_encoders;
 	unsigned int num_encoders;

+ 5 - 32
drivers/gpu/drm/tinydrm/core/tinydrm-core.c

@@ -10,6 +10,7 @@
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/tinydrm/tinydrm.h>
 #include <drm/tinydrm/tinydrm.h>
 #include <linux/device.h>
 #include <linux/device.h>
@@ -35,23 +36,6 @@
  * and registers the DRM device using devm_tinydrm_register().
  * and registers the DRM device using devm_tinydrm_register().
  */
  */
 
 
-/**
- * tinydrm_lastclose - DRM lastclose helper
- * @drm: DRM device
- *
- * This function ensures that fbdev is restored when drm_lastclose() is called
- * on the last drm_release(). Drivers can use this as their
- * &drm_driver->lastclose callback.
- */
-void tinydrm_lastclose(struct drm_device *drm)
-{
-	struct tinydrm_device *tdev = drm->dev_private;
-
-	DRM_DEBUG_KMS("\n");
-	drm_fbdev_cma_restore_mode(tdev->fbdev_cma);
-}
-EXPORT_SYMBOL(tinydrm_lastclose);
-
 /**
 /**
  * tinydrm_gem_cma_prime_import_sg_table - Produce a CMA GEM object from
  * tinydrm_gem_cma_prime_import_sg_table - Produce a CMA GEM object from
  *     another driver's scatter/gather table of pinned pages
  *     another driver's scatter/gather table of pinned pages
@@ -214,35 +198,24 @@ EXPORT_SYMBOL(devm_tinydrm_init);
 static int tinydrm_register(struct tinydrm_device *tdev)
 static int tinydrm_register(struct tinydrm_device *tdev)
 {
 {
 	struct drm_device *drm = tdev->drm;
 	struct drm_device *drm = tdev->drm;
-	int bpp = drm->mode_config.preferred_depth;
-	struct drm_fbdev_cma *fbdev;
 	int ret;
 	int ret;
 
 
 	ret = drm_dev_register(tdev->drm, 0);
 	ret = drm_dev_register(tdev->drm, 0);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
-	fbdev = drm_fbdev_cma_init_with_funcs(drm, bpp ? bpp : 32,
-					      drm->mode_config.num_connector,
-					      tdev->fb_funcs);
-	if (IS_ERR(fbdev))
-		DRM_ERROR("Failed to initialize fbdev: %ld\n", PTR_ERR(fbdev));
-	else
-		tdev->fbdev_cma = fbdev;
+	ret = drm_fb_cma_fbdev_init_with_funcs(drm, 0, 0, tdev->fb_funcs);
+	if (ret)
+		DRM_ERROR("Failed to initialize fbdev: %d\n", ret);
 
 
 	return 0;
 	return 0;
 }
 }
 
 
 static void tinydrm_unregister(struct tinydrm_device *tdev)
 static void tinydrm_unregister(struct tinydrm_device *tdev)
 {
 {
-	struct drm_fbdev_cma *fbdev_cma = tdev->fbdev_cma;
-
 	drm_atomic_helper_shutdown(tdev->drm);
 	drm_atomic_helper_shutdown(tdev->drm);
-	/* don't restore fbdev in lastclose, keep pipeline disabled */
-	tdev->fbdev_cma = NULL;
+	drm_fb_cma_fbdev_fini(tdev->drm);
 	drm_dev_unregister(tdev->drm);
 	drm_dev_unregister(tdev->drm);
-	if (fbdev_cma)
-		drm_fbdev_cma_fini(fbdev_cma);
 }
 }
 
 
 static void devm_tinydrm_register_release(void *data)
 static void devm_tinydrm_register_release(void *data)

+ 2 - 1
drivers/gpu/drm/tinydrm/ili9225.c

@@ -20,6 +20,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
 #include <video/mipi_display.h>
 #include <video/mipi_display.h>
 
 
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/tinydrm/mipi-dbi.h>
 #include <drm/tinydrm/mipi-dbi.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
@@ -381,7 +382,7 @@ static struct drm_driver ili9225_driver = {
 				  DRIVER_ATOMIC,
 				  DRIVER_ATOMIC,
 	.fops			= &ili9225_fops,
 	.fops			= &ili9225_fops,
 	TINYDRM_GEM_DRIVER_OPS,
 	TINYDRM_GEM_DRIVER_OPS,
-	.lastclose		= tinydrm_lastclose,
+	.lastclose		= drm_fb_helper_lastclose,
 	.name			= "ili9225",
 	.name			= "ili9225",
 	.desc			= "Ilitek ILI9225",
 	.desc			= "Ilitek ILI9225",
 	.date			= "20171106",
 	.date			= "20171106",

+ 2 - 1
drivers/gpu/drm/tinydrm/mi0283qt.c

@@ -9,6 +9,7 @@
  * (at your option) any later version.
  * (at your option) any later version.
  */
  */
 
 
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_modeset_helper.h>
 #include <drm/drm_modeset_helper.h>
 #include <drm/tinydrm/ili9341.h>
 #include <drm/tinydrm/ili9341.h>
 #include <drm/tinydrm/mipi-dbi.h>
 #include <drm/tinydrm/mipi-dbi.h>
@@ -140,7 +141,7 @@ static struct drm_driver mi0283qt_driver = {
 				  DRIVER_ATOMIC,
 				  DRIVER_ATOMIC,
 	.fops			= &mi0283qt_fops,
 	.fops			= &mi0283qt_fops,
 	TINYDRM_GEM_DRIVER_OPS,
 	TINYDRM_GEM_DRIVER_OPS,
-	.lastclose		= tinydrm_lastclose,
+	.lastclose		= drm_fb_helper_lastclose,
 	.debugfs_init		= mipi_dbi_debugfs_init,
 	.debugfs_init		= mipi_dbi_debugfs_init,
 	.name			= "mi0283qt",
 	.name			= "mi0283qt",
 	.desc			= "Multi-Inno MI0283QT",
 	.desc			= "Multi-Inno MI0283QT",

+ 2 - 1
drivers/gpu/drm/tinydrm/st7586.c

@@ -17,6 +17,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/spi.h>
 #include <video/mipi_display.h>
 #include <video/mipi_display.h>
 
 
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/tinydrm/mipi-dbi.h>
 #include <drm/tinydrm/mipi-dbi.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
 #include <drm/tinydrm/tinydrm-helpers.h>
@@ -320,7 +321,7 @@ static struct drm_driver st7586_driver = {
 				  DRIVER_ATOMIC,
 				  DRIVER_ATOMIC,
 	.fops			= &st7586_fops,
 	.fops			= &st7586_fops,
 	TINYDRM_GEM_DRIVER_OPS,
 	TINYDRM_GEM_DRIVER_OPS,
-	.lastclose		= tinydrm_lastclose,
+	.lastclose		= drm_fb_helper_lastclose,
 	.debugfs_init		= mipi_dbi_debugfs_init,
 	.debugfs_init		= mipi_dbi_debugfs_init,
 	.name			= "st7586",
 	.name			= "st7586",
 	.desc			= "Sitronix ST7586",
 	.desc			= "Sitronix ST7586",

+ 0 - 1
drivers/gpu/drm/tve200/tve200_drm.h

@@ -103,7 +103,6 @@ struct tve200_drm_dev_private {
 	struct drm_panel *panel;
 	struct drm_panel *panel;
 	struct drm_bridge *bridge;
 	struct drm_bridge *bridge;
 	struct drm_simple_display_pipe pipe;
 	struct drm_simple_display_pipe pipe;
-	struct drm_fbdev_cma *fbdev;
 
 
 	void *regs;
 	void *regs;
 	struct clk *pclk;
 	struct clk *pclk;

+ 4 - 12
drivers/gpu/drm/tve200/tve200_drv.c

@@ -46,6 +46,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_panel.h>
 #include <drm/drm_panel.h>
 #include <drm/drm_of.h>
 #include <drm/drm_of.h>
@@ -130,8 +131,7 @@ static int tve200_modeset_init(struct drm_device *dev)
 	 * Passing in 16 here will make the RGB656 mode the default
 	 * Passing in 16 here will make the RGB656 mode the default
 	 * Passing in 32 will use XRGB8888 mode
 	 * Passing in 32 will use XRGB8888 mode
 	 */
 	 */
-	priv->fbdev = drm_fbdev_cma_init(dev, 16,
-					 dev->mode_config.num_connector);
+	drm_fb_cma_fbdev_init(dev, 16, 0);
 	drm_kms_helper_poll_init(dev);
 	drm_kms_helper_poll_init(dev);
 
 
 	goto finish;
 	goto finish;
@@ -146,17 +146,10 @@ finish:
 
 
 DEFINE_DRM_GEM_CMA_FOPS(drm_fops);
 DEFINE_DRM_GEM_CMA_FOPS(drm_fops);
 
 
-static void tve200_lastclose(struct drm_device *dev)
-{
-	struct tve200_drm_dev_private *priv = dev->dev_private;
-
-	drm_fbdev_cma_restore_mode(priv->fbdev);
-}
-
 static struct drm_driver tve200_drm_driver = {
 static struct drm_driver tve200_drm_driver = {
 	.driver_features =
 	.driver_features =
 		DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC,
 		DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC,
-	.lastclose = tve200_lastclose,
+	.lastclose = drm_fb_helper_lastclose,
 	.ioctls = NULL,
 	.ioctls = NULL,
 	.fops = &drm_fops,
 	.fops = &drm_fops,
 	.name = "tve200",
 	.name = "tve200",
@@ -270,8 +263,7 @@ static int tve200_remove(struct platform_device *pdev)
 	struct tve200_drm_dev_private *priv = drm->dev_private;
 	struct tve200_drm_dev_private *priv = drm->dev_private;
 
 
 	drm_dev_unregister(drm);
 	drm_dev_unregister(drm);
-	if (priv->fbdev)
-		drm_fbdev_cma_fini(priv->fbdev);
+	drm_fb_cma_fbdev_fini(drm);
 	if (priv->panel)
 	if (priv->panel)
 		drm_panel_bridge_remove(priv->bridge);
 		drm_panel_bridge_remove(priv->bridge);
 	drm_mode_config_cleanup(drm);
 	drm_mode_config_cleanup(drm);

+ 2 - 11
drivers/gpu/drm/vc4/vc4_drv.c

@@ -111,13 +111,6 @@ static int vc4_get_param_ioctl(struct drm_device *dev, void *data,
 	return 0;
 	return 0;
 }
 }
 
 
-static void vc4_lastclose(struct drm_device *dev)
-{
-	struct vc4_dev *vc4 = to_vc4_dev(dev);
-
-	drm_fbdev_cma_restore_mode(vc4->fbdev);
-}
-
 static const struct vm_operations_struct vc4_vm_ops = {
 static const struct vm_operations_struct vc4_vm_ops = {
 	.fault = vc4_fault,
 	.fault = vc4_fault,
 	.open = drm_gem_vm_open,
 	.open = drm_gem_vm_open,
@@ -159,7 +152,7 @@ static struct drm_driver vc4_drm_driver = {
 			    DRIVER_HAVE_IRQ |
 			    DRIVER_HAVE_IRQ |
 			    DRIVER_RENDER |
 			    DRIVER_RENDER |
 			    DRIVER_PRIME),
 			    DRIVER_PRIME),
-	.lastclose = vc4_lastclose,
+	.lastclose = drm_fb_helper_lastclose,
 	.irq_handler = vc4_irq,
 	.irq_handler = vc4_irq,
 	.irq_preinstall = vc4_irq_preinstall,
 	.irq_preinstall = vc4_irq_preinstall,
 	.irq_postinstall = vc4_irq_postinstall,
 	.irq_postinstall = vc4_irq_postinstall,
@@ -301,12 +294,10 @@ static void vc4_drm_unbind(struct device *dev)
 {
 {
 	struct platform_device *pdev = to_platform_device(dev);
 	struct platform_device *pdev = to_platform_device(dev);
 	struct drm_device *drm = platform_get_drvdata(pdev);
 	struct drm_device *drm = platform_get_drvdata(pdev);
-	struct vc4_dev *vc4 = to_vc4_dev(drm);
 
 
 	drm_dev_unregister(drm);
 	drm_dev_unregister(drm);
 
 
-	if (vc4->fbdev)
-		drm_fbdev_cma_fini(vc4->fbdev);
+	drm_fb_cma_fbdev_fini(drm);
 
 
 	drm_mode_config_cleanup(drm);
 	drm_mode_config_cleanup(drm);
 
 

+ 0 - 2
drivers/gpu/drm/vc4/vc4_drv.h

@@ -39,8 +39,6 @@ struct vc4_dev {
 	struct vc4_dsi *dsi1;
 	struct vc4_dsi *dsi1;
 	struct vc4_vec *vec;
 	struct vc4_vec *vec;
 
 
-	struct drm_fbdev_cma *fbdev;
-
 	struct vc4_hang_state *hang_state;
 	struct vc4_hang_state *hang_state;
 
 
 	/* The kernel-space BO cache.  Tracks buffers that have been
 	/* The kernel-space BO cache.  Tracks buffers that have been

+ 4 - 14
drivers/gpu/drm/vc4/vc4_kms.c

@@ -19,17 +19,11 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_plane_helper.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include "vc4_drv.h"
 #include "vc4_drv.h"
 
 
-static void vc4_output_poll_changed(struct drm_device *dev)
-{
-	struct vc4_dev *vc4 = to_vc4_dev(dev);
-
-	drm_fbdev_cma_hotplug_event(vc4->fbdev);
-}
-
 static void
 static void
 vc4_atomic_complete_commit(struct drm_atomic_state *state)
 vc4_atomic_complete_commit(struct drm_atomic_state *state)
 {
 {
@@ -194,7 +188,7 @@ static struct drm_framebuffer *vc4_fb_create(struct drm_device *dev,
 }
 }
 
 
 static const struct drm_mode_config_funcs vc4_mode_funcs = {
 static const struct drm_mode_config_funcs vc4_mode_funcs = {
-	.output_poll_changed = vc4_output_poll_changed,
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_commit = vc4_atomic_commit,
 	.atomic_commit = vc4_atomic_commit,
 	.fb_create = vc4_fb_create,
 	.fb_create = vc4_fb_create,
@@ -224,12 +218,8 @@ int vc4_kms_load(struct drm_device *dev)
 
 
 	drm_mode_config_reset(dev);
 	drm_mode_config_reset(dev);
 
 
-	if (dev->mode_config.num_connector) {
-		vc4->fbdev = drm_fbdev_cma_init(dev, 32,
-						dev->mode_config.num_connector);
-		if (IS_ERR(vc4->fbdev))
-			vc4->fbdev = NULL;
-	}
+	if (dev->mode_config.num_connector)
+		drm_fb_cma_fbdev_init(dev, 32, 0);
 
 
 	drm_kms_helper_poll_init(dev);
 	drm_kms_helper_poll_init(dev);
 
 

+ 6 - 42
drivers/gpu/drm/zte/zx_drm_drv.c

@@ -29,37 +29,19 @@
 #include "zx_drm_drv.h"
 #include "zx_drm_drv.h"
 #include "zx_vou.h"
 #include "zx_vou.h"
 
 
-struct zx_drm_private {
-	struct drm_fbdev_cma *fbdev;
-};
-
-static void zx_drm_fb_output_poll_changed(struct drm_device *drm)
-{
-	struct zx_drm_private *priv = drm->dev_private;
-
-	drm_fbdev_cma_hotplug_event(priv->fbdev);
-}
-
 static const struct drm_mode_config_funcs zx_drm_mode_config_funcs = {
 static const struct drm_mode_config_funcs zx_drm_mode_config_funcs = {
 	.fb_create = drm_gem_fb_create,
 	.fb_create = drm_gem_fb_create,
-	.output_poll_changed = zx_drm_fb_output_poll_changed,
+	.output_poll_changed = drm_fb_helper_output_poll_changed,
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_commit = drm_atomic_helper_commit,
 	.atomic_commit = drm_atomic_helper_commit,
 };
 };
 
 
-static void zx_drm_lastclose(struct drm_device *drm)
-{
-	struct zx_drm_private *priv = drm->dev_private;
-
-	drm_fbdev_cma_restore_mode(priv->fbdev);
-}
-
 DEFINE_DRM_GEM_CMA_FOPS(zx_drm_fops);
 DEFINE_DRM_GEM_CMA_FOPS(zx_drm_fops);
 
 
 static struct drm_driver zx_drm_driver = {
 static struct drm_driver zx_drm_driver = {
 	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
 	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
 			   DRIVER_ATOMIC,
 			   DRIVER_ATOMIC,
-	.lastclose = zx_drm_lastclose,
+	.lastclose = drm_fb_helper_lastclose,
 	.gem_free_object_unlocked = drm_gem_cma_free_object,
 	.gem_free_object_unlocked = drm_gem_cma_free_object,
 	.gem_vm_ops = &drm_gem_cma_vm_ops,
 	.gem_vm_ops = &drm_gem_cma_vm_ops,
 	.dumb_create = drm_gem_cma_dumb_create,
 	.dumb_create = drm_gem_cma_dumb_create,
@@ -83,18 +65,12 @@ static struct drm_driver zx_drm_driver = {
 static int zx_drm_bind(struct device *dev)
 static int zx_drm_bind(struct device *dev)
 {
 {
 	struct drm_device *drm;
 	struct drm_device *drm;
-	struct zx_drm_private *priv;
 	int ret;
 	int ret;
 
 
-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
 	drm = drm_dev_alloc(&zx_drm_driver, dev);
 	drm = drm_dev_alloc(&zx_drm_driver, dev);
 	if (IS_ERR(drm))
 	if (IS_ERR(drm))
 		return PTR_ERR(drm);
 		return PTR_ERR(drm);
 
 
-	drm->dev_private = priv;
 	dev_set_drvdata(dev, drm);
 	dev_set_drvdata(dev, drm);
 
 
 	drm_mode_config_init(drm);
 	drm_mode_config_init(drm);
@@ -125,12 +101,9 @@ static int zx_drm_bind(struct device *dev)
 	drm_mode_config_reset(drm);
 	drm_mode_config_reset(drm);
 	drm_kms_helper_poll_init(drm);
 	drm_kms_helper_poll_init(drm);
 
 
-	priv->fbdev = drm_fbdev_cma_init(drm, 32,
-					 drm->mode_config.num_connector);
-	if (IS_ERR(priv->fbdev)) {
-		ret = PTR_ERR(priv->fbdev);
+	ret = drm_fb_cma_fbdev_init(drm, 32, 0);
+	if (ret) {
 		DRM_DEV_ERROR(dev, "failed to init cma fbdev: %d\n", ret);
 		DRM_DEV_ERROR(dev, "failed to init cma fbdev: %d\n", ret);
-		priv->fbdev = NULL;
 		goto out_poll_fini;
 		goto out_poll_fini;
 	}
 	}
 
 
@@ -141,10 +114,7 @@ static int zx_drm_bind(struct device *dev)
 	return 0;
 	return 0;
 
 
 out_fbdev_fini:
 out_fbdev_fini:
-	if (priv->fbdev) {
-		drm_fbdev_cma_fini(priv->fbdev);
-		priv->fbdev = NULL;
-	}
+	drm_fb_cma_fbdev_fini(drm);
 out_poll_fini:
 out_poll_fini:
 	drm_kms_helper_poll_fini(drm);
 	drm_kms_helper_poll_fini(drm);
 	drm_mode_config_cleanup(drm);
 	drm_mode_config_cleanup(drm);
@@ -152,7 +122,6 @@ out_unbind:
 	component_unbind_all(dev, drm);
 	component_unbind_all(dev, drm);
 out_unregister:
 out_unregister:
 	dev_set_drvdata(dev, NULL);
 	dev_set_drvdata(dev, NULL);
-	drm->dev_private = NULL;
 	drm_dev_unref(drm);
 	drm_dev_unref(drm);
 	return ret;
 	return ret;
 }
 }
@@ -160,18 +129,13 @@ out_unregister:
 static void zx_drm_unbind(struct device *dev)
 static void zx_drm_unbind(struct device *dev)
 {
 {
 	struct drm_device *drm = dev_get_drvdata(dev);
 	struct drm_device *drm = dev_get_drvdata(dev);
-	struct zx_drm_private *priv = drm->dev_private;
 
 
 	drm_dev_unregister(drm);
 	drm_dev_unregister(drm);
-	if (priv->fbdev) {
-		drm_fbdev_cma_fini(priv->fbdev);
-		priv->fbdev = NULL;
-	}
+	drm_fb_cma_fbdev_fini(drm);
 	drm_kms_helper_poll_fini(drm);
 	drm_kms_helper_poll_fini(drm);
 	drm_mode_config_cleanup(drm);
 	drm_mode_config_cleanup(drm);
 	component_unbind_all(dev, drm);
 	component_unbind_all(dev, drm);
 	dev_set_drvdata(dev, NULL);
 	dev_set_drvdata(dev, NULL);
-	drm->dev_private = NULL;
 	drm_dev_unref(drm);
 	drm_dev_unref(drm);
 }
 }
 
 

+ 2 - 0
include/drm/drm_edid.h

@@ -465,6 +465,8 @@ struct edid *drm_get_edid(struct drm_connector *connector,
 struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
 struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
 				     struct i2c_adapter *adapter);
 				     struct i2c_adapter *adapter);
 struct edid *drm_edid_duplicate(const struct edid *edid);
 struct edid *drm_edid_duplicate(const struct edid *edid);
+void drm_reset_display_info(struct drm_connector *connector);
+u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edid);
 int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
 int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
 
 
 u8 drm_match_cea_mode(const struct drm_display_mode *to_match);
 u8 drm_match_cea_mode(const struct drm_display_mode *to_match);

+ 7 - 0
include/drm/drm_fb_cma_helper.h

@@ -16,6 +16,13 @@ struct drm_mode_fb_cmd2;
 struct drm_plane;
 struct drm_plane;
 struct drm_plane_state;
 struct drm_plane_state;
 
 
+int drm_fb_cma_fbdev_init_with_funcs(struct drm_device *dev,
+	unsigned int preferred_bpp, unsigned int max_conn_count,
+	const struct drm_framebuffer_funcs *funcs);
+int drm_fb_cma_fbdev_init(struct drm_device *dev, unsigned int preferred_bpp,
+			  unsigned int max_conn_count);
+void drm_fb_cma_fbdev_fini(struct drm_device *dev);
+
 struct drm_fbdev_cma *drm_fbdev_cma_init_with_funcs(struct drm_device *dev,
 struct drm_fbdev_cma *drm_fbdev_cma_init_with_funcs(struct drm_device *dev,
 	unsigned int preferred_bpp, unsigned int max_conn_count,
 	unsigned int preferred_bpp, unsigned int max_conn_count,
 	const struct drm_framebuffer_funcs *funcs);
 	const struct drm_framebuffer_funcs *funcs);

+ 0 - 3
include/drm/tinydrm/tinydrm.h

@@ -19,14 +19,12 @@
  * @drm: DRM device
  * @drm: DRM device
  * @pipe: Display pipe structure
  * @pipe: Display pipe structure
  * @dirty_lock: Serializes framebuffer flushing
  * @dirty_lock: Serializes framebuffer flushing
- * @fbdev_cma: CMA fbdev structure
  * @fb_funcs: Framebuffer functions used when creating framebuffers
  * @fb_funcs: Framebuffer functions used when creating framebuffers
  */
  */
 struct tinydrm_device {
 struct tinydrm_device {
 	struct drm_device *drm;
 	struct drm_device *drm;
 	struct drm_simple_display_pipe pipe;
 	struct drm_simple_display_pipe pipe;
 	struct mutex dirty_lock;
 	struct mutex dirty_lock;
-	struct drm_fbdev_cma *fbdev_cma;
 	const struct drm_framebuffer_funcs *fb_funcs;
 	const struct drm_framebuffer_funcs *fb_funcs;
 };
 };
 
 
@@ -80,7 +78,6 @@ pipe_to_tinydrm(struct drm_simple_display_pipe *pipe)
 	.type = DRM_MODE_TYPE_DRIVER, \
 	.type = DRM_MODE_TYPE_DRIVER, \
 	.clock = 1 /* pass validation */
 	.clock = 1 /* pass validation */
 
 
-void tinydrm_lastclose(struct drm_device *drm);
 void tinydrm_gem_cma_free_object(struct drm_gem_object *gem_obj);
 void tinydrm_gem_cma_free_object(struct drm_gem_object *gem_obj);
 struct drm_gem_object *
 struct drm_gem_object *
 tinydrm_gem_cma_prime_import_sg_table(struct drm_device *drm,
 tinydrm_gem_cma_prime_import_sg_table(struct drm_device *drm,