From patchwork Mon Jun 24 22:27:27 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Herrmann X-Patchwork-Id: 2773741 Return-Path: X-Original-To: patchwork-linux-fbdev@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id D32129F758 for ; Mon, 24 Jun 2013 22:29:00 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id ACBDC20222 for ; Mon, 24 Jun 2013 22:28:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 769FC20214 for ; Mon, 24 Jun 2013 22:28:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751445Ab3FXW2U (ORCPT ); Mon, 24 Jun 2013 18:28:20 -0400 Received: from mail-ea0-f172.google.com ([209.85.215.172]:49817 "EHLO mail-ea0-f172.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751411Ab3FXW2S (ORCPT ); Mon, 24 Jun 2013 18:28:18 -0400 Received: by mail-ea0-f172.google.com with SMTP id q10so6441188eaj.3 for ; Mon, 24 Jun 2013 15:28:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=G21hx/V403LzxzSFVCh+zFDUtM4okmEV1M3ZYoM2cgw=; b=jUv2ZYiE++EHMqDPQBWx1jC4oS2xAArBi2gVXGAy3tr4EDCrb5hPhSxCx08dPFqTT1 9z/97YtSc49eEWblxs8pN8HZM/31aeg3jK/fP+YV6ZBKVJJB4HDHeBNkea6XU7ruJqJI o2GwQ1yoSD7pqjip5Sa2/6GjIdLijtyT3x3A+Nxte3x+QE0sZdnUN2Bps8GhhaX7uW/J dr2TXBzQynVuCgkbwTDuFHVnEP9DunMrTAMjVmz2Wt7RJoHnmo26HoHdPVIAjWOeK/Hq 4mya1ILrYEy1M4wUs0bycbc7moz/uveCsQqz5AlTF4S6h0MUcgza7E10aMsZyKNg/AZZ HsNg== X-Received: by 10.14.251.202 with SMTP id b50mr26784914ees.85.1372112897187; Mon, 24 Jun 2013 15:28:17 -0700 (PDT) Received: from localhost.localdomain (stgt-5f718d2d.pool.mediaWays.net. [95.113.141.45]) by mx.google.com with ESMTPSA id b7sm31487934eef.16.2013.06.24.15.28.15 for (version=TLSv1.2 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 24 Jun 2013 15:28:16 -0700 (PDT) From: David Herrmann To: dri-devel@lists.freedesktop.org Cc: linux-kernel@vger.kernel.org, Dave Airlie , linux-fbdev@vger.kernel.org, Stephen Warren , Olof Johansson , David Herrmann Subject: [RFC 4/6] drm: simpledrm: add fbdev fallback support Date: Tue, 25 Jun 2013 00:27:27 +0200 Message-Id: <1372112849-670-5-git-send-email-dh.herrmann@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1372112849-670-1-git-send-email-dh.herrmann@gmail.com> References: <1372112849-670-1-git-send-email-dh.herrmann@gmail.com> Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org X-Spam-Status: No, score=-7.9 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Create a simple fbdev device during SimpleDRM setup so legacy user-space and fbcon can use it. fbdev deletion is quite buggy. A unregister_framebuffer() call followed by a printk() causes NULL-derefs in hide_cursor() and other places in the VT layer. Hence, we leak the fbdev device currently to make the VT layer happy. This needs to be fixed soon! Otherwise, we need a "depends !VT" line for SimpleDRM. Signed-off-by: David Herrmann --- drivers/gpu/drm/simpledrm/Kconfig | 11 ++ drivers/gpu/drm/simpledrm/Makefile | 4 + drivers/gpu/drm/simpledrm/simpledrm.h | 22 ++++ drivers/gpu/drm/simpledrm/simpledrm_fbdev.c | 180 ++++++++++++++++++++++++++++ drivers/gpu/drm/simpledrm/simpledrm_main.c | 2 + 5 files changed, 219 insertions(+) create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_fbdev.c diff --git a/drivers/gpu/drm/simpledrm/Kconfig b/drivers/gpu/drm/simpledrm/Kconfig index 1d4f38e..7936211 100644 --- a/drivers/gpu/drm/simpledrm/Kconfig +++ b/drivers/gpu/drm/simpledrm/Kconfig @@ -12,7 +12,18 @@ config DRM_SIMPLEDRM SimpleDRM supports: "simple-framebuffer" DeviceTree objects, x86 VESA BIOS Extensions (VBE), EFI framebuffers + If fbdev support is enabled, this driver will also provide an fbdev + compatibility layer. + If unsure, say Y. To compile this driver as a module, choose M here: the module will be called simpledrm. + +config DRM_SIMPLEDRM_FBDEV + bool + depends on DRM_SIMPLEDRM && FB + default y + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT diff --git a/drivers/gpu/drm/simpledrm/Makefile b/drivers/gpu/drm/simpledrm/Makefile index 2d474a5..e77bd9b 100644 --- a/drivers/gpu/drm/simpledrm/Makefile +++ b/drivers/gpu/drm/simpledrm/Makefile @@ -2,4 +2,8 @@ ccflags-y := -Iinclude/drm simpledrm-y := simpledrm_drv.o simpledrm_main.o simpledrm_mem.o +ifdef CONFIG_DRM_SIMPLEDRM_FBDEV + simpledrm-y += simpledrm_fbdev.o +endif + obj-$(CONFIG_DRM_SIMPLEDRM) := simpledrm.o diff --git a/drivers/gpu/drm/simpledrm/simpledrm.h b/drivers/gpu/drm/simpledrm/simpledrm.h index 279d847..cfd99f9 100644 --- a/drivers/gpu/drm/simpledrm/simpledrm.h +++ b/drivers/gpu/drm/simpledrm/simpledrm.h @@ -48,6 +48,9 @@ struct sdrm_device { struct drm_encoder enc; struct drm_connector conn; struct drm_display_mode *mode; + + /* fbdev */ + struct fb_info *fbdev; }; int sdrm_drm_load(struct drm_device *ddev, unsigned long flags); @@ -88,4 +91,23 @@ struct sdrm_framebuffer { #define to_sdrm_fb(x) container_of(x, struct sdrm_framebuffer, base) +/* simpledrm fbdev helpers */ + +#ifdef CONFIG_DRM_SIMPLEDRM_FBDEV + +void sdrm_fbdev_init(struct sdrm_device *sdrm); +void sdrm_fbdev_cleanup(struct sdrm_device *sdrm); + +#else /* CONFIG_DRM_SIMPLEDRM_FBDEV */ + +static inline void sdrm_fbdev_init(struct sdrm_device *sdrm) +{ +} + +static inline void sdrm_fbdev_cleanup(struct sdrm_device *sdrm) +{ +} + +#endif /* CONFIG_DRM_SIMPLEDRM_FBDEV */ + #endif /* SDRM_DRV_H */ diff --git a/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c b/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c new file mode 100644 index 0000000..40a2696 --- /dev/null +++ b/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c @@ -0,0 +1,180 @@ +/* + * SimpleDRM firmware framebuffer driver + * Copyright (c) 2012-2013 David Herrmann + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +/* + * fbdev compatibility layer + * We provide a basic fbdev device for the same framebuffer that is used for + * the pseudo CRTC. + */ + +#include +#include +#include +#include +#include +#include +#include "simpledrm.h" + +struct sdrm_fbdev { + u32 palette[256]; +}; + +static int sdrm_fbdev_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + /* + * Set a single color register. The values supplied are + * already rounded down to the hardware's capabilities + * (according to the entries in the `var' structure). Return != 0 for + * invalid regno. + */ + + if (regno >= info->cmap.len) + return 1; + if (info->var.bits_per_pixel == 8) + return -EINVAL; + if (regno >= 16) + return 0; + + switch (info->var.bits_per_pixel) { + case 16: + if (info->var.red.offset == 10) { + /* 1:5:5:5 */ + ((u32*) (info->pseudo_palette))[regno] = + ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + } else { + /* 0:5:6:5 */ + ((u32*) (info->pseudo_palette))[regno] = + ((red & 0xf800) ) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + } + break; + case 24: + case 32: + red >>= 8; + green >>= 8; + blue >>= 8; + ((u32*) (info->pseudo_palette))[regno] = + (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + break; + } + + return 0; +} + +static struct fb_ops sdrm_fbdev_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = sdrm_fbdev_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +void sdrm_fbdev_init(struct sdrm_device *sdrm) +{ + struct sdrm_fbdev *fb; + struct fb_info *info; + int ret; + + info = framebuffer_alloc(sizeof(struct sdrm_fbdev), sdrm->ddev->dev); + if (!info) + goto err_out; + + fb = info->par; + info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE; + info->pseudo_palette = fb->palette; + info->fbops = &sdrm_fbdev_ops; + info->screen_base = sdrm->fb_map; + + strncpy(info->fix.id, "simpledrmfb", 15); + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->fix.accel = FB_ACCEL_NONE; + info->fix.smem_start = (unsigned long)sdrm->fb_base; + info->fix.smem_len = sdrm->fb_size; + info->fix.line_length = sdrm->fb_stride; + + info->var.activate = FB_ACTIVATE_NOW; + info->var.vmode = FB_VMODE_NONINTERLACED; + info->var.bits_per_pixel = sdrm->fb_bpp; + info->var.height = -1; + info->var.width = -1; + info->var.xres = sdrm->fb_width; + info->var.yres = sdrm->fb_height; + info->var.xres_virtual = info->var.xres; + info->var.yres_virtual = info->var.yres; + info->var.red = sdrm->fb_sformat->red; + info->var.green = sdrm->fb_sformat->green; + info->var.blue = sdrm->fb_sformat->blue; + info->var.transp = sdrm->fb_sformat->transp; + + /* some dummy values for timing to make fbset happy */ + info->var.pixclock = 10000000 / info->var.xres * 1000 / info->var.yres; + info->var.left_margin = (info->var.xres / 8) & 0xf8; + info->var.right_margin = 32; + info->var.upper_margin = 16; + info->var.lower_margin = 4; + info->var.hsync_len = (info->var.xres / 8) & 0xf8; + info->var.vsync_len = 4; + + info->apertures = alloc_apertures(1); + if (!info->apertures) + goto err_free; + + info->apertures->ranges[0].base = (unsigned long)sdrm->fb_base; + info->apertures->ranges[0].size = sdrm->fb_size; + + sdrm->fbdev = info; + ret = register_framebuffer(info); + if (ret < 0) + goto err_free; + + dev_info(sdrm->ddev->dev, "fbdev frontend %s as fb%d\n", + info->fix.id, info->node); + + return; + +err_free: + framebuffer_release(info); +err_out: + dev_warn(sdrm->ddev->dev, "cannot create fbdev frontend\n"); +} + +void sdrm_fbdev_cleanup(struct sdrm_device *sdrm) +{ + struct fb_info *info; + + if (!sdrm->info) + return; + + dev_info(sdrm->ddev->dev, "fbdev cleanup\n"); + info = sdrm->fbdev; + sdrm->fbdev = NULL; + + unregister_framebuffer(info); + + /* + * FIXME: unregister_framebuffer() may silently fail, which is odd + * because there is no sane way for us to detect when to release the + * framebuffer. + * If we fix unbind_console() to not fail during framebuffer + * unregistration, we end up with NULL-derefs in the VT layer + * afterwards. So lets just leak the FB here for the VT layer's sake. + */ + /* framebuffer_release(info); */ +} diff --git a/drivers/gpu/drm/simpledrm/simpledrm_main.c b/drivers/gpu/drm/simpledrm/simpledrm_main.c index dcc3d0a..ffa1abb 100644 --- a/drivers/gpu/drm/simpledrm/simpledrm_main.c +++ b/drivers/gpu/drm/simpledrm/simpledrm_main.c @@ -305,6 +305,7 @@ int sdrm_drm_load(struct drm_device *ddev, unsigned long flags) if (ret) goto err_cleanup; + sdrm_fbdev_init(sdrm); return 0; err_cleanup: @@ -322,6 +323,7 @@ int sdrm_drm_unload(struct drm_device *ddev) { struct sdrm_device *sdrm = ddev->dev_private; + sdrm_fbdev_cleanup(sdrm); drm_mode_config_cleanup(ddev); sdrm_pdev_destroy(sdrm); kfree(sdrm);