drm: add fbdev emulate implement

PD#152825: add amlogic emulate fbdev implement
it just support software renderring mode

Change-Id: Iffb3b83bbfcc831608e46d9c176fc6c8da8e3ff4
Signed-off-by: Yalong Liu <yalong.liu@amlogic.com>
This commit is contained in:
Yalong Liu
2017-10-30 10:54:27 +08:00
committed by Jianxin Pan
parent 72b7250455
commit 5ab46dc70c
11 changed files with 338 additions and 25 deletions

View File

@@ -14114,3 +14114,4 @@ F: drivers/amlogic/media/video_processor/pic_dev/*
AMLOGIC DRM DRIVER
M: Sky Zhou <sky.zhou@amlogic.com>
F: driver/amlogic/drm/*
F: driver/amlogic/drm/am_meson_fbdev.c

View File

@@ -12,4 +12,8 @@ ifeq ($(CONFIG_DRM_MESON_USE_ION),y)
ccflags-y += -Idrivers/staging/android/
endif
ifeq ($(CONFIG_DRM_MESON_EMULATE_FBDEV),y)
meson-y += am_meson_fbdev.o
endif
obj-$(CONFIG_DRM_MESON) += meson.o

View File

@@ -14,16 +14,18 @@
* more details.
*
*/
#include <drm/drm_atomic_helper.h>
#include "am_meson_fb.h"
#define to_am_meson_fb(x) container_of(x, struct am_meson_fb, base)
void am_meson_fb_destroy(struct drm_framebuffer *framebuffer)
void am_meson_fb_destroy(struct drm_framebuffer *fb)
{
struct am_meson_fb *meson_fb = to_am_meson_fb(framebuffer);
struct am_meson_fb *meson_fb = to_am_meson_fb(fb);
drm_gem_object_unreference_unlocked(&meson_fb->bufp->base);
drm_framebuffer_cleanup(framebuffer);
drm_framebuffer_cleanup(fb);
kfree(meson_fb);
}
@@ -31,8 +33,10 @@ int am_meson_fb_create_handle(struct drm_framebuffer *fb,
struct drm_file *file_priv,
unsigned int *handle)
{
DRM_INFO("ERROR: am_meson_fb_create_handle NOT implement.\n");
return 0;
struct am_meson_fb *meson_fb = to_am_meson_fb(fb);
return drm_gem_handle_create(file_priv,
&meson_fb->bufp->base, handle);
}
struct drm_framebuffer_funcs am_meson_fb_funcs = {
@@ -40,6 +44,39 @@ struct drm_framebuffer_funcs am_meson_fb_funcs = {
.destroy = am_meson_fb_destroy,
};
struct drm_framebuffer *
am_meson_fb_alloc(struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj)
{
struct am_meson_fb *meson_fb;
struct am_meson_gem_object *meson_gem;
int ret = 0;
meson_fb = kzalloc(sizeof(*meson_fb), GFP_KERNEL);
if (!meson_fb)
return ERR_PTR(-ENOMEM);
meson_gem = container_of(obj, struct am_meson_gem_object, base);
meson_fb->bufp = meson_gem;
drm_helper_mode_fill_fb_struct(&meson_fb->base, mode_cmd);
ret = drm_framebuffer_init(dev, &meson_fb->base,
&am_meson_fb_funcs);
if (ret) {
dev_err(dev->dev, "Failed to initialize framebuffer: %d\n",
ret);
goto err_free_fb;
}
return &meson_fb->base;
err_free_fb:
kfree(meson_fb);
return ERR_PTR(ret);
}
struct drm_framebuffer *am_meson_fb_create(struct drm_device *dev,
struct drm_file *file_priv,
const struct drm_mode_fb_cmd2 *mode_cmd)
@@ -78,3 +115,17 @@ struct drm_framebuffer *am_meson_fb_create(struct drm_device *dev,
return &meson_fb->base;
}
struct drm_framebuffer *
am_meson_drm_framebuffer_init(struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj)
{
struct drm_framebuffer *fb;
fb = am_meson_fb_alloc(dev, mode_cmd, obj);
if (IS_ERR(fb))
return NULL;
return fb;
}

View File

@@ -32,4 +32,8 @@ struct am_meson_fb {
struct drm_framebuffer *am_meson_fb_create(struct drm_device *dev,
struct drm_file *file_priv,
const struct drm_mode_fb_cmd2 *mode_cmd);
struct drm_framebuffer *am_meson_drm_framebuffer_init(
struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj);
#endif

View File

@@ -0,0 +1,217 @@
/*
* drivers/amlogic/drm/am_meson_fbdev.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <drm/drm.h>
#include <drm/drmP.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>
#include "meson_drv.h"
#include "am_meson_gem.h"
#include "am_meson_fb.h"
#include "am_meson_fbdev.h"
#define PREFERRED_BPP 32
#define MESON_DRM_MAX_CONNECTOR 2
static int meson_fbdev_mmap(struct fb_info *info,
struct vm_area_struct *vma)
{
struct drm_fb_helper *helper = info->par;
struct meson_drm *private;
struct am_meson_gem_object *meson_gem;
private = helper->dev->dev_private;
meson_gem = container_of(private->fbdev_bo,
struct am_meson_gem_object, base);
return am_meson_gem_object_mmap(meson_gem, vma);
}
static int meson_drm_fbdev_sync(struct fb_info *info)
{
return 0;
}
static int meson_drm_fbdev_ioctl(struct fb_info *info,
unsigned int cmd, unsigned long arg)
{
return 0;
}
static struct fb_ops meson_drm_fbdev_ops = {
.owner = THIS_MODULE,
.fb_mmap = meson_fbdev_mmap,
.fb_fillrect = drm_fb_helper_cfb_fillrect,
.fb_copyarea = drm_fb_helper_cfb_copyarea,
.fb_imageblit = drm_fb_helper_cfb_imageblit,
.fb_check_var = drm_fb_helper_check_var,
.fb_set_par = drm_fb_helper_set_par,
.fb_blank = drm_fb_helper_blank,
.fb_pan_display = drm_fb_helper_pan_display,
.fb_setcmap = drm_fb_helper_setcmap,
.fb_sync = meson_drm_fbdev_sync,
.fb_ioctl = meson_drm_fbdev_ioctl,
#ifdef CONFIG_COMPAT
.fb_compat_ioctl = meson_drm_fbdev_ioctl,
#endif
};
static int meson_drm_fbdev_create(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
{
struct meson_drm *private = helper->dev->dev_private;
struct drm_mode_fb_cmd2 mode_cmd = { 0 };
struct drm_device *dev = helper->dev;
struct am_meson_gem_object *meson_obj;
struct drm_framebuffer *fb;
struct ion_client *client;
unsigned int bytes_per_pixel;
unsigned long offset;
struct fb_info *fbi;
size_t size;
int ret;
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] = ALIGN(sizes->surface_width * bytes_per_pixel, 64);
mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
sizes->surface_depth);
size = mode_cmd.pitches[0] * mode_cmd.height;
client = (struct ion_client *)private->gem_client;
meson_obj = am_meson_gem_object_create(dev, 0, size, client);
if (IS_ERR(meson_obj))
return -ENOMEM;
private->fbdev_bo = &meson_obj->base;
fbi = drm_fb_helper_alloc_fbi(helper);
if (IS_ERR(fbi)) {
dev_err(dev->dev, "Failed to create framebuffer info.\n");
ret = PTR_ERR(fbi);
goto err_meson_gem_free_object;
}
helper->fb = am_meson_drm_framebuffer_init(dev, &mode_cmd,
private->fbdev_bo);
if (IS_ERR(helper->fb)) {
dev_err(dev->dev, "Failed to allocate DRM framebuffer.\n");
ret = PTR_ERR(helper->fb);
goto err_release_fbi;
}
fbi->par = helper;
fbi->flags = FBINFO_FLAG_DEFAULT;
fbi->fbops = &meson_drm_fbdev_ops;
fb = helper->fb;
drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height);
offset = fbi->var.xoffset * bytes_per_pixel;
offset += fbi->var.yoffset * fb->pitches[0];
dev->mode_config.fb_base = 0;
fbi->screen_size = size;
fbi->fix.smem_len = size;
DRM_DEBUG_KMS("FB [%dx%d]-%d offset=%ld size=%zu\n",
fb->width, fb->height, fb->depth, offset, size);
fbi->skip_vt_switch = true;
return 0;
err_release_fbi:
drm_fb_helper_release_fbi(helper);
err_meson_gem_free_object:
am_meson_gem_object_free(&meson_obj->base);
return ret;
}
static const struct drm_fb_helper_funcs meson_drm_fb_helper_funcs = {
.fb_probe = meson_drm_fbdev_create,
};
int meson_drm_fbdev_init(struct drm_device *dev)
{
struct meson_drm *private = dev->dev_private;
struct drm_fb_helper *helper;
unsigned int num_crtc;
int ret;
if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector)
return -EINVAL;
num_crtc = dev->mode_config.num_crtc;
helper = devm_kzalloc(dev->dev, sizeof(*helper), GFP_KERNEL);
if (!helper)
return -ENOMEM;
drm_fb_helper_prepare(dev, helper, &meson_drm_fb_helper_funcs);
ret = drm_fb_helper_init(dev, helper, num_crtc,
MESON_DRM_MAX_CONNECTOR);
if (ret < 0) {
dev_err(dev->dev, "Failed to initialize drm fb helper - %d.\n",
ret);
goto err_free;
}
ret = drm_fb_helper_single_add_all_connectors(helper);
if (ret < 0) {
dev_err(dev->dev, "Failed to add connectors - %d.\n", ret);
goto err_drm_fb_helper_fini;
}
ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP);
if (ret < 0) {
dev_err(dev->dev, "Failed to set initial hw config - %d.\n",
ret);
goto err_drm_fb_helper_fini;
}
private->fbdev_helper = helper;
return 0;
err_drm_fb_helper_fini:
drm_fb_helper_fini(helper);
err_free:
kfree(fbdev_cma);
return ret;
}
void meson_drm_fbdev_fini(struct drm_device *dev)
{
struct meson_drm *private = dev->dev_private;
struct drm_fb_helper *helper = private->fbdev_helper;
if (!helper)
return;
drm_fb_helper_unregister_fbi(helper);
drm_fb_helper_release_fbi(helper);
if (helper->fb)
drm_framebuffer_unreference(helper->fb);
drm_fb_helper_fini(helper);
}

View File

@@ -0,0 +1,24 @@
/*
* drivers/amlogic/drm/am_meson_fbdev.h
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _MESON_DRM_FBDEV_H
#define _MESON_DRM_FBDEV_H
#ifdef CONFIG_DRM_MESON_EMULATE_FBDEV
int meson_drm_fbdev_init(struct drm_device *dev);
void meson_drm_fbdev_fini(struct drm_device *dev);
#endif
#endif /* _MESON_DRM_FBDEV_H */

View File

@@ -81,7 +81,7 @@ static void am_meson_gem_free_ion_buf(
}
}
static struct am_meson_gem_object *am_meson_gem_object_create(
struct am_meson_gem_object *am_meson_gem_object_create(
struct drm_device *dev,
unsigned int flags,
unsigned long size,
@@ -207,7 +207,7 @@ int am_meson_gem_mmap(
obj = vma->vm_private_data;
meson_gem_obj = to_am_meson_gem_obj(obj);
DRM_ERROR("am_meson_gem_mmap %p.\n", meson_gem_obj);
DRM_DEBUG("am_meson_gem_mmap %p.\n", meson_gem_obj);
ret = am_meson_gem_object_mmap(meson_gem_obj, vma);
@@ -221,6 +221,11 @@ int am_meson_gem_object_get_phyaddr(
int addr;
size_t len;
if (!meson_gem->handle) {
DRM_INFO("%s handle null\n", __func__);
return -1;
}
ion_phys(drm->gem_client, meson_gem->handle,
(ion_phys_addr_t *)&addr, &len);

View File

@@ -60,8 +60,16 @@ int am_meson_gem_dumb_map_offset(
uint64_t *offset);
/* GEM OBJECT OPERATIONS */
struct am_meson_gem_object *am_meson_gem_object_create(
struct drm_device *dev, unsigned int flags,
unsigned long size, struct ion_client *client);
void am_meson_gem_object_free(struct drm_gem_object *gem_obj);
int am_meson_gem_object_mmap(
struct am_meson_gem_object *obj,
struct vm_area_struct *vma);
int am_meson_gem_object_get_phyaddr(
struct meson_drm *drm,
struct am_meson_gem_object *meson_gem);

View File

@@ -86,7 +86,7 @@ void am_osd_do_display(
dma_addr_t phyaddr;
unsigned long flags;
//DRM_INFO("am_osd_do_display osd %d.\n", osd_plane->osd_idx);
//DRM_INFO("%s osd %d.\n", __func__, osd_plane->osd_idx);
switch (fb->pixel_format) {
case DRM_FORMAT_XRGB8888:
@@ -174,7 +174,7 @@ int am_osd_check(struct drm_plane *plane, struct drm_plane_state *state)
{
struct am_osd_plane *osd_plane = to_am_osd_plane(plane);
DRM_DEBUG("am_osd_check osd %d.\n", osd_plane->osd_idx);
DRM_DEBUG("%s osd %d.\n", __func__, osd_plane->osd_idx);
return 0;
}
@@ -182,7 +182,7 @@ void am_osd_blank(struct drm_plane *plane, struct drm_plane_state *old_state)
{
struct am_osd_plane *osd_plane = to_am_osd_plane(plane);
DRM_DEBUG("am_osd_blank osd %d.\n", osd_plane->osd_idx);
DRM_DEBUG("%s osd %d.\n", __func__, osd_plane->osd_idx);
}
static const struct drm_plane_helper_funcs am_osd_helper_funcs = {
@@ -238,7 +238,7 @@ int meson_plane_create(struct meson_drm *priv)
{
struct am_osd_plane *plane;
DRM_DEBUG("amlogic meson_plane_create. enter\n");
DRM_DEBUG("%s. enter\n", __func__);
/*crate primary plane*/
plane = am_osd_plane_create(priv, DRM_PLANE_TYPE_PRIMARY);
if (plane == NULL)

View File

@@ -55,6 +55,9 @@
#include "am_meson_gem.h"
#include "am_meson_fb.h"
#endif
#ifdef CONFIG_DRM_MESON_EMULATE_FBDEV
#include "am_meson_fbdev.h"
#endif
#define DRIVER_NAME "meson"
#define DRIVER_DESC "Amlogic Meson DRM driver"
@@ -328,19 +331,13 @@ static int meson_drv_probe(struct platform_device *pdev)
drm->mode_config.max_width = 8192;
drm->mode_config.max_height = 8192;
drm->mode_config.funcs = &meson_mode_config_funcs;
#ifdef CONFIG_DRM_MESON_EMULATE_FBDEV
priv->fbdev = drm_fbdev_cma_init(drm, 32,
drm->mode_config.num_crtc,
drm->mode_config.num_connector);
if (IS_ERR(priv->fbdev)) {
ret = PTR_ERR(priv->fbdev);
goto free_drm;
}
#endif
drm_kms_helper_poll_init(drm);
#ifdef CONFIG_DRM_MESON_EMULATE_FBDEV
ret = meson_drm_fbdev_init(drm);
if (ret)
goto free_drm;
drm->mode_config.allow_fb_modifiers = true;
#endif
platform_set_drvdata(pdev, priv);
ret = drm_dev_register(drm, 0);
@@ -369,10 +366,10 @@ static int meson_drv_remove(struct platform_device *pdev)
osd_drm_debugfs_exit();
#endif
drm_dev_unregister(drm);
drm_kms_helper_poll_fini(drm);
#ifdef CONFIG_DRM_MESON_EMULATE_FBDEV
drm_fbdev_cma_fini(priv->fbdev);
meson_drm_fbdev_fini(drm);
#endif
drm_kms_helper_poll_fini(drm);
drm_mode_config_cleanup(drm);
drm_vblank_cleanup(drm);
#ifdef CONFIG_DRM_MESON_USE_ION

View File

@@ -41,6 +41,8 @@ struct meson_drm {
struct drm_device *drm;
struct drm_crtc *crtc;
struct drm_fbdev_cma *fbdev;
struct drm_fb_helper *fbdev_helper;
struct drm_gem_object *fbdev_bo;
struct drm_plane *primary_plane;
struct drm_plane *cursor_plane;