Skip to content

Commit

Permalink
drm/mediatek: Add MTK Framebuffer-Device (mt7623)
Browse files Browse the repository at this point in the history
This patch adds Framebuffer-Driver for Mediatek

currently tested on mt7623, maybe works on other platforms
MTK-FBDev written by CK Hu and ported from 4.4

based on patchset drm/hdmi for 7623 v5 (except last part included in 4.20)
  https://patchwork.kernel.org/project/linux-mediatek/list/?series=25989

depends on
  dts-patch (resend of 5/5, parts 1-4 already in 4.20):
    "arm: dts: mt7623: add display subsystem related device nodes"
    https://patchwork.kernel.org/patch/10588951/
  2 bugfix-patches from bibby hsieh
    fix-boot-up-for-720-and-480-but-1080
    using-different-round-rate-for-mt7623
  1 Patch from Ryder Lee
    http://forum.banana-pi.org/t/kernel-4-19-rc1-for-testers/6618/52

full working tree here for reference:
https://github.com/frank-w/BPI-R2-4.14/commits/4.20-hdmiv5

v2: [fbdev] fix problems mentioned by CK Hu

Signed-off-by: CK Hu <[email protected]>
Signed-off-by: Alexander Ryabchenko <[email protected]>
Signed-off-by: Frank Wunderlich <[email protected]>
Tested-by: Frank Wunderlich <[email protected]>
  • Loading branch information
ckhu-mediatek authored and frank-w committed Jan 9, 2019
1 parent 88aa4bf commit 4bda848
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 2 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/mediatek/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ mediatek-drm-y := mtk_disp_color.o \
mtk_mipi_tx.o \
mtk_dpi.o

mediatek-drm-$(CONFIG_DRM_FBDEV_EMULATION) += mtk_drm_fbdev.o
obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o

mediatek-drm-hdmi-objs := mtk_cec.o \
Expand Down
6 changes: 6 additions & 0 deletions drivers/gpu/drm/mediatek/mtk_drm_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "mtk_drm_ddp_comp.h"
#include "mtk_drm_drv.h"
#include "mtk_drm_fb.h"
#include "mtk_drm_fbdev.h"
#include "mtk_drm_gem.h"

#define DRIVER_NAME "mediatek"
Expand Down Expand Up @@ -299,6 +300,10 @@ static int mtk_drm_kms_init(struct drm_device *drm)
drm_kms_helper_poll_init(drm);
drm_mode_config_reset(drm);

ret = mtk_fbdev_init(drm);
if (ret)
goto err_component_unbind;

return 0;

err_component_unbind:
Expand All @@ -311,6 +316,7 @@ static int mtk_drm_kms_init(struct drm_device *drm)

static void mtk_drm_kms_deinit(struct drm_device *drm)
{
mtk_fbdev_fini(drm);
drm_kms_helper_poll_fini(drm);

component_unbind_all(drm->dev, drm);
Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/mediatek/mtk_drm_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#ifndef MTK_DRM_DRV_H
#define MTK_DRM_DRV_H

#include <drm/drm_fb_helper.h>
#include <linux/io.h>
#include "mtk_drm_ddp_comp.h"

Expand Down Expand Up @@ -59,6 +60,8 @@ struct mtk_drm_private {
} commit;

struct drm_atomic_state *suspend_state;
struct drm_fb_helper fb_helper;
struct drm_gem_object *fbdev_bo;
};

extern struct platform_driver mtk_ddp_driver;
Expand Down
3 changes: 1 addition & 2 deletions drivers/gpu/drm/mediatek/mtk_drm_fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ static const struct drm_framebuffer_funcs mtk_drm_fb_funcs = {
.destroy = drm_gem_fb_destroy,
};

