AMLOGIC DRM DRIVER
M: Sky Zhou <sky.zhou@amlogic.com>
F: driver/amlogic/drm/*
+F: driver/amlogic/drm/am_meson_fbdev.c
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
* 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);
}
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 = {
.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)
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;
+}
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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 */
}
}
-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,
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);
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);
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);
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:
{
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;
}
{
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 = {
{
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)
#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"
drm->mode_config.max_width = 8192;
drm->mode_config.max_height = 8192;
drm->mode_config.funcs = &meson_mode_config_funcs;
-
+ drm_kms_helper_poll_init(drm);
#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);
+ ret = meson_drm_fbdev_init(drm);
+ if (ret)
goto free_drm;
- }
+ drm->mode_config.allow_fb_modifiers = true;
#endif
-
- drm_kms_helper_poll_init(drm);
-
platform_set_drvdata(pdev, priv);
ret = drm_dev_register(drm, 0);
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
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;