unplugged-kernel/drivers/misc/mediatek/video/mt6768/dispsys/ddp_met.c

238 lines
5.4 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#define LOG_TAG "MET"
#include "ddp_log.h"
#include "disp_drv_platform.h"
#include "ddp_irq.h"
#include "ddp_reg.h"
#include "ddp_met.h"
#include "ddp_path.h"
#include "ddp_ovl.h"
#include "ddp_rdma.h"
#include "DpDataType.h"
#define DDP_IRQ_EER_ID (0xFFFF0000)
#define DDP_IRQ_FPS_ID (DDP_IRQ_EER_ID + 1)
#define DDP_IRQ_LAYER_FPS_ID (DDP_IRQ_EER_ID + 2)
#define DDP_IRQ_LAYER_SIZE_ID (DDP_IRQ_EER_ID + 3)
#define DDP_IRQ_LAYER_FORMAT_ID (DDP_IRQ_EER_ID + 4)
#define MAX_PATH_NUM (3)
#define RDMA_NUM (2)
#define MAX_OVL_LAYERS (4)
#define OVL_LAYER_NUM_PER_OVL (4)
static unsigned int met_tag_on;
#if defined(CONFIG_MTK_MET)
#include <linux/module.h>
extern int met_tag_oneshot_real(unsigned int class_id,
const char *name, unsigned int value);
static struct ovl_info_s {
unsigned char ovl_idx;
unsigned char layer_num;
} ovl_infos[OVL_NUM] = {
{DISP_MODULE_OVL0, 4}, {DISP_MODULE_OVL0_2L, 2},
{DISP_MODULE_OVL1_2L, 2},
};
#endif
/**
* check if it's decouple mode
*
* mutex_id | decouple | direct-link
* -------------------------------------
* OVL_Path | 1 | 0
* RDMA_Path | 0 | X
*
*/
int dpp_disp_is_decouple(void)
{
if (ddp_is_moudule_in_mutex(0, DISP_MODULE_OVL0) ||
ddp_is_moudule_in_mutex(0, DISP_MODULE_OVL0_2L))
return 0;
else
return 1;
}
/**
* Represent to LCM display refresh rate
* Primary Display: map to RDMA0 sof/eof ISR, for all display mode
* External Display: map to RDMA1 sof/eof ISR, for all display mode
* NOTICE:
* for WFD, nothing we can do here
*/
static void ddp_disp_refresh_tag_start(unsigned int index)
{
#if defined(CONFIG_MTK_MET)
static unsigned long sBufAddr[RDMA_NUM];
static struct RDMA_BASIC_STRUCT rdmaInfo;
char tag_name[30] = { '\0' };
static struct OVL_BASIC_STRUCT old_ovlInfo[4+2+2];
static struct OVL_BASIC_STRUCT ovlInfo[4+2+2];
int layer_idx = 0;
int layer_pos = 0;
int b_layer_changed = 0;
int i, j;
int (*met_tag_oneshot_symbol)(unsigned int class_id,
const char *name, unsigned int value) = NULL;
met_tag_oneshot_symbol =
(void *)symbol_get(met_tag_oneshot_real);
if (dpp_disp_is_decouple() == 1) {
rdma_get_info(index, &rdmaInfo);
if (rdmaInfo.addr == 0 || (rdmaInfo.addr != 0 &&
sBufAddr[index] != rdmaInfo.addr)) {
sBufAddr[index] = rdmaInfo.addr;
sprintf(tag_name, index ?
"ExtDispRefresh" : "PrimDispRefresh");
if (met_tag_oneshot_symbol)
met_tag_oneshot_symbol(DDP_IRQ_FPS_ID,
tag_name, 1);
}
return;
}
/*essential for structure comparision*/
memset(ovlInfo, 0, sizeof(ovlInfo));
/*Traversal layers and get layer info*/
for (i = 0; i < OVL_NUM; i++) {
if (i > 0)
layer_pos += ovl_infos[i-1].layer_num;
ovl_get_info(ovl_infos[i].ovl_idx, &(ovlInfo[layer_pos]));
for (j = 0; j < ovl_infos[i].layer_num; j++) {
if (memcmp(&(ovlInfo[layer_idx]),
&(old_ovlInfo[layer_idx]),
sizeof(struct OVL_BASIC_STRUCT)) == 0)
continue;
if (ovlInfo[layer_idx].layer_en)
b_layer_changed = 1;
layer_idx++;
}
/*store old value*/
memcpy(&(old_ovlInfo[layer_pos]),
&(ovlInfo[layer_pos]),
ovl_infos[i].layer_num *
sizeof(struct OVL_BASIC_STRUCT));
}
if (b_layer_changed) {
sprintf(tag_name,
index ? "ExtDispRefresh" : "PrimDispRefresh");
if (met_tag_oneshot_symbol)
met_tag_oneshot_symbol(DDP_IRQ_FPS_ID, tag_name, 1);
}
#endif
}
static void ddp_disp_refresh_tag_end(unsigned int index)
{
#if defined(CONFIG_MTK_MET)
char tag_name[30] = { '\0' };
int (*met_tag_oneshot_symbol)(unsigned int class_id,
const char *name, unsigned int value) = NULL;
sprintf(tag_name, index ?
"ExtDispRefresh" : "PrimDispRefresh");
met_tag_oneshot_symbol =
(void *)symbol_get(met_tag_oneshot_real);
if (met_tag_oneshot_symbol)
met_tag_oneshot_symbol(DDP_IRQ_FPS_ID, tag_name, 0);
#endif
}
/**
* Represent to OVL0/0VL1 each layer's refresh rate
*/
static void ddp_inout_info_tag(unsigned int index)
{
}
static void ddp_err_irq_met_tag(const char *name)
{
#if defined(CONFIG_MTK_MET)
int (*met_tag_oneshot_symbol)(unsigned int class_id,
const char *name, unsigned int value) = NULL;
met_tag_oneshot_symbol =
(void *)symbol_get(met_tag_oneshot_real);
if (met_tag_oneshot_symbol) {
met_tag_oneshot_symbol(DDP_IRQ_EER_ID, name, 1);
met_tag_oneshot_symbol(DDP_IRQ_EER_ID, name, 0);
}
#endif
}
static void met_irq_handler(enum DISP_MODULE_ENUM module,
unsigned int reg_val)
{
int index = 0;
char tag_name[30] = { '\0' };
switch (module) {
case DISP_MODULE_RDMA0:
case DISP_MODULE_RDMA1:
index = module - DISP_MODULE_RDMA0;
/*Always process eof prior to sof*/
if (reg_val & (1 << 2))
ddp_disp_refresh_tag_end(index);
if (reg_val & (1 << 1))
ddp_disp_refresh_tag_start(index);
if (reg_val & (1 << 4)) {
sprintf(tag_name, "rdma%d_underflow", index);
ddp_err_irq_met_tag(tag_name);
}
if (reg_val & (1 << 3)) {
sprintf(tag_name, "rdma%d_abnormal", index);
ddp_err_irq_met_tag(tag_name);
}
break;
case DISP_MODULE_OVL0:
index = module - DISP_MODULE_OVL0;
if (reg_val & (1 << 1)) /*EOF*/
ddp_inout_info_tag(index);
break;
case DISP_MODULE_MUTEX:
break;
default:
break;
}
}
void ddp_init_met_tag(int state, int rdma0_mode, int rdma1_mode)
{
if ((!met_tag_on) && state) {
met_tag_on = state;
disp_register_irq_callback(met_irq_handler);
}
if (met_tag_on && (!state)) {
met_tag_on = state;
disp_unregister_irq_callback(met_irq_handler);
}
}
EXPORT_SYMBOL(ddp_init_met_tag);