Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1468026 > unrolled thread

[PATCH v4 0/5] drm: add SimpleDRM driver

Started byNoralf Trønnes <noralf@tronnes.org>
First post2016-08-22 22:30 +0200
Last post2016-08-22 22:30 +0200
Articles 4 — 2 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v4 0/5] drm: add SimpleDRM driver Noralf Trønnes <noralf@tronnes.org> - 2016-08-22 22:30 +0200
    [PATCH v4 4/5] drm: simpledrm: add fbdev fallback support Noralf Trønnes <noralf@tronnes.org> - 2016-08-22 22:30 +0200
      Re: [PATCH v4 4/5] drm: simpledrm: add fbdev fallback support Daniel Vetter <daniel@ffwll.ch> - 2016-08-23 08:20 +0200
    [PATCH v4 1/5] of: Add EXPORT_SYMBOL for of_chosen Noralf Trønnes <noralf@tronnes.org> - 2016-08-22 22:30 +0200

#1468026 — [PATCH v4 0/5] drm: add SimpleDRM driver

FromNoralf Trønnes <noralf@tronnes.org>
Date2016-08-22 22:30 +0200
Subject[PATCH v4 0/5] drm: add SimpleDRM driver
Message-ID<s9413-2Ex-9@gated-at.bofh.it>
This patchset adds the simpledrm driver by David Herrmann based on a
patchset[1] from 2014. That patchset also included patches for kicking
out simpledrm by real drivers. I have stayed away from that since it
involves another subsystem and I would probably be unable to answer any
questions about the implementation.

Two main changes in this fourth version:

The gem code has been reworked to match that of the udl driver. This
has led me to drop PRIME support since it was not trivial to implement.

The fbdev emulation doesn't use the native framebuffer directly, but uses
the framebuffer flushing/blitting functionality. This means that fbdev mmap
doesn't work anymore as noted in an udl commit message
(see note in simpledrm_fbdev.c).

Also added a patch to export of_chosen so the driver can be built as a module
and added drm_fb_helper_set_suspend_lock() that takes the console lock.

I have tested simpledrm on a Raspberry Pi B+ with U-boot setting up the
framebuffer and producing this node (legacy, not under /chosen):

