+ccflags-y += -I$(srctree)/drivers/amlogic
+
ifeq ($(CONFIG_DRM_MESON_USE_ION),y)
meson-drm-y += meson_gem.o meson_fb.o
ccflags-y += -Idrivers/staging/android/
meson-drm-y += meson_drv.o meson_plane.o meson_vpu_pipeline_traverse.o \
meson_crtc.o meson_vpu_pipeline.o meson_vpu_pipeline_private.o \
meson_debugfs.o meson_vpu_util.o \
+ meson_fence.o
meson-drm-y += \
vpu-hw/meson_vpu_osd_mif.o \
.atomic_flush = am_meson_crtc_atomic_flush,
};
-int am_meson_crtc_create(struct am_meson_crtc *amcrtc)
+int am_meson_crtc_create(struct am_meson_crtc *amcrtc,
+ struct osd_device_data_s *osd_dev)
{
struct meson_drm *priv = amcrtc->priv;
struct drm_crtc *crtc = &amcrtc->base;
DRM_INFO("%s\n", __func__);
ret = drm_crtc_init_with_planes(priv->drm, crtc,
- priv->primary_plane, priv->cursor_plane,
+ priv->primary_plane, NULL,
&am_meson_crtc_funcs, "amlogic vpu");
if (ret) {
dev_err(amcrtc->dev, "Failed to init CRTC\n");
}
drm_crtc_helper_add(crtc, &am_crtc_helper_funcs);
- osd_drm_init(&osd_meson_dev);
+ osd_drm_init(osd_dev);
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT
amvecm_drm_init(0);
return 0;
}
-
+EXPORT_SYMBOL(am_meson_crtc_create);
struct am_meson_crtc, base)
#define to_am_meson_crtc_state(x) container_of(x, \
struct am_meson_crtc_state, base)
-
-int am_meson_crtc_create(struct am_meson_crtc *amcrtc);
+int am_meson_crtc_create(struct am_meson_crtc *amcrtc,
+ struct osd_device_data_s *osd_dev);
#endif
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
#include <linux/seq_file.h>
-#endif
+
+#include <drm/drmP.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#endif /* CONFIG_DEBUG_FS */
#include "meson_drv.h"
#include "meson_crtc.h"
#ifdef CONFIG_DEBUG_FS
+struct meson_gem_info_debugfs {
+ struct drm_file *filp;
+ struct seq_file *m;
+};
+
static int meson_dump_show(struct seq_file *sf, void *data)
{
struct drm_crtc *crtc = sf->private;
&dev->vma_offset_manager->vm_addr_space_mm);
}
+static int meson_gem_info_print(int id, void *ptr, void *data)
+{
+ struct drm_gem_object *obj = ptr;
+ struct meson_gem_info_debugfs *gem_info = data;
+
+ if(!obj) {
+ pr_err("obj is already null\n");
+ return 0;
+ }
+
+ if(gem_info) {
+ seq_printf(gem_info->m, " %5d %3d %4d %8zd %3d %3d %6d\n",
+ gem_info->filp->drm_pid,
+ obj->name,
+ id,
+ obj->size,
+ atomic_read(&obj->refcount.refcount),
+ obj->handle_count,
+ obj->import_attach ? 1 : 0);
+ }
+ return 0;
+}
+
+static int meson_gem_info(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *)m->private;
+ struct drm_device *drm_dev = node->minor->dev;
+ struct meson_gem_info_debugfs gem_info;
+
+ seq_printf(m, " pid name id size ref handles import\n");
+
+ gem_info.m = m;
+
+ mutex_lock(&drm_dev->struct_mutex);
+ list_for_each_entry_reverse(gem_info.filp, &drm_dev->filelist, lhead) {
+ spin_lock(&gem_info.filp->table_lock);
+ idr_for_each(&gem_info.filp->object_idr, meson_gem_info_print,
+ &gem_info);
+ spin_unlock(&gem_info.filp->table_lock);
+ }
+ mutex_unlock(&drm_dev->struct_mutex);
+
+ return 0;
+}
+
static struct drm_info_list meson_debugfs_list[] = {
{"mm", mm_show, 0},
+ {"gem_info", meson_gem_info, 0},
};
int meson_debugfs_init(struct drm_minor *minor)
drm_debugfs_remove_files(meson_debugfs_list,
ARRAY_SIZE(meson_debugfs_list), minor);
}
-#endif
+#endif /* CONFIG_DEBUG_FS */
#include <drm/drm_rect.h>
#include <drm/drm_fb_helper.h>
+#include "osd_hw.h"
#include "meson_fbdev.h"
#ifdef CONFIG_DRM_MESON_USE_ION
#include "meson_gem.h"
#include "meson_fb.h"
#endif
#include "meson_drv.h"
+#include "meson_vpu.h"
#include "meson_vpu_pipeline.h"
-
+#include "meson_fence.h"
#define DRIVER_NAME "meson"
#define DRIVER_DESC "Amlogic Meson DRM driver"
{
}
-static void am_meson_load(struct drm_device *dev)
-{
-#if 0
- struct meson_drm *priv = dev->dev_private;
- struct drm_crtc *crtc = priv->crtc;
- int pipe = drm_crtc_index(crtc);
-
- if (priv->crtc_funcs[pipe] &&
- priv->crtc_funcs[pipe]->loader_protect)
- priv->crtc_funcs[pipe]->loader_protect(crtc, true);
-#endif
-}
#ifdef CONFIG_DRM_MESON_USE_ION
static const struct drm_ioctl_desc meson_ioctls[] = {
DRM_IOCTL_DEF_DRV(MESON_GEM_CREATE, am_meson_gem_create_ioctl,
- DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(MESON_GEM_GET, am_meson_gem_get_ioctl,
+ DRM_UNLOCKED),
+ DRM_IOCTL_DEF_DRV(MESON_SET_BLANK, am_meson_drv_set_blank_ioctl,
+ DRM_UNLOCKED),
+ DRM_IOCTL_DEF_DRV(MESON_GEM_SYNC, am_meson_gem_sync_ioctl,
+ DRM_UNLOCKED | DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(MESON_GEM_CPU_PREP, am_meson_gem_cpu_prep_ioctl,
+ DRM_UNLOCKED),
+ DRM_IOCTL_DEF_DRV(MESON_GEM_CPU_FINI, am_meson_gem_cpu_fini_ioctl,
+ DRM_UNLOCKED),
};
#endif
+int am_meson_drv_set_blank_ioctl(
+ struct drm_device *dev,
+ void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_meson_plane_blank *args = data;
+ u32 index, enable;
+
+ index = (args->plane_type == DRM_PLANE_TYPE_OVERLAY) ? OSD2 : OSD1;
+ enable = (args->onoff) ? 0 : 1;
+
+ osd_drm_plane_enable_hw(index, enable);
+
+ return 0;
+}
+
static const struct file_operations fops = {
.owner = THIS_MODULE,
.open = drm_open,
/* PRIME Ops */
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
-
+ .gem_open_object = am_meson_gem_open_object,
.gem_prime_export = drm_gem_prime_export,
.gem_prime_get_sg_table = am_meson_gem_prime_get_sg_table,
goto err_gem;
DRM_INFO("mode_config crtc number:%d\n", drm->mode_config.num_crtc);
+ priv->dev_fctx = am_meson_fence_context_create("meson.drm-fence");
+
+ if (IS_ERR(priv->dev_fctx))
+ goto err_unbind_all;
+
ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
if (ret)
- goto err_unbind_all;
+ goto err_fctx;
drm_mode_config_reset(drm);
drm->mode_config.max_width = 4096;
drm_kms_helper_poll_init(drm);
- am_meson_load(drm);
+ if (priv->primary_plane != NULL && priv->overlay_plane != NULL) {
+ drm_plane_create_zpos_property(priv->primary_plane, 0, 0, OSD_MAX);
+ drm_plane_create_zpos_property(priv->overlay_plane, 1, 0, OSD_MAX);
+ }
#ifdef CONFIG_DRM_MESON_EMULATE_FBDEV
ret = am_meson_drm_fbdev_init(drm);
return 0;
-
err_fbdev_fini:
#ifdef CONFIG_DRM_MESON_EMULATE_FBDEV
am_meson_drm_fbdev_fini(drm);
drm_vblank_cleanup(drm);
err_unbind_all:
component_unbind_all(dev, drm);
+err_fctx:
+ am_meson_fence_context_destroy(priv->dev_fctx);
err_gem:
drm_mode_config_cleanup(drm);
#ifdef CONFIG_DRM_MESON_USE_ION
static void am_meson_drm_unbind(struct device *dev)
{
struct drm_device *drm = dev_get_drvdata(dev);
+ struct meson_drm *priv = dev->driver_data;
drm_dev_unregister(drm);
#ifdef CONFIG_DRM_MESON_EMULATE_FBDEV
drm->irq_enabled = false;
drm_vblank_cleanup(drm);
component_unbind_all(dev, drm);
+ am_meson_fence_context_destroy(priv->dev_fctx);
drm_mode_config_cleanup(drm);
#ifdef CONFIG_DRM_MESON_USE_ION
am_meson_gem_cleanup(drm->dev_private);
if (strcmp(str, "okay") && strcmp(str, "ok")) {
DRM_INFO("device %s status is %s\n",
- node->name, str);
+ node->name, str);
} else {
DRM_INFO("device %s status is %s\n",
- node->name, str);
+ node->name, str);
return true;
}
}
struct component_match *match = NULL;
int i;
+ pr_info("[%s] in\n", __func__);
if (am_meson_drv_use_osd())
return am_meson_drv_probe_prune(pdev);
am_meson_add_endpoints(dev, &match, port);
of_node_put(port);
}
-
+ pr_info("[%s] out\n", __func__);
return component_master_add_with_match(dev, &am_meson_drm_ops, match);
}
struct drm_fb_helper *fbdev_helper;
struct drm_gem_object *fbdev_bo;
struct drm_plane *primary_plane;
- struct drm_plane *cursor_plane;
+ struct drm_plane *overlay_plane;
struct drm_property_blob *gamma_lut_blob;
#ifdef CONFIG_DRM_MESON_USE_ION
struct ion_client *gem_client;
#endif
+ struct meson_fence_context *dev_fctx;
+
struct meson_vpu_pipeline *pipeline;
struct meson_vpu_funcs *funcs;
+ struct am_meson_logo *logo;
u32 num_crtcs;
struct am_meson_crtc *crtcs[MESON_MAX_CRTC];
struct am_osd_plane *planes[MESON_MAX_OSD];
};
+int am_meson_drv_set_blank_ioctl(
+ struct drm_device *dev,
+ void *data,
+ struct drm_file *file_priv);
+
static inline int meson_vpu_is_compatible(struct meson_drm *priv,
const char *compat)
{
extern int am_meson_register_crtc_funcs(struct drm_crtc *crtc,
const struct meson_crtc_funcs *crtc_funcs);
extern void am_meson_unregister_crtc_funcs(struct drm_crtc *crtc);
+struct drm_connector *am_meson_hdmi_connector(void);
#ifdef CONFIG_DEBUG_FS
int meson_debugfs_init(struct drm_minor *minor);
#include <drm/drm_atomic_helper.h>
#include "meson_fb.h"
-
-#define to_am_meson_fb(x) container_of(x, struct am_meson_fb, base)
+#include "meson_vpu.h"
void am_meson_fb_destroy(struct drm_framebuffer *fb)
{
drm_gem_object_unreference_unlocked(&meson_fb->bufp->base);
drm_framebuffer_cleanup(fb);
+ DRM_DEBUG("meson_fb=0x%p,\n", meson_fb);
kfree(meson_fb);
}
if (!meson_fb)
return ERR_PTR(-ENOMEM);
- meson_gem = container_of(obj, struct am_meson_gem_object, base);
- meson_fb->bufp = meson_gem;
-
+ if (obj) {
+ meson_gem = container_of(obj, struct am_meson_gem_object, base);
+ meson_fb->bufp = meson_gem;
+ } else {
+ meson_fb->bufp = NULL;
+ }
drm_helper_mode_fill_fb_struct(&meson_fb->base, mode_cmd);
ret = drm_framebuffer_init(dev, &meson_fb->base,
ret);
goto err_free_fb;
}
+ DRM_INFO("meson_fb[id:%d,ref:%d]=0x%p,meson_fb->bufp=0x%p\n",
+ meson_fb->base.base.id,
+ atomic_read(&meson_fb->base.base.refcount.refcount),
+ meson_fb, meson_fb->bufp);
return &meson_fb->base;
kfree(meson_fb);
return ERR_PTR(ret);
}
+ DRM_DEBUG("meson_fb[in:%d,ref:%d]=0x%px,meson_fb->bufp=0x%p\n",
+ meson_fb->base.base.id,
+ atomic_read(&meson_fb->base.base.refcount.refcount),
+ meson_fb, meson_fb->bufp);
return &meson_fb->base;
}
#include "meson_gem.h"
+#define to_am_meson_fb(x) container_of(x, struct am_meson_fb, base)
+
+#define VMODE_NAME_LEN_MAX 64
+
+struct am_meson_logo {
+ struct page *logo_page;
+ phys_addr_t start;
+ u32 size;
+ u32 width;
+ u32 height;
+ u32 bpp;
+ u32 alloc_flag;
+ u32 info_loaded_mask;
+ char *outputmode_t;
+ char outputmode[VMODE_NAME_LEN_MAX];
+};
+
struct am_meson_fb {
struct drm_framebuffer base;
struct am_meson_gem_object *bufp;
+ struct am_meson_logo *logo;
};
-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);
+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);
+struct drm_framebuffer *
+am_meson_fb_alloc(struct drm_device *dev,
+ struct drm_mode_fb_cmd2 *mode_cmd,
+ struct drm_gem_object *obj);
+
#endif
--- /dev/null
+/*
+ * Copyright (C) 2019 Samsung Electronics Co.Ltd
+ *
+ * based on: drivers/gpu/drm/tilcdc/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "meson_fence.h"
+
+#define to_meson_fence(fence) container_of(fence, struct meson_fence, base)
+
+struct meson_fence_context*
+am_meson_fence_context_create(const char *name)
+{
+ struct meson_fence_context *fence_context;
+
+ fence_context = kmalloc(sizeof(*fence_context), GFP_KERNEL);
+ if (!fence_context)
+ return NULL;
+
+ fence_context->context = fence_context_alloc(1);
+ fence_context->name = name;
+ atomic_set(&fence_context->seqno, 0);
+ atomic_set(&fence_context->fence_count, 0);
+
+ return fence_context;
+}
+
+void
+am_meson_fence_context_destroy(
+ struct meson_fence_context *fence_context)
+{
+ unsigned fence_count;
+
+ fence_count = atomic_read(&fence_context->fence_count);
+ if (WARN_ON(fence_count))
+ DRM_DEBUG_DRIVER("%s context has %u fence(s) remaining\n",
+ fence_context->name, fence_count);
+
+ kfree(fence_context);
+}
+
+static const char*
+am_meson_fence_get_driver_name(struct fence *fence)
+{
+ return "meson.drm";
+}
+
+static const char*
+am_meson_fence_get_timeline_name(struct fence *fence)
+{
+ struct meson_fence *meson_fence = to_meson_fence(fence);
+ return meson_fence->fence_context->name;
+}
+
+static bool
+am_meson_fence_enable_signaling(struct fence *fence)
+{
+ return true;
+}
+
+static void
+am_meson_fence_release(struct fence *fence)
+{
+ struct meson_fence *meson_fence = to_meson_fence(fence);
+
+ atomic_dec(&meson_fence->fence_context->fence_count);
+ kfree(meson_fence);
+}
+
+static struct fence_ops meson_fence_ops = {
+ .get_driver_name = am_meson_fence_get_driver_name,
+ .get_timeline_name = am_meson_fence_get_timeline_name,
+ .enable_signaling = am_meson_fence_enable_signaling,
+ .wait = fence_default_wait,
+ .release = am_meson_fence_release,
+};
+
+static inline unsigned
+am_meson_fence_context_seqno_next(
+ struct meson_fence_context *fence_context)
+{
+ return atomic_inc_return(&fence_context->seqno) - 1;
+}
+
+struct fence *
+am_meson_fence_create(struct meson_fence_context *fence_context)
+{
+ struct meson_fence *meson_fence;
+ unsigned int seqno;
+
+ meson_fence = kmalloc(sizeof(*meson_fence), GFP_KERNEL);
+ if (!meson_fence)
+ return NULL;
+
+ spin_lock_init(&meson_fence->lock);
+ meson_fence->fence_context = fence_context;
+
+ seqno = am_meson_fence_context_seqno_next(fence_context);
+ fence_init(&meson_fence->base, &meson_fence_ops, &meson_fence->lock,
+ fence_context->context, seqno);
+
+ atomic_inc(&fence_context->fence_count);
+
+ return &meson_fence->base;
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2019 Samsung Electronics Co.Ltd
+ *
+ * based on: drivers/gpu/drm/tilcdc/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __MESON_FENCE_H__
+#define __MESON_FENCE_H__
+
+#include <linux/atomic.h>
+#include <linux/fence.h>
+#include <drm/drmP.h>
+
+struct meson_fence_context {
+ unsigned int context;
+ const char *name;
+ atomic_t seqno;
+ atomic_t fence_count;
+};
+
+struct meson_fence {
+ struct meson_fence_context *fence_context;
+ struct fence base;
+ spinlock_t lock;
+};
+
+struct meson_fence_context*
+am_meson_fence_context_create(const char *name);
+
+struct fence *
+am_meson_fence_create(struct meson_fence_context *fence_context);
+
+void
+am_meson_fence_context_destroy(struct meson_fence_context *fence_context);
+
+#endif /* __MESON_FENCE_H__ */
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/dma-buf.h>
-#include <linux/meson_ion.h>
+#include <media/common/ion_dev/meson_ion.h>
#include <ion/ion.h>
#include "meson_gem.h"
+#include "meson_fence.h"
#define to_am_meson_gem_obj(x) container_of(x, struct am_meson_gem_object, base)
//check flags to set different ion heap type.
//if flags is set to 0, need to use ion dma buffer.
- if (((flags & (MESON_USE_SCANOUT | MESON_USE_CURSOR)) != 0)
+ if (((flags & (MESON_USE_SCANOUT | MESON_USE_CURSOR | MESON_USE_OVERLAY)) != 0)
|| (flags == 0)) {
handle = ion_alloc(client, meson_gem_obj->base.size,
0, (1 << ION_HEAP_TYPE_DMA), 0);
bscatter = true;
}
- if (IS_ERR(handle)) {
+ if (IS_ERR_OR_NULL(handle)) {
DRM_ERROR("%s: FAILED, flags:0x%x.\n",
__func__, flags);
return -ENOMEM;
meson_gem_obj->handle = handle;
meson_gem_obj->bscatter = bscatter;
+ meson_gem_obj->flags = flags;
DRM_DEBUG("%s: allocate handle (%p).\n",
__func__, meson_gem_obj->handle);
return 0;
goto error;
}
+ /*for release check*/
+ meson_gem_obj->flags = flags;
+ meson_gem_obj->size = size;
+
+ reservation_object_init(&meson_gem_obj->resv);
+
return meson_gem_obj;
error:
DRM_DEBUG("am_meson_gem_object_free %p handle count = %d\n",
meson_gem_obj, obj->handle_count);
+ reservation_object_fini(&meson_gem_obj->resv);
+
if (obj->import_attach == false)
am_meson_gem_free_ion_buf(obj->dev, meson_gem_obj);
else
return ret;
}
+int am_meson_gem_open_object(
+ struct drm_gem_object *obj,
+ struct drm_file *file_priv)
+{
+ if (obj && file_priv)
+ file_priv->drm_pid = task_tgid_nr(current);
+
+ return 0;
+}
+
phys_addr_t am_meson_gem_object_get_phyaddr(
struct meson_drm *drm,
struct am_meson_gem_object *meson_gem)
}
ret = drm_gem_create_mmap_offset(obj);
- if (ret)
+ if (ret) {
+ struct am_meson_gem_object *meson_gem_obj = to_am_meson_gem_obj(obj);
+ reservation_object_fini(&meson_gem_obj->resv);
goto out;
+ }
*offset = drm_vma_node_offset_addr(&obj->vma_node);
DRM_DEBUG("offset = 0x%lx\n", (unsigned long)*offset);
}
}
+int am_meson_gem_get_ioctl(
+ struct drm_device *dev,
+ void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_gem_object *obj;
+ struct drm_meson_gem_info *args;
+ struct am_meson_gem_object *meson_gem_obj;
+
+ args = (struct drm_meson_gem_info *)data;
+ obj = drm_gem_object_lookup(file_priv, args->handle);
+ if (!obj) {
+ DRM_ERROR("failed to lookup gem object.\n");
+ return -EINVAL;
+ }
+ meson_gem_obj = to_am_meson_gem_obj(obj);
+ args->flags = meson_gem_obj->flags;
+ args->size = meson_gem_obj->size;
+
+ drm_gem_object_unreference_unlocked(obj);
+
+ return 0;
+}
+
+int am_meson_gem_sync_ioctl(
+ struct drm_device *dev,
+ void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_gem_object *obj;
+ struct drm_meson_gem_sync *args;
+ struct am_meson_gem_object *meson_gem_obj;
+ struct ion_buffer *buffer;
+ int ret = 0;
+
+ mutex_lock(&dev->struct_mutex);
+
+ args = (struct drm_meson_gem_sync *)data;
+ obj = drm_gem_object_lookup(file_priv, args->handle);
+ if (!obj) {
+ DRM_ERROR("failed to lookup gem object.\n");
+ ret = -EINVAL;
+ goto unlock;
+ }
+ meson_gem_obj = to_am_meson_gem_obj(obj);
+ if (!meson_gem_obj) {
+ DRM_ERROR("failed to lookup am_meson_gem_object.\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ if (meson_gem_obj->bscatter &&
+ !(meson_gem_obj->flags & MESON_USE_RENDER_VIP)) {
+ buffer = meson_gem_obj->handle->buffer;
+ dma_sync_sg_for_cpu(dev->dev, buffer->sg_table->sgl,
+ buffer->sg_table->nents, DMA_FROM_DEVICE);
+ }
+
+out:
+ drm_gem_object_unreference(obj);
+unlock:
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+}
+
+int am_meson_gem_cpu_prep_ioctl(
+ struct drm_device *dev,
+ void *data,
+ struct drm_file *file_priv)
+{
+ int err = 0;
+ struct drm_meson_gem_cpu_access *args = (struct drm_meson_gem_cpu_access *)data;
+ struct meson_drm *priv = dev->dev_private;
+ struct drm_gem_object *obj;
+ bool write = !!(args->flags & MESON_GEM_CPU_PREP_WRITE);
+ bool wait = !(args->flags & MESON_GEM_CPU_PREP_NOWAIT);
+ struct am_meson_gem_object *meson_gem_obj;
+
+ if (args->flags & ~(MESON_GEM_CPU_PREP_READ |
+ MESON_GEM_CPU_PREP_WRITE |
+ MESON_GEM_CPU_PREP_NOWAIT)) {
+ DRM_ERROR("invalid flags: %#08x\n", args->flags);
+ return -EINVAL;
+ }
+
+ mutex_lock(&dev->struct_mutex);
+ obj = drm_gem_object_lookup(file_priv, args->handle);
+ mutex_unlock(&dev->struct_mutex);
+ if (!obj) {
+ err = -ENOENT;
+ goto exit_unlock;
+ }
+ if (obj->import_attach) {
+ err = -EINVAL;
+ goto exit_unref;
+ }
+
+ meson_gem_obj = to_am_meson_gem_obj(obj);
+ if (meson_gem_obj->prep_data.cpu_prep) {
+ err = -EBUSY;
+ DRM_DEBUG("EBUSY cpu_prep not unlocked yet by caller\n");
+ goto exit_unref;
+ }
+
+ if (wait) {
+ long lerr;
+ lerr = reservation_object_wait_timeout_rcu(&meson_gem_obj->resv, write, true, 10 * HZ);
+ if (!lerr) {
+ err = -EBUSY;
+ goto exit_unref;
+ } else if (lerr < 0) {
+ err = lerr;
+ goto exit_unref;
+ }
+
+ meson_gem_obj->prep_data.fence = am_meson_fence_create(priv->dev_fctx);
+ if (!meson_gem_obj->prep_data.fence) {
+ err = -ENOMEM;
+ goto exit_unref;
+ }
+
+ if (write) {
+ ww_mutex_lock(&meson_gem_obj->resv.lock, NULL);
+ reservation_object_add_excl_fence(
+ &meson_gem_obj->resv, meson_gem_obj->prep_data.fence);
+ ww_mutex_unlock(&meson_gem_obj->resv.lock);
+ } else {
+ ww_mutex_lock(&meson_gem_obj->resv.lock, NULL);
+ err = reservation_object_reserve_shared(&meson_gem_obj->resv);
+ if (err) {
+ fence_put(meson_gem_obj->prep_data.fence);
+ } else {
+ reservation_object_add_shared_fence(
+ &meson_gem_obj->resv, meson_gem_obj->prep_data.fence);
+ }
+ ww_mutex_unlock(&meson_gem_obj->resv.lock);
+ }
+ } else {
+ if (!reservation_object_test_signaled_rcu(&meson_gem_obj->resv, write))
+ err = -EBUSY;
+ }
+
+ if (!err)
+ meson_gem_obj->prep_data.cpu_prep = true;
+
+exit_unref:
+ drm_gem_object_unreference_unlocked(obj);
+exit_unlock:
+ return err;
+}
+
+int am_meson_gem_cpu_fini_ioctl(
+ struct drm_device *dev,
+ void *data,
+ struct drm_file *file_priv)
+{
+ int err = 0;
+ struct drm_meson_gem_cpu_access *args = (struct drm_meson_gem_cpu_access *)data;
+ struct drm_gem_object *obj;
+ struct am_meson_gem_object *meson_gem_obj;
+
+ mutex_lock(&dev->struct_mutex);
+ obj = drm_gem_object_lookup(file_priv, args->handle);
+ if (!obj) {
+ err = -ENOENT;
+ goto exit_unlock;
+ }
+
+ meson_gem_obj = to_am_meson_gem_obj(obj);
+ if (!meson_gem_obj->prep_data.cpu_prep) {
+ err = -EINVAL;
+ goto exit_unref;
+ }
+
+ if (meson_gem_obj->prep_data.fence) {
+ WARN_ON(fence_signal(meson_gem_obj->prep_data.fence)); /* Signal the fence */
+ fence_put(meson_gem_obj->prep_data.fence);
+ meson_gem_obj->prep_data.fence = NULL;
+ }
+ meson_gem_obj->prep_data.cpu_prep = false;
+
+exit_unref:
+ drm_gem_object_unreference_unlocked(obj);
+exit_unlock:
+ mutex_unlock(&dev->struct_mutex);
+
+ return err;
+}
+
struct sg_table *am_meson_gem_prime_get_sg_table(
struct drm_gem_object *obj)
{
#include <drm/drm_gem.h>
#include <uapi/drm/meson_drm.h>
#include <ion/ion_priv.h>
+#include <linux/reservation.h>
#include "meson_drv.h"
+struct fence_prep_data {
+ int cpu_prep;
+ struct fence *fence;
+};
+
struct am_meson_gem_object {
struct drm_gem_object base;
unsigned int flags;
/* for buffer import form other driver */
phys_addr_t addr;
struct sg_table *sg;
+
+ struct reservation_object resv;
+ struct fence_prep_data prep_data;
+ unsigned int size;
};
/* GEM MANAGER CREATE*/
uint32_t handle,
uint64_t *offset);
+int am_meson_gem_get_ioctl(
+ struct drm_device *dev,
+ void *data,
+ struct drm_file *file_priv);
+
+int am_meson_gem_sync_ioctl(
+ struct drm_device *dev,
+ void *data,
+ struct drm_file *file_priv);
+
+int am_meson_gem_cpu_prep_ioctl(
+ struct drm_device *dev,
+ void *data,
+ struct drm_file *file_priv);
+
+int am_meson_gem_cpu_fini_ioctl(
+ struct drm_device *dev,
+ void *data,
+ struct drm_file *file_priv);
+
/* GEM OBJECT OPERATIONS */
struct am_meson_gem_object *am_meson_gem_object_create(
struct drm_device *dev, unsigned int flags,
struct am_meson_gem_object *obj,
struct vm_area_struct *vma);
+int am_meson_gem_open_object(
+ struct drm_gem_object *obj,
+ struct drm_file *file_priv);
+
extern phys_addr_t am_meson_gem_object_get_phyaddr(
struct meson_drm *drm,
struct am_meson_gem_object *meson_gem);
#include <linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h>
#include "meson_hdmi.h"
#include "meson_hdcp.h"
+#include "meson_vpu.h"
#define DEVICE_NAME "amhdmitx"
struct am_hdmi_tx am_hdmi_info;
-struct am_vout_mode {
- char name[DRM_DISPLAY_MODE_LEN];
- enum vmode_e mode;
- int width, height, vrefresh;
- unsigned int flags;
-};
-
static struct am_vout_mode am_vout_modes[] = {
{ "1080p60hz", VMODE_HDMI, 1920, 1080, 60, 0},
{ "1080p30hz", VMODE_HDMI, 1920, 1080, 30, 0},
vout_notifier_call_chain(VOUT_EVENT_MODE_CHANGE_PRE, &vmode);
set_vout_vmode(vmode);
vout_notifier_call_chain(VOUT_EVENT_MODE_CHANGE, &vmode);
- am_hdmi->hdcp_work = NULL;
mdelay(1000);
am_hdmi_hdcp_work_state_change(am_hdmi, 0);
}
MODULE_DEVICE_TABLE(of, am_meson_hdmi_dt_ids);
+struct drm_connector *am_meson_hdmi_connector(void)
+{
+ return &am_hdmi_info.connector;
+}
+
static int am_meson_hdmi_bind(struct device *dev,
struct device *master, void *data)
{
int ret;
int irq;
- am_hdmi = devm_kzalloc(priv->dev, sizeof(*am_hdmi),
- GFP_KERNEL);
- if (!am_hdmi)
- return -ENOMEM;
- memcpy(&am_hdmi_info, am_hdmi, sizeof(*am_hdmi));
+ DRM_INFO("[%s] in\n", __func__);
am_hdmi = &am_hdmi_info;
+ memset(am_hdmi, 0, sizeof(*am_hdmi));
DRM_INFO("drm hdmitx init and version:%s\n", DRM_HDMITX_VER);
am_hdmi->priv = priv;
DRM_DEBUG_KMS("HDCP init failed, skipping.\n");
}
}
+ DRM_INFO("[%s] out\n", __func__);
return 0;
}
static int am_meson_hdmi_probe(struct platform_device *pdev)
{
+ DRM_INFO("[%s] in\n", __func__);
return component_add(&pdev->dev, &am_meson_hdmi_ops);
}
__func__, lcd->lcd_drv->lcd_config->lcd_basic.h_active,
lcd->lcd_drv->lcd_config->lcd_basic.v_active);
+ connector->display_info.width_mm = mode->width_mm;
+ connector->display_info.height_mm = mode->height_mm;
+
drm_mode_probed_add(connector, mode);
count = 1;
pr_info("am_drm_lcd: %s %d\n", __func__, __LINE__);
return 0;
}
-static struct notifier_block am_drm_lcd_notifier_nb = {
- .notifier_call = am_drm_lcd_notify_callback,
-};
-
static const struct of_device_id am_meson_lcd_dt_ids[] = {
{ .compatible = "amlogic,drm-lcd", },
{},
pr_err("invalid lcd driver, exit\n");
return -ENODEV;
}
- /*
- * register vout client for timing init,
- * avoid init with null info when lcd probe with unifykey case.
- */
- vout_register_client(&am_drm_lcd_notifier_nb);
-
+ am_drm_lcd_display_mode_timing_init(am_drm_lcd);
drm_panel_init(&am_drm_lcd->panel);
am_drm_lcd->panel.dev = NULL;
am_drm_lcd->panel.funcs = &am_drm_lcd_funcs;
DRM_FORMAT_MOD_INVALID
};
-static void meson_plane_position_calc(
- struct meson_vpu_osd_layer_info *plane_info,
- struct drm_plane_state *state,
- struct drm_display_mode *mode)
+static void
+meson_plane_position_calc(struct meson_vpu_osd_layer_info *plane_info,
+ struct drm_plane_state *state,
+ struct drm_display_mode *disp_mode)
{
u32 dst_w, dst_h, src_w, src_h, scan_mode_out;
+ struct drm_display_mode *mode;
+
+ if (IS_ERR_OR_NULL(state->crtc))
+ mode = disp_mode;
+ else
+ mode = &state->crtc->mode;
scan_mode_out = mode->flags & DRM_MODE_FLAG_INTERLACE;
plane_info->src_x = state->src_x;
#else
struct drm_gem_cma_object *gem;
#endif
- dma_addr_t phyaddr;
+ phys_addr_t phyaddr;
#ifdef CONFIG_DRM_MESON_USE_ION
meson_fb = container_of(fb, struct am_meson_fb, base);
DRM_DEBUG("meson_fb is NULL!\n");
return -EINVAL;
}
- phyaddr = am_meson_gem_object_get_phyaddr(drv, meson_fb->bufp);
- if (meson_fb->bufp->bscatter)
- DRM_ERROR("am_meson_plane meet a scatter framebuffer.\n");
+ DRM_DEBUG("meson_fb[id:%d,ref:%d]=0x%p\n",
+ meson_fb->base.base.id,
+ atomic_read(&meson_fb->base.base.refcount.refcount),
+ meson_fb);
+ if (meson_fb->logo && meson_fb->logo->alloc_flag &&
+ meson_fb->logo->start) {
+ phyaddr = meson_fb->logo->start;
+ DRM_DEBUG("logo->phyaddr=0x%pa\n", &phyaddr);
+ } else if (meson_fb->bufp) {
+ phyaddr = am_meson_gem_object_get_phyaddr(drv, meson_fb->bufp);
+ } else {
+ phyaddr = 0;
+ DRM_INFO("don't find phyaddr!\n");
+ return -EINVAL;
+ }
#else
if (!fb) {
DRM_INFO("fb is NULL!\n");
struct am_osd_plane *osd_plane = to_am_osd_plane(plane);
struct drm_framebuffer *fb = new_state->fb;
struct meson_drm *drv = osd_plane->drv;
- #ifdef CONFIG_DRM_MESON_USE_ION
- struct am_meson_fb *meson_fb;
- #else
- struct drm_gem_cma_object *gem;
- #endif
- dma_addr_t phyaddr;
if (!drv) {
DRM_INFO("%s new_state/meson_drm is NULL!\n", __func__);
DRM_INFO("%s invalid plane_index!\n", __func__);
return -EINVAL;
}
-
- #ifdef CONFIG_DRM_MESON_USE_ION
- meson_fb = container_of(fb, struct am_meson_fb, base);
- if (!meson_fb) {
- DRM_INFO("meson_fb is NULL!\n");
- return 0;
- }
- phyaddr = am_meson_gem_object_get_phyaddr(drv, meson_fb->bufp);
- if (meson_fb->bufp->bscatter)
- DRM_ERROR("ERROR:am_meson_plane meet a scatter framebuffer.\n");
- plane_info->fb_size = meson_fb->bufp->base.size;
- #else
- if (!fb) {
- DRM_INFO("fb is NULL!\n");
- return -EINVAL;
- }
- /* Update Canvas with buffer address */
- gem = drm_fb_cma_get_gem_obj(fb, 0);
- phyaddr = gem->paddr;
- #endif
-
plane_info->pixel_format = fb->pixel_format;
- plane_info->phy_addr = phyaddr;
plane_info->byte_stride = fb->pitches[0];
/*setup afbc info*/
struct drm_property *property,
uint64_t *val)
{
+ struct am_osd_plane *osd_plane;
+ struct am_meson_plane_state *plane_state;
+
+ osd_plane = to_am_osd_plane(plane);
+ plane_state = to_am_meson_plane_state(state);
+ if (property == osd_plane->prop_premult_en)
+ *val = plane_state->premult_en;
return 0;
}
struct drm_property *property,
uint64_t val)
{
+ struct am_osd_plane *osd_plane;
+ struct am_meson_plane_state *plane_state;
+
+ osd_plane = to_am_osd_plane(plane);
+ plane_state = to_am_meson_plane_state(state);
+ if (property == osd_plane->prop_premult_en)
+ plane_state->premult_en = val;
+
return 0;
}
ret = true;
break;
case DRM_FORMAT_MOD_MESON_AFBC:
- if (osd_meson_dev.afbc_type == MESON_AFBC &&
- plane->type == DRM_PLANE_TYPE_PRIMARY)
+ if (plane->type == DRM_PLANE_TYPE_PRIMARY)
ret = true;
break;
case DRM_FORMAT_MOD_MESON_AFBC_WB:
- if (osd_meson_dev.afbc_type == MALI_AFBC &&
- plane->type == DRM_PLANE_TYPE_PRIMARY) {
+ if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
if (format == DRM_FORMAT_BGR565)
ret = false;
else
{
struct am_osd_plane *osd_plane = to_am_osd_plane(plane);
- DRM_DEBUG("%s osd %d.\n", __func__, osd_plane->plane_index);
+ DRM_DEBUG("osd %d.\n", osd_plane->plane_index);
}
static void meson_plane_atomic_update(struct drm_plane *plane,
struct meson_vpu_pipeline_state *mvps;
struct am_osd_plane *osd_plane = to_am_osd_plane(plane);
struct meson_drm *drv = osd_plane->drv;
+ struct am_meson_plane_state *plane_state;
int ret;
if (!state || !drv) {
return ret;
}
+ plane_state = to_am_meson_plane_state(state);
+ plane_info->premult_en = plane_state->premult_en;
plane_info->enable = 1;
DRM_DEBUG("index=%d, zorder=%d\n",
plane_info->plane_index, plane_info->zorder);
.atomic_disable = meson_plane_atomic_disable,
};
+int drm_plane_create_premult_en_property(struct drm_plane *plane)
+{
+ struct drm_device *dev = plane->dev;
+ struct drm_property *prop;
+ struct am_osd_plane *osd_plane;
+
+ osd_plane = to_am_osd_plane(plane);
+ prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC,
+ "PREMULT_EN");
+ if (!prop)
+ return -ENOMEM;
+
+ drm_object_attach_property(&plane->base, prop, 0);
+ osd_plane->prop_premult_en = prop;
+
+ return 0;
+}
+
static struct am_osd_plane *am_plane_create(struct meson_drm *priv, int i)
{
struct am_osd_plane *osd_plane;
if (!osd_plane)
return 0;
- if (i == 0)
+ if (i == OSD1)
+ type = DRM_PLANE_TYPE_OVERLAY;
+ else if (i == OSD2)
type = DRM_PLANE_TYPE_PRIMARY;
else
- type = DRM_PLANE_TYPE_OVERLAY;
+ type = DRM_PLANE_TYPE_CURSOR;
osd_plane->drv = priv;
osd_plane->plane_index = i;
format_modifiers,
type, plane_name);
+ drm_plane_create_premult_en_property(plane);
drm_plane_helper_add(plane, &am_osd_helper_funcs);
osd_drm_debugfs_add(&osd_plane->plane_debugfs_dir,
plane_name, osd_plane->plane_index);
if (!plane)
return -ENOMEM;
- if (i == 0)
+ if (i == OSD1)
+ priv->overlay_plane = &plane->base;
+ else if (i == OSD2)
priv->primary_plane = &plane->base;
-
priv->planes[priv->num_planes++] = plane;
}
return 0;
}
+EXPORT_SYMBOL(am_meson_plane_create);
struct am_meson_plane_state {
struct drm_plane_state base;
+ u32 premult_en;
};
struct am_osd_plane {
struct meson_drm *drv; //point to struct parent.
struct dentry *plane_debugfs_dir;
int plane_index;
+ struct drm_property *prop_premult_en;
};
#define to_am_osd_plane(x) container_of(x, \
.osd0_sc_independ = 1,
};
struct osd_device_data_s osd_meson_dev;
-static u32 logo_memsize;
-static struct page *logo_page;
-static struct delayed_work osd_dwork;
static struct platform_device *gp_dev;
static unsigned long gem_mem_start, gem_mem_size;
+struct am_meson_logo logo;
int am_meson_crtc_dts_info_set(const void *dt_match_data)
{
return NULL;
}
+bool am_meson_crtc_check_mode(struct drm_display_mode *mode, char *outputmode)
+{
+ int i;
+
+ if (!mode || !outputmode)
+ return false;
+ if (!strcmp(mode->name, "panel"))
+ return true;
+
+ for (i = 0; i < ARRAY_SIZE(am_vout_modes); i++) {
+ if (!strcmp(am_vout_modes[i].name, outputmode) &&
+ am_vout_modes[i].width == mode->hdisplay &&
+ am_vout_modes[i].height == mode->vdisplay &&
+ am_vout_modes[i].vrefresh == mode->vrefresh &&
+ am_vout_modes[i].flags ==
+ (mode->flags & DRM_MODE_FLAG_INTERLACE)) {
+ return true;
+ }
+ }
+ return false;
+}
+
void am_meson_crtc_handle_vsync(struct am_meson_crtc *amcrtc)
{
unsigned long flags;
return IRQ_HANDLED;
}
-static void mem_free_work(struct work_struct *work)
+static int am_meson_logo_info_update(struct meson_drm *priv)
{
- if (logo_memsize > 0) {
-#ifdef CONFIG_CMA
- pr_info("%s, free memory: addr:0x%x\n",
- __func__, logo_memsize);
-
- dma_release_from_contiguous(&gp_dev->dev,
- logo_page,
- logo_memsize >> PAGE_SHIFT);
-#endif
+ logo.start = page_to_phys(logo.logo_page);
+ logo.alloc_flag = 1;
+ /*config 1080p logo as default*/
+ if (!logo.width || !logo.height) {
+ logo.width = 1920;
+ logo.height = 1080;
+ }
+ if (!logo.bpp)
+ logo.bpp = 16;
+ if (!logo.outputmode_t) {
+ strcpy(logo.outputmode, "1080p60hz");
+ } else {
+ strncpy(logo.outputmode, logo.outputmode_t, VMODE_NAME_LEN_MAX);
+ logo.outputmode[VMODE_NAME_LEN_MAX - 1] = '\0';
}
+ priv->logo = &logo;
+
+ return 0;
}
static int am_meson_vpu_bind(struct device *dev,
int ret, irq;
/* Allocate crtc struct */
- pr_info("[%s] in\n", __func__);
+ DRM_INFO("[%s] in\n", __func__);
amcrtc = devm_kzalloc(dev, sizeof(*amcrtc),
GFP_KERNEL);
if (!amcrtc)
ret = of_reserved_mem_device_init(&pdev->dev);
if (ret != 0) {
dev_err(dev, "failed to init reserved memory\n");
+ } else {
#ifdef CONFIG_CMA
gp_dev = pdev;
cma = dev_get_cma_area(&pdev->dev);
if (cma) {
- logo_memsize = cma_get_size(cma);
- pr_info("reserved memory base:0x%x, size:0x%x\n",
- (u32)cma_get_base(cma), logo_memsize);
- if (logo_memsize > 0) {
- logo_page =
+ logo.size = cma_get_size(cma);
+ DRM_INFO("reserved memory base:0x%x, size:0x%x\n",
+ (u32)cma_get_base(cma), logo.size);
+ if (logo.size > 0) {
+ logo.logo_page =
dma_alloc_from_contiguous(&pdev->dev,
- logo_memsize >>
+ logo.size >>
PAGE_SHIFT,
0);
- if (!logo_page) {
- pr_err("allocate buffer failed:%d\n",
- logo_memsize);
- }
+ if (!logo.logo_page)
+ DRM_INFO("allocate buffer failed\n");
+ else
+ am_meson_logo_info_update(private);
}
} else {
- pr_info("------ NO CMA\n");
+ DRM_INFO("------ NO CMA\n");
}
#endif
- } else {
- dma_declare_coherent_memory(drm_dev->dev, gem_mem_start,
- gem_mem_start, gem_mem_size,
- DMA_MEMORY_EXCLUSIVE);
- pr_info("meson drm mem_start = 0x%x, size = 0x%x\n",
- (u32)gem_mem_start, (u32)gem_mem_size);
+ if (gem_mem_start) {
+ dma_declare_coherent_memory(drm_dev->dev,
+ gem_mem_start,
+ gem_mem_start,
+ gem_mem_size,
+ DMA_MEMORY_EXCLUSIVE);
+ pr_info("meson drm mem_start = 0x%x, size = 0x%x\n",
+ (u32)gem_mem_start, (u32)gem_mem_size);
+ } else {
+ DRM_INFO("------ NO reserved dma\n");
+ }
}
ret = am_meson_plane_create(private);
if (ret)
return ret;
-
- ret = am_meson_crtc_create(amcrtc);
+ ret = am_meson_crtc_create(amcrtc, &osd_meson_dev);
if (ret)
return ret;
/* IRQ is initially disabled; it gets enabled in crtc_enable */
disable_irq(amcrtc->irq);
- INIT_DELAYED_WORK(&osd_dwork, mem_free_work);
- schedule_delayed_work(&osd_dwork, msecs_to_jiffies(60 * 1000));
- pr_info("[%s] out\n", __func__);
+ DRM_INFO("[%s] out\n", __func__);
return 0;
}
unsigned int flags;
};
-extern struct osd_device_data_s osd_meson_dev;
char *am_meson_crtc_get_voutmode(struct drm_display_mode *mode);
+bool am_meson_crtc_check_mode(struct drm_display_mode *mode, char *outputmode);
#endif /* __AM_MESON_VPU_H */
VPU_PIPELINE_HW_INIT(&pipeline->postblend->base);
}
+EXPORT_SYMBOL(vpu_pipeline_init);
/* maybe use graph traverse is a good choice */
int vpu_pipeline_update(struct meson_vpu_pipeline *pipeline,
#define MESON_BLOCK_MAX_NAME_LEN 32
/*ratio base for scaler calc;maybe need bigger than 1000*/
#define RATIO_BASE 1000
-#define MESON_OSD_INPUT_W_LIMIT 1920
+#define MESON_OSD_INPUT_W_LIMIT 3840
#define MAX_DIN_NUM 4
#define MAX_DOUT_NUM 2
u32 afbc_inter_format;
u32 afbc_en;
u32 fb_size;
+ u32 premult_en;
};
struct meson_vpu_osd {
int r_mode;
u32 plane_index;
u32 fb_size;
+ u32 premult_en;
};
struct meson_vpu_afbc {
return 0;
}
#endif
-
-/** canvas config **/
-
-void meson_drm_canvas_config(u32 index, unsigned long addr, u32 width,
- u32 height, u32 wrap, u32 blkmode)
-{
- canvas_config(index, addr, width, height, wrap, blkmode);
-}
-
-int meson_drm_canvas_pool_alloc_table(const char *owner, u32 *table, int size,
- enum canvas_map_type_e type)
-{
- return canvas_pool_alloc_canvas_table(owner, table, size, type);
-}
-
0xf84d42f9, 0xf84a45f9, 0xf84848f8
};
+static unsigned int __osd_filter_coefs_2point_binilear[] = {
+ /* 2 point bilinear, bank_length == 2 coef2 */
+ 0x80000000, 0x7e020000, 0x7c040000, 0x7a060000, 0x78080000, 0x760a0000,
+ 0x740c0000, 0x720e0000, 0x70100000, 0x6e120000, 0x6c140000, 0x6a160000,
+ 0x68180000, 0x661a0000, 0x641c0000, 0x621e0000, 0x60200000, 0x5e220000,
+ 0x5c240000, 0x5a260000, 0x58280000, 0x562a0000, 0x542c0000, 0x522e0000,
+ 0x50300000, 0x4e320000, 0x4c340000, 0x4a360000, 0x48380000, 0x463a0000,
+ 0x443c0000, 0x423e0000, 0x40400000
+};
+
+static unsigned int __osd_filter_coefs_4point_triangle[] = {
+ 0x20402000, 0x20402000, 0x1f3f2101, 0x1f3f2101,
+ 0x1e3e2202, 0x1e3e2202, 0x1d3d2303, 0x1d3d2303,
+ 0x1c3c2404, 0x1c3c2404, 0x1b3b2505, 0x1b3b2505,
+ 0x1a3a2606, 0x1a3a2606, 0x19392707, 0x19392707,
+ 0x18382808, 0x18382808, 0x17372909, 0x17372909,
+ 0x16362a0a, 0x16362a0a, 0x15352b0b, 0x15352b0b,
+ 0x14342c0c, 0x14342c0c, 0x13332d0d, 0x13332d0d,
+ 0x12322e0e, 0x12322e0e, 0x11312f0f, 0x11312f0f,
+ 0x10303010
+};
+
+static unsigned int *osd_scaler_filter_table[] = {
+ __osd_filter_coefs_bicubic,
+ __osd_filter_coefs_2point_binilear,
+ __osd_filter_coefs_4point_triangle
+};
+
/*********vsc config begin**********/
/*vsc phase_step=(v_in << 20)/v_out */
void osd_vsc_phase_step_set(struct osd_scaler_reg_s *reg, u32 phase_step)
*1:config horizontal coef
*0:config vertical coef
*/
-void osd_sc_coef_set(struct osd_scaler_reg_s *reg, bool flag)
+void osd_sc_coef_set(struct osd_scaler_reg_s *reg, bool flag, u32 *coef)
{
u8 i;
(flag << 8) |
(0 << 0)/*coef index 7bits*/);
for (i = 0; i < 33; i++)
- VSYNCOSD_WR_MPEG_REG(reg->vpp_osd_scale_coef,
- __osd_filter_coefs_bicubic[i]);
+ VSYNCOSD_WR_MPEG_REG(reg->vpp_osd_scale_coef, coef[i]);
}
/*********sc top ctrl end************/
static void f2v_get_vertical_phase(
u32 width_out = scaler_state->output_width;
u32 height_out = scaler_state->output_height;
u32 scan_mode_out = scaler_state->scan_mode_out;
+ u32 vsc_double_line_mode;
+ u32 *coef_h, *coef_v;
bool scaler_enable;
if (width_in == width_out && height_in == height_out &&
else
scaler_enable = true;
- if (width_out > linebuffer)
+ if (width_in > linebuffer) {
vsc_bank_length = bank_length >> 1;
- else
+ vsc_double_line_mode = 1;
+ } else {
vsc_bank_length = bank_length;
+ vsc_double_line_mode = 0;
+ }
hsc_init_rec_num = bank_length;
hsc_bank_length = bank_length;
hsc_init_rpt_p0_num = bank_length / 2 - 1;
phase_step_v <<= (OSD_ZOOM_TOTAL_BITS - OSD_ZOOM_HEIGHT_BITS);
phase_step_h = (width_in << OSD_ZOOM_WIDTH_BITS) / width_out;
phase_step_h <<= (OSD_ZOOM_TOTAL_BITS - OSD_ZOOM_WIDTH_BITS);
+ /*check coef*/
+ if (scan_mode_out && width_out <= 720) {
+ coef_h = osd_scaler_filter_table[COEFS_4POINT_TRIANGLE];
+ coef_v = osd_scaler_filter_table[COEFS_4POINT_TRIANGLE];
+ } else if (vsc_double_line_mode == 1) {
+ coef_h = osd_scaler_filter_table[COEFS_BICUBIC];
+ coef_v = osd_scaler_filter_table[COEFS_2POINT_BINILEAR];
+ } else {
+ coef_h = osd_scaler_filter_table[COEFS_BICUBIC];
+ coef_v = osd_scaler_filter_table[COEFS_BICUBIC];
+ }
/*input size config*/
osd_sc_in_h_set(reg, height_in);
osd_sc_dummy_data_set(reg, 0x80808080);
/*h/v coef config*/
- osd_sc_coef_set(reg, 1);
- osd_sc_coef_set(reg, 0);
+ osd_sc_coef_set(reg, OSD_SCALER_COEFF_H, coef_h);
+ osd_sc_coef_set(reg, OSD_SCALER_COEFF_V, coef_v);
/*init recv line num*/
osd_vsc_top_ini_rcv_num_set(reg, vsc_top_init_rec_num);
osd_vsc_bot_ini_rcv_num_set(reg, vsc_bot_init_rec_num);
osd_hsc_ini_rcv_num0_set(reg, hsc_init_rec_num);
+ osd_vsc_double_line_mode_set(reg, vsc_double_line_mode);
/*repeate line0 num*/
osd_vsc_top_rpt_l0_num_set(reg, vsc_top_rpt_l0_num);
scaler->reg = &osd_scaler_reg[vblk->index];
scaler->linebuffer = OSD_SCALE_LINEBUFFER;
scaler->bank_length = OSD_SCALE_BANK_LENGTH;
- /*disable sc*/
- osd_sc_en_set(scaler->reg, 0);
- osd_sc_path_en_set(scaler->reg, 0);
DRM_DEBUG("%s hw_init called.\n", scaler->base.name);
}
#define OSD_ZOOM_TOTAL_BITS 24
#define OSD_PHASE_BITS 16
+#define OSD_SCALER_COEFF_H 1
+#define OSD_SCALER_COEFF_V 0
+
+enum scaler_coef_e {
+ COEFS_BICUBIC = 0,
+ COEFS_2POINT_BINILEAR,
+ COEFS_4POINT_TRIANGLE
+};
+
enum f2v_vphase_type_e {
F2V_IT2IT = 0,
F2V_IB2IB,
VSYNCOSD_WR_MPEG_REG_BITS(reg->viu_osd_ctrl_stat, flag, 0, 1);
}
+/*osd alpha_div en
+ *if input is premult,alpha_div=1,else alpha_div=0
+ */
+void osd_alpha_div_enable(struct osd_mif_reg_s *reg, bool flag)
+{
+ VSYNCOSD_WR_MPEG_REG_BITS(reg->viu_osd_mali_unpack_ctrl, flag, 28, 1);
+}
+
/*osd ctrl config*/
-void osd_ctrl_set(struct osd_mif_reg_s *reg)
+void osd_ctrl_set(struct osd_mif_reg_s *reg, u32 osd_idx, u32 canvas_index)
{
+ u32 enable = 1;
+
+ if (osd_idx > OSD2)
+ enable = 0;
+
VSYNCOSD_WR_MPEG_REG(reg->viu_osd_ctrl_stat,
(0 << 31) |/*osd_cfg_sync_en*/
(0 << 30) |/*Enable free_clk*/
(0 << 11) |/*TEST_RD_EN*/
(0 << 2) |/*osd_mem_mode 0:canvas_addr*/
(0 << 1) |/*premult_en*/
- (0 << 0)/*OSD_BLK_ENABLE*/);
+ (enable << 0)/*OSD_BLK_ENABLE*/
+ );
VSYNCOSD_WR_MPEG_REG(reg->viu_osd_ctrl_stat2,
(1 << 14) |/*replaced_alpha_en*/
(0xff << 6) |/*replaced_alpha*/
(0 << 30) |/*read from ddr[0]/afbc[1]*/
(0 << 29) |/*y reverse disable*/
(0 << 28) |/*x reverse disable*/
- (osd_canvas[0][0] << 16) |/*canvas index*/
+ (canvas_index << 16) |
(1 << 15) |/*little endian in ddr*/
(0 << 14) |/*no repeat display y pre line*/
(0 << 12) |/*no interpolation per pixel*/
(1 << 2) |/*ARGB format for 32bit mode*/
(0 << 1) |/*interlace en*/
(0 << 0)/*output odd/even lines sel*/);
- VSYNCOSD_WR_MPEG_REG(reg->viu_osd_blk0_cfg_w1,
- (1919 << 16) |/*x_end pixels[13bits]*/
- (0 << 0)/*x_start pixels[13bits]*/);
- VSYNCOSD_WR_MPEG_REG(reg->viu_osd_blk0_cfg_w2,
- (1079 << 16) |/*y_end pixels[13bits]*/
- (0 << 0)/*y_start pixels[13bits]*/);
/*frame addr in linear addr*/
VSYNCOSD_WR_MPEG_REG(reg->viu_osd_blk1_cfg_w4, 0);
/*line_stride in linear addr*/
mvos->phy_addr = plane_info->phy_addr;
mvos->pixel_format = plane_info->pixel_format;
mvos->fb_size = plane_info->fb_size;
+ mvos->premult_en = plane_info->premult_en;
return 0;
}
u32 pixel_format, canvas_index, src_h, byte_stride, phy_addr;
struct osd_scope_s scope_src = {0, 1919, 0, 1079};
struct osd_mif_reg_s *reg = osd->reg;
+ bool alpha_div_en;
crtc = vblk->pipeline->crtc;
amc = to_am_meson_crtc(crtc);
DRM_DEBUG("set_state break for NULL.\n");
return;
}
+ alpha_div_en = mvos->premult_en ? 1 : 0;
src_h = mvos->src_h;
byte_stride = mvos->byte_stride;
phy_addr = mvos->phy_addr;
scope_src.v_end = mvos->src_y + mvos->src_h - 1;
pixel_format = mvos->pixel_format;
canvas_index = osd_canvas[vblk->index][osd_canvas_index[vblk->index]];
+ /*Toto: need to separate*/
+ osd_ctrl_set(osd->reg, vblk->index, canvas_index);
canvas_config(canvas_index, phy_addr, byte_stride, src_h,
CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
osd_canvas_index[vblk->index] ^= 1;
- osd_canvas_config(reg, canvas_index);
osd_input_size_config(reg, scope_src);
osd_color_config(reg, pixel_format);
+ osd_alpha_div_enable(reg, alpha_div_en);
DRM_DEBUG("plane_index=%d,HW-OSD=%d\n",
mvos->plane_index, vblk->index);
DRM_DEBUG("canvas_index[%d]=0x%x,phy_addr=0x%x\n",
return;
}
osd->reg = &osd_mif_reg[vblk->index];
- osd_ctrl_set(osd->reg);
DRM_DEBUG("%s hw_init done.\n", osd->base.name);
}
/* for compatibility root is always authenticated */
priv->authenticated = capable(CAP_SYS_ADMIN);
priv->lock_count = 0;
+ priv->drm_pid = task_tgid_nr(current);
INIT_LIST_HEAD(&priv->lhead);
INIT_LIST_HEAD(&priv->fbs);
struct mutex event_read_lock;
+ pid_t drm_pid;
struct drm_prime_file_private prime;
};
#ifndef _MESON_DRM_H
#define _MESON_DRM_H
-#include <drm/drm.h>
+#include "drm.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
/* Use flags */
#define MESON_USE_NONE 0
#define MESON_USE_CAMERA_WRITE (1ull << 13)
#define MESON_USE_CAMERA_READ (1ull << 14)
#define MESON_USE_TEXTURE (1ull << 17)
+#define MESON_USE_RENDER_VIP (1ull << 18)
+#define MESON_USE_OVERLAY (1ull << 19)
+/* For Buffer synchronization using dma-buf fence */
+#define MESON_GEM_CPU_PREP_READ (1 << 0)
+#define MESON_GEM_CPU_PREP_WRITE (1 << 1)
+#define MESON_GEM_CPU_PREP_NOWAIT (1 << 2)
/**
* User-desired buffer creation information structure.
__u32 handle;
};
+/**
+ * A structure to gem information.
+ *
+ * @handle: a handle to gem object created.
+ * @flags: flag value including memory type and cache attribute and
+ * this value would be set by driver.
+ * @size: size to memory region allocated by gem and this size would
+ * be set by driver.
+ */
+struct drm_meson_gem_info {
+ uint32_t handle;
+ uint32_t flags;
+ uint64_t size;
+};
+
+struct drm_meson_plane_blank {
+ uint32_t plane_type;
+ uint32_t onoff;
+};
+
+struct drm_meson_gem_sync {
+ uint32_t handle;
+};
+
+struct drm_meson_gem_cpu_access {
+ uint32_t handle;
+ uint32_t flags;
+};
+
#define DRM_MESON_GEM_CREATE 0x00
+#define DRM_MESON_GEM_GET 0x01
+#define DRM_MESON_SET_BLANK 0x02
+#define DRM_MESON_GEM_SYNC 0x03
+#define DRM_MESON_GEM_CPU_PREP 0x04
+#define DRM_MESON_GEM_CPU_FINI 0x05
#define DRM_IOCTL_MESON_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \
DRM_MESON_GEM_CREATE, struct drm_meson_gem_create)
+#define DRM_IOCTL_MESON_GEM_GET DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_MESON_GEM_GET, struct drm_meson_gem_info)
+#define DRM_IOCTL_MESON_SET_BLANK DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_MESON_SET_BLANK, struct drm_meson_plane_blank)
+#define DRM_IOCTL_MESON_GEM_SYNC DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_MESON_GEM_SYNC, struct drm_meson_gem_sync)
+#define DRM_IOCTL_MESON_GEM_CPU_PREP DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_MESON_GEM_CPU_PREP, struct drm_meson_gem_cpu_access)
+#define DRM_IOCTL_MESON_GEM_CPU_FINI DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_MESON_GEM_CPU_FINI, struct drm_meson_gem_cpu_access)
+
+#if defined(__cplusplus)
+}
+#endif
#endif /* _MESON_DRM_H */