From: "Noralf Trønnes" <noralf@tronnes.org>
To: dri-devel@lists.freedesktop.org
Cc: intel-gfx@lists.freedesktop.org,
"Noralf Trønnes" <noralf@tronnes.org>,
laurent.pinchart@ideasonboard.com
Subject: [PATCH v2 05/12] drm/fb-helper: Add generic fbdev emulation .fb_probe function
Date: Mon, 18 Jun 2018 16:17:32 +0200 [thread overview]
Message-ID: <20180618141739.48151-6-noralf@tronnes.org> (raw)
In-Reply-To: <20180618141739.48151-1-noralf@tronnes.org>
This is the first step in getting generic fbdev emulation.
A drm_fb_helper_funcs.fb_probe function is added which uses the
DRM client API to get a framebuffer backed by a dumb buffer.
A transitional hack for tinydrm is needed in order to switch over all
CMA helper drivers in a later patch. This hack will be removed when
tinydrm moves to vmalloc buffers.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
Changes since version 1:
- Embed drm_client at the beginning of drm_fb_helper to avoid a fragile
transitional kfree hack in drm_client_release()
- Set owner in drm_fbdev_fb_ops
- Add kerneldoc to drm_fb_helper_generic_probe()
drivers/gpu/drm/drm_fb_helper.c | 209 +++++++++++++++++++++++++++++++++++++++-
include/drm/drm_fb_helper.h | 31 ++++++
2 files changed, 239 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 2ee1eaa66188..be6bab889f1b 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -30,6 +30,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/console.h>
+#include <linux/dma-buf.h>
#include <linux/kernel.h>
#include <linux/sysrq.h>
#include <linux/slab.h>
@@ -745,6 +746,24 @@ static void drm_fb_helper_resume_worker(struct work_struct *work)
console_unlock();
}
+static void drm_fb_helper_dirty_blit_real(struct drm_fb_helper *fb_helper,
+ struct drm_clip_rect *clip)
+{
+ struct drm_framebuffer *fb = fb_helper->fb;
+ unsigned int cpp = drm_format_plane_cpp(fb->format->format, 0);
+ size_t offset = clip->y1 * fb->pitches[0] + clip->x1 * cpp;
+ void *src = fb_helper->fbdev->screen_buffer + offset;
+ void *dst = fb_helper->buffer->vaddr + offset;
+ size_t len = (clip->x2 - clip->x1) * cpp;
+ unsigned int y;
+
+ for (y = clip->y1; y < clip->y2; y++) {
+ memcpy(dst, src, len);
+ src += fb->pitches[0];
+ dst += fb->pitches[0];
+ }
+}
+
static void drm_fb_helper_dirty_work(struct work_struct *work)
{
struct drm_fb_helper *helper = container_of(work, struct drm_fb_helper,
@@ -760,8 +779,11 @@ static void drm_fb_helper_dirty_work(struct work_struct *work)
spin_unlock_irqrestore(&helper->dirty_lock, flags);
/* call dirty callback only when it has been really touched */
- if (clip_copy.x1 < clip_copy.x2 && clip_copy.y1 < clip_copy.y2)
+ if (clip_copy.x1 < clip_copy.x2 && clip_copy.y1 < clip_copy.y2) {
+ if (helper->buffer) /* Generic fbdev uses a shadow buffer */
+ drm_fb_helper_dirty_blit_real(helper, &clip_copy);
helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, &clip_copy, 1);
+ }
}
/**
@@ -2928,6 +2950,191 @@ void drm_fb_helper_output_poll_changed(struct drm_device *dev)
}
EXPORT_SYMBOL(drm_fb_helper_output_poll_changed);
+/* @user: 1=userspace, 0=fbcon */
+static int drm_fbdev_fb_open(struct fb_info *info, int user)
+{
+ struct drm_fb_helper *fb_helper = info->par;
+
+ if (!try_module_get(fb_helper->dev->driver->fops->owner))
+ return -ENODEV;
+
+ return 0;
+}
+
+static int drm_fbdev_fb_release(struct fb_info *info, int user)
+{
+ struct drm_fb_helper *fb_helper = info->par;
+
+ module_put(fb_helper->dev->driver->fops->owner);
+
+ return 0;
+}
+
+/*
+ * FIXME:
+ * Merge this into drm_fbdev_generic_client_release() when all CMA drivers have
+ * been moved over to using drm_fbdev_generic_setup().
+ */
+static void drm_fbdev_generic_client_release_do(struct drm_client_dev *client)
+{
+ struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
+ struct fb_info *fbi = fb_helper->fbdev;
+ bool defio = fbi->fbdefio;
+ struct fb_ops *fbops;
+ void *shadow;
+
+ if (defio) {
+ fb_deferred_io_cleanup(fbi);
+ fbops = fbi->fbops;
+ shadow = fbi->screen_buffer;
+ }
+
+ drm_fb_helper_fini(fb_helper);
+
+ if (defio) {
+ kfree(fbops);
+ vfree(shadow);
+ }
+
+ drm_client_framebuffer_delete(fb_helper->buffer);
+}
+
+/*
+ * fb_ops.fb_destroy is called by the last put_fb_info() call at the end of
+ * unregister_framebuffer() or fb_release().
+ */
+static void drm_fbdev_fb_destroy(struct fb_info *info)
+{
+ struct drm_fb_helper *fb_helper = info->par;
+
+ /*
+ * FIXME:
+ * Remove this when all CMA drivers have been moved over to using
+ * drm_fbdev_generic_setup().
+ */
+ drm_fbdev_generic_client_release_do(&fb_helper->client);
+
+ drm_client_put(&fb_helper->client);
+}
+
+static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ struct drm_fb_helper *fb_helper = info->par;
+
+ if (fb_helper->dev->driver->gem_prime_mmap)
+ return fb_helper->dev->driver->gem_prime_mmap(fb_helper->buffer->gem, vma);
+ else
+ return -ENODEV;
+}
+
+static struct fb_ops drm_fbdev_fb_ops = {
+ .owner = THIS_MODULE,
+ DRM_FB_HELPER_DEFAULT_OPS,
+ .fb_open = drm_fbdev_fb_open,
+ .fb_release = drm_fbdev_fb_release,
+ .fb_destroy = drm_fbdev_fb_destroy,
+ .fb_mmap = drm_fbdev_fb_mmap,
+ .fb_read = drm_fb_helper_sys_read,
+ .fb_write = drm_fb_helper_sys_write,
+ .fb_fillrect = drm_fb_helper_sys_fillrect,
+ .fb_copyarea = drm_fb_helper_sys_copyarea,
+ .fb_imageblit = drm_fb_helper_sys_imageblit,
+};
+
+static struct fb_deferred_io drm_fbdev_defio = {
+ .delay = HZ / 20,
+ .deferred_io = drm_fb_helper_deferred_io,
+};
+
+/**
+ * drm_fb_helper_generic_probe - Generic fbdev emulation probe helper
+ * @fb_helper: fbdev helper structure
+ * @sizes: describes fbdev size and scanout surface size
+ *
+ * This function uses the client API to crate a framebuffer backed by a dumb buffer.
+ *
+ * The _sys_ versions are used for &fb_ops.fb_read, fb_write, fb_fillrect,
+ * fb_copyarea, fb_imageblit.
+ *
+ * Returns:
+ * Zero on success or negative error code on failure.
+ */
+int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
+ struct drm_fb_helper_surface_size *sizes)
+{
+ struct drm_client_dev *client = &fb_helper->client;
+ struct drm_client_buffer *buffer;
+ struct drm_framebuffer *fb;
+ struct fb_info *fbi;
+ u32 format;
+ int ret;
+
+ DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n",
+ sizes->surface_width, sizes->surface_height,
+ sizes->surface_bpp);
+
+ format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth);
+ buffer = drm_client_framebuffer_create(client, sizes->surface_width,
+ sizes->surface_height, format);
+ if (IS_ERR(buffer))
+ return PTR_ERR(buffer);
+
+ fb_helper->buffer = buffer;
+ fb_helper->fb = buffer->fb;
+ fb = buffer->fb;
+
+ fbi = drm_fb_helper_alloc_fbi(fb_helper);
+ if (IS_ERR(fbi)) {
+ ret = PTR_ERR(fbi);
+ goto err_free_buffer;
+ }
+
+ fbi->par = fb_helper;
+ fbi->fbops = &drm_fbdev_fb_ops;
+ fbi->screen_size = fb->height * fb->pitches[0];
+ fbi->fix.smem_len = fbi->screen_size;
+ fbi->screen_buffer = buffer->vaddr;
+ strcpy(fbi->fix.id, "DRM emulated");
+
+ drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->format->depth);
+ drm_fb_helper_fill_var(fbi, fb_helper, sizes->fb_width, sizes->fb_height);
+
+ if (fb->funcs->dirty) {
+ struct fb_ops *fbops;
+ void *shadow;
+
+ /*
+ * fb_deferred_io_cleanup() clears &fbops->fb_mmap so a per
+ * instance version is necessary.
+ */
+ fbops = kzalloc(sizeof(*fbops), GFP_KERNEL);
+ shadow = vzalloc(fbi->screen_size);
+ if (!fbops || !shadow) {
+ kfree(fbops);
+ vfree(shadow);
+ ret = -ENOMEM;
+ goto err_fb_info_destroy;
+ }
+
+ *fbops = *fbi->fbops;
+ fbi->fbops = fbops;
+ fbi->screen_buffer = shadow;
+ fbi->fbdefio = &drm_fbdev_defio;
+
+ fb_deferred_io_init(fbi);
+ }
+
+ return 0;
+
+err_fb_info_destroy:
+ drm_fb_helper_fini(fb_helper);
+err_free_buffer:
+ drm_client_framebuffer_delete(buffer);
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_fb_helper_generic_probe);
+
/* The Kconfig DRM_KMS_HELPER selects FRAMEBUFFER_CONSOLE (if !EXPERT)
* but the module doesn't depend on any fb console symbols. At least
* attempt to load fbcon to avoid leaving the system without a usable console.
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index b069433e7fc1..c134bbcfd2e9 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -32,6 +32,7 @@
struct drm_fb_helper;
+#include <drm/drm_client.h>
#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
#include <linux/kgdb.h>
@@ -154,6 +155,20 @@ struct drm_fb_helper_connector {
* operations.
*/
struct drm_fb_helper {
+ /**
+ * @client:
+ *
+ * DRM client used by the generic fbdev emulation.
+ */
+ struct drm_client_dev client;
+
+ /**
+ * @buffer:
+ *
+ * Framebuffer used by the generic fbdev emulation.
+ */
+ struct drm_client_buffer *buffer;
+
struct drm_framebuffer *fb;
struct drm_device *dev;
int crtc_count;
@@ -234,6 +249,12 @@ struct drm_fb_helper {
int preferred_bpp;
};
+static inline struct drm_fb_helper *
+drm_fb_helper_from_client(struct drm_client_dev *client)
+{
+ return container_of(client, struct drm_fb_helper, client);
+}
+
/**
* define DRM_FB_HELPER_DEFAULT_OPS - helper define for drm drivers
*
@@ -330,6 +351,9 @@ void drm_fb_helper_fbdev_teardown(struct drm_device *dev);
void drm_fb_helper_lastclose(struct drm_device *dev);
void drm_fb_helper_output_poll_changed(struct drm_device *dev);
+
+int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
+ struct drm_fb_helper_surface_size *sizes);
#else
static inline void drm_fb_helper_prepare(struct drm_device *dev,
struct drm_fb_helper *helper,
@@ -564,6 +588,13 @@ static inline void drm_fb_helper_output_poll_changed(struct drm_device *dev)
{
}
+static inline int
+drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
+ struct drm_fb_helper_surface_size *sizes)
+{
+ return 0;
+}
+
#endif
static inline int
--
2.15.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
next prev parent reply other threads:[~2018-06-18 14:17 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-06-18 14:17 [PATCH v2 00/12] drm: Add generic fbdev emulation Noralf Trønnes
2018-06-18 14:17 ` [PATCH v2 01/12] drm: provide management functions for drm_file Noralf Trønnes
2018-06-18 14:17 ` [PATCH v2 02/12] drm/file: Don't set master on in-kernel clients Noralf Trønnes
2018-06-18 14:17 ` [PATCH v2 03/12] drm: Make ioctls available for " Noralf Trønnes
2018-06-18 14:17 ` [PATCH v2 04/12] drm: Begin an API " Noralf Trønnes
2018-06-18 14:17 ` Noralf Trønnes [this message]
2018-06-18 14:17 ` [PATCH v2 06/12] drm/pl111: Set .gem_prime_vmap and .gem_prime_mmap Noralf Trønnes
2018-06-18 14:17 ` [PATCH v2 07/12] drm/cma-helper: Use the generic fbdev emulation Noralf Trønnes
2018-06-18 14:17 ` [PATCH v2 08/12] drm/client: Add client callbacks Noralf Trønnes
2018-06-18 14:17 ` [PATCH v2 09/12] drm/debugfs: Add internal client debugfs file Noralf Trønnes
2018-06-20 9:23 ` [Intel-gfx] " Daniel Vetter
2018-06-18 14:17 ` [PATCH v2 10/12] drm/fb-helper: Finish the generic fbdev emulation Noralf Trønnes
2018-06-18 14:17 ` [PATCH v2 11/12] drm/tinydrm: Use drm_fbdev_generic_setup() Noralf Trønnes
2018-06-18 14:17 ` [PATCH v2 12/12] drm/cma-helper: Remove drm_fb_cma_fbdev_init_with_funcs() Noralf Trønnes
2018-06-18 15:05 ` ✗ Fi.CI.CHECKPATCH: warning for drm: Add generic fbdev emulation Patchwork
2018-06-18 15:09 ` ✗ Fi.CI.SPARSE: " Patchwork
2018-06-18 15:20 ` ✓ Fi.CI.BAT: success " Patchwork
2018-06-18 20:02 ` ✓ Fi.CI.IGT: " Patchwork
2018-06-20 9:34 ` [PATCH v2 00/12] " Daniel Vetter
2018-06-20 13:52 ` [Intel-gfx] " Noralf Trønnes
2018-06-20 15:28 ` Noralf Trønnes
2018-06-21 7:14 ` Daniel Vetter
2018-06-21 17:19 ` Noralf Trønnes
2018-06-26 13:41 ` [Intel-gfx] " Noralf Trønnes
2018-06-26 13:42 ` Daniel Vetter
2018-06-25 14:28 ` Noralf Trønnes
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180618141739.48151-6-noralf@tronnes.org \
--to=noralf@tronnes.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=intel-gfx@lists.freedesktop.org \
--cc=laurent.pinchart@ideasonboard.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.