Message ID | 1470411883-3534-3-git-send-email-noralf@tronnes.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Fri, Aug 5, 2016 at 11:44 AM, Noralf Trønnes <noralf@tronnes.org> wrote: > Create a simple fbdev device during SimpleDRM setup so legacy user-space > and fbcon can use it. > > Original work by David Herrmann. > > Cc: dh.herrmann@gmail.com > Signed-off-by: Noralf Trønnes <noralf@tronnes.org> > --- > > Changes from version 1: > No changes > > Changes from previous version: > - Remove the DRM_SIMPLEDRM_FBDEV kconfig option and use DRM_FBDEV_EMULATION > - Suspend fbcon/fbdev when the pipeline is enabled, resume in lastclose > - Add FBINFO_CAN_FORCE_OUTPUT flag so we get oops'es on the console > > drivers/gpu/drm/simpledrm/Kconfig | 3 + > drivers/gpu/drm/simpledrm/Makefile | 1 + > drivers/gpu/drm/simpledrm/simpledrm.h | 24 +++++ > drivers/gpu/drm/simpledrm/simpledrm_drv.c | 4 + > drivers/gpu/drm/simpledrm/simpledrm_fbdev.c | 160 ++++++++++++++++++++++++++++ > drivers/gpu/drm/simpledrm/simpledrm_kms.c | 12 +++ > 6 files changed, 204 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 f45b25d..9454536 100644 > --- a/drivers/gpu/drm/simpledrm/Kconfig > +++ b/drivers/gpu/drm/simpledrm/Kconfig > @@ -13,6 +13,9 @@ config DRM_SIMPLEDRM > SimpleDRM supports "simple-framebuffer" DeviceTree objects and > compatible platform framebuffers. > > + If fbdev support is enabled, this driver will also provide an fbdev > + compatibility layer. > + > If unsure, say Y. > > To compile this driver as a module, choose M here: the > diff --git a/drivers/gpu/drm/simpledrm/Makefile b/drivers/gpu/drm/simpledrm/Makefile > index f6a62dc..7087245 100644 > --- a/drivers/gpu/drm/simpledrm/Makefile > +++ b/drivers/gpu/drm/simpledrm/Makefile > @@ -1,4 +1,5 @@ > simpledrm-y := simpledrm_drv.o simpledrm_kms.o simpledrm_gem.o \ > simpledrm_damage.o > +simpledrm-$(CONFIG_DRM_FBDEV_EMULATION) += simpledrm_fbdev.o > > obj-$(CONFIG_DRM_SIMPLEDRM) := simpledrm.o > diff --git a/drivers/gpu/drm/simpledrm/simpledrm.h b/drivers/gpu/drm/simpledrm/simpledrm.h > index f9f082c..eb18d59 100644 > --- a/drivers/gpu/drm/simpledrm/simpledrm.h > +++ b/drivers/gpu/drm/simpledrm/simpledrm.h > @@ -30,6 +30,7 @@ struct sdrm_device { > struct drm_device *ddev; > struct drm_simple_display_pipe pipe; > struct drm_connector conn; > + struct fb_info *fbdev; > > /* framebuffer information */ > const struct simplefb_format *fb_sformat; > @@ -52,6 +53,7 @@ struct sdrm_device { > #endif > }; > > +void sdrm_lastclose(struct drm_device *ddev); > int sdrm_drm_modeset_init(struct sdrm_device *sdrm); > int sdrm_drm_mmap(struct file *filp, struct vm_area_struct *vma); > > @@ -93,4 +95,26 @@ struct sdrm_framebuffer { > > #define to_sdrm_fb(x) container_of(x, struct sdrm_framebuffer, base) > > +#ifdef CONFIG_DRM_FBDEV_EMULATION > + > +void sdrm_fbdev_init(struct sdrm_device *sdrm); > +void sdrm_fbdev_cleanup(struct sdrm_device *sdrm); > +void sdrm_fbdev_set_suspend(struct sdrm_device *sdrm, int state); > + > +#else > + > +static inline void sdrm_fbdev_init(struct sdrm_device *sdrm) > +{ > +} > + > +static inline void sdrm_fbdev_cleanup(struct sdrm_device *sdrm) > +{ > +} > + > +static inline void sdrm_fbdev_set_suspend(struct sdrm_device *sdrm, int state) > +{ > +} > + > +#endif > + > #endif /* SDRM_DRV_H */ > diff --git a/drivers/gpu/drm/simpledrm/simpledrm_drv.c b/drivers/gpu/drm/simpledrm/simpledrm_drv.c > index 35296d2..88ad717c 100644 > --- a/drivers/gpu/drm/simpledrm/simpledrm_drv.c > +++ b/drivers/gpu/drm/simpledrm/simpledrm_drv.c > @@ -41,6 +41,7 @@ static struct drm_driver sdrm_drm_driver = { > .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | > DRIVER_ATOMIC, > .fops = &sdrm_drm_fops, > + .lastclose = sdrm_lastclose, > > .gem_free_object = sdrm_gem_free_object, > .prime_fd_to_handle = drm_gem_prime_fd_to_handle, > @@ -447,6 +448,8 @@ static int sdrm_simplefb_probe(struct platform_device *pdev) > if (ret) > goto err_regulators; > > + sdrm_fbdev_init(ddev->dev_private); > + > DRM_INFO("Initialized %s on minor %d\n", ddev->driver->name, > ddev->primary->index); > > @@ -472,6 +475,7 @@ static int sdrm_simplefb_remove(struct platform_device *pdev) > struct drm_device *ddev = platform_get_drvdata(pdev); > struct sdrm_device *sdrm = ddev->dev_private; > > + sdrm_fbdev_cleanup(sdrm); > drm_dev_unregister(ddev); > drm_mode_config_cleanup(ddev); > > diff --git a/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c b/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c > new file mode 100644 > index 0000000..b83646b > --- /dev/null > +++ b/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c > @@ -0,0 +1,160 @@ > +/* > + * SimpleDRM firmware framebuffer driver > + * Copyright (c) 2012-2014 David Herrmann <dh.herrmann@gmail.com> > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License as published by the Free > + * Software Foundation; either version 2 of the License, or (at your option) > + * any later version. > + */ > + > +/* > + * fbdev compatibility layer > + * We provide a basic fbdev device for the same framebuffer that is used for > + * the pseudo CRTC. > + */ > + > +#include <linux/console.h> > +#include <linux/errno.h> > +#include <linux/kernel.h> > +#include <linux/mm.h> > +#include <linux/module.h> You should not need module.h here since this file is not doing the module_init or module_exit or MODULE_ALIAS etc etc. An empty file with just module.h in it outputs about 750k of goo from cpp, so it is best avoided wherever not strictly needed. Thanks, Paul. -- > +#include <linux/string.h> > +#include <linux/fb.h> > +#include "simpledrm.h" > +
Den 06.08.2016 00:38, skrev Paul Gortmaker: > On Fri, Aug 5, 2016 at 11:44 AM, Noralf Trønnes <noralf@tronnes.org> wrote: >> Create a simple fbdev device during SimpleDRM setup so legacy user-space >> and fbcon can use it. >> >> Original work by David Herrmann. >> >> Cc: dh.herrmann@gmail.com >> Signed-off-by: Noralf Trønnes <noralf@tronnes.org> >> --- >> >> Changes from version 1: >> No changes >> >> Changes from previous version: >> - Remove the DRM_SIMPLEDRM_FBDEV kconfig option and use DRM_FBDEV_EMULATION >> - Suspend fbcon/fbdev when the pipeline is enabled, resume in lastclose >> - Add FBINFO_CAN_FORCE_OUTPUT flag so we get oops'es on the console <snip> >> diff --git a/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c b/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c >> new file mode 100644 >> index 0000000..b83646b >> --- /dev/null >> +++ b/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c >> @@ -0,0 +1,160 @@ >> +/* >> + * SimpleDRM firmware framebuffer driver >> + * Copyright (c) 2012-2014 David Herrmann <dh.herrmann@gmail.com> >> + * >> + * This program is free software; you can redistribute it and/or modify it >> + * under the terms of the GNU General Public License as published by the Free >> + * Software Foundation; either version 2 of the License, or (at your option) >> + * any later version. >> + */ >> + >> +/* >> + * fbdev compatibility layer >> + * We provide a basic fbdev device for the same framebuffer that is used for >> + * the pseudo CRTC. >> + */ >> + >> +#include <linux/console.h> >> +#include <linux/errno.h> >> +#include <linux/kernel.h> >> +#include <linux/mm.h> >> +#include <linux/module.h> > You should not need module.h here since this file is not doing the > module_init or module_exit or MODULE_ALIAS etc etc. > > An empty file with just module.h in it outputs about 750k of goo > from cpp, so it is best avoided wherever not strictly needed. I've never thought of superfluous includes in terms of compile time before, but that makes sense, especially on a large project like this. Thanks, Noralf. > Thanks, > Paul. > -- > >> +#include <linux/string.h> >> +#include <linux/fb.h> >> +#include "simpledrm.h" >> +
diff --git a/drivers/gpu/drm/simpledrm/Kconfig b/drivers/gpu/drm/simpledrm/Kconfig index f45b25d..9454536 100644 --- a/drivers/gpu/drm/simpledrm/Kconfig +++ b/drivers/gpu/drm/simpledrm/Kconfig @@ -13,6 +13,9 @@ config DRM_SIMPLEDRM SimpleDRM supports "simple-framebuffer" DeviceTree objects and compatible platform framebuffers. + If fbdev support is enabled, this driver will also provide an fbdev + compatibility layer. + If unsure, say Y. To compile this driver as a module, choose M here: the diff --git a/drivers/gpu/drm/simpledrm/Makefile b/drivers/gpu/drm/simpledrm/Makefile index f6a62dc..7087245 100644 --- a/drivers/gpu/drm/simpledrm/Makefile +++ b/drivers/gpu/drm/simpledrm/Makefile @@ -1,4 +1,5 @@ simpledrm-y := simpledrm_drv.o simpledrm_kms.o simpledrm_gem.o \ simpledrm_damage.o +simpledrm-$(CONFIG_DRM_FBDEV_EMULATION) += simpledrm_fbdev.o obj-$(CONFIG_DRM_SIMPLEDRM) := simpledrm.o diff --git a/drivers/gpu/drm/simpledrm/simpledrm.h b/drivers/gpu/drm/simpledrm/simpledrm.h index f9f082c..eb18d59 100644 --- a/drivers/gpu/drm/simpledrm/simpledrm.h +++ b/drivers/gpu/drm/simpledrm/simpledrm.h @@ -30,6 +30,7 @@ struct sdrm_device { struct drm_device *ddev; struct drm_simple_display_pipe pipe; struct drm_connector conn; + struct fb_info *fbdev; /* framebuffer information */ const struct simplefb_format *fb_sformat; @@ -52,6 +53,7 @@ struct sdrm_device { #endif }; +void sdrm_lastclose(struct drm_device *ddev); int sdrm_drm_modeset_init(struct sdrm_device *sdrm); int sdrm_drm_mmap(struct file *filp, struct vm_area_struct *vma); @@ -93,4 +95,26 @@ struct sdrm_framebuffer { #define to_sdrm_fb(x) container_of(x, struct sdrm_framebuffer, base) +#ifdef CONFIG_DRM_FBDEV_EMULATION + +void sdrm_fbdev_init(struct sdrm_device *sdrm); +void sdrm_fbdev_cleanup(struct sdrm_device *sdrm); +void sdrm_fbdev_set_suspend(struct sdrm_device *sdrm, int state); + +#else + +static inline void sdrm_fbdev_init(struct sdrm_device *sdrm) +{ +} + +static inline void sdrm_fbdev_cleanup(struct sdrm_device *sdrm) +{ +} + +static inline void sdrm_fbdev_set_suspend(struct sdrm_device *sdrm, int state) +{ +} + +#endif + #endif /* SDRM_DRV_H */ diff --git a/drivers/gpu/drm/simpledrm/simpledrm_drv.c b/drivers/gpu/drm/simpledrm/simpledrm_drv.c index 35296d2..88ad717c 100644 --- a/drivers/gpu/drm/simpledrm/simpledrm_drv.c +++ b/drivers/gpu/drm/simpledrm/simpledrm_drv.c @@ -41,6 +41,7 @@ static struct drm_driver sdrm_drm_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_ATOMIC, .fops = &sdrm_drm_fops, + .lastclose = sdrm_lastclose, .gem_free_object = sdrm_gem_free_object, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, @@ -447,6 +448,8 @@ static int sdrm_simplefb_probe(struct platform_device *pdev) if (ret) goto err_regulators; + sdrm_fbdev_init(ddev->dev_private); + DRM_INFO("Initialized %s on minor %d\n", ddev->driver->name, ddev->primary->index); @@ -472,6 +475,7 @@ static int sdrm_simplefb_remove(struct platform_device *pdev) struct drm_device *ddev = platform_get_drvdata(pdev); struct sdrm_device *sdrm = ddev->dev_private; + sdrm_fbdev_cleanup(sdrm); drm_dev_unregister(ddev); drm_mode_config_cleanup(ddev); diff --git a/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c b/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c new file mode 100644 index 0000000..b83646b --- /dev/null +++ b/drivers/gpu/drm/simpledrm/simpledrm_fbdev.c @@ -0,0 +1,160 @@ +/* + * SimpleDRM firmware framebuffer driver + * Copyright (c) 2012-2014 David Herrmann <dh.herrmann@gmail.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +/* + * fbdev compatibility layer + * We provide a basic fbdev device for the same framebuffer that is used for + * the pseudo CRTC. + */ + +#include <linux/console.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/fb.h> +#include "simpledrm.h" + +struct sdrm_fbdev { + u32 palette[16]; +}; + +static int sdrm_fbdev_setcolreg(u_int regno, u_int red, u_int green, + u_int blue, u_int transp, struct fb_info *info) +{ + u32 *pal = info->pseudo_palette; + u32 cr = red >> (16 - info->var.red.length); + u32 cg = green >> (16 - info->var.green.length); + u32 cb = blue >> (16 - info->var.blue.length); + u32 value; + + if (regno >= 16) + return -EINVAL; + + value = (cr << info->var.red.offset) | + (cg << info->var.green.offset) | + (cb << info->var.blue.offset); + + if (info->var.transp.length > 0) { + u32 mask = (1 << info->var.transp.length) - 1; + + mask <<= info->var.transp.offset; + value |= mask; + } + + pal[regno] = value; + + 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; + + if (fb_get_options("simpledrmfb", NULL)) + return; + + info = framebuffer_alloc(sizeof(struct sdrm_fbdev), sdrm->ddev->dev); + if (!info) + goto err_out; + + fb = info->par; + info->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE | + FBINFO_CAN_FORCE_OUTPUT; + 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; + + ret = register_framebuffer(info); + if (ret < 0) + goto err_free; + + sdrm->fbdev = info; + 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->fbdev) + return; + + info = sdrm->fbdev; + sdrm->fbdev = NULL; + + dev_info(sdrm->ddev->dev, "remove fbdev frontend %s (fb%d)\n", + info->fix.id, info->node); + + if (unregister_framebuffer(info)) + dev_err(sdrm->ddev->dev, "unregister_framebuffer() failed, leaking fw-fb\n"); + else + framebuffer_release(info); +} + +void sdrm_fbdev_set_suspend(struct sdrm_device *sdrm, int state) +{ + if (!sdrm->fbdev) + return; + + console_lock(); + fb_set_suspend(sdrm->fbdev, state); + console_unlock(); +} diff --git a/drivers/gpu/drm/simpledrm/simpledrm_kms.c b/drivers/gpu/drm/simpledrm/simpledrm_kms.c index 193c3c3..5f53624 100644 --- a/drivers/gpu/drm/simpledrm/simpledrm_kms.c +++ b/drivers/gpu/drm/simpledrm/simpledrm_kms.c @@ -25,6 +25,14 @@ static const uint32_t sdrm_formats[] = { DRM_FORMAT_XRGB8888, }; +void sdrm_lastclose(struct drm_device *ddev) +{ + struct sdrm_device *sdrm = ddev->dev_private; + + /* resume fbcon/fbdev */ + sdrm_fbdev_set_suspend(sdrm, 0); +} + static int sdrm_conn_get_modes(struct drm_connector *conn) { struct sdrm_device *sdrm = conn->dev->dev_private; @@ -98,7 +106,11 @@ static void sdrm_crtc_send_vblank_event(struct drm_crtc *crtc) static void sdrm_display_pipe_enable(struct drm_simple_display_pipe *pipe, struct drm_crtc_state *crtc_state) { + struct sdrm_device *sdrm = pipe_to_sdrm(pipe); + sdrm_crtc_send_vblank_event(&pipe->crtc); + /* suspend fbcon/fbdev */ + sdrm_fbdev_set_suspend(sdrm, 1); } static void sdrm_display_pipe_disable(struct drm_simple_display_pipe *pipe)
Create a simple fbdev device during SimpleDRM setup so legacy user-space and fbcon can use it. Original work by David Herrmann. Cc: dh.herrmann@gmail.com Signed-off-by: Noralf Trønnes <noralf@tronnes.org> --- Changes from version 1: No changes Changes from previous version: - Remove the DRM_SIMPLEDRM_FBDEV kconfig option and use DRM_FBDEV_EMULATION - Suspend fbcon/fbdev when the pipeline is enabled, resume in lastclose - Add FBINFO_CAN_FORCE_OUTPUT flag so we get oops'es on the console drivers/gpu/drm/simpledrm/Kconfig | 3 + drivers/gpu/drm/simpledrm/Makefile | 1 + drivers/gpu/drm/simpledrm/simpledrm.h | 24 +++++ drivers/gpu/drm/simpledrm/simpledrm_drv.c | 4 + drivers/gpu/drm/simpledrm/simpledrm_fbdev.c | 160 ++++++++++++++++++++++++++++ drivers/gpu/drm/simpledrm/simpledrm_kms.c | 12 +++ 6 files changed, 204 insertions(+) create mode 100644 drivers/gpu/drm/simpledrm/simpledrm_fbdev.c -- 2.8.2