static struct drm_framebuffer *mtk_drm_framebuffer_init(struct drm_device *dev,
struct drm_framebuffer *mtk_drm_framebuffer_init(struct drm_device *dev,
const struct drm_mode_fb_cmd2 *mode,
struct drm_gem_object *obj)
{
Expand All @@ -55,7 +55,6 @@ static struct drm_framebuffer *mtk_drm_framebuffer_init(struct drm_device *dev,

return fb;
}

/*
* Wait for any exclusive fence in fb's gem object's reservation object.
*
Expand Down
4 changes: 4 additions & 0 deletions drivers/gpu/drm/mediatek/mtk_drm_fb.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@ struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev,
struct drm_file *file,
const struct drm_mode_fb_cmd2 *cmd);

struct drm_framebuffer *mtk_drm_framebuffer_init(struct drm_device *dev,
const struct drm_mode_fb_cmd2 *mode,
struct drm_gem_object *obj);

#endif /* MTK_DRM_FB_H */
176 changes: 176 additions & 0 deletions drivers/gpu/drm/mediatek/mtk_drm_fbdev.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018 MediaTek Inc.
* Author: CK Hu <[email protected]>
*/

#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_gem.h>

#include "mtk_drm_drv.h"
#include "mtk_drm_fb.h"
#include "mtk_drm_fbdev.h"
#include "mtk_drm_gem.h"

#define to_drm_private(x) \
container_of(x, struct mtk_drm_private, fb_helper)

static int mtk_drm_fbdev_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
struct drm_fb_helper *helper = info->par;
struct mtk_drm_private *private = to_drm_private(helper);

return mtk_drm_gem_mmap_buf(private->fbdev_bo, vma);
}

static struct fb_ops mtk_fbdev_ops = {
.owner = THIS_MODULE,
DRM_FB_HELPER_DEFAULT_OPS,
.fb_fillrect = drm_fb_helper_cfb_fillrect,
.fb_copyarea = drm_fb_helper_cfb_copyarea,
.fb_imageblit = drm_fb_helper_cfb_imageblit,
.fb_pan_display = drm_fb_helper_pan_display,
.fb_mmap = mtk_drm_fbdev_mmap,
};

static int mtk_fbdev_probe(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
{
struct drm_device *dev = helper->dev;
struct mtk_drm_private *private = to_drm_private(helper);
struct drm_mode_fb_cmd2 mode = { 0 };
struct mtk_drm_gem_obj *mtk_gem;
struct fb_info *info;
struct drm_framebuffer *fb;
unsigned int bytes_per_pixel;
unsigned long offset;
size_t size;
int err;

bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);

mode.width = sizes->surface_width;
mode.height = sizes->surface_height;
mode.pitches[0] = sizes->surface_width * bytes_per_pixel;
mode.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
sizes->surface_depth);

size = mode.pitches[0] * mode.height;

mtk_gem = mtk_drm_gem_create(dev, size, true);
if (IS_ERR(mtk_gem))
return PTR_ERR(mtk_gem);

private->fbdev_bo = &mtk_gem->base;

info = drm_fb_helper_alloc_fbi(helper);
if (IS_ERR(info)) {
err = PTR_ERR(info);
DRM_DEV_ERROR(dev->dev,
"failed to allocate framebuffer info, %d\n",
err);
goto err_gem_free_object;
}

fb = mtk_drm_framebuffer_init(dev, &mode, private->fbdev_bo);
if (IS_ERR(fb)) {
err = PTR_ERR(fb);
DRM_DEV_ERROR(dev->dev,
"failed to allocate DRM framebuffer, %d\n",
err);
goto err_gem_release_info;
}
helper->fb = fb;

info->par = helper;
info->flags = FBINFO_FLAG_DEFAULT;
info->fbops = &mtk_fbdev_ops;

drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
drm_fb_helper_fill_var(info, 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 = 0;
info->screen_base = mtk_gem->kvaddr + offset;
info->screen_size = size;
info->fix.smem_len = size;

DRM_DEBUG_KMS("FB [%ux%u]-%u offset=%lu size=%zd\n",
fb->width, fb->height, fb->format->depth, offset, size);

info->skip_vt_switch = true;

return 0;

err_gem_release_info:

drm_fb_helper_unregister_fbi(helper);

err_gem_free_object:

mtk_drm_gem_free_object(&mtk_gem->base);
return err;
}

static const struct drm_fb_helper_funcs mtk_drm_fb_helper_funcs = {
.fb_probe = mtk_fbdev_probe,
};

int mtk_fbdev_init(struct drm_device *dev)
{
struct mtk_drm_private *priv = dev->dev_private;
struct drm_fb_helper *helper = &priv->fb_helper;
int ret;

if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector)
return -EINVAL;

drm_fb_helper_prepare(dev, helper, &mtk_drm_fb_helper_funcs);

ret = drm_fb_helper_init(dev, helper, dev->mode_config.num_connector);
if (ret < 0) {
DRM_DEV_ERROR(dev->dev,
"failed to initialize DRM FB helper, %d\n",
ret);
return ret;
}

ret = drm_fb_helper_single_add_all_connectors(helper);
if (ret < 0) {
DRM_DEV_ERROR(dev->dev, "failed to add connectors, %d\n", ret);
goto err_fini;
}

ret = drm_fb_helper_initial_config(helper, 32);
if (ret < 0) {
DRM_DEV_ERROR(dev->dev,
"failed to set initial configuration, %d\n",
ret);
goto err_fini;
}

return 0;

err_fini:
drm_fb_helper_fini(helper);
return ret;
}

void mtk_fbdev_fini(struct drm_device *dev)
{
struct mtk_drm_private *priv = dev->dev_private;
struct drm_fb_helper *helper = &priv->fb_helper;

drm_fb_helper_unregister_fbi(helper);

if (helper->fb) {
drm_framebuffer_unregister_private(helper->fb);
drm_framebuffer_remove(helper->fb);
}

drm_fb_helper_fini(helper);
}
25 changes: 25 additions & 0 deletions drivers/gpu/drm/mediatek/mtk_drm_fbdev.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2018 MediaTek Inc.
* Author: CK Hu <[email protected]>
*/

#ifndef MTK_DRM_FBDEV_H
#define MTK_DRM_FBDEV_H

#ifdef CONFIG_DRM_FBDEV_EMULATION
int mtk_fbdev_init(struct drm_device *dev);
void mtk_fbdev_fini(struct drm_device *dev);
#else
int mtk_fbdev_init(struct drm_device *dev)
{
return 0;
}

void mtk_fbdev_fini(struct drm_device *dev)
{

}
#endif /* CONFIG_DRM_FBDEV_EMULATION */

#endif /* MTK_DRM_FBDEV_H */

0 comments on commit 4bda848

Please sign in to comment.