3468 lines
103 KiB
C
3468 lines
103 KiB
C
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/sync_file.h>
|
|
#include <linux/dma-fence.h>
|
|
#include <linux/dma-buf.h>
|
|
#include <uapi/linux/dma-buf.h>
|
|
#include <uapi/linux/magic.h>
|
|
#include <drm/drm_atomic_uapi.h>
|
|
#include <drm/drm_blend.h>
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_FB
|
|
#include <linux/amlogic/media/osd/osd_logo.h>
|
|
#endif
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_VECM
|
|
#include <linux/amlogic/media/amvecm/amvecm.h>
|
|
#endif
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
|
|
#include <linux/amlogic/media/amdolbyvision/dolby_vision.h>
|
|
#else
|
|
#include <linux/amlogic/media/amdolbyvision/dolby_vision_ext.h>
|
|
#endif
|
|
#include <linux/amlogic/media/video_sink/video.h>
|
|
#include <linux/amlogic/media/video_sink/v4lvideo_ext.h>
|
|
#include "meson_plane.h"
|
|
#include "meson_crtc.h"
|
|
#include "meson_vpu.h"
|
|
#include "meson_drv.h"
|
|
#include "meson_vpu_pipeline.h"
|
|
#include "vpu-hw/meson_osd_afbc.h"
|
|
#include "meson_gem.h"
|
|
#include "meson_logo.h"
|
|
|
|
static const struct drm_plane_funcs am_video_plane_funs;
|
|
|
|
static int video_axis_zoom = -1;
|
|
module_param(video_axis_zoom, int, 0664);
|
|
MODULE_PARM_DESC(video_axis_zoom, "video_axis_zoom");
|
|
|
|
static int bypass_video_crop;
|
|
module_param(bypass_video_crop, int, 0664);
|
|
MODULE_PARM_DESC(bypass_video_crop, "bypass_video_crop");
|
|
|
|
static int osd_enable[MESON_MAX_OSDS];
|
|
|
|
static u64 afbc_modifier[] = {
|
|
/*
|
|
* - TOFIX Support AFBC modifiers for YUV formats (16x16 + TILED)
|
|
* - SPLIT is mandatory for performances reasons when in 16x16
|
|
* block size
|
|
* - 32x8 block size + SPLIT is mandatory with 4K frame size
|
|
* for performances reasons
|
|
*/
|
|
DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
|
|
AFBC_FORMAT_MOD_SPARSE |
|
|
AFBC_FORMAT_MOD_SPLIT),
|
|
DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
|
|
AFBC_FORMAT_MOD_YTR |
|
|
AFBC_FORMAT_MOD_SPARSE |
|
|
AFBC_FORMAT_MOD_SPLIT),
|
|
DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
|
|
AFBC_FORMAT_MOD_TILED |
|
|
AFBC_FORMAT_MOD_SC |
|
|
AFBC_FORMAT_MOD_YTR |
|
|
AFBC_FORMAT_MOD_SPARSE |
|
|
AFBC_FORMAT_MOD_SPLIT),
|
|
DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
|
|
AFBC_FORMAT_MOD_SPARSE |
|
|
AFBC_FORMAT_MOD_SPLIT),
|
|
DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
|
|
AFBC_FORMAT_MOD_YTR |
|
|
AFBC_FORMAT_MOD_SPARSE |
|
|
AFBC_FORMAT_MOD_SPLIT),
|
|
DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 |
|
|
AFBC_FORMAT_MOD_TILED |
|
|
AFBC_FORMAT_MOD_SC |
|
|
AFBC_FORMAT_MOD_YTR |
|
|
AFBC_FORMAT_MOD_SPARSE |
|
|
AFBC_FORMAT_MOD_SPLIT),
|
|
/* - AFRC
|
|
* - now just support scanline layout, we need notify encoder this flag
|
|
* - by add AFRC_FORMAT_MOD_LAYOUT_SCAN explicitly.
|
|
*/
|
|
DRM_FORMAT_MOD_ARM_AFRC(AFRC_FORMAT_MOD_CU_SIZE_16 |
|
|
AFRC_FORMAT_MOD_LAYOUT_SCAN),
|
|
DRM_FORMAT_MOD_ARM_AFRC(AFRC_FORMAT_MOD_CU_SIZE_24 |
|
|
AFRC_FORMAT_MOD_LAYOUT_SCAN),
|
|
DRM_FORMAT_MOD_ARM_AFRC(AFRC_FORMAT_MOD_CU_SIZE_32 |
|
|
AFRC_FORMAT_MOD_LAYOUT_SCAN),
|
|
DRM_FORMAT_MOD_LINEAR,
|
|
DRM_FORMAT_MOD_INVALID
|
|
};
|
|
|
|
/* default groups */
|
|
u32 supported_drm_formats[] = {
|
|
DRM_FORMAT_ABGR2101010,
|
|
DRM_FORMAT_XRGB8888,
|
|
DRM_FORMAT_XBGR8888,
|
|
DRM_FORMAT_RGBX8888,
|
|
DRM_FORMAT_BGRX8888,
|
|
DRM_FORMAT_ARGB8888,
|
|
DRM_FORMAT_ABGR8888,
|
|
DRM_FORMAT_RGBA8888,
|
|
DRM_FORMAT_BGRA8888,
|
|
DRM_FORMAT_RGB888,
|
|
DRM_FORMAT_BGR888,
|
|
DRM_FORMAT_RGB565,
|
|
};
|
|
|
|
/* default groups + 1010102 formats */
|
|
u32 supported_drm_formats_v2[] = {
|
|
DRM_FORMAT_RGBA1010102,
|
|
DRM_FORMAT_ARGB2101010,
|
|
DRM_FORMAT_ABGR2101010,
|
|
DRM_FORMAT_BGRA1010102,
|
|
DRM_FORMAT_XRGB8888,
|
|
DRM_FORMAT_XBGR8888,
|
|
DRM_FORMAT_RGBX8888,
|
|
DRM_FORMAT_BGRX8888,
|
|
DRM_FORMAT_ARGB8888,
|
|
DRM_FORMAT_ABGR8888,
|
|
DRM_FORMAT_RGBA8888,
|
|
DRM_FORMAT_BGRA8888,
|
|
DRM_FORMAT_RGB888,
|
|
DRM_FORMAT_BGR888,
|
|
DRM_FORMAT_RGB565,
|
|
};
|
|
|
|
u32 supported_drm_formats_v6[] = {
|
|
DRM_FORMAT_RGBA1010102,
|
|
DRM_FORMAT_RGBX1010102,
|
|
DRM_FORMAT_ABGR2101010,
|
|
DRM_FORMAT_XBGR2101010,
|
|
DRM_FORMAT_ARGB2101010,
|
|
DRM_FORMAT_BGRA1010102,
|
|
DRM_FORMAT_XRGB8888,
|
|
DRM_FORMAT_XBGR8888,
|
|
DRM_FORMAT_RGBX8888,
|
|
DRM_FORMAT_BGRX8888,
|
|
DRM_FORMAT_ARGB8888,
|
|
DRM_FORMAT_ABGR8888,
|
|
DRM_FORMAT_RGBA8888,
|
|
DRM_FORMAT_BGRA8888,
|
|
DRM_FORMAT_RGB888,
|
|
DRM_FORMAT_BGR888,
|
|
DRM_FORMAT_RGB565,
|
|
DRM_FORMAT_ARGB4444,
|
|
DRM_FORMAT_RGBA4444,
|
|
DRM_FORMAT_RGBX4444,
|
|
DRM_FORMAT_XRGB4444,
|
|
DRM_FORMAT_RGBA5551,
|
|
DRM_FORMAT_ARGB1555,
|
|
DRM_FORMAT_RGBX5551,
|
|
DRM_FORMAT_XRGB1555,
|
|
DRM_FORMAT_C8,
|
|
};
|
|
|
|
/* v2 groups + 4444 formats */
|
|
u32 supported_drm_formats_v3[] = {
|
|
DRM_FORMAT_RGBA1010102,
|
|
DRM_FORMAT_ARGB2101010,
|
|
DRM_FORMAT_ABGR2101010,
|
|
DRM_FORMAT_BGRA1010102,
|
|
DRM_FORMAT_XRGB8888,
|
|
DRM_FORMAT_XBGR8888,
|
|
DRM_FORMAT_RGBX8888,
|
|
DRM_FORMAT_BGRX8888,
|
|
DRM_FORMAT_ARGB8888,
|
|
DRM_FORMAT_ABGR8888,
|
|
DRM_FORMAT_RGBA8888,
|
|
DRM_FORMAT_BGRA8888,
|
|
DRM_FORMAT_RGB888,
|
|
DRM_FORMAT_BGR888,
|
|
DRM_FORMAT_ABGR4444,
|
|
DRM_FORMAT_ARGB4444,
|
|
DRM_FORMAT_BGRA4444,
|
|
DRM_FORMAT_RGBA4444,
|
|
DRM_FORMAT_RGB565,
|
|
};
|
|
|
|
/* formats supported by s1a */
|
|
u32 supported_drm_formats_v4[] = {
|
|
DRM_FORMAT_XRGB8888,
|
|
DRM_FORMAT_XBGR8888,
|
|
DRM_FORMAT_RGBX8888,
|
|
DRM_FORMAT_BGRX8888,
|
|
DRM_FORMAT_RGB565,
|
|
DRM_FORMAT_RGBA4444,
|
|
DRM_FORMAT_ARGB4444,
|
|
DRM_FORMAT_RGBA5551,
|
|
DRM_FORMAT_ARGB1555,
|
|
DRM_FORMAT_RGB888,
|
|
DRM_FORMAT_BGR888,
|
|
DRM_FORMAT_RGBA8888,
|
|
DRM_FORMAT_ABGR8888,
|
|
DRM_FORMAT_ARGB8888,
|
|
DRM_FORMAT_BGRA8888,
|
|
DRM_FORMAT_RGBA1010102,
|
|
DRM_FORMAT_ABGR2101010,
|
|
DRM_FORMAT_C8,
|
|
};
|
|
|
|
/* default groups + 10101010 format for s7d*/
|
|
u32 supported_drm_formats_v5[] = {
|
|
DRM_FORMAT_ABGR10101010,
|
|
DRM_FORMAT_ABGR2101010,
|
|
DRM_FORMAT_XRGB8888,
|
|
DRM_FORMAT_XBGR8888,
|
|
DRM_FORMAT_RGBX8888,
|
|
DRM_FORMAT_BGRX8888,
|
|
DRM_FORMAT_ARGB8888,
|
|
DRM_FORMAT_ABGR8888,
|
|
DRM_FORMAT_RGBA8888,
|
|
DRM_FORMAT_BGRA8888,
|
|
DRM_FORMAT_RGB888,
|
|
DRM_FORMAT_BGR888,
|
|
DRM_FORMAT_RGB565,
|
|
};
|
|
|
|
static u64 video_fbc_modifier[] = {
|
|
DRM_FORMAT_MOD_AMLOGIC_FBC(AMLOGIC_FBC_LAYOUT_BASIC, 0),
|
|
DRM_FORMAT_MOD_AMLOGIC_FBC(AMLOGIC_FBC_LAYOUT_BASIC,
|
|
AMLOGIC_FBC_OPTION_MEM_SAVING),
|
|
DRM_FORMAT_MOD_AMLOGIC_FBC(AMLOGIC_FBC_LAYOUT_SCATTER, 0),
|
|
DRM_FORMAT_MOD_AMLOGIC_FBC(AMLOGIC_FBC_LAYOUT_SCATTER,
|
|
AMLOGIC_FBC_OPTION_MEM_SAVING),
|
|
DRM_FORMAT_MOD_LINEAR,
|
|
DRM_FORMAT_MOD_INVALID
|
|
};
|
|
|
|
u32 video_supported_drm_formats[] = {
|
|
DRM_FORMAT_NV12,
|
|
DRM_FORMAT_NV21,
|
|
DRM_FORMAT_UYVY,
|
|
DRM_FORMAT_VUY888,
|
|
DRM_FORMAT_YUVX1010102,
|
|
};
|
|
|
|
static void osd_plane_mute(bool mute)
|
|
{
|
|
/* to do */
|
|
DRM_DEBUG_DRIVER("mute osd plane.\n");
|
|
}
|
|
|
|
static void video_plane_mute(bool mute)
|
|
{
|
|
DRM_DEBUG_DRIVER("mute video plane.\n");
|
|
set_video_mute(DRM_MUTE_SET, mute);
|
|
}
|
|
|
|
int meson_plane_mute_ioctl(struct drm_device *dev,
|
|
void *data, struct drm_file *file_priv)
|
|
{
|
|
struct drm_meson_plane_mute *arg = data;
|
|
|
|
if (!arg) {
|
|
DRM_ERROR("para is NULL!\n");
|
|
return -EINVAL;
|
|
}
|
|
if (arg->plane_type == OSD_PLANE) {
|
|
if (arg->plane_mute) {
|
|
DRM_DEBUG_DRIVER("mute osd plane!\n");
|
|
osd_plane_mute(true);
|
|
} else {
|
|
DRM_DEBUG_DRIVER("unmute osd plane!\n");
|
|
osd_plane_mute(false);
|
|
}
|
|
return 0;
|
|
}
|
|
if (arg->plane_type == VIDEO_PLANE) {
|
|
if (arg->plane_mute) {
|
|
DRM_DEBUG_DRIVER("mute video plane!\n");
|
|
video_plane_mute(true);
|
|
} else {
|
|
DRM_DEBUG_DRIVER("unmute video plane!\n");
|
|
video_plane_mute(false);
|
|
}
|
|
return 0;
|
|
}
|
|
return -EINVAL;
|
|
}
|
|
|
|
#if IS_ENABLED(CONFIG_SYNC_FILE)
|
|
int am_meson_dmabuf_export_sync_file_ioctl(struct drm_device *dev,
|
|
void *data, struct drm_file *file_priv)
|
|
{
|
|
struct drm_meson_dma_buf_export_sync_file *arg = data;
|
|
struct dma_fence *fence = NULL;
|
|
struct dma_buf *dmabuf = NULL;
|
|
struct sync_file *sync_file;
|
|
enum dma_resv_usage usage;
|
|
int fd, ret = -1;
|
|
|
|
MESON_DRM_FENCE("dmabuf-%px fence-%px", dmabuf, fence);
|
|
if (arg->flags & ~DMA_BUF_SYNC_RW)
|
|
return -EINVAL;
|
|
|
|
if ((arg->flags & DMA_BUF_SYNC_RW) == 0)
|
|
return -EINVAL;
|
|
|
|
fd = get_unused_fd_flags(O_CLOEXEC);
|
|
if (fd < 0)
|
|
return fd;
|
|
|
|
dmabuf = dma_buf_get(arg->dmabuf_fd);
|
|
if (IS_ERR_OR_NULL(dmabuf))
|
|
goto err_put_fd;
|
|
|
|
if (arg->flags & DMA_BUF_SYNC_WRITE) {
|
|
//fence = dma_resv_get_singleton_unlocked(dmabuf->resv);
|
|
//if (IS_ERR(fence)) {
|
|
// ret = PTR_ERR(fence);
|
|
// goto err_put_fd;
|
|
//}
|
|
} else if (arg->flags & DMA_BUF_SYNC_READ) {
|
|
usage = dma_resv_usage_rw(arg->flags & DMA_BUF_SYNC_WRITE);
|
|
ret = dma_resv_get_singleton(dmabuf->resv, usage, &fence);
|
|
if (ret)
|
|
goto err_put_fd;
|
|
}
|
|
|
|
if (!fence)
|
|
fence = dma_fence_get_stub();
|
|
|
|
sync_file = sync_file_create(fence);
|
|
|
|
dma_fence_put(fence);
|
|
dma_buf_put(dmabuf);
|
|
|
|
if (!sync_file) {
|
|
ret = -ENOMEM;
|
|
goto err_put_fd;
|
|
}
|
|
|
|
fd_install(fd, sync_file->file);
|
|
|
|
arg->fd = fd;
|
|
MESON_DRM_FENCE("dmabuf-%px fence-%px fd-%d", dmabuf, fence, fd);
|
|
return 0;
|
|
|
|
err_put_fd:
|
|
put_unused_fd(fd);
|
|
MESON_DRM_FENCE("get fence fd failed! ret=%d\n", ret);
|
|
return ret;
|
|
}
|
|
#endif
|
|
struct meson_plane_supported_formats osd_formats = {
|
|
.formats = supported_drm_formats,
|
|
.format_num = ARRAY_SIZE(supported_drm_formats),
|
|
};
|
|
|
|
struct meson_plane_supported_formats osd_formats_t5m = {
|
|
.formats = supported_drm_formats_v2,
|
|
.format_num = ARRAY_SIZE(supported_drm_formats_v2),
|
|
};
|
|
|
|
struct meson_plane_supported_formats osd_formats_t6d = {
|
|
.formats = supported_drm_formats_v6,
|
|
.format_num = ARRAY_SIZE(supported_drm_formats_v6),
|
|
};
|
|
|
|
struct meson_plane_supported_formats osd_formats_t3x = {
|
|
.formats = supported_drm_formats_v3,
|
|
.format_num = ARRAY_SIZE(supported_drm_formats_v3),
|
|
};
|
|
|
|
struct meson_plane_supported_formats osd_formats_s1a = {
|
|
.formats = supported_drm_formats_v4,
|
|
.format_num = ARRAY_SIZE(supported_drm_formats_v4),
|
|
};
|
|
|
|
struct meson_plane_supported_formats osd_formats_s7d = {
|
|
.formats = supported_drm_formats_v5,
|
|
.format_num = ARRAY_SIZE(supported_drm_formats_v5),
|
|
};
|
|
|
|
struct meson_plane_supported_formats video_formats = {
|
|
.formats = video_supported_drm_formats,
|
|
.format_num = ARRAY_SIZE(video_supported_drm_formats),
|
|
};
|
|
|
|
static void
|
|
meson_plane_position_calc(struct meson_vpu_osd_layer_info *plane_info,
|
|
struct drm_plane_state *state,
|
|
struct meson_vpu_pipeline *pipeline)
|
|
{
|
|
u32 dst_w, dst_h, src_w, src_h, scan_mode_out;
|
|
struct am_osd_plane *amp;
|
|
struct drm_atomic_state *atomic_state = state->state;
|
|
struct drm_crtc *crtc = state->crtc;
|
|
struct drm_crtc_state *crtc_state;
|
|
struct drm_display_mode *mode = NULL;
|
|
|
|
if (crtc) {
|
|
crtc_state = drm_atomic_get_crtc_state(atomic_state, crtc);
|
|
if (crtc_state)
|
|
mode = &crtc_state->mode;
|
|
} else {
|
|
DRM_DEBUG_DRIVER("Disabling plane %d, so skip position calc",
|
|
plane_info->plane_index);
|
|
return;
|
|
}
|
|
|
|
if (!crtc_state || !mode)
|
|
mode = &pipeline->subs[crtc->index]->mode;
|
|
scan_mode_out = mode->flags & DRM_MODE_FLAG_INTERLACE;
|
|
plane_info->src_x = state->src_x >> 16;
|
|
plane_info->src_y = state->src_y >> 16;
|
|
plane_info->src_w = (state->src_w >> 16) & 0xffff;
|
|
plane_info->src_h = (state->src_h >> 16) & 0xffff;
|
|
plane_info->ori_src_x = plane_info->src_x;
|
|
plane_info->ori_src_y = plane_info->src_y;
|
|
plane_info->ori_src_w = plane_info->src_w;
|
|
plane_info->ori_src_h = plane_info->src_h;
|
|
|
|
plane_info->dst_x = state->crtc_x;
|
|
plane_info->dst_y = state->crtc_y;
|
|
plane_info->dst_w = state->crtc_w;
|
|
plane_info->dst_h = state->crtc_h;
|
|
plane_info->ori_dst_x = plane_info->dst_x;
|
|
plane_info->ori_dst_y = plane_info->dst_y;
|
|
plane_info->ori_dst_w = plane_info->dst_w;
|
|
plane_info->ori_dst_h = plane_info->dst_h;
|
|
plane_info->rotation = state->rotation;
|
|
DRM_DEBUG_DRIVER("original:src[(%d %d),%dx%d]dst[(%d %d),%dx%d]mode[%dx%d]\n",
|
|
plane_info->ori_src_x, plane_info->ori_src_y,
|
|
plane_info->ori_src_w, plane_info->ori_src_h,
|
|
plane_info->ori_dst_x, plane_info->ori_dst_y,
|
|
plane_info->ori_dst_w, plane_info->ori_dst_h,
|
|
mode->hdisplay, mode->vdisplay);
|
|
|
|
if (state->plane) {
|
|
amp = to_am_osd_plane(state->plane);
|
|
|
|
if (amp->adjust_src.x1 > -1 && amp->adjust_src.y1 > -1 &&
|
|
amp->adjust_src.x2 > -1 && amp->adjust_src.y2 > -1) {
|
|
plane_info->src_x = amp->adjust_src.x1;
|
|
plane_info->src_y = amp->adjust_src.y1;
|
|
plane_info->src_w = amp->adjust_src.x2;
|
|
plane_info->src_h = amp->adjust_src.y2;
|
|
DRM_DEBUG_DRIVER("resize original src [(%d %d), %dx%d]\n",
|
|
amp->adjust_src.x1, amp->adjust_src.y1, amp->adjust_src.x2,
|
|
amp->adjust_src.y2);
|
|
}
|
|
|
|
if (amp->adjust_dst.x1 > -1 && amp->adjust_dst.y1 > -1 &&
|
|
amp->adjust_dst.x2 > -1 && amp->adjust_dst.y2 > -1) {
|
|
plane_info->dst_x = amp->adjust_dst.x1;
|
|
plane_info->dst_y = amp->adjust_dst.y1;
|
|
plane_info->dst_w = amp->adjust_dst.x2;
|
|
plane_info->dst_h = amp->adjust_dst.y2;
|
|
DRM_DEBUG_DRIVER("resize original dst [(%d %d), %dx%d]\n",
|
|
amp->adjust_dst.x1, amp->adjust_dst.y1, amp->adjust_dst.x2,
|
|
amp->adjust_dst.y2);
|
|
}
|
|
|
|
if (plane_info->rotation != amp->osd_reverse)
|
|
plane_info->rotation = amp->osd_reverse;
|
|
if (plane_info->blend_bypass != amp->osd_blend_bypass)
|
|
plane_info->blend_bypass = amp->osd_blend_bypass;
|
|
if (plane_info->read_ports != amp->osd_read_ports)
|
|
plane_info->read_ports = amp->osd_read_ports;
|
|
else
|
|
plane_info->read_ports = 2;
|
|
|
|
if (amp->zorder)
|
|
plane_info->zorder = amp->zorder;
|
|
}
|
|
if (scan_mode_out) {
|
|
plane_info->dst_y >>= 1;
|
|
plane_info->dst_h >>= 1;
|
|
}
|
|
/*negative position process*/
|
|
if (plane_info->dst_x < 0) {
|
|
dst_w = plane_info->dst_w + plane_info->dst_x;
|
|
if (dst_w > 0) {
|
|
src_w = plane_info->src_w * dst_w / plane_info->dst_w;
|
|
plane_info->src_x += plane_info->src_w - src_w;
|
|
plane_info->src_w = src_w;
|
|
plane_info->dst_w = dst_w;
|
|
plane_info->dst_x = 0;
|
|
} else {
|
|
plane_info->enable = 0;
|
|
}
|
|
DRM_DEBUG_DRIVER("state->crtc_x < 0\n");
|
|
}
|
|
if (plane_info->dst_y < 0) {
|
|
dst_h = plane_info->dst_h + plane_info->dst_y;
|
|
if (dst_h > 0) {
|
|
src_h = plane_info->src_h * dst_h / plane_info->dst_h;
|
|
plane_info->src_y += plane_info->src_h - src_h;
|
|
plane_info->src_h = src_h;
|
|
plane_info->dst_h = dst_h;
|
|
plane_info->dst_y = 0;
|
|
} else {
|
|
plane_info->enable = 0;
|
|
}
|
|
DRM_DEBUG_DRIVER("state->crtc_y < 0\n");
|
|
}
|
|
/*overdisplay process*/
|
|
if ((plane_info->dst_x + plane_info->dst_w) > mode->hdisplay) {
|
|
if (plane_info->dst_x >= mode->hdisplay) {
|
|
plane_info->enable = 0;
|
|
} else {
|
|
dst_w = plane_info->dst_w;
|
|
src_w = plane_info->src_w;
|
|
plane_info->dst_w =
|
|
mode->hdisplay - plane_info->dst_x;
|
|
plane_info->src_w =
|
|
(src_w * plane_info->dst_w) / dst_w;
|
|
}
|
|
DRM_DEBUG_DRIVER("(plane_info->dst_x + plane_info->dst_w) > mode->hdisplay\n");
|
|
}
|
|
if ((plane_info->dst_y + plane_info->dst_h) > mode->vdisplay) {
|
|
if (plane_info->dst_y >= mode->vdisplay) {
|
|
plane_info->enable = 0;
|
|
} else {
|
|
dst_h = plane_info->dst_h;
|
|
src_h = plane_info->src_h;
|
|
plane_info->dst_h =
|
|
mode->vdisplay - plane_info->dst_y;
|
|
plane_info->src_h =
|
|
(src_h * plane_info->dst_h) / dst_h;
|
|
}
|
|
DRM_DEBUG_DRIVER("(plane_info->dst_y + plane_info->dst_h) > mode->vdisplay\n");
|
|
}
|
|
/*reverse process*/
|
|
if (plane_info->rotation & DRM_MODE_REFLECT_X)
|
|
plane_info->dst_x = mode->hdisplay - plane_info->dst_w -
|
|
plane_info->dst_x;
|
|
if (plane_info->rotation & DRM_MODE_REFLECT_Y)
|
|
plane_info->dst_y = mode->vdisplay - plane_info->dst_h -
|
|
plane_info->dst_y;
|
|
|
|
plane_info->hdisplay = mode->hdisplay;
|
|
plane_info->vdisplay = mode->vdisplay;
|
|
/* add for calculation of scaler coefficient */
|
|
plane_info->htotal = mode->htotal;
|
|
plane_info->clock = mode->clock;
|
|
DRM_DEBUG_DRIVER("modified:src[(%d %d),%dx%d]dst[(%d %d),%dx%d]enable[%d]\n",
|
|
plane_info->src_x, plane_info->src_y, plane_info->src_w, plane_info->src_h,
|
|
plane_info->dst_x, plane_info->dst_y, plane_info->dst_w, plane_info->dst_h,
|
|
plane_info->enable);
|
|
}
|
|
|
|
static void
|
|
meson_video_plane_position_calc(struct meson_vpu_video_layer_info *plane_info,
|
|
struct drm_plane_state *state,
|
|
struct meson_vpu_pipeline *pipeline)
|
|
{
|
|
u32 orig_w, orig_h;
|
|
u32 crop_w = 0, crop_h = 0;
|
|
struct drm_atomic_state *atomic_state = state->state;
|
|
struct drm_crtc *crtc = state->crtc;
|
|
struct drm_crtc_state *crtc_state;
|
|
struct drm_display_mode *mode = NULL;
|
|
struct am_video_plane *avp;
|
|
|
|
if (crtc) {
|
|
crtc_state = drm_atomic_get_crtc_state(atomic_state, crtc);
|
|
if (crtc_state)
|
|
mode = &crtc_state->mode;
|
|
} else {
|
|
DRM_DEBUG_DRIVER("Disabling video plane %d, so skip position calc",
|
|
plane_info->plane_index);
|
|
return;
|
|
}
|
|
|
|
if (!crtc_state || !mode)
|
|
mode = &pipeline->subs[crtc->index]->mode;
|
|
|
|
plane_info->src_x = state->src_x >> 16;
|
|
plane_info->src_y = state->src_y >> 16;
|
|
plane_info->src_w = (state->src_w >> 16) & 0xffff;
|
|
plane_info->src_h = (state->src_h >> 16) & 0xffff;
|
|
plane_info->ori_src_x = plane_info->src_x;
|
|
plane_info->ori_src_y = plane_info->src_y;
|
|
plane_info->ori_src_w = plane_info->src_w;
|
|
plane_info->ori_src_h = plane_info->src_h;
|
|
|
|
plane_info->dst_x = state->crtc_x;
|
|
plane_info->dst_y = state->crtc_y;
|
|
plane_info->dst_w = state->crtc_w;
|
|
plane_info->dst_h = state->crtc_h;
|
|
plane_info->ori_dst_x = plane_info->dst_x;
|
|
plane_info->ori_dst_y = plane_info->dst_y;
|
|
plane_info->ori_dst_w = plane_info->dst_w;
|
|
plane_info->ori_dst_h = plane_info->dst_h;
|
|
|
|
DRM_DEBUG_DRIVER("original:src[(%d %d),%dx%d]dst[(%d %d),%dx%d]mode[%dx%d]\n",
|
|
plane_info->ori_src_x, plane_info->ori_src_y,
|
|
plane_info->ori_src_w, plane_info->ori_src_h,
|
|
plane_info->ori_dst_x, plane_info->ori_dst_y,
|
|
plane_info->ori_dst_w, plane_info->ori_dst_h,
|
|
mode->hdisplay, mode->vdisplay);
|
|
|
|
if (state->plane) {
|
|
avp = to_am_video_plane(state->plane);
|
|
|
|
if (avp->adjust_src.x1 > -1 && avp->adjust_src.y1 > -1 &&
|
|
avp->adjust_src.x2 > -1 && avp->adjust_src.y2 > -1) {
|
|
plane_info->src_x = avp->adjust_src.x1;
|
|
plane_info->src_y = avp->adjust_src.y1;
|
|
plane_info->src_w = avp->adjust_src.x2;
|
|
plane_info->src_h = avp->adjust_src.y2;
|
|
DRM_DEBUG_DRIVER("resize original src [(%d %d), %dx%d]\n",
|
|
avp->adjust_src.x1, avp->adjust_src.y1, avp->adjust_src.x2,
|
|
avp->adjust_src.y2);
|
|
}
|
|
|
|
if (avp->adjust_dst.x1 > -1 && avp->adjust_dst.y1 > -1 &&
|
|
avp->adjust_dst.x2 > -1 && avp->adjust_dst.y2 > -1) {
|
|
plane_info->dst_x = avp->adjust_dst.x1;
|
|
plane_info->dst_y = avp->adjust_dst.y1;
|
|
plane_info->dst_w = avp->adjust_dst.x2;
|
|
plane_info->dst_h = avp->adjust_dst.y2;
|
|
DRM_DEBUG_DRIVER("resize original dst [(%d %d), %dx%d]\n",
|
|
avp->adjust_dst.x1, avp->adjust_dst.y1, avp->adjust_dst.x2,
|
|
avp->adjust_dst.y2);
|
|
}
|
|
}
|
|
|
|
if (plane_info->is_uvm && plane_info->vf) {
|
|
DRM_DEBUG_DRIVER("type=0x%x, video_axis_zoom=%d, comp[%u, %u][%u %u]\n",
|
|
plane_info->vf->type, video_axis_zoom,
|
|
plane_info->vf->compWidth, plane_info->vf->compHeight,
|
|
plane_info->vf->width, plane_info->vf->height);
|
|
if ((video_axis_zoom != -1) && (plane_info->vf->type & VIDTYPE_COMPRESS)) {
|
|
plane_info->src_x = plane_info->src_x *
|
|
(plane_info->vf->compWidth / plane_info->vf->width);
|
|
plane_info->src_y = plane_info->src_y *
|
|
(plane_info->vf->compHeight / plane_info->vf->height);
|
|
plane_info->src_w = plane_info->src_w *
|
|
(plane_info->vf->compWidth / plane_info->vf->width);
|
|
plane_info->src_h = plane_info->src_h *
|
|
(plane_info->vf->compHeight / plane_info->vf->height);
|
|
DRM_DEBUG_DRIVER("COMPRESS:src[(%d %d), %dx%d]\n",
|
|
plane_info->src_x, plane_info->src_y,
|
|
plane_info->src_w, plane_info->src_h);
|
|
}
|
|
}
|
|
|
|
orig_w = plane_info->src_w;
|
|
orig_h = plane_info->src_h;
|
|
|
|
if (!bypass_video_crop && !(plane_info->frame_flag &
|
|
BIT(VIDEO_FRAME_BYPASS_CROP))) {
|
|
/*negative position process*/
|
|
if (plane_info->dst_x < 0) {
|
|
plane_info->src_x = (-plane_info->dst_x) *
|
|
plane_info->src_w / plane_info->dst_w;
|
|
plane_info->dst_w += state->crtc_x;
|
|
DRM_DEBUG_DRIVER("x<0:src_x=%d, dst_w=%d\n",
|
|
plane_info->src_x, plane_info->dst_w);
|
|
if (plane_info->dst_w > 0) {
|
|
plane_info->src_w -= plane_info->src_x;
|
|
plane_info->dst_x = 0;
|
|
} else {
|
|
plane_info->enable = 0;
|
|
}
|
|
DRM_DEBUG_DRIVER("x<0:src_x=%d, src_w=%d, dst_x=%d, dst_w=%d, enable=%d\n",
|
|
plane_info->src_x, plane_info->src_w,
|
|
plane_info->dst_x, plane_info->dst_w, plane_info->enable);
|
|
}
|
|
|
|
if (plane_info->dst_y < 0) {
|
|
plane_info->src_y = (-plane_info->dst_y) *
|
|
plane_info->src_h / plane_info->dst_h;
|
|
plane_info->dst_h += state->crtc_y;
|
|
DRM_DEBUG_DRIVER("y<0:src_y=%d, dst_h=%d\n",
|
|
plane_info->src_y, plane_info->dst_h);
|
|
if (plane_info->dst_h > 0) {
|
|
plane_info->src_h -= plane_info->src_y;
|
|
plane_info->dst_y = 0;
|
|
} else {
|
|
plane_info->enable = 0;
|
|
}
|
|
DRM_DEBUG_DRIVER("y<0:src_y=%d, src_h=%d, dst_y=%d, dst_h=%d, enable=%d\n",
|
|
plane_info->src_y, plane_info->src_h,
|
|
plane_info->dst_y, plane_info->dst_h, plane_info->enable);
|
|
}
|
|
|
|
/*overdisplay process*/
|
|
if ((plane_info->dst_x + plane_info->dst_w) > mode->hdisplay) {
|
|
if (plane_info->dst_x >= mode->hdisplay) {
|
|
plane_info->enable = 0;
|
|
} else {
|
|
u32 crop_w_src;
|
|
crop_w = plane_info->dst_x + plane_info->dst_w - mode->hdisplay;
|
|
crop_w_src = crop_w * orig_w / state->crtc_w;
|
|
if (plane_info->src_w >= crop_w_src)
|
|
plane_info->src_w -= crop_w_src;
|
|
else
|
|
plane_info->src_w = 0;
|
|
|
|
DRM_DEBUG_DRIVER("(x+w)>hdisplay:orig_w=%d, crop_w=%d, src_w=%d\n",
|
|
orig_w, crop_w, plane_info->src_w);
|
|
|
|
plane_info->dst_w -= crop_w;
|
|
}
|
|
DRM_DEBUG_DRIVER("(x+w)>hdisplay:src_w=%d, dst_w=%d, enable=%d\n",
|
|
plane_info->src_w, plane_info->dst_w, plane_info->enable);
|
|
}
|
|
|
|
if ((plane_info->dst_y + plane_info->dst_h) > mode->vdisplay) {
|
|
if (plane_info->dst_y >= mode->vdisplay) {
|
|
plane_info->enable = 0;
|
|
} else {
|
|
u32 crop_h_src;
|
|
crop_h = plane_info->dst_y + plane_info->dst_h - mode->vdisplay;
|
|
crop_h_src = crop_h * orig_h / state->crtc_h;
|
|
|
|
if (plane_info->src_h >= crop_h_src)
|
|
plane_info->src_h -= crop_h_src;
|
|
else
|
|
plane_info->src_h = 0;
|
|
|
|
DRM_DEBUG_DRIVER("(y+h)>vdisplay:orig_h=%d, crop_h=%d, src_h=%d\n",
|
|
orig_h, crop_h, plane_info->src_h);
|
|
|
|
plane_info->dst_h -= crop_h;
|
|
}
|
|
DRM_DEBUG_DRIVER("(y+h)>vdisplay:src_h=%d, dst_h=%d, enable=%d\n",
|
|
plane_info->src_h, plane_info->dst_h, plane_info->enable);
|
|
}
|
|
}
|
|
DRM_DEBUG_DRIVER("modified:src[(%d %d), %dx%d], dst[(%d %d), %dx%d]\n",
|
|
plane_info->src_x, plane_info->src_y, plane_info->src_w, plane_info->src_h,
|
|
plane_info->dst_x, plane_info->dst_y, plane_info->dst_w, plane_info->dst_h);
|
|
DRM_DEBUG_DRIVER("modified:enable = %d, orig[%d %d], crop[%d %d]\n",
|
|
plane_info->enable, orig_w, orig_h, crop_w, crop_h);
|
|
}
|
|
|
|
static int meson_plane_fb_check(struct drm_plane *plane,
|
|
struct drm_plane_state *new_state,
|
|
struct meson_vpu_osd_layer_info *plane_info)
|
|
{
|
|
struct drm_framebuffer *fb = new_state->fb;
|
|
#ifdef CONFIG_AMLOGIC_DRM_USE_ION
|
|
struct am_osd_plane *osd_plane = to_am_osd_plane(plane);
|
|
struct meson_drm *drv = osd_plane->drv;
|
|
struct am_meson_fb *meson_fb;
|
|
#else
|
|
struct drm_gem_cma_object *gem;
|
|
#endif
|
|
size_t fb_size = 0;
|
|
phys_addr_t phyaddr;
|
|
|
|
#ifdef CONFIG_AMLOGIC_DRM_USE_ION
|
|
meson_fb = container_of(fb, struct am_meson_fb, base);
|
|
if (!meson_fb) {
|
|
DRM_DEBUG_DRIVER("meson_fb is NULL\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
DRM_DEBUG_DRIVER("meson_fb[id:%d,ref:%d]=0x%p\n",
|
|
meson_fb->base.base.id,
|
|
kref_read(&meson_fb->base.base.refcount), meson_fb);
|
|
if (meson_fb->logo && meson_fb->logo->alloc_flag &&
|
|
meson_fb->logo->start) {
|
|
phyaddr = meson_fb->logo->start;
|
|
fb_size = meson_fb->logo->size;
|
|
DRM_DEBUG_DRIVER("logo->phyaddr=0x%pa\n", &phyaddr);
|
|
} else if (meson_fb->bufp[0]) {
|
|
phyaddr = am_meson_gem_object_get_phyaddr(drv,
|
|
meson_fb->bufp[0],
|
|
&fb_size);
|
|
if (drv->logo && drv->logo->is_std)
|
|
drv->logo->plane_has_fb = 1;
|
|
} else {
|
|
phyaddr = 0;
|
|
DRM_INFO("don't find phyaddr!\n");
|
|
return -EINVAL;
|
|
}
|
|
#else
|
|
if (!fb) {
|
|
DRM_DEBUG_DRIVER("fb is NULL\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Update Canvas with buffer address */
|
|
gem = drm_fb_cma_get_gem_obj(fb, 0);
|
|
if (!gem) {
|
|
DRM_INFO("gem is NULL!\n");
|
|
return -EINVAL;
|
|
}
|
|
phyaddr = gem->paddr;
|
|
#endif
|
|
plane_info->phy_addr = phyaddr;
|
|
plane_info->fb_size = (u32)fb_size;
|
|
return 0;
|
|
}
|
|
|
|
static struct vframe_s *get_vf_from_uvm(struct dma_buf *dmabuf)
|
|
{
|
|
struct vframe_s *vf = NULL;
|
|
bool is_dec_vf = false;
|
|
struct file_private_data *file_private_data = NULL;
|
|
struct uvm_hook_mod *uhmod;
|
|
|
|
if (!dmabuf)
|
|
return NULL;
|
|
|
|
is_dec_vf = is_valid_mod_type(dmabuf, VF_SRC_DECODER);
|
|
if (is_dec_vf) {
|
|
vf = dmabuf_get_vframe(dmabuf);
|
|
if (vf) {
|
|
DRM_DEBUG("vframe_type = 0x%x, vframe_flag = 0x%x.\n",
|
|
vf->type, vf->flag);
|
|
dmabuf_put_vframe(dmabuf);
|
|
} else {
|
|
DRM_DEBUG("vf is NULL.\n");
|
|
}
|
|
} else {
|
|
uhmod = uvm_get_hook_mod(dmabuf,
|
|
VF_PROCESS_V4LVIDEO);
|
|
if (!uhmod) {
|
|
DRM_DEBUG("uhmod is NULL\n");
|
|
return NULL;
|
|
}
|
|
if (IS_ERR_VALUE(uhmod) || !uhmod->arg) {
|
|
DRM_DEBUG("file_private_data is NULL.\n");
|
|
return NULL;
|
|
}
|
|
|
|
file_private_data = uhmod->arg;
|
|
uvm_put_hook_mod(dmabuf,
|
|
VF_PROCESS_V4LVIDEO);
|
|
vf = &file_private_data->vf;
|
|
}
|
|
|
|
return vf;
|
|
}
|
|
|
|
static int meson_video_plane_fb_check(struct drm_plane *plane,
|
|
struct drm_plane_state *new_state,
|
|
struct meson_vpu_video_layer_info *plane_info)
|
|
{
|
|
struct drm_framebuffer *fb = new_state->fb;
|
|
#ifdef CONFIG_AMLOGIC_DRM_USE_ION
|
|
struct am_video_plane *video_plane = to_am_video_plane(plane);
|
|
struct meson_drm *drv = video_plane->drv;
|
|
struct am_meson_fb *meson_fb;
|
|
struct dma_buf *dmabuf;
|
|
#else
|
|
struct drm_gem_cma_object *gem;
|
|
#endif
|
|
size_t fb_size[2] = {0};
|
|
phys_addr_t phyaddr, phyaddr1 = 0;
|
|
|
|
#ifdef CONFIG_AMLOGIC_DRM_USE_ION
|
|
if (!fb) {
|
|
DRM_INFO("fb is NULL!\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
meson_fb = container_of(fb, struct am_meson_fb, base);
|
|
if (!meson_fb) {
|
|
DRM_DEBUG_DRIVER("meson_fb is NULL!\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
DRM_DEBUG_DRIVER("meson_fb[id:%d,ref:%d]=0x%p\n",
|
|
meson_fb->base.base.id,
|
|
kref_read(&meson_fb->base.base.refcount), meson_fb);
|
|
if (meson_fb->bufp[0]) {
|
|
phyaddr =
|
|
am_meson_gem_object_get_phyaddr(drv,
|
|
meson_fb->bufp[0],
|
|
&fb_size[0]);
|
|
} else {
|
|
//phyaddr = 0;
|
|
DRM_INFO("don't find phyaddr!\n");
|
|
return -EINVAL;
|
|
}
|
|
if (meson_fb->bufp[1] && meson_fb->bufp[1] != meson_fb->bufp[0] &&
|
|
(fb->format->format == DRM_FORMAT_NV12 ||
|
|
fb->format->format == DRM_FORMAT_NV21 ||
|
|
fb->format->format == DRM_FORMAT_NV61 ||
|
|
fb->format->format == DRM_FORMAT_NV16)) {
|
|
phyaddr1 = am_meson_gem_object_get_phyaddr(drv,
|
|
meson_fb->bufp[1],
|
|
&fb_size[1]);
|
|
plane_info->dmabuf[1] = meson_fb->bufp[1]->base.dma_buf;
|
|
if (!plane_info->dmabuf[1])
|
|
plane_info->dmabuf[1] = meson_fb->bufp[1]->dmabuf;
|
|
} else {
|
|
plane_info->dmabuf[1] = NULL;
|
|
}
|
|
|
|
/* start to get vframe from uvm */
|
|
if (meson_fb->bufp[0]->is_uvm) {
|
|
dmabuf = meson_fb->bufp[0]->base.dma_buf;
|
|
plane_info->vf = get_vf_from_uvm(dmabuf);
|
|
plane_info->is_uvm = meson_fb->bufp[0]->is_uvm;
|
|
plane_info->dmabuf[0] = dmabuf;
|
|
} else {
|
|
plane_info->vf = NULL;
|
|
plane_info->is_uvm = 0;
|
|
plane_info->dmabuf[0] = meson_fb->bufp[0]->base.dma_buf;
|
|
if (!plane_info->dmabuf[0])
|
|
plane_info->dmabuf[0] = meson_fb->bufp[0]->dmabuf;
|
|
}
|
|
if (!plane_info->dmabuf[0]) {
|
|
DRM_ERROR("plane_info->dmabuf[0] is NULL!\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
DRM_DEBUG_DRIVER("dmabuf %px, %px, is_uvm %d, vf %px\n",
|
|
plane_info->dmabuf[0], plane_info->dmabuf[1],
|
|
plane_info->is_uvm, plane_info->vf);
|
|
#else
|
|
if (!fb) {
|
|
DRM_DEBUG_DRIVER("fb is NULL!\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Update Canvas with buffer address */
|
|
gem = drm_fb_cma_get_gem_obj(fb, 0);
|
|
if (!gem) {
|
|
DRM_INFO("gem is NULL!\n");
|
|
return -EINVAL;
|
|
}
|
|
phyaddr = gem->paddr;
|
|
#endif
|
|
plane_info->phy_addr[0] = phyaddr;
|
|
plane_info->fb_size[0] = (u32)fb_size[0];
|
|
plane_info->phy_addr[1] = phyaddr1;
|
|
plane_info->fb_size[1] = (u32)fb_size[1];
|
|
return 0;
|
|
}
|
|
|
|
static int meson_plane_get_fb_info(struct drm_plane *plane,
|
|
struct drm_plane_state *new_state,
|
|
struct meson_vpu_osd_layer_info *plane_info)
|
|
{
|
|
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;
|
|
|
|
if (!drv) {
|
|
DRM_INFO("%s new_state/meson_drm is NULL!\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
if (osd_plane->plane_index >= MESON_MAX_OSDS) {
|
|
DRM_INFO("%s invalid plane_index!\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
plane_info->pixel_format = fb->format->format;
|
|
plane_info->byte_stride = fb->pitches[0];
|
|
plane_info->fb_w = fb->width;
|
|
plane_info->fb_h = fb->height;
|
|
|
|
plane_info->afbc_en = 0;
|
|
plane_info->afbc_inter_format = 0;
|
|
plane_info->process_unit = MIF_MODE;
|
|
plane_info->afrc_cu_bits = 0;
|
|
|
|
if (fb->modifier) {
|
|
//afrc
|
|
if ((fb->modifier >> 52 & 0xf) ==
|
|
DRM_FORMAT_MOD_ARM_TYPE_AFRC) {
|
|
if ((fb->modifier & AFRC_FORMAT_MOD_CU_SIZE_MASK) ==
|
|
AFRC_FORMAT_MOD_CU_SIZE_16)
|
|
plane_info->afrc_cu_bits = 0;
|
|
else if ((fb->modifier & AFRC_FORMAT_MOD_CU_SIZE_MASK) ==
|
|
AFRC_FORMAT_MOD_CU_SIZE_24)
|
|
plane_info->afrc_cu_bits = 1;
|
|
else if ((fb->modifier & AFRC_FORMAT_MOD_CU_SIZE_MASK) ==
|
|
AFRC_FORMAT_MOD_CU_SIZE_32)
|
|
plane_info->afrc_cu_bits = 2;
|
|
|
|
plane_info->process_unit = GFCD_AFRC;
|
|
} else {
|
|
if (drv->vpu_data && drv->vpu_data->has_gfcd &&
|
|
(drv->of_conf.gfcd_enable ||
|
|
plane_info->pixel_format == DRM_FORMAT_ABGR10101010)) {
|
|
plane_info->process_unit = GFCD_AFBC;
|
|
if (am_drm_param.force_mali_afbc_mode) {
|
|
plane_info->process_unit = MALI_AFBC;
|
|
plane_info->afbc_en = 1;
|
|
plane_info->afbc_inter_format = AFBC_EN;
|
|
}
|
|
} else {
|
|
plane_info->afbc_en = 1;
|
|
plane_info->afbc_inter_format = AFBC_EN;
|
|
}
|
|
|
|
if (fb->modifier & AFBC_FORMAT_MOD_YTR)
|
|
plane_info->afbc_inter_format |= YUV_TRANSFORM;
|
|
|
|
if (fb->modifier & AFBC_FORMAT_MOD_SPLIT)
|
|
plane_info->afbc_inter_format |= BLOCK_SPLIT;
|
|
|
|
if (fb->modifier & AFBC_FORMAT_MOD_TILED)
|
|
plane_info->afbc_inter_format |= TILED_HEADER_EN;
|
|
|
|
if ((fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) ==
|
|
AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)
|
|
plane_info->afbc_inter_format |= SUPER_BLOCK_ASPECT;
|
|
}
|
|
}
|
|
|
|
if (!drv->of_conf.gfcd_enable &&
|
|
(plane_info->process_unit == GFCD_AFBC ||
|
|
plane_info->process_unit == GFCD_AFRC))
|
|
DRM_DEBUG_DRIVER("gfcd enable config mismatched with real frame,please check dts!");
|
|
|
|
DRM_DEBUG_DRIVER("flags=%d,pixel_format=0x%x,modifier=0x%llx,stride=%d\n",
|
|
fb->flags, fb->format->format, fb->modifier, plane_info->byte_stride);
|
|
DRM_DEBUG_DRIVER("afbc_en=%u,afbc_inter_format=0x%x,process_unit=%d,afrc_cu_bits=%d\n",
|
|
plane_info->afbc_en, plane_info->afbc_inter_format,
|
|
plane_info->process_unit, plane_info->afrc_cu_bits);
|
|
return 0;
|
|
}
|
|
|
|
static int meson_video_plane_get_fb_info(struct drm_plane *plane,
|
|
struct drm_plane_state *new_state,
|
|
struct meson_vpu_video_layer_info *plane_info)
|
|
{
|
|
struct am_video_plane *video_plane = to_am_video_plane(plane);
|
|
struct drm_framebuffer *fb = new_state->fb;
|
|
struct meson_drm *drv = video_plane->drv;
|
|
|
|
if (!drv) {
|
|
DRM_INFO("%s new_state/meson_drm is NULL!\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
if (video_plane->plane_index >= MESON_MAX_VIDEO) {
|
|
DRM_INFO("%s invalid plane_index!\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
plane_info->pixel_format = fb->format->format;
|
|
plane_info->byte_stride = fb->pitches[0];
|
|
plane_info->fb_w = fb->width;
|
|
plane_info->fb_h = fb->height;
|
|
|
|
DRM_DEBUG_DRIVER("flags=%d,modifier=%llu,fb=%dx%d,stride=%d,pixel_format=0x%x\n",
|
|
fb->flags, fb->modifier,
|
|
plane_info->fb_w, plane_info->fb_h,
|
|
plane_info->byte_stride, plane_info->pixel_format);
|
|
return 0;
|
|
}
|
|
|
|
static bool meson_video_plane_is_repeat_frame(struct meson_vpu_video *mvv)
|
|
{
|
|
struct meson_vpu_block *mvb = &mvv->base;
|
|
struct meson_vpu_block_state *mvbs = priv_to_block_state(mvb->obj.state);
|
|
struct meson_vpu_video_state *mvvs = to_video_state(mvbs);
|
|
|
|
if (mvvs->repeat_frame)
|
|
MESON_DRM_FENCE("video repeat frame!\n");
|
|
|
|
return mvvs->repeat_frame;
|
|
}
|
|
|
|
static const char *am_meson_video_fence_get_driver_name(struct dma_fence *fence)
|
|
{
|
|
return "aml_drm";
|
|
}
|
|
|
|
static void
|
|
am_meson_video_fence_release(struct dma_fence *fence)
|
|
{
|
|
kfree_rcu(fence, rcu);
|
|
fence = NULL;
|
|
}
|
|
|
|
static const char *
|
|
am_meson_video_fence_get_timeline_name(struct dma_fence *fence)
|
|
{
|
|
return "video_fence";
|
|
}
|
|
|
|
static const char *
|
|
am_meson_video_present_fence_get_timeline_name(struct dma_fence *fence)
|
|
{
|
|
return "video_present_fence";
|
|
}
|
|
|
|
static const struct dma_fence_ops am_meson_video_plane_fence_ops = {
|
|
.get_driver_name = am_meson_video_fence_get_driver_name,
|
|
.get_timeline_name = am_meson_video_fence_get_timeline_name,
|
|
.release = am_meson_video_fence_release,
|
|
};
|
|
|
|
static const struct dma_fence_ops am_meson_video_plane_present_fence_ops = {
|
|
.get_driver_name = am_meson_video_fence_get_driver_name,
|
|
.get_timeline_name = am_meson_video_present_fence_get_timeline_name,
|
|
.release = am_meson_video_fence_release,
|
|
};
|
|
|
|
static struct dma_fence *am_meson_video_create_fence(spinlock_t *lock,
|
|
struct am_video_plane *video_plane)
|
|
{
|
|
struct dma_fence *fence;
|
|
|
|
fence = kzalloc(sizeof(*fence), GFP_KERNEL);
|
|
if (!fence)
|
|
return NULL;
|
|
|
|
dma_fence_init(fence, &am_meson_video_plane_fence_ops,
|
|
lock, video_plane->context, ++video_plane->seqno);
|
|
|
|
return fence;
|
|
}
|
|
|
|
static struct dma_fence *am_meson_video_create_present_fence(spinlock_t *lock,
|
|
struct am_video_plane *video_plane)
|
|
{
|
|
struct dma_fence *fence;
|
|
|
|
fence = kzalloc(sizeof(*fence), GFP_KERNEL);
|
|
if (!fence)
|
|
return NULL;
|
|
|
|
dma_fence_init(fence, &am_meson_video_plane_present_fence_ops,
|
|
lock, video_plane->present_context, ++video_plane->present_seqno);
|
|
|
|
return fence;
|
|
}
|
|
|
|
static void set_release_fence_for_video(struct am_meson_video_plane_state *plane_state,
|
|
s32 __user *fence_ptr)
|
|
{
|
|
plane_state->video_release_fence_state.video_release_ptr = fence_ptr;
|
|
MESON_DRM_FENCE("%px, %px\n", plane_state, fence_ptr);
|
|
}
|
|
|
|
static s32 __user *get_release_fence_for_video(struct am_meson_video_plane_state *plane_state)
|
|
{
|
|
s32 __user *fence_ptr;
|
|
|
|
fence_ptr = plane_state->video_release_fence_state.video_release_ptr;
|
|
plane_state->video_release_fence_state.video_release_ptr = NULL;
|
|
MESON_DRM_FENCE("%px, %px\n", plane_state, fence_ptr);
|
|
return fence_ptr;
|
|
}
|
|
|
|
static int meson_video_prepare_fence(struct drm_plane *plane,
|
|
struct drm_plane_state *state,
|
|
struct meson_vpu_video *mvv)
|
|
{
|
|
struct am_video_plane *video_plane = to_am_video_plane(plane);
|
|
struct dma_fence *fence = NULL;
|
|
struct drm_video_release_fence_state *fence_state;
|
|
struct am_meson_video_plane_state *plane_state;
|
|
int ret = 0;
|
|
s32 __user *fence_ptr;
|
|
|
|
plane_state = to_am_meson_video_plane_state(state);
|
|
|
|
fence_ptr = get_release_fence_for_video(plane_state);
|
|
fence_state = &plane_state->video_release_fence_state;
|
|
|
|
/*creat implicit fence as out_fence, and next will directly
|
|
*export to video composer module
|
|
*/
|
|
fence = am_meson_video_create_fence(&video_plane->fence_lock, video_plane);
|
|
if (!fence)
|
|
return -ENOMEM;
|
|
|
|
mvv->fence = fence;
|
|
|
|
if (fence_ptr) {
|
|
fence_state->fd = get_unused_fd_flags(O_CLOEXEC);
|
|
if (fence_state->fd < 0) {
|
|
ret = fence_state->fd;
|
|
goto err_put_fence;
|
|
}
|
|
|
|
if (put_user(fence_state->fd, fence_ptr)) {
|
|
ret = -EFAULT;
|
|
MESON_DRM_FENCE("put_user fail\n");
|
|
goto err_put_fence;
|
|
}
|
|
|
|
fence_state->sync_file = sync_file_create(fence);
|
|
if (!fence_state->sync_file) {
|
|
ret = -ENOMEM;
|
|
goto err_put_fd;
|
|
}
|
|
|
|
fd_install(fence_state->fd, fence_state->sync_file->file);
|
|
|
|
MESON_DRM_FENCE("creat release fence(%px) seq:(%llx,%llx),plane_index%d\n",
|
|
fence, video_plane->context, video_plane->seqno,
|
|
video_plane->plane_index);
|
|
|
|
return 0;
|
|
|
|
err_put_fd:
|
|
put_unused_fd(fence_state->fd);
|
|
err_put_fence:
|
|
dma_fence_put(fence);
|
|
}
|
|
|
|
MESON_DRM_FENCE("creat fence(%px) seq:(%llx,%llx),plane_index%d\n",
|
|
fence, video_plane->context, video_plane->seqno,
|
|
video_plane->plane_index);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int meson_video_prepare_repeat_fence(struct drm_plane *plane,
|
|
struct drm_plane_state *state,
|
|
struct meson_vpu_video *mvv)
|
|
{
|
|
struct am_video_plane *video_plane = to_am_video_plane(plane);
|
|
struct drm_video_release_fence_state *fence_state;
|
|
struct am_meson_video_plane_state *plane_state;
|
|
int ret = 0;
|
|
s32 __user *fence_ptr;
|
|
|
|
if (!mvv->fence) {
|
|
WARN_ON(!mvv->fence);
|
|
return -EFAULT;
|
|
}
|
|
|
|
plane_state = to_am_meson_video_plane_state(state);
|
|
|
|
fence_ptr = get_release_fence_for_video(plane_state);
|
|
fence_state = &plane_state->video_release_fence_state;
|
|
|
|
if (fence_ptr) {
|
|
fence_state->fd = get_unused_fd_flags(O_CLOEXEC);
|
|
if (fence_state->fd < 0) {
|
|
ret = fence_state->fd;
|
|
goto err_put_fence;
|
|
}
|
|
|
|
if (put_user(fence_state->fd, fence_ptr)) {
|
|
ret = -EFAULT;
|
|
MESON_DRM_FENCE("put_user fail\n");
|
|
goto err_put_fence;
|
|
}
|
|
|
|
fence_state->sync_file = sync_file_create(mvv->fence);
|
|
if (!fence_state->sync_file) {
|
|
ret = -ENOMEM;
|
|
goto err_put_fd;
|
|
}
|
|
|
|
fd_install(fence_state->fd, fence_state->sync_file->file);
|
|
|
|
MESON_DRM_FENCE("repeat fence(%px) seq:(%llx,%llx),plane_index%d\n",
|
|
mvv->fence, video_plane->context, video_plane->seqno,
|
|
video_plane->plane_index);
|
|
|
|
return 0;
|
|
|
|
err_put_fd:
|
|
put_unused_fd(fence_state->fd);
|
|
err_put_fence:
|
|
dma_fence_put(mvv->fence);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void set_present_fence_for_video(struct am_meson_video_plane_state *plane_state,
|
|
s32 __user *fence_ptr)
|
|
{
|
|
plane_state->video_present_fence_state.video_present_ptr = fence_ptr;
|
|
MESON_DRM_FENCE("%px, %px\n", plane_state, fence_ptr);
|
|
}
|
|
|
|
static s32 __user *get_present_fence_for_video(struct am_meson_video_plane_state *plane_state)
|
|
{
|
|
s32 __user *fence_ptr;
|
|
|
|
fence_ptr = plane_state->video_present_fence_state.video_present_ptr;
|
|
plane_state->video_present_fence_state.video_present_ptr = NULL;
|
|
MESON_DRM_FENCE("%px, %px\n", plane_state, fence_ptr);
|
|
return fence_ptr;
|
|
}
|
|
|
|
static int meson_video_prepare_present_fence(struct drm_plane *plane,
|
|
struct drm_plane_state *state,
|
|
struct meson_vpu_video *mvv)
|
|
{
|
|
struct am_video_plane *video_plane = to_am_video_plane(plane);
|
|
struct dma_fence *fence = NULL;
|
|
struct drm_video_present_fence_state *fence_state;
|
|
struct am_meson_video_plane_state *plane_state;
|
|
int ret = 0;
|
|
s32 __user *fence_ptr;
|
|
|
|
plane_state = to_am_meson_video_plane_state(state);
|
|
|
|
fence_ptr = get_present_fence_for_video(plane_state);
|
|
fence_state = &plane_state->video_present_fence_state;
|
|
|
|
/*creat implicit fence as out_fence, and next will directly
|
|
*export to video composer module
|
|
*/
|
|
|
|
if (fence_ptr) {
|
|
fence = am_meson_video_create_present_fence(&video_plane->present_fence_lock,
|
|
video_plane);
|
|
if (!fence)
|
|
return -ENOMEM;
|
|
|
|
fence_state->fd = get_unused_fd_flags(O_CLOEXEC);
|
|
if (fence_state->fd < 0) {
|
|
ret = fence_state->fd;
|
|
goto err_put_fence;
|
|
}
|
|
|
|
if (put_user(fence_state->fd, fence_ptr)) {
|
|
ret = -EFAULT;
|
|
MESON_DRM_FENCE("put_user fail\n");
|
|
goto err_put_fence;
|
|
}
|
|
|
|
fence_state->sync_file = sync_file_create(fence);
|
|
if (!fence_state->sync_file) {
|
|
ret = -ENOMEM;
|
|
goto err_put_fd;
|
|
}
|
|
|
|
fd_install(fence_state->fd, fence_state->sync_file->file);
|
|
mvv->present_fence = fence;
|
|
|
|
MESON_DRM_FENCE("fence(%px), fd(%d), plane_index%d\n",
|
|
fence, fence_state->fd, video_plane->plane_index);
|
|
|
|
return 0;
|
|
|
|
err_put_fd:
|
|
put_unused_fd(fence_state->fd);
|
|
err_put_fence:
|
|
dma_fence_put(fence);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int meson_plane_atomic_get_property(struct drm_plane *plane,
|
|
const struct drm_plane_state *state,
|
|
struct drm_property *property,
|
|
uint64_t *val)
|
|
{
|
|
struct am_osd_plane *osd_plane = to_am_osd_plane(plane);
|
|
struct am_meson_plane_state *plane_state;
|
|
struct meson_drm *drv = osd_plane->drv;
|
|
int ret = 0;
|
|
|
|
plane_state = to_am_meson_plane_state(state);
|
|
|
|
if (property == osd_plane->occupied_property) {
|
|
*val = osd_plane->osd_occupied;
|
|
return 0;
|
|
} else if (property == osd_plane->prop_sec_en) {
|
|
*val = plane_state->sec_en;
|
|
ret = 0;
|
|
} else if (property == osd_plane->palette) {
|
|
*val = osd_plane->palette_id;
|
|
ret = 0;
|
|
} else if (property == osd_plane->rotation_reflect_property) {
|
|
*val = osd_plane->osd_reverse;
|
|
ret = 0;
|
|
} else if (property == osd_plane->unsupport_nonafbc) {
|
|
if (!drv) {
|
|
DRM_INFO("%s meson_drm is NULL!\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
*val = drv->pipeline->osd_axi_sel;
|
|
ret = 0;
|
|
} else if (property == osd_plane->dimm_ctrl_property) {
|
|
*val = osd_plane->osd_dimm.dimm_value;
|
|
ret = 0;
|
|
} else if (property == osd_plane->osd_capability_property) {
|
|
*val = drv->pipeline->osd_capability[osd_plane->plane_index];
|
|
ret = 0;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int meson_plane_atomic_set_property(struct drm_plane *plane,
|
|
struct drm_plane_state *state,
|
|
struct drm_property *property,
|
|
uint64_t val)
|
|
{
|
|
struct am_osd_plane *osd_plane = to_am_osd_plane(plane);
|
|
struct am_meson_plane_state *plane_state;
|
|
struct drm_property_blob *new_blob = NULL;
|
|
int ret = 0;
|
|
|
|
plane_state = to_am_meson_plane_state(state);
|
|
|
|
if (property == osd_plane->occupied_property) {
|
|
osd_plane->osd_occupied = val;
|
|
return 0;
|
|
} else if (property == osd_plane->prop_sec_en) {
|
|
plane_state->sec_en = val;
|
|
ret = 0;
|
|
} else if (property == osd_plane->palette) {
|
|
osd_plane->palette_id = val;
|
|
new_blob = drm_property_lookup_blob(osd_plane->drv->drm, val);
|
|
if (!new_blob)
|
|
return ret;
|
|
osd_plane->receive_palette = new_blob->data;
|
|
drm_property_blob_put(new_blob);
|
|
ret = 0;
|
|
} else if (property == osd_plane->rotation_reflect_property) {
|
|
osd_plane->osd_reverse = val;
|
|
ret = 0;
|
|
} else if (property == osd_plane->dimm_ctrl_property) {
|
|
osd_plane->osd_dimm.dimm_value = val;
|
|
osd_plane->osd_dimm.dimm_ctrl = 1;
|
|
ret = 0;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int meson_video_plane_atomic_get_property(struct drm_plane *plane,
|
|
const struct drm_plane_state *state,
|
|
struct drm_property *property,
|
|
uint64_t *val)
|
|
{
|
|
struct am_video_plane *video_plane = to_am_video_plane(plane);
|
|
struct am_meson_video_plane_state *plane_state;
|
|
struct meson_vpu_pipeline *ppl = video_plane->pipeline;
|
|
struct meson_vpu_video *mvv = ppl->video[video_plane->plane_index];
|
|
|
|
plane_state = to_am_meson_video_plane_state(state);
|
|
|
|
if (property == video_plane->signal_fmt_property) {
|
|
*val = plane_state->signal_fmt;
|
|
} else if (property == video_plane->frame_flag_prop) {
|
|
*val = 0;
|
|
} else if (property == video_plane->video_cap_property) {
|
|
*val = mvv->video_cap;
|
|
} else if (property == video_plane->video_src_min_size_property) {
|
|
*val = mvv->src_min_size;
|
|
} else if (property == video_plane->video_src_max_size_property) {
|
|
*val = mvv->src_max_size;
|
|
} else if (property == video_plane->async_in_fence_property) {
|
|
*val = -1;
|
|
} else if (property == video_plane->video_present_fence_property) {
|
|
*val = 0;
|
|
} else if (property == video_plane->video_release_fence_property) {
|
|
*val = 0;
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int meson_video_plane_atomic_set_property(struct drm_plane *plane,
|
|
struct drm_plane_state *state,
|
|
struct drm_property *property,
|
|
uint64_t val)
|
|
{
|
|
struct am_video_plane *video_plane = to_am_video_plane(plane);
|
|
struct am_meson_video_plane_state *plane_state;
|
|
|
|
plane_state = to_am_meson_video_plane_state(state);
|
|
|
|
if (property == video_plane->signal_fmt_property) {
|
|
plane_state->signal_fmt = val;
|
|
return 0;
|
|
} else if (property == video_plane->frame_flag_prop) {
|
|
plane_state->frame_flag = val;
|
|
return 0;
|
|
} else if (property == video_plane->async_in_fence_property) {
|
|
if (plane_state->async_in_fence)
|
|
return -EINVAL;
|
|
|
|
if (U642I64(val) == -1)
|
|
return 0;
|
|
|
|
plane_state->async_in_fence = sync_file_get_fence(val);
|
|
if (!plane_state->async_in_fence)
|
|
return -EINVAL;
|
|
} else if (property == video_plane->video_present_fence_property) {
|
|
s32 __user *fence_ptr = u64_to_user_ptr(val);
|
|
|
|
if (!fence_ptr)
|
|
return 0;
|
|
|
|
if (put_user(-1, fence_ptr))
|
|
return -EFAULT;
|
|
set_present_fence_for_video(plane_state, fence_ptr);
|
|
} else if (property == video_plane->video_release_fence_property) {
|
|
s32 __user *fence_ptr = u64_to_user_ptr(val);
|
|
|
|
if (!fence_ptr)
|
|
return 0;
|
|
|
|
if (put_user(-1, fence_ptr))
|
|
return -EFAULT;
|
|
set_release_fence_for_video(plane_state, fence_ptr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int meson_async_atomic_plane_set_property(struct drm_plane *plane,
|
|
struct drm_plane_state *state, struct drm_file *file_priv,
|
|
struct drm_property *property, u64 val)
|
|
{
|
|
struct am_video_plane *video_plane = NULL;
|
|
struct am_meson_video_plane_state *plane_state = NULL;
|
|
struct drm_device *dev = plane->dev;
|
|
struct drm_mode_config *config = &dev->mode_config;
|
|
|
|
bool replaced = false;
|
|
int ret;
|
|
|
|
if (plane->funcs == &am_video_plane_funs) {
|
|
video_plane = to_am_video_plane(plane);
|
|
plane_state = to_am_meson_video_plane_state(state);
|
|
}
|
|
|
|
if (property == config->prop_fb_id) {
|
|
struct drm_framebuffer *fb;
|
|
|
|
fb = drm_framebuffer_lookup(dev, file_priv, val);
|
|
drm_atomic_set_fb_for_plane(state, fb);
|
|
if (fb)
|
|
drm_framebuffer_put(fb);
|
|
} else if (property == config->prop_in_fence_fd) {
|
|
if (state->fence)
|
|
return -EINVAL;
|
|
|
|
if (U642I64(val) == -1)
|
|
return 0;
|
|
|
|
state->fence = sync_file_get_fence(val);
|
|
if (!state->fence)
|
|
return -EINVAL;
|
|
|
|
} else if (video_plane && property == video_plane->async_in_fence_property) {
|
|
if (plane_state->async_in_fence)
|
|
return -EINVAL;
|
|
|
|
if (U642I64(val) == -1)
|
|
return 0;
|
|
|
|
plane_state->async_in_fence = sync_file_get_fence(val);
|
|
MESON_DRM_FENCE("plane_state->async_in_fence %px",
|
|
plane_state->async_in_fence);
|
|
if (!plane_state->async_in_fence)
|
|
return -EINVAL;
|
|
|
|
} else if (video_plane && property == video_plane->video_present_fence_property) {
|
|
s32 __user *fence_ptr = u64_to_user_ptr(val);
|
|
|
|
if (!fence_ptr)
|
|
return 0;
|
|
|
|
if (put_user(-1, fence_ptr))
|
|
return -EFAULT;
|
|
set_present_fence_for_video(plane_state, fence_ptr);
|
|
} else if (video_plane && property == video_plane->video_release_fence_property) {
|
|
s32 __user *fence_ptr = u64_to_user_ptr(val);
|
|
|
|
if (!fence_ptr)
|
|
return 0;
|
|
|
|
if (put_user(-1, fence_ptr))
|
|
return -EFAULT;
|
|
set_release_fence_for_video(plane_state, fence_ptr);
|
|
} else if (property == config->prop_crtc_id) {
|
|
struct drm_crtc *crtc = drm_crtc_find(dev, file_priv, val);
|
|
|
|
if (val && !crtc)
|
|
return -EACCES;
|
|
return drm_atomic_set_crtc_for_plane(state, crtc);
|
|
} else if (property == config->prop_crtc_x) {
|
|
state->crtc_x = U642I64(val);
|
|
} else if (property == config->prop_crtc_y) {
|
|
state->crtc_y = U642I64(val);
|
|
} else if (property == config->prop_crtc_w) {
|
|
state->crtc_w = val;
|
|
} else if (property == config->prop_crtc_h) {
|
|
state->crtc_h = val;
|
|
} else if (property == config->prop_src_x) {
|
|
state->src_x = val;
|
|
} else if (property == config->prop_src_y) {
|
|
state->src_y = val;
|
|
} else if (property == config->prop_src_w) {
|
|
state->src_w = val;
|
|
} else if (property == config->prop_src_h) {
|
|
state->src_h = val;
|
|
} else if (property == plane->alpha_property) {
|
|
state->alpha = val;
|
|
} else if (property == plane->blend_mode_property) {
|
|
state->pixel_blend_mode = val;
|
|
} else if (property == plane->rotation_property) {
|
|
if (!is_power_of_2(val & DRM_MODE_ROTATE_MASK)) {
|
|
DRM_DEBUG_ATOMIC("[PLANE:%d:%s] bad rotation bitmask: 0x%llx\n",
|
|
plane->base.id, plane->name, val);
|
|
return -EINVAL;
|
|
}
|
|
state->rotation = val;
|
|
} else if (property == plane->zpos_property) {
|
|
state->zpos = val;
|
|
} else if (property == plane->color_encoding_property) {
|
|
state->color_encoding = val;
|
|
} else if (property == plane->color_range_property) {
|
|
state->color_range = val;
|
|
} else if (property == config->prop_fb_damage_clips) {
|
|
ret = drm_property_replace_blob_from_id(dev,
|
|
&state->fb_damage_clips,
|
|
val,
|
|
-1,
|
|
sizeof(struct drm_rect),
|
|
&replaced);
|
|
return ret;
|
|
} else if (property == plane->scaling_filter_property) {
|
|
state->scaling_filter = val;
|
|
} else if (plane->funcs->atomic_set_property) {
|
|
return plane->funcs->atomic_set_property(plane, state,
|
|
property, val);
|
|
} else {
|
|
DRM_DEBUG_ATOMIC("[PLANE:%d:%s] unknown property [PROP:%d:%s]]\n",
|
|
plane->base.id, plane->name,
|
|
property->base.id, property->name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct drm_plane_state *
|
|
meson_plane_duplicate_state(struct drm_plane *plane)
|
|
{
|
|
struct am_meson_plane_state *meson_plane_state;
|
|
|
|
if (WARN_ON(!plane->state))
|
|
return NULL;
|
|
|
|
DRM_DEBUG_DRIVER("(%s)\n", plane->name);
|
|
|
|
meson_plane_state = kzalloc(sizeof(*meson_plane_state), GFP_KERNEL);
|
|
if (!meson_plane_state)
|
|
return NULL;
|
|
|
|
__drm_atomic_helper_plane_duplicate_state(plane,
|
|
&meson_plane_state->base);
|
|
return &meson_plane_state->base;
|
|
}
|
|
|
|
static struct drm_plane_state *
|
|
meson_video_plane_duplicate_state(struct drm_plane *plane)
|
|
{
|
|
struct am_meson_video_plane_state *meson_plane_state;
|
|
|
|
if (WARN_ON(!plane->state))
|
|
return NULL;
|
|
|
|
DRM_DEBUG("(%s)\n", plane->name);
|
|
|
|
meson_plane_state = kzalloc(sizeof(*meson_plane_state), GFP_KERNEL);
|
|
if (!meson_plane_state)
|
|
return NULL;
|
|
|
|
__drm_atomic_helper_plane_duplicate_state(plane,
|
|
&meson_plane_state->base);
|
|
return &meson_plane_state->base;
|
|
}
|
|
|
|
static void meson_plane_destroy_state(struct drm_plane *plane,
|
|
struct drm_plane_state *state)
|
|
{
|
|
struct am_meson_plane_state *meson_plane_state;
|
|
|
|
meson_plane_state = to_am_meson_plane_state(state);
|
|
__drm_atomic_helper_plane_destroy_state(&meson_plane_state->base);
|
|
kfree(meson_plane_state);
|
|
}
|
|
|
|
static void meson_video_plane_destroy_state(struct drm_plane *plane,
|
|
struct drm_plane_state *state)
|
|
{
|
|
struct am_meson_video_plane_state *meson_plane_state;
|
|
|
|
meson_plane_state = to_am_meson_video_plane_state(state);
|
|
__drm_atomic_helper_plane_destroy_state(&meson_plane_state->base);
|
|
kfree(meson_plane_state);
|
|
}
|
|
|
|
static void meson_osd_plane_reset(struct drm_plane *plane)
|
|
{
|
|
struct am_meson_plane_state *meson_plane_state;
|
|
int zpos = 0;
|
|
struct am_osd_plane *osd_plane = to_am_osd_plane(plane);
|
|
|
|
zpos = osd_plane->plane_index + OSD_PLANE_BEGIN_ZORDER;
|
|
|
|
if (plane->state) {
|
|
meson_plane_destroy_state(plane, plane->state);
|
|
plane->state = NULL;
|
|
}
|
|
|
|
meson_plane_state = kzalloc(sizeof(*meson_plane_state), GFP_KERNEL);
|
|
if (!meson_plane_state)
|
|
return;
|
|
|
|
__drm_atomic_helper_plane_reset(plane, &meson_plane_state->base);
|
|
meson_plane_state->base.pixel_blend_mode = DRM_MODE_BLEND_COVERAGE;
|
|
/*reset zpos property unless it set by hwc*/
|
|
if (meson_plane_state->base.zpos == 0)
|
|
meson_plane_state->base.zpos = zpos;
|
|
}
|
|
|
|
static void meson_video_plane_reset(struct drm_plane *plane)
|
|
{
|
|
struct am_meson_video_plane_state *meson_plane_state;
|
|
int zpos = 0;
|
|
struct am_video_plane *video_plane = to_am_video_plane(plane);
|
|
|
|
zpos = video_plane->plane_index + VIDEO_PLANE_BEGIN_ZORDER;
|
|
|
|
if (plane->state) {
|
|
meson_plane_state = to_am_meson_video_plane_state(plane->state);
|
|
__drm_atomic_helper_plane_destroy_state(plane->state);
|
|
kfree(meson_plane_state);
|
|
plane->state = NULL;
|
|
}
|
|
|
|
meson_plane_state = kzalloc(sizeof(*meson_plane_state), GFP_KERNEL);
|
|
if (!meson_plane_state)
|
|
return;
|
|
|
|
__drm_atomic_helper_plane_reset(plane, &meson_plane_state->base);
|
|
/*reset zpos property unless it set by hwc*/
|
|
if (meson_plane_state->base.zpos == 0)
|
|
meson_plane_state->base.zpos = zpos;
|
|
}
|
|
|
|
bool am_meson_vpu_check_format_mod(struct drm_plane *plane,
|
|
u32 format, u64 modifier)
|
|
{
|
|
DRM_DEBUG_DRIVER("modifier %llu", modifier);
|
|
if (modifier == DRM_FORMAT_MOD_INVALID)
|
|
return false;
|
|
|
|
if (modifier == DRM_FORMAT_MOD_LINEAR)
|
|
return true;
|
|
|
|
switch (format) {
|
|
case DRM_FORMAT_XRGB8888:
|
|
case DRM_FORMAT_ARGB8888:
|
|
/* YTR is forbidden for non XBGR formats */
|
|
if (modifier & AFBC_FORMAT_MOD_YTR)
|
|
return false;
|
|
fallthrough;
|
|
case DRM_FORMAT_XBGR8888:
|
|
case DRM_FORMAT_ABGR8888:
|
|
case DRM_FORMAT_ABGR2101010:
|
|
case DRM_FORMAT_ABGR10101010:
|
|
case DRM_FORMAT_RGBA8888:
|
|
return true;
|
|
case DRM_FORMAT_RGB888:
|
|
/* YTR is forbidden for non XBGR formats */
|
|
//if (modifier & AFBC_FORMAT_MOD_YTR)
|
|
// return false;
|
|
return true;
|
|
case DRM_FORMAT_RGB565:
|
|
/* YTR is forbidden for non XBGR formats */
|
|
if (modifier & AFBC_FORMAT_MOD_YTR)
|
|
return false;
|
|
return true;
|
|
/* TOFIX support mode formats */
|
|
default:
|
|
DRM_DEBUG_DRIVER("unsupported afbc format[%08x]\n", format);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool am_meson_vpu_check_video_format_mod(struct drm_plane *plane,
|
|
u32 format, u64 modifier)
|
|
{
|
|
if (modifier == DRM_FORMAT_MOD_LINEAR &&
|
|
format != DRM_FORMAT_YUV420_8BIT &&
|
|
format != DRM_FORMAT_YUV420_10BIT)
|
|
return true;
|
|
|
|
if ((modifier & DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) ==
|
|
DRM_FORMAT_MOD_AMLOGIC_FBC(0, 0)) {
|
|
unsigned int layout = modifier &
|
|
DRM_FORMAT_MOD_AMLOGIC_FBC(__fourcc_mod_amlogic_layout_mask, 0);
|
|
unsigned int options =
|
|
(modifier >> __fourcc_mod_amlogic_options_shift) &
|
|
__fourcc_mod_amlogic_options_mask;
|
|
|
|
if (format != DRM_FORMAT_YUV420_8BIT &&
|
|
format != DRM_FORMAT_YUV420_10BIT) {
|
|
DRM_DEBUG_DRIVER("%llx invalid format 0x%08x\n",
|
|
modifier, format);
|
|
return false;
|
|
}
|
|
|
|
if (layout != AMLOGIC_FBC_LAYOUT_BASIC &&
|
|
layout != AMLOGIC_FBC_LAYOUT_SCATTER) {
|
|
DRM_DEBUG_DRIVER("%llx invalid layout %x\n",
|
|
modifier, layout);
|
|
return false;
|
|
}
|
|
|
|
if (options &&
|
|
options != AMLOGIC_FBC_OPTION_MEM_SAVING) {
|
|
DRM_DEBUG_DRIVER("%llx invalid layout %x\n",
|
|
modifier, layout);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
DRM_DEBUG_DRIVER("invalid modifier %llx for format 0x%08x\n",
|
|
modifier, format);
|
|
|
|
return false;
|
|
}
|
|
|
|
static void meson_osd_plane_atomic_print_state(struct drm_printer *p,
|
|
const struct drm_plane_state *state)
|
|
{
|
|
struct drm_plane *plane;
|
|
struct meson_vpu_osd_layer_info *plane_info;
|
|
struct meson_vpu_sub_pipeline_state *mvps;
|
|
struct am_osd_plane *osd_plane;
|
|
struct meson_drm *drv;
|
|
struct drm_private_state *obj_state;
|
|
u32 crtc_index = 0;
|
|
|
|
if (!state) {
|
|
DRM_INFO("%s state/meson_drm is NULL!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
plane = state->plane;
|
|
if (!plane) {
|
|
DRM_INFO("%s drm_plane is NULL!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
osd_plane = to_am_osd_plane(plane);
|
|
DRM_DEBUG_DRIVER("[%d]\n", osd_plane->plane_index);
|
|
|
|
drv = osd_plane->drv;
|
|
if (!drv || !drv->pipeline) {
|
|
DRM_INFO("%s private state or pipeline is NULL!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
if (state->crtc)
|
|
crtc_index = state->crtc->index;
|
|
else if (drv->pipeline->osd_crtc_index[osd_plane->plane_index] != -1)
|
|
crtc_index = drv->pipeline->osd_crtc_index[osd_plane->plane_index];
|
|
|
|
obj_state = drv->pipeline->subs[crtc_index]->obj.state;
|
|
if (!obj_state) {
|
|
DRM_ERROR("null pipeline obj state!\n");
|
|
return;
|
|
}
|
|
|
|
mvps = container_of(obj_state, struct meson_vpu_sub_pipeline_state, obj);
|
|
if (!mvps || osd_plane->plane_index >= MESON_MAX_OSDS) {
|
|
DRM_INFO("%s mvps/osd_plane is NULL!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
plane_info = &mvps->plane_info[osd_plane->plane_index];
|
|
|
|
drm_printf(p, "\tmeson osd plane %d info:\n", osd_plane->plane_index);
|
|
drm_printf(p, "\t\tori_src_x=%u\n", plane_info->ori_src_x);
|
|
drm_printf(p, "\t\tori_src_y=%u\n", plane_info->ori_src_y);
|
|
drm_printf(p, "\t\tori_src_w=%u\n", plane_info->ori_src_w);
|
|
drm_printf(p, "\t\tori_src_h=%u\n", plane_info->ori_src_h);
|
|
drm_printf(p, "\t\tori_dst_x=%d\n", plane_info->ori_dst_x);
|
|
drm_printf(p, "\t\tori_dst_y=%d\n", plane_info->ori_dst_y);
|
|
drm_printf(p, "\t\tori_dst_w=%u\n", plane_info->ori_dst_w);
|
|
drm_printf(p, "\t\tori_dst_h=%u\n", plane_info->ori_dst_h);
|
|
drm_printf(p, "\t\tsrc_x=%u\n", plane_info->src_x);
|
|
drm_printf(p, "\t\tsrc_y=%u\n", plane_info->src_y);
|
|
drm_printf(p, "\t\tsrc_w=%u\n", plane_info->src_w);
|
|
drm_printf(p, "\t\tsrc_h=%u\n", plane_info->src_h);
|
|
drm_printf(p, "\t\tdst_x=%d\n", plane_info->dst_x);
|
|
drm_printf(p, "\t\tdst_y=%d\n", plane_info->dst_y);
|
|
drm_printf(p, "\t\tdst_w=%u\n", plane_info->dst_w);
|
|
drm_printf(p, "\t\tdst_h=%u\n", plane_info->dst_h);
|
|
drm_printf(p, "\t\tsrc_w_offset4hdr=%d\n", plane_info->src_w_offset4hdr);
|
|
drm_printf(p, "\t\tfb_w=%u\n", plane_info->fb_w);
|
|
drm_printf(p, "\t\tfb_h=%u\n", plane_info->fb_h);
|
|
drm_printf(p, "\t\tzorder=%u\n", plane_info->zorder);
|
|
drm_printf(p, "\t\tbyte_stride=%u\n", plane_info->byte_stride);
|
|
drm_printf(p, "\t\tpixel_format=%u\n", plane_info->pixel_format);
|
|
drm_printf(p, "\t\tphy_addr=0x%llx\n", plane_info->phy_addr);
|
|
drm_printf(p, "\t\tplane_index=%u\n", plane_info->plane_index);
|
|
drm_printf(p, "\t\tuhd_plane_index=%u\n", plane_info->uhd_plane_index);
|
|
drm_printf(p, "\t\tenable=%u\n", plane_info->enable);
|
|
drm_printf(p, "\t\tratio_x=%u\n", plane_info->ratio_x);
|
|
drm_printf(p, "\t\tafbc_inter_format=%u\n",
|
|
plane_info->afbc_inter_format);
|
|
drm_printf(p, "\t\tafbc_en=%u\n", plane_info->afbc_en);
|
|
drm_printf(p, "\t\tprocess_unit=%u\n", plane_info->process_unit);
|
|
drm_printf(p, "\t\tfb_size=%u\n", plane_info->fb_size);
|
|
drm_printf(p, "\t\tpixel_blend=%u\n", plane_info->pixel_blend);
|
|
drm_printf(p, "\t\trotation=%u\n", plane_info->rotation);
|
|
drm_printf(p, "\t\tblend_bypass=%u\n", plane_info->blend_bypass);
|
|
drm_printf(p, "\t\tglobal_alpha=%u\n", plane_info->global_alpha);
|
|
drm_printf(p, "\t\tscaling_filter=%u\n", plane_info->scaling_filter);
|
|
drm_printf(p, "\t\tread_ports=%u\n", plane_info->read_ports);
|
|
drm_printf(p, "\t\tdisable_thread_en=%u\n", drv->of_conf.disable_thread_en);
|
|
}
|
|
|
|
static void meson_video_plane_atomic_print_state(struct drm_printer *p,
|
|
const struct drm_plane_state *state)
|
|
{
|
|
struct drm_plane *plane;
|
|
struct meson_vpu_video_layer_info *plane_info;
|
|
struct meson_video_sub_pipeline_state *mvps;
|
|
struct am_video_plane *video_plane;
|
|
struct meson_drm *drv;
|
|
struct drm_private_state *obj_state;
|
|
u32 crtc_index = 0;
|
|
|
|
if (!state) {
|
|
DRM_INFO("%s state/meson_drm is NULL!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
plane = state->plane;
|
|
if (!plane) {
|
|
DRM_INFO("%s drm_plane is NULL!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
video_plane = to_am_video_plane(plane);
|
|
DRM_DEBUG_DRIVER("[%d]\n", video_plane->plane_index);
|
|
|
|
drv = video_plane->drv;
|
|
if (!drv || !drv->pipeline) {
|
|
DRM_INFO("%s private state is NULL!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
if (state->crtc)
|
|
crtc_index = state->crtc->index;
|
|
else if (drv->pipeline->video_crtc_index[video_plane->plane_index] != -1)
|
|
crtc_index = drv->pipeline->video_crtc_index[video_plane->plane_index];
|
|
|
|
obj_state = drv->pipeline->video_subs[crtc_index].obj.state;
|
|
if (!obj_state) {
|
|
DRM_ERROR("null pipeline obj state!\n");
|
|
return;
|
|
}
|
|
|
|
mvps = container_of(obj_state, struct meson_video_sub_pipeline_state, obj);
|
|
if (!mvps || video_plane->plane_index >= MESON_MAX_VIDEO) {
|
|
DRM_INFO("%s mvps/video_plane is NULL!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
plane_info = &mvps->video_plane_info[video_plane->plane_index];
|
|
drm_printf(p, "\tmeson video plane %d info:\n",
|
|
video_plane->plane_index);
|
|
drm_printf(p, "\t\tori_src_x=%u\n", plane_info->ori_src_x);
|
|
drm_printf(p, "\t\tori_src_y=%u\n", plane_info->ori_src_y);
|
|
drm_printf(p, "\t\tori_src_w=%u\n", plane_info->ori_src_w);
|
|
drm_printf(p, "\t\tori_src_h=%u\n", plane_info->ori_src_h);
|
|
drm_printf(p, "\t\tori_dst_x=%d\n", plane_info->ori_dst_x);
|
|
drm_printf(p, "\t\tori_dst_y=%d\n", plane_info->ori_dst_y);
|
|
drm_printf(p, "\t\tori_dst_w=%u\n", plane_info->ori_dst_w);
|
|
drm_printf(p, "\t\tori_dst_h=%u\n", plane_info->ori_dst_h);
|
|
drm_printf(p, "\t\tsrc_x=%u\n", plane_info->src_x);
|
|
drm_printf(p, "\t\tsrc_y=%u\n", plane_info->src_y);
|
|
drm_printf(p, "\t\tsrc_w=%u\n", plane_info->src_w);
|
|
drm_printf(p, "\t\tsrc_h=%u\n", plane_info->src_h);
|
|
drm_printf(p, "\t\tdst_x=%d\n", plane_info->dst_x);
|
|
drm_printf(p, "\t\tdst_y=%d\n", plane_info->dst_y);
|
|
drm_printf(p, "\t\tdst_w=%u\n", plane_info->dst_w);
|
|
drm_printf(p, "\t\tdst_h=%u\n", plane_info->dst_h);
|
|
drm_printf(p, "\t\tzorder=%u\n", plane_info->zorder);
|
|
drm_printf(p, "\t\tbyte_stride=%u\n", plane_info->byte_stride);
|
|
drm_printf(p, "\t\tpixel_format=%u\n", plane_info->pixel_format);
|
|
drm_printf(p, "\t\tphy_addr[0]=0x%llx\n", plane_info->phy_addr[0]);
|
|
drm_printf(p, "\t\tphy_addr[1]=0x%llx\n", plane_info->phy_addr[1]);
|
|
drm_printf(p, "\t\tplane_index=%u\n", plane_info->plane_index);
|
|
drm_printf(p, "\t\tenable=%u\n", plane_info->enable);
|
|
drm_printf(p, "\t\tratio_x=%u\n", plane_info->ratio_x);
|
|
drm_printf(p, "\t\tfb_size[0]=%u\n", plane_info->fb_size[0]);
|
|
drm_printf(p, "\t\tfb_size[1]=%u\n", plane_info->fb_size[1]);
|
|
drm_printf(p, "\t\tpixel_blend=%u\n", plane_info->pixel_blend);
|
|
/*TODO: vframe_s */
|
|
drm_printf(p, "\t\tis_uvm=%u\n", plane_info->is_uvm);
|
|
}
|
|
|
|
static const struct drm_plane_funcs am_osd_plane_funs = {
|
|
.update_plane = drm_atomic_helper_update_plane,
|
|
.disable_plane = drm_atomic_helper_disable_plane,
|
|
.destroy = drm_plane_cleanup,
|
|
.reset = meson_osd_plane_reset,
|
|
.atomic_duplicate_state = meson_plane_duplicate_state,
|
|
.atomic_destroy_state = meson_plane_destroy_state,
|
|
.atomic_set_property = meson_plane_atomic_set_property,
|
|
.atomic_get_property = meson_plane_atomic_get_property,
|
|
.format_mod_supported = am_meson_vpu_check_format_mod,
|
|
.atomic_print_state = meson_osd_plane_atomic_print_state,
|
|
};
|
|
|
|
static const struct drm_plane_funcs am_video_plane_funs = {
|
|
.update_plane = drm_atomic_helper_update_plane,
|
|
.disable_plane = drm_atomic_helper_disable_plane,
|
|
.destroy = drm_plane_cleanup,
|
|
.reset = meson_video_plane_reset,
|
|
.atomic_duplicate_state = meson_video_plane_duplicate_state,
|
|
.atomic_destroy_state = meson_video_plane_destroy_state,
|
|
.atomic_set_property = meson_video_plane_atomic_set_property,
|
|
.atomic_get_property = meson_video_plane_atomic_get_property,
|
|
.format_mod_supported = am_meson_vpu_check_video_format_mod,
|
|
.atomic_print_state = meson_video_plane_atomic_print_state,
|
|
};
|
|
|
|
static int meson_plane_prepare_fb(struct drm_plane *plane,
|
|
struct drm_plane_state *new_state)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static void meson_plane_cleanup_fb(struct drm_plane *plane,
|
|
struct drm_plane_state *old_state)
|
|
{
|
|
//struct am_osd_plane *osd_plane = to_am_osd_plane(plane);
|
|
|
|
//DRM_DEBUG("osd %d.\n", osd_plane->plane_index);
|
|
}
|
|
|
|
static void meson_plane_atomic_update(struct drm_plane *plane,
|
|
struct drm_atomic_state *state)
|
|
{
|
|
struct meson_vpu_osd_layer_info *plane_info;
|
|
struct meson_vpu_sub_pipeline_state *mvps;
|
|
struct am_osd_plane *osd_plane = to_am_osd_plane(plane);
|
|
struct drm_crtc *crtc = NULL;
|
|
struct meson_drm *drv;
|
|
struct drm_private_state *obj_state;
|
|
int crtc_index = 0;
|
|
|
|
if (!plane->state) {
|
|
DRM_INFO("%s state is NULL!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
drv = osd_plane->drv;
|
|
if (!drv || !drv->pipeline) {
|
|
DRM_INFO("%s private state or pipeline is NULL!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
crtc = plane->state->crtc;
|
|
if (crtc)
|
|
crtc_index = crtc->index;
|
|
|
|
obj_state = drv->pipeline->subs[crtc_index]->obj.state;
|
|
if (!obj_state) {
|
|
DRM_ERROR("null pipeline obj state!\n");
|
|
return;
|
|
}
|
|
|
|
mvps = container_of(obj_state, struct meson_vpu_sub_pipeline_state, obj);
|
|
if (!mvps || osd_plane->plane_index >= MESON_MAX_OSDS) {
|
|
DRM_INFO("%s mvps/osd_plane is NULL!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
plane_info = &mvps->plane_info[osd_plane->plane_index];
|
|
if (mvps->more_60) {
|
|
osd_enable[OSD1_SLICE0] = 1;
|
|
osd_enable[OSD3_SLICE1] = 1;
|
|
DRM_DEBUG_DRIVER("mode_60hz case, osd0_status=%d osd2_status=%d\n",
|
|
osd_enable[OSD1_SLICE0], osd_enable[OSD3_SLICE1]);
|
|
return;
|
|
}
|
|
|
|
if (plane_info->enable == 1)
|
|
osd_enable[plane_info->plane_index] = 1;
|
|
else
|
|
osd_enable[plane_info->plane_index] = 0;
|
|
|
|
DRM_DEBUG_DRIVER("plane_index=%d, osd_status=%d\n",
|
|
plane_info->plane_index, osd_enable[plane_info->plane_index]);
|
|
}
|
|
|
|
static void meson_video_plane_atomic_update(struct drm_plane *plane,
|
|
struct drm_atomic_state *old_atomic_state)
|
|
{
|
|
int video_index, crtc_index;
|
|
struct meson_video_sub_pipeline *mvsp;
|
|
struct am_video_plane *video_plane = to_am_video_plane(plane);
|
|
struct drm_crtc *crtc = plane->state->crtc;
|
|
struct am_meson_crtc *amcrtc = to_am_meson_crtc(crtc);
|
|
struct meson_vpu_pipeline *pipeline = amcrtc->priv->pipeline;
|
|
struct drm_plane_state *new_plane_state;
|
|
struct meson_vpu_video *mvv = pipeline->video[video_plane->plane_index];
|
|
|
|
crtc_index = crtc->index;
|
|
video_index = video_plane->plane_index;
|
|
mvsp = &pipeline->video_subs[crtc_index];
|
|
new_plane_state = drm_atomic_get_new_plane_state(old_atomic_state, plane);
|
|
|
|
DRM_DEBUG_DRIVER("video plane atomic_update new_plane_state %p\n", new_plane_state);
|
|
if (new_plane_state && !meson_video_plane_is_repeat_frame(mvv)) {
|
|
meson_video_prepare_fence(plane, new_plane_state, mvv);
|
|
meson_video_prepare_present_fence(plane, new_plane_state, mvv);
|
|
}
|
|
|
|
if (new_plane_state && meson_video_plane_is_repeat_frame(mvv))
|
|
meson_video_prepare_repeat_fence(plane, new_plane_state, mvv);
|
|
|
|
video_pipeline_block_update(mvsp, old_atomic_state, video_index);
|
|
}
|
|
|
|
#if defined(CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION) ||\
|
|
defined(CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_VECM)
|
|
/* -1: invalid osd index
|
|
* 0: osd is disabled
|
|
* 1: osd is enabled
|
|
*/
|
|
int get_osd_status_callback(u32 index)
|
|
{
|
|
if (index < MESON_MAX_OSDS)
|
|
return osd_enable[index];
|
|
else
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
static int meson_plane_atomic_check(struct drm_plane *plane,
|
|
struct drm_atomic_state *atomic_state)
|
|
{
|
|
struct meson_vpu_osd_layer_info *plane_info;
|
|
struct meson_vpu_osd_layer_info *old_plane_info = NULL;
|
|
struct meson_vpu_sub_pipeline_state *mvps, *old_mvps;
|
|
struct am_osd_plane *osd_plane = to_am_osd_plane(plane);
|
|
struct meson_drm *drv = osd_plane->drv;
|
|
struct drm_plane_state *state;
|
|
struct am_meson_plane_state *plane_state;
|
|
u16 blend_mask_val;
|
|
u32 crtc_index = 0;
|
|
int ret;
|
|
|
|
DRM_DEBUG_DRIVER("IN, pid[%s %d], plane_index[%d]\n",
|
|
current->comm, current->pid, osd_plane->plane_index);
|
|
|
|
state = drm_atomic_get_new_plane_state(atomic_state, plane);
|
|
if (!state || !drv) {
|
|
DRM_INFO("%s state/meson_drm is NULL!\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (state->crtc)
|
|
crtc_index = state->crtc->index;
|
|
else if (drv->pipeline->osd_crtc_index[osd_plane->plane_index] != -1)
|
|
crtc_index = drv->pipeline->osd_crtc_index[osd_plane->plane_index];
|
|
|
|
mvps = meson_vpu_pipeline_get_state(drv->pipeline->subs[crtc_index],
|
|
atomic_state);
|
|
if (PTR_ERR(mvps) == -EDEADLK)
|
|
return -EDEADLK;
|
|
|
|
if (!mvps || osd_plane->plane_index >= MESON_MAX_OSDS) {
|
|
DRM_INFO("%s mvps/osd_plane is NULL!\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
plane_info = &mvps->plane_info[osd_plane->plane_index];
|
|
plane_info->plane_index = osd_plane->plane_index;
|
|
plane_info->osd_dimm.dimm_value = osd_plane->osd_dimm.dimm_value;
|
|
plane_info->osd_dimm.dimm_ctrl = osd_plane->osd_dimm.dimm_ctrl;
|
|
/*get plane prop value*/
|
|
plane_info->zorder = state->zpos;
|
|
|
|
blend_mask_val = osd_plane->pixel_blend_debug;
|
|
if ((blend_mask_val & 0xf0) == 0x10) /* forced pixel blend */
|
|
state->pixel_blend_mode = blend_mask_val & 0x0f;
|
|
|
|
plane_info->pixel_blend = state->pixel_blend_mode;
|
|
|
|
plane_info->global_alpha = state->alpha;
|
|
plane_info->scaling_filter = (u32)state->scaling_filter;
|
|
if (osd_plane->receive_palette)
|
|
plane_info->palette_arry = osd_plane->receive_palette;
|
|
|
|
mvps->plane_index[osd_plane->plane_index] = osd_plane->plane_index;
|
|
|
|
meson_plane_position_calc(plane_info, state, mvps->pipeline);
|
|
|
|
old_mvps = meson_vpu_pipeline_get_old_state(drv->pipeline->subs[crtc_index],
|
|
state->state);
|
|
if (old_mvps) {
|
|
old_plane_info = &old_mvps->plane_info[osd_plane->plane_index];
|
|
plane_info->status_changed =
|
|
plane_info->enable != old_plane_info->enable;
|
|
} else {
|
|
DRM_DEBUG_DRIVER("old_mvps is NULL\n");
|
|
plane_info->status_changed = 1;
|
|
}
|
|
|
|
ret = meson_plane_fb_check(plane, state, plane_info);
|
|
if (ret < 0) {
|
|
plane_info->enable = 0;
|
|
DRM_DEBUG_DRIVER("plane%d fb is NULL,disable the plane!\n",
|
|
plane_info->plane_index);
|
|
return 0;
|
|
}
|
|
ret = meson_plane_get_fb_info(plane, state, plane_info);
|
|
if (ret < 0 ||
|
|
plane_info->src_w > MESON_OSD_INPUT_W_LIMIT || plane_info->src_w == 0) {
|
|
plane_info->enable = 0;
|
|
DRM_DEBUG_DRIVER("fb is invalid, disable plane, src_w=%d, ret=%d\n",
|
|
plane_info->src_w, ret);
|
|
return ret;
|
|
}
|
|
|
|
if (old_plane_info) {
|
|
if (plane_info->pixel_format != old_plane_info->pixel_format) {
|
|
DRM_DEBUG_DRIVER("pixel format changed [0x%x -> 0x%x].\n",
|
|
old_plane_info->pixel_format, plane_info->pixel_format);
|
|
}
|
|
}
|
|
|
|
plane_info->enable = 1;
|
|
if (osd_plane->osd_permanent_blank) {
|
|
plane_info->enable = 0;
|
|
DRM_INFO("osd-%d is forcibly disabled by debug node.\n", osd_plane->plane_index);
|
|
}
|
|
|
|
plane_info->crtc_index = crtc_index;
|
|
drv->pipeline->osd_crtc_index[osd_plane->plane_index] = crtc_index;
|
|
plane_state = to_am_meson_plane_state(state);
|
|
plane_info->sec_en = plane_state->sec_en;
|
|
|
|
MESON_DRM_STATE("osd%d (\"%s\" pid=%d]) state(0x%p)\n"
|
|
"mvps:0x%p phy:0x%llx src[%d %d %d %d] dst[%d %d %d %d]\n",
|
|
plane_info->plane_index, current->comm, task_pid_nr(current),
|
|
atomic_state, mvps, plane_info->phy_addr,
|
|
plane_info->src_x, plane_info->src_y, plane_info->src_w, plane_info->src_h,
|
|
plane_info->dst_x, plane_info->dst_y, plane_info->dst_w, plane_info->dst_h);
|
|
|
|
DRM_DEBUG_DRIVER("OSD PLANE index=%d, zorder=%d, premult= %d, alpha = %d, phy = %llx\n",
|
|
plane_info->plane_index, plane_info->zorder,
|
|
state->pixel_blend_mode, plane_info->global_alpha,
|
|
plane_info->phy_addr);
|
|
DRM_DEBUG_DRIVER("w/h = %d/%d, src_x/y/w/h=%d/%d/%d/%d, dimm=[0x%x,%d]\n",
|
|
plane_info->fb_w, plane_info->fb_h,
|
|
plane_info->src_x, plane_info->src_y,
|
|
plane_info->src_w, plane_info->src_h,
|
|
plane_info->osd_dimm.dimm_value, plane_info->osd_dimm.dimm_ctrl);
|
|
DRM_DEBUG_DRIVER("status_changed = %d, dst_x/y/w/h=%d/%d/%d/%d\n",
|
|
plane_info->status_changed, plane_info->dst_x, plane_info->dst_y,
|
|
plane_info->dst_w, plane_info->dst_h);
|
|
return 0;
|
|
}
|
|
|
|
static int meson_video_plane_atomic_check(struct drm_plane *plane,
|
|
struct drm_atomic_state *atomic_state)
|
|
{
|
|
struct meson_video_sub_pipeline *mvsp;
|
|
struct meson_vpu_video_layer_info *plane_info, *old_plane_info;
|
|
struct meson_video_sub_pipeline_state *mvps, *old_mvps;
|
|
struct am_video_plane *video_plane = to_am_video_plane(plane);
|
|
struct meson_drm *drv = video_plane->drv;
|
|
struct drm_plane_state *state;
|
|
struct am_meson_video_plane_state *plane_state;
|
|
int ret, crtc_index;
|
|
|
|
state = drm_atomic_get_new_plane_state(atomic_state, plane);
|
|
if (!state || !drv) {
|
|
DRM_INFO("%s state/meson_drm is NULL!\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (state->crtc)
|
|
crtc_index = state->crtc->index;
|
|
else if (drv->pipeline->video_crtc_index[video_plane->plane_index] != -1)
|
|
crtc_index = drv->pipeline->video_crtc_index[video_plane->plane_index];
|
|
else
|
|
crtc_index = 0;
|
|
|
|
mvsp = &drv->pipeline->video_subs[crtc_index];
|
|
mvps = meson_video_pipeline_get_state(mvsp, atomic_state);
|
|
if (PTR_ERR(mvps) == -EDEADLK) {
|
|
DRM_DEBUG_DRIVER("mvps is error!\n");
|
|
return -EDEADLK;
|
|
}
|
|
|
|
if (!mvps || video_plane->plane_index >= MESON_MAX_VIDEO) {
|
|
DRM_INFO("%s mvps/video_plane is NULL!\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
DRM_DEBUG_DRIVER("IN, pid[%s %d], plane_index[%d], crtc_index[%d]\n",
|
|
current->comm, current->pid,
|
|
video_plane->plane_index, crtc_index);
|
|
|
|
plane_info = &mvps->video_plane_info[video_plane->plane_index];
|
|
plane_info->plane_index = video_plane->plane_index;
|
|
plane_info->zorder = state->zpos;
|
|
plane_info->rotation = state->rotation;
|
|
|
|
plane_state = to_am_meson_video_plane_state(state);
|
|
plane_info->signal_fmt = plane_state->signal_fmt;
|
|
plane_info->frame_flag = plane_state->frame_flag;
|
|
plane_info->in_fence = plane_state->async_in_fence;
|
|
|
|
mvps->video_plane_index[video_plane->plane_index] = video_plane->plane_index;
|
|
ret = meson_video_plane_fb_check(plane, state, plane_info);
|
|
if (ret < 0) {
|
|
plane_info->enable = 0;
|
|
plane_info->dmabuf[0] = NULL;
|
|
plane_info->dmabuf[1] = NULL;
|
|
video_pipeline_block_check(mvsp, atomic_state, video_plane->plane_index);
|
|
DRM_DEBUG_DRIVER("plane%d fb is NULL,disable the plane!\n",
|
|
plane_info->plane_index);
|
|
return 0;
|
|
}
|
|
meson_video_plane_position_calc(plane_info, state,
|
|
drv->pipeline);
|
|
|
|
old_mvps = meson_video_pipeline_get_old_state(mvsp, atomic_state);
|
|
if (old_mvps) {
|
|
old_plane_info = &old_mvps->video_plane_info[video_plane->plane_index];
|
|
if (plane_info->src_w != old_plane_info->src_w ||
|
|
plane_info->src_h != old_plane_info->src_h ||
|
|
plane_info->dst_x != old_plane_info->dst_x ||
|
|
plane_info->dst_y != old_plane_info->dst_y ||
|
|
plane_info->dst_w != old_plane_info->dst_w ||
|
|
plane_info->dst_h != old_plane_info->dst_h ||
|
|
plane_info->zorder != old_plane_info->zorder ||
|
|
!plane_info->enable) {
|
|
DRM_DEBUG_DRIVER("old:src(%dx%d)dst(%d,%d)(%dx%d), zorder=%d\n",
|
|
old_plane_info->src_w, old_plane_info->src_h,
|
|
old_plane_info->dst_x, old_plane_info->dst_y,
|
|
old_plane_info->dst_w, old_plane_info->dst_h,
|
|
old_plane_info->zorder);
|
|
DRM_DEBUG_DRIVER("new:src(%dx%d)dst(%d,%d)(%dx%d), zorder=%d, enable=%d\n",
|
|
plane_info->src_w, plane_info->src_h,
|
|
plane_info->dst_x, plane_info->dst_y,
|
|
plane_info->dst_w, plane_info->dst_h,
|
|
plane_info->zorder, plane_info->enable);
|
|
plane_info->status_changed = 1;
|
|
} else {
|
|
plane_info->status_changed = 0;
|
|
}
|
|
} else {
|
|
DRM_DEBUG_DRIVER("old_mvps is NULL\n");
|
|
plane_info->status_changed = 1;
|
|
}
|
|
ret = meson_video_plane_get_fb_info(plane, state, plane_info);
|
|
if (ret < 0 || plane_info->src_w == 0) {
|
|
DRM_DEBUG_DRIVER("fb is invalid, disable plane, src_w=%d, ret=%d\n",
|
|
plane_info->src_w, ret);
|
|
plane_info->enable = 0;
|
|
video_pipeline_block_check(mvsp, atomic_state, video_plane->plane_index);
|
|
return ret;
|
|
}
|
|
|
|
plane_info->crtc_index = crtc_index;
|
|
drv->pipeline->video_crtc_index[video_plane->plane_index] = crtc_index;
|
|
plane_info->enable = 1;
|
|
|
|
video_pipeline_block_check(mvsp, atomic_state, video_plane->plane_index);
|
|
|
|
MESON_DRM_STATE("video%d (\"%s\" pid=%d]) state:0x%p\n"
|
|
"mvps:0x%p dmabuf:0x%px src[%d %d %d %d] dst[%d %d %d %d]\n",
|
|
plane_info->plane_index, current->comm, task_pid_nr(current),
|
|
atomic_state, mvps, plane_info->dmabuf[0],
|
|
plane_info->src_x, plane_info->src_y, plane_info->src_w, plane_info->src_h,
|
|
plane_info->dst_x, plane_info->dst_y, plane_info->dst_w, plane_info->dst_h);
|
|
|
|
DRM_DEBUG_DRIVER("VIDEO PLANE index=%d, zorder=%d\n",
|
|
plane_info->plane_index, plane_info->zorder);
|
|
DRM_DEBUG_DRIVER("src_x/y/w/h=%d/%d/%d/%d\n",
|
|
plane_info->src_x, plane_info->src_y,
|
|
plane_info->src_w, plane_info->src_h);
|
|
DRM_DEBUG_DRIVER("status_changed = %d, dst_x/y/w/h=%d/%d/%d/%d\n",
|
|
plane_info->status_changed, plane_info->dst_x, plane_info->dst_y,
|
|
plane_info->dst_w, plane_info->dst_h);
|
|
return 0;
|
|
}
|
|
|
|
static void meson_plane_atomic_disable(struct drm_plane *plane,
|
|
struct drm_atomic_state *old_state)
|
|
{
|
|
struct meson_vpu_osd_layer_info *plane_info;
|
|
struct meson_vpu_sub_pipeline_state *mvps;
|
|
struct am_osd_plane *osd_plane = to_am_osd_plane(plane);
|
|
struct meson_drm *drv;
|
|
struct drm_private_state *obj_state;
|
|
struct drm_plane_state *old_plane_state;
|
|
|
|
if (!plane->state) {
|
|
DRM_INFO("%s state is NULL!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
old_plane_state = drm_atomic_get_old_plane_state(old_state, plane);
|
|
if (!old_plane_state) {
|
|
DRM_INFO("%s old plane state is NULL!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
drv = osd_plane->drv;
|
|
if (!drv || !drv->pipeline) {
|
|
DRM_INFO("%s private state or pipeline is NULL!\n", __func__);
|
|
return;
|
|
}
|
|
|
|
obj_state = drv->pipeline->subs[old_plane_state->crtc->index]->obj.state;
|
|
if (!obj_state) {
|
|
DRM_ERROR("null pipeline obj state!\n");
|
|
return;
|
|
}
|
|
|
|
mvps = container_of(obj_state, struct meson_vpu_sub_pipeline_state, obj);
|
|
if (!mvps || osd_plane->plane_index >= MESON_MAX_OSDS) {
|
|
DRM_INFO("%s mvps/osd_plane is NULL!\n", __func__);
|
|
return;
|
|
}
|
|
plane_info = &mvps->plane_info[osd_plane->plane_index];
|
|
osd_enable[plane_info->plane_index] = 0;
|
|
if (mvps->more_60 && plane_info->plane_index == OSD1_SLICE0) {
|
|
osd_enable[OSD1_SLICE0] = 0;
|
|
osd_enable[OSD3_SLICE1] = 0;
|
|
DRM_DEBUG_DRIVER("mode_60hz case, osd0_status=%d osd2_status=%d\n",
|
|
osd_enable[OSD1_SLICE0], osd_enable[OSD3_SLICE1]);
|
|
}
|
|
|
|
DRM_DEBUG_DRIVER("plane_index=%d, osd_status=%d\n",
|
|
plane_info->plane_index, osd_enable[plane_info->plane_index]);
|
|
}
|
|
|
|
static void meson_video_plane_atomic_disable(struct drm_plane *plane,
|
|
struct drm_atomic_state *old_atomic_state)
|
|
{
|
|
int video_index, crtc_index;
|
|
struct meson_video_sub_pipeline *sub_pipe;
|
|
struct am_video_plane *video_plane = to_am_video_plane(plane);
|
|
struct meson_vpu_pipeline *pipeline = video_plane->pipeline;
|
|
unsigned long pos_crtcs = plane->possible_crtcs;
|
|
|
|
crtc_index = find_first_bit(&pos_crtcs, 32);
|
|
if (crtc_index >= MESON_MAX_CRTC)
|
|
crtc_index = 0;
|
|
|
|
video_index = video_plane->plane_index;
|
|
sub_pipe = &pipeline->video_subs[crtc_index];
|
|
DRM_DEBUG_DRIVER("video %d, crtc %d.\n", video_index, crtc_index);
|
|
video_pipeline_block_update(sub_pipe, old_atomic_state, video_index);
|
|
}
|
|
|
|
/*add async check & atomic funs*/
|
|
int meson_osd_plane_async_check(struct drm_plane *plane,
|
|
struct drm_atomic_state *atomic_state)
|
|
{
|
|
int ret = 0;
|
|
struct meson_vpu_sub_pipeline_state *mvps;
|
|
struct am_osd_plane *osd_plane = to_am_osd_plane(plane);
|
|
struct meson_drm *drv = osd_plane->drv;
|
|
struct meson_vpu_osd_layer_info *plane_info;
|
|
struct drm_plane_state *new_state;
|
|
|
|
DRM_DEBUG_DRIVER("plane_index-%d\n", osd_plane->plane_index);
|
|
|
|
new_state = drm_atomic_get_new_plane_state(atomic_state, plane);
|
|
if (!new_state) {
|
|
DRM_ERROR("atomic state is NULL!\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
mvps = meson_vpu_pipeline_get_state(drv->pipeline->subs[new_state->crtc->index],
|
|
atomic_state);
|
|
if (PTR_ERR(mvps) == -EDEADLK)
|
|
return -EDEADLK;
|
|
|
|
if (!mvps) {
|
|
DRM_ERROR("mvps is NULL.\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
plane_info = &mvps->plane_info[osd_plane->plane_index];
|
|
if ((plane_info->enable && !new_state->fb) || !plane_info->enable) {
|
|
DRM_ERROR("osd plane visible state changed, enable=%d,fb=%p\n",
|
|
plane_info->enable, new_state->fb);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (plane_info->status_changed) {
|
|
DRM_DEBUG("osd%d plane info changed\n", osd_plane->plane_index);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int meson_video_plane_async_check(struct drm_plane *plane,
|
|
struct drm_atomic_state *atomic_state)
|
|
{
|
|
int crtc_index;
|
|
struct meson_vpu_video_layer_info *plane_info;
|
|
struct meson_video_sub_pipeline *mvsp;
|
|
struct meson_video_sub_pipeline_state *mvps;
|
|
struct drm_plane_state *new_state;
|
|
struct am_video_plane *video_plane = to_am_video_plane(plane);
|
|
struct meson_drm *drv = video_plane->drv;
|
|
|
|
DRM_DEBUG_DRIVER("plane_index-%d\n", video_plane->plane_index);
|
|
|
|
new_state = drm_atomic_get_new_plane_state(atomic_state, plane);
|
|
if (!new_state) {
|
|
DRM_ERROR("atomic state is NULL!\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (new_state->crtc)
|
|
crtc_index = new_state->crtc->index;
|
|
else
|
|
crtc_index = 0;
|
|
|
|
mvsp = &drv->pipeline->video_subs[crtc_index];
|
|
mvps = meson_video_pipeline_get_state(mvsp, atomic_state);
|
|
if (PTR_ERR(mvps) == -EDEADLK)
|
|
return -EDEADLK;
|
|
|
|
if (!mvps) {
|
|
DRM_ERROR("mvps is NULL.\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
plane_info = &mvps->video_plane_info[video_plane->plane_index];
|
|
if ((plane_info->enable && !new_state->fb) || !plane_info->enable) {
|
|
DRM_ERROR("vide plane visible state changed, enable=%d,fb=%p\n",
|
|
plane_info->enable, new_state->fb);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void meson_osd_plane_async_update(struct drm_plane *plane,
|
|
struct drm_atomic_state *state)
|
|
{
|
|
struct am_osd_plane *osd_plane = to_am_osd_plane(plane);
|
|
struct drm_plane_state *old_plane_state;
|
|
struct drm_plane_state *new_state;
|
|
struct meson_vpu_sub_pipeline *sub_pipe;
|
|
struct am_meson_crtc *amcrtc;
|
|
struct meson_vpu_pipeline *pipeline;
|
|
struct drm_private_obj *obj;
|
|
struct meson_vpu_sub_pipeline_state *cur_sps, *new_sps;
|
|
int i, crtc_index;
|
|
struct drm_private_state *new_obj_state;
|
|
|
|
old_plane_state = drm_atomic_get_old_plane_state(state, plane);
|
|
if (!old_plane_state) {
|
|
DRM_ERROR("plane state is null.\n");
|
|
return;
|
|
}
|
|
|
|
new_state = drm_atomic_get_new_plane_state(state, plane);
|
|
if (!new_state || !new_state->state) {
|
|
DRM_ERROR("atomic state is NULL![%p]\n", new_state);
|
|
return;
|
|
}
|
|
|
|
amcrtc = to_am_meson_crtc(new_state->crtc);
|
|
pipeline = amcrtc->pipeline;
|
|
crtc_index = amcrtc->crtc_index;
|
|
sub_pipe = pipeline->subs[crtc_index];
|
|
|
|
DRM_DEBUG_DRIVER("plane_index-%d, crtc_index=%d, fb=%p, src=%dx%d, dst=%dx%d\n",
|
|
osd_plane->plane_index, crtc_index, new_state->fb,
|
|
new_state->src_x, new_state->src_y,
|
|
new_state->crtc_x, new_state->crtc_y);
|
|
|
|
do {
|
|
struct drm_connector *connector;
|
|
struct drm_connector_state *old_conn_state;
|
|
struct drm_crtc *crtc;
|
|
struct drm_crtc_state *old_crtc_state;
|
|
struct drm_plane *plane;
|
|
struct drm_plane_state *old_plane_state;
|
|
struct drm_crtc_commit *commit;
|
|
int ret;
|
|
|
|
for_each_old_crtc_in_state(state, crtc, old_crtc_state, i) {
|
|
commit = old_crtc_state->commit;
|
|
|
|
if (!commit)
|
|
continue;
|
|
|
|
ret = wait_for_completion_interruptible(&commit->hw_done);
|
|
if (ret)
|
|
DRM_ERROR("crtc timeout!");
|
|
}
|
|
|
|
for_each_old_connector_in_state(state, connector, old_conn_state, i) {
|
|
commit = old_conn_state->commit;
|
|
|
|
if (!commit)
|
|
continue;
|
|
|
|
ret = wait_for_completion_interruptible(&commit->hw_done);
|
|
if (ret)
|
|
DRM_ERROR("connector timeout!");
|
|
}
|
|
|
|
for_each_old_plane_in_state(state, plane, old_plane_state, i) {
|
|
commit = old_plane_state->commit;
|
|
|
|
if (!commit)
|
|
continue;
|
|
|
|
ret = wait_for_completion_interruptible(&commit->hw_done);
|
|
if (ret)
|
|
DRM_ERROR("plane timeout!");
|
|
}
|
|
} while (0);
|
|
|
|
meson_commit_reenter_inc(pipeline->priv, crtc_index, ASYNC_MODE);
|
|
|
|
plane->state->src_x = new_state->src_x;
|
|
plane->state->src_y = new_state->src_y;
|
|
plane->state->src_w = new_state->src_w;
|
|
plane->state->src_h = new_state->src_h;
|
|
plane->state->crtc_x = new_state->crtc_x;
|
|
plane->state->crtc_y = new_state->crtc_y;
|
|
plane->state->crtc_w = new_state->crtc_w;
|
|
plane->state->crtc_h = new_state->crtc_h;
|
|
plane->state->zpos = new_state->zpos;
|
|
swap(plane->state->fb, new_state->fb);
|
|
for_each_new_private_obj_in_state(state, obj, new_obj_state, i) {
|
|
if (obj != &sub_pipe->obj)
|
|
continue;
|
|
new_sps = priv_to_sub_pipeline_state(new_obj_state);
|
|
cur_sps = priv_to_sub_pipeline_state(obj->state);
|
|
cur_sps->plane_info[osd_plane->plane_index] =
|
|
new_sps->plane_info[osd_plane->plane_index];
|
|
}
|
|
|
|
/*
|
|
* C5 does not have a scanout pos register, so there is
|
|
* no need to determine when a register is written.
|
|
*/
|
|
if (amcrtc->pipeline->priv->vpu_data->enc_method != ENC_METHOD_NULL)
|
|
vpu_pipeline_prepare_update(pipeline, new_state->crtc->mode.vdisplay,
|
|
drm_mode_vrefresh(&new_state->crtc->mode), crtc_index);
|
|
|
|
if (vpu_pipeline_osd_update(sub_pipe, state))
|
|
goto out;
|
|
|
|
vpu_pipeline_finish_update(pipeline, crtc_index);
|
|
|
|
out:
|
|
meson_commit_reenter_dec(pipeline->priv, crtc_index, ASYNC_MODE);
|
|
}
|
|
|
|
void meson_video_plane_async_update(struct drm_plane *plane,
|
|
struct drm_atomic_state *state)
|
|
{
|
|
struct am_video_plane *video_plane = to_am_video_plane(plane);
|
|
struct meson_video_sub_pipeline *sub_pipe;
|
|
struct am_meson_crtc *amcrtc = NULL;
|
|
struct meson_vpu_pipeline *pipeline = video_plane->pipeline;
|
|
struct meson_vpu_video *mvv;
|
|
int crtc_index = 0;
|
|
struct drm_plane_state *old_plane_state;
|
|
struct drm_plane_state *new_state;
|
|
int i;
|
|
struct drm_private_obj *obj;
|
|
struct drm_private_state *old_obj_state, *new_obj_state;
|
|
unsigned long flags;
|
|
struct drm_crtc *crtc;
|
|
struct drm_crtc_state *crtc_state;
|
|
|
|
old_plane_state = drm_atomic_get_old_plane_state(state, plane);
|
|
if (!old_plane_state) {
|
|
DRM_ERROR("plane state is null.\n");
|
|
return;
|
|
}
|
|
|
|
new_state = drm_atomic_get_new_plane_state(state, plane);
|
|
if (!new_state || !new_state->state) {
|
|
DRM_ERROR("atomic state is NULL![%p %p]\n", new_state, new_state->state);
|
|
return;
|
|
}
|
|
|
|
DRM_DEBUG_DRIVER("plane_index-%d, crtc-%p\n",
|
|
video_plane->plane_index, new_state->crtc);
|
|
if (new_state->crtc) {
|
|
amcrtc = to_am_meson_crtc(new_state->crtc);
|
|
crtc_index = amcrtc->crtc_index;
|
|
}
|
|
|
|
sub_pipe = &pipeline->video_subs[crtc_index];
|
|
mvv = pipeline->video[video_plane->plane_index];
|
|
|
|
DRM_DEBUG_DRIVER("plane_index=%d,crtc=%p,crtc_index=%d,fb=%p,src=%dx%d,dst=%dx%d\n",
|
|
video_plane->plane_index, new_state->crtc,
|
|
crtc_index, new_state->fb,
|
|
new_state->src_x, new_state->src_y,
|
|
new_state->crtc_x, new_state->crtc_y);
|
|
plane->state->src_x = new_state->src_x;
|
|
plane->state->src_y = new_state->src_y;
|
|
plane->state->src_w = new_state->src_w;
|
|
plane->state->src_h = new_state->src_h;
|
|
plane->state->crtc_x = new_state->crtc_x;
|
|
plane->state->crtc_y = new_state->crtc_y;
|
|
plane->state->crtc_w = new_state->crtc_w;
|
|
plane->state->crtc_h = new_state->crtc_h;
|
|
plane->state->zpos = new_state->zpos;
|
|
swap(plane->state->fb, new_state->fb);
|
|
|
|
for_each_oldnew_private_obj_in_state(state, obj, old_obj_state, new_obj_state, i) {
|
|
if (obj != &sub_pipe->obj && obj != &mvv->base.obj)
|
|
continue;
|
|
|
|
old_obj_state->state = state;
|
|
new_obj_state->state = NULL;
|
|
|
|
state->private_objs[i].state = old_obj_state;
|
|
obj->state = new_obj_state;
|
|
}
|
|
|
|
if (new_state && !meson_video_plane_is_repeat_frame(mvv)) {
|
|
meson_video_prepare_fence(plane, new_state, mvv);
|
|
meson_video_prepare_present_fence(plane, new_state, mvv);
|
|
}
|
|
|
|
if (new_state && meson_video_plane_is_repeat_frame(mvv))
|
|
meson_video_prepare_repeat_fence(plane, new_state, mvv);
|
|
|
|
video_pipeline_block_update(sub_pipe, new_state->state, video_plane->plane_index);
|
|
|
|
for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
|
|
spin_lock_irqsave(&crtc->dev->event_lock, flags);
|
|
DRM_DEBUG_VBL("add event to list, event=%p, crct=%d!\n",
|
|
crtc_state->event, drm_crtc_vblank_get(crtc));
|
|
if (crtc_state->event) {
|
|
if (drm_crtc_vblank_get(crtc) == 0)
|
|
drm_crtc_arm_vblank_event(crtc, crtc_state->event);
|
|
else if (amcrtc)
|
|
amcrtc->event = crtc_state->event;
|
|
|
|
crtc_state->event = NULL;
|
|
}
|
|
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
|
|
}
|
|
}
|
|
|
|
static const struct drm_plane_helper_funcs am_osd_helper_funcs = {
|
|
.prepare_fb = meson_plane_prepare_fb,
|
|
.cleanup_fb = meson_plane_cleanup_fb,
|
|
.atomic_update = meson_plane_atomic_update,
|
|
.atomic_check = meson_plane_atomic_check,
|
|
.atomic_disable = meson_plane_atomic_disable,
|
|
.atomic_async_check = meson_osd_plane_async_check,
|
|
.atomic_async_update = meson_osd_plane_async_update,
|
|
};
|
|
|
|
static const struct drm_plane_helper_funcs am_video_helper_funcs = {
|
|
.prepare_fb = meson_plane_prepare_fb,
|
|
.cleanup_fb = meson_plane_cleanup_fb,
|
|
.atomic_update = meson_video_plane_atomic_update,
|
|
.atomic_check = meson_video_plane_atomic_check,
|
|
.atomic_disable = meson_video_plane_atomic_disable,
|
|
.atomic_async_check = meson_video_plane_async_check,
|
|
.atomic_async_update = meson_video_plane_async_update,
|
|
};
|
|
|
|
static void meson_plane_create_security_en_property(struct drm_device *drm_dev,
|
|
struct am_osd_plane *osd_plane)
|
|
{
|
|
struct drm_property *prop;
|
|
|
|
prop = drm_property_create_bool(drm_dev, 0, "SEC_EN");
|
|
if (prop) {
|
|
osd_plane->prop_sec_en = prop;
|
|
drm_object_attach_property(&osd_plane->base.base, prop, 0);
|
|
} else {
|
|
DRM_ERROR("Failed to SEC_EN property\n");
|
|
}
|
|
}
|
|
|
|
struct drm_property *
|
|
meson_create_scaling_filter_prop(struct drm_device *dev,
|
|
unsigned int supported_filters)
|
|
{
|
|
struct drm_property *prop;
|
|
static const struct drm_prop_enum_list props[] = {
|
|
{ DRM_SCALING_FILTER_DEFAULT, "Default" },
|
|
{ DRM_SCALING_FILTER_NEAREST_NEIGHBOR, "Nearest Neighbor" },
|
|
{ DRM_SCALING_FILTER_BICUBIC_SHARP, "Bicubic_Sharp" },
|
|
{ DRM_SCALING_FILTER_BICUBIC, "Bicubic" },
|
|
{ DRM_SCALING_FILTER_BILINEAR, "Bilinear" },
|
|
{ DRM_SCALING_FILTER_2POINT_BILINEAR, "2Point_Bilinear" },
|
|
{ DRM_SCALING_FILTER_3POINT_TRIANGLE_SHARP, "3Point_Triangle_Sharp" },
|
|
{ DRM_SCALING_FILTER_3POINT_TRIANGLE, "3Point_Triangle" },
|
|
{ DRM_SCALING_FILTER_4POINT_TRIANGLE, "4Point_Triangle" },
|
|
{ DRM_SCALING_FILTER_4POINT_BSPLINE, "4Point_BSPline" },
|
|
{ DRM_SCALING_FILTER_3POINT_BSPLINE, "3Point_BSPline" },
|
|
{ DRM_SCALING_FILTER_REPEATE, "Repeate" },
|
|
};
|
|
unsigned int valid_mode_mask = BIT(DRM_SCALING_FILTER_DEFAULT) |
|
|
BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR) |
|
|
BIT(DRM_SCALING_FILTER_BICUBIC_SHARP) |
|
|
BIT(DRM_SCALING_FILTER_BICUBIC) |
|
|
BIT(DRM_SCALING_FILTER_BILINEAR) |
|
|
BIT(DRM_SCALING_FILTER_2POINT_BILINEAR) |
|
|
BIT(DRM_SCALING_FILTER_3POINT_TRIANGLE_SHARP) |
|
|
BIT(DRM_SCALING_FILTER_3POINT_TRIANGLE) |
|
|
BIT(DRM_SCALING_FILTER_4POINT_TRIANGLE) |
|
|
BIT(DRM_SCALING_FILTER_4POINT_BSPLINE) |
|
|
BIT(DRM_SCALING_FILTER_3POINT_BSPLINE) |
|
|
BIT(DRM_SCALING_FILTER_REPEATE);
|
|
|
|
int i;
|
|
|
|
if (WARN_ON((supported_filters & ~valid_mode_mask) ||
|
|
((supported_filters & BIT(DRM_SCALING_FILTER_DEFAULT)) == 0)))
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
|
|
"SCALING_FILTER",
|
|
hweight32(supported_filters));
|
|
if (!prop)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(props); i++) {
|
|
int ret;
|
|
|
|
if (!(BIT(props[i].type) & supported_filters))
|
|
continue;
|
|
|
|
ret = drm_property_add_enum(prop, props[i].type,
|
|
props[i].name);
|
|
|
|
if (ret) {
|
|
drm_property_destroy(dev, prop);
|
|
|
|
return ERR_PTR(ret);
|
|
}
|
|
}
|
|
|
|
return prop;
|
|
}
|
|
|
|
int meson_plane_create_scaling_filter_property(struct drm_plane *plane,
|
|
unsigned int supported_filters)
|
|
{
|
|
struct drm_property *prop =
|
|
meson_create_scaling_filter_prop(plane->dev, supported_filters);
|
|
|
|
if (IS_ERR(prop))
|
|
return PTR_ERR(prop);
|
|
|
|
drm_object_attach_property(&plane->base, prop,
|
|
DRM_SCALING_FILTER_DEFAULT);
|
|
plane->scaling_filter_property = prop;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void meson_plane_add_occupied_property(struct drm_device *drm_dev,
|
|
struct am_osd_plane *osd_plane)
|
|
{
|
|
struct drm_property *prop;
|
|
|
|
prop = drm_property_create_bool(drm_dev, 0, "meson.plane.occupied");
|
|
if (prop) {
|
|
osd_plane->occupied_property = prop;
|
|
drm_object_attach_property(&osd_plane->base.base, prop, 0);
|
|
} else {
|
|
DRM_ERROR("Failed to occupied property\n");
|
|
}
|
|
}
|
|
|
|
static void meson_plane_add_palette_property(struct drm_device *drm_dev,
|
|
struct am_osd_plane *osd_plane)
|
|
{
|
|
struct drm_property *prop;
|
|
|
|
prop = drm_property_create(drm_dev, DRM_MODE_PROP_BLOB, "palette", 1);
|
|
if (prop) {
|
|
osd_plane->palette = prop;
|
|
drm_object_attach_property(&osd_plane->base.base, prop, 12);
|
|
} else {
|
|
DRM_ERROR("Failed to palette property\n");
|
|
}
|
|
}
|
|
|
|
static void meson_plane_add_unsupport_nonafbc_property(struct drm_device *drm_dev,
|
|
struct am_osd_plane *osd_plane)
|
|
{
|
|
struct drm_property *prop;
|
|
|
|
prop = drm_property_create_bool(drm_dev, 0, "unsupport_nonafbc");
|
|
if (prop) {
|
|
osd_plane->unsupport_nonafbc = prop;
|
|
drm_object_attach_property(&osd_plane->base.base, prop, 0);
|
|
} else {
|
|
DRM_ERROR("Failed to add unsupport_nonafbc property\n");
|
|
}
|
|
}
|
|
|
|
static const u32 meson_plane_fb_size_list[] = {
|
|
1080 << 16 | 1920,
|
|
2160 << 16 | 3840,
|
|
};
|
|
|
|
static void meson_plane_add_max_fb_property(struct drm_device *drm_dev,
|
|
struct am_osd_plane *osd_plane)
|
|
{
|
|
int ret;
|
|
u32 size_index = 0, max_fb_size;
|
|
struct drm_property *prop;
|
|
|
|
ret = of_property_read_u32(drm_dev->dev->of_node, "max_fb_size", &size_index);
|
|
|
|
if (ret)
|
|
max_fb_size = meson_plane_fb_size_list[0];
|
|
else
|
|
max_fb_size = meson_plane_fb_size_list[size_index];
|
|
|
|
prop = drm_property_create_range(drm_dev, DRM_MODE_PROP_IMMUTABLE,
|
|
"max_fb_size", 0, UINT_MAX);
|
|
if (prop) {
|
|
osd_plane->max_fb_property = prop;
|
|
drm_object_attach_property(&osd_plane->base.base, prop, max_fb_size);
|
|
} else {
|
|
DRM_ERROR("Failed to create max_fb property\n");
|
|
}
|
|
}
|
|
|
|
static void meson_plane_add_osd_capability_property(struct drm_device *drm_dev,
|
|
struct am_osd_plane *osd_plane)
|
|
{
|
|
struct drm_property *prop;
|
|
|
|
prop = drm_property_create_range(drm_dev, 0,
|
|
"osd_capability", 0, UINT_MAX);
|
|
if (prop) {
|
|
osd_plane->osd_capability_property = prop;
|
|
drm_object_attach_property(&osd_plane->base.base, prop, 0);
|
|
} else {
|
|
DRM_ERROR("Failed to create osd_capability property\n");
|
|
}
|
|
}
|
|
|
|
static const struct drm_prop_enum_list osd_rotation_reflect_list[] = {
|
|
{ DRM_MODE_ROTATE_0, "reflect-0" },
|
|
{ DRM_MODE_REFLECT_X, "reflect-x" },
|
|
{ DRM_MODE_REFLECT_Y, "reflect-y" },
|
|
{ DRM_MODE_REFLECT_MASK, "reflect-all" },
|
|
};
|
|
|
|
static void meson_plane_add_rotation_reflect_property(struct drm_device *drm_dev,
|
|
struct am_osd_plane *osd_plane)
|
|
{
|
|
struct drm_property *prop;
|
|
|
|
prop = drm_property_create_enum(drm_dev, 0, "rotation_reflect",
|
|
osd_rotation_reflect_list,
|
|
ARRAY_SIZE(osd_rotation_reflect_list));
|
|
if (prop) {
|
|
osd_plane->rotation_reflect_property = prop;
|
|
drm_object_attach_property(&osd_plane->base.base, prop, DRM_MODE_ROTATE_0);
|
|
} else {
|
|
DRM_ERROR("Failed to create rotation reflect property\n");
|
|
}
|
|
}
|
|
|
|
static void meson_video_create_video_cap_property(struct drm_device *drm_dev,
|
|
struct am_video_plane *video_plane)
|
|
{
|
|
struct drm_property *prop;
|
|
|
|
prop = drm_property_create_range(drm_dev, 0,
|
|
"video_cap", 0, 0);
|
|
if (prop) {
|
|
video_plane->video_cap_property = prop;
|
|
drm_object_attach_property(&video_plane->base.base, prop, 0);
|
|
} else {
|
|
DRM_ERROR("Failed to create video_cap property\n");
|
|
}
|
|
}
|
|
|
|
static void meson_video_create_video_src_min_size_property(struct drm_device *drm_dev,
|
|
struct am_video_plane *video_plane)
|
|
{
|
|
struct drm_property *prop;
|
|
|
|
prop = drm_property_create_range(drm_dev, 0,
|
|
"video_min_size", 0, 0);
|
|
if (prop) {
|
|
video_plane->video_src_min_size_property = prop;
|
|
drm_object_attach_property(&video_plane->base.base, prop, 0);
|
|
} else {
|
|
DRM_ERROR("Failed to create video_min_size property\n");
|
|
}
|
|
}
|
|
|
|
static void meson_video_create_video_src_max_size_property(struct drm_device *drm_dev,
|
|
struct am_video_plane *video_plane)
|
|
{
|
|
struct drm_property *prop;
|
|
|
|
prop = drm_property_create_range(drm_dev, 0,
|
|
"video_max_size", 0, 0);
|
|
if (prop) {
|
|
video_plane->video_src_max_size_property = prop;
|
|
drm_object_attach_property(&video_plane->base.base, prop, 0);
|
|
} else {
|
|
DRM_ERROR("Failed to create video_max_size property\n");
|
|
}
|
|
}
|
|
|
|
struct drm_property *
|
|
meson_create_signal_fmt_prop(struct drm_device *dev,
|
|
unsigned int supported_filters)
|
|
{
|
|
struct drm_property *prop;
|
|
static const struct drm_prop_enum_list props[] = {
|
|
{ SIGNAL_FMT_SDR, "sdr" },
|
|
{ SIGNAL_FMT_HDR10, "hdr10" },
|
|
{ SIGNAL_FMT_HDR10PRIME, "hdr10prime" },
|
|
{ SIGNAL_FMT_CUVA_HDR, "cuva_hdr" },
|
|
};
|
|
unsigned int valid_mode_mask = BIT(SIGNAL_FMT_SDR) |
|
|
BIT(SIGNAL_FMT_HDR10) |
|
|
BIT(SIGNAL_FMT_HDR10PRIME) |
|
|
BIT(SIGNAL_FMT_CUVA_HDR);
|
|
int i;
|
|
|
|
if (WARN_ON((supported_filters & ~valid_mode_mask) ||
|
|
((supported_filters & BIT(VFRAME_SIGNAL_FMT_SDR)) == 0)))
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
|
|
"signal_format",
|
|
hweight32(supported_filters));
|
|
if (!prop)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(props); i++) {
|
|
int ret;
|
|
|
|
if (!(BIT(props[i].type) & supported_filters))
|
|
continue;
|
|
|
|
ret = drm_property_add_enum(prop, props[i].type,
|
|
props[i].name);
|
|
|
|
if (ret) {
|
|
drm_property_destroy(dev, prop);
|
|
|
|
return ERR_PTR(ret);
|
|
}
|
|
}
|
|
|
|
return prop;
|
|
}
|
|
|
|
int meson_video_plane_create_signal_fmt_property(struct am_video_plane *video_plane,
|
|
unsigned int supported_filters)
|
|
{
|
|
struct drm_property *prop =
|
|
meson_create_signal_fmt_prop(video_plane->base.dev, supported_filters);
|
|
|
|
if (IS_ERR(prop))
|
|
return PTR_ERR(prop);
|
|
|
|
drm_object_attach_property(&video_plane->base.base, prop,
|
|
VFRAME_SIGNAL_FMT_SDR);
|
|
video_plane->signal_fmt_property = prop;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int meson_video_plane_create_in_fence_property(struct meson_drm *priv,
|
|
struct am_video_plane *video_plane)
|
|
{
|
|
struct drm_property *prop;
|
|
|
|
prop = drm_property_create_signed_range(priv->drm, DRM_MODE_PROP_ATOMIC,
|
|
"ASYNC_IN_FENCE_FD", -1,
|
|
INT_MAX);
|
|
if (!prop)
|
|
return -ENOMEM;
|
|
drm_object_attach_property(&video_plane->base.base, prop, -1);
|
|
|
|
video_plane->async_in_fence_property = prop;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void meson_video_create_video_present_fence_property(struct drm_device *drm_dev,
|
|
struct am_video_plane *video_plane)
|
|
{
|
|
struct drm_property *prop;
|
|
|
|
prop = drm_property_create_range(drm_dev, 0,
|
|
"video_present_fence", 0, U64_MAX);//
|
|
if (prop) {
|
|
video_plane->video_present_fence_property = prop;
|
|
drm_object_attach_property(&video_plane->base.base, prop, 0);
|
|
} else {
|
|
DRM_ERROR("Failed to create video_present_fence property\n");
|
|
}
|
|
}
|
|
|
|
static void meson_video_create_video_release_fence_property(struct drm_device *drm_dev,
|
|
struct am_video_plane *video_plane)
|
|
{
|
|
struct drm_property *prop;
|
|
|
|
prop = drm_property_create_range(drm_dev, 0,
|
|
"video_release_fence", 0, U64_MAX);//
|
|
if (prop) {
|
|
video_plane->video_release_fence_property = prop;
|
|
drm_object_attach_property(&video_plane->base.base, prop, 0);
|
|
} else {
|
|
DRM_ERROR("Failed to create video_present_fence property\n");
|
|
}
|
|
}
|
|
|
|
static void meson_video_create_frame_flag_property(struct drm_device *drm_dev,
|
|
struct am_video_plane *video_plane)
|
|
{
|
|
struct drm_property *prop;
|
|
|
|
prop = drm_property_create_range(drm_dev, 0,
|
|
"video_frame_flag", 0, UINT_MAX);
|
|
if (prop) {
|
|
video_plane->frame_flag_prop = prop;
|
|
drm_object_attach_property(&video_plane->base.base, prop, 0);
|
|
} else {
|
|
DRM_ERROR("Failed to create video_frame_flag property\n");
|
|
}
|
|
}
|
|
|
|
static int meson_plane_create_dimm_ctrl_property(struct am_osd_plane *osd_plane,
|
|
unsigned int bgcolor,
|
|
unsigned int min, unsigned int max)
|
|
{
|
|
struct drm_property *prop;
|
|
|
|
prop = drm_property_create_range(osd_plane->base.dev, 0, "OSD_DIMMING_CTRL", min, max);
|
|
if (!prop)
|
|
return -ENOMEM;
|
|
|
|
drm_object_attach_property(&osd_plane->base.base, prop, bgcolor);
|
|
|
|
osd_plane->dimm_ctrl_property = prop;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void meson_plane_get_primary_plane(struct meson_drm *priv,
|
|
enum drm_plane_type *type)
|
|
{
|
|
int i, j;
|
|
|
|
for (j = 0; j < MESON_MAX_OSDS; j++)
|
|
type[j] = DRM_PLANE_TYPE_OVERLAY;
|
|
|
|
for (i = 0; i < MESON_MAX_CRTC; i++) {
|
|
for (j = 0; j < MESON_MAX_OSDS; j++) {
|
|
if (j < MESON_MAX_OSDS &&
|
|
i == priv->of_conf.crtcmask_osd[j] &&
|
|
priv->osd_occupied_index != j) {
|
|
type[j] = DRM_PLANE_TYPE_PRIMARY;
|
|
priv->primary_plane_index[i] = j;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static struct am_osd_plane *am_osd_plane_create(struct meson_drm *priv,
|
|
int i, u32 crtc_mask, enum drm_plane_type type)
|
|
{
|
|
struct am_osd_plane *osd_plane;
|
|
struct meson_of_conf *conf;
|
|
struct drm_plane *plane;
|
|
u32 zpos, min_zpos, max_zpos, index, osd_reverse;
|
|
char plane_name[8];
|
|
const u32 *formats_group;
|
|
int num_formats;
|
|
const char *const_plane_name;
|
|
struct drm_rect adjust_rect = {-1, -1, -1, -1};
|
|
|
|
osd_plane = devm_kzalloc(priv->drm->dev, sizeof(*osd_plane),
|
|
GFP_KERNEL);
|
|
if (!osd_plane)
|
|
return 0;
|
|
|
|
min_zpos = OSD_PLANE_BEGIN_ZORDER;
|
|
max_zpos = OSD_PLANE_END_ZORDER;
|
|
|
|
osd_plane->drv = priv;
|
|
osd_plane->plane_index = i;
|
|
osd_plane->plane_type = OSD_PLANE;
|
|
osd_plane->adjust_src = adjust_rect;
|
|
osd_plane->adjust_dst = adjust_rect;
|
|
conf = &priv->of_conf;
|
|
osd_reverse = DRM_MODE_ROTATE_0;
|
|
index = 0;
|
|
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_FB
|
|
get_logo_osd_reverse(&index, &osd_reverse);
|
|
#else
|
|
drm_logo_get_osd_reverse(&index, &osd_reverse);
|
|
#endif
|
|
if (index == osd_plane->plane_index || index == DEV_ALL) {
|
|
switch (osd_reverse) {
|
|
case 1:
|
|
osd_plane->osd_reverse = DRM_MODE_REFLECT_MASK;
|
|
break;
|
|
case 2:
|
|
osd_plane->osd_reverse = DRM_MODE_REFLECT_X;
|
|
break;
|
|
case 3:
|
|
osd_plane->osd_reverse = DRM_MODE_REFLECT_Y;
|
|
break;
|
|
default:
|
|
osd_plane->osd_reverse = DRM_MODE_ROTATE_0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
zpos = osd_plane->plane_index + min_zpos;
|
|
|
|
plane = &osd_plane->base;
|
|
sprintf(plane_name, "osd%d", i);
|
|
const_plane_name = plane_name;
|
|
|
|
if (i == priv->osd_occupied_index)
|
|
osd_plane->osd_occupied = true;
|
|
else
|
|
osd_plane->osd_occupied = false;
|
|
|
|
if (!priv->vpu_data->osd_formats) {
|
|
formats_group = supported_drm_formats;
|
|
num_formats = ARRAY_SIZE(supported_drm_formats);
|
|
} else {
|
|
formats_group = priv->vpu_data->osd_formats->formats;
|
|
num_formats = priv->vpu_data->osd_formats->format_num;
|
|
}
|
|
|
|
if (conf->osd_afbc_mask & BIT(i)) {
|
|
drm_universal_plane_init(priv->drm, plane, 1 << crtc_mask,
|
|
&am_osd_plane_funs,
|
|
formats_group,
|
|
num_formats,
|
|
afbc_modifier,
|
|
type, const_plane_name);
|
|
} else {
|
|
priv->drm->mode_config.fb_modifiers_not_supported = !false;
|
|
drm_universal_plane_init(priv->drm, plane, 1 << crtc_mask,
|
|
&am_osd_plane_funs,
|
|
formats_group,
|
|
num_formats,
|
|
NULL,
|
|
type, const_plane_name);
|
|
priv->drm->mode_config.fb_modifiers_not_supported = !true;
|
|
}
|
|
drm_plane_create_blend_mode_property(plane,
|
|
BIT(DRM_MODE_BLEND_PIXEL_NONE) |
|
|
BIT(DRM_MODE_BLEND_PREMULTI) |
|
|
BIT(DRM_MODE_BLEND_COVERAGE));
|
|
drm_plane_create_alpha_property(plane);
|
|
drm_plane_create_rotation_property(plane,
|
|
DRM_MODE_ROTATE_0,
|
|
DRM_MODE_ROTATE_0 |
|
|
DRM_MODE_REFLECT_MASK);
|
|
drm_plane_create_zpos_property(plane, zpos, min_zpos, max_zpos);
|
|
drm_plane_helper_add(plane, &am_osd_helper_funcs);
|
|
meson_plane_create_scaling_filter_property(plane,
|
|
BIT(DRM_SCALING_FILTER_DEFAULT) |
|
|
BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR) |
|
|
BIT(DRM_SCALING_FILTER_BICUBIC_SHARP) |
|
|
BIT(DRM_SCALING_FILTER_BICUBIC) |
|
|
BIT(DRM_SCALING_FILTER_BILINEAR) |
|
|
BIT(DRM_SCALING_FILTER_2POINT_BILINEAR) |
|
|
BIT(DRM_SCALING_FILTER_3POINT_TRIANGLE_SHARP) |
|
|
BIT(DRM_SCALING_FILTER_3POINT_TRIANGLE) |
|
|
BIT(DRM_SCALING_FILTER_4POINT_TRIANGLE) |
|
|
BIT(DRM_SCALING_FILTER_4POINT_BSPLINE) |
|
|
BIT(DRM_SCALING_FILTER_3POINT_BSPLINE) |
|
|
BIT(DRM_SCALING_FILTER_REPEATE));
|
|
meson_plane_add_occupied_property(priv->drm, osd_plane);
|
|
meson_plane_add_max_fb_property(priv->drm, osd_plane);
|
|
meson_plane_add_osd_capability_property(priv->drm, osd_plane);
|
|
meson_plane_add_rotation_reflect_property(priv->drm, osd_plane);
|
|
DRM_INFO("osd plane %d create done,occupied-%d crtc_mask-%d type-%d reverse-%d zpos-%d\n",
|
|
i, osd_plane->osd_occupied, crtc_mask, type, osd_reverse, zpos);
|
|
meson_plane_create_security_en_property(priv->drm, osd_plane);
|
|
meson_plane_add_palette_property(priv->drm, osd_plane);
|
|
meson_plane_add_unsupport_nonafbc_property(priv->drm, osd_plane);
|
|
meson_plane_create_dimm_ctrl_property(osd_plane, 0, 0, 0xffffffff);
|
|
return osd_plane;
|
|
}
|
|
|
|
static struct am_video_plane *am_video_plane_create(struct meson_drm *priv,
|
|
int i, u32 crtc_mask)
|
|
{
|
|
struct am_video_plane *video_plane;
|
|
struct drm_plane *plane;
|
|
const u32 *formats_group;
|
|
int num_formats;
|
|
char plane_name[8];
|
|
u32 zpos, min_zpos, max_zpos;
|
|
const char *const_plane_name;
|
|
struct drm_rect adjust_rect = {-1, -1, -1, -1};
|
|
|
|
video_plane = devm_kzalloc(priv->drm->dev, sizeof(*video_plane),
|
|
GFP_KERNEL);
|
|
if (!video_plane) {
|
|
DRM_INFO("no memory to alloc video plane\n");
|
|
return 0;
|
|
}
|
|
|
|
video_plane->context = dma_fence_context_alloc(1);
|
|
video_plane->seqno = 0;
|
|
|
|
video_plane->present_context = dma_fence_context_alloc(1);
|
|
video_plane->present_seqno = 0;
|
|
|
|
min_zpos = VIDEO_PLANE_BEGIN_ZORDER;
|
|
max_zpos = VIDEO_PLANE_END_ZORDER;
|
|
|
|
video_plane->drv = priv;
|
|
video_plane->plane_index = i;
|
|
|
|
video_plane->plane_type = VIDEO_PLANE;
|
|
video_plane->pipeline = priv->pipeline;
|
|
video_plane->adjust_src = adjust_rect;
|
|
video_plane->adjust_dst = adjust_rect;
|
|
zpos = video_plane->plane_index + min_zpos;
|
|
|
|
plane = &video_plane->base;
|
|
sprintf(plane_name, "video%d", i);
|
|
const_plane_name = plane_name;
|
|
|
|
if (!priv->vpu_data->video_formats) {
|
|
formats_group = video_supported_drm_formats;
|
|
num_formats = ARRAY_SIZE(video_supported_drm_formats);
|
|
} else {
|
|
formats_group = priv->vpu_data->video_formats->formats;
|
|
num_formats = priv->vpu_data->video_formats->format_num;
|
|
}
|
|
|
|
drm_universal_plane_init(priv->drm, plane, 1 << crtc_mask,
|
|
&am_video_plane_funs,
|
|
formats_group,
|
|
num_formats,
|
|
video_fbc_modifier,
|
|
DRM_PLANE_TYPE_OVERLAY, const_plane_name);
|
|
|
|
drm_plane_create_rotation_property(plane,
|
|
DRM_MODE_ROTATE_0,
|
|
DRM_MODE_ROTATE_MASK |
|
|
DRM_MODE_REFLECT_MASK);
|
|
drm_plane_create_zpos_property(plane, zpos, min_zpos, max_zpos);
|
|
meson_video_plane_create_in_fence_property(priv, video_plane);
|
|
meson_video_create_video_present_fence_property(priv->drm, video_plane);
|
|
meson_video_create_video_release_fence_property(priv->drm, video_plane);
|
|
meson_video_plane_create_signal_fmt_property(video_plane,
|
|
BIT(SIGNAL_FMT_SDR) |
|
|
BIT(SIGNAL_FMT_HDR10) |
|
|
BIT(SIGNAL_FMT_HDR10PRIME) |
|
|
BIT(SIGNAL_FMT_CUVA_HDR));
|
|
meson_video_create_frame_flag_property(priv->drm, video_plane);
|
|
|
|
drm_plane_helper_add(plane, &am_video_helper_funcs);
|
|
|
|
meson_video_create_video_cap_property(priv->drm, video_plane);
|
|
meson_video_create_video_src_min_size_property(priv->drm, video_plane);
|
|
meson_video_create_video_src_max_size_property(priv->drm, video_plane);
|
|
|
|
spin_lock_init(&video_plane->fence_lock);
|
|
spin_lock_init(&video_plane->present_fence_lock);
|
|
|
|
DRM_INFO("video plane %d create done\n", i);
|
|
return video_plane;
|
|
}
|
|
|
|
static void register_osd_status_cb_func(void)
|
|
{
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_VECM
|
|
#ifndef CONFIG_AMLOGIC_ZAPPER_CUT
|
|
register_osd_status_cb(get_osd_status_callback);
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
|
|
register_osd_func(get_osd_status_callback);
|
|
#endif
|
|
}
|
|
|
|
int am_meson_plane_create(struct meson_drm *priv)
|
|
{
|
|
struct am_osd_plane *plane;
|
|
struct am_video_plane *video_plane;
|
|
struct meson_vpu_pipeline *pipeline = priv->pipeline;
|
|
struct meson_of_conf *conf = &priv->of_conf;
|
|
enum drm_plane_type type[MESON_MAX_OSD];
|
|
int i, osd_index, video_index;
|
|
u32 num_osd_plane = 0;
|
|
|
|
memset(priv->osd_planes, 0, sizeof(struct am_osd_plane *) * MESON_MAX_OSD);
|
|
memset(priv->video_planes, 0, sizeof(struct am_video_plane *) * MESON_MAX_VIDEO);
|
|
|
|
/*calculate primary plane*/
|
|
meson_plane_get_primary_plane(priv, type);
|
|
|
|
register_osd_status_cb_func();
|
|
|
|
/*osd plane*/
|
|
for (i = 0; i < MESON_MAX_OSD; i++) {
|
|
if (!pipeline->osds[i])
|
|
continue;
|
|
|
|
osd_index = pipeline->osds[i]->base.index;
|
|
plane = am_osd_plane_create(priv, osd_index,
|
|
conf->crtcmask_osd[i],
|
|
type[i]);
|
|
|
|
if (!plane)
|
|
return -ENOMEM;
|
|
|
|
if (i == 0)
|
|
priv->primary_plane = &plane->base;
|
|
|
|
priv->osd_planes[i] = plane;
|
|
priv->num_planes++;
|
|
}
|
|
|
|
num_osd_plane = priv->num_planes;
|
|
|
|
/*video plane: init after osd to provide osd id at first.*/
|
|
for (i = 0; i < pipeline->num_video; i++) {
|
|
video_index = pipeline->video[i]->base.index;
|
|
video_plane = am_video_plane_create(priv, video_index,
|
|
conf->crtcmask_video[i]);
|
|
if (!video_plane)
|
|
return -ENOMEM;
|
|
|
|
priv->video_planes[i] = video_plane;
|
|
priv->num_planes++;
|
|
}
|
|
|
|
DRM_INFO("%u osd and %u video plane are created\n", num_osd_plane,
|
|
priv->num_planes - num_osd_plane);
|
|
return 0;
|
|
}
|