[PATCH 6/7] drm/hisilicon:Add fbdev
lijianhua
jueying0518 at gmail.com
Mon Feb 29 00:58:40 UTC 2016
Add fbdev.
Signed-off-by: lijianhua <jueying0518 at gmail.com>
---
drivers/gpu/drm/hisilicon/hibmc/Makefile | 2 +-
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 5 +
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h | 2 +
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 290 ++++++++++++++++++++++
4 files changed, 298 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
index 6ab59b1..1ca1d49 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,5 +1,5 @@
ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_hw.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_fbdev.o hibmc_drm_hw.o
obj-$(CONFIG_DRM_HISI_HIBMC) +=hibmc-drm.o
#obj-y += hibmc-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 673a8cd..7439f62 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -250,6 +250,7 @@ static int hibmc_unload(struct drm_device *dev)
{
struct hibmc_private *hiprivate = dev->dev_private;
+ hibmc_fbdev_fini(hiprivate);
hibmc_kms_fini(hiprivate);
hibmc_hw_fini(dev);
dev->dev_private = NULL;
@@ -283,6 +284,10 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
/* reset all the states of crtc/plane/encoder/connector */
drm_mode_config_reset(dev);
+ ret = hibmc_fbdev_init(hiprivate);
+ if (ret)
+ goto err;
+
return 0;
err:
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index 1f6b25c..e863e1a 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -50,5 +50,7 @@ int hibmc_plane_init(struct drm_device *dev);
int hibmc_crtc_init(struct drm_device *dev);
int hibmc_encoder_init(struct drm_device *dev);
int hibmc_connector_init(struct drm_device *dev);
+int hibmc_fbdev_init(struct hibmc_private *hiprivate);
+void hibmc_fbdev_fini(struct hibmc_private *hiprivate);
#endif
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
new file mode 100644
index 0000000..416a6c6
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * 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.
+ *
+ */
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include "hibmc_drm_drv.h"
+
+/* ---------------------------------------------------------------------- */
+
+void hibmc_drm_fb_destroy(struct drm_framebuffer *fb)
+{
+ struct hibmc_private *hiprivate =
+ container_of(fb, struct hibmc_private, fbdev.fb.fb);
+ struct drm_gem_object *base = &hiprivate->fbdev.fb.obj->base;
+
+ if (hiprivate->fbdev.fb.obj)
+ drm_gem_object_unreference_unlocked(base);
+ drm_framebuffer_cleanup(fb);
+ kfree(fb);
+}
+
+static struct drm_framebuffer_funcs hibmc_drm_fb_funcs = {
+ .destroy = hibmc_drm_fb_destroy,
+};
+
+int hibmc_drm_fb_init(struct drm_device *dev,
+ struct hibmc_framebuffer *gfb,
+ struct drm_mode_fb_cmd2 *mode_cmd,
+ struct drm_gem_cma_object *obj)
+{
+ int ret;
+
+ drm_helper_mode_fill_fb_struct(&gfb->fb, mode_cmd);
+ gfb->obj = obj;
+ gfb->is_fbdev_fb = true;
+ ret = drm_framebuffer_init(dev, &gfb->fb, &hibmc_drm_fb_funcs);
+ if (ret) {
+ DRM_ERROR("drm_framebuffer_init failed: %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+struct drm_gem_cma_object *hibmc_drm_gem_create_object(
+ struct hibmc_private *hiprivate,
+ size_t size)
+{
+ struct drm_gem_cma_object *cma_obj;
+ struct drm_gem_object *gem_obj;
+ struct drm_device *drm = hiprivate->dev;
+ int ret;
+
+ cma_obj = devm_kzalloc(drm->dev, sizeof(*cma_obj), GFP_KERNEL);
+ if (!cma_obj)
+ return ERR_PTR(-ENOMEM);
+
+ gem_obj = &cma_obj->base;
+
+ ret = drm_gem_object_init(drm, gem_obj, size);
+ if (ret)
+ return ERR_PTR(ret);
+
+ cma_obj->vaddr = hiprivate->fb_map;
+ cma_obj->paddr = hiprivate->fb_base;
+ return cma_obj;
+}
+
+void hibmc_drm_gem_free_object(struct drm_gem_object *gem_obj)
+{
+ struct drm_gem_cma_object *cma_obj;
+
+ cma_obj = to_drm_gem_cma_obj(gem_obj);
+ drm_gem_object_release(gem_obj);
+}
+
+static struct fb_ops hibmc_drm_fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = drm_fb_helper_check_var,
+ .fb_set_par = drm_fb_helper_set_par,
+ .fb_fillrect = sys_fillrect,
+ .fb_copyarea = sys_copyarea,
+ .fb_imageblit = sys_imageblit,
+ .fb_pan_display = drm_fb_helper_pan_display,
+ .fb_blank = drm_fb_helper_blank,
+ .fb_setcmap = drm_fb_helper_setcmap,
+};
+
+static int hibmc_drm_fb_probe(struct drm_fb_helper *helper,
+ struct drm_fb_helper_surface_size *sizes)
+{
+ struct hibmc_private *hiprivate =
+ container_of(helper, struct hibmc_private, fbdev.helper);
+ struct drm_device *dev = hiprivate->dev;
+ struct fb_info *info;
+ struct drm_framebuffer *fb;
+ struct drm_mode_fb_cmd2 mode_cmd;
+ struct device *device = &dev->pdev->dev;
+ struct drm_gem_cma_object *obj = NULL;
+ int ret = 0;
+ size_t size;
+ unsigned int bytes_per_pixel;
+ unsigned long offset;
+
+ DRM_DEBUG_DRIVER("surface width(%d), height(%d) and bpp(%d)\n",
+ sizes->surface_width, sizes->surface_height,
+ sizes->surface_bpp);
+ sizes->surface_depth = 32;
+
+ bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
+
+ mode_cmd.width = sizes->surface_width;
+ mode_cmd.height = sizes->surface_height;
+ mode_cmd.pitches[0] = mode_cmd.width * bytes_per_pixel;
+ mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+ sizes->surface_depth);
+
+ size = roundup(mode_cmd.pitches[0] * mode_cmd.height, PAGE_SIZE);
+
+ obj = hibmc_drm_gem_create_object(hiprivate, size);
+ if (IS_ERR(obj)) {
+ DRM_ERROR("can't allocate gem object\n");
+ return -ENOMEM;
+ }
+
+ /* init fb device */
+ info = framebuffer_alloc(0, device);
+ if (!info) {
+ DRM_ERROR("can't allocate framebuffer\n");
+ goto err_drm_gem_cma_free_object;
+ }
+
+ ret = hibmc_drm_fb_init(hiprivate->dev,
+ &hiprivate->fbdev.fb, &mode_cmd, obj);
+ if (ret) {
+ DRM_ERROR("framebuffer init error\n");
+ goto err_drm_gem_cma_free_object;
+ }
+
+ /* setup helper */
+ fb = &hiprivate->fbdev.fb.fb;
+ hiprivate->fbdev.helper.fb = fb;
+ hiprivate->fbdev.helper.fbdev = info;
+
+ strcpy(info->fix.id, "hibmcdrmfb");
+ info->par = &hiprivate->fbdev.helper;
+ info->flags = FBINFO_DEFAULT;
+ info->fbops = &hibmc_drm_fb_ops;
+
+ drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
+ drm_fb_helper_fill_var(info, &hiprivate->fbdev.helper, sizes->fb_width,
+ sizes->fb_height);
+
+ offset = info->var.xoffset * bytes_per_pixel;
+ offset += info->var.yoffset * fb->pitches[0];
+
+ dev->mode_config.fb_base = (resource_size_t)obj->paddr;
+ info->screen_base = obj->vaddr + offset;
+ info->fix.smem_start = (unsigned long)(obj->paddr + offset);
+ info->screen_size = size;
+ info->fix.smem_len = size;
+
+ ret = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (ret) {
+ DRM_ERROR("%s: can't allocate color map\n", info->fix.id);
+ goto err_hisi_drm_fb_destroy;
+ }
+
+ return 0;
+
+err_hisi_drm_fb_destroy:
+ drm_framebuffer_unregister_private(fb);
+err_drm_gem_cma_free_object:
+ hibmc_drm_gem_free_object(&obj->base);
+ return ret;
+}
+
+static int hibmc_fbdev_destroy(struct hibmc_private *hiprivate)
+{
+ struct hibmc_framebuffer *gfb = &hiprivate->fbdev.fb;
+ struct fb_info *info;
+
+ DRM_DEBUG_DRIVER("hibmc_fbdev_destroy\n");
+
+ if (hiprivate->fbdev.helper.fbdev) {
+ info = hiprivate->fbdev.helper.fbdev;
+
+ unregister_framebuffer(info);
+ if (info->cmap.len)
+ fb_dealloc_cmap(&info->cmap);
+ framebuffer_release(info);
+ }
+
+ drm_framebuffer_unregister_private(&gfb->fb);
+ if (gfb->obj) {
+ drm_gem_object_unreference_unlocked(&gfb->obj->base);
+ gfb->obj = NULL;
+ }
+
+ drm_framebuffer_cleanup(&gfb->fb);
+ drm_fb_helper_fini(&hiprivate->fbdev.helper);
+
+ return 0;
+}
+
+static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = {
+ .fb_probe = hibmc_drm_fb_probe,
+};
+
+int hibmc_fbdev_init(struct hibmc_private *hiprivate)
+{
+ int ret;
+ struct fb_var_screeninfo *var;
+ struct fb_fix_screeninfo *fix;
+
+ drm_fb_helper_prepare(hiprivate->dev, &hiprivate->fbdev.helper,
+ &hibmc_fbdev_helper_funcs);
+
+ /* Now just one crtc and one channel */
+ ret = drm_fb_helper_init(hiprivate->dev,
+ &hiprivate->fbdev.helper, 1, 1);
+ if (ret)
+ return ret;
+
+ ret = drm_fb_helper_single_add_all_connectors(&hiprivate->fbdev.helper);
+ if (ret)
+ goto fini;
+
+ drm_helper_disable_unused_functions(hiprivate->dev);
+
+ ret = drm_fb_helper_initial_config(&hiprivate->fbdev.helper, 16);
+ if (ret)
+ goto fini;
+
+ hiprivate->fbdev.initialized = true;
+
+ var = &hiprivate->fbdev.helper.fbdev->var;
+ fix = &hiprivate->fbdev.helper.fbdev->fix;
+
+ DRM_DEBUG("Member of info->var is :\n"
+ "xres=%d\n"
+ "yres=%d\n"
+ "xres_virtual=%d\n"
+ "yres_virtual=%d\n"
+ "xoffset=%d\n"
+ "yoffset=%d\n"
+ "bits_per_pixel=%d\n"
+ "...\n", var->xres, var->yres, var->xres_virtual,
+ var->yres_virtual, var->xoffset, var->yoffset,
+ var->bits_per_pixel);
+ DRM_DEBUG("Member of info->fix is :\n"
+ "smem_start=%lx\n"
+ "smem_len=%d\n"
+ "type=%d\n"
+ "type_aux=%d\n"
+ "visual=%d\n"
+ "xpanstep=%d\n"
+ "ypanstep=%d\n"
+ "ywrapstep=%d\n"
+ "line_length=%d\n"
+ "accel=%d\n"
+ "capabilities=%d\n"
+ "...\n", fix->smem_start, fix->smem_len, fix->type,
+ fix->type_aux, fix->visual, fix->xpanstep,
+ fix->ypanstep, fix->ywrapstep, fix->line_length,
+ fix->accel, fix->capabilities);
+
+ return 0;
+
+fini:
+ drm_fb_helper_fini(&hiprivate->fbdev.helper);
+ return ret;
+}
+
+void hibmc_fbdev_fini(struct hibmc_private *hiprivate)
+{
+ if (!hiprivate->fbdev.initialized)
+ return;
+
+ hibmc_fbdev_destroy(hiprivate);
+ hiprivate->fbdev.initialized = false;
+}
--
1.9.1
More information about the dri-devel
mailing list