/ {
        framebuffer@1e887000 {
                compatible = "simple-framebuffer";
                reg = <0x1e887000 0x36c600>;
                format = "r5g6b5";
                width = <1824>;
                height = <984>;
                stride = <3648>;
                status = "okay";
        };

I have only tested with fbcon and modetest (XR24,RG16).


Noralf.


Changes from version 3:
of:
- Export of_chosen so simpledrm can be built as a module
drm_fb_helper:
- Add drm_fb_helper_set_suspend_lock()
simpledrm:
- Reworked gem code to match udl
- Dropped PRIME support
- Dropped dirty_info_property, it's gone
- Don't use drm_device.platformdev it's deprecated
- Remove struct sdrm_device #ifdef's
- Split out sdrm_fb_init() from sdrm_fb_create(), needed by fbdev code
- Simplify drm_clip validation by extending the check in
  sdrm_dirty() and drop the one in sdrm_blit()
- Removed sdrm_dirty_all_unlocked() which was unused.
fbdev:
- Remove #ifdef CONFIG_DRM_FBDEV_EMULATION
- Use drm_fb_helper_set_suspend_lock()
- Don't access the native framebuffer directly, but do blitting here as well.
- Use the drm_fb_helper_sys_*() functions instead of the cfb versions.
- Remove FBINFO_CAN_FORCE_OUTPUT flag which doesn't work now.
- Pass struct drm_fb_helper around instead of struct sdrm_fbdev.
remove_conflicting_framebuffers:
- drm_device.platformdev is deprecated, use to_platform_device(ddev->dev).
- fb_helper might have been released in sdrm_fbdev_fb_destroy(),
  so open code drm_fb_helper_release_fbi()
- Strengthen the test in sdrm_fbdev_event_notify() that we're the one.

Changes from version 2:
- Remove superfluos module.h includes
- Move includes from header to source files
- Set plane.fb before flushing in pipe update, or else the previous one
  gets flushed
- Added check for vblank event in sdrm_display_pipe_update()
fbdev:
- Switch to using drm_fb_helper in preparation for future panic handling
  which needs an enabled pipeline.
- Don't forget to free fb_info when kicked out.

Changes from version 1:
- Move platform_set_drvdata() before drm_dev_register()
- Remove drm_legacy_mmap() call.
- Set mode_config.{min,max}_{width,height} to the actual dimensions
  of the native framebuffer
- Remove plane positioning since it won't work with the simple display pipe,
  meaning sdrm_display_pipe_check() isn't necessary either
- Support the additions to the Device Tree binding document, including
  clocks, regulators and having the node under /chosen
fbdev:
- Honour remove_conflicting_framebuffers()

Changes from previous version[2]:
- Remove FB_SIMPLE=n dependency to avoid kconfig recursive error
- Changed module name to match kconfig help text: sdrm -> simpledrm
- Use drm_simple_display_pipe
- Replace deprecated drm_platform_init()
- sdrm_dumb_create(): drm_gem_object_unreference() -> *_unlocked()
- sdrm_dumb_map_offset(): drm_gem_object_lookup() remove drm_device parameter
- sdrm_drm_mmap() changes:
  Remove struct_mutex locking
  Add drm_vma_offset_{lock,unlock}_lookup()
  drm_mmap() -> drm_legacy_mmap()
- dma_buf_begin_cpu_access() doesn't require start and length anymore
- Use drm_cvt_mode() instead of open coding a mode
- Fix format conversion. In the intermediate step, store the 8/6/5 bit color
  value in the upper part of the 16-bit color variable, not the lower.
- Support clips == NULL in sdrm_dirty()
- Set mode_config.preferred_depth
- Attach mode_config.dirty_info_property to connector
fbdev:
- Remove the DRM_SIMPLEDRM_FBDEV kconfig option and use DRM_FBDEV_EMULATION
- Suspend fbcon/fbdev when the pipeline is enabled, resume in lastclose
- Add FBINFO_CAN_FORCE_OUTPUT flag so we get oops'es on the console

[1] https://lists.freedesktop.org/archives/dri-devel/2014-January/052584.html
[2] https://lists.freedesktop.org/archives/dri-devel/2014-January/052594.html


Noralf Trønnes (5):
  of: Add EXPORT_SYMBOL for of_chosen
  drm/fb-helper: Add drm_fb_helper_set_suspend_lock()
  drm: add SimpleDRM driver
  drm: simpledrm: add fbdev fallback support
  drm: simpledrm: honour remove_conflicting_framebuffers()

 drivers/gpu/drm/Kconfig                      |   2 +
 drivers/gpu/drm/Makefile                     |   1 +
 drivers/gpu/drm/drm_fb_helper.c              |  57 +++
 drivers/gpu/drm/simpledrm/Kconfig            |  27 ++
 drivers/gpu/drm/simpledrm/Makefile           |   4 +
 drivers/gpu/drm/simpledrm/simpledrm.h        |  93 +++++
 drivers/gpu/drm/simpledrm/simpledrm_damage.c | 235 ++++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_drv.c    | 550 +++++++++++++++++++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_fbdev.c  | 259 +++++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_gem.c    | 202 ++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_kms.c    | 248 ++++++++++++
 drivers/of/base.c                            |   1 +
 include/drm/drm_fb_helper.h                  |   9 +
 13 files changed, 1688 insertions(+)
 create mode 100644 drivers/gpu/drm/simpledrm/Kconfig
 create mode 100644 drivers/gpu/drm/simpledrm/Makefile
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm.h
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_damage.c
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_drv.c
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_fbdev.c
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_gem.c
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_kms.c

--
2.8.2

[toc] | [next] | [standalone]


#1468028 — [PATCH v4 4/5] drm: simpledrm: add fbdev fallback support

FromNoralf Trønnes <noralf@tronnes.org>
Date2016-08-22 22:30 +0200
Subject[PATCH v4 4/5] drm: simpledrm: add fbdev fallback support
Message-ID<s9414-2Ex-33@gated-at.bofh.it>
In reply to#1468026
Create a simple fbdev device during SimpleDRM setup so legacy user-space
and fbcon can use it.

Original work by David Herrmann.

Cc: dh.herrmann@gmail.com
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---

Changes from version 3:
- Remove #ifdef CONFIG_DRM_FBDEV_EMULATION
- Use drm_fb_helper_set_suspend_lock()
- Don't access the native framebuffer directly, but do blitting here as well.
- Use the drm_fb_helper_sys_*() functions instead of the cfb versions.
- Remove FBINFO_CAN_FORCE_OUTPUT flag which doesn't work now.
- Pass struct drm_fb_helper around instead of struct sdrm_fbdev.

Changes from version 2:
- Switch to using drm_fb_helper in preparation for future panic handling
  which needs an enabled pipeline.

Changes from version 1:
  No changes

Changes from previous version:
- Remove the DRM_SIMPLEDRM_FBDEV kconfig option and use DRM_FBDEV_EMULATION
- Suspend fbcon/fbdev when the pipeline is enabled, resume in lastclose
- Add FBINFO_CAN_FORCE_OUTPUT flag so we get oops'es on the console

 drivers/gpu/drm/simpledrm/Kconfig           |   3 +
 drivers/gpu/drm/simpledrm/Makefile          |   2 +-
 drivers/gpu/drm/simpledrm/simpledrm.h       |   5 +
 drivers/gpu/drm/simpledrm/simpledrm_drv.c   |   4 +
 drivers/gpu/drm/simpledrm/simpledrm_fbdev.c | 201 ++++++++++++++++++++++++++++
 drivers/gpu/drm/simpledrm/simpledrm_kms.c   |  14 ++
 6 files changed, 228 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_fbdev.c

diff --git a/drivers/gpu/drm/simpledrm/Kconfig b/drivers/gpu/drm/simpledrm/Kconfig
index f45b25d..3257590 100644
--- a/drivers/gpu/drm/simpledrm/Kconfig
+++ b/drivers/gpu/drm/simpledrm/Kconfig
@@ -13,6 +13,9 @@ config DRM_SIMPLEDRM
 	  SimpleDRM supports "simple-framebuffer" DeviceTree objects and
 	  compatible platform framebuffers.

+	  If fbdev support is enabled, this driver will also provide an fbdev
+	  compatibility layer that supports fbcon, mmap is not supported.
+
 	  If unsure, say Y.

 	  To compile this driver as a module, choose M here: the
diff --git a/drivers/gpu/drm/simpledrm/Makefile b/drivers/gpu/drm/simpledrm/Makefile
index f6a62dc..5474f7f 100644
--- a/drivers/gpu/drm/simpledrm/Makefile
+++ b/drivers/gpu/drm/simpledrm/Makefile
@@ -1,4 +1,4 @@
 simpledrm-y :=	simpledrm_drv.o simpledrm_kms.o simpledrm_gem.o \
-		simpledrm_damage.o
+		simpledrm_damage.o simpledrm_fbdev.o

 obj-$(CONFIG_DRM_SIMPLEDRM) := simpledrm.o
diff --git a/drivers/gpu/drm/simpledrm/simpledrm.h b/drivers/gpu/drm/simpledrm/simpledrm.h
index 0739581..d4eb52c 100644
--- a/drivers/gpu/drm/simpledrm/simpledrm.h
+++ b/drivers/gpu/drm/simpledrm/simpledrm.h
@@ -16,6 +16,7 @@
 #include <drm/drm_simple_kms_helper.h>

 struct simplefb_format;
+struct drm_fb_helper;
 struct regulator;
 struct clk;

@@ -23,6 +24,7 @@ struct sdrm_device {
 	struct drm_device *ddev;
 	struct drm_simple_display_pipe pipe;
 	struct drm_connector conn;
+	struct drm_fb_helper *fb_helper;

 	/* framebuffer information */
 	const struct simplefb_format *fb_sformat;
@@ -42,6 +44,7 @@ struct sdrm_device {
 	struct regulator **regulators;
 };

+void sdrm_lastclose(struct drm_device *ddev);
 int sdrm_drm_modeset_init(struct sdrm_device *sdrm);

 int sdrm_dirty(struct drm_framebuffer *fb,
@@ -82,5 +85,7 @@ struct sdrm_framebuffer {
 int sdrm_fb_init(struct drm_device *ddev, struct sdrm_framebuffer *fb,
 		 const struct drm_mode_fb_cmd2 *mode_cmd,
 		 struct sdrm_gem_object *obj);
+void sdrm_fbdev_init(struct sdrm_device *sdrm);
+void sdrm_fbdev_cleanup(struct sdrm_device *sdrm);

 #endif /* SDRM_DRV_H */
diff --git a/drivers/gpu/drm/simpledrm/simpledrm_drv.c b/drivers/gpu/drm/simpledrm/simpledrm_drv.c
index 17c1b55..fe752c6 100644
--- a/drivers/gpu/drm/simpledrm/simpledrm_drv.c
+++ b/drivers/gpu/drm/simpledrm/simpledrm_drv.c
@@ -47,6 +47,7 @@ static const struct vm_operations_struct sdrm_gem_vm_ops = {
 static struct drm_driver sdrm_drm_driver = {
 	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
 	.fops = &sdrm_drm_fops,
+	.lastclose = sdrm_lastclose,

 	.gem_free_object = sdrm_gem_free_object,
 	.gem_vm_ops = &sdrm_gem_vm_ops,
@@ -451,6 +452,8 @@ static int sdrm_simplefb_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_regulators;

+	sdrm_fbdev_init(sdrm);
+
 	DRM_INFO("Initialized %s on minor %d\n", ddev->driver->name,
 		 ddev->primary->index);

@@ -476,6 +479,7 @@ static int sdrm_simplefb_remove(struct platform_device *pdev)
 	struct drm_device *ddev = platform_get_drvdata(pdev);
 	struct sdrm_device *sdrm = ddev->dev_private;

+	sdrm_fbdev_cleanup(sdrm);
 	drm_dev_unregister(ddev);
 	drm_mode_config_cleanup(ddev);

diff --git a/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c b/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c
new file mode 100644
index 0000000..c6596ad
--- /dev/null
+++ b/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c
@@ -0,0 +1,201 @@
+/*
+ * SimpleDRM firmware framebuffer driver
+ * Copyright (c) 2012-2014 David Herrmann <dh.herrmann@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <linux/fb.h>
+#include <linux/platform_device.h>
+
+#include "simpledrm.h"
+
+struct sdrm_fbdev {
+	struct drm_fb_helper fb_helper;
+	struct sdrm_framebuffer fb;
+};
+
+static inline struct sdrm_fbdev *to_sdrm_fbdev(struct drm_fb_helper *helper)
+{
+	return container_of(helper, struct sdrm_fbdev, fb_helper);
+}
+
+/*
+ * simpledrm uses the same gem code as udl and work on that driver has shown
+ * that it doens't work well with fb_deferred_io. So mmap is not supported.
+ *
+ * This is documented in commit 677d23b70bf9:
+ *
+ * drm/udl: disable fb_defio by default
+ * There seems to be a bad interaction between gem/shmem and defio on top,
+ * I get list corruption on the page lru in the shmem code.
+ *
+ * Turn it off for now until we get some more digging done.
+ *
+ */
+static int sdrm_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+	return -ENODEV;
+}
+
+static struct fb_ops sdrm_fbdev_ops = {
+	.owner		= THIS_MODULE,
+	.fb_fillrect	= drm_fb_helper_sys_fillrect,
+	.fb_copyarea	= drm_fb_helper_sys_copyarea,
+	.fb_imageblit	= drm_fb_helper_sys_imageblit,
+	.fb_check_var	= drm_fb_helper_check_var,
+	.fb_set_par	= drm_fb_helper_set_par,
+	.fb_setcmap	= drm_fb_helper_setcmap,
+	.fb_mmap	= sdrm_fb_mmap,
+};
+
+static int sdrm_fbdev_create(struct drm_fb_helper *helper,
+			     struct drm_fb_helper_surface_size *sizes)
+{
+	struct sdrm_fbdev *fbdev = to_sdrm_fbdev(helper);
+	struct drm_device *ddev = helper->dev;
+	struct sdrm_device *sdrm = ddev->dev_private;
+	struct drm_mode_fb_cmd2 mode_cmd = {
+		.width = sdrm->fb_width,
+		.height = sdrm->fb_height,
+		.pitches[0] = sdrm->fb_stride,
+		.pixel_format = sdrm->fb_format,
+	};
+	struct sdrm_gem_object *obj;
+	struct drm_framebuffer *fb;
+	struct fb_info *fbi;
+	size_t size;
+	int ret;
+
+	size = PAGE_ALIGN(sdrm->fb_size);
+	obj = sdrm_gem_alloc_object(ddev, size);
+	if (!obj)
+		return -ENOMEM;
+
+	ret = sdrm_gem_vmap(obj);
+	if (ret) {
+		DRM_ERROR("failed to vmap fb\n");
+		goto err_gem_free;
+	}
+
+	fbi = drm_fb_helper_alloc_fbi(helper);
+	if (IS_ERR(fbi)) {
+		ret = PTR_ERR(fbi);
+		goto err_gem_free;
+	}
+
+	ret = sdrm_fb_init(ddev, &fbdev->fb, &mode_cmd, obj);
+	if (ret) {
+		dev_err(ddev->dev, "Failed to init framebuffer: %d\n", ret);
+		goto err_fbi_release;
+	}
+
+	fb = &fbdev->fb.base;
+	helper->fb = fb;
+	fbi->par = helper;
+
+	fbi->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE;
+	fbi->fbops = &sdrm_fbdev_ops;
+
+	drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
+	drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
+
+	strncpy(fbi->fix.id, "simpledrmfb", 15);
+	fbi->screen_base = obj->vmapping;
+	fbi->fix.smem_len = sdrm->fb_size;
+
+	return 0;
+
+err_fbi_release:
+	drm_fb_helper_release_fbi(helper);
+
+err_gem_free:
+	drm_gem_object_unreference_unlocked(&obj->base);
+
+	return ret;
+}
+
+static const struct drm_fb_helper_funcs sdrm_fb_helper_funcs = {
+	.fb_probe = sdrm_fbdev_create,
+};
+
+void sdrm_fbdev_init(struct sdrm_device *sdrm)
+{
+	struct drm_device *ddev = sdrm->ddev;
+	struct drm_fb_helper *fb_helper;
+	struct sdrm_fbdev *fbdev;
+	int ret;
+
+	fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
+	if (!fbdev) {
+		dev_err(ddev->dev, "Failed to allocate drm fbdev.\n");
+		return;
+	}
+
+	fb_helper = &fbdev->fb_helper;
+
+	drm_fb_helper_prepare(ddev, fb_helper, &sdrm_fb_helper_funcs);
+
+	ret = drm_fb_helper_init(ddev, fb_helper, 1, 1);
+	if (ret < 0) {
+		dev_err(ddev->dev, "Failed to initialize drm fb helper.\n");
+		goto err_free;
+	}
+
+	ret = drm_fb_helper_single_add_all_connectors(fb_helper);
+	if (ret < 0) {
+		dev_err(ddev->dev, "Failed to add connectors.\n");
+		goto err_drm_fb_helper_fini;
+	}
+
+	ret = drm_fb_helper_initial_config(fb_helper,
+					   ddev->mode_config.preferred_depth);
+	if (ret < 0) {
+		dev_err(ddev->dev, "Failed to set initial hw configuration.\n");
+		goto err_drm_fb_helper_fini;
+	}
+
+	if (!fb_helper->fbdev) {
+		/* fbdev emulation is disabled */
+		kfree(fbdev);
+		return;
+	}
+
+	sdrm->fb_helper = fb_helper;
+
+	return;
+
+err_drm_fb_helper_fini:
+	drm_fb_helper_fini(fb_helper);
+err_free:
+	kfree(fbdev);
+}
+
+void sdrm_fbdev_cleanup(struct sdrm_device *sdrm)
+{
+	struct drm_fb_helper *fb_helper = sdrm->fb_helper;
+	struct sdrm_fbdev *fbdev;
+
+	if (!fb_helper)
+		return;
+
+	sdrm->fb_helper = NULL;
+	fbdev = to_sdrm_fbdev(fb_helper);
+
+	drm_fb_helper_unregister_fbi(fb_helper);
+	cancel_work_sync(&fb_helper->dirty_work);
+	drm_fb_helper_release_fbi(fb_helper);
+
+	drm_framebuffer_unregister_private(fb_helper->fb);
+	drm_framebuffer_cleanup(fb_helper->fb);
+	drm_gem_object_unreference_unlocked(&fbdev->fb.obj->base);
+
+	drm_fb_helper_fini(fb_helper);
+	kfree(fbdev);
+}
diff --git a/drivers/gpu/drm/simpledrm/simpledrm_kms.c b/drivers/gpu/drm/simpledrm/simpledrm_kms.c
index e6dc3df..8b98a08 100644
--- a/drivers/gpu/drm/simpledrm/simpledrm_kms.c
+++ b/drivers/gpu/drm/simpledrm/simpledrm_kms.c
@@ -12,6 +12,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_gem.h>
 #include <drm/drm_simple_kms_helper.h>
 #include <linux/slab.h>
@@ -24,6 +25,16 @@ static const uint32_t sdrm_formats[] = {
 	DRM_FORMAT_XRGB8888,
 };

+void sdrm_lastclose(struct drm_device *ddev)
+{
+	struct sdrm_device *sdrm = ddev->dev_private;
+
+	if (sdrm->fb_helper) {
+		drm_fb_helper_restore_fbdev_mode_unlocked(sdrm->fb_helper);
+		drm_fb_helper_set_suspend_lock(sdrm->fb_helper, 0);
+	}
+}
+
 static int sdrm_conn_get_modes(struct drm_connector *conn)
 {
 	struct sdrm_device *sdrm = conn->dev->dev_private;
@@ -92,6 +103,9 @@ void sdrm_display_pipe_update(struct drm_simple_display_pipe *pipe,

 	sdrm_crtc_send_vblank_event(&pipe->crtc);

+	if (sdrm->fb_helper && fb && fb != sdrm->fb_helper->fb)
+		drm_fb_helper_set_suspend_lock(sdrm->fb_helper, 1);
+
 	if (fb) {
 		pipe->plane.fb = fb;
 		sdrm_dirty_all_locked(sdrm);
--
2.8.2

[toc] | [prev] | [next] | [standalone]


#1468312 — Re: [PATCH v4 4/5] drm: simpledrm: add fbdev fallback support

FromDaniel Vetter <daniel@ffwll.ch>
Date2016-08-23 08:20 +0200
SubjectRe: [PATCH v4 4/5] drm: simpledrm: add fbdev fallback support
Message-ID<s9de1-ab-3@gated-at.bofh.it>
In reply to#1468028
On Mon, Aug 22, 2016 at 10:25:24PM +0200, Noralf Trønnes wrote:
> Create a simple fbdev device during SimpleDRM setup so legacy user-space
> and fbcon can use it.
> 
> Original work by David Herrmann.
> 
> Cc: dh.herrmann@gmail.com
> Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
> ---
> 
> Changes from version 3:
> - Remove #ifdef CONFIG_DRM_FBDEV_EMULATION
> - Use drm_fb_helper_set_suspend_lock()
> - Don't access the native framebuffer directly, but do blitting here as well.
> - Use the drm_fb_helper_sys_*() functions instead of the cfb versions.
> - Remove FBINFO_CAN_FORCE_OUTPUT flag which doesn't work now.
> - Pass struct drm_fb_helper around instead of struct sdrm_fbdev.
> 
> Changes from version 2:
> - Switch to using drm_fb_helper in preparation for future panic handling
>   which needs an enabled pipeline.
> 
> Changes from version 1:
>   No changes
> 
> Changes from previous version:
> - Remove the DRM_SIMPLEDRM_FBDEV kconfig option and use DRM_FBDEV_EMULATION
> - Suspend fbcon/fbdev when the pipeline is enabled, resume in lastclose
> - Add FBINFO_CAN_FORCE_OUTPUT flag so we get oops'es on the console
> 
>  drivers/gpu/drm/simpledrm/Kconfig           |   3 +
>  drivers/gpu/drm/simpledrm/Makefile          |   2 +-
>  drivers/gpu/drm/simpledrm/simpledrm.h       |   5 +
>  drivers/gpu/drm/simpledrm/simpledrm_drv.c   |   4 +
>  drivers/gpu/drm/simpledrm/simpledrm_fbdev.c | 201 ++++++++++++++++++++++++++++
>  drivers/gpu/drm/simpledrm/simpledrm_kms.c   |  14 ++
>  6 files changed, 228 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_fbdev.c
> 
> diff --git a/drivers/gpu/drm/simpledrm/Kconfig b/drivers/gpu/drm/simpledrm/Kconfig
> index f45b25d..3257590 100644
> --- a/drivers/gpu/drm/simpledrm/Kconfig
> +++ b/drivers/gpu/drm/simpledrm/Kconfig
> @@ -13,6 +13,9 @@ config DRM_SIMPLEDRM
>  	  SimpleDRM supports "simple-framebuffer" DeviceTree objects and
>  	  compatible platform framebuffers.
> 
> +	  If fbdev support is enabled, this driver will also provide an fbdev
> +	  compatibility layer that supports fbcon, mmap is not supported.
> +
>  	  If unsure, say Y.
> 
>  	  To compile this driver as a module, choose M here: the
> diff --git a/drivers/gpu/drm/simpledrm/Makefile b/drivers/gpu/drm/simpledrm/Makefile
> index f6a62dc..5474f7f 100644
> --- a/drivers/gpu/drm/simpledrm/Makefile
> +++ b/drivers/gpu/drm/simpledrm/Makefile
> @@ -1,4 +1,4 @@
>  simpledrm-y :=	simpledrm_drv.o simpledrm_kms.o simpledrm_gem.o \
> -		simpledrm_damage.o
> +		simpledrm_damage.o simpledrm_fbdev.o
> 
>  obj-$(CONFIG_DRM_SIMPLEDRM) := simpledrm.o
> diff --git a/drivers/gpu/drm/simpledrm/simpledrm.h b/drivers/gpu/drm/simpledrm/simpledrm.h
> index 0739581..d4eb52c 100644
> --- a/drivers/gpu/drm/simpledrm/simpledrm.h
> +++ b/drivers/gpu/drm/simpledrm/simpledrm.h
> @@ -16,6 +16,7 @@
>  #include <drm/drm_simple_kms_helper.h>
> 
>  struct simplefb_format;
> +struct drm_fb_helper;
>  struct regulator;
>  struct clk;
> 
> @@ -23,6 +24,7 @@ struct sdrm_device {
>  	struct drm_device *ddev;
>  	struct drm_simple_display_pipe pipe;
>  	struct drm_connector conn;
> +	struct drm_fb_helper *fb_helper;
> 
>  	/* framebuffer information */
>  	const struct simplefb_format *fb_sformat;
> @@ -42,6 +44,7 @@ struct sdrm_device {
>  	struct regulator **regulators;
>  };
> 
> +void sdrm_lastclose(struct drm_device *ddev);
>  int sdrm_drm_modeset_init(struct sdrm_device *sdrm);
> 
>  int sdrm_dirty(struct drm_framebuffer *fb,
> @@ -82,5 +85,7 @@ struct sdrm_framebuffer {
>  int sdrm_fb_init(struct drm_device *ddev, struct sdrm_framebuffer *fb,
>  		 const struct drm_mode_fb_cmd2 *mode_cmd,
>  		 struct sdrm_gem_object *obj);
> +void sdrm_fbdev_init(struct sdrm_device *sdrm);
> +void sdrm_fbdev_cleanup(struct sdrm_device *sdrm);
> 
>  #endif /* SDRM_DRV_H */
> diff --git a/drivers/gpu/drm/simpledrm/simpledrm_drv.c b/drivers/gpu/drm/simpledrm/simpledrm_drv.c
> index 17c1b55..fe752c6 100644
> --- a/drivers/gpu/drm/simpledrm/simpledrm_drv.c
> +++ b/drivers/gpu/drm/simpledrm/simpledrm_drv.c
> @@ -47,6 +47,7 @@ static const struct vm_operations_struct sdrm_gem_vm_ops = {
>  static struct drm_driver sdrm_drm_driver = {
>  	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
>  	.fops = &sdrm_drm_fops,
> +	.lastclose = sdrm_lastclose,
> 
>  	.gem_free_object = sdrm_gem_free_object,
>  	.gem_vm_ops = &sdrm_gem_vm_ops,
> @@ -451,6 +452,8 @@ static int sdrm_simplefb_probe(struct platform_device *pdev)
>  	if (ret)
>  		goto err_regulators;
> 
> +	sdrm_fbdev_init(sdrm);
> +
>  	DRM_INFO("Initialized %s on minor %d\n", ddev->driver->name,
>  		 ddev->primary->index);
> 
> @@ -476,6 +479,7 @@ static int sdrm_simplefb_remove(struct platform_device *pdev)
>  	struct drm_device *ddev = platform_get_drvdata(pdev);
>  	struct sdrm_device *sdrm = ddev->dev_private;
> 
> +	sdrm_fbdev_cleanup(sdrm);
>  	drm_dev_unregister(ddev);
>  	drm_mode_config_cleanup(ddev);
> 
> diff --git a/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c b/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c
> new file mode 100644
> index 0000000..c6596ad
> --- /dev/null
> +++ b/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c
> @@ -0,0 +1,201 @@
> +/*
> + * SimpleDRM firmware framebuffer driver
> + * Copyright (c) 2012-2014 David Herrmann <dh.herrmann@gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the Free
> + * Software Foundation; either version 2 of the License, or (at your option)
> + * any later version.
> + */
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fb_helper.h>
> +#include <linux/fb.h>
> +#include <linux/platform_device.h>
> +
> +#include "simpledrm.h"
> +
> +struct sdrm_fbdev {
> +	struct drm_fb_helper fb_helper;
> +	struct sdrm_framebuffer fb;
> +};
> +
> +static inline struct sdrm_fbdev *to_sdrm_fbdev(struct drm_fb_helper *helper)
> +{
> +	return container_of(helper, struct sdrm_fbdev, fb_helper);
> +}
> +
> +/*
> + * simpledrm uses the same gem code as udl and work on that driver has shown
> + * that it doens't work well with fb_deferred_io. So mmap is not supported.
> + *
> + * This is documented in commit 677d23b70bf9:
> + *
> + * drm/udl: disable fb_defio by default
> + * There seems to be a bad interaction between gem/shmem and defio on top,
> + * I get list corruption on the page lru in the shmem code.
> + *
> + * Turn it off for now until we get some more digging done.
> + *
> + */
> +static int sdrm_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
> +{
> +	return -ENODEV;
> +}
> +
> +static struct fb_ops sdrm_fbdev_ops = {
> +	.owner		= THIS_MODULE,
> +	.fb_fillrect	= drm_fb_helper_sys_fillrect,
> +	.fb_copyarea	= drm_fb_helper_sys_copyarea,
> +	.fb_imageblit	= drm_fb_helper_sys_imageblit,
> +	.fb_check_var	= drm_fb_helper_check_var,
> +	.fb_set_par	= drm_fb_helper_set_par,
> +	.fb_setcmap	= drm_fb_helper_setcmap,
> +	.fb_mmap	= sdrm_fb_mmap,
> +};
> +
> +static int sdrm_fbdev_create(struct drm_fb_helper *helper,
> +			     struct drm_fb_helper_surface_size *sizes)
> +{
> +	struct sdrm_fbdev *fbdev = to_sdrm_fbdev(helper);
> +	struct drm_device *ddev = helper->dev;
> +	struct sdrm_device *sdrm = ddev->dev_private;
> +	struct drm_mode_fb_cmd2 mode_cmd = {
> +		.width = sdrm->fb_width,
> +		.height = sdrm->fb_height,
> +		.pitches[0] = sdrm->fb_stride,
> +		.pixel_format = sdrm->fb_format,
> +	};
> +	struct sdrm_gem_object *obj;
> +	struct drm_framebuffer *fb;
> +	struct fb_info *fbi;
> +	size_t size;
> +	int ret;
> +
> +	size = PAGE_ALIGN(sdrm->fb_size);
> +	obj = sdrm_gem_alloc_object(ddev, size);
> +	if (!obj)
> +		return -ENOMEM;
> +
> +	ret = sdrm_gem_vmap(obj);
> +	if (ret) {
> +		DRM_ERROR("failed to vmap fb\n");
> +		goto err_gem_free;
> +	}
> +
> +	fbi = drm_fb_helper_alloc_fbi(helper);
> +	if (IS_ERR(fbi)) {
> +		ret = PTR_ERR(fbi);
> +		goto err_gem_free;
> +	}
> +
> +	ret = sdrm_fb_init(ddev, &fbdev->fb, &mode_cmd, obj);
> +	if (ret) {
> +		dev_err(ddev->dev, "Failed to init framebuffer: %d\n", ret);
> +		goto err_fbi_release;
> +	}
> +
> +	fb = &fbdev->fb.base;
> +	helper->fb = fb;
> +	fbi->par = helper;
> +
> +	fbi->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE;
> +	fbi->fbops = &sdrm_fbdev_ops;
> +
> +	drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
> +	drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
> +
> +	strncpy(fbi->fix.id, "simpledrmfb", 15);
> +	fbi->screen_base = obj->vmapping;
> +	fbi->fix.smem_len = sdrm->fb_size;
> +
> +	return 0;
> +
> +err_fbi_release:
> +	drm_fb_helper_release_fbi(helper);
> +
> +err_gem_free:
> +	drm_gem_object_unreference_unlocked(&obj->base);
> +
> +	return ret;
> +}
> +
> +static const struct drm_fb_helper_funcs sdrm_fb_helper_funcs = {
> +	.fb_probe = sdrm_fbdev_create,
> +};
> +
> +void sdrm_fbdev_init(struct sdrm_device *sdrm)
> +{
> +	struct drm_device *ddev = sdrm->ddev;
> +	struct drm_fb_helper *fb_helper;
> +	struct sdrm_fbdev *fbdev;
> +	int ret;
> +
> +	fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
> +	if (!fbdev) {
> +		dev_err(ddev->dev, "Failed to allocate drm fbdev.\n");
> +		return;
> +	}
> +
> +	fb_helper = &fbdev->fb_helper;
> +
> +	drm_fb_helper_prepare(ddev, fb_helper, &sdrm_fb_helper_funcs);
> +
> +	ret = drm_fb_helper_init(ddev, fb_helper, 1, 1);
> +	if (ret < 0) {
> +		dev_err(ddev->dev, "Failed to initialize drm fb helper.\n");
> +		goto err_free;
> +	}
> +
> +	ret = drm_fb_helper_single_add_all_connectors(fb_helper);
> +	if (ret < 0) {
> +		dev_err(ddev->dev, "Failed to add connectors.\n");
> +		goto err_drm_fb_helper_fini;
> +	}
> +
> +	ret = drm_fb_helper_initial_config(fb_helper,
> +					   ddev->mode_config.preferred_depth);
> +	if (ret < 0) {
> +		dev_err(ddev->dev, "Failed to set initial hw configuration.\n");
> +		goto err_drm_fb_helper_fini;
> +	}
> +
> +	if (!fb_helper->fbdev) {
> +		/* fbdev emulation is disabled */
> +		kfree(fbdev);
> +		return;
> +	}
> +
> +	sdrm->fb_helper = fb_helper;
> +
> +	return;
> +
> +err_drm_fb_helper_fini:
> +	drm_fb_helper_fini(fb_helper);
> +err_free:
> +	kfree(fbdev);
> +}
> +
> +void sdrm_fbdev_cleanup(struct sdrm_device *sdrm)
> +{
> +	struct drm_fb_helper *fb_helper = sdrm->fb_helper;
> +	struct sdrm_fbdev *fbdev;
> +
> +	if (!fb_helper)
> +		return;
> +
> +	sdrm->fb_helper = NULL;
> +	fbdev = to_sdrm_fbdev(fb_helper);
> +
> +	drm_fb_helper_unregister_fbi(fb_helper);
> +	cancel_work_sync(&fb_helper->dirty_work);
> +	drm_fb_helper_release_fbi(fb_helper);
> +
> +	drm_framebuffer_unregister_private(fb_helper->fb);
> +	drm_framebuffer_cleanup(fb_helper->fb);
> +	drm_gem_object_unreference_unlocked(&fbdev->fb.obj->base);
> +
> +	drm_fb_helper_fini(fb_helper);
> +	kfree(fbdev);
> +}
> diff --git a/drivers/gpu/drm/simpledrm/simpledrm_kms.c b/drivers/gpu/drm/simpledrm/simpledrm_kms.c
> index e6dc3df..8b98a08 100644
> --- a/drivers/gpu/drm/simpledrm/simpledrm_kms.c
> +++ b/drivers/gpu/drm/simpledrm/simpledrm_kms.c
> @@ -12,6 +12,7 @@
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fb_helper.h>
>  #include <drm/drm_gem.h>
>  #include <drm/drm_simple_kms_helper.h>
>  #include <linux/slab.h>
> @@ -24,6 +25,16 @@ static const uint32_t sdrm_formats[] = {
>  	DRM_FORMAT_XRGB8888,
>  };
> 
> +void sdrm_lastclose(struct drm_device *ddev)
> +{
> +	struct sdrm_device *sdrm = ddev->dev_private;
> +
> +	if (sdrm->fb_helper) {
> +		drm_fb_helper_restore_fbdev_mode_unlocked(sdrm->fb_helper);
> +		drm_fb_helper_set_suspend_lock(sdrm->fb_helper, 0);

David's original fbdev support needed the set_suspend here because without
it fbcon would have trampled all over native kms clients. But with the new
implementation using the fb emulation helpers and dirty callbacks we don't
need that any more I think. I think for consistency with other drivers
it'd be good to remove this flag.

Otherwise this looks good now I think.
-Daniel

> +	}
> +}
> +
>  static int sdrm_conn_get_modes(struct drm_connector *conn)
>  {
>  	struct sdrm_device *sdrm = conn->dev->dev_private;
> @@ -92,6 +103,9 @@ void sdrm_display_pipe_update(struct drm_simple_display_pipe *pipe,
> 
>  	sdrm_crtc_send_vblank_event(&pipe->crtc);
> 
> +	if (sdrm->fb_helper && fb && fb != sdrm->fb_helper->fb)
> +		drm_fb_helper_set_suspend_lock(sdrm->fb_helper, 1);
> +
>  	if (fb) {
>  		pipe->plane.fb = fb;
>  		sdrm_dirty_all_locked(sdrm);
> --
> 2.8.2
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

[toc] | [prev] | [next] | [standalone]


#1468029 — [PATCH v4 1/5] of: Add EXPORT_SYMBOL for of_chosen

FromNoralf Trønnes <noralf@tronnes.org>
Date2016-08-22 22:30 +0200
Subject[PATCH v4 1/5] of: Add EXPORT_SYMBOL for of_chosen
Message-ID<s9414-2Ex-35@gated-at.bofh.it>
In reply to#1468026
Export of_chosen so drivers built as modules can get access to it.
The simpledrm driver will use this and is compatible with
simple-framebuffer which is a subnode of /chosen.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/of/base.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index 7792266..489be01 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -38,6 +38,7 @@ LIST_HEAD(aliases_lookup);
 struct device_node *of_root;
 EXPORT_SYMBOL(of_root);
 struct device_node *of_chosen;
+EXPORT_SYMBOL(of_chosen);
 struct device_node *of_aliases;
 struct device_node *of_stdout;
 static const char *of_stdout_options;
-- 
2.8.2

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web