6db4831e98
Android 14
554 lines
15 KiB
C
554 lines
15 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (c) 2019 MediaTek Inc.
|
|
*/
|
|
|
|
#include <drm/drmP.h>
|
|
#include <drm/drm_atomic.h>
|
|
#include <drm/drm_atomic_helper.h>
|
|
#include <drm/drm_plane_helper.h>
|
|
#include <linux/mailbox_controller.h>
|
|
|
|
#include "mtk_drm_crtc.h"
|
|
#include "mtk_drm_ddp_comp.h"
|
|
#include "mtk_drm_drv.h"
|
|
#include "mtk_drm_fb.h"
|
|
#include "mtk_drm_gem.h"
|
|
#include "mtk_drm_plane.h"
|
|
#include "cmdq-sec.h"
|
|
#include "mtk_drm_mmp.h"
|
|
|
|
#define MTK_DRM_PLANE_SCALING_MIN 16
|
|
#define MTK_DRM_PLANE_SCALING_MAX (1 << 16)
|
|
|
|
static const u32 formats[] = {
|
|
DRM_FORMAT_C8, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888,
|
|
DRM_FORMAT_ARGB8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_BGRX8888,
|
|
DRM_FORMAT_RGBX8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_RGBA8888,
|
|
DRM_FORMAT_BGR888, DRM_FORMAT_RGB888, DRM_FORMAT_BGR565,
|
|
DRM_FORMAT_RGB565, DRM_FORMAT_YUYV, DRM_FORMAT_YVYU,
|
|
DRM_FORMAT_UYVY, DRM_FORMAT_VYUY, DRM_FORMAT_ABGR2101010,
|
|
DRM_FORMAT_ABGR16161616F,
|
|
DRM_FORMAT_RGB332, // for skip_update
|
|
};
|
|
|
|
unsigned int to_crtc_plane_index(unsigned int plane_index)
|
|
{
|
|
if ((plane_index >= 0) && (plane_index < OVL_LAYER_NR))
|
|
return plane_index;
|
|
else if (plane_index < (OVL_LAYER_NR + EXTERNAL_INPUT_LAYER_NR))
|
|
return plane_index - OVL_LAYER_NR;
|
|
else if (plane_index < MAX_PLANE_NR)
|
|
return plane_index - OVL_LAYER_NR - EXTERNAL_INPUT_LAYER_NR;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
int mtk_get_format_bpp(uint32_t format)
|
|
{
|
|
switch (format) {
|
|
case MTK_DRM_FORMAT_DIM:
|
|
case DRM_FORMAT_C8:
|
|
return 0;
|
|
case DRM_FORMAT_RGB565:
|
|
case DRM_FORMAT_BGR565:
|
|
case DRM_FORMAT_YUYV:
|
|
case DRM_FORMAT_YVYU:
|
|
case DRM_FORMAT_UYVY:
|
|
case DRM_FORMAT_VYUY:
|
|
return 2;
|
|
case DRM_FORMAT_RGB888:
|
|
case DRM_FORMAT_BGR888:
|
|
return 3;
|
|
case DRM_FORMAT_XRGB8888:
|
|
case DRM_FORMAT_XBGR8888:
|
|
case DRM_FORMAT_RGBX8888:
|
|
case DRM_FORMAT_BGRX8888:
|
|
case DRM_FORMAT_ARGB8888:
|
|
case DRM_FORMAT_ABGR8888:
|
|
case DRM_FORMAT_RGBA8888:
|
|
case DRM_FORMAT_BGRA8888:
|
|
case DRM_FORMAT_XRGB2101010:
|
|
case DRM_FORMAT_XBGR2101010:
|
|
case DRM_FORMAT_RGBX1010102:
|
|
case DRM_FORMAT_BGRX1010102:
|
|
case DRM_FORMAT_ARGB2101010:
|
|
case DRM_FORMAT_ABGR2101010:
|
|
case DRM_FORMAT_RGBA1010102:
|
|
case DRM_FORMAT_BGRA1010102:
|
|
return 4;
|
|
case DRM_FORMAT_YUV422:
|
|
case DRM_FORMAT_YVU422:
|
|
return 2;
|
|
case DRM_FORMAT_YUV444:
|
|
case DRM_FORMAT_YVU444:
|
|
return 3;
|
|
case DRM_FORMAT_ABGR16161616F:
|
|
return 8;
|
|
default:
|
|
return 4;
|
|
}
|
|
}
|
|
|
|
char *mtk_get_format_name(uint32_t format)
|
|
{
|
|
switch (format) {
|
|
case DRM_FORMAT_C8:
|
|
return "C8";
|
|
case DRM_FORMAT_XRGB8888:
|
|
return "XRGB8888";
|
|
case DRM_FORMAT_XBGR8888:
|
|
return "XBGR8888";
|
|
case DRM_FORMAT_ARGB8888:
|
|
return "ARGB8888";
|
|
case DRM_FORMAT_ABGR8888:
|
|
return "ABGR8888";
|
|
case DRM_FORMAT_BGRX8888:
|
|
return "BGRX8888";
|
|
case DRM_FORMAT_RGBX8888:
|
|
return "RGBX8888";
|
|
case DRM_FORMAT_BGRA8888:
|
|
return "BGRA8888";
|
|
case DRM_FORMAT_RGBA8888:
|
|
return "RGBA8888";
|
|
case DRM_FORMAT_BGR888:
|
|
return "BGR888";
|
|
case DRM_FORMAT_RGB888:
|
|
return "RGB888";
|
|
case DRM_FORMAT_BGR565:
|
|
return "BGR565";
|
|
case DRM_FORMAT_RGB565:
|
|
return "RGB565";
|
|
case DRM_FORMAT_YUYV:
|
|
return "YUYV";
|
|
case DRM_FORMAT_YVYU:
|
|
return "YVYU";
|
|
case DRM_FORMAT_UYVY:
|
|
return "UYVY";
|
|
case DRM_FORMAT_VYUY:
|
|
return "VYUY";
|
|
case DRM_FORMAT_ABGR2101010:
|
|
return "ABGR2101010";
|
|
case DRM_FORMAT_ABGR16161616F:
|
|
return "ABGRFP16";
|
|
}
|
|
return "fmt_unknown";
|
|
}
|
|
|
|
static struct mtk_drm_property mtk_plane_property[PLANE_PROP_MAX] = {
|
|
{DRM_MODE_PROP_ATOMIC, "NEXT_BUFF_IDX", 0, UINT_MAX, 0},
|
|
{DRM_MODE_PROP_ATOMIC, "LYE_BLOB_IDX", 0, UINT_MAX, 0},
|
|
{DRM_MODE_PROP_ATOMIC, "PLANE_PROP_ALPHA_CON", 0, 0x1, 0x1},
|
|
{DRM_MODE_PROP_ATOMIC, "PLANE_PROP_PLANE_ALPHA", 0, 0xFF, 0xFF},
|
|
{DRM_MODE_PROP_ATOMIC, "DATASPACE", 0, INT_MAX, 0},
|
|
{DRM_MODE_PROP_ATOMIC, "VPITCH", 0, UINT_MAX, 0},
|
|
{DRM_MODE_PROP_ATOMIC, "COMPRESS", 0, UINT_MAX, 0},
|
|
{DRM_MODE_PROP_ATOMIC, "DIM_COLOR", 0, UINT_MAX, 0},
|
|
{DRM_MODE_PROP_ATOMIC, "IS_MML", 0, UINT_MAX, 0},
|
|
{DRM_MODE_PROP_ATOMIC, "MML_SUBMIT", 0, ULONG_MAX, 0},
|
|
};
|
|
|
|
static void mtk_plane_reset(struct drm_plane *plane)
|
|
{
|
|
struct mtk_plane_state *state;
|
|
|
|
if (plane->state) {
|
|
__drm_atomic_helper_plane_destroy_state(plane->state);
|
|
|
|
state = to_mtk_plane_state(plane->state);
|
|
memset(state, 0, sizeof(*state));
|
|
} else {
|
|
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
|
if (!state)
|
|
return;
|
|
plane->state = &state->base;
|
|
}
|
|
state->prop_val[PLANE_PROP_ALPHA_CON] = 0x1;
|
|
state->prop_val[PLANE_PROP_PLANE_ALPHA] = 0xFF;
|
|
state->base.plane = plane;
|
|
state->pending.format = DRM_FORMAT_RGB565;
|
|
}
|
|
|
|
static struct drm_plane_state *
|
|
mtk_plane_duplicate_state(struct drm_plane *plane)
|
|
{
|
|
struct mtk_plane_state *old_state = to_mtk_plane_state(plane->state);
|
|
struct mtk_plane_state *state;
|
|
|
|
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
|
if (!state)
|
|
return NULL;
|
|
|
|
__drm_atomic_helper_plane_duplicate_state(plane, &state->base);
|
|
|
|
if (state->base.plane != plane)
|
|
DDPAEE("%s:%d, invalid plane:(%p,%p)\n",
|
|
__func__, __LINE__,
|
|
state->base.plane, plane);
|
|
|
|
state->prop_val[PLANE_PROP_ALPHA_CON] =
|
|
old_state->prop_val[PLANE_PROP_ALPHA_CON];
|
|
state->prop_val[PLANE_PROP_PLANE_ALPHA] =
|
|
old_state->prop_val[PLANE_PROP_PLANE_ALPHA];
|
|
state->pending = old_state->pending;
|
|
state->comp_state = old_state->comp_state;
|
|
state->crtc = old_state->crtc;
|
|
|
|
return &state->base;
|
|
}
|
|
|
|
static void mtk_drm_plane_destroy_state(struct drm_plane *plane,
|
|
struct drm_plane_state *state)
|
|
{
|
|
struct mtk_plane_state *s;
|
|
|
|
s = to_mtk_plane_state(state);
|
|
__drm_atomic_helper_plane_destroy_state(state);
|
|
kfree(s);
|
|
}
|
|
|
|
static int mtk_plane_atomic_set_property(struct drm_plane *plane,
|
|
struct drm_plane_state *state,
|
|
struct drm_property *property,
|
|
uint64_t val)
|
|
{
|
|
struct mtk_drm_plane *mtk_plane = to_mtk_plane(plane);
|
|
struct mtk_plane_state *plane_state = to_mtk_plane_state(state);
|
|
int ret = 0;
|
|
int i;
|
|
|
|
if (!mtk_plane) {
|
|
DDPPR_ERR("%s:%d mtk plane is null\n", __func__, __LINE__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
for (i = 0; i < PLANE_PROP_MAX; i++) {
|
|
if (mtk_plane->plane_property[i] == property) {
|
|
plane_state->prop_val[i] = (unsigned int)val;
|
|
DDPDBG("set property:%s %d\n", property->name,
|
|
(unsigned int)val);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
DDPPR_ERR("%s:%d fail to set property:%s %d\n", property->name,
|
|
(unsigned int)val, __func__, __LINE__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int mtk_plane_atomic_get_property(struct drm_plane *plane,
|
|
const struct drm_plane_state *state,
|
|
struct drm_property *property,
|
|
uint64_t *val)
|
|
{
|
|
struct mtk_drm_plane *mtk_plane = to_mtk_plane(plane);
|
|
struct mtk_plane_state *plane_state = to_mtk_plane_state(state);
|
|
int ret = 0;
|
|
int i;
|
|
|
|
if (!mtk_plane) {
|
|
DDPPR_ERR("%s:%d mtk plane is null\n", __func__, __LINE__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
for (i = 0; i < PLANE_PROP_MAX; i++) {
|
|
if (mtk_plane->plane_property[i] == property) {
|
|
*val = plane_state->prop_val[i];
|
|
DDPINFO("get property:%s %lld\n", property->name, *val);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
DDPPR_ERR("%s:%d fail to get property:%s %p\n", __func__, __LINE__,
|
|
property->name, val);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static const struct drm_plane_funcs mtk_plane_funcs = {
|
|
.update_plane = drm_atomic_helper_update_plane,
|
|
.disable_plane = drm_atomic_helper_disable_plane,
|
|
.destroy = drm_plane_cleanup,
|
|
.reset = mtk_plane_reset,
|
|
.atomic_duplicate_state = mtk_plane_duplicate_state,
|
|
.atomic_destroy_state = mtk_drm_plane_destroy_state,
|
|
.atomic_set_property = mtk_plane_atomic_set_property,
|
|
.atomic_get_property = mtk_plane_atomic_get_property,
|
|
};
|
|
|
|
static int mtk_plane_atomic_check(struct drm_plane *plane,
|
|
struct drm_plane_state *state)
|
|
{
|
|
struct drm_framebuffer *fb = state->fb;
|
|
struct drm_crtc_state *crtc_state;
|
|
struct mtk_drm_private *private = plane->dev->dev_private;
|
|
|
|
if (!fb)
|
|
return 0;
|
|
|
|
if (!mtk_fb_get_gem_obj(fb) && fb->format->format != DRM_FORMAT_C8) {
|
|
DRM_DEBUG_KMS("buffer is null\n");
|
|
return -EFAULT;
|
|
}
|
|
|
|
if (!state->crtc)
|
|
return 0;
|
|
|
|
crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
|
|
if (IS_ERR(crtc_state))
|
|
return PTR_ERR(crtc_state);
|
|
|
|
if (mtk_drm_helper_get_opt(private->helper_opt, MTK_DRM_OPT_RPO))
|
|
return drm_atomic_helper_check_plane_state(
|
|
state, crtc_state, MTK_DRM_PLANE_SCALING_MIN,
|
|
MTK_DRM_PLANE_SCALING_MAX, true, true);
|
|
else
|
|
return drm_atomic_helper_check_plane_state(
|
|
state, crtc_state, DRM_PLANE_HELPER_NO_SCALING,
|
|
DRM_PLANE_HELPER_NO_SCALING, true, true);
|
|
}
|
|
|
|
#ifdef MTK_DRM_ADVANCE
|
|
static void _mtk_plane_get_comp_state(struct mtk_drm_lyeblob_ids *lyeblob_ids,
|
|
struct mtk_plane_comp_state *comp_state,
|
|
struct drm_crtc *crtc,
|
|
unsigned int plane_index)
|
|
{
|
|
int blob_id;
|
|
int ref_cnt;
|
|
struct drm_property_blob *blob;
|
|
|
|
blob_id = lyeblob_ids->lye_plane_blob_id[crtc->index][plane_index];
|
|
ref_cnt = lyeblob_ids->ref_cnt;
|
|
if (blob_id && ref_cnt) {
|
|
blob = drm_property_lookup_blob(crtc->dev, blob_id);
|
|
if (blob) {
|
|
memcpy(comp_state, blob->data,
|
|
sizeof(struct mtk_plane_comp_state));
|
|
drm_property_blob_put(blob);
|
|
}
|
|
}
|
|
}
|
|
|
|
void mtk_plane_get_comp_state(struct drm_plane *plane,
|
|
struct mtk_plane_comp_state *comp_state,
|
|
struct drm_crtc *crtc, int lock)
|
|
{
|
|
struct mtk_drm_lyeblob_ids *lyeblob_ids, *next;
|
|
struct mtk_drm_private *mtk_drm = crtc->dev->dev_private;
|
|
struct mtk_crtc_state *crtc_state = to_mtk_crtc_state(crtc->state);
|
|
unsigned int crtc_lye_idx = crtc_state->prop_val[CRTC_PROP_LYE_IDX];
|
|
unsigned int plane_index = to_crtc_plane_index(plane->index);
|
|
|
|
memset(comp_state, 0x0, sizeof(struct mtk_plane_comp_state));
|
|
|
|
if (lock)
|
|
mutex_lock(&mtk_drm->lyeblob_list_mutex);
|
|
list_for_each_entry_safe(lyeblob_ids, next, &mtk_drm->lyeblob_head,
|
|
list) {
|
|
if (lyeblob_ids->lye_idx == crtc_lye_idx) {
|
|
_mtk_plane_get_comp_state(lyeblob_ids, comp_state, crtc,
|
|
plane_index);
|
|
} else if (lyeblob_ids->lye_idx > crtc_lye_idx)
|
|
break;
|
|
}
|
|
|
|
if (lock)
|
|
mutex_unlock(&mtk_drm->lyeblob_list_mutex);
|
|
}
|
|
#endif
|
|
|
|
static void mtk_plane_atomic_update(struct drm_plane *plane,
|
|
struct drm_plane_state *old_state)
|
|
{
|
|
struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
|
|
struct drm_crtc *crtc = plane->state->crtc;
|
|
struct mtk_crtc_state *crtc_state;
|
|
struct drm_framebuffer *fb = plane->state->fb;
|
|
int src_w, src_h, dst_x, dst_y, dst_w, dst_h, i;
|
|
struct mtk_drm_crtc *mtk_crtc;
|
|
unsigned int plane_index = to_crtc_plane_index(plane->index);
|
|
static int cnt;
|
|
bool skip_update = 0;
|
|
int crtc_index = 0;
|
|
|
|
if (!crtc)
|
|
return;
|
|
|
|
crtc_state = to_mtk_crtc_state(crtc->state);
|
|
mtk_crtc = to_mtk_crtc(crtc);
|
|
crtc_index = drm_crtc_index(crtc);
|
|
|
|
if ((!fb) || (mtk_crtc->ddp_mode == DDP_NO_USE))
|
|
return;
|
|
|
|
src_w = drm_rect_width(&plane->state->src) >> 16;
|
|
src_h = drm_rect_height(&plane->state->src) >> 16;
|
|
dst_x = plane->state->dst.x1;
|
|
dst_y = plane->state->dst.y1;
|
|
dst_w = drm_rect_width(&plane->state->dst);
|
|
dst_h = drm_rect_height(&plane->state->dst);
|
|
|
|
if (src_w < dst_w || src_h < dst_h) {
|
|
dst_x = ((dst_x * src_w * 10) / dst_w + 5) / 10
|
|
- crtc_state->rsz_src_roi.x;
|
|
dst_y = ((dst_y * src_h * 10) / dst_h + 5) / 10
|
|
- crtc_state->rsz_src_roi.y;
|
|
dst_w = src_w;
|
|
dst_h = src_h;
|
|
}
|
|
|
|
state->pending.enable = plane->state->visible;
|
|
state->pending.pitch = fb->pitches[0];
|
|
state->pending.format = fb->format->format;
|
|
state->pending.modifier = fb->modifier;
|
|
state->pending.addr = mtk_fb_get_dma(fb);
|
|
state->pending.size = mtk_fb_get_size(fb);
|
|
state->pending.src_x = (plane->state->src.x1 >> 16);
|
|
state->pending.src_y = (plane->state->src.y1 >> 16);
|
|
state->pending.dst_x = dst_x;
|
|
state->pending.dst_y = dst_y;
|
|
state->pending.width = dst_w;
|
|
state->pending.height = dst_h;
|
|
if (mtk_drm_fb_is_secure(fb)) {
|
|
state->pending.is_sec = true;
|
|
state->pending.sec_id = mtk_fb_get_sec_id(fb);
|
|
} else {
|
|
state->pending.is_sec = false;
|
|
state->pending.sec_id = -1;
|
|
}
|
|
for (i = 0; i < PLANE_PROP_MAX; i++)
|
|
state->pending.prop_val[i] = state->prop_val[i];
|
|
|
|
wmb(); /* Make sure the above parameters are set before update */
|
|
state->pending.dirty = true;
|
|
|
|
DDPINFO("%s:%d enable%d,pitch%d,format%d\n",
|
|
__func__, __LINE__, (unsigned int)state->pending.enable,
|
|
state->pending.pitch, state->pending.format);
|
|
DDPINFO("addr0x%lx,x%d,y%d,width%d,height%d\n",
|
|
(unsigned long)state->pending.addr, state->pending.dst_x,
|
|
state->pending.dst_y, state->pending.width,
|
|
state->pending.height);
|
|
|
|
for (i = 0; i < PLANE_PROP_MAX; i++) {
|
|
DDPINFO("prop_val[%d]:%d ", i,
|
|
(unsigned int)state->pending.prop_val[i]);
|
|
}
|
|
DDPINFO("\n");
|
|
|
|
DDPFENCE("S+/%sL%d/e%d/id%d/mva0x%08llx/size0x%08lx/S%d\n",
|
|
mtk_crtc_index_spy(crtc_index),
|
|
plane_index,
|
|
state->pending.enable,
|
|
state->pending.prop_val[PLANE_PROP_NEXT_BUFF_IDX],
|
|
state->pending.addr,
|
|
state->pending.size,
|
|
state->pending.is_sec);
|
|
|
|
if (!mtk_crtc->sec_on && state->pending.is_sec) {
|
|
DDPMSG("receive sec buffer in non-sec mode\n");
|
|
return;
|
|
}
|
|
|
|
if (state->pending.enable)
|
|
atomic_set(&mtk_crtc->already_config, 1);
|
|
|
|
if (cnt <= 5) {
|
|
cnt++;
|
|
if (state->pending.format == DRM_FORMAT_RGB332 &&
|
|
drm_crtc_index(crtc) == 0)
|
|
skip_update = 1;
|
|
}
|
|
|
|
/* workaround for skip plane update when hwc set crtc */
|
|
if (skip_update == 0)
|
|
mtk_drm_crtc_plane_update(crtc, plane, state);
|
|
|
|
}
|
|
|
|
static void mtk_plane_atomic_disable(struct drm_plane *plane,
|
|
struct drm_plane_state *old_state)
|
|
{
|
|
struct mtk_plane_state *state = to_mtk_plane_state(plane->state);
|
|
|
|
state->pending.enable = false;
|
|
wmb(); /* Make sure the above parameter is set before update */
|
|
state->pending.dirty = true;
|
|
|
|
#ifdef MTK_DRM_ADVANCE
|
|
if (!state->crtc) {
|
|
DDPPR_ERR("%s, empty crtc state\n", __func__);
|
|
} else {
|
|
mtk_drm_crtc_plane_update(state->crtc, plane, state);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = {
|
|
.atomic_check = mtk_plane_atomic_check,
|
|
.atomic_update = mtk_plane_atomic_update,
|
|
.atomic_disable = mtk_plane_atomic_disable,
|
|
};
|
|
|
|
static void mtk_plane_attach_property(struct mtk_drm_plane *plane)
|
|
{
|
|
struct drm_device *dev = plane->base.dev;
|
|
struct drm_property *prop;
|
|
static struct drm_property *mtk_prop[PLANE_PROP_MAX];
|
|
struct mtk_drm_property *plane_prop;
|
|
int i;
|
|
static int num;
|
|
|
|
if (num == 0) {
|
|
for (i = 0; i < PLANE_PROP_MAX; i++) {
|
|
plane_prop = &(mtk_plane_property[i]);
|
|
mtk_prop[i] = drm_property_create_range(
|
|
dev, plane_prop->flags, plane_prop->name,
|
|
plane_prop->min, plane_prop->max);
|
|
if (!mtk_prop[i]) {
|
|
DDPPR_ERR("fail to create property:%s\n",
|
|
plane_prop->name);
|
|
return;
|
|
}
|
|
DDPINFO("create property:%s, flags:0x%x\n",
|
|
plane_prop->name, mtk_prop[i]->flags);
|
|
}
|
|
num++;
|
|
}
|
|
|
|
for (i = 0; i < PLANE_PROP_MAX; i++) {
|
|
prop = plane->plane_property[i];
|
|
plane_prop = &(mtk_plane_property[i]);
|
|
if (!prop) {
|
|
prop = mtk_prop[i];
|
|
plane->plane_property[i] = prop;
|
|
drm_object_attach_property(&plane->base.base, prop,
|
|
plane_prop->val);
|
|
}
|
|
}
|
|
}
|
|
|
|
int mtk_plane_init(struct drm_device *dev, struct mtk_drm_plane *plane,
|
|
unsigned int zpos, unsigned long possible_crtcs,
|
|
enum drm_plane_type type)
|
|
{
|
|
int err;
|
|
|
|
err = drm_universal_plane_init(dev, &plane->base, possible_crtcs,
|
|
&mtk_plane_funcs, formats,
|
|
ARRAY_SIZE(formats), NULL,
|
|
type, NULL);
|
|
if (err) {
|
|
DRM_ERROR("%s:%d failed to initialize plane\n", __func__,
|
|
__LINE__);
|
|
return err;
|
|
}
|
|
|
|
drm_plane_helper_add(&plane->base, &mtk_plane_helper_funcs);
|
|
|
|
mtk_plane_attach_property(plane);
|
|
|
|
return 0;
|
|
}
|