437 lines
12 KiB
C
437 lines
12 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright (c) 2019 MediaTek Inc.
|
|
*/
|
|
|
|
|
|
#include <linux/delay.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/semaphore.h>
|
|
#include <linux/module.h>
|
|
#include <linux/wait.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/types.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_irq.h>
|
|
|
|
#include "disp_drv_log.h"
|
|
#include "primary_display.h"
|
|
|
|
#include "mtk_boot.h"
|
|
#include "disp_helper.h"
|
|
#include "disp_drv_platform.h"
|
|
#include "primary_display.h"
|
|
#include "mt-plat/mtk_chip.h"
|
|
|
|
/* use this magic_code to detect memory corruption */
|
|
#define MAGIC_CODE 0xDEADAAA0U
|
|
|
|
#ifdef CONFIG_FPGA_EARLY_PORTING
|
|
static unsigned int disp_global_stage =
|
|
MAGIC_CODE | DISP_HELPER_STAGE_EARLY_PORTING;
|
|
#else
|
|
/* please change this to DISP_HELPER_STAGE_NORMAL after bring up done */
|
|
#if 1
|
|
static unsigned int disp_global_stage =
|
|
MAGIC_CODE | DISP_HELPER_STAGE_BRING_UP;
|
|
#else
|
|
|
|
static unsigned int disp_global_stage =
|
|
MAGIC_CODE | DISP_HELPER_STAGE_NORMAL;
|
|
#endif
|
|
#endif
|
|
|
|
static unsigned int _is_early_porting_stage(void)
|
|
{
|
|
return (disp_global_stage & (~MAGIC_CODE)) ==
|
|
DISP_HELPER_STAGE_EARLY_PORTING;
|
|
}
|
|
|
|
static unsigned int _is_bringup_stage(void)
|
|
{
|
|
return (disp_global_stage & (~MAGIC_CODE)) ==
|
|
DISP_HELPER_STAGE_BRING_UP;
|
|
}
|
|
|
|
static unsigned int _is_normal_stage(void)
|
|
{
|
|
return (disp_global_stage & (~MAGIC_CODE)) == DISP_HELPER_STAGE_NORMAL;
|
|
}
|
|
|
|
static struct {
|
|
enum DISP_HELPER_OPT opt;
|
|
unsigned int val;
|
|
const char *desc;
|
|
} help_info[] = {
|
|
{DISP_OPT_USE_CMDQ, 0, "DISP_OPT_USE_CMDQ"}, /* must enable */
|
|
{DISP_OPT_USE_M4U, 0, "DISP_OPT_USE_M4U"}, /* must enable */
|
|
{DISP_OPT_MIPITX_ON_CHIP, 0,
|
|
"DISP_OPT_MIPITX_ON_CHIP"}, /* not use now */
|
|
{DISP_OPT_USE_DEVICE_TREE, 0,
|
|
"DISP_OPT_USE_DEVICE_TREE"}, /* not use now */
|
|
{DISP_OPT_FAKE_LCM_X, 0, "DISP_OPT_FAKE_LCM_X"},
|
|
{DISP_OPT_FAKE_LCM_Y, 0, "DISP_OPT_FAKE_LCM_Y"},
|
|
{DISP_OPT_FAKE_LCM_WIDTH, 0, "DISP_OPT_FAKE_LCM_WIDTH"},
|
|
{DISP_OPT_FAKE_LCM_HEIGHT, 0, "DISP_OPT_FAKE_LCM_HEIGHT"},
|
|
{DISP_OPT_OVL_WARM_RESET, 0,
|
|
"DISP_OPT_OVL_WARM_RESET"}, /* not use now */
|
|
{DISP_OPT_DYNAMIC_SWITCH_UNDERFLOW_EN, 0,
|
|
"DISP_OPT_DYNAMIC_SWITCH_UNDERFLOW_EN"}, /* not use now */
|
|
{DISP_OPT_SODI_SUPPORT, 0, "DISP_OPT_SODI_SUPPORT"}, /* low power */
|
|
{DISP_OPT_IDLE_MGR, 0, "DISP_OPT_IDLE_MGR"}, /* low power */
|
|
{DISP_OPT_IDLEMGR_SWTCH_DECOUPLE, 0,
|
|
"DISP_OPT_IDLEMGR_SWTCH_DECOUPLE"}, /* low power */
|
|
{DISP_OPT_IDLEMGR_ENTER_ULPS, 0,
|
|
"DISP_OPT_IDLEMGR_ENTER_ULPS"}, /* low power */
|
|
{DISP_OPT_SHARE_SRAM, 0, "DISP_OPT_SHARE_SRAM"}, /* low power */
|
|
{DISP_OPT_DYNAMIC_SWITCH_MMSYSCLK, 0,
|
|
"DISP_OPT_DYNAMIC_SWITCH_MMSYSCLK"}, /* low power */
|
|
{DISP_OPT_DYNAMIC_RDMA_GOLDEN_SETTING, 0,
|
|
"DISP_OPT_DYNAMIC_RDMA_GOLDEN_SETTING"}, /* low power */
|
|
{DISP_OPT_IDLEMGR_DISABLE_ROUTINE_IRQ, 0,
|
|
"DISP_OPT_IDLEMGR_DISABLE_ROUTINE_IRQ"}, /* low power */
|
|
{DISP_OPT_MET_LOG, 0, "DISP_OPT_MET_LOG"}, /* low power */
|
|
{DISP_OPT_DECOUPLE_MODE_USE_RGB565, 0,
|
|
"DISP_OPT_DECOUPLE_MODE_USE_RGB565"}, /* not use now */
|
|
{DISP_OPT_NO_LCM_FOR_LOW_POWER_MEASUREMENT, 0,
|
|
"DISP_OPT_NO_LCM_FOR_LOW_POWER_MEASUREMENT"},
|
|
{DISP_OPT_NO_LK, 0, "DISP_OPT_NO_LK"}, /* not use now */
|
|
{DISP_OPT_BYPASS_PQ, 1, "DISP_OPT_BYPASS_PQ"},
|
|
{DISP_OPT_ESD_CHECK_RECOVERY, 0, "DISP_OPT_ESD_CHECK_RECOVERY"},
|
|
{DISP_OPT_ESD_CHECK_SWITCH, 0, "DISP_OPT_ESD_CHECK_SWITCH"},
|
|
{DISP_OPT_PRESENT_FENCE, 1, "DISP_OPT_PRESENT_FENCE"},
|
|
{DISP_OPT_PERFORMANCE_DEBUG, 0, "DISP_OPT_PERFORMANCE_DEBUG"},
|
|
{DISP_OPT_SWITCH_DST_MODE, 0, "DISP_OPT_SWITCH_DST_MODE"},
|
|
{DISP_OPT_MUTEX_EOF_EN_FOR_CMD_MODE, 1,
|
|
"DISP_OPT_MUTEX_EOF_EN_FOR_CMD_MODE"},
|
|
{DISP_OPT_SCREEN_CAP_FROM_DITHER, 0, "DISP_OPT_SCREEN_CAP_FROM_DITHER"},
|
|
{DISP_OPT_BYPASS_OVL, 0, "DISP_OPT_BYPASS_OVL"},
|
|
{DISP_OPT_FPS_CALC_WND, 10, "DISP_OPT_FPS_CALC_WND"},
|
|
{DISP_OPT_FPS_EXT, 0, "DISP_OPT_FPS_EXT"},
|
|
{DISP_OPT_FPS_EXT_INTERVAL, 0, "DISP_OPT_FPS_EXT_INTERVAL"},
|
|
{DISP_OPT_SMART_OVL, 0, "DISP_OPT_SMART_OVL"},
|
|
{DISP_OPT_DYNAMIC_DEBUG, 0, "DISP_OPT_DYNAMIC_DEBUG"}, /* not use now */
|
|
{DISP_OPT_SHOW_VISUAL_DEBUG_INFO, 0, "DISP_OPT_SHOW_VISUAL_DEBUG_INFO"},
|
|
{DISP_OPT_RDMA_UNDERFLOW_AEE, 0, "DISP_OPT_RDMA_UNDERFLOW_AEE"},
|
|
{DISP_OPT_DSI_UNDERRUN_AEE, 0, "DISP_OPT_DSI_UNDERRUN_AEE"},
|
|
{DISP_OPT_HRT, 1, "DISP_OPT_HRT"},
|
|
{DISP_OPT_PARTIAL_UPDATE, 0, "DISP_OPT_PARTIAL_UPDATE"},
|
|
{DISP_OPT_CV_BYSUSPEND, 0, "DISP_OPT_CV_BYSUSPEND"},
|
|
{DISP_OPT_DELAYED_TRIGGER, 0, "DISP_OPT_DELAYED_TRIGGER"},
|
|
{DISP_OPT_SHADOW_REGISTER, 0, "DISP_OPT_SHADOW_REGISTER"},
|
|
{DISP_OPT_SHADOW_MODE, 0, "DISP_OPT_SHADOW_MODE"},
|
|
{DISP_OPT_OVL_EXT_LAYER, 0, "DISP_OPT_OVL_EXT_LAYER"},
|
|
{DISP_OPT_REG_PARSER_RAW_DUMP, 0, "DISP_OPT_REG_PARSER_RAW_DUMP"},
|
|
{DISP_OPT_AOD, 0, "DISP_OPT_AOD"},
|
|
{DISP_OPT_ARR_PHASE_1, 0, "DISP_OPT_ARR_PHASE_1"},
|
|
{DISP_OPT_RSZ, 0, "DISP_OPT_RSZ"},
|
|
{DISP_OPT_RPO, 0, "DISP_OPT_RPO"},
|
|
{DISP_OPT_DUAL_PIPE, 0, "DISP_OPT_DUAL_PIPE"},
|
|
{DISP_OPT_SHARE_WDMA0, 0, "DISP_OPT_SHARE_WDMA0"},
|
|
{DISP_OPT_FRAME_QUEUE, 0, "DISP_OPT_FRAME_QUEUE"},
|
|
{DISP_OPT_ROUND_CORNER, 0, "DISP_OPT_ROUND_CORNER"},
|
|
{DISP_OPT_ROUND_CORNER_MODE, DISP_HELPER_SW_RC,
|
|
"DISP_OPT_ROUND_CORNER_MODE"},
|
|
{DISP_OPT_OVL_SBCH, 0, "DISP_OPT_OVL_SBCH"},
|
|
{DISP_OPT_GMO_OPTIMIZE, 0, "DISP_OPT_GMO_OPTIMIZE"},
|
|
{DISP_OPT_TUI_MODE, 0, "DISP_OPT_TUI_MODE"},
|
|
};
|
|
|
|
const char *disp_helper_option_spy(enum DISP_HELPER_OPT option)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(help_info); i++) {
|
|
if (help_info[i].opt == option)
|
|
return help_info[i].desc;
|
|
}
|
|
|
|
return "unknown option!!";
|
|
}
|
|
|
|
enum DISP_HELPER_OPT disp_helper_name_to_opt(const char *name)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < DISP_OPT_NUM; i++) {
|
|
const char *opt_name = disp_helper_option_spy(i);
|
|
|
|
if (strcmp(name, opt_name) == 0)
|
|
return i;
|
|
}
|
|
DISPWARN("%s: unknown name: %s\n", __func__, name);
|
|
return DISP_OPT_NUM;
|
|
}
|
|
|
|
int disp_helper_set_option(enum DISP_HELPER_OPT option, int value)
|
|
{
|
|
int ret;
|
|
unsigned int i;
|
|
|
|
if (option == DISP_OPT_FPS_CALC_WND) {
|
|
ret = primary_fps_ctx_set_wnd_sz(value);
|
|
if (ret) {
|
|
DISPWARN("%s error to set fps_wnd_sz to %d\n",
|
|
__func__, value);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
if (option >= DISP_OPT_NUM) {
|
|
DISPWARN("Wrong option: %d\n", option);
|
|
return -EINVAL;
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(help_info); i++) {
|
|
if (help_info[i].opt == option && help_info[i].val != value) {
|
|
DISPCHECK("Set Option %d(%s) from (%d) to (%d)\n",
|
|
option, disp_helper_option_spy(option),
|
|
disp_helper_get_option(option), value);
|
|
|
|
help_info[i].val = value;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int disp_helper_set_option_by_name(const char *name, int value)
|
|
{
|
|
enum DISP_HELPER_OPT opt;
|
|
|
|
opt = disp_helper_name_to_opt(name);
|
|
if (opt >= DISP_OPT_NUM)
|
|
return -1;
|
|
|
|
return disp_helper_set_option(opt, value);
|
|
}
|
|
|
|
int disp_helper_get_option(enum DISP_HELPER_OPT option)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (option >= DISP_OPT_NUM) {
|
|
DISPWARN("%s: option invalid %d\n", __func__, option);
|
|
return -1;
|
|
}
|
|
|
|
switch (option) {
|
|
case DISP_OPT_MIPITX_ON_CHIP:
|
|
{
|
|
if (_is_normal_stage())
|
|
return 1;
|
|
else if (_is_bringup_stage())
|
|
return 1;
|
|
else if (_is_early_porting_stage())
|
|
return 0;
|
|
|
|
DISPWARN("%s,get option MIPITX fail\n", __FILE__);
|
|
return -1;
|
|
}
|
|
case DISP_OPT_FAKE_LCM_X:
|
|
{
|
|
int x = 0;
|
|
|
|
#ifdef CONFIG_CUSTOM_LCM_X
|
|
ret = kstrtoint(CONFIG_CUSTOM_LCM_X, 0, &x);
|
|
if (ret) {
|
|
pr_info("%s error to parse x: %s\n",
|
|
__func__, CONFIG_CUSTOM_LCM_X);
|
|
x = 0;
|
|
}
|
|
#endif
|
|
return x;
|
|
}
|
|
case DISP_OPT_FAKE_LCM_Y:
|
|
{
|
|
int y = 0;
|
|
|
|
#ifdef CONFIG_CUSTOM_LCM_Y
|
|
ret = kstrtoint(CONFIG_CUSTOM_LCM_Y, 0, &y);
|
|
if (ret) {
|
|
pr_info("%s error to parse x: %s\n",
|
|
__func__, CONFIG_CUSTOM_LCM_Y);
|
|
y = 0;
|
|
}
|
|
|
|
#endif
|
|
return y;
|
|
}
|
|
case DISP_OPT_FAKE_LCM_WIDTH:
|
|
{
|
|
int w = primary_display_get_virtual_width();
|
|
|
|
if (w == 0)
|
|
w = DISP_GetScreenWidth();
|
|
return w;
|
|
}
|
|
case DISP_OPT_FAKE_LCM_HEIGHT:
|
|
{
|
|
int h = primary_display_get_virtual_height();
|
|
|
|
if (h == 0)
|
|
h = DISP_GetScreenHeight();
|
|
return h;
|
|
}
|
|
case DISP_OPT_NO_LK:
|
|
{
|
|
return 1;
|
|
}
|
|
case DISP_OPT_PERFORMANCE_DEBUG:
|
|
{
|
|
if (_is_normal_stage())
|
|
return 0;
|
|
else if (_is_bringup_stage())
|
|
return 0;
|
|
else if (_is_early_porting_stage())
|
|
return 0;
|
|
}
|
|
case DISP_OPT_SWITCH_DST_MODE:
|
|
{
|
|
if (_is_normal_stage())
|
|
return 0;
|
|
else if (_is_bringup_stage())
|
|
return 0;
|
|
else if (_is_early_porting_stage())
|
|
return 0;
|
|
else
|
|
return 0;
|
|
}
|
|
default:
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(help_info); i++) {
|
|
if (help_info[i].opt == option)
|
|
return help_info[i].val;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
enum DISP_HELPER_STAGE disp_helper_get_stage(void)
|
|
{
|
|
return disp_global_stage & (~MAGIC_CODE);
|
|
}
|
|
|
|
const char *disp_helper_stage_spy(void)
|
|
{
|
|
if (disp_helper_get_stage() == DISP_HELPER_STAGE_EARLY_PORTING)
|
|
return "EARLY_PORTING";
|
|
else if (disp_helper_get_stage() == DISP_HELPER_STAGE_BRING_UP)
|
|
return "BRINGUP";
|
|
else if (disp_helper_get_stage() == DISP_HELPER_STAGE_NORMAL)
|
|
return "NORMAL";
|
|
|
|
return "UNKNOWN";
|
|
}
|
|
|
|
void disp_helper_option_init(void)
|
|
{
|
|
disp_helper_set_option(DISP_OPT_USE_CMDQ, 0);
|
|
disp_helper_set_option(DISP_OPT_USE_M4U, 0);
|
|
|
|
/* test solution for 6795 rdma underflow caused by ufoe LR mode
|
|
* (ufoe fifo is larger than rdma)
|
|
*/
|
|
disp_helper_set_option(DISP_OPT_DYNAMIC_SWITCH_UNDERFLOW_EN, 0);
|
|
|
|
/* warm reset ovl before each trigger for cmd mode */
|
|
disp_helper_set_option(DISP_OPT_OVL_WARM_RESET, 0);
|
|
|
|
/* =================Begin: lowpower option setting================= */
|
|
disp_helper_set_option(DISP_OPT_SODI_SUPPORT, 0);
|
|
disp_helper_set_option(DISP_OPT_IDLE_MGR, 0);
|
|
|
|
/* 1. vdo mode + screen idle(need idlemgr) */
|
|
disp_helper_set_option(DISP_OPT_IDLEMGR_SWTCH_DECOUPLE, 0);
|
|
disp_helper_set_option(DISP_OPT_SHARE_SRAM, 0);
|
|
disp_helper_set_option(DISP_OPT_IDLEMGR_DISABLE_ROUTINE_IRQ, 0);
|
|
|
|
/* 2. cmd mode + screen idle(need idlemgr) */
|
|
disp_helper_set_option(DISP_OPT_IDLEMGR_ENTER_ULPS, 0);
|
|
|
|
/* 3. cmd mode + vdo mode */
|
|
disp_helper_set_option(DISP_OPT_DYNAMIC_SWITCH_MMSYSCLK, 0);
|
|
disp_helper_set_option(DISP_OPT_DYNAMIC_RDMA_GOLDEN_SETTING, 1);
|
|
|
|
disp_helper_set_option(DISP_OPT_MET_LOG, 0);
|
|
/* =================End: lowpower option setting=================== */
|
|
|
|
disp_helper_set_option(DISP_OPT_PRESENT_FENCE, 0);
|
|
|
|
/* use fake vsync timer for low power measurement */
|
|
disp_helper_set_option(DISP_OPT_NO_LCM_FOR_LOW_POWER_MEASUREMENT, 0);
|
|
|
|
/* use RGB565 format for decouple mode intermediate buffer */
|
|
disp_helper_set_option(DISP_OPT_DECOUPLE_MODE_USE_RGB565, 0);
|
|
|
|
disp_helper_set_option(DISP_OPT_BYPASS_PQ, 1);
|
|
disp_helper_set_option(DISP_OPT_MUTEX_EOF_EN_FOR_CMD_MODE, 1);
|
|
disp_helper_set_option(DISP_OPT_ESD_CHECK_RECOVERY, 0);
|
|
disp_helper_set_option(DISP_OPT_ESD_CHECK_SWITCH, 0);
|
|
|
|
disp_helper_set_option(DISP_OPT_BYPASS_OVL, 0);
|
|
disp_helper_set_option(DISP_OPT_FPS_CALC_WND, 10);
|
|
/* report external fps statistics */
|
|
disp_helper_set_option(DISP_OPT_FPS_EXT, 0);
|
|
/* set external fps interval (ms) */
|
|
disp_helper_set_option(DISP_OPT_FPS_EXT_INTERVAL, 1000);
|
|
disp_helper_set_option(DISP_OPT_SMART_OVL, 0);
|
|
disp_helper_set_option(DISP_OPT_DYNAMIC_DEBUG, 0);
|
|
disp_helper_set_option(DISP_OPT_HRT, 0);
|
|
|
|
/* display partial update */
|
|
disp_helper_set_option(DISP_OPT_PARTIAL_UPDATE, 0);
|
|
|
|
disp_helper_set_option(DISP_OPT_CV_BYSUSPEND, 0);
|
|
disp_helper_set_option(DISP_OPT_DELAYED_TRIGGER, 0);
|
|
disp_helper_set_option(DISP_OPT_SHADOW_REGISTER, 0);
|
|
disp_helper_set_option(DISP_OPT_SHADOW_MODE, 0);
|
|
|
|
/* smart layer OVL*/
|
|
disp_helper_set_option(DISP_OPT_OVL_EXT_LAYER, 0);
|
|
|
|
disp_helper_set_option(DISP_OPT_REG_PARSER_RAW_DUMP, 0);
|
|
|
|
disp_helper_set_option(DISP_OPT_AOD, 0);
|
|
|
|
/* ARR phase 1 option*/
|
|
disp_helper_set_option(DISP_OPT_ARR_PHASE_1, 0);
|
|
/* HW does not support this */
|
|
disp_helper_set_option(DISP_OPT_RSZ, 0);
|
|
disp_helper_set_option(DISP_OPT_RPO, 0);
|
|
disp_helper_set_option(DISP_OPT_DUAL_PIPE, 0);
|
|
disp_helper_set_option(DISP_OPT_SHARE_WDMA0, 0);
|
|
disp_helper_set_option(DISP_OPT_FRAME_QUEUE, 0);
|
|
disp_helper_set_option(DISP_OPT_ROUND_CORNER, 0);
|
|
disp_helper_set_option(DISP_OPT_ROUND_CORNER_MODE, DISP_HELPER_HW_RC);
|
|
/* OVL SBCH */
|
|
disp_helper_set_option(DISP_OPT_OVL_SBCH, 0);
|
|
disp_helper_set_option(DISP_OPT_GMO_OPTIMIZE, 0);
|
|
disp_helper_set_option(DISP_OPT_DSI_UNDERRUN_AEE, 0);
|
|
disp_helper_set_option(DISP_OPT_RDMA_UNDERFLOW_AEE, 0);
|
|
disp_helper_set_option(DISP_OPT_TUI_MODE, 0);
|
|
}
|
|
|
|
int disp_helper_get_option_list(char *stringbuf, int buf_len)
|
|
{
|
|
int len = 0;
|
|
int i = 0;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(help_info); i++) {
|
|
if (stringbuf != NULL && buf_len > 0)
|
|
len += scnprintf(stringbuf + len, buf_len - len,
|
|
"Option: [%d][%s] Value: [%d]\n",
|
|
i, disp_helper_option_spy(i),
|
|
disp_helper_get_option(i));
|
|
}
|
|
|
|
return len;
|
|
}
|