kernel_samsung_a34x-permissive/drivers/misc/mediatek/mdp/cmdq_virtual.c
2024-04-28 15:51:13 +02:00

691 lines
16 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include "mdp_cmdq_helper_ext.h"
#include "cmdq_reg.h"
#include "mdp_cmdq_device.h"
#include "cmdq_virtual.h"
#include <linux/seq_file.h>
#ifdef CMDQ_CG_M4U_LARB0
#include "m4u.h"
#endif
#ifdef CONFIG_MTK_SMI_EXT
#include "smi_public.h"
#endif
static struct cmdqCoreFuncStruct gFunctionPointer;
u64 cmdq_virtual_flag_from_scenario_default(enum CMDQ_SCENARIO_ENUM scn)
{
u64 flag = 0;
switch (scn) {
case CMDQ_SCENARIO_TRIGGER_LOOP:
/* Trigger loop does not related to any HW by itself. */
flag = 0LL;
break;
case CMDQ_SCENARIO_USER_SPACE:
/* user space case, engine flag is passed seprately */
flag = 0LL;
break;
case CMDQ_SCENARIO_DEBUG:
case CMDQ_SCENARIO_DEBUG_PREFETCH:
flag = 0LL;
break;
case CMDQ_SCENARIO_USER_DISP_COLOR:
/* color path */
flag = 0LL;
break;
default:
if (scn < 0 || scn >= CMDQ_MAX_SCENARIO_COUNT) {
/* Error status print */
CMDQ_ERR("Unknown scenario type %d\n", scn);
}
flag = 0LL;
break;
}
return flag;
}
const char *cmdq_virtual_parse_module_from_reg_addr_legacy(u32 reg_addr)
{
const u32 addr_base_and_page = (reg_addr & 0xFFFFF000);
/* for well-known base, we check them with 12-bit mask
* defined in mt_reg_base.h
* TODO: comfirm with SS if IO_VIRT_TO_PHYS workable when enable device
* tree?
*/
switch (addr_base_and_page) {
case 0x14000000:
return "MMSYS";
case 0x14001000:
return "MDP_RDMA0";
case 0x14002000:
return "MDP_RDMA1";
case 0x14003000:
return "MDP_RSZ0";
case 0x14004000:
return "MDP_RSZ1";
case 0x14005000:
return "MDP_RSZ2";
case 0x14006000:
return "MDP_WDMA";
case 0x14007000:
return "MDP_WROT0";
case 0x14008000:
return "MDP_WROT1";
case 0x14009000:
return "MDP_TDSHP0";
case 0x1400A000:
return "MDP_TDSHP1";
case 0x1400B000:
return "MDP_CROP";
case 0x1400C000:
return "DISP_OVL0";
case 0x1400D000:
return "DISP_OVL1";
case 0x14013000:
return "COLOR0";
case 0x14014000:
return "COLOR1";
case 0x14015000:
return "AAL";
case 0x14016000:
return "GAMA";
case 0x14020000:
return "MMSYS_MUTEX";
case 0x18000000:
return "VENC_GCON";
case 0x18002000:
return "VENC";
case 0x18003000:
return "JPGENC";
case 0x18004000:
return "JPGDEC";
}
/* for other register address we rely on GCE subsys to group them
* with 16-bit mask.
*/
return cmdq_core_parse_subsys_from_reg_addr(reg_addr);
}
/*
* GCE capability
*/
u32 cmdq_virtual_get_subsys_LSB_in_arg_a(void)
{
return 16;
}
/* HW thread related */
bool cmdq_virtual_is_a_secure_thread(const s32 thread)
{
#ifdef CMDQ_SECURE_PATH_SUPPORT
if ((thread >= CMDQ_MIN_SECURE_THREAD_ID) &&
(thread < CMDQ_MIN_SECURE_THREAD_ID +
CMDQ_MAX_SECURE_THREAD_COUNT)) {
return true;
}
#endif
return false;
}
/**
* Scenario related
*
*/
bool cmdq_virtual_is_disp_scenario(const enum CMDQ_SCENARIO_ENUM scenario)
{
bool dispScenario = false;
switch (scenario) {
case CMDQ_SCENARIO_TRIGGER_LOOP:
case CMDQ_SCENARIO_USER_DISP_COLOR:
dispScenario = true;
break;
default:
break;
}
/* freely dispatch */
return dispScenario;
}
bool cmdq_virtual_is_dynamic_scenario(
const enum CMDQ_SCENARIO_ENUM scenario)
{
bool dynamic_thread;
switch (scenario) {
case CMDQ_SCENARIO_USER_SPACE:
case CMDQ_SCENARIO_USER_MDP:
case CMDQ_SCENARIO_DEBUG_MDP:
dynamic_thread = true;
break;
default:
dynamic_thread = false;
break;
}
return dynamic_thread;
}
int cmdq_virtual_disp_thread(enum CMDQ_SCENARIO_ENUM scenario)
{
switch (scenario) {
/* HACK: force debug into 0/1 thread */
case CMDQ_SCENARIO_DEBUG_PREFETCH:
/* primary config: thread 0 */
return 0;
case CMDQ_SCENARIO_USER_DISP_COLOR:
return 4;
case CMDQ_SCENARIO_TRIGGER_LOOP:
return 7;
default:
/* freely dispatch */
return CMDQ_INVALID_THREAD;
}
/* freely dispatch */
return CMDQ_INVALID_THREAD;
}
int cmdq_virtual_get_thread_index(enum CMDQ_SCENARIO_ENUM scenario,
const bool secure)
{
if (!secure)
return cmdq_get_func()->dispThread(scenario);
/* dispatch secure thread according to scenario */
switch (scenario) {
case CMDQ_SCENARIO_DEBUG_PREFETCH:
/* CMDQ_MIN_SECURE_THREAD_ID */
return CMDQ_THREAD_SEC_PRIMARY_DISP;
case CMDQ_SCENARIO_USER_MDP:
case CMDQ_SCENARIO_USER_SPACE:
case CMDQ_SCENARIO_DEBUG:
case CMDQ_SCENARIO_DEBUG_MDP:
/* because there is one input engine for MDP, reserve one
* secure thread is enough
*/
return CMDQ_THREAD_SEC_MDP;
case CMDQ_SCENARIO_ISP_FDVT:
case CMDQ_SCENARIO_ISP_FDVT_OFF:
return CMDQ_THREAD_SEC_ISP;
default:
CMDQ_ERR("no dedicated secure thread for senario:%d\n",
scenario);
return CMDQ_INVALID_THREAD;
}
}
enum CMDQ_HW_THREAD_PRIORITY_ENUM cmdq_virtual_priority_from_scenario(
enum CMDQ_SCENARIO_ENUM scenario)
{
switch (scenario) {
case CMDQ_SCENARIO_USER_DISP_COLOR:
/* currently, a prefetch thread is always in high priority. */
return CMDQ_THR_PRIO_DISPLAY_CONFIG;
/* HACK: force debug into 0/1 thread */
case CMDQ_SCENARIO_DEBUG_PREFETCH:
return CMDQ_THR_PRIO_DISPLAY_CONFIG;
default:
/* other cases need exta logic, see below. */
break;
}
if (cmdq_get_func()->is_disp_loop(scenario))
return CMDQ_THR_PRIO_DISPLAY_TRIGGER;
else
return CMDQ_THR_PRIO_NORMAL;
}
bool cmdq_virtual_is_disp_loop(enum CMDQ_SCENARIO_ENUM scenario)
{
bool is_disp_loop = false;
if (scenario == CMDQ_SCENARIO_TRIGGER_LOOP)
is_disp_loop = true;
return is_disp_loop;
}
/**
* Module dependent
*
*/
void cmdq_virtual_get_reg_id_from_hwflag(u64 hwflag,
enum cmdq_gpr_reg *valueRegId,
enum cmdq_gpr_reg *destRegId,
enum cmdq_event *regAccessToken)
{
*regAccessToken = CMDQ_SYNC_TOKEN_INVALID;
if (hwflag & (1LL << CMDQ_ENG_MDP_TDSHP0)) {
*valueRegId = CMDQ_DATA_REG_2D_SHARPNESS_0;
*destRegId = CMDQ_DATA_REG_2D_SHARPNESS_0_DST;
*regAccessToken = CMDQ_SYNC_TOKEN_GPR_SET_1;
} else if (hwflag & (1LL << CMDQ_ENG_MDP_TDSHP1)) {
*valueRegId = CMDQ_DATA_REG_2D_SHARPNESS_1;
*destRegId = CMDQ_DATA_REG_2D_SHARPNESS_1_DST;
*regAccessToken = CMDQ_SYNC_TOKEN_GPR_SET_2;
} else {
/* assume others are debug cases */
*valueRegId = CMDQ_DATA_REG_DEBUG;
*destRegId = CMDQ_DATA_REG_DEBUG_DST;
*regAccessToken = CMDQ_SYNC_TOKEN_GPR_SET_4;
}
}
const char *cmdq_virtual_module_from_event_id(const s32 event,
struct CmdqCBkStruct *groupCallback, u64 engineFlag)
{
const char *module = "CMDQ";
enum CMDQ_GROUP_ENUM group = CMDQ_MAX_GROUP_COUNT;
switch (event) {
case CMDQ_EVENT_MDP_RDMA0_SOF ... CMDQ_EVENT_MDP_WROT3_SOF:
case CMDQ_EVENT_MDP_RDMA0_EOF ... CMDQ_EVENT_MDP_WROT3_WRITE_EOF:
case CMDQ_EVENT_IMG_DL_RELAY_SOF ... CMDQ_EVENT_IMG_DL_RELAY3_SOF:
module = "MDP";
group = CMDQ_GROUP_MDP;
break;
case CMDQ_EVENT_ISP_PASS2_2_EOF ... CMDQ_EVENT_ISP_PASS2_0_EOF:
case CMDQ_EVENT_DIP_CQ_THREAD0_EOF ... CMDQ_EVENT_DIP_CQ_THREAD18_EOF:
case CMDQ_EVENT_IMG1_EVENT_TX_FRAME_DONE_0
... CMDQ_EVENT_IMG2_EVENT_TX_FRAME_DONE_23:
module = "DIP";
group = CMDQ_GROUP_ISP;
break;
case CMDQ_EVENT_WPE_A_EOF:
case CMDQ_EVENT_WPE_B_FRAME_DONE:
module = "WPE";
group = CMDQ_GROUP_WPE;
break;
default:
module = "CMDQ";
group = CMDQ_MAX_GROUP_COUNT;
break;
}
if (group < CMDQ_MAX_GROUP_COUNT && groupCallback[group].dispatchMod)
module = groupCallback[group].dispatchMod(engineFlag);
return module;
}
const char *cmdq_virtual_parse_module_from_reg_addr(u32 reg_addr)
{
const u32 addr_base_and_page = (reg_addr & 0xFFFFF000);
#ifdef CMDQ_USE_LEGACY
return cmdq_virtual_parse_module_from_reg_addr_legacy(reg_addr);
#else
/* for well-known base, we check them with 12-bit mask
* defined in mt_reg_base.h
* TODO: comfirm with SS if IO_VIRT_TO_PHYS workable when enable
* device tree?
*/
switch (addr_base_and_page) {
case 0x14001000: /* MDP_RDMA0 */
case 0x14002000: /* MDP_RDMA1 */
case 0x14003000: /* MDP_RSZ0 */
case 0x14004000: /* MDP_RSZ1 */
case 0x14005000: /* MDP_RSZ2 */
case 0x14006000: /* MDP_WDMA */
case 0x14007000: /* MDP_WROT0 */
case 0x14008000: /* MDP_WROT1 */
case 0x14009000: /* MDP_TDSHP */
return "MDP";
case 0x14014000: /* DISP_COLOR0 */
case 0x14015000: /* DISP_COLOR1 */
return "COLOR";
case 0x14016000: /* DISP_COLOR0 */
case 0x14017000: /* DISP_COLOR1 */
return "CCORR";
case 0x1400B000: /* DISP_OVL0 */
case 0x1400D000: /* DISP_OVL0_2L */
return "OVL0";
case 0x1400C000: /* DISP_OVL1 */
case 0x1400E000: /* DISP_OVL1_2L */
return "OVL1";
case 0x14018000: /* DISP_AAL0 */
case 0x14019000: /* DISP_AAL1 */
case 0x1401a000: /* DISP_GAMMA0 */
case 0x1401b000: /* DISP_GAMMA1 */
return "AAL";
case 0x17020000: /* VENC */
return "VENC";
case 0x17030000: /* JPGENC */
return "JPGENC";
case 0x17040000: /* JPGDEC */
return "JPGDEC";
}
/* for other register address we rely on GCE subsys to group them
* with 16-bit mask.
*/
return cmdq_core_parse_subsys_from_reg_addr(reg_addr);
#endif
}
s32 cmdq_virtual_can_module_entry_suspend(struct EngineStruct *engineList)
{
s32 status = 0;
int i;
enum CMDQ_ENG_ENUM e = 0;
u32 mdpEngines[] = {
CMDQ_ENG_ISP_IMGI,
CMDQ_ENG_MDP_RDMA0,
CMDQ_ENG_MDP_RDMA1,
CMDQ_ENG_MDP_RSZ0,
CMDQ_ENG_MDP_RSZ1,
CMDQ_ENG_MDP_RSZ2,
CMDQ_ENG_MDP_TDSHP0,
CMDQ_ENG_MDP_TDSHP1,
CMDQ_ENG_MDP_COLOR0,
CMDQ_ENG_MDP_WROT0,
CMDQ_ENG_MDP_WROT1,
CMDQ_ENG_MDP_WDMA,
};
for (i = 0; i < ARRAY_SIZE(mdpEngines); i++) {
e = mdpEngines[i];
if (engineList[e].userCount != 0) {
CMDQ_ERR(
"suspend but engine %d has userCount %d, owner=%d\n",
e, engineList[e].userCount,
engineList[e].currOwner);
status = -EBUSY;
}
}
return status;
}
ssize_t cmdq_virtual_print_status_clock(char *buf)
{
s32 length = 0;
char *pBuffer = buf;
#ifdef CMDQ_PWR_AWARE
/* MT_CG_DISP0_MUTEX_32K is removed in this platform */
pBuffer += sprintf(pBuffer, "MT_CG_INFRA_GCE: %d\n",
cmdq_dev_gce_clock_is_enable());
pBuffer += sprintf(pBuffer, "\n");
#endif
length = pBuffer - buf;
return length;
}
void cmdq_virtual_print_status_seq_clock(struct seq_file *m)
{
#ifdef CMDQ_PWR_AWARE
/* MT_CG_DISP0_MUTEX_32K is removed in this platform */
seq_printf(m, "MT_CG_INFRA_GCE: %d", cmdq_dev_gce_clock_is_enable());
seq_puts(m, "\n");
#endif
}
void cmdq_virtual_enable_common_clock_locked(bool enable)
{
#ifdef CMDQ_PWR_AWARE
if (enable) {
CMDQ_VERBOSE("[CLOCK] Enable SMI & LARB0 Clock\n");
/* Use SMI clock API */
#ifdef CONFIG_MTK_SMI_EXT
smi_bus_prepare_enable(SMI_LARB0, "CMDQ");
#endif
} else {
CMDQ_VERBOSE("[CLOCK] Disable SMI & LARB0 Clock\n");
/* disable, reverse the sequence */
#ifdef CONFIG_MTK_SMI_EXT
smi_bus_disable_unprepare(SMI_LARB0, "CMDQ");
#endif
}
#endif /* CMDQ_PWR_AWARE */
}
void cmdq_virtual_enable_gce_clock_locked(bool enable)
{
#ifdef CMDQ_PWR_AWARE
if (enable) {
CMDQ_VERBOSE("[CLOCK] Enable CMDQ(GCE) Clock\n");
cmdq_dev_enable_gce_clock(enable);
} else {
CMDQ_VERBOSE("[CLOCK] Disable CMDQ(GCE) Clock\n");
cmdq_dev_enable_gce_clock(enable);
}
#endif
}
const char *cmdq_virtual_parse_handle_error_module_by_hwflag_impl(
const struct cmdqRecStruct *pHandle)
{
const char *module = NULL;
if (cmdq_get_func()->isDispScenario(pHandle->scenario))
module = "DISP";
else
module = cmdq_mdp_parse_handle_error_module_by_hwflag(pHandle);
/* other case, we need to analysis instruction for more detail */
return module;
}
const char *cmdq_virtual_parse_error_module_by_hwflag_impl(
const struct cmdqRecStruct *task)
{
const char *module = NULL;
/* TODO: fill in correct dispatch module */
if (cmdq_get_func()->isDispScenario(task->scenario))
module = "DISP";
else
module = cmdq_mdp_parse_handle_error_module_by_hwflag(task);
/* other case, we need to analysis instruction for more detail */
return module;
}
/**
* Debug
*
*/
int cmdq_virtual_dump_smi(const int showSmiDump)
{
int isSMIHang = 0;
#if defined(CONFIG_MTK_SMI_EXT) && !defined(CONFIG_FPGA_EARLY_PORTING) && \
!defined(CONFIG_MTK_SMI_VARIANT)
isSMIHang = smi_debug_bus_hang_detect(showSmiDump, "CMDQ");
CMDQ_ERR("SMI Hang? = %d\n", isSMIHang);
#else
CMDQ_LOG("[WARNING]not enable SMI dump now\n");
#endif
return isSMIHang;
}
void cmdq_virtual_dump_gpr(void)
{
int i = 0;
long offset = 0;
u32 value = 0;
CMDQ_LOG("========= GPR dump =========\n");
for (i = 0; i < 16; i++) {
offset = CMDQ_GPR_R32(i);
value = CMDQ_REG_GET32(offset);
CMDQ_LOG("[GPR %2d]+0x%lx = 0x%08x\n", i, offset, value);
}
CMDQ_LOG("========= GPR dump =========\n");
}
/**
* Event backup
*
*/
struct cmdq_backup_event_struct {
enum cmdq_event EventID;
u32 BackupValue;
};
static struct cmdq_backup_event_struct g_cmdq_backup_event[] = {
#ifdef CMDQ_EVENT_NEED_BACKUP
{CMDQ_SYNC_TOKEN_VENC_EOF, 0,},
{CMDQ_SYNC_TOKEN_VENC_INPUT_READY, 0,},
#endif /* CMDQ_EVENT_NEED_BACKUP */
};
void cmdq_virtual_event_backup(void)
{
int i;
int array_size = (sizeof(g_cmdq_backup_event) /
sizeof(struct cmdq_backup_event_struct));
for (i = 0; i < array_size; i++) {
if (g_cmdq_backup_event[i].EventID < 0 ||
g_cmdq_backup_event[i].EventID >= CMDQ_SYNC_TOKEN_MAX)
continue;
g_cmdq_backup_event[i].BackupValue = cmdqCoreGetEvent(
g_cmdq_backup_event[i].EventID);
CMDQ_MSG("[backup event] event: %s, value: %d\n",
cmdq_core_get_event_name_enum(
g_cmdq_backup_event[i].EventID),
g_cmdq_backup_event[i].BackupValue);
}
}
void cmdq_virtual_event_restore(void)
{
int i;
int array_size = (sizeof(g_cmdq_backup_event) /
sizeof(struct cmdq_backup_event_struct));
for (i = 0; i < array_size; i++) {
if (g_cmdq_backup_event[i].EventID < 0 ||
g_cmdq_backup_event[i].EventID >= CMDQ_SYNC_TOKEN_MAX)
continue;
CMDQ_MSG("[restore event] event: %s, value: %d\n",
cmdq_core_get_event_name_enum(
g_cmdq_backup_event[i].EventID),
g_cmdq_backup_event[i].BackupValue);
if (g_cmdq_backup_event[i].BackupValue == 1)
cmdqCoreSetEvent(g_cmdq_backup_event[i].EventID);
else if (g_cmdq_backup_event[i].BackupValue == 0)
cmdqCoreClearEvent(g_cmdq_backup_event[i].EventID);
}
}
/**
* Test
*
*/
void cmdq_virtual_test_setup(void)
{
/* unconditionally set CMDQ_SYNC_TOKEN_CONFIG_ALLOW and mutex
* STREAM_DONE so that DISPSYS scenarios may pass check.
*/
}
void cmdq_virtual_test_cleanup(void)
{
/* do nothing */
}
void cmdq_virtual_init_module_PA_stat(void)
{
}
void cmdq_virtual_function_setting(void)
{
struct cmdqCoreFuncStruct *pFunc;
pFunc = &(gFunctionPointer);
/*
* GCE capability
*/
pFunc->getSubsysLSBArgA = cmdq_virtual_get_subsys_LSB_in_arg_a;
/* HW thread related */
pFunc->isSecureThread = cmdq_virtual_is_a_secure_thread;
/**
* Scenario related
*
*/
pFunc->isDispScenario = cmdq_virtual_is_disp_scenario;
pFunc->isDynamic = cmdq_virtual_is_dynamic_scenario;
pFunc->dispThread = cmdq_virtual_disp_thread;
pFunc->getThreadID = cmdq_virtual_get_thread_index;
pFunc->priority = cmdq_virtual_priority_from_scenario;
pFunc->is_disp_loop = cmdq_virtual_is_disp_loop;
/**
* Module dependent
*
*/
pFunc->getRegID = cmdq_virtual_get_reg_id_from_hwflag;
pFunc->moduleFromEvent = cmdq_virtual_module_from_event_id;
pFunc->parseModule = cmdq_virtual_parse_module_from_reg_addr;
pFunc->moduleEntrySuspend = cmdq_virtual_can_module_entry_suspend;
pFunc->printStatusClock = cmdq_virtual_print_status_clock;
pFunc->printStatusSeqClock = cmdq_virtual_print_status_seq_clock;
pFunc->enableGCEClockLocked = cmdq_virtual_enable_gce_clock_locked;
pFunc->parseErrorModule =
cmdq_virtual_parse_error_module_by_hwflag_impl;
pFunc->parseHandleErrorModule =
cmdq_virtual_parse_handle_error_module_by_hwflag_impl;
/**
* Debug
*
*/
pFunc->dumpSMI = cmdq_virtual_dump_smi;
pFunc->dumpGPR = cmdq_virtual_dump_gpr;
/**
* Event backup
*
*/
pFunc->eventBackup = cmdq_virtual_event_backup;
pFunc->eventRestore = cmdq_virtual_event_restore;
/**
* Test
*
*/
pFunc->testSetup = cmdq_virtual_test_setup;
pFunc->testCleanup = cmdq_virtual_test_cleanup;
pFunc->initModulePAStat = cmdq_virtual_init_module_PA_stat;
}
struct cmdqCoreFuncStruct *cmdq_get_func(void)
{
return &gFunctionPointer;
}