412 lines
9.8 KiB
C
412 lines
9.8 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
|
||
|
|
|
||
|
|
/* CONFIG_MTK_FPGA is used in linux kernel for early porting. */
|
||
|
|
/* if the macro name changed, please modify the code here too. */
|
||
|
|
|
||
|
|
#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 */
|
||
|
|
|
||
|
|
/* static unsigned int disp_global_stage =
|
||
|
|
* MAGIC_CODE | DISP_HELPER_STAGE_BRING_UP;
|
||
|
|
*/
|
||
|
|
static unsigned int disp_global_stage = MAGIC_CODE | DISP_HELPER_STAGE_NORMAL;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#if 0 /* defined but not used */
|
||
|
|
static int _is_E1(void)
|
||
|
|
{
|
||
|
|
unsigned int ver = mt_get_chip_sw_ver();
|
||
|
|
|
||
|
|
if (ver == CHIP_SW_VER_01)
|
||
|
|
return 1;
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int _is_E2(void)
|
||
|
|
{
|
||
|
|
unsigned int ver = mt_get_chip_sw_ver();
|
||
|
|
|
||
|
|
if (ver == CHIP_SW_VER_02)
|
||
|
|
return 1;
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int _is_E3(void)
|
||
|
|
{
|
||
|
|
return !(_is_E1() || _is_E2());
|
||
|
|
}
|
||
|
|
#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 int _disp_helper_option_value[DISP_OPT_NUM] = {0};
|
||
|
|
|
||
|
|
const char *disp_helper_option_string[DISP_OPT_NUM] = {
|
||
|
|
"DISP_OPT_USE_CMDQ",
|
||
|
|
"DISP_OPT_USE_M4U",
|
||
|
|
"DISP_OPT_MIPITX_ON_CHIP",
|
||
|
|
"DISP_OPT_USE_DEVICE_TREE",
|
||
|
|
"DISP_OPT_FAKE_LCM_X",
|
||
|
|
"DISP_OPT_FAKE_LCM_Y",
|
||
|
|
"DISP_OPT_FAKE_LCM_WIDTH",
|
||
|
|
"DISP_OPT_FAKE_LCM_HEIGHT",
|
||
|
|
"DISP_OPT_OVL_WARM_RESET",
|
||
|
|
"DISP_OPT_DYNAMIC_SWITCH_UNDERFLOW_EN",
|
||
|
|
/* Begin: lowpower option*/
|
||
|
|
"DISP_OPT_SODI_SUPPORT",
|
||
|
|
"DISP_OPT_IDLE_MGR",
|
||
|
|
"DISP_OPT_IDLEMGR_SWTCH_DECOUPLE",
|
||
|
|
"DISP_OPT_IDLEMGR_ENTER_ULPS",
|
||
|
|
"DISP_OPT_SHARE_SRAM",
|
||
|
|
"DISP_OPT_DYNAMIC_SWITCH_MMSYSCLK",
|
||
|
|
"DISP_OPT_DYNAMIC_RDMA_GOLDEN_SETTING",
|
||
|
|
"DISP_OPT_IDLEMGR_DISABLE_ROUTINE_IRQ",
|
||
|
|
"DISP_OPT_MET_LOG", /* for met */
|
||
|
|
/* End: lowpower option */
|
||
|
|
"DISP_OPT_DECOUPLE_MODE_USE_RGB565",
|
||
|
|
"DISP_OPT_NO_LCM_FOR_LOW_POWER_MEASUREMENT",
|
||
|
|
"DISP_OPT_NO_LK",
|
||
|
|
"DISP_OPT_BYPASS_PQ",
|
||
|
|
"DISP_OPT_ESD_CHECK_RECOVERY",
|
||
|
|
"DISP_OPT_ESD_CHECK_SWITCH",
|
||
|
|
"DISP_OPT_PRESENT_FENCE",
|
||
|
|
"DISP_OPT_PERFORMANCE_DEBUG",
|
||
|
|
"DISP_OPT_SWITCH_DST_MODE",
|
||
|
|
"DISP_OPT_MUTEX_EOF_EN_FOR_CMD_MODE",
|
||
|
|
"DISP_OPT_SCREEN_CAP_FROM_DITHER",
|
||
|
|
"DISP_OPT_BYPASS_OVL",
|
||
|
|
"DISP_OPT_FPS_CALC_WND",
|
||
|
|
"DISP_OPT_SMART_OVL",
|
||
|
|
"DISP_OPT_DYNAMIC_DEBUG",
|
||
|
|
"DISP_OPT_SHOW_VISUAL_DEBUG_INFO",
|
||
|
|
"DISP_OPT_RDMA_UNDERFLOW_AEE",
|
||
|
|
"DISP_OPT_HRT",
|
||
|
|
"DISP_OPT_PARTIAL_UPDATE",
|
||
|
|
"DISP_OPT_CV_BYSUSPEND",
|
||
|
|
"DISP_OPT_DELAYED_TRIGGER",
|
||
|
|
"DISP_OPT_SHADOW_REGISTER",
|
||
|
|
"DISP_OPT_SHADOW_MODE",
|
||
|
|
"DISP_OPT_OVL_EXT_LAYER",
|
||
|
|
"DISP_OPT_REG_PARSER_RAW_DUMP",
|
||
|
|
"DISP_OPT_AOD",
|
||
|
|
"DISP_OPT_RSZ",
|
||
|
|
"DISP_OPT_DUAL_PIPE",
|
||
|
|
"DISP_OPT_ARR_PHASE_1",
|
||
|
|
"DISP_OPT_GMO_OPTIMIZE",
|
||
|
|
"DISP_OPT_MIRROR_MODE_FROCE_DISABLE_SODI",
|
||
|
|
};
|
||
|
|
|
||
|
|
const char *disp_helper_option_spy(enum DISP_HELPER_OPT option)
|
||
|
|
{
|
||
|
|
unsigned int idx = (unsigned int)option;
|
||
|
|
if (option >= DISP_OPT_NUM)
|
||
|
|
return "unknown option!!";
|
||
|
|
return disp_helper_option_string[idx];
|
||
|
|
}
|
||
|
|
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
DISPERR("%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;
|
||
|
|
|
||
|
|
if (option == DISP_OPT_FPS_CALC_WND) {
|
||
|
|
ret = primary_fps_ctx_set_wnd_sz(value);
|
||
|
|
if (ret) {
|
||
|
|
DISPERR("%s error to set fps_wnd_sz to %d\n",
|
||
|
|
__func__, value);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (option < DISP_OPT_NUM) {
|
||
|
|
DISPCHECK("Set Option %d(%s) from (%d) to (%d)\n", option,
|
||
|
|
disp_helper_option_spy(option),
|
||
|
|
disp_helper_get_option(option), value);
|
||
|
|
_disp_helper_option_value[option] = value;
|
||
|
|
DISPCHECK("After set (%s) is (%d)\n",
|
||
|
|
disp_helper_option_spy(option),
|
||
|
|
disp_helper_get_option(option));
|
||
|
|
} else {
|
||
|
|
DISPERR("Wrong option: %d\n", option);
|
||
|
|
}
|
||
|
|
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) {
|
||
|
|
DISPERR("%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;
|
||
|
|
|
||
|
|
DISPERR("%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) {
|
||
|
|
DISPERR("%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) {
|
||
|
|
DISPERR("%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;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
default:
|
||
|
|
{
|
||
|
|
return _disp_helper_option_value[option];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
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, 1);
|
||
|
|
disp_helper_set_option(DISP_OPT_USE_M4U, 1);
|
||
|
|
|
||
|
|
/*
|
||
|
|
* 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, 1);
|
||
|
|
disp_helper_set_option(DISP_OPT_IDLE_MGR, 1);
|
||
|
|
|
||
|
|
/* 1. vdo mode + screen idle(need idlemgr) */
|
||
|
|
disp_helper_set_option(DISP_OPT_IDLEMGR_SWTCH_DECOUPLE, 1);
|
||
|
|
disp_helper_set_option(DISP_OPT_SHARE_SRAM, 1);
|
||
|
|
disp_helper_set_option(DISP_OPT_IDLEMGR_DISABLE_ROUTINE_IRQ, 1);
|
||
|
|
|
||
|
|
/* 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, 1);
|
||
|
|
|
||
|
|
/* 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, 0);
|
||
|
|
disp_helper_set_option(DISP_OPT_MUTEX_EOF_EN_FOR_CMD_MODE, 0);
|
||
|
|
disp_helper_set_option(DISP_OPT_ESD_CHECK_RECOVERY, 1);
|
||
|
|
disp_helper_set_option(DISP_OPT_ESD_CHECK_SWITCH, 1);
|
||
|
|
|
||
|
|
disp_helper_set_option(DISP_OPT_BYPASS_OVL, 1);
|
||
|
|
disp_helper_set_option(DISP_OPT_FPS_CALC_WND, 10);
|
||
|
|
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, 1);
|
||
|
|
|
||
|
|
/* display partial update */
|
||
|
|
#ifdef CONFIG_MTK_CONSUMER_PARTIAL_UPDATE_SUPPORT
|
||
|
|
disp_helper_set_option(DISP_OPT_PARTIAL_UPDATE, 0);
|
||
|
|
#endif
|
||
|
|
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, 1);
|
||
|
|
|
||
|
|
disp_helper_set_option(DISP_OPT_REG_PARSER_RAW_DUMP, 0);
|
||
|
|
|
||
|
|
disp_helper_set_option(DISP_OPT_AOD, 0);
|
||
|
|
disp_helper_set_option(DISP_OPT_RSZ, 0);
|
||
|
|
disp_helper_set_option(DISP_OPT_DUAL_PIPE, 0);
|
||
|
|
|
||
|
|
/* ARR phase 1 option*/
|
||
|
|
disp_helper_set_option(DISP_OPT_ARR_PHASE_1, 0);
|
||
|
|
|
||
|
|
disp_helper_set_option(DISP_OPT_GMO_OPTIMIZE, 1);
|
||
|
|
disp_helper_set_option(DISP_OPT_MIRROR_MODE_FROCE_DISABLE_SODI, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
int disp_helper_get_option_list(char *stringbuf, int buf_len)
|
||
|
|
{
|
||
|
|
int len = 0;
|
||
|
|
int i = 0;
|
||
|
|
|
||
|
|
for (i = 0; i < DISP_OPT_NUM; i++) {
|
||
|
|
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;
|
||
|
|
}
|