linux-fbdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Thomas Zimmermann <tzimmermann@suse.de>
To: airlied@linux.ie, daniel@ffwll.ch,
	maarten.lankhorst@linux.intel.com, mripard@kernel.org,
	sean@poorly.run, b.zolnierkie@samsung.com, ajax@redhat.com,
	ville.syrjala@linux.intel.com, malat@debian.org,
	michel@daenzer.net
Cc: gregkh@linuxfoundation.org, linux-fbdev@vger.kernel.org,
	Thomas Zimmermann <tzimmermann@suse.de>,
	dri-devel@lists.freedesktop.org, corbet@lwn.net
Subject: [PATCH v2 10/15] drm/fbconv: Reimplement several fbdev interfaces
Date: Mon, 14 Oct 2019 14:04:11 +0000	[thread overview]
Message-ID: <20191014140416.28517-11-tzimmermann@suse.de> (raw)
In-Reply-To: <20191014140416.28517-1-tzimmermann@suse.de>

This patch reimplements fb_blank(), fb_pan_display(), fb_set_cmap() and
fb_set_var() for fbconv helpers. The goal is to have all calls to driver
callback functions located within fbconv and to reduce the amount of
contained work to a minimum.

Some noteable differences to fbdev include:

  * Code related to fbcon has been left out. Console support is
    emulated by DRM and the drivers don't interact directly with
    it.

  * No events are sent out. As the fbconv helpers are not part of
    the fbdev framework, there are no event listeners anyway.

  * Code related to ioctl and user-space has been left out as
    well. User-space interfaces are provided by DRM.

  * Error messages have been added.

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 drivers/gpu/drm/drm_fbconv_helper.c | 240 +++++++++++++++++++++++++---
 1 file changed, 220 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c
