kernel_samsung_a34x-permissive/drivers/gpu/drm/mediatek/mtk_drm_plane.c
2024-04-28 15:51:13 +02:00

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;
}