6db4831e98
Android 14
501 lines
12 KiB
C
501 lines
12 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (c) 2019 MediaTek Inc.
|
|
*/
|
|
|
|
#include <drm/drmP.h>
|
|
#include <drm/drm_gem.h>
|
|
#include <linux/dma-buf.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/kmemleak.h>
|
|
#include <drm/mediatek_drm.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 "mtk_drm_assert.h"
|
|
#include "mtk_drm_fbconsole.h"
|
|
#include "mtk_drm_mmp.h"
|
|
|
|
#define RGB888_To_RGB565(x) \
|
|
((((x)&0xF80000) >> 8) | (((x)&0x00FC00) >> 5) | (((x)&0x0000F8) >> 3))
|
|
|
|
#define MAKE_TWO_RGB565_COLOR(high, low) (((low) << 16) | (high))
|
|
|
|
#define DAL_STR_BUF_LEN (1024)
|
|
#define DAL_BPP (2)
|
|
|
|
#define MTK_FB_ALIGNMENT 32
|
|
|
|
static DEFINE_SEMAPHORE(dal_sem);
|
|
|
|
static inline int DAL_LOCK(void)
|
|
{
|
|
if (down_interruptible(&dal_sem)) {
|
|
DDPPR_ERR("Can't get semaphore in %s\n", __func__);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#define DAL_UNLOCK() up(&dal_sem)
|
|
|
|
struct mtk_drm_gem_obj *dal_buff;
|
|
static void *mfc_handle;
|
|
char drm_dal_str_buf[DAL_STR_BUF_LEN];
|
|
/* DAL layer only surve CRTC0 only */
|
|
static int drm_dal_enable;
|
|
static struct drm_crtc *dal_crtc;
|
|
static void *dal_va;
|
|
static u32 dal_pa;
|
|
|
|
static u32 DAL_GetLayerSize(void)
|
|
{
|
|
static unsigned int size;
|
|
|
|
if (!size) {
|
|
struct MFC_CONTEXT *ctxt = (struct MFC_CONTEXT *)mfc_handle;
|
|
|
|
if (ctxt)
|
|
size = ctxt->fb_width * ctxt->fb_height * DAL_BPP;
|
|
else
|
|
DDPPR_ERR("%s MFC_CONTEXT is NULL\n", __func__);
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
int mtk_drm_dal_setscreencolor(enum DAL_COLOR color)
|
|
{
|
|
u32 i, size, bg_color, offset;
|
|
struct MFC_CONTEXT *ctxt;
|
|
u32 *addr;
|
|
|
|
color = RGB888_To_RGB565(color);
|
|
bg_color = MAKE_TWO_RGB565_COLOR(color, color);
|
|
|
|
ctxt = (struct MFC_CONTEXT *)mfc_handle;
|
|
if (!ctxt)
|
|
return -1;
|
|
if (ctxt->screen_color == color)
|
|
return 0;
|
|
|
|
offset = MFC_Get_Cursor_Offset(mfc_handle);
|
|
addr = (u32 *)(ctxt->fb_addr + offset);
|
|
|
|
size = DAL_GetLayerSize();
|
|
if (!size) {
|
|
DDPPR_ERR("%s wrong fb size\n", __func__);
|
|
return 0;
|
|
}
|
|
size -= offset;
|
|
|
|
for (i = 0; i < size / sizeof(u32); ++i)
|
|
*addr++ = bg_color;
|
|
ctxt->screen_color = color;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int DAL_SetScreenColor(enum DAL_COLOR color)
|
|
{
|
|
uint32_t i;
|
|
uint32_t size;
|
|
uint32_t bg_color;
|
|
struct MFC_CONTEXT *ctxt = NULL;
|
|
uint32_t offset;
|
|
unsigned int *addr;
|
|
|
|
if (!mfc_handle)
|
|
return -1;
|
|
|
|
color = RGB888_To_RGB565(color);
|
|
bg_color = MAKE_TWO_RGB565_COLOR(color, color);
|
|
|
|
ctxt = (struct MFC_CONTEXT *)mfc_handle;
|
|
if (!ctxt)
|
|
return -1;
|
|
if (ctxt->screen_color == color)
|
|
return 0;
|
|
|
|
offset = MFC_Get_Cursor_Offset(mfc_handle);
|
|
addr = (unsigned int *)(ctxt->fb_addr + offset);
|
|
|
|
size = DAL_GetLayerSize();
|
|
if (!size) {
|
|
DDPPR_ERR("%s wrong fb size\n", __func__);
|
|
return 0;
|
|
}
|
|
size -= offset;
|
|
|
|
for (i = 0; i < size / sizeof(uint32_t); ++i)
|
|
*addr++ = bg_color;
|
|
ctxt->screen_color = color;
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(DAL_SetScreenColor);
|
|
|
|
int DAL_SetColor(unsigned int fgColor, unsigned int bgColor)
|
|
{
|
|
if (!mfc_handle)
|
|
return -1;
|
|
|
|
DAL_LOCK();
|
|
MFC_SetColor(mfc_handle, RGB888_To_RGB565(fgColor),
|
|
RGB888_To_RGB565(bgColor));
|
|
DAL_UNLOCK();
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(DAL_SetColor);
|
|
|
|
static struct mtk_ddp_comp *_handle_phy_top_plane(struct mtk_drm_crtc *mtk_crtc)
|
|
{
|
|
int i, j, type;
|
|
int lay_num;
|
|
struct drm_plane *plane;
|
|
struct mtk_plane_state *plane_state;
|
|
struct mtk_plane_comp_state comp_state;
|
|
struct mtk_ddp_comp *ovl_comp = NULL;
|
|
struct mtk_ddp_comp *comp;
|
|
|
|
for_each_comp_in_cur_crtc_path(comp, mtk_crtc, i, j) {
|
|
type = mtk_ddp_comp_get_type(comp->id);
|
|
if (type == MTK_DISP_OVL)
|
|
ovl_comp = comp;
|
|
else if (type == MTK_DISP_RDMA)
|
|
break;
|
|
}
|
|
|
|
if (ovl_comp == NULL) {
|
|
DDPPR_ERR("No proper ovl module in CRTC %s\n",
|
|
mtk_crtc->base.name);
|
|
return NULL;
|
|
}
|
|
|
|
lay_num = mtk_ovl_layer_num(ovl_comp);
|
|
if (lay_num < 0) {
|
|
DDPPR_ERR("invalid layer number:%d\n", lay_num);
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0 ; i < mtk_crtc->layer_nr; ++i) {
|
|
plane = &mtk_crtc->planes[i].base;
|
|
plane_state = to_mtk_plane_state(plane->state);
|
|
comp_state = plane_state->comp_state;
|
|
|
|
/*find been cascaded ovl comp */
|
|
if (comp_state.comp_id == ovl_comp->id &&
|
|
comp_state.lye_id == lay_num - 1) {
|
|
plane_state->pending.enable = false;
|
|
plane_state->pending.dirty = 1;
|
|
}
|
|
}
|
|
|
|
return ovl_comp;
|
|
}
|
|
|
|
#ifndef MTK_DRM_FB_LEAK
|
|
static void mtk_drm_cmdq_done(struct cmdq_cb_data data)
|
|
{
|
|
struct cmdq_pkt *cmdq_handle = data.data;
|
|
cmdq_pkt_destroy(cmdq_handle);
|
|
}
|
|
#endif
|
|
|
|
static struct mtk_plane_state *drm_set_dal_plane_state(struct drm_crtc *crtc,
|
|
bool enable)
|
|
{
|
|
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
|
|
struct drm_plane *plane;
|
|
struct mtk_plane_state *plane_state;
|
|
struct mtk_plane_pending_state *pending;
|
|
struct mtk_ddp_comp *ovl_comp = _handle_phy_top_plane(mtk_crtc);
|
|
struct MFC_CONTEXT *ctxt = (struct MFC_CONTEXT *)mfc_handle;
|
|
int layer_id = -1;
|
|
|
|
if (ovl_comp)
|
|
layer_id = mtk_ovl_layer_num(ovl_comp) - 1;
|
|
|
|
if (!ctxt) {
|
|
DDPPR_ERR("%s MFC_CONTEXT is NULL\n", __func__);
|
|
return NULL;
|
|
}
|
|
if (layer_id < 0) {
|
|
DDPPR_ERR("%s invalid layer id:%d\n", __func__, layer_id);
|
|
return NULL;
|
|
}
|
|
|
|
plane = &mtk_crtc->planes[mtk_crtc->layer_nr - 1].base;
|
|
plane_state = to_mtk_plane_state(plane->state);
|
|
pending = &plane_state->pending;
|
|
|
|
plane_state->pending.addr = dal_pa;
|
|
plane_state->pending.pitch = ctxt->fb_width * DAL_BPP;
|
|
plane_state->pending.format = DRM_FORMAT_RGB565;
|
|
plane_state->pending.src_x = 0;
|
|
plane_state->pending.src_y = 0;
|
|
plane_state->pending.dst_x = 0;
|
|
plane_state->pending.dst_y = 0;
|
|
plane_state->pending.height = ctxt->fb_height;
|
|
plane_state->pending.width = ctxt->fb_width;
|
|
plane_state->pending.config = 1;
|
|
plane_state->pending.dirty = 1;
|
|
plane_state->pending.enable = !!enable;
|
|
plane_state->pending.is_sec = false;
|
|
|
|
pending->prop_val[PLANE_PROP_ALPHA_CON] = 0x1;
|
|
pending->prop_val[PLANE_PROP_PLANE_ALPHA] = 0x80;
|
|
pending->prop_val[PLANE_PROP_COMPRESS] = 0;
|
|
|
|
plane_state->comp_state.comp_id = ovl_comp->id;
|
|
plane_state->comp_state.lye_id = layer_id;
|
|
plane_state->comp_state.ext_lye_id = 0;
|
|
plane_state->base.crtc = crtc;
|
|
|
|
return plane_state;
|
|
}
|
|
|
|
static void disable_attached_layer(struct drm_crtc *crtc, struct mtk_ddp_comp *ovl_comp,
|
|
int layer_id, struct cmdq_pkt *cmdq_handle)
|
|
{
|
|
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
|
|
int i;
|
|
|
|
for (i = 0; i < mtk_crtc->layer_nr; i++) {
|
|
struct mtk_drm_private *priv = crtc->dev->dev_private;
|
|
struct drm_plane *plane = &mtk_crtc->planes[i].base;
|
|
struct mtk_plane_state *plane_state;
|
|
struct mtk_ddp_comp *comp;
|
|
unsigned int ext_lye_id;
|
|
|
|
plane_state = to_mtk_plane_state(plane->state);
|
|
if (i >= OVL_PHY_LAYER_NR && !plane_state->comp_state.comp_id)
|
|
continue;
|
|
comp = priv->ddp_comp[plane_state->comp_state.comp_id];
|
|
|
|
if (comp == NULL)
|
|
continue;
|
|
|
|
if (comp == ovl_comp && plane_state->comp_state.lye_id &&
|
|
plane_state->comp_state.lye_id == layer_id &&
|
|
plane_state->comp_state.ext_lye_id) {
|
|
DDPINFO("plane %d comp_id %u lye_id %u ext_id %u\n",
|
|
i, plane_state->comp_state.comp_id,
|
|
plane_state->comp_state.lye_id,
|
|
plane_state->comp_state.ext_lye_id);
|
|
ext_lye_id = plane_state->comp_state.ext_lye_id;
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
if (mtk_crtc->is_dual_pipe) {
|
|
struct mtk_drm_private *priv = mtk_crtc->base.dev->dev_private;
|
|
struct mtk_ddp_comp *r_comp;
|
|
unsigned int comp_id = plane_state->comp_state.comp_id;
|
|
|
|
|
|
r_comp = priv->ddp_comp[dual_pipe_comp_mapping(comp_id)];
|
|
mtk_ddp_comp_layer_off(r_comp, layer_id,
|
|
ext_lye_id, cmdq_handle);
|
|
}
|
|
mtk_ddp_comp_layer_off(comp, layer_id, ext_lye_id, cmdq_handle);
|
|
}
|
|
}
|
|
|
|
int drm_show_dal(struct drm_crtc *crtc, bool enable)
|
|
{
|
|
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
|
|
struct mtk_plane_state *plane_state;
|
|
struct mtk_ddp_comp *ovl_comp = _handle_phy_top_plane(mtk_crtc);
|
|
struct cmdq_pkt *cmdq_handle;
|
|
int layer_id;
|
|
|
|
if (ovl_comp == NULL) {
|
|
DDPPR_ERR("%s: can't find ovl comp\n", __func__);
|
|
return 0;
|
|
}
|
|
layer_id = mtk_ovl_layer_num(ovl_comp) - 1;
|
|
if (layer_id < 0) {
|
|
DDPPR_ERR("%s invalid layer id:%d\n", __func__, layer_id);
|
|
return 0;
|
|
}
|
|
|
|
DDP_MUTEX_LOCK(&mtk_crtc->lock, __func__, __LINE__);
|
|
if (!mtk_crtc->enabled) {
|
|
DDP_MUTEX_UNLOCK(&mtk_crtc->lock, __func__, __LINE__);
|
|
return 0;
|
|
}
|
|
|
|
plane_state = drm_set_dal_plane_state(crtc, enable);
|
|
if (!plane_state) {
|
|
DDPPR_ERR("%s: can't set dal plane_state\n", __func__);
|
|
DDP_MUTEX_UNLOCK(&mtk_crtc->lock, __func__, __LINE__);
|
|
return 0;
|
|
}
|
|
|
|
mtk_drm_idlemgr_kick(__func__, crtc, 0);
|
|
|
|
/* set DAL config and trigger display */
|
|
cmdq_handle = mtk_crtc_gce_commit_begin(crtc);
|
|
|
|
disable_attached_layer(crtc, ovl_comp, layer_id, cmdq_handle);
|
|
|
|
if (mtk_crtc->is_dual_pipe) {
|
|
mtk_crtc_dual_layer_config(mtk_crtc, ovl_comp, layer_id, plane_state, cmdq_handle);
|
|
} else {
|
|
mtk_ddp_comp_layer_config(ovl_comp, layer_id, plane_state, cmdq_handle);
|
|
}
|
|
|
|
plane_state->base.crtc = NULL;
|
|
|
|
#ifdef MTK_DRM_FB_LEAK
|
|
mtk_crtc_gce_flush(crtc, NULL, cmdq_handle, cmdq_handle);
|
|
cmdq_pkt_wait_complete(cmdq_handle);
|
|
cmdq_pkt_destroy(cmdq_handle);
|
|
#else
|
|
mtk_crtc_gce_flush(crtc, mtk_drm_cmdq_done, cmdq_handle, cmdq_handle);
|
|
#endif
|
|
DDP_MUTEX_UNLOCK(&mtk_crtc->lock, __func__, __LINE__);
|
|
return 0;
|
|
}
|
|
|
|
void drm_set_dal(struct drm_crtc *crtc, struct cmdq_pkt *cmdq_handle)
|
|
{
|
|
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
|
|
struct mtk_plane_state *plane_state;
|
|
struct mtk_ddp_comp *ovl_comp = _handle_phy_top_plane(mtk_crtc);
|
|
int layer_id;
|
|
|
|
if (ovl_comp == NULL) {
|
|
DDPPR_ERR("%s: can't find ovl comp\n", __func__);
|
|
return;
|
|
}
|
|
layer_id = mtk_ovl_layer_num(ovl_comp) - 1;
|
|
if (layer_id < 0) {
|
|
DDPPR_ERR("%s invalid layer id:%d\n", __func__, layer_id);
|
|
return;
|
|
}
|
|
|
|
plane_state = drm_set_dal_plane_state(crtc, true);
|
|
if (!plane_state) {
|
|
DDPPR_ERR("%s: can't set dal plane_state\n", __func__);
|
|
return;
|
|
}
|
|
|
|
disable_attached_layer(crtc, ovl_comp, layer_id, cmdq_handle);
|
|
|
|
if (mtk_crtc->is_dual_pipe) {
|
|
mtk_crtc_dual_layer_config(mtk_crtc, ovl_comp, layer_id, plane_state, cmdq_handle);
|
|
} else {
|
|
mtk_ddp_comp_layer_config(ovl_comp, layer_id, plane_state, cmdq_handle);
|
|
}
|
|
|
|
plane_state->base.crtc = NULL;
|
|
}
|
|
|
|
int DAL_Clean(void)
|
|
{
|
|
struct MFC_CONTEXT *ctxt = (struct MFC_CONTEXT *)mfc_handle;
|
|
|
|
if (!mfc_handle)
|
|
return 0;
|
|
|
|
DAL_LOCK();
|
|
if (MFC_ResetCursor(mfc_handle) != MFC_STATUS_OK)
|
|
goto end;
|
|
|
|
ctxt->screen_color = 0;
|
|
DAL_SetScreenColor(DAL_COLOR_RED);
|
|
|
|
if (drm_dal_enable == 1) {
|
|
drm_dal_enable = 0;
|
|
drm_show_dal(dal_crtc, false);
|
|
}
|
|
|
|
end:
|
|
DAL_UNLOCK();
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(DAL_Clean);
|
|
|
|
int DAL_Printf(const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
u32 i;
|
|
|
|
if (!mfc_handle)
|
|
return -1;
|
|
if (!fmt)
|
|
return -1;
|
|
|
|
DAL_LOCK();
|
|
|
|
va_start(args, fmt);
|
|
i = vsprintf(drm_dal_str_buf, fmt, args);
|
|
va_end(args);
|
|
|
|
if (i >= DAL_STR_BUF_LEN) {
|
|
DDPPR_ERR("%s, string size %u exceed limit\n", __func__, i);
|
|
return -1;
|
|
}
|
|
|
|
MFC_Print(mfc_handle, drm_dal_str_buf);
|
|
|
|
if (drm_dal_enable == 0)
|
|
drm_dal_enable = 1;
|
|
|
|
#ifdef CONFIG_MTK_DISPLAY_CMDQ
|
|
drm_show_dal(dal_crtc, true);
|
|
#endif
|
|
|
|
DAL_UNLOCK();
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(DAL_Printf);
|
|
|
|
int mtk_drm_dal_enable(void)
|
|
{
|
|
return drm_dal_enable;
|
|
}
|
|
|
|
void mtk_drm_assert_fb_init(struct drm_device *dev, u32 width, u32 height)
|
|
{
|
|
struct mtk_drm_gem_obj *mtk_gem;
|
|
u32 size = width * height * DAL_BPP;
|
|
|
|
mtk_gem = mtk_drm_gem_create(dev, size, true);
|
|
if (IS_ERR(mtk_gem)) {
|
|
DDPINFO("alloc buffer fail\n");
|
|
return;
|
|
}
|
|
//Avoid kmemleak to scan
|
|
kmemleak_ignore(mtk_gem);
|
|
|
|
dal_va = mtk_gem->kvaddr;
|
|
dal_pa = mtk_gem->dma_addr;
|
|
|
|
MFC_Open(&mfc_handle, mtk_gem->kvaddr, width, height, DAL_BPP,
|
|
RGB888_To_RGB565(DAL_COLOR_WHITE),
|
|
RGB888_To_RGB565(DAL_COLOR_RED), mtk_gem->base.filp);
|
|
}
|
|
|
|
int mtk_drm_assert_layer_init(struct drm_crtc *crtc)
|
|
{
|
|
if (!dal_pa || !dal_va) {
|
|
DDPPR_ERR("init DAL without proper buffer\n");
|
|
return -1;
|
|
}
|
|
|
|
dal_crtc = crtc;
|
|
DAL_SetScreenColor(DAL_COLOR_RED);
|
|
|
|
return 0;
|
|
}
|