From patchwork Mon Oct 14 14:04:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 11188767 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id F136017E6 for ; Mon, 14 Oct 2019 14:04:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D246821721 for ; Mon, 14 Oct 2019 14:04:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732398AbfJNOEW (ORCPT ); Mon, 14 Oct 2019 10:04:22 -0400 Received: from mx2.suse.de ([195.135.220.15]:50720 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1732349AbfJNOEW (ORCPT ); Mon, 14 Oct 2019 10:04:22 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 766B4AF92; Mon, 14 Oct 2019 14:04:20 +0000 (UTC) From: Thomas Zimmermann 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: corbet@lwn.net, gregkh@linuxfoundation.org, dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH v2 01/15] fbdev: Export fb_check_foreignness() Date: Mon, 14 Oct 2019 16:04:02 +0200 Message-Id: <20191014140416.28517-2-tzimmermann@suse.de> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191014140416.28517-1-tzimmermann@suse.de> References: <20191014140416.28517-1-tzimmermann@suse.de> MIME-Version: 1.0 Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org This function is required by DRM's fbdev conversion helpers. Export it from the module. Signed-off-by: Thomas Zimmermann --- drivers/video/fbdev/core/fbmem.c | 3 ++- include/linux/fb.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 95c32952fa8a..e828fcccce40 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1481,7 +1481,7 @@ static const struct file_operations fb_fops = { struct class *fb_class; EXPORT_SYMBOL(fb_class); -static int fb_check_foreignness(struct fb_info *fi) +int fb_check_foreignness(struct fb_info *fi) { const bool foreign_endian = fi->flags & FBINFO_FOREIGN_ENDIAN; @@ -1505,6 +1505,7 @@ static int fb_check_foreignness(struct fb_info *fi) return 0; } +EXPORT_SYMBOL(fb_check_foreignness); static bool apertures_overlap(struct aperture *gen, struct aperture *hw) { diff --git a/include/linux/fb.h b/include/linux/fb.h index 41e0069eca0a..372f1f6ae42e 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -622,6 +622,7 @@ extern int fb_get_color_depth(struct fb_var_screeninfo *var, struct fb_fix_screeninfo *fix); extern int fb_get_options(const char *name, char **option); extern int fb_new_modelist(struct fb_info *info); +extern int fb_check_foreignness(struct fb_info *fi); extern struct fb_info *registered_fb[FB_MAX]; extern int num_registered_fb; From patchwork Mon Oct 14 14:04:03 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 11188769 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2231B18B8 for ; Mon, 14 Oct 2019 14:04:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 045CD21721 for ; Mon, 14 Oct 2019 14:04:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732349AbfJNOEW (ORCPT ); Mon, 14 Oct 2019 10:04:22 -0400 Received: from mx2.suse.de ([195.135.220.15]:50716 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1732370AbfJNOEW (ORCPT ); Mon, 14 Oct 2019 10:04:22 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 76F9AAFE8; Mon, 14 Oct 2019 14:04:20 +0000 (UTC) From: Thomas Zimmermann 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: corbet@lwn.net, gregkh@linuxfoundation.org, dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH v2 02/15] fbdev: Export FBPIXMAPSIZE Date: Mon, 14 Oct 2019 16:04:03 +0200 Message-Id: <20191014140416.28517-3-tzimmermann@suse.de> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191014140416.28517-1-tzimmermann@suse.de> References: <20191014140416.28517-1-tzimmermann@suse.de> MIME-Version: 1.0 Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org This constant is required by DRM's fbdev conversion helpers. Define it in fbdev's public header file. Signed-off-by: Thomas Zimmermann --- drivers/video/fbdev/core/fbmem.c | 2 -- include/linux/fb.h | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index e828fcccce40..f02377e959dc 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -43,8 +43,6 @@ * Frame buffer device initialization and setup routines */ -#define FBPIXMAPSIZE (1024 * 8) - static DEFINE_MUTEX(registration_lock); struct fb_info *registered_fb[FB_MAX] __read_mostly; diff --git a/include/linux/fb.h b/include/linux/fb.h index 372f1f6ae42e..e17d3e1d86ad 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -199,6 +199,8 @@ struct fb_pixmap { void (*readio) (struct fb_info *info, void *dst, void __iomem *src, unsigned int size); }; +#define FBPIXMAPSIZE (1024 * 8) + #ifdef CONFIG_FB_DEFERRED_IO struct fb_deferred_io { /* delay between mkwrite and deferred handler */ From patchwork Mon Oct 14 14:04:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 11188773 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B44D329B1 for ; Mon, 14 Oct 2019 14:04:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9FFB721721 for ; Mon, 14 Oct 2019 14:04:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732437AbfJNOEX (ORCPT ); Mon, 14 Oct 2019 10:04:23 -0400 Received: from mx2.suse.de ([195.135.220.15]:50722 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1732339AbfJNOEX (ORCPT ); Mon, 14 Oct 2019 10:04:23 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 83FCEB112; Mon, 14 Oct 2019 14:04:20 +0000 (UTC) From: Thomas Zimmermann 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: corbet@lwn.net, gregkh@linuxfoundation.org, dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH v2 03/15] drm/simple-kms-helper: Add mode_fixup() to simple display pipe Date: Mon, 14 Oct 2019 16:04:04 +0200 Message-Id: <20191014140416.28517-4-tzimmermann@suse.de> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191014140416.28517-1-tzimmermann@suse.de> References: <20191014140416.28517-1-tzimmermann@suse.de> MIME-Version: 1.0 Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org The mode fix-up function for simple display helpers is equivalent to the regular pipeline's CRTC mode fix-up function. It's called to adjust the CRTC's display mode for the encoder. Add this function for DRM fbconv helpers. Signed-off-by: Thomas Zimmermann --- drivers/gpu/drm/drm_simple_kms_helper.c | 15 +++++++++ include/drm/drm_simple_kms_helper.h | 43 +++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c index 046055719245..acd9b79bf92a 100644 --- a/drivers/gpu/drm/drm_simple_kms_helper.c +++ b/drivers/gpu/drm/drm_simple_kms_helper.c @@ -46,6 +46,20 @@ drm_simple_kms_crtc_mode_valid(struct drm_crtc *crtc, return pipe->funcs->mode_valid(crtc, mode); } +static bool +drm_simple_kms_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_simple_display_pipe *pipe; + + pipe = container_of(crtc, struct drm_simple_display_pipe, crtc); + if (!pipe->funcs || !pipe->funcs->mode_fixup) + return true; + + return pipe->funcs->mode_fixup(crtc, mode, adjusted_mode); +} + static int drm_simple_kms_crtc_check(struct drm_crtc *crtc, struct drm_crtc_state *state) { @@ -87,6 +101,7 @@ static void drm_simple_kms_crtc_disable(struct drm_crtc *crtc, static const struct drm_crtc_helper_funcs drm_simple_kms_crtc_helper_funcs = { .mode_valid = drm_simple_kms_crtc_mode_valid, + .mode_fixup = drm_simple_kms_crtc_mode_fixup, .atomic_check = drm_simple_kms_crtc_check, .atomic_enable = drm_simple_kms_crtc_enable, .atomic_disable = drm_simple_kms_crtc_disable, diff --git a/include/drm/drm_simple_kms_helper.h b/include/drm/drm_simple_kms_helper.h index 4d89cd0a60db..1b975ab67144 100644 --- a/include/drm/drm_simple_kms_helper.h +++ b/include/drm/drm_simple_kms_helper.h @@ -52,6 +52,49 @@ struct drm_simple_display_pipe_funcs { enum drm_mode_status (*mode_valid)(struct drm_crtc *crtc, const struct drm_display_mode *mode); + /** + * @mode_fixup: + * + * This callback is used to validate a mode. The parameter mode is the + * display mode that userspace requested, adjusted_mode is the mode the + * encoders need to be fed with. Note that this is the inverse semantics + * of the meaning for the &drm_encoder and &drm_bridge_funcs.mode_fixup + * vfunc. If the CRTC of the simple display pipe cannot support the + * requested conversion from mode to adjusted_mode it should reject the + * modeset. + * + * This function is optional. + * + * NOTE: + * + * This function is called in the check phase of atomic modesets, which + * can be aborted for any reason (including on userspace's request to + * just check whether a configuration would be possible). Atomic drivers + * MUST NOT touch any persistent state (hardware or software) or data + * structures except the passed in adjusted_mode parameter. + * + * Atomic drivers which need to inspect and adjust more state should + * instead use the @atomic_check callback, but note that they're not + * perfectly equivalent: @mode_valid is called from + * drm_atomic_helper_check_modeset(), but @atomic_check is called from + * drm_atomic_helper_check_planes(), because originally it was meant for + * plane update checks only. + * + * Also beware that userspace can request its own custom modes, neither + * core nor helpers filter modes to the list of probe modes reported by + * the GETCONNECTOR IOCTL and stored in &drm_connector.modes. To ensure + * that modes are filtered consistently put any CRTC constraints and + * limits checks into @mode_valid. + * + * RETURNS: + * + * True if an acceptable configuration is possible, false if the modeset + * operation should be rejected. + */ + bool (*mode_fixup)(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + /** * @enable: * From patchwork Mon Oct 14 14:04:05 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 11188771 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 48BD618A6 for ; Mon, 14 Oct 2019 14:04:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2AA2D21721 for ; Mon, 14 Oct 2019 14:04:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732370AbfJNOEW (ORCPT ); Mon, 14 Oct 2019 10:04:22 -0400 Received: from mx2.suse.de ([195.135.220.15]:50760 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1732389AbfJNOEW (ORCPT ); Mon, 14 Oct 2019 10:04:22 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 08B0FB12D; Mon, 14 Oct 2019 14:04:21 +0000 (UTC) From: Thomas Zimmermann 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: corbet@lwn.net, gregkh@linuxfoundation.org, dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH v2 04/15] drm: Add fbconv helper module Date: Mon, 14 Oct 2019 16:04:05 +0200 Message-Id: <20191014140416.28517-5-tzimmermann@suse.de> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191014140416.28517-1-tzimmermann@suse.de> References: <20191014140416.28517-1-tzimmermann@suse.de> MIME-Version: 1.0 Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org This adds fbconv helpers for DRM to the build infrastructure. The configuration symbol is DRM_FBCONV_HELPERS. Drivers should select it if they wish to use fbconv. Signed-off-by: Thomas Zimmermann --- drivers/gpu/drm/Kconfig | 10 ++++++++++ drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/drm_fbconv_helper.c | 1 + 3 files changed, 12 insertions(+) create mode 100644 drivers/gpu/drm/drm_fbconv_helper.c diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 9591bd720e56..ed689201ec81 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -157,6 +157,16 @@ config DRM_DP_CEC Note: not all adapters support this feature, and even for those that do support this they often do not hook up the CEC pin. +config DRM_FBCONV_HELPER + tristate "Enable fbdev conversion helpers" + depends on DRM + help + Provides helpers for running DRM on top of fbdev drivers. Choose + this option if you're converting an fbdev driver to DRM. The + helpers provide conversion functions for fbdev data structures + and allow to build a basic DRM driver on top of the fbdev + interfaces. + config DRM_TTM tristate depends on DRM && MMU diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 9f1c7c486f88..a7178245d938 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -52,6 +52,7 @@ drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o drm_kms_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o +drm_kms_helper-$(CONFIG_DRM_FBCONV_HELPER) += drm_fbconv_helper.o obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/ diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c new file mode 100644 index 000000000000..0cb46d2c98c3 --- /dev/null +++ b/drivers/gpu/drm/drm_fbconv_helper.c @@ -0,0 +1 @@ +// SPDX-License-Identifier: GPL-2.0-or-later From patchwork Mon Oct 14 14:04:06 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 11188783 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4C07217E6 for ; Mon, 14 Oct 2019 14:04:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 37AFC21882 for ; Mon, 14 Oct 2019 14:04:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732435AbfJNOEZ (ORCPT ); Mon, 14 Oct 2019 10:04:25 -0400 Received: from mx2.suse.de ([195.135.220.15]:50860 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1732434AbfJNOEZ (ORCPT ); Mon, 14 Oct 2019 10:04:25 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 772C6B17A; Mon, 14 Oct 2019 14:04:21 +0000 (UTC) From: Thomas Zimmermann 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: corbet@lwn.net, gregkh@linuxfoundation.org, dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH v2 05/15] drm/fbconv: Add DRM <-> fbdev pixel-format conversion Date: Mon, 14 Oct 2019 16:04:06 +0200 Message-Id: <20191014140416.28517-6-tzimmermann@suse.de> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191014140416.28517-1-tzimmermann@suse.de> References: <20191014140416.28517-1-tzimmermann@suse.de> MIME-Version: 1.0 Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org DRM uses FOURCC constants to describe pixel formats, fbdev uses a per-component bitfield structure. The functions in this patch convert between the two. Signed-off-by: Thomas Zimmermann Acked-by: Sam Ravnborg --- drivers/gpu/drm/drm_fbconv_helper.c | 435 ++++++++++++++++++++++++++++ include/drm/drm_fbconv_helper.h | 23 ++ 2 files changed, 458 insertions(+) create mode 100644 include/drm/drm_fbconv_helper.h diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c index 0cb46d2c98c3..af45358a156a 100644 --- a/drivers/gpu/drm/drm_fbconv_helper.c +++ b/drivers/gpu/drm/drm_fbconv_helper.c @@ -1 +1,436 @@ // SPDX-License-Identifier: GPL-2.0-or-later + +#include + +#include + +#include + +/* + * Format conversion helpers + */ + +static bool is_c8(const struct fb_var_screeninfo *fb_var) +{ + return fb_var->bits_per_pixel == 8; +} + +static bool is_rgb565(const struct fb_var_screeninfo *fb_var) +{ + return (fb_var->bits_per_pixel == 16) && + (fb_var->red.offset == 11) && + (fb_var->red.length == 5) && + (fb_var->green.offset == 5) && + (fb_var->green.length == 6) && + (fb_var->blue.offset == 0) && + (fb_var->blue.length == 5); +} + +static bool is_bgr565(const struct fb_var_screeninfo *fb_var) +{ + return (fb_var->bits_per_pixel == 16) && + (fb_var->red.offset == 0) && + (fb_var->red.length == 5) && + (fb_var->green.offset == 5) && + (fb_var->green.length == 6) && + (fb_var->blue.offset == 11) && + (fb_var->blue.length == 5); +} + +static bool is_rgb888(const struct fb_var_screeninfo *fb_var) +{ + return (fb_var->bits_per_pixel == 24) && + (fb_var->red.offset == 16) && + (fb_var->red.length == 8) && + (fb_var->green.offset == 8) && + (fb_var->green.length == 8) && + (fb_var->blue.offset == 0) && + (fb_var->blue.length == 8); +} + +static bool is_bgr888(const struct fb_var_screeninfo *fb_var) +{ + return (fb_var->bits_per_pixel == 24) && + (fb_var->red.offset == 0) && + (fb_var->red.length == 8) && + (fb_var->green.offset == 8) && + (fb_var->green.length == 8) && + (fb_var->blue.offset == 16) && + (fb_var->blue.length == 8); +} + +static bool is_xrgb8888(const struct fb_var_screeninfo *fb_var) +{ + return (fb_var->bits_per_pixel == 32) && + (fb_var->red.offset == 16) && + (fb_var->red.length == 8) && + (fb_var->green.offset == 8) && + (fb_var->green.length == 8) && + (fb_var->blue.offset == 0) && + (fb_var->blue.length == 8) && + (fb_var->transp.length == 0); +} + +static bool is_xbgr8888(const struct fb_var_screeninfo *fb_var) +{ + return (fb_var->bits_per_pixel == 32) && + (fb_var->red.offset == 0) && + (fb_var->red.length == 8) && + (fb_var->green.offset == 8) && + (fb_var->green.length == 8) && + (fb_var->blue.offset == 16) && + (fb_var->blue.length == 8) && + (fb_var->transp.length == 0); +} + +static bool is_rgbx8888(const struct fb_var_screeninfo *fb_var) +{ + return (fb_var->bits_per_pixel == 32) && + (fb_var->red.offset == 24) && + (fb_var->red.length == 8) && + (fb_var->green.offset == 16) && + (fb_var->green.length == 8) && + (fb_var->blue.offset == 8) && + (fb_var->blue.length == 8) && + (fb_var->transp.length == 0); +} + +static bool is_bgrx8888(const struct fb_var_screeninfo *fb_var) +{ + return (fb_var->bits_per_pixel == 32) && + (fb_var->red.offset == 8) && + (fb_var->red.length == 8) && + (fb_var->green.offset == 16) && + (fb_var->green.length == 8) && + (fb_var->blue.offset == 24) && + (fb_var->blue.length == 8) && + (fb_var->transp.length == 0); +} + +static bool is_argb8888(const struct fb_var_screeninfo *fb_var) +{ + return (fb_var->bits_per_pixel == 32) && + (fb_var->red.offset == 16) && + (fb_var->red.length == 8) && + (fb_var->green.offset == 8) && + (fb_var->green.length == 8) && + (fb_var->blue.offset == 0) && + (fb_var->blue.length == 8) && + (fb_var->transp.offset == 24) && + (fb_var->transp.length == 8); +} + +static bool is_abgr8888(const struct fb_var_screeninfo *fb_var) +{ + return (fb_var->bits_per_pixel == 32) && + (fb_var->red.offset == 0) && + (fb_var->red.length == 8) && + (fb_var->green.offset == 8) && + (fb_var->green.length == 8) && + (fb_var->blue.offset == 16) && + (fb_var->blue.length == 8) && + (fb_var->transp.offset == 24) && + (fb_var->transp.length == 8); +} + +static bool is_rgba8888(const struct fb_var_screeninfo *fb_var) +{ + return (fb_var->bits_per_pixel == 32) && + (fb_var->red.offset == 24) && + (fb_var->red.length == 8) && + (fb_var->green.offset == 16) && + (fb_var->green.length == 8) && + (fb_var->blue.offset == 8) && + (fb_var->blue.length == 8) && + (fb_var->transp.offset == 0) && + (fb_var->transp.length == 8); +} + +static bool is_bgra8888(const struct fb_var_screeninfo *fb_var) +{ + return (fb_var->bits_per_pixel == 32) && + (fb_var->red.offset == 8) && + (fb_var->red.length == 8) && + (fb_var->green.offset == 16) && + (fb_var->green.length == 8) && + (fb_var->blue.offset == 24) && + (fb_var->blue.length == 8) && + (fb_var->transp.offset == 0) && + (fb_var->transp.length == 8); +} + +struct format_map { + bool (*is_format)(const struct fb_var_screeninfo *fb_var); + uint32_t format; +}; + +/** + * drm_fbconv_format_of_fb_var_screeninfo - Returns a DRM_FORMAT constant + * from an fb_var_screeninfo structure + * @fb_info: the fb_var_screeninfo structure + * Returns: + * A DRM_FORMAT constant on success, or + * DRM_FORMAT_INVALID otherwise. + */ +uint32_t +drm_fbconv_format_of_fb_var_screeninfo(const struct fb_var_screeninfo *fb_var) +{ + static const struct format_map map[] = { + { is_c8, DRM_FORMAT_C8 }, /* 256-color palette */ + { is_rgb565, DRM_FORMAT_RGB565 }, + { is_bgr565, DRM_FORMAT_BGR565 }, + { is_rgb888, DRM_FORMAT_RGB888 }, + { is_bgr888, DRM_FORMAT_BGR888 }, + { is_xrgb8888, DRM_FORMAT_XRGB8888 }, + { is_xbgr8888, DRM_FORMAT_XBGR8888 }, + { is_rgbx8888, DRM_FORMAT_RGBX8888 }, + { is_bgrx8888, DRM_FORMAT_BGRX8888 }, + { is_argb8888, DRM_FORMAT_ARGB8888 }, + { is_abgr8888, DRM_FORMAT_ABGR8888 }, + { is_rgba8888, DRM_FORMAT_RGBA8888 }, + { is_bgra8888, DRM_FORMAT_BGRA8888 } + }; + + size_t i; + + if (fb_var->bits_per_pixel < 8) + goto err; /* at least 8-bit color required */ + if (fb_var->grayscale == 1) + goto err; /* grayscale output is not supported */ + + for (i = 0; i < ARRAY_SIZE(map); ++i) { + if (map[i].is_format(fb_var)) + return map[i].format; + } + +err: + return DRM_FORMAT_INVALID; +} +EXPORT_SYMBOL(drm_fbconv_format_of_fb_var_screeninfo); + +/** + * drm_fbconv_format_of_fb_info - Returns a DRM_FORMAT constant from + * an fb_info structure + * @fb_info: the fb_info structure + * Returns: + * A DRM_FORMAT constant on success, or + * DRM_FORMAT_INVALID otherwise. + */ +uint32_t drm_fbconv_format_of_fb_info(const struct fb_info *fb_info) +{ + if (fb_info->fix.type != FB_TYPE_PACKED_PIXELS) + return DRM_FORMAT_INVALID; /* no multi-plane formats */ + + return drm_fbconv_format_of_fb_var_screeninfo(&fb_info->var); +} +EXPORT_SYMBOL(drm_fbconv_format_of_fb_info); + +static void set_fb_bitfield(struct fb_bitfield *bits, __u32 offset, + __u32 length) +{ + bits->offset = offset; + bits->length = length; + bits->msb_right = 0; +} + +static void set_c8(struct fb_var_screeninfo *fb_var) +{ + fb_var->bits_per_pixel = 8; + fb_var->grayscale = 0; + set_fb_bitfield(&fb_var->red, 0, 8); + set_fb_bitfield(&fb_var->green, 0, 8); + set_fb_bitfield(&fb_var->blue, 0, 8); + set_fb_bitfield(&fb_var->transp, 0, 0); + fb_var->nonstd = 0; +} + +static void set_rgb565(struct fb_var_screeninfo *fb_var) +{ + fb_var->bits_per_pixel = 16; + fb_var->grayscale = 0; + set_fb_bitfield(&fb_var->red, 11, 5); + set_fb_bitfield(&fb_var->green, 5, 6); + set_fb_bitfield(&fb_var->blue, 0, 5); + set_fb_bitfield(&fb_var->transp, 0, 0); + fb_var->nonstd = 0; +} + +static void set_bgr565(struct fb_var_screeninfo *fb_var) +{ + fb_var->bits_per_pixel = 16; + fb_var->grayscale = 0; + set_fb_bitfield(&fb_var->red, 0, 5); + set_fb_bitfield(&fb_var->green, 5, 6); + set_fb_bitfield(&fb_var->blue, 11, 5); + set_fb_bitfield(&fb_var->transp, 0, 0); + fb_var->nonstd = 0; +} + +static void set_rgb888(struct fb_var_screeninfo *fb_var) +{ + fb_var->bits_per_pixel = 24; + fb_var->grayscale = 0; + set_fb_bitfield(&fb_var->red, 16, 8); + set_fb_bitfield(&fb_var->green, 8, 8); + set_fb_bitfield(&fb_var->blue, 0, 8); + set_fb_bitfield(&fb_var->transp, 0, 0); + fb_var->nonstd = 0; +} + +static void set_bgr888(struct fb_var_screeninfo *fb_var) +{ + fb_var->bits_per_pixel = 24; + fb_var->grayscale = 0; + set_fb_bitfield(&fb_var->red, 0, 8); + set_fb_bitfield(&fb_var->green, 8, 8); + set_fb_bitfield(&fb_var->blue, 16, 8); + set_fb_bitfield(&fb_var->transp, 0, 0); + fb_var->nonstd = 0; +} + +static void set_xrgb8888(struct fb_var_screeninfo *fb_var) +{ + fb_var->bits_per_pixel = 32; + fb_var->grayscale = 0; + set_fb_bitfield(&fb_var->red, 16, 8); + set_fb_bitfield(&fb_var->green, 8, 8); + set_fb_bitfield(&fb_var->blue, 0, 8); + set_fb_bitfield(&fb_var->transp, 24, 0); + fb_var->nonstd = 0; +} + +static void set_xbgr8888(struct fb_var_screeninfo *fb_var) +{ + fb_var->bits_per_pixel = 32; + fb_var->grayscale = 0; + set_fb_bitfield(&fb_var->red, 0, 8); + set_fb_bitfield(&fb_var->green, 8, 8); + set_fb_bitfield(&fb_var->blue, 16, 8); + set_fb_bitfield(&fb_var->transp, 24, 0); + fb_var->nonstd = 0; +} + +static void set_rgbx8888(struct fb_var_screeninfo *fb_var) +{ + fb_var->bits_per_pixel = 32; + fb_var->grayscale = 0; + set_fb_bitfield(&fb_var->red, 24, 8); + set_fb_bitfield(&fb_var->green, 16, 8); + set_fb_bitfield(&fb_var->blue, 8, 8); + set_fb_bitfield(&fb_var->transp, 0, 0); + fb_var->nonstd = 0; +} + +static void set_bgrx8888(struct fb_var_screeninfo *fb_var) +{ + fb_var->bits_per_pixel = 32; + fb_var->grayscale = 0; + set_fb_bitfield(&fb_var->red, 8, 8); + set_fb_bitfield(&fb_var->green, 16, 8); + set_fb_bitfield(&fb_var->blue, 24, 8); + set_fb_bitfield(&fb_var->transp, 0, 0); + fb_var->nonstd = 0; +} + +static void set_argb8888(struct fb_var_screeninfo *fb_var) +{ + fb_var->bits_per_pixel = 32; + fb_var->grayscale = 0; + set_fb_bitfield(&fb_var->red, 16, 8); + set_fb_bitfield(&fb_var->green, 8, 8); + set_fb_bitfield(&fb_var->blue, 0, 8); + set_fb_bitfield(&fb_var->transp, 24, 8); + fb_var->nonstd = 0; +} + +static void set_abgr8888(struct fb_var_screeninfo *fb_var) +{ + fb_var->bits_per_pixel = 32; + fb_var->grayscale = 0; + set_fb_bitfield(&fb_var->red, 0, 8); + set_fb_bitfield(&fb_var->green, 8, 8); + set_fb_bitfield(&fb_var->blue, 16, 8); + set_fb_bitfield(&fb_var->transp, 24, 8); + fb_var->nonstd = 0; +} + +static void set_rgba8888(struct fb_var_screeninfo *fb_var) +{ + fb_var->bits_per_pixel = 32; + fb_var->grayscale = 0; + set_fb_bitfield(&fb_var->red, 24, 8); + set_fb_bitfield(&fb_var->green, 16, 8); + set_fb_bitfield(&fb_var->blue, 8, 8); + set_fb_bitfield(&fb_var->transp, 0, 8); + fb_var->nonstd = 0; +} + +static void set_bgra8888(struct fb_var_screeninfo *fb_var) +{ + fb_var->bits_per_pixel = 32; + fb_var->grayscale = 0; + set_fb_bitfield(&fb_var->red, 8, 8); + set_fb_bitfield(&fb_var->green, 16, 8); + set_fb_bitfield(&fb_var->blue, 24, 8); + set_fb_bitfield(&fb_var->transp, 0, 8); + fb_var->nonstd = 0; +} + +/** + * drm_fbconv_update_fb_var_screen_info_from_format - sets the pixel format + * of a fb_var_screeninfo structure from a DRM_FORMAT constant + * @fb_var: the fb_var_screeninfo structure to update + * @format: a DRM_FORMAT constant + * Returns: + * 0 on success, or + * a negative error code otherwise. + */ +int drm_fbconv_update_fb_var_screeninfo_from_format( + struct fb_var_screeninfo *fb_var, uint32_t format) +{ + switch (format) { + case DRM_FORMAT_C8: + set_c8(fb_var); + break; + case DRM_FORMAT_RGB565: + set_rgb565(fb_var); + break; + case DRM_FORMAT_BGR565: + set_bgr565(fb_var); + break; + case DRM_FORMAT_RGB888: + set_rgb888(fb_var); + break; + case DRM_FORMAT_BGR888: + set_bgr888(fb_var); + break; + case DRM_FORMAT_XRGB8888: + set_xrgb8888(fb_var); + break; + case DRM_FORMAT_XBGR8888: + set_xbgr8888(fb_var); + break; + case DRM_FORMAT_RGBX8888: + set_rgbx8888(fb_var); + break; + case DRM_FORMAT_BGRX8888: + set_bgrx8888(fb_var); + break; + case DRM_FORMAT_ARGB8888: + set_argb8888(fb_var); + break; + case DRM_FORMAT_ABGR8888: + set_abgr8888(fb_var); + break; + case DRM_FORMAT_RGBA8888: + set_rgba8888(fb_var); + break; + case DRM_FORMAT_BGRA8888: + set_bgra8888(fb_var); + break; + default: + return -EINVAL; + } + return 0; +} +EXPORT_SYMBOL(drm_fbconv_update_fb_var_screeninfo_from_format); diff --git a/include/drm/drm_fbconv_helper.h b/include/drm/drm_fbconv_helper.h new file mode 100644 index 000000000000..6b2ed12b579a --- /dev/null +++ b/include/drm/drm_fbconv_helper.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef DRM_FBCONV_HELPER_H +#define DRM_FBCONV_HELPER_H + +#include + +struct fb_info; +struct fb_var_screeninfo; + +/* + * Format conversion helpers + */ + +uint32_t +drm_fbconv_format_of_fb_var_screeninfo(const struct fb_var_screeninfo *fb_var); + +uint32_t drm_fbconv_format_of_fb_info(const struct fb_info *fb_info); + +int drm_fbconv_update_fb_var_screeninfo_from_format( + struct fb_var_screeninfo *fb_var, uint32_t format); + +#endif From patchwork Mon Oct 14 14:04:07 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 11188777 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C9EC718A6 for ; Mon, 14 Oct 2019 14:04:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id AD0652083B for ; Mon, 14 Oct 2019 14:04:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732447AbfJNOEZ (ORCPT ); Mon, 14 Oct 2019 10:04:25 -0400 Received: from mx2.suse.de ([195.135.220.15]:50858 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1732389AbfJNOEZ (ORCPT ); Mon, 14 Oct 2019 10:04:25 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id ED784B190; Mon, 14 Oct 2019 14:04:21 +0000 (UTC) From: Thomas Zimmermann 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: corbet@lwn.net, gregkh@linuxfoundation.org, dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH v2 06/15] drm/fbconv: Add mode conversion DRM <-> fbdev Date: Mon, 14 Oct 2019 16:04:07 +0200 Message-Id: <20191014140416.28517-7-tzimmermann@suse.de> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191014140416.28517-1-tzimmermann@suse.de> References: <20191014140416.28517-1-tzimmermann@suse.de> MIME-Version: 1.0 Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org DRM uses struct drm_display_mode to describe a display mode. The conversion functions fill it from fbdev data strucutures, and vice versa. Signed-off-by: Thomas Zimmermann --- drivers/gpu/drm/drm_fbconv_helper.c | 201 ++++++++++++++++++++++++++++ include/drm/drm_fbconv_helper.h | 31 +++++ 2 files changed, 232 insertions(+) diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c index af45358a156a..e5a58a361ae9 100644 --- a/drivers/gpu/drm/drm_fbconv_helper.c +++ b/drivers/gpu/drm/drm_fbconv_helper.c @@ -5,6 +5,7 @@ #include #include +#include /* * Format conversion helpers @@ -434,3 +435,203 @@ int drm_fbconv_update_fb_var_screeninfo_from_format( return 0; } EXPORT_SYMBOL(drm_fbconv_update_fb_var_screeninfo_from_format); + +/* + * Mode conversion helpers + */ + +/** + * drm_mode_update_from_fb_videomode - Sets a drm_display mode struecture + * from an fb_videomode structure + * @mode: the DRM display mode structure to update + * @fb_mode: an fb_videomode structure + */ +void drm_mode_update_from_fb_videomode(struct drm_display_mode *mode, + const struct fb_videomode *fb_mode) +{ + mode->type = DRM_MODE_TYPE_DRIVER; + + mode->clock = PICOS2KHZ(fb_mode->pixclock); + + mode->hdisplay = fb_mode->xres; + mode->hsync_start = mode->hdisplay + fb_mode->right_margin; + mode->hsync_end = mode->hsync_start + fb_mode->hsync_len; + mode->htotal = mode->hsync_end + fb_mode->left_margin; + mode->hskew = 0; + + mode->vdisplay = fb_mode->yres; + mode->vsync_start = mode->vdisplay + fb_mode->lower_margin; + mode->vsync_end = mode->vsync_start + fb_mode->vsync_len; + mode->vtotal = mode->vsync_end + fb_mode->upper_margin; + mode->vscan = 0; + + mode->flags = 0; + + if (fb_mode->sync & FB_SYNC_HOR_HIGH_ACT) + mode->flags |= DRM_MODE_FLAG_PHSYNC; + else + mode->flags |= DRM_MODE_FLAG_NHSYNC; + + if (fb_mode->sync & FB_SYNC_VERT_HIGH_ACT) + mode->flags |= DRM_MODE_FLAG_PVSYNC; + else + mode->flags |= DRM_MODE_FLAG_NVSYNC; + + if (fb_mode->sync & FB_SYNC_COMP_HIGH_ACT) + mode->flags |= DRM_MODE_FLAG_CSYNC | DRM_MODE_FLAG_PCSYNC; + + if (fb_mode->vmode & FB_VMODE_INTERLACED) + mode->flags |= DRM_MODE_FLAG_INTERLACE; + + if (fb_mode->vmode & FB_VMODE_DOUBLE) + mode->flags |= DRM_MODE_FLAG_DBLSCAN; + + mode->width_mm = 0; + mode->height_mm = 0; + + mode->vrefresh = fb_mode->refresh; + mode->hsync = mode->clock / mode->vtotal; + + /* final step; depends on previous setup */ + if (fb_mode->name) { + strncpy(mode->name, fb_mode->name, sizeof(mode->name) - 1); + mode->name[sizeof(mode->name) - 1] = '\0'; + } else { + drm_mode_set_name(mode); + } +} +EXPORT_SYMBOL(drm_mode_update_from_fb_videomode); + +/** + * drm_mode_update_from_fb_var_screeninfo - Sets a drm_display mode structure + * from an fb_var_screenmode structure + * @mode: the DRM display mode structure to update + * @fb_var: an fb_var_screeninfo structure + */ +void drm_mode_update_from_fb_var_screeninfo( + struct drm_display_mode *mode, const struct fb_var_screeninfo *fb_var) +{ + struct fb_videomode fb_mode; + + fb_var_to_videomode(&fb_mode, fb_var); + drm_mode_update_from_fb_videomode(mode, &fb_mode); +} +EXPORT_SYMBOL(drm_mode_update_from_fb_var_screeninfo); + +/** + * drm_mode_create_from_fb_videomode - Creates a drm_display mode structure + * from an fb_videomode structure + * @dev: the new mode's DRM device + * @fb_mode: an fb_videomode structure + * Returns: + * A newly allocated DRM display mode structure on success, or + * NULL otherwise + */ +struct drm_display_mode * drm_mode_create_from_fb_videomode( + struct drm_device *dev, const struct fb_videomode *fb_mode) +{ + /* cleared to '0' */ + struct drm_display_mode *mode; + + mode = drm_mode_create(dev); + if (!mode) + return NULL; + + drm_mode_update_from_fb_videomode(mode, fb_mode); + + return mode; +} +EXPORT_SYMBOL(drm_mode_create_from_fb_videomode); + +/** + * drm_fbconv_update_fb_videomode_from_mode - updates an fb_videomode + * structure from a DRM display mode + * @fb_mode: the fb_videomode structure to update + * @mode: a DRM display mode + */ +void +drm_fbconv_update_fb_videomode_from_mode(struct fb_videomode *fb_mode, + const struct drm_display_mode *mode) +{ + fb_mode->name = NULL; + fb_mode->refresh = mode->vrefresh; + fb_mode->xres = mode->hdisplay; + fb_mode->yres = mode->vdisplay; + fb_mode->pixclock = KHZ2PICOS(mode->clock); + fb_mode->left_margin = mode->htotal - mode->hsync_end; + fb_mode->right_margin = mode->hsync_start - mode->hdisplay; + fb_mode->upper_margin = mode->vtotal - mode->vsync_end; + fb_mode->lower_margin = mode->vsync_start - mode->vdisplay; + fb_mode->hsync_len = mode->hsync_end - mode->hsync_start; + fb_mode->vsync_len = mode->vsync_end - mode->vsync_start; + + fb_mode->sync = 0; + if (mode->flags & DRM_MODE_FLAG_PHSYNC) + fb_mode->sync |= FB_SYNC_HOR_HIGH_ACT; + if (mode->flags & DRM_MODE_FLAG_PVSYNC) + fb_mode->sync |= FB_SYNC_VERT_HIGH_ACT; + if (mode->flags & (DRM_MODE_FLAG_CSYNC | DRM_MODE_FLAG_PCSYNC)) + fb_mode->sync |= FB_SYNC_COMP_HIGH_ACT; + + fb_mode->vmode = 0; + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + fb_mode->vmode |= FB_VMODE_INTERLACED; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + fb_mode->vmode |= FB_VMODE_DOUBLE; + + fb_mode->flag = 0; +} +EXPORT_SYMBOL(drm_fbconv_update_fb_videomode_from_mode); + +/** + * drm_fbconv_init_fb_videomode_from_mode - initializes an fb_videomode + * structure from a DRM display mode + * @fb_mode: the fb_videomode structure to update + * @mode: a DRM display mode + * + * This is the same as drm_fbconv_update_fb_videomode_from_mode(), but + * first clears the fb_screeninfo structure to 0. + */ +void drm_fbconv_init_fb_videomode_from_mode( + struct fb_videomode *fb_mode, const struct drm_display_mode *mode) +{ + memset(fb_mode, 0, sizeof(*fb_mode)); + drm_fbconv_update_fb_videomode_from_mode(fb_mode, mode); +} +EXPORT_SYMBOL(drm_fbconv_init_fb_videomode_from_mode); + +/** + * drm_fbconv_update_fb_var_screeninfo_from_mode - updates an + * fb_var_screeninfo structure from a DRM display mode + * @fb_var: the fb_var_screeninfo structure to update + * @mode: a DRM display mode + */ +void drm_fbconv_update_fb_var_screeninfo_from_mode( + struct fb_var_screeninfo *fb_var, const struct drm_display_mode *mode) +{ + struct fb_videomode fb_mode; + + drm_fbconv_init_fb_videomode_from_mode(&fb_mode, mode); + fb_videomode_to_var(fb_var, &fb_mode); + + fb_var->height = mode->height_mm; + fb_var->width = mode->width_mm; +} +EXPORT_SYMBOL(drm_fbconv_update_fb_var_screeninfo_from_mode); + +/** + * drm_fbconv_init_fb_var_screeninfo_from_mode - initialize an + * fb_var_screeninfo structure from a DRM display mode + * @fb_var: the fb_var_screeninfo structure to update + * @mode: a DRM display mode + * + * This is the same as drm_fbconv_update_fb_var_screeninfo_from_mode(), but + * first clears the fb_screeninfo structure to 0. + */ +void drm_fbconv_init_fb_var_screeninfo_from_mode( + struct fb_var_screeninfo *fb_var, const struct drm_display_mode *mode) +{ + memset(fb_var, 0, sizeof(*fb_var)); + drm_fbconv_update_fb_var_screeninfo_from_mode(fb_var, mode); +} +EXPORT_SYMBOL(drm_fbconv_init_fb_var_screeninfo_from_mode); diff --git a/include/drm/drm_fbconv_helper.h b/include/drm/drm_fbconv_helper.h index 6b2ed12b579a..cbb13228c76c 100644 --- a/include/drm/drm_fbconv_helper.h +++ b/include/drm/drm_fbconv_helper.h @@ -5,8 +5,12 @@ #include +struct drm_device; +struct drm_display_mode; struct fb_info; struct fb_var_screeninfo; +struct fb_var_screeninfo; +struct fb_videomode; /* * Format conversion helpers @@ -20,4 +24,31 @@ uint32_t drm_fbconv_format_of_fb_info(const struct fb_info *fb_info); int drm_fbconv_update_fb_var_screeninfo_from_format( struct fb_var_screeninfo *fb_var, uint32_t format); +/* + * Mode conversion helpers + */ + +void drm_mode_update_from_fb_videomode(struct drm_display_mode *mode, + const struct fb_videomode *fb_mode); + +void drm_mode_update_from_fb_var_screeninfo( + struct drm_display_mode *mode, const struct fb_var_screeninfo *fb_var); + +struct drm_display_mode * drm_mode_create_from_fb_videomode( + struct drm_device *dev, const struct fb_videomode *fb_mode); + +void +drm_fbconv_update_fb_videomode_from_mode(struct fb_videomode *fb_mode, + const struct drm_display_mode *mode); + +void +drm_fbconv_init_fb_videomode_from_mode(struct fb_videomode *fb_mode, + const struct drm_display_mode *mode); + +void drm_fbconv_update_fb_var_screeninfo_from_mode( + struct fb_var_screeninfo *var, const struct drm_display_mode *mode); + +void drm_fbconv_init_fb_var_screeninfo_from_mode( + struct fb_var_screeninfo *var, const struct drm_display_mode *mode); + #endif From patchwork Mon Oct 14 14:04:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 11188781 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 24996199D for ; Mon, 14 Oct 2019 14:04:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 0777621882 for ; Mon, 14 Oct 2019 14:04:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732389AbfJNOEZ (ORCPT ); Mon, 14 Oct 2019 10:04:25 -0400 Received: from mx2.suse.de ([195.135.220.15]:50874 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1732435AbfJNOEZ (ORCPT ); Mon, 14 Oct 2019 10:04:25 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 6F636B1A3; Mon, 14 Oct 2019 14:04:22 +0000 (UTC) From: Thomas Zimmermann 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: corbet@lwn.net, gregkh@linuxfoundation.org, dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH v2 07/15] drm/fbconv: Add modesetting infrastructure Date: Mon, 14 Oct 2019 16:04:08 +0200 Message-Id: <20191014140416.28517-8-tzimmermann@suse.de> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191014140416.28517-1-tzimmermann@suse.de> References: <20191014140416.28517-1-tzimmermann@suse.de> MIME-Version: 1.0 Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org Modesetting for fbconv supports a single display pipeline with CRTC, primary plane, encoder and connector. It's implementation is based on struct drm_simple_display_pipe, which fits this use case nicely. Signed-off-by: Thomas Zimmermann --- drivers/gpu/drm/drm_fbconv_helper.c | 382 ++++++++++++++++++++++++++++ include/drm/drm_fbconv_helper.h | 78 ++++++ 2 files changed, 460 insertions(+) diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c index e5a58a361ae9..4cda1f15e072 100644 --- a/drivers/gpu/drm/drm_fbconv_helper.c +++ b/drivers/gpu/drm/drm_fbconv_helper.c @@ -4,8 +4,13 @@ #include +#include #include +#include +#include #include +#include +#include /* * Format conversion helpers @@ -635,3 +640,380 @@ void drm_fbconv_init_fb_var_screeninfo_from_mode( drm_fbconv_update_fb_var_screeninfo_from_mode(fb_var, mode); } EXPORT_SYMBOL(drm_fbconv_init_fb_var_screeninfo_from_mode); + +/* + * Connector + */ + +static int connector_helper_get_modes(struct drm_connector *connector) +{ + return 0; +} + +static int connector_helper_detect_ctx(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) +{ + return connector_status_connected; +} + +static enum drm_mode_status connector_helper_mode_valid( + struct drm_connector *connector, struct drm_display_mode *mode) +{ + return MODE_OK; +} + +static int connector_helper_atomic_check(struct drm_connector *connector, + struct drm_atomic_state *state) +{ + return 0; +} + +static void connector_helper_atomic_commit(struct drm_connector *connector, + struct drm_connector_state *state) +{ } + +static const struct drm_connector_helper_funcs connector_helper_funcs = { + .get_modes = connector_helper_get_modes, + .detect_ctx = connector_helper_detect_ctx, + .mode_valid = connector_helper_mode_valid, + .best_encoder = NULL, /* use default */ + .atomic_best_encoder = NULL, /* use best_encoder instead */ + .atomic_check = connector_helper_atomic_check, + .atomic_commit = connector_helper_atomic_commit +}; + +static enum drm_connector_status connector_detect( + struct drm_connector *connector, bool force) +{ + return connector_status_connected; +} + +static void connector_force(struct drm_connector *connector) +{ } + +static void connector_destroy(struct drm_connector *connector) +{ } + +static int connector_atomic_set_property(struct drm_connector *connector, + struct drm_connector_state *state, + struct drm_property *property, + uint64_t val) +{ + return -EINVAL; +} + +static int connector_atomic_get_property( + struct drm_connector *connector, + const struct drm_connector_state *state, struct drm_property *property, + uint64_t *val) +{ + return -EINVAL; +} + +static const struct drm_connector_funcs connector_funcs = { + .dpms = NULL, /* not used by atomic drivers */ + .reset = drm_atomic_helper_connector_reset, + .detect = connector_detect, + .force = connector_force, + .fill_modes = drm_helper_probe_single_connector_modes, + .set_property = NULL, + .late_register = NULL, + .early_unregister = NULL, + .destroy = connector_destroy, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + .atomic_set_property = connector_atomic_set_property, + .atomic_get_property = connector_atomic_get_property, + .atomic_print_state = NULL +}; + +/* + * Simple display pipe + */ + +/** + * drm_fbconv_simple_display_pipe_mode_valid - default implementation for + * struct drm_simple_display_pipe_funcs.mode_valid + * @crtc: the DRM CRTC structure + * @mode: the display mode to validate + * Returns: + * MODE_OK on success, or + * a MODE constant otherwise + */ +enum drm_mode_status +drm_fbconv_simple_display_pipe_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) +{ + return MODE_OK; +} +EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_mode_valid); + +/** + * drm_fbconv_simple_display_pipe_mode_fixup - default implementation for + * struct drm_simple_display_pipe_funcs.mode_fixup + * @crtc: the DRM CRTC structure + * @mode: the display mode + * @adjusted_mode: the adjusted display mode + * Returns: + * true on success, or + * false otherwise + */ +bool drm_fbconv_simple_display_pipe_mode_fixup( + struct drm_crtc *crtc, const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} +EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_mode_fixup); + +/** + * drm_fbconv_simple_display_pipe_enable - default implementation for + * struct drm_simple_display_pipe_funcs.enable + * @pipe: the display pipe structure + * @crtc_state: the new CRTC state + * @plane_state: the new plane state + */ +void +drm_fbconv_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, + struct drm_crtc_state *crtc_state, + struct drm_plane_state *plane_state) +{ } +EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_enable); + +/** + * drm_fbconv_simple_display_pipe_disable - default implementation for + * struct drm_simple_display_pipe_funcs.disable + * @pipe: the display pipe structure + */ +void +drm_fbconv_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe) +{ } +EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_disable); + +/** + * drm_fbconv_simple_display_pipe_check - default implementation for + * struct drm_simple_display_pipe_funcs.check + * @pipe: the display pipe structure + * @plane_state: the new plane state + * @crtc_state: the new CRTC state + */ +int +drm_fbconv_simple_display_pipe_check(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *plane_state, + struct drm_crtc_state *crtc_state) +{ + return 0; +} +EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_check); + +/** + * drm_fbconv_simple_display_pipe_mode_update - default implementation for + * struct drm_simple_display_pipe_funcs.update + * @pipe: the display pipe structure + * @old_plane_state: the old plane state + */ +void +drm_fbconv_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *old_plane_state) +{ } +EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_update); + +/** + * drm_fbconv_simple_display_pipe_prepare_fb - default implementation for + * struct drm_simple_display_pipe_funcs.prepare_fb + * @pipe: the display pipe structure + * @plane_state: the new plane state + * Returns: + * 0 on success, or + * a negative error code otherwise. + * + * The implementation of struct drm_simple_display_pipe_funcs.prepare_fb + * maps the framebuffer's buffer object and the fbdev's screen memory, if + * necessary. After converting the fbdev driver to DRM, only the buffer-object + * mapping should remaing. See drm_fbconv_simple_display_pipe_cleanup_fb() for + * the corresponding clean-up helper. + */ +int +drm_fbconv_simple_display_pipe_prepare_fb(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *plane_state) +{ } +EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_prepare_fb); + +/** + * drm_fbconv_simple_display_pipe_cleanup_fb - default implementation for + * struct drm_simple_display_pipe_funcs.cleanup_fb + * @pipe: the display pipe structure + * @plane_state: the old plane state + * + * This function cleans up the framebuffer state after a plane update. See + * drm_fbconv_simple_display_pipe_prepare_fb() for the corresponding prepare + * helper. + */ +void +drm_fbconv_simple_display_pipe_cleanup_fb(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *plane_state) +{ } + +static const struct drm_simple_display_pipe_funcs simple_display_pipe_funcs = { + .mode_valid = drm_fbconv_simple_display_pipe_mode_valid, + .mode_fixup = drm_fbconv_simple_display_pipe_mode_fixup, + .enable = drm_fbconv_simple_display_pipe_enable, + .disable = drm_fbconv_simple_display_pipe_disable, + .check = drm_fbconv_simple_display_pipe_check, + .update = drm_fbconv_simple_display_pipe_update, + .prepare_fb = drm_fbconv_simple_display_pipe_prepare_fb, + .cleanup_fb = drm_fbconv_simple_display_pipe_cleanup_fb, +}; + +/* + * Mode config + */ + +static enum drm_mode_status mode_config_mode_valid( + struct drm_device *dev, const struct drm_display_mode *mode) +{ + return MODE_OK; +} + +static const struct drm_mode_config_funcs mode_config_funcs = { + .fb_create = drm_gem_fb_create_with_dirty, + .get_format_info = NULL, + /* DRM porting notes: the output_poll_changed callback is used by + * fb helpers to implement fbdev emulation. If you're porting an + * fbdev driver to DRM and enable fbdev emulation, this callback + * will become useful. + */ + .output_poll_changed = drm_fb_helper_output_poll_changed, + .mode_valid = mode_config_mode_valid, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, + .atomic_state_alloc = NULL, + .atomic_state_clear = NULL, + .atomic_state_free = NULL +}; + +/** + * drm_fbconv_modeset_init - initializes an fbconv modesetting structure + * @modeset: the fbconv modesetting structure to initialize + * @dev: the DRM device + * @fb_info: the fbdev driver's fb_info structure + * @max_width: the maximum display width that is supported by + * the device + * @max_height: the maximum display height that is supported by + * the device + * @preferred_depth: the device's preferred color depth + * Returns: + * 0 on success, or + * a negative error code otherwise + * + * This function initializes an instance of struct drm_fbconv_modeset. The + * supplied values for max_width, max_height, and max_depth should match the + * devices capabilities and be supported by the fbdev driver. DRM helpers + * will use these to auto-configure and validate display settings. + */ +int drm_fbconv_modeset_init(struct drm_fbconv_modeset *modeset, + struct drm_device *dev, struct fb_info *fb_info, + unsigned int max_width, unsigned int max_height, + unsigned int preferred_depth) +{ + struct drm_mode_config *mode_config = &dev->mode_config; + + modeset->dev = dev; + modeset->fb_info = fb_info; + + drm_mode_config_init(dev); + + mode_config->max_width = (int)max_width; + mode_config->max_height = (int)max_height; + mode_config->fb_base = fb_info->fix.smem_start; + mode_config->preferred_depth = preferred_depth; + mode_config->prefer_shadow_fbdev = true; + mode_config->funcs = &mode_config_funcs; + + return 0; +} +EXPORT_SYMBOL(drm_fbconv_modeset_init); + +/** + * drm_fbconv_modeset_cleanup - Cleans up an fbconv modesetting structure + * @modeset: the fbconv modesetting structure to clean up + */ +void drm_fbconv_modeset_cleanup(struct drm_fbconv_modeset *modeset) +{ + drm_mode_config_cleanup(modeset->dev); +} +EXPORT_SYMBOL(drm_fbconv_modeset_cleanup); + +/** + * drm_fbconv_modeset_setup_pipe - sets up the display pipeline for fbconv + * @modeset: an fbconv modesetting structure + * @funcs: an implementation of + * struct drm_simple_display_pipe_funcs, or NULL + * @formats: the device's supported display formats + * @format_count: the number of entries in @formats + * @format_modifiers: DRM format modifiers, or NULL + * @connector: the DRM connector, or NULL + * Returns: + * 0 on success, or + * a negative error code otherwise + * + * This function sets up the display pipeline for an initialized instance of + * struct drm_fbconv_modeset. For maximum compatibility with userspace, the + * provided list of formats should contain at least DRM_FORMAT_XRGB8888 and + * DRM_FORMAT_RGB565. The necessary conversion to the hardware's actual + * configuration can be performed by drm_fbconv_simple_display_pipe_update(). + * + * The values for @funcs, @format_modifiers, and @connector should be NULL + * by default. Explicitly settings these parameters will only be helpful for + * refactoring an fbdev driver into a DRM driver. + */ +int +drm_fbconv_modeset_setup_pipe(struct drm_fbconv_modeset *modeset, + const struct drm_simple_display_pipe_funcs *funcs, + const uint32_t *formats, + unsigned int format_count, + const uint64_t *format_modifiers, + struct drm_connector *connector) +{ + int ret; + + /* DRM porting note: Now let's enable the display pipeline. If + * you're porting a framebuffer driver to DRM, you may want to + * set the correct connector type or replace the simple display + * pipeline with something more sophisticated. + */ + + if (!funcs) + funcs = &simple_display_pipe_funcs; + + if (!connector) { + connector = &modeset->connector; + + ret = drm_connector_init(modeset->dev, connector, + &connector_funcs, + DRM_MODE_CONNECTOR_Unknown); + if (ret) + return ret; + drm_connector_helper_add(connector, &connector_helper_funcs); + + ret = drm_connector_register(connector); + if (ret < 0) + return ret; + + } + + ret = drm_simple_display_pipe_init(modeset->dev, &modeset->pipe, + funcs, formats, format_count, + format_modifiers, connector); + if (ret) + return ret; + + /* Final step: resetting the device's mode config creates + * state for all objects in the mode-setting pipeline. + */ + drm_mode_config_reset(modeset->dev); + + return 0; +} +EXPORT_SYMBOL(drm_fbconv_modeset_setup_pipe); diff --git a/include/drm/drm_fbconv_helper.h b/include/drm/drm_fbconv_helper.h index cbb13228c76c..79716af687c1 100644 --- a/include/drm/drm_fbconv_helper.h +++ b/include/drm/drm_fbconv_helper.h @@ -3,7 +3,11 @@ #ifndef DRM_FBCONV_HELPER_H #define DRM_FBCONV_HELPER_H +#include +#include +#include #include +#include struct drm_device; struct drm_display_mode; @@ -51,4 +55,78 @@ void drm_fbconv_update_fb_var_screeninfo_from_mode( void drm_fbconv_init_fb_var_screeninfo_from_mode( struct fb_var_screeninfo *var, const struct drm_display_mode *mode); +/* + * Simple display pipe + */ + +enum drm_mode_status +drm_fbconv_simple_display_pipe_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode); + +bool drm_fbconv_simple_display_pipe_mode_fixup( + struct drm_crtc *crtc, const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + +void +drm_fbconv_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, + struct drm_crtc_state *crtc_state, + struct drm_plane_state *plane_state); + +void +drm_fbconv_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe); + +int +drm_fbconv_simple_display_pipe_check(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *plane_state, + struct drm_crtc_state *crtc_state); + +void +drm_fbconv_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *old_plane_state); + +int +drm_fbconv_simple_display_pipe_prepare_fb(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *plane_state); + +void +drm_fbconv_simple_display_pipe_cleanup_fb(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *plane_state); + +/* + * Modeset helpers + */ + +/** + * struct drm_fbconv_modeset - contains state for fbconv modesetting + * @connector: the DRM connector + * @pipe: the modesetting pipeline + * @dev: the DRM device + * @fb_info: the fbdev driver's fb_info structure + */ +struct drm_fbconv_modeset { + struct drm_connector connector; + struct drm_simple_display_pipe pipe; + + struct drm_device *dev; + struct fb_info *fb_info; +}; + +static inline struct drm_fbconv_modeset *drm_fbconv_modeset_of_pipe( + struct drm_simple_display_pipe *pipe) +{ + return container_of(pipe, struct drm_fbconv_modeset, pipe); +} + +int drm_fbconv_modeset_init(struct drm_fbconv_modeset *modeset, + struct drm_device *dev, struct fb_info *fb_info, + unsigned int max_width, unsigned int max_height, + unsigned int preferred_depth); +void drm_fbconv_modeset_cleanup(struct drm_fbconv_modeset *modeset); + +int drm_fbconv_modeset_setup_pipe( + struct drm_fbconv_modeset *modeset, + const struct drm_simple_display_pipe_funcs *funcs, + const uint32_t *formats, unsigned int format_count, + const uint64_t *format_modifiers, struct drm_connector *connector); + #endif From patchwork Mon Oct 14 14:04:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 11188785 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0300118B8 for ; Mon, 14 Oct 2019 14:04:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id CF4DA2083B for ; Mon, 14 Oct 2019 14:04:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732448AbfJNOE0 (ORCPT ); Mon, 14 Oct 2019 10:04:26 -0400 Received: from mx2.suse.de ([195.135.220.15]:50908 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1732339AbfJNOE0 (ORCPT ); Mon, 14 Oct 2019 10:04:26 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id E22BDB1A8; Mon, 14 Oct 2019 14:04:22 +0000 (UTC) From: Thomas Zimmermann 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: corbet@lwn.net, gregkh@linuxfoundation.org, dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH v2 08/15] drm/fbconv: Add plane-state check and update Date: Mon, 14 Oct 2019 16:04:09 +0200 Message-Id: <20191014140416.28517-9-tzimmermann@suse.de> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191014140416.28517-1-tzimmermann@suse.de> References: <20191014140416.28517-1-tzimmermann@suse.de> MIME-Version: 1.0 Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org For the update of the primary plane, we copy the content of a SHMEM buffer object to the hardware's on-screen buffer; doing a format conversion if necessary. This is able to support all combinations of framebuffers and hardware, and should work with any fbdev driver. Occasionally, fbdev drivers require an update of the hardware's gamma tables to not show distorted colors. We also do this during the plane update. There's no support for horizontal panning, as fbdev drivers vary widely in their capability to do this. Vertical panning is supported to the extend allowed by available video ram. However, this whole functionality is more interesting for porting drivers and not directly required by fbconv itself. Signed-off-by: Thomas Zimmermann --- drivers/gpu/drm/Kconfig | 1 + drivers/gpu/drm/drm_fbconv_helper.c | 500 +++++++++++++++++++++++++++- include/drm/drm_fbconv_helper.h | 9 + 3 files changed, 507 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index ed689201ec81..2ce7749c3157 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -160,6 +160,7 @@ config DRM_DP_CEC config DRM_FBCONV_HELPER tristate "Enable fbdev conversion helpers" depends on DRM + select DRM_GEM_SHMEM_HELPER help Provides helpers for running DRM on top of fbdev drivers. Choose this option if you're converting an fbdev driver to DRM. The diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c index 4cda1f15e072..cf218016ac05 100644 --- a/drivers/gpu/drm/drm_fbconv_helper.c +++ b/drivers/gpu/drm/drm_fbconv_helper.c @@ -5,12 +5,17 @@ #include #include +#include #include #include +#include #include +#include #include #include +#include #include +#include /* * Format conversion helpers @@ -728,10 +733,192 @@ static const struct drm_connector_funcs connector_funcs = { .atomic_print_state = NULL }; +/* + * Colormap updates + */ + +/* provides a default colormap for palette modes */ +static int create_palette_cmap(struct fb_cmap *cmap, + const struct fb_var_screeninfo *fb_var) +{ + __u32 len; + const struct fb_cmap *default_cmap; + int ret; + + len = max3(fb_var->red.length, + fb_var->green.length, + fb_var->blue.length); + if (!len || (len > 31)) { + DRM_ERROR("fbconv: Gamma LUT has invalid bit count of %u\n", + (unsigned int)len); + return -EINVAL; + } + + default_cmap = fb_default_cmap(1ul << len); + if (!default_cmap) { + DRM_ERROR("fbconv: fb_default_cmap() failed\n"); + return -EINVAL; + } + + ret = fb_alloc_cmap(cmap, default_cmap->len, 0); + if (ret) { + DRM_ERROR("fbconv: fb_alloc_cmap() failed: %d\n", ret); + return ret; + } + ret = fb_copy_cmap(default_cmap, cmap); + if (ret) { + DRM_ERROR("fbconv: fb_copy_cmap() failed: %d\n", ret); + goto err_fb_dealloc_cmap; + } + + return 0; + +err_fb_dealloc_cmap: + fb_dealloc_cmap(cmap); + return ret; +} + +/* provides a linear color ramp for RGB modes */ +static int create_linear_cmap(struct fb_cmap *cmap, + const struct fb_var_screeninfo *fb_var) +{ + int ret; + size_t i; + unsigned int j; + u16 *lut; + u16 incr; + u16 *gamma_lut[3]; + __u32 len; + const __u32 gamma_len[3] = { + fb_var->red.length, + fb_var->green.length, + fb_var->blue.length + }; + + len = max3(gamma_len[0], gamma_len[1], gamma_len[2]); + if (!len || (len > 8)) { + DRM_ERROR("fbconv: gamma LUT has invalid bit count of %u\n", + (unsigned int)len); + return -EINVAL; + } + + ret = fb_alloc_cmap(cmap, 1ul << len, 0); + if (ret) { + DRM_ERROR("fbconv: fb_alloc_cmap() failed: %d\n", ret); + return ret; + } + + gamma_lut[0] = cmap->red; + gamma_lut[1] = cmap->green; + gamma_lut[2] = cmap->blue; + + for (i = 0; i < ARRAY_SIZE(gamma_lut); ++i) { + lut = gamma_lut[i]; + len = 1ul << gamma_len[i]; + incr = 0x10000u >> gamma_len[i]; + for (j = 0; j < len; ++j, ++lut) + *lut = incr * j; + + /* In order to have no intensity at index 0 and full + * intensity at the final index of the LUT, we fix-up the + * table's final entries. The fix-up makes intensity grow + * faster near the final entries of the gamma LUT. The human + * eye is more sensitive to changes to the lower intensities, + * so this is probably not directly perceivable. + */ + for (lut -= gamma_len[i], j = gamma_len[i]; j > 0; ++lut) { + --j; + /* subtract 1 to not overflow the LUT's final entry */ + *lut += (incr >> j) - 1; + } + } + + return 0; +} + +static int set_cmap(struct fb_info *fb_info) +{ + struct fb_cmap cmap; + int ret; + + memset(&cmap, 0, sizeof(cmap)); + + switch (fb_info->fix.visual) { + case FB_VISUAL_PSEUDOCOLOR: + ret = create_palette_cmap(&cmap, &fb_info->var); + break; + case FB_VISUAL_DIRECTCOLOR: + ret = create_linear_cmap(&cmap, &fb_info->var); + break; + default: + return 0; + } + if (ret) + return ret; + + ret = fb_set_cmap(&cmap, fb_info); + if (ret) { + DRM_ERROR("fbconv: fb_set_cmap() failed: %d\n", ret); + goto err_fb_dealloc_cmap; + } + fb_dealloc_cmap(&cmap); + + return 0; + +err_fb_dealloc_cmap: + fb_dealloc_cmap(&cmap); + return ret; +} + /* * Simple display pipe */ +static void drm_fbconv_update_fb_var_screeninfo_from_crtc_state( + struct fb_var_screeninfo *fb_var, struct drm_crtc_state *crtc_state) +{ + drm_fbconv_update_fb_var_screeninfo_from_mode( + fb_var, &crtc_state->adjusted_mode); +} + +static int drm_fbconv_update_fb_var_screeninfo_from_framebuffer( + struct fb_var_screeninfo *fb_var, struct drm_framebuffer *fb, + size_t vram_size) +{ + unsigned int width, pitch; + uint64_t cpp, lines; + int ret; + + /* 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(). + */ + + width = fb->pitches[0]; + cpp = fb->format[0].cpp[0]; + do_div(width, cpp); + + if (width > (__u32)-1) + return -EINVAL; /* would overflow fb_var->xres_virtual */ + + pitch = fb->pitches[0]; + lines = vram_size; + do_div(lines, pitch); + + if (lines > (__u32)-1) + return -EINVAL; /* would overflow fb_var->yres_virtual */ + + fb_var->xres_virtual = width; + fb_var->yres_virtual = lines; + + ret = drm_fbconv_update_fb_var_screeninfo_from_format( + fb_var, fb->format[0].format); + if (ret) + return ret; + + return 0; +} + /** * drm_fbconv_simple_display_pipe_mode_valid - default implementation for * struct drm_simple_display_pipe_funcs.mode_valid @@ -767,6 +954,52 @@ bool drm_fbconv_simple_display_pipe_mode_fixup( } EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_mode_fixup); +/** + * drm_fbconv_blit_rect - copy an area of pixel data from a framebuffer + * to the hardware buffer + * @dst: the on-screen hardware buffer + * @vaddr: the source buffer in kernel address space + * @fb: the framebuffer of the source buffer + * @rect: the area to copy + * Returns: + * 0 on success, or + * a negative error code otherwise. + * + * This function copies the pixel data from a DRM framebuffer to a hardware + * buffer; doing necessary format conversion in the process. Not all + * combinations of source and destination formats are currently supported. + */ +int drm_fbconv_blit_rect(void *dst, void *vaddr, struct drm_framebuffer *fb, + struct drm_rect *rect) +{ + struct drm_device *dev = fb->dev; + + if (!vaddr) + return 0; /* no framebuffer set for plane; no error */ + + if (dev->mode_config.preferred_depth == (fb->format->cpp[0] * 8)) + drm_fb_memcpy_dstclip(dst, vaddr, fb, rect); + + else if (fb->format->cpp[0] == 4 && + dev->mode_config.preferred_depth == 16) + drm_fb_xrgb8888_to_rgb565_dstclip(dst, fb->pitches[0], + vaddr, fb, rect, false); + + else if (fb->format->cpp[0] == 4 && + dev->mode_config.preferred_depth == 24) + drm_fb_xrgb8888_to_rgb888_dstclip(dst, fb->pitches[0], + vaddr, fb, rect); + + else { + /* TODO: add the missing conversion */ + DRM_ERROR("fbconv: mismatching pixel formats\n"); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(drm_fbconv_blit_rect); + /** * drm_fbconv_simple_display_pipe_enable - default implementation for * struct drm_simple_display_pipe_funcs.enable @@ -803,6 +1036,100 @@ drm_fbconv_simple_display_pipe_check(struct drm_simple_display_pipe *pipe, struct drm_plane_state *plane_state, struct drm_crtc_state *crtc_state) { + struct drm_fbconv_modeset *modeset; + struct fb_videomode fb_mode, fb_var_mode; + int ret; + struct fb_var_screeninfo fb_var; + + /* + * CRTC check + */ + + modeset = drm_fbconv_modeset_of_pipe(pipe); + + /* DRM porting notes: when fbcon takes over the console, it regularly + * changes the display mode. Where's apparently no way to detect this + * directly from fbcon itself. DRM's mode information might therefore + * be out of data, after it takes over the display at a later time. + * Here, we test the CRTC's current mode with the fbdev state. If they + * do not match, we request a mode change from DRM. If you port an + * fbdev driver to DRM, you can remove this code section, DRM will + * be in full control of the display device and doesn't have to react + * to changes from external sources. + */ + + if (!crtc_state->mode_changed && crtc_state->adjusted_mode.clock) { + drm_fbconv_init_fb_videomode_from_mode( + &fb_mode, &crtc_state->adjusted_mode); + fb_var_to_videomode(&fb_var_mode, &modeset->fb_info->var); + if (!fb_mode_is_equal(&fb_mode, &fb_var_mode)) + crtc_state->mode_changed = true; + } + + /* TODO: The vblank interrupt is currently not supported. We set + * the corresponding flag as a workaround. Some fbdev drivers + * support FBIO_WAITFORVSYNC, which we might use for querying + * vblanks. + * + * DRM porting notes: if you're porting an fbdev driver to DRM, + * remove this line and instead signal a vblank event from the + * interrupt handler. + */ + crtc_state->no_vblank = true; + + /* + * Plane check + */ + + if (!plane_state->crtc) + return 0; + + ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, + 1 << 16, 1 << 16, + false, true); + if (ret < 0) + return ret; + + if (!plane_state->visible || !plane_state->fb) + return 0; + + /* Virtual screen sizes are not supported. + */ + + if (drm_rect_width(&plane_state->dst) != plane_state->fb->width || + drm_rect_height(&plane_state->dst) != plane_state->fb->height) { + DRM_ERROR("fbconv: virtual screen sizes not supported\n"); + return -EINVAL; + } + if (plane_state->dst.x1 || plane_state->dst.y1) { + DRM_ERROR("fbconv: virtual screen offset not supported\n"); + return -EINVAL; + } + + /* Pixel formats have to be compatible with fbdev. This is + * usually some variation of XRGB. + */ + + if (!pipe->plane.state || + !pipe->plane.state->fb || + pipe->plane.state->fb->format[0].format != + plane_state->fb->format[0].format) { + + if (modeset->fb_info->fbops->fb_check_var) { + memcpy(&fb_var, &modeset->fb_info->var, + sizeof(fb_var)); + drm_fbconv_update_fb_var_screeninfo_from_crtc_state( + &fb_var, crtc_state); + drm_fbconv_update_fb_var_screeninfo_from_framebuffer( + &fb_var, plane_state->fb, + modeset->fb_info->fix.smem_len); + ret = modeset->fb_info->fbops->fb_check_var( + &fb_var, modeset->fb_info); + if (ret < 0) + return ret; + } + } + return 0; } EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_check); @@ -816,7 +1143,119 @@ EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_check); void drm_fbconv_simple_display_pipe_update(struct drm_simple_display_pipe *pipe, struct drm_plane_state *old_plane_state) -{ } +{ + struct drm_fbconv_modeset *modeset; + uint32_t format; + struct fb_var_screeninfo fb_var; + int ret; + bool do_blit; + struct drm_rect rect; + struct drm_crtc *crtc = &pipe->crtc; + + /* + * Plane update + */ + + modeset = drm_fbconv_modeset_of_pipe(pipe); + + format = drm_fbconv_format_of_fb_info(modeset->fb_info); + + /* DRM porting notes: Some fbdev drivers report alpha channels for + * their framebuffer, even though they don't support transparent + * primary planes. For the format test below, we ignore the alpha + * channel and use the non-transparent equivalent of the pixel format. + * If you're porting an fbdev driver to DRM, remove this switch + * statement and report the correct format instead. + */ + switch (format) { + case DRM_FORMAT_ARGB8888: + format = DRM_FORMAT_XRGB8888; + break; + case DRM_FORMAT_ABGR8888: + format = DRM_FORMAT_XBGR8888; + break; + case DRM_FORMAT_RGBA8888: + format = DRM_FORMAT_RGBX8888; + break; + case DRM_FORMAT_BGRA8888: + format = DRM_FORMAT_BGRX8888; + break; + default: + break; + } + + if (!pipe->plane.state->fb) { + /* No framebuffer installed; blank display. */ + fb_blank(modeset->fb_info, FB_BLANK_NORMAL); + return; + } + + if ((format != pipe->plane.state->fb->format[0].format) || + (modeset->fb_info->var.xres_virtual != + pipe->plane.state->fb->width)) { + + /* Pixel format changed, update fb_info accordingly + */ + + memcpy(&fb_var, &modeset->fb_info->var, sizeof(fb_var)); + ret = drm_fbconv_update_fb_var_screeninfo_from_framebuffer( + &fb_var, pipe->plane.state->fb, + modeset->fb_info->fix.smem_len); + if (ret) + return; + + 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); + return; + } + } + + if (!old_plane_state->fb || /* first-time update */ + (format != pipe->plane.state->fb->format[0].format)) { + + /* DRM porting notes: Below we set the LUTs for palette and + * gamma correction. This is required by some fbdev drivers, + * such as nvidiafb and atyfb, which don't initialize the + * table to pass-through the framebuffer values unchanged. This + * is actually CRTC state, but the respective function + * crtc_helper_mode_set_nofb() is only called when a CRTC + * property changes, changes in color formats are not handled + * there. When you're porting a fbdev driver to DRM, remove + * the call. Gamma LUTs are CRTC properties and should be + * handled there. Either remove gamma correction or set up + * the respective CRTC properties for userspace. + */ + set_cmap(modeset->fb_info); + } + + memcpy(&fb_var, &modeset->fb_info->var, sizeof(fb_var)); + 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); + return; + } + + do_blit = drm_atomic_helper_damage_merged(old_plane_state, + pipe->plane.state, + &rect); + if (do_blit) + drm_fbconv_blit_rect(modeset->blit.screen_base, + modeset->blit.vmap, pipe->plane.state->fb, + &rect); + + if (crtc->state->event) { + spin_lock_irq(&crtc->dev->event_lock); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + crtc->state->event = NULL; + spin_unlock_irq(&crtc->dev->event_lock); + } +} EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_update); /** @@ -837,7 +1276,48 @@ EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_update); int drm_fbconv_simple_display_pipe_prepare_fb(struct drm_simple_display_pipe *pipe, struct drm_plane_state *plane_state) -{ } +{ + struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe); + struct fb_info *fb_info = modeset->fb_info; + struct drm_framebuffer *fb = plane_state->fb; + bool unmap_screen_base = false; + void *screen_base; + void *vmap; + int ret; + + if (!fb) + return 0; + + screen_base = fb_info->screen_base; + + if (!screen_base) { + screen_base = ioremap(fb_info->fix.smem_start, + fb_info->fix.smem_len); + if (!screen_base) { + DRM_ERROR("fbconv: ioremap() failed\n"); + return -ENOMEM; + } + unmap_screen_base = true; + } + + vmap = drm_gem_shmem_vmap(fb->obj[0]); + if (!vmap) { + DRM_ERROR("fbconv: drm_gem_shmem_vmap() failed\n"); + ret = -ENOMEM; + goto err_iounmap; + } + + modeset->blit.vmap = vmap; + modeset->blit.screen_base = screen_base; + modeset->blit.unmap_screen_base = unmap_screen_base; + + return 0; + +err_iounmap: + if (unmap_screen_base) + iounmap(screen_base); + return ret; +} EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_prepare_fb); /** @@ -853,7 +1333,21 @@ EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_prepare_fb); void drm_fbconv_simple_display_pipe_cleanup_fb(struct drm_simple_display_pipe *pipe, struct drm_plane_state *plane_state) -{ } +{ + struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe); + struct drm_framebuffer *fb = plane_state->fb; + + if (!fb) + return; + + drm_gem_shmem_vunmap(fb->obj[0], modeset->blit.vmap); + + if (modeset->blit.unmap_screen_base) + iounmap(modeset->blit.screen_base); + + memset(&modeset->blit, 0, sizeof(modeset->blit)); +} +EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_cleanup_fb); static const struct drm_simple_display_pipe_funcs simple_display_pipe_funcs = { .mode_valid = drm_fbconv_simple_display_pipe_mode_valid, diff --git a/include/drm/drm_fbconv_helper.h b/include/drm/drm_fbconv_helper.h index 79716af687c1..3e62b5e80af6 100644 --- a/include/drm/drm_fbconv_helper.h +++ b/include/drm/drm_fbconv_helper.h @@ -92,6 +92,9 @@ void drm_fbconv_simple_display_pipe_cleanup_fb(struct drm_simple_display_pipe *pipe, struct drm_plane_state *plane_state); +int drm_fbconv_blit_rect(void *dst, void *vaddr, struct drm_framebuffer *fb, + struct drm_rect *rect); + /* * Modeset helpers */ @@ -107,6 +110,12 @@ struct drm_fbconv_modeset { struct drm_connector connector; struct drm_simple_display_pipe pipe; + struct { + void *vmap; + void *screen_base; + bool unmap_screen_base; + } blit; + struct drm_device *dev; struct fb_info *fb_info; }; From patchwork Mon Oct 14 14:04:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 11188791 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 76E861922 for ; Mon, 14 Oct 2019 14:04:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5F82A20854 for ; Mon, 14 Oct 2019 14:04:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732450AbfJNOE1 (ORCPT ); Mon, 14 Oct 2019 10:04:27 -0400 Received: from mx2.suse.de ([195.135.220.15]:50960 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1732382AbfJNOE0 (ORCPT ); Mon, 14 Oct 2019 10:04:26 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 5F8F2B219; Mon, 14 Oct 2019 14:04:23 +0000 (UTC) From: Thomas Zimmermann 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: corbet@lwn.net, gregkh@linuxfoundation.org, dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH v2 09/15] drm/fbconv: Mode-setting pipeline enable / disable Date: Mon, 14 Oct 2019 16:04:10 +0200 Message-Id: <20191014140416.28517-10-tzimmermann@suse.de> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191014140416.28517-1-tzimmermann@suse.de> References: <20191014140416.28517-1-tzimmermann@suse.de> MIME-Version: 1.0 Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org The display mode is set by converting the DRM display mode to an fb_info state and handling it to the fbdev driver's fb_setvar() function. This also requires a color depth, which we take from the value of struct drm_mode_config.preferred_depth Signed-off-by: Thomas Zimmermann --- drivers/gpu/drm/drm_fbconv_helper.c | 113 +++++++++++++++++++++++++++- include/drm/drm_fbconv_helper.h | 2 + 2 files changed, 113 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c index cf218016ac05..ca8b43c91266 100644 --- a/drivers/gpu/drm/drm_fbconv_helper.c +++ b/drivers/gpu/drm/drm_fbconv_helper.c @@ -919,6 +919,24 @@ static int drm_fbconv_update_fb_var_screeninfo_from_framebuffer( return 0; } +static int drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe( + struct fb_var_screeninfo *fb_var, struct drm_simple_display_pipe *pipe) +{ + struct drm_plane *primary = pipe->crtc.primary; + struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe); + + if (primary && primary->state && primary->state->fb) + return drm_fbconv_update_fb_var_screeninfo_from_framebuffer( + fb_var, primary->state->fb, + modeset->fb_info->fix.smem_len); + + fb_var->xres_virtual = fb_var->xres; + fb_var->yres_virtual = fb_var->yres; + fb_var->bits_per_pixel = modeset->dev->mode_config.preferred_depth; + + return 0; +} + /** * drm_fbconv_simple_display_pipe_mode_valid - default implementation for * struct drm_simple_display_pipe_funcs.mode_valid @@ -950,6 +968,28 @@ bool drm_fbconv_simple_display_pipe_mode_fixup( struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { + struct drm_simple_display_pipe *pipe = + container_of(crtc, struct drm_simple_display_pipe, crtc); + struct drm_fbconv_modeset *modeset = drm_fbconv_modeset_of_pipe(pipe); + struct fb_var_screeninfo fb_var; + int ret; + + if (!modeset->fb_info->fbops->fb_check_var) + return true; + + drm_fbconv_init_fb_var_screeninfo_from_mode(&fb_var, mode); + + ret = drm_fbconv_update_fb_var_screeninfo_from_simple_display_pipe( + &fb_var, &modeset->pipe); + if (ret) + return true; + + ret = modeset->fb_info->fbops->fb_check_var(&fb_var, modeset->fb_info); + if (ret < 0) + return false; + + drm_mode_update_from_fb_var_screeninfo(adjusted_mode, &fb_var); + return true; } EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_mode_fixup); @@ -1000,6 +1040,32 @@ int drm_fbconv_blit_rect(void *dst, void *vaddr, struct drm_framebuffer *fb, } EXPORT_SYMBOL(drm_fbconv_blit_rect); +/** + * drm_fbconv_blit_fullscreen - copy all pixel data from a framebuffer + * to the hardware buffer + * @dst: the on-screen hardware buffer + * @vaddr: the source buffer in kernel address space + * @fb: the framebuffer of the source buffer + * Returns: + * 0 on success, or + * a negative error code otherwise. + * + * This function is equivalent to drm_fbconv_blit_rect(), but copies the + * framebuffer's complete content. + */ +int drm_fbconv_blit_fullscreen(void *dst, void *vaddr, + struct drm_framebuffer *fb) +{ + struct drm_rect fullscreen = { + .x1 = 0, + .x2 = fb->width, + .y1 = 0, + .y2 = fb->height, + }; + return drm_fbconv_blit_rect(dst, vaddr, fb, &fullscreen); +} +EXPORT_SYMBOL(drm_fbconv_blit_fullscreen); + /** * drm_fbconv_simple_display_pipe_enable - default implementation for * struct drm_simple_display_pipe_funcs.enable @@ -1011,7 +1077,46 @@ void drm_fbconv_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe, struct drm_crtc_state *crtc_state, struct drm_plane_state *plane_state) -{ } +{ + struct drm_fbconv_modeset *modeset; + struct fb_var_screeninfo fb_var; + int ret; + + /* As this is atomic mode setting, any function call is not + * allowed to fail. If it does, an additional test should be + * added to simple_display_pipe_check(). + */ + + modeset = drm_fbconv_modeset_of_pipe(pipe); + + drm_fbconv_init_fb_var_screeninfo_from_mode( + &fb_var, &crtc_state->adjusted_mode); + + if (plane_state && plane_state->fb) { + ret = drm_fbconv_update_fb_var_screeninfo_from_framebuffer( + &fb_var, plane_state->fb, + modeset->fb_info->fix.smem_len); + if (ret) + return; + } else { + fb_var.xres_virtual = fb_var.xres; + fb_var.yres_virtual = fb_var.yres; + } + + 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); + return; + } + + fb_blank(modeset->fb_info, FB_BLANK_UNBLANK); + + drm_fbconv_blit_fullscreen(modeset->blit.screen_base, + modeset->blit.vmap, + plane_state->fb); +} EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_enable); /** @@ -1021,7 +1126,11 @@ EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_enable); */ void 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); +} EXPORT_SYMBOL(drm_fbconv_simple_display_pipe_disable); /** diff --git a/include/drm/drm_fbconv_helper.h b/include/drm/drm_fbconv_helper.h index 3e62b5e80af6..c7d211f40462 100644 --- a/include/drm/drm_fbconv_helper.h +++ b/include/drm/drm_fbconv_helper.h @@ -94,6 +94,8 @@ drm_fbconv_simple_display_pipe_cleanup_fb(struct drm_simple_display_pipe *pipe, int drm_fbconv_blit_rect(void *dst, void *vaddr, struct drm_framebuffer *fb, struct drm_rect *rect); +int drm_fbconv_blit_fullscreen(void *dst, void *vaddr, + struct drm_framebuffer *fb); /* * Modeset helpers From patchwork Mon Oct 14 14:04:11 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 11188789 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 570A218A6 for ; Mon, 14 Oct 2019 14:04:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 42FE520854 for ; Mon, 14 Oct 2019 14:04:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732449AbfJNOE0 (ORCPT ); Mon, 14 Oct 2019 10:04:26 -0400 Received: from mx2.suse.de ([195.135.220.15]:51034 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1732441AbfJNOE0 (ORCPT ); Mon, 14 Oct 2019 10:04:26 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id CFC80B206; Mon, 14 Oct 2019 14:04:23 +0000 (UTC) From: Thomas Zimmermann 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: corbet@lwn.net, gregkh@linuxfoundation.org, dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH v2 10/15] drm/fbconv: Reimplement several fbdev interfaces Date: Mon, 14 Oct 2019 16:04:11 +0200 Message-Id: <20191014140416.28517-11-tzimmermann@suse.de> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191014140416.28517-1-tzimmermann@suse.de> References: <20191014140416.28517-1-tzimmermann@suse.de> MIME-Version: 1.0 Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org 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 --- 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, From patchwork Mon Oct 14 14:04:12 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 11188787 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1E90C17E6 for ; Mon, 14 Oct 2019 14:04:27 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 09BBF2083B for ; Mon, 14 Oct 2019 14:04:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732339AbfJNOE0 (ORCPT ); Mon, 14 Oct 2019 10:04:26 -0400 Received: from mx2.suse.de ([195.135.220.15]:51084 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1732444AbfJNOE0 (ORCPT ); Mon, 14 Oct 2019 10:04:26 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 51359B25A; Mon, 14 Oct 2019 14:04:24 +0000 (UTC) From: Thomas Zimmermann 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: corbet@lwn.net, gregkh@linuxfoundation.org, dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH v2 11/15] drm/fbconv: Add helpers for init and cleanup of fb_info structures Date: Mon, 14 Oct 2019 16:04:12 +0200 Message-Id: <20191014140416.28517-12-tzimmermann@suse.de> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191014140416.28517-1-tzimmermann@suse.de> References: <20191014140416.28517-1-tzimmermann@suse.de> MIME-Version: 1.0 Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org The implementation of drm_fbconv_fill_fb_info() sets up an fbdev driver's fb_info structure for use. It's similar to register_framebuffer(), but does not create device files, register the driver with the fbdev code or create a console. drm_fbconv_cleanup_fb_info() does the inverse. Signed-off-by: Thomas Zimmermann --- drivers/gpu/drm/drm_fbconv_helper.c | 123 ++++++++++++++++++++++++++++ include/drm/drm_fbconv_helper.h | 7 ++ 2 files changed, 130 insertions(+) diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c index f7f247e30a3d..7d7e4da2a29e 100644 --- a/drivers/gpu/drm/drm_fbconv_helper.c +++ b/drivers/gpu/drm/drm_fbconv_helper.c @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -1722,6 +1723,9 @@ int drm_fbconv_modeset_init(struct drm_fbconv_modeset *modeset, { struct drm_mode_config *mode_config = &dev->mode_config; + if (WARN_ON(fb_info->node != FB_MAX)) + return -EINVAL; /* forgot to run drm_fbconv_fill_fb_info()? */ + modeset->dev = dev; modeset->fb_info = fb_info; @@ -1820,3 +1824,122 @@ drm_fbconv_modeset_setup_pipe(struct drm_fbconv_modeset *modeset, return 0; } EXPORT_SYMBOL(drm_fbconv_modeset_setup_pipe); + +/* + * Helpers for struct fb_info + * + * This is the setup and cleanup code for struct fb_info. It has been + * adapted from the fbdev core modules. + * + * The original implementation in fbdev also handles device files, console, + * and framebuffer events. As DRM drivers use DRM's framebuffer emulation, + * the respective code has been removed here. + * + * In contrast to the fbdev core, we don't need locking here. These don't + * interact with fbdev's internal state. + */ + +static bool is_matroxfb(const struct fb_info *fb_info) +{ + return !!(fb_info->fix.accel & (FB_ACCEL_MATROX_MGA2064W | + FB_ACCEL_MATROX_MGA1064SG | + FB_ACCEL_MATROX_MGA2164W | + FB_ACCEL_MATROX_MGA2164W_AGP | + FB_ACCEL_MATROX_MGAG100 | + FB_ACCEL_MATROX_MGAG200 | + FB_ACCEL_MATROX_MGAG400)); +} + +/** + * drm_fbconv_fill_fb_info - prepares an fbdev driver's fb_info structure + * for use + * @fb_info: the fb_info structure to set up + * Returns: + * 0 on success, or + * a negative error code otherwise. + * + * The fbdev driver provides fbconv helpers with an fb_info structure. Before + * use, the structure has to be set up correctly. In fbdev core, + * register_framebuffer() does this; here it's provided by + * drm_fbconv_fill_fb_info(). + * + * Call drm_fbconv_cleanup_fb_info() during shutdown to clean up the fb_info + * structure. + */ +int drm_fbconv_fill_fb_info(struct fb_info *fb_info) +{ + struct fb_videomode mode; + + /* Returing -ENOSYS on error is technically wrong, but it's + * what the fbdev core code would do. So we do the same. + */ + if (fb_check_foreignness(fb_info)) + return -ENOSYS; + + fb_info->node = FB_MAX; /* not registered; filled by fbconv helpers */ + atomic_set(&fb_info->count, 1); + mutex_init(&fb_info->lock); + mutex_init(&fb_info->mm_lock); + + fb_info->dev = NULL; /* device file not needed for fbconv. */ + + if (fb_info->pixmap.addr == NULL) { + fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL); + if (fb_info->pixmap.addr) { + fb_info->pixmap.size = FBPIXMAPSIZE; + fb_info->pixmap.buf_align = 1; + fb_info->pixmap.scan_align = 1; + fb_info->pixmap.access_align = 32; + fb_info->pixmap.flags = FB_PIXMAP_DEFAULT; + } + } + fb_info->pixmap.offset = 0; + + if (!fb_info->pixmap.blit_x) + fb_info->pixmap.blit_x = ~(u32)0; + + if (!fb_info->pixmap.blit_y) + fb_info->pixmap.blit_y = ~(u32)0; + + if (!fb_info->modelist.prev || !fb_info->modelist.next) + INIT_LIST_HEAD(&fb_info->modelist); + + fb_var_to_videomode(&mode, &fb_info->var); + fb_add_videomode(&mode, &fb_info->modelist); + + /* matroxfb: Requries a call to fb_set_par() to initialize + * fbinfo->fix.{smem_start,smem_len}. Otherwise, we won't be + * able to initialize framebuffer memory management. + */ + if (is_matroxfb(fb_info)) { + if (fb_info->fbops->fb_set_par) + fb_info->fbops->fb_set_par(fb_info); + } + + return 0; +} +EXPORT_SYMBOL(drm_fbconv_fill_fb_info); + +/** + * drm_fbconv_cleanup_fb_info - cleans up an fbdev driver's fb_info structure + * after use + * @fb_info: the fb_info structure to clean up + */ +void drm_fbconv_cleanup_fb_info(struct fb_info *fb_info) +{ + if (fb_info->node != FB_MAX) + return; + + if (fb_info->pixmap.addr && + (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) + kfree(fb_info->pixmap.addr); + + fb_destroy_modelist(&fb_info->modelist); + + if (!atomic_dec_and_test(&fb_info->count)) + return; + + if (fb_info->fbops->fb_destroy) + fb_info->fbops->fb_destroy(fb_info); +} +EXPORT_SYMBOL(drm_fbconv_cleanup_fb_info); diff --git a/include/drm/drm_fbconv_helper.h b/include/drm/drm_fbconv_helper.h index c7d211f40462..23d17ad14b81 100644 --- a/include/drm/drm_fbconv_helper.h +++ b/include/drm/drm_fbconv_helper.h @@ -140,4 +140,11 @@ int drm_fbconv_modeset_setup_pipe( const uint32_t *formats, unsigned int format_count, const uint64_t *format_modifiers, struct drm_connector *connector); +/* + * Helpers for struct fb_info + */ + +int drm_fbconv_fill_fb_info(struct fb_info *fb_info); +void drm_fbconv_cleanup_fb_info(struct fb_info *fb_info); + #endif From patchwork Mon Oct 14 14:04:13 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 11188793 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 51C1018A6 for ; Mon, 14 Oct 2019 14:04:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 34C3521835 for ; Mon, 14 Oct 2019 14:04:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732382AbfJNOE2 (ORCPT ); Mon, 14 Oct 2019 10:04:28 -0400 Received: from mx2.suse.de ([195.135.220.15]:51130 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1732445AbfJNOE1 (ORCPT ); Mon, 14 Oct 2019 10:04:27 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id BEA72B255; Mon, 14 Oct 2019 14:04:24 +0000 (UTC) From: Thomas Zimmermann 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: corbet@lwn.net, gregkh@linuxfoundation.org, dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH v2 12/15] drm/fbconv: Add helper documentation Date: Mon, 14 Oct 2019 16:04:13 +0200 Message-Id: <20191014140416.28517-13-tzimmermann@suse.de> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191014140416.28517-1-tzimmermann@suse.de> References: <20191014140416.28517-1-tzimmermann@suse.de> MIME-Version: 1.0 Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org There's now a tutorial on how to create a DRM driver on top of fbconv helpers. The DRM TODO list contains an entry for converting fbdev drivers over to DRM. Signed-off-by: Thomas Zimmermann --- Documentation/gpu/drm-kms-helpers.rst | 12 ++ Documentation/gpu/todo.rst | 15 +++ drivers/gpu/drm/drm_fbconv_helper.c | 181 ++++++++++++++++++++++++++ 3 files changed, 208 insertions(+) diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index 9668a7fe2408..1232a3ef24ff 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -411,3 +411,15 @@ SHMEM GEM Helper Reference .. kernel-doc:: drivers/gpu/drm/drm_gem_shmem_helper.c :export: + +fbdev Conversion Helper Reference +================================= + +.. kernel-doc:: drivers/gpu/drm/drm_fbconv_helper.c + :doc: fbconv helpers + +.. kernel-doc:: include/drm/drm_fbconv_helper.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_fbconv_helper.c + :export: diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 79785559d711..1be44a17f3e8 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -462,3 +462,18 @@ Contact: Sam Ravnborg Outside DRM =========== + +Convert fbdev drivers to DRM +---------------------------- + +There are plenty of fbdev drivers for old hardware. With fbconv helpers, we +have a simple and clean way of transitioning fbdev drivers to DRM. Set up a +simple DRM driver that builds onto the fbconv helpers, copy over the fbdev +driver and connect both. This should result in a basic DRM driver that can +run X11 and Weston. There's a tutorial for this process with example source +code in the fbconv documentation. + +From there, refactor the driver source code into a clean DRM driver that +requires neither fbdev nor fbconv helpers. + +Contact: Thomas Zimmermann diff --git a/drivers/gpu/drm/drm_fbconv_helper.c b/drivers/gpu/drm/drm_fbconv_helper.c index 7d7e4da2a29e..1fa240a4789f 100644 --- a/drivers/gpu/drm/drm_fbconv_helper.c +++ b/drivers/gpu/drm/drm_fbconv_helper.c @@ -18,6 +18,187 @@ #include #include +/** + * DOC: fbconv helpers + * + * The Linux kernel's fbdev subsystem provides a wide range of drivers for + * older graphics hardware. Except for these existng drivers, fbdev is + * deprecated and expected to be removed at some point in the future. All new + * development happens in DRM. Some of the fbdev drivers are worth carrying + * forward. The fbconv helper functions provide a framework for porting fbdev + * drivers to DRM. + * + * When porting over fbdev drivers to DRM, the most significant problem is the + * difference in how the internal driver interfaces work. Fbdev has a single + * function, struct fb_ops.fb_set_par(), to set video mode and framebuffer + * format. DRM use a much more fine-grained interface. In fbdev, framebuffer + * memory is managed by a single client, while in DRM multiple clients can + * hold buffers with framebuffer data. + * + * The fbconv helper library provides a set of data structures and functions + * that connect DRM and fbdev. The resulting DRM driver maps DRM operations + * to fbdev interfaces and uses an fbdev driver for its hardware operations. + * Such a driver is not intended to be merged into DRM as-is. It does, + * however, provide a starting point for refactoring the fbdev driver's + * implementation into first-class DRM code. + * + * As an example, we create a DRM driver from vesafb, fbdev's generic + * vesa driver. We begin by creating a DRM stub driver vesadrm. Please keep + * in mind that the provided code is for illustrative purposes and requires + * error handling. + * + * .. code-block:: c + * + * DEFINE_DRM_GEM_SHMEM_FOPS(vesadrm_file_operations); + * + * static struct drm_driver vesadrm_driver = { + * .major = 1, + * .minor = 0, + * .patchlevel = 0, + * .name = "vesadrm", + * .desc = "DRM VESA driver", + * .date = "01/01/1970", + * .driver_features = DRIVER_ATOMIC | + * DRIVER_GEM | + * DRIVER_MODESET, + * .fops = &vesadrm_file_operations, + * DRM_GEM_SHMEM_DRIVER_OPS, + * }; + * + * Fbconv uses SHMEM, so we set up the structures accordingly. + * + * The fbdev code usually calls register_framebuffer() and + * unregister_framebuffer() to connect and disconnect itself to the fbdev + * core code. In our case, we replace these calls with + * vesadrm_register_framebuffer() and vesadrm_unregister_framebuffer(), which + * serve as entry points for vesafb. + * + * .. code-block:: c + * + * #include + * + * struct vesadrm_device { + * struct drm_device dev; + * struct fb_info *fb_info; + * + * struct drm_fbconv_modeset modeset; + * }; + * + * struct vesadrm_device* vesadrm_register_framebuffer(struct fb_info *fb_info) + * { + * struct vesadrm *vdev; + * + * drm_fbconv_fill_fb_info(fb_info); + * + * vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); + * vesadrm_device_init(vdev, &vesadrm_driver, fb_info) + * + * drm_dev_register(&vdev->dev, 0); + * + * return vdev; + * } + * + * Here, we have the first references to fbconf helpers. The instance + * of struct drm_fbconv_modeset is the central data structure for fbconv. + * Built upon struct drm_simple_display_pipe, it stores most state for the + * DRM driver. + * + * The function vesadrm_register_framebuffer() will later be called by + * vesafb code with the fbdev driver's fb_info structure. In core fbdev, + * register_framebuffer() would fill fb_info with general state and complete + * registration. With fbconv helpers, drm_fbconv_fill_fb_info() does this. + * It's a simplified version of the fbdev setup process, without device file + * creation, registration, or events. No console is created either. + * Finally vesadrm_register_framebuffer() initializes the vesadrm device and + * registers the DRM device. At this point, vesadrm is completely initialized. + * + * For completeness, here's the implementation of + * vesadrm_unregister_framebuffer(), which shuts the device down. + * + * .. code-block:: c + * + * void vesadrm_unregister_framebuffer(struct vesadrm_device *vdev) + * { + * struct fb_info *fb_info = vdev->fb_info; + * + * vesadrm_device_cleanup(vdev); + * kfree(vdev); + * drm_fbconv_cleanup_fb_info(fb_info); + * } + * + * Next we need an implementation of vesadrm_device_init() and + * vesadrm_device_cleanup(). These functions handle the details of + * device configuration and console setup. As all this functionality + * is provided by helpers, the actual implementation is fairly small. + * + * .. code-block:: c + * + * static int vesadrm_device_init(struct vesadrm_device *vdev, + * struct drm_driver *drv, + * struct fb_info *fb_info) + * { + * static const uint32_t formats[] = { + * DRM_FORMAT_XRGB8888, + * DRM_FORMAT_RGB565 + * }; + * static unsigned int max_width = 1600; + * static unsigned int max_height = 1200; + * static unsigned int preferred_depth = 32; + * + * drm_dev_init(&vdev->dev, drv, fb_info->device); + * + * vdev->dev.dev_private = vdev; + * vdev->dev.pdev = container_of(fb_info->device, struct pci_dev, dev); + * vdev->fb_info = fb_info; + * + * drm_fbconv_modeset_init(&vdev->modeset, &vdev->dev, fb_info, + * max_width, max_height, preferred_depth); + * + * drm_fbconv_modeset_setup_pipe(&vdev->modeset, NULL, formats, + * ARRAY_SIZE(formats), NULL, NULL); + * + * drm_fbdev_generic_setup(&vdev->dev, 0); + * + * return 0; + * } + * + * static void vesadrm_device_cleanup(struct vesadrm_device *vdev) + * { + * struct drm_device *dev = &vdev->dev; + * + * drm_fbconv_modeset_cleanup(&vdev->modeset); + * + * drm_dev_fini(dev); + * dev->dev_private = NULL; + * } + * + * In vesadrm_device_init(), several device-specific constants are declared. + * Depending on the hardware, drivers should set them accordingly. + * The call to drm_fbconv_modeset_init() initializes fbconv modesetting + * helpers with these device constants. + * + * The drm_fbconv_modeset_setup_pipe() creates the simple display pipe with + * the specified color formats. By default, everything is set up + * automatically. But the function also accepts format modifiers, a DRM + * connector, and call-back functions for struct drm_simple_display_pipe. + * So each of these can be refactored individually later on. + * + * After setting up the fbconv helpers, there's is a call to + * drm_fbdev_generic_setup(), which set an initial mode and creates a + * framebuffer console. + * + * The implementation of vesadrm_device_cleanup() is the inverse of the + * init function. It cleans up the fbconv modesetting helper and releases + * the DRM device. + * + * What is left is connecting vesafb to vesadrm. As a first step, we need a + * copy the vesafb source files into the vesadrm driver and make them compile. + * Once this is done, we have to replace the call to register_framebuffer() + * with a call to vesadrm_register_framebuffer(), and unregister_framebuffer() + * with vesadrm_unregister_framebuffer(). We have now disconnected vesafb from + * the fbdev core and run it as part of DRM. + */ + /* * Format conversion helpers */ From patchwork Mon Oct 14 14:04:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 11188795 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DD76417E6 for ; Mon, 14 Oct 2019 14:04:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C098F21721 for ; Mon, 14 Oct 2019 14:04:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732452AbfJNOE2 (ORCPT ); Mon, 14 Oct 2019 10:04:28 -0400 Received: from mx2.suse.de ([195.135.220.15]:50858 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1732434AbfJNOE2 (ORCPT ); Mon, 14 Oct 2019 10:04:28 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 4320AAF92; Mon, 14 Oct 2019 14:04:25 +0000 (UTC) From: Thomas Zimmermann 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: corbet@lwn.net, gregkh@linuxfoundation.org, dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH v2 13/15] staging: Add mgakms driver Date: Mon, 14 Oct 2019 16:04:14 +0200 Message-Id: <20191014140416.28517-14-tzimmermann@suse.de> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191014140416.28517-1-tzimmermann@suse.de> References: <20191014140416.28517-1-tzimmermann@suse.de> MIME-Version: 1.0 Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org The mgakms driver uses DRM's fbconv helpers to provide a DRM driver for Matrox chipsets. This will allow matroxfb to be refactored into a first-class DRM driver. Signed-off-by: Thomas Zimmermann --- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/mgakms/Kconfig | 13 +++ drivers/staging/mgakms/Makefile | 6 ++ drivers/staging/mgakms/mga_device.c | 68 +++++++++++++++ drivers/staging/mgakms/mga_device.h | 30 +++++++ drivers/staging/mgakms/mga_drv.c | 129 ++++++++++++++++++++++++++++ drivers/staging/mgakms/mga_drv.h | 14 +++ 8 files changed, 263 insertions(+) create mode 100644 drivers/staging/mgakms/Kconfig create mode 100644 drivers/staging/mgakms/Makefile create mode 100644 drivers/staging/mgakms/mga_device.c create mode 100644 drivers/staging/mgakms/mga_device.h create mode 100644 drivers/staging/mgakms/mga_drv.c create mode 100644 drivers/staging/mgakms/mga_drv.h diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 6f1fa4c849a1..fd25596813c5 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -125,4 +125,6 @@ source "drivers/staging/exfat/Kconfig" source "drivers/staging/qlge/Kconfig" +source "drivers/staging/mgakms/Kconfig" + endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index a90f9b308c8d..4c98b028ee99 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -53,3 +53,4 @@ obj-$(CONFIG_UWB) += uwb/ obj-$(CONFIG_USB_WUSB) += wusbcore/ obj-$(CONFIG_EXFAT_FS) += exfat/ obj-$(CONFIG_QLGE) += qlge/ +obj-$(CONFIG_DRM_MGAKMS) += mgakms/ diff --git a/drivers/staging/mgakms/Kconfig b/drivers/staging/mgakms/Kconfig new file mode 100644 index 000000000000..de23e76317bd --- /dev/null +++ b/drivers/staging/mgakms/Kconfig @@ -0,0 +1,13 @@ +config DRM_MGAKMS + tristate "Matrox g200/g400" + depends on DRM && PCI + select DRM_FBCONV_HELPER + select DRM_GEM_SHMEM_HELPER + select DRM_KMS_HELPER + help + Choose this option if you have a Matrox Millennium, + Matrox Millennium II, Matrox Mystique, Matrox Mystique 220, + Matrox Productiva G100, Matrox Mystique G200, + Matrox Millennium G200, Matrox Marvel G200 video, Matrox G400, + G450 or G550 card. If M is selected, the module will be called mga. + AGP support is required for this driver to work. diff --git a/drivers/staging/mgakms/Makefile b/drivers/staging/mgakms/Makefile new file mode 100644 index 000000000000..65695f04eb7f --- /dev/null +++ b/drivers/staging/mgakms/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 + +mgakms-y := mga_device.o \ + mga_drv.o + +obj-$(CONFIG_DRM_MGAKMS) += mgakms.o diff --git a/drivers/staging/mgakms/mga_device.c b/drivers/staging/mgakms/mga_device.c new file mode 100644 index 000000000000..34b3bb1ed8a5 --- /dev/null +++ b/drivers/staging/mgakms/mga_device.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +#include +#include +#include + +#include "mga_device.h" + +/* + * struct mga_device + */ + +int mga_device_init(struct mga_device *mdev, struct drm_driver *drv, + struct fb_info *fb_info) +{ + static const uint32_t formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_RGB565 + }; + static unsigned int max_width = 2048; + static unsigned int max_height = 2048; + static unsigned int preferred_depth = 32; + + int ret; + + ret = drm_dev_init(&mdev->dev, drv, fb_info->device); + if (ret) + return ret; + mdev->dev.dev_private = mdev; + mdev->dev.pdev = container_of(fb_info->device, struct pci_dev, dev); + mdev->fb_info = fb_info; + + ret = drm_fbconv_modeset_init(&mdev->modeset, &mdev->dev, fb_info, + max_width, max_height, preferred_depth); + if (ret) + goto err_drm_dev_fini; + + ret = drm_fbconv_modeset_setup_pipe(&mdev->modeset, NULL, formats, + ARRAY_SIZE(formats), NULL, NULL); + if (ret) + goto err_drm_fbconv_modeset_cleanup; + + ret = drm_fbdev_generic_setup(&mdev->dev, 0); + if (ret) + goto err_drm_fbconv_modeset_cleanup; + + return 0; + +err_drm_fbconv_modeset_cleanup: + /* cleans up all mode-setting structures */ + drm_fbconv_modeset_cleanup(&mdev->modeset); +err_drm_dev_fini: + drm_dev_fini(&mdev->dev); + return ret; +} + +void mga_device_cleanup(struct mga_device *mdev) +{ + struct drm_device *dev = &mdev->dev; + + drm_fbconv_modeset_cleanup(&mdev->modeset); + + drm_dev_fini(dev); + dev->dev_private = NULL; +} diff --git a/drivers/staging/mgakms/mga_device.h b/drivers/staging/mgakms/mga_device.h new file mode 100644 index 000000000000..442effbf37bc --- /dev/null +++ b/drivers/staging/mgakms/mga_device.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef MGA_DEVICE_H +#define MGA_DEVICE_H + +#include + +#include +#include + +struct drm_driver; +struct fb_info; + +struct mga_device { + struct drm_device dev; + struct fb_info *fb_info; + + struct drm_fbconv_modeset modeset; +}; + +static inline struct mga_device *mga_device_of_dev(struct drm_device *dev) +{ + return container_of(dev, struct mga_device, dev); +} + +int mga_device_init(struct mga_device *mdev, struct drm_driver *drv, + struct fb_info *fb_info); +void mga_device_cleanup(struct mga_device *mdev); + +#endif diff --git a/drivers/staging/mgakms/mga_drv.c b/drivers/staging/mgakms/mga_drv.c new file mode 100644 index 000000000000..75e26d3046f3 --- /dev/null +++ b/drivers/staging/mgakms/mga_drv.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "mga_device.h" +#include "mga_drv.h" + +#define DRIVER_AUTHOR "Thomas Zimmermann " +#define DRIVER_NAME "mgakms" +#define DRIVER_DESCRIPTION "DRM driver for Matrox graphics chipsets" +#define DRIVER_LICENSE "GPL" +#define DRIVER_DATE "20190301" +#define DRIVER_MAJOR 0 +#define DRIVER_MINOR 0 +#define DRIVER_PATCHLEVEL 1 + +/* + * DRM driver + */ + +DEFINE_DRM_GEM_SHMEM_FOPS(mga_file_operations); + +static struct drm_driver mga_driver = { + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, + .name = DRIVER_NAME, + .desc = DRIVER_DESCRIPTION, + .date = DRIVER_DATE, + .driver_features = DRIVER_ATOMIC | + DRIVER_GEM | + DRIVER_MODESET, + .fops = &mga_file_operations, + DRM_GEM_SHMEM_DRIVER_OPS, +}; + +static void mga_remove_conflicting_framebuffers(struct pci_dev *pdev) +{ + struct apertures_struct *ap; + bool primary = false; + + ap = alloc_apertures(1); + if (!ap) + return; + + ap->ranges[0].base = pci_resource_start(pdev, 1); + ap->ranges[0].size = pci_resource_len(pdev, 1); + +#ifdef CONFIG_X86 + primary = pdev->resource[PCI_ROM_RESOURCE].flags & + IORESOURCE_ROM_SHADOW; +#endif + drm_fb_helper_remove_conflicting_framebuffers(ap, DRIVER_NAME, + primary); + kfree(ap); +} + +static struct mga_device *mga_create_device(struct fb_info *fb_info) +{ + struct mga_device *mdev; + int ret; + + mdev = devm_kzalloc(fb_info->device, sizeof(*mdev), GFP_KERNEL); + if (!mdev) + return ERR_PTR(-ENOMEM); + ret = mga_device_init(mdev, &mga_driver, fb_info); + if (ret) + goto err_devm_kfree; + return mdev; + +err_devm_kfree: + devm_kfree(fb_info->device, mdev); + return ERR_PTR(ret); +} + +static void mga_destroy_device(struct mga_device *mdev) +{ + struct device *dev = mdev->fb_info->device; + + mga_device_cleanup(mdev); + devm_kfree(dev, mdev); +} + +struct mga_device *mga_register_framebuffer(struct fb_info *fb_info, + struct pci_dev *pdev) +{ + int ret; + struct mga_device *mdev; + + mga_remove_conflicting_framebuffers(pdev); + + ret = drm_fbconv_fill_fb_info(fb_info); + if (ret) + return ERR_PTR(ret); + + mdev = mga_create_device(fb_info); + if (IS_ERR(mdev)) { + ret = PTR_ERR(mdev); + goto err_drm_fbconv_cleanup_fb_info; + } + + ret = drm_dev_register(&mdev->dev, 0); + if (ret) + goto err_mga_destroy_device; + + return mdev; + +err_mga_destroy_device: + mga_destroy_device(mdev); +err_drm_fbconv_cleanup_fb_info: + drm_fbconv_cleanup_fb_info(fb_info); + return ERR_PTR(ret); +} + +void mga_unregister_framebuffer(struct mga_device *mdev) +{ + struct fb_info *fb_info = mdev->fb_info; + + mga_destroy_device(mdev); + drm_fbconv_cleanup_fb_info(fb_info); +} diff --git a/drivers/staging/mgakms/mga_drv.h b/drivers/staging/mgakms/mga_drv.h new file mode 100644 index 000000000000..d214719516c0 --- /dev/null +++ b/drivers/staging/mgakms/mga_drv.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef MGA_DRV_H +#define MGA_DRV_H + +struct fb_info; +struct mga_device; +struct pci_dev; + +struct mga_device *mga_register_framebuffer(struct fb_info *fb_info, + struct pci_dev *pdev); +void mga_unregister_framebuffer(struct mga_device *mdev); + +#endif From patchwork Mon Oct 14 14:04:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 11188799 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6C7B817D4 for ; Mon, 14 Oct 2019 14:04:30 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 4705C2083B for ; Mon, 14 Oct 2019 14:04:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732362AbfJNOEa (ORCPT ); Mon, 14 Oct 2019 10:04:30 -0400 Received: from mx2.suse.de ([195.135.220.15]:50860 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1732441AbfJNOE3 (ORCPT ); Mon, 14 Oct 2019 10:04:29 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id A17C5AF9F; Mon, 14 Oct 2019 14:04:26 +0000 (UTC) From: Thomas Zimmermann 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: corbet@lwn.net, gregkh@linuxfoundation.org, dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org, Thomas Zimmermann Subject: [PATCH v2 15/15] staging/mgakms: Update matroxfb driver code for DRM Date: Mon, 14 Oct 2019 16:04:16 +0200 Message-Id: <20191014140416.28517-16-tzimmermann@suse.de> X-Mailer: git-send-email 2.23.0 In-Reply-To: <20191014140416.28517-1-tzimmermann@suse.de> References: <20191014140416.28517-1-tzimmermann@suse.de> MIME-Version: 1.0 Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org With the update, all driver code coming from matroxfb is build unconditionally. The driver registers itself with the mgakms driver, instead of the fbdev core. Signed-off-by: Thomas Zimmermann --- drivers/staging/mgakms/Kconfig | 5 ++ drivers/staging/mgakms/Makefile | 11 ++++ drivers/staging/mgakms/matroxfb_DAC1064.c | 77 +++++++---------------- drivers/staging/mgakms/matroxfb_DAC1064.h | 6 -- drivers/staging/mgakms/matroxfb_Ti3026.c | 2 - drivers/staging/mgakms/matroxfb_Ti3026.h | 2 - drivers/staging/mgakms/matroxfb_base.c | 29 +++------ drivers/staging/mgakms/matroxfb_base.h | 20 ++---- drivers/staging/mgakms/matroxfb_g450.h | 5 -- 9 files changed, 51 insertions(+), 106 deletions(-) diff --git a/drivers/staging/mgakms/Kconfig b/drivers/staging/mgakms/Kconfig index de23e76317bd..66c5b3b8669f 100644 --- a/drivers/staging/mgakms/Kconfig +++ b/drivers/staging/mgakms/Kconfig @@ -4,6 +4,11 @@ config DRM_MGAKMS select DRM_FBCONV_HELPER select DRM_GEM_SHMEM_HELPER select DRM_KMS_HELPER + select FB_CFB_COPYAREA + select FB_CFB_FILLRECT + select FB_CFB_IMAGEBLIT + select FB_MACMODES if PPC_PMAC + select FB_TILEBLITTING help Choose this option if you have a Matrox Millennium, Matrox Millennium II, Matrox Mystique, Matrox Mystique 220, diff --git a/drivers/staging/mgakms/Makefile b/drivers/staging/mgakms/Makefile index 65695f04eb7f..b368f8a5e38a 100644 --- a/drivers/staging/mgakms/Makefile +++ b/drivers/staging/mgakms/Makefile @@ -3,4 +3,15 @@ mgakms-y := mga_device.o \ mga_drv.o +# Old matroxfb driver code. Keep this separate and +# remove it after conversion. +mgakms-y += g450_pll.o \ + i2c-matroxfb.o \ + matroxfb_accel.o \ + matroxfb_base.o \ + matroxfb_DAC1064.o \ + matroxfb_g450.o \ + matroxfb_misc.o \ + matroxfb_Ti3026.o + obj-$(CONFIG_DRM_MGAKMS) += mgakms.o diff --git a/drivers/staging/mgakms/matroxfb_DAC1064.c b/drivers/staging/mgakms/matroxfb_DAC1064.c index b380a393cbc3..6bb214c548af 100644 --- a/drivers/staging/mgakms/matroxfb_DAC1064.c +++ b/drivers/staging/mgakms/matroxfb_DAC1064.c @@ -19,7 +19,6 @@ #include "g450_pll.h" #include -#ifdef NEED_DAC1064 #define outDAC1064 matroxfb_DAC_out #define inDAC1064 matroxfb_DAC_in @@ -42,11 +41,11 @@ static void DAC1064_calcclock(const struct matrox_fb_info *minfo, unsigned int p; DBG(__func__) - + /* only for devices older than G450 */ fvco = PLL_calcclock(minfo, freq, fmax, in, feed, &p); - + p = (1 << p) - 1; if (fvco <= 100000) ; @@ -160,7 +159,6 @@ static void DAC1064_setmclk(struct matrox_fb_info *minfo, int oscinfo, hw->MXoptionReg = mx; } -#ifdef CONFIG_FB_MATROX_G static void g450_set_plls(struct matrox_fb_info *minfo) { u_int32_t c2_ctl; @@ -168,7 +166,7 @@ static void g450_set_plls(struct matrox_fb_info *minfo) struct matrox_hw_state *hw = &minfo->hw; int pixelmnp; int videomnp; - + c2_ctl = hw->crtc2.ctl & ~0x4007; /* Clear PLL + enable for CRTC2 */ c2_ctl |= 0x0001; /* Enable CRTC2 */ hw->DACreg[POS1064_XPWRCTRL] &= ~0x02; /* Stop VIDEO PLL */ @@ -191,7 +189,7 @@ static void g450_set_plls(struct matrox_fb_info *minfo) } c2_ctl |= 0x0006; /* Use video PLL */ hw->DACreg[POS1064_XPWRCTRL] |= 0x02; - + outDAC1064(minfo, M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]); matroxfb_g450_setpll_cond(minfo, videomnp, M_VIDEO_PLL); } @@ -199,7 +197,7 @@ static void g450_set_plls(struct matrox_fb_info *minfo) hw->DACreg[POS1064_XPIXCLKCTRL] &= ~M1064_XPIXCLKCTRL_PLL_UP; if (pixelmnp >= 0) { hw->DACreg[POS1064_XPIXCLKCTRL] |= M1064_XPIXCLKCTRL_PLL_UP; - + outDAC1064(minfo, M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]); matroxfb_g450_setpll_cond(minfo, pixelmnp, M_PIXEL_PLL_C); } @@ -251,7 +249,6 @@ static void g450_set_plls(struct matrox_fb_info *minfo) } } } -#endif void DAC1064_global_init(struct matrox_fb_info *minfo) { @@ -260,7 +257,6 @@ void DAC1064_global_init(struct matrox_fb_info *minfo) hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK; hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN; hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL; -#ifdef CONFIG_FB_MATROX_G if (minfo->devflags.g450dac) { hw->DACreg[POS1064_XPWRCTRL] = 0x1F; /* powerup everything */ hw->DACreg[POS1064_XOUTPUTCONN] = 0x00; /* disable outputs */ @@ -302,15 +298,14 @@ void DAC1064_global_init(struct matrox_fb_info *minfo) poweroff TMDS. But if we boot with DFP connected, TMDS generated clocks are used instead of ALL pixclocks available... If someone knows which register - handles it, please reveal this secret to me... */ + handles it, please reveal this secret to me... */ hw->DACreg[POS1064_XPWRCTRL] &= ~0x04; /* Poweroff TMDS */ -#endif +#endif break; } /* Now set timming related variables... */ g450_set_plls(minfo); } else -#endif { if (minfo->outputs[1].src == MATROXFB_SRC_CRTC1) { hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT; @@ -510,7 +505,6 @@ static struct matrox_altout m1064 = { .compute = m1064_compute, }; -#ifdef CONFIG_FB_MATROX_G static int g450_compute(void* out, struct my_timming* m) { #define minfo ((struct matrox_fb_info*)out) if (m->mnp < 0) { @@ -527,11 +521,7 @@ static struct matrox_altout g450out = { .name = "Primary output", .compute = g450_compute, }; -#endif -#endif /* NEED_DAC1064 */ - -#ifdef CONFIG_FB_MATROX_MYSTIQUE static int MGA1064_init(struct matrox_fb_info *minfo, struct my_timming *m) { struct matrox_hw_state *hw = &minfo->hw; @@ -552,9 +542,7 @@ static int MGA1064_init(struct matrox_fb_info *minfo, struct my_timming *m) if (DAC1064_init_2(minfo, m)) return 1; return 0; } -#endif -#ifdef CONFIG_FB_MATROX_G static int MGAG100_init(struct matrox_fb_info *minfo, struct my_timming *m) { struct matrox_hw_state *hw = &minfo->hw; @@ -576,9 +564,7 @@ static int MGAG100_init(struct matrox_fb_info *minfo, struct my_timming *m) if (DAC1064_init_2(minfo, m)) return 1; return 0; } -#endif /* G */ -#ifdef CONFIG_FB_MATROX_MYSTIQUE static void MGA1064_ramdac_init(struct matrox_fb_info *minfo) { @@ -596,9 +582,7 @@ static void MGA1064_ramdac_init(struct matrox_fb_info *minfo) /* maybe cmdline MCLK= ?, doc says gclk=44MHz, mclk=66MHz... it was 55/83 with old values */ DAC1064_setmclk(minfo, DAC1064_OPT_MDIV2 | DAC1064_OPT_GDIV3 | DAC1064_OPT_SCLK_PLL, 133333); } -#endif -#ifdef CONFIG_FB_MATROX_G /* BIOS environ */ static int x7AF4 = 0x10; /* flags, maybe 0x10 = SDRAM, 0x00 = SGRAM??? */ /* G100 wants 0x10, G200 SGRAM does not care... */ @@ -662,9 +646,7 @@ static void MGAG100_setPixClock(const struct matrox_fb_info *minfo, int flags, DAC1064_calcclock(minfo, freq, minfo->max_pixel_clock, &m, &n, &p); MGAG100_progPixClock(minfo, flags, m, n, p); } -#endif -#ifdef CONFIG_FB_MATROX_MYSTIQUE static int MGA1064_preinit(struct matrox_fb_info *minfo) { static const int vxres_mystique[] = { 512, 640, 768, 800, 832, 960, @@ -710,9 +692,7 @@ static void MGA1064_reset(struct matrox_fb_info *minfo) MGA1064_ramdac_init(minfo); } -#endif -#ifdef CONFIG_FB_MATROX_G static void g450_mclk_init(struct matrox_fb_info *minfo) { /* switch all clocks to PCI source */ @@ -727,14 +707,14 @@ static void g450_mclk_init(struct matrox_fb_info *minfo) } else { unsigned long flags; unsigned int pwr; - + matroxfb_DAC_lock_irqsave(flags); pwr = inDAC1064(minfo, M1064_XPWRCTRL) & ~0x02; outDAC1064(minfo, M1064_XPWRCTRL, pwr); matroxfb_DAC_unlock_irqrestore(flags); } matroxfb_g450_setclk(minfo, minfo->values.pll.system, M_SYSTEM_PLL); - + /* switch clocks to their real PLL source(s) */ pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg | 4); pci_write_config_dword(minfo->pcidev, PCI_OPTION3_REG, minfo->values.reg.opt3); @@ -747,15 +727,15 @@ static void g450_memory_init(struct matrox_fb_info *minfo) /* disable memory refresh */ minfo->hw.MXoptionReg &= ~0x001F8000; pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg); - + /* set memory interface parameters */ minfo->hw.MXoptionReg &= ~0x00207E00; minfo->hw.MXoptionReg |= 0x00207E00 & minfo->values.reg.opt; pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg); pci_write_config_dword(minfo->pcidev, PCI_OPTION2_REG, minfo->values.reg.opt2); - + mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst); - + /* first set up memory interface with disabled memory interface clocks */ pci_write_config_dword(minfo->pcidev, PCI_MEMMISC_REG, minfo->values.reg.memmisc & ~0x80000000U); mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk); @@ -764,25 +744,25 @@ static void g450_memory_init(struct matrox_fb_info *minfo) pci_write_config_dword(minfo->pcidev, PCI_MEMMISC_REG, minfo->values.reg.memmisc | 0x80000000U); udelay(200); - + if (minfo->values.memory.ddr && (!minfo->values.memory.emrswen || !minfo->values.memory.dll)) { mga_outl(M_MEMRDBK, minfo->values.reg.memrdbk & ~0x1000); } mga_outl(M_MACCESS, minfo->values.reg.maccess | 0x8000); - + udelay(200); - + minfo->hw.MXoptionReg |= 0x001F8000 & minfo->values.reg.opt; pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg); - + /* value is written to memory chips only if old != new */ mga_outl(M_PLNWT, 0); mga_outl(M_PLNWT, ~0); - + if (minfo->values.reg.mctlwtst != minfo->values.reg.mctlwtst_core) { mga_outl(M_CTLWTST, minfo->values.reg.mctlwtst_core); } - + } static void g450_preinit(struct matrox_fb_info *minfo) @@ -790,7 +770,7 @@ static void g450_preinit(struct matrox_fb_info *minfo) u_int32_t c2ctl; u_int8_t curctl; u_int8_t c1ctl; - + /* minfo->hw.MXoptionReg = minfo->values.reg.opt; */ minfo->hw.MXoptionReg &= 0xC0000100; minfo->hw.MXoptionReg |= 0x00000020; @@ -804,7 +784,7 @@ static void g450_preinit(struct matrox_fb_info *minfo) pci_write_config_dword(minfo->pcidev, PCI_OPTION_REG, minfo->hw.MXoptionReg); /* Init system clocks */ - + /* stop crtc2 */ c2ctl = mga_inl(M_C2CTL); mga_outl(M_C2CTL, c2ctl & ~1); @@ -817,20 +797,20 @@ static void g450_preinit(struct matrox_fb_info *minfo) g450_mclk_init(minfo); g450_memory_init(minfo); - + /* set legacy VGA clock sources for DOSEmu or VMware... */ matroxfb_g450_setclk(minfo, 25175, M_PIXEL_PLL_A); matroxfb_g450_setclk(minfo, 28322, M_PIXEL_PLL_B); /* restore crtc1 */ mga_setr(M_SEQ_INDEX, 1, c1ctl); - + /* restore cursor */ outDAC1064(minfo, M1064_XCURCTRL, curctl); /* restore crtc2 */ mga_outl(M_C2CTL, c2ctl); - + return; } @@ -1031,9 +1011,7 @@ static void MGAG100_reset(struct matrox_fb_info *minfo) } } } -#endif -#ifdef CONFIG_FB_MATROX_MYSTIQUE static void MGA1064_restore(struct matrox_fb_info *minfo) { int i; @@ -1058,9 +1036,7 @@ static void MGA1064_restore(struct matrox_fb_info *minfo) mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]); DAC1064_restore_2(minfo); } -#endif -#ifdef CONFIG_FB_MATROX_G static void MGAG100_restore(struct matrox_fb_info *minfo) { int i; @@ -1084,9 +1060,7 @@ static void MGAG100_restore(struct matrox_fb_info *minfo) mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]); DAC1064_restore_2(minfo); } -#endif -#ifdef CONFIG_FB_MATROX_MYSTIQUE struct matrox_switch matrox_mystique = { .preinit = MGA1064_preinit, .reset = MGA1064_reset, @@ -1094,9 +1068,7 @@ struct matrox_switch matrox_mystique = { .restore = MGA1064_restore, }; EXPORT_SYMBOL(matrox_mystique); -#endif -#ifdef CONFIG_FB_MATROX_G struct matrox_switch matrox_G100 = { .preinit = MGAG100_preinit, .reset = MGAG100_reset, @@ -1104,10 +1076,7 @@ struct matrox_switch matrox_G100 = { .restore = MGAG100_restore, }; EXPORT_SYMBOL(matrox_G100); -#endif -#ifdef NEED_DAC1064 EXPORT_SYMBOL(DAC1064_global_init); EXPORT_SYMBOL(DAC1064_global_restore); -#endif MODULE_LICENSE("GPL"); diff --git a/drivers/staging/mgakms/matroxfb_DAC1064.h b/drivers/staging/mgakms/matroxfb_DAC1064.h index 3b2a6fd35fff..3d388941b51d 100644 --- a/drivers/staging/mgakms/matroxfb_DAC1064.h +++ b/drivers/staging/mgakms/matroxfb_DAC1064.h @@ -5,16 +5,10 @@ #include "matroxfb_base.h" -#ifdef CONFIG_FB_MATROX_MYSTIQUE extern struct matrox_switch matrox_mystique; -#endif -#ifdef CONFIG_FB_MATROX_G extern struct matrox_switch matrox_G100; -#endif -#ifdef NEED_DAC1064 void DAC1064_global_init(struct matrox_fb_info *minfo); void DAC1064_global_restore(struct matrox_fb_info *minfo); -#endif #define M1064_INDEX 0x00 #define M1064_PALWRADD 0x00 diff --git a/drivers/staging/mgakms/matroxfb_Ti3026.c b/drivers/staging/mgakms/matroxfb_Ti3026.c index 9ff9be85759e..e82e2a3cf76a 100644 --- a/drivers/staging/mgakms/matroxfb_Ti3026.c +++ b/drivers/staging/mgakms/matroxfb_Ti3026.c @@ -84,7 +84,6 @@ #include "matroxfb_accel.h" #include -#ifdef CONFIG_FB_MATROX_MILLENIUM #define outTi3026 matroxfb_DAC_out #define inTi3026 matroxfb_DAC_in @@ -744,5 +743,4 @@ struct matrox_switch matrox_millennium = { .restore = Ti3026_restore }; EXPORT_SYMBOL(matrox_millennium); -#endif MODULE_LICENSE("GPL"); diff --git a/drivers/staging/mgakms/matroxfb_Ti3026.h b/drivers/staging/mgakms/matroxfb_Ti3026.h index faee149d0ba0..2fda3b30b9e7 100644 --- a/drivers/staging/mgakms/matroxfb_Ti3026.h +++ b/drivers/staging/mgakms/matroxfb_Ti3026.h @@ -5,8 +5,6 @@ #include "matroxfb_base.h" -#ifdef CONFIG_FB_MATROX_MILLENIUM extern struct matrox_switch matrox_millennium; -#endif #endif /* __MATROXFB_TI3026_H__ */ diff --git a/drivers/staging/mgakms/matroxfb_base.c b/drivers/staging/mgakms/matroxfb_base.c index d11b5e6210ed..7ee0ea046a5f 100644 --- a/drivers/staging/mgakms/matroxfb_base.c +++ b/drivers/staging/mgakms/matroxfb_base.c @@ -114,6 +114,7 @@ #include #include #include +#include "mga_drv.h" #ifdef CONFIG_PPC_PMAC #include @@ -368,7 +369,7 @@ static void matroxfb_remove(struct matrox_fb_info *minfo, int dummy) return; } matroxfb_unregister_device(minfo); - unregister_framebuffer(&minfo->fbcon); + mga_unregister_framebuffer(minfo->mdev); matroxfb_g450_shutdown(minfo); arch_phys_wc_del(minfo->wc_cookie); iounmap(minfo->mmio.vbase.vaddr); @@ -1319,9 +1320,7 @@ static int matroxfb_getmemory(struct matrox_fb_info *minfo, mga_outb(M_EXTVGA_DATA, orig); *realSize = offs - 0x100000; -#ifdef CONFIG_FB_MATROX_MILLENIUM minfo->interleave = !(!isMillenium(minfo) || ((offs - 0x100000) & 0x3FFFFF)); -#endif return 1; } @@ -1331,7 +1330,6 @@ struct video_board { int accelID; struct matrox_switch* lowlevel; }; -#ifdef CONFIG_FB_MATROX_MILLENIUM static struct video_board vbMillennium = { .maxvram = 0x0800000, .maxdisplayable = 0x0800000, @@ -1352,16 +1350,12 @@ static struct video_board vbMillennium2A = { .accelID = FB_ACCEL_MATROX_MGA2164W_AGP, .lowlevel = &matrox_millennium }; -#endif /* CONFIG_FB_MATROX_MILLENIUM */ -#ifdef CONFIG_FB_MATROX_MYSTIQUE static struct video_board vbMystique = { .maxvram = 0x0800000, .maxdisplayable = 0x0800000, .accelID = FB_ACCEL_MATROX_MGA1064SG, .lowlevel = &matrox_mystique }; -#endif /* CONFIG_FB_MATROX_MYSTIQUE */ -#ifdef CONFIG_FB_MATROX_G static struct video_board vbG100 = { .maxvram = 0x0800000, .maxdisplayable = 0x0800000, @@ -1383,7 +1377,6 @@ static struct video_board vbG400 = { .accelID = FB_ACCEL_MATROX_MGAG400, .lowlevel = &matrox_G100 }; -#endif #define DEVF_VIDEO64BIT 0x0001 #define DEVF_SWAPS 0x0002 @@ -1418,7 +1411,6 @@ static struct board { struct video_board* base; const char* name; } dev_list[] = { -#ifdef CONFIG_FB_MATROX_MILLENIUM {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, 0xFF, 0, 0, DEVF_TEXT4B, @@ -1440,8 +1432,6 @@ static struct board { MGA_2164, &vbMillennium2A, "Millennium II (AGP)"}, -#endif -#ifdef CONFIG_FB_MATROX_MYSTIQUE {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, 0x02, 0, 0, DEVF_VIDEO64BIT | DEVF_CROSS4MB, @@ -1470,8 +1460,6 @@ static struct board { MGA_1164, &vbMystique, "Mystique 220 (AGP)"}, -#endif -#ifdef CONFIG_FB_MATROX_G {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_MM, 0xFF, 0, 0, DEVF_G100, @@ -1563,7 +1551,6 @@ static struct board { MGA_G550, &vbG400, "G550"}, -#endif {0, 0, 0xFF, 0, 0, 0, @@ -1622,6 +1609,7 @@ static int initMatrox2(struct matrox_fb_info *minfo, struct board *b) unsigned long video_base_phys = 0; unsigned int memsize; int err; + struct mga_device *mdev; static const struct pci_device_id intel_82437[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437) }, @@ -1918,9 +1906,12 @@ static int initMatrox2(struct matrox_fb_info *minfo, struct board *b) * and we do not want currcon == 0 for subsequent framebuffers */ minfo->fbcon.device = &minfo->pcidev->dev; - if (register_framebuffer(&minfo->fbcon) < 0) { + mdev = mga_register_framebuffer(&minfo->fbcon, minfo->pcidev); + if (IS_ERR(mdev)) { + err = PTR_ERR(mdev); goto failVideoIO; } + minfo->mdev = mdev; fb_info(&minfo->fbcon, "%s frame buffer device\n", minfo->fbcon.fix.id); /* there is no console on this fb... but we have to initialize hardware @@ -2116,19 +2107,14 @@ static void pci_remove_matrox(struct pci_dev* pdev) { } static const struct pci_device_id matroxfb_devices[] = { -#ifdef CONFIG_FB_MATROX_MILLENIUM {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#endif -#ifdef CONFIG_FB_MATROX_MYSTIQUE {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MYS, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#endif -#ifdef CONFIG_FB_MATROX_G {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_MM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, @@ -2141,7 +2127,6 @@ static const struct pci_device_id matroxfb_devices[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#endif {0, 0, 0, 0, 0, 0, 0} }; diff --git a/drivers/staging/mgakms/matroxfb_base.h b/drivers/staging/mgakms/matroxfb_base.h index f85ad25659e5..f7548549b3a6 100644 --- a/drivers/staging/mgakms/matroxfb_base.h +++ b/drivers/staging/mgakms/matroxfb_base.h @@ -115,11 +115,7 @@ #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) -/* G-series and Mystique have (almost) same DAC */ -#undef NEED_DAC1064 -#if defined(CONFIG_FB_MATROX_MYSTIQUE) || defined(CONFIG_FB_MATROX_G) -#define NEED_DAC1064 1 -#endif +struct mga_device; typedef struct { void __iomem* vaddr; @@ -282,9 +278,7 @@ struct matrox_hw_state { }; struct matrox_accel_data { -#ifdef CONFIG_FB_MATROX_MILLENIUM unsigned char ramdac_rev; -#endif u_int32_t m_dwg_rect; u_int32_t m_opmode; u_int32_t m_access; @@ -302,9 +296,9 @@ struct matrox_altout { int (*verifymode)(void* altout_dev, u_int32_t mode); int (*getqueryctrl)(void* altout_dev, struct v4l2_queryctrl* ctrl); - int (*getctrl)(void* altout_dev, + int (*getctrl)(void* altout_dev, struct v4l2_control* ctrl); - int (*setctrl)(void* altout_dev, + int (*setctrl)(void* altout_dev, struct v4l2_control* ctrl); }; @@ -338,6 +332,8 @@ struct matrox_vsync { struct matrox_fb_info { struct fb_info fbcon; + struct mga_device *mdev; + struct list_head next_fb; int dead; @@ -676,15 +672,9 @@ void matroxfb_unregister_driver(struct matroxfb_driver* drv); #define WaitTillIdle() do { mga_inl(M_STATUS); do {} while (mga_inl(M_STATUS) & 0x10000); } while (0) /* code speedup */ -#ifdef CONFIG_FB_MATROX_MILLENIUM #define isInterleave(x) (x->interleave) #define isMillenium(x) (x->millenium) #define isMilleniumII(x) (x->milleniumII) -#else -#define isInterleave(x) (0) -#define isMillenium(x) (0) -#define isMilleniumII(x) (0) -#endif #define matroxfb_DAC_lock() spin_lock(&minfo->lock.DAC) #define matroxfb_DAC_unlock() spin_unlock(&minfo->lock.DAC) diff --git a/drivers/staging/mgakms/matroxfb_g450.h b/drivers/staging/mgakms/matroxfb_g450.h index b5f17b86eae5..2cec778a2a81 100644 --- a/drivers/staging/mgakms/matroxfb_g450.h +++ b/drivers/staging/mgakms/matroxfb_g450.h @@ -4,12 +4,7 @@ #include "matroxfb_base.h" -#ifdef CONFIG_FB_MATROX_G void matroxfb_g450_connect(struct matrox_fb_info *minfo); void matroxfb_g450_shutdown(struct matrox_fb_info *minfo); -#else -static inline void matroxfb_g450_connect(struct matrox_fb_info *minfo) { }; -static inline void matroxfb_g450_shutdown(struct matrox_fb_info *minfo) { }; -#endif #endif /* __MATROXFB_G450_H__ */