index ca8b43c91266..f7f247e30a3d 100644
--- a/drivers/gpu/drm/drm_fbconv_helper.c
+++ b/drivers/gpu/drm/drm_fbconv_helper.c
@@ -737,6 +737,55 @@ static const struct drm_connector_funcs connector_funcs = {
  * Colormap updates
  */
 
+static int drm_fbconv_set_cmap(struct fb_cmap *cmap, struct fb_info *fb_info)
+{
+	int i, start, res;
+	u16 *red, *green, *blue, *transp;
+	u_int hred, hgreen, hblue, htransp = 0xffff;
+
+	red = cmap->red;
+	green = cmap->green;
+	blue = cmap->blue;
+	transp = cmap->transp;
+	start = cmap->start;
+
+	if (start < 0 || (!fb_info->fbops->fb_setcolreg &&
+			  !fb_info->fbops->fb_setcmap)) {
+		DRM_ERROR("fbconv: Palette not supported.\n");
+		return -EINVAL;
+	}
+
+	if (fb_info->fbops->fb_setcmap) {
+		res = fb_info->fbops->fb_setcmap(cmap, fb_info);
+		if (res) {
+			DRM_ERROR("fbconv: fbops->fb_setcmap() failed: %d\n",
+				  res);
+			return res;
+		}
+	} else {
+		for (i = 0; i < cmap->len; i++) {
+			hred = *red++;
+			hgreen = *green++;
+			hblue = *blue++;
+			if (transp)
+				htransp = *transp++;
+			res = fb_info->fbops->fb_setcolreg(start++,
+							   hred, hgreen, hblue,
+							   htransp, fb_info);
+			if (res) {
+				DRM_ERROR("fbconv: fbops->fb_setcolreg() failed: %d\n",
+					  res);
+				/* cmap handling is a mess; don't err here */
+				break;
+			}
+		}
+	}
+
+	fb_copy_cmap(cmap, &fb_info->cmap);
+
+	return 0;
+}
+
 /* provides a default colormap for palette modes */
 static int create_palette_cmap(struct fb_cmap *cmap,
 			       const struct fb_var_screeninfo *fb_var)
@@ -856,11 +905,9 @@ static int set_cmap(struct fb_info *fb_info)
 	if (ret)
 		return ret;
 
-	ret = fb_set_cmap(&cmap, fb_info);
-	if (ret) {
-		DRM_ERROR("fbconv: fb_set_cmap() failed: %d\n", ret);
+	ret = drm_fbconv_set_cmap(&cmap, fb_info);
+	if (ret)
 		goto err_fb_dealloc_cmap;
-	}
 	fb_dealloc_cmap(&cmap);
 
 	return 0;
@@ -891,7 +938,7 @@ static int drm_fbconv_update_fb_var_screeninfo_from_framebuffer(
 
 	/* Our virtual screen covers all the graphics memory (sans some
 	 * trailing bytes). This allows for setting the scanout buffer's
-	 * address with fb_pan_display().
+	 * address with drm_fbconv_pan_display().
 	 */
 
 	width = fb->pitches[0];
@@ -937,6 +984,165 @@ static int drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe(
 	return 0;
 }
 
+static int drm_fbconv_blank(struct fb_info *fb_info, int blank)
+{
+	int ret = -EINVAL;
+
+	if (fb_info->fbops->fb_blank) {
+		ret = fb_info->fbops->fb_blank(blank, fb_info);
+		if (ret) {
+			DRM_ERROR("fbconv: fbops->fb_blank() failed: %d\n",
+				  ret);
+		}
+	}
+	return ret;
+}
+
+static int drm_fbconv_pan_display(struct fb_info *fb_info,
+				  struct fb_var_screeninfo *var)
+{
+	struct fb_fix_screeninfo *fix = &fb_info->fix;
+	unsigned int yres = fb_info->var.yres;
+	int err;
+
+	if (var->yoffset > 0) {
+		if (var->vmode & FB_VMODE_YWRAP) {
+			if (!fix->ywrapstep ||
+			    (var->yoffset % fix->ywrapstep)) {
+				DRM_ERROR("fbconv: Invalid fix->ywrapstep: %d\n",
+					  fix->ywrapstep);
+				return -EINVAL;
+			}
+			yres = 0;
+		} else if (!fix->ypanstep || (var->yoffset % fix->ypanstep)) {
+			DRM_ERROR("fbconv: Invalid fix->ypanstep: %d\n",
+				  fix->ypanstep);
+			return -EINVAL;
+		}
+	}
+
+	if (var->xoffset > 0) {
+		if (!fix->xpanstep || (var->xoffset % fix->xpanstep)) {
+			DRM_ERROR("fbconv: Invalid fix->xpanstep: %d\n",
+				  fix->xpanstep);
+			return -EINVAL;
+		}
+	}
+
+	if (!fb_info->fbops->fb_pan_display ||
+	    var->yoffset > fb_info->var.yres_virtual - yres ||
+	    var->xoffset > fb_info->var.xres_virtual - fb_info->var.xres) {
+		DRM_ERROR("fbconv: Display panning unsupported\n");
+		return -EINVAL;
+	}
+
+	err = fb_info->fbops->fb_pan_display(var, fb_info);
+	if (err) {
+		DRM_ERROR("fbconv: fbops->pan_display() failed: %d", err);
+		return err;
+	}
+
+	fb_info->var.xoffset = var->xoffset;
+	fb_info->var.yoffset = var->yoffset;
+
+	if (var->vmode & FB_VMODE_YWRAP)
+		fb_info->var.vmode |= FB_VMODE_YWRAP;
+	else
+		fb_info->var.vmode &= ~FB_VMODE_YWRAP;
+
+	return 0;
+}
+
+static int drm_fbconv_set_var(struct fb_info *fb_info,
+			      struct fb_var_screeninfo *var)
+{
+	int ret = 0;
+	u32 activate;
+	struct fb_var_screeninfo old_var;
+	struct fb_videomode mode;
+
+	if (var->activate & FB_ACTIVATE_INV_MODE) {
+		struct fb_videomode mode1, mode2;
+
+		fb_var_to_videomode(&mode1, var);
+		fb_var_to_videomode(&mode2, &fb_info->var);
+		/* make sure we don't delete the videomode of current var */
+		ret = fb_mode_is_equal(&mode1, &mode2);
+		if (ret) {
+			DRM_ERROR("fbconv: fb_mode_is_equal() failed: %d\n",
+				  ret);
+			return -EINVAL;
+		}
+
+		fb_delete_videomode(&mode1, &fb_info->modelist);
+
+		return 0;
+	}
+
+	if (!(var->activate & FB_ACTIVATE_FORCE) &&
+	    !memcmp(&fb_info->var, var, sizeof(*var)))
+		return 0;
+
+	activate = var->activate;
+
+	/* When using FOURCC mode, make sure the red, green, blue and
+	 * transp fields are set to 0.
+	 */
+	if ((fb_info->fix.capabilities & FB_CAP_FOURCC) && var->grayscale > 1) {
+		if (var->red.offset     || var->green.offset    ||
+		    var->blue.offset    || var->transp.offset   ||
+		    var->red.length     || var->green.length    ||
+		    var->blue.length    || var->transp.length   ||
+		    var->red.msb_right  || var->green.msb_right ||
+		    var->blue.msb_right || var->transp.msb_right) {
+			DRM_ERROR("fbconv: Invalid color offsets in FOURCC mode\n");
+			return -EINVAL;
+		}
+	}
+
+	if (!fb_info->fbops->fb_check_var) {
+		*var = fb_info->var;
+		return 0;
+	}
+
+	ret = fb_info->fbops->fb_check_var(var, fb_info);
+	if (ret) {
+		DRM_ERROR("fbconv: fbops->fb_check_var() failed: %d\n", ret);
+		return ret;
+	}
+
+	if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
+		return 0;
+
+	old_var = fb_info->var;
+	fb_info->var = *var;
+
+	if (fb_info->fbops->fb_set_par) {
+		ret = fb_info->fbops->fb_set_par(fb_info);
+		if (ret) {
+			fb_info->var = old_var;
+			DRM_ERROR("fbconv: fbops->fb_set_par() failed: %d\n",
+				  ret);
+			return ret;
+		}
+	}
+
+	drm_fbconv_pan_display(fb_info, &fb_info->var);
+	drm_fbconv_set_cmap(&fb_info->cmap, fb_info);
+	fb_var_to_videomode(&mode, &fb_info->var);
+
+	if (fb_info->modelist.prev && fb_info->modelist.next &&
+	    !list_empty(&fb_info->modelist))
+		ret = fb_add_videomode(&mode, &fb_info->modelist);
+
+	if (ret) {
+		DRM_ERROR("fbconv: fb_add_videomode() failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 /**
  * drm_fbconv_simple_display_pipe_mode_valid - default implementation for
  *	struct drm_simple_display_pipe_funcs.mode_valid
@@ -1105,13 +1311,11 @@ drm_fbconv_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
 
 	fb_var.activate = FB_ACTIVATE_NOW;
 
-	ret = fb_set_var(modeset->fb_info, &fb_var);
-	if (ret) {
-		DRM_ERROR("fbconv: fb_set_var() failed: %d\n", ret);
+	ret = drm_fbconv_set_var(modeset->fb_info, &fb_var);
+	if (ret)
 		return;
-	}
 
-	fb_blank(modeset->fb_info, FB_BLANK_UNBLANK);
+	drm_fbconv_blank(modeset->fb_info, FB_BLANK_UNBLANK);
 
 	drm_fbconv_blit_fullscreen(modeset->blit.screen_base,
 				   modeset->blit.vmap,
@@ -1129,7 +1333,7 @@ drm_fbconv_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe)
 {
 	struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe);
 
-	fb_blank(modeset->fb_info, FB_BLANK_POWERDOWN);
+	drm_fbconv_blank(modeset->fb_info, FB_BLANK_POWERDOWN);
 }
 EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_disable);
 
@@ -1295,7 +1499,7 @@ drm_fbconv_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
 
 	if (!pipe->plane.state->fb) {
 		/* No framebuffer installed; blank display. */
-		fb_blank(modeset->fb_info, FB_BLANK_NORMAL);
+		drm_fbconv_blank(modeset->fb_info, FB_BLANK_NORMAL);
 		return;
 	}
 
@@ -1315,11 +1519,9 @@ drm_fbconv_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
 
 		fb_var.activate = FB_ACTIVATE_NOW;
 
-		ret = fb_set_var(modeset->fb_info, &fb_var);
-		if (ret) {
-			DRM_ERROR("fbconv: fb_set_var() failed: %d\n", ret);
+		ret = drm_fbconv_set_var(modeset->fb_info, &fb_var);
+		if (ret)
 			return;
-		}
 	}
 
 	if (!old_plane_state->fb || /* first-time update */
@@ -1344,11 +1546,9 @@ drm_fbconv_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
 	fb_var.xoffset = 0;
 	fb_var.yoffset = 0;
 
-	ret = fb_pan_display(modeset->fb_info, &fb_var);
-	if (ret) {
-		DRM_ERROR("fbconv: fb_pan_display() failed: %d\n", ret);
+	ret = drm_fbconv_pan_display(modeset->fb_info, &fb_var);
+	if (ret)
 		return;
-	}
 
 	do_blit = drm_atomic_helper_damage_merged(old_plane_state,
 						  pipe->plane.state,
-- 
2.23.0

  parent reply	other threads:[~2019-10-14 14:04 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-14 14:04 [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 01/15] fbdev: Export fb_check_foreignness() Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 02/15] fbdev: Export FBPIXMAPSIZE Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 03/15] drm/simple-kms-helper: Add mode_fixup() to simple display pipe Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 04/15] drm: Add fbconv helper module Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 05/15] drm/fbconv: Add DRM <-> fbdev pixel-format conversion Thomas Zimmermann
2019-10-14 20:30   ` Sam Ravnborg
2019-10-15  5:48     ` Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 06/15] drm/fbconv: Add mode conversion DRM <-> fbdev Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 07/15] drm/fbconv: Add modesetting infrastructure Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 08/15] drm/fbconv: Add plane-state check and update Thomas Zimmermann
2019-10-15  8:30   ` kbuild test robot
2019-10-15 17:28   ` kbuild test robot
2019-10-14 14:04 ` [PATCH v2 09/15] drm/fbconv: Mode-setting pipeline enable / disable Thomas Zimmermann
2022-05-28 20:17   ` Geert Uytterhoeven
2022-05-30  7:47     ` Thomas Zimmermann
2022-05-30  8:34       ` Geert Uytterhoeven
2022-07-01 20:01         ` Geert Uytterhoeven
2019-10-14 14:04 ` Thomas Zimmermann [this message]
2019-10-14 14:04 ` [PATCH v2 11/15] drm/fbconv: Add helpers for init and cleanup of fb_info structures Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 12/15] drm/fbconv: Add helper documentation Thomas Zimmermann
2019-10-15  8:40   ` kbuild test robot
2019-10-14 14:04 ` [PATCH v2 13/15] staging: Add mgakms driver Thomas Zimmermann
2019-10-14 14:04 ` [PATCH v2 15/15] staging/mgakms: Update matroxfb driver code for DRM Thomas Zimmermann
2019-10-17 16:19   ` kbuild test robot
2019-10-14 20:36 ` [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers Sam Ravnborg
2019-10-15  6:11   ` Thomas Zimmermann
     [not found] ` <20191014140416.28517-15-tzimmermann@suse.de>
2019-10-15 11:48   ` [PATCH v2 14/15] staging/mgakms: Import matroxfb driver source code Ville Syrjälä
2019-10-15 12:46     ` Thomas Zimmermann
2019-10-15 14:33 ` [PATCH v2 00/15] DRM fbconv helpers for converting fbdev drivers Daniel Vetter
2019-10-15 17:28   ` Thomas Zimmermann
2019-10-15 17:48     ` Daniel Vetter
2019-10-15 18:05       ` Greg KH
2019-10-15 18:13       ` Ville Syrjälä
2019-10-15 18:28         ` Ville Syrjälä

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=20191014140416.28517-11-tzimmermann@suse.de \
    --to=tzimmermann@suse.de \
    --cc=airlied@linux.ie \
    --cc=ajax@redhat.com \
    --cc=b.zolnierkie@samsung.com \
    --cc=corbet@lwn.net \
    --cc=daniel@ffwll.ch \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-fbdev@vger.kernel.org \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=malat@debian.org \
    --cc=michel@daenzer.net \
    --cc=mripard@kernel.org \
    --cc=sean@poorly.run \
    --cc=ville.syrjala@linux.intel.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).