blob: 6d8be985684977465834cda57359cc2d3feb3cfe [file] [log] [blame]
/*
* Copyright (c) 2022 Amlogic, Inc. All rights reserved.
*
* This source code is subject to the terms and conditions defined in the
* file 'LICENSE' which is part of this source code package.
*
* Description:
*/
#include "ModePolicy.h"
#include <modepolicy/mode_ubootenv.h>
#include <inttypes.h>
#include <sys/utsname.h>
#include <memory>
#include <sys/ioctl.h>
//#include <systemcontrol.h>
static int g_activeLevel= 3;
/* testing if tv support this displaymode and deepcolor combination, then if cat result is 1: support, 0: not */
#define DISPLAY_HDMI_VALID_MODE "/sys/class/amhdmitx/amhdmitx0/valid_mode"
#define PROP_DEFAULT_COLOR "ro_vendor_platform_default_color"
#define LOW_POWER_DEFAULT_COLOR "ro_vendor_low_power_default_color" /* Set default deep color is 8bit for Low Power Mode */
#define UBOOTENV_COLORATTRIBUTE "ubootenv.var.colorattribute"
#define EDID_MAX_SIZE 2049
#define MODE_8K4K_PREFIX "4320p"
#define PROP_VALUE_MAX 92
#define HDMI_HDR_STATUS_HDR10PLUS 0
#define HDMI_HDR_STATUS_DolbyVision_STD 1
#define HDMI_HDR_STATUS_DolbyVision_Lowlatency 2
#define HDMI_HDR_STATUS_HDR10_ST2084 3
#define HDMI_HDR_STATUS_HDR10_TRADITIONAL 4
#define HDMI_HDR_STATUS_HDR_HLG 5
#define HDMI_HDR_STATUS_SDR 6
enum {
DISPLAY_TYPE_NONE = 0,
DISPLAY_TYPE_TABLET = 1,
DISPLAY_TYPE_MBOX = 2,
DISPLAY_TYPE_TV = 3,
DISPLAY_TYPE_REPEATER = 4
};
static const char* AMDV_MODE_TYPE[] = {
"DV_RGB_444_8BIT",
"DV_YCbCr_422_12BIT",
"LL_YCbCr_422_12BIT",
"LL_RGB_444_10BIT",
"LL_RGB_444_12BIT"
};
static const char* ALLM_MODE_CAP[] = {
"0",
"1",
};
static const char* ALLM_MODE[] = {
"-1",
"0",
"1",
};
static const char* CONTENT_TYPE_CAP[] = {
"graphics",
"photo",
"cinema",
"game",
};
/*****************************************/
/* deepcolor */
//this is check hdmi mode(4K60/4k50) list
static const char* COLOR_ATTRIBUTE_LIST[] = {
COLOR_RGB_8BIT,
COLOR_YCBCR444_8BIT,
COLOR_YCBCR420_8BIT,
COLOR_YCBCR422_8BIT,
};
//this is check hdmi mode list
static const char* COLOR_ATTRIBUTE_LIST_8BIT[] = {
COLOR_RGB_8BIT,
COLOR_YCBCR444_8BIT,
COLOR_YCBCR422_8BIT,
};
std::shared_ptr<ModePolicy> g_Policy;
std::shared_ptr<DisplayAdapter> g_Adapter;
ModePolicy::ModePolicy() {
mDisplayType = DISPLAY_TYPE_MBOX;
mPolicy = MESON_POLICY_MIX;
mReason = OUTPUT_CHANGE_BY_INIT;
mDisplayId = 0;
memset(&mConnectorType, 0, sizeof(mConnectorType));
memset(&mModeConType, 0, sizeof(mModeConType));
memset(&mConData, 0, sizeof(mConData));
memset(&mSceneOutInfo, 0, sizeof(mSceneOutInfo));
memset(&mState, 0, sizeof(mState));
memset(&mDvInfo, 0, sizeof(mDvInfo));
mDisplayWidth = 0;
mDisplayHeight = 0;
mFracMode = MODE_FRACTION;
mEnvLock = PTHREAD_MUTEX_INITIALIZER;
mSeamlessSwitchEnabled = true;
}
ModePolicy::ModePolicy(std::shared_ptr<DisplayAdapter> adapter, const uint32_t displayId) {
mAdapter = adapter;
mDisplayType = DISPLAY_TYPE_MBOX;
mPolicy = MESON_POLICY_MIX;
mReason = OUTPUT_CHANGE_BY_INIT;
mDisplayId = displayId;
memset(&mConnectorType, 0, sizeof(mConnectorType));
memset(&mModeConType, 0, sizeof(mModeConType));
memset(&mConData, 0, sizeof(mConData));
memset(&mSceneOutInfo, 0, sizeof(mSceneOutInfo));
memset(&mState, 0, sizeof(mState));
memset(&mDvInfo, 0, sizeof(mDvInfo));
mDisplayWidth = 0;
mDisplayHeight = 0;
mFracMode = MODE_FRACTION;
mEnvLock = PTHREAD_MUTEX_INITIALIZER;
mSeamlessSwitchEnabled = true;
}
ModePolicy::~ModePolicy() {
}
bool ModePolicy::getBootEnv(const char *key, char *value) {
const char* p_value;
const char* envName = key;
if (strstr(key, PROFIX_UBOOTENV_VAR) != NULL)
envName = key + strlen(PROFIX_UBOOTENV_VAR);
p_value = bootenv_get(envName);
MESON_LOGD("get key:%s value:%s", key, p_value ? p_value : "novalue");
if (p_value) {
strcpy(value, p_value);
return true;
}
return false;
}
int ModePolicy::getBootenvInt(const char* key, int defaultVal) {
int value = defaultVal;
const char* p_value;
const char* envName = key;
if (strstr(key, PROFIX_UBOOTENV_VAR) != NULL)
envName = key + strlen(PROFIX_UBOOTENV_VAR);
p_value = bootenv_get(envName);
if (p_value) {
value = atoi(p_value);
}
return value;
}
void ModePolicy::setBootEnv(const char* key, const char* value) {
const char* p_value;
const char* envName = key;
if (strstr(key, PROFIX_UBOOTENV_VAR) != NULL)
envName = key + strlen(PROFIX_UBOOTENV_VAR);
p_value = bootenv_get(envName);
if (p_value && !strcmp(p_value, value)) {
MESON_LOGV("value is equal, do not set");
return;
}
MESON_LOGD("set key:%s value:%s", key, value);
bootenv_update(envName, value);
}
// TODO: need refactor
#ifdef HDR_AMDV_PROPERTY
void ModePolicy::getDvCap(struct meson_hdr_info *data) {
if (!data) {
MESON_LOGE("%s data is NULL\n", __FUNCTION__);
return;
}
std::string amdv_cap;
int cap = 0;
getDisplayAttribute(DISPLAY_AMDV_CAP, amdv_cap);
strcpy(data->dv_cap, amdv_cap.c_str());
cap = atoi(data->dv_cap);
if (cap != 0) {
uint32_t index = (cap & (1 << 2)) ? 19 : 17;
if ((strlen(data->dv_max_mode) + strlen(DISPLAY_MODE_LIST[index]) + 1) < sizeof(data->dv_max_mode)) {
strcat(data->dv_max_mode, DISPLAY_MODE_LIST[index]);
strcat(data->dv_max_mode, ",");
} else {
MESON_LOGE("DisplayMode strcat overflow: src=%s, dst=%s\n", DISPLAY_MODE_LIST[index], data->dv_max_mode);
}
index = ((cap & 0xf8) >> 3);
for (int i = 0; i < ARRAY_SIZE(AMDV_MODE_TYPE); i++) {
if (index & (1 << i)) {
strcat(data->dv_deepcolor, AMDV_MODE_TYPE[i]);
strcat(data->dv_deepcolor, ",");
}
}
}
}
#else
void ModePolicy::getDvCap(struct meson_hdr_info *data) {
if (!data) {
MESON_LOGE("%s data is NULL\n", __FUNCTION__);
return;
}
std::string amdv_cap;
getDisplayAttribute(DISPLAY_AMDV_CAP2, amdv_cap);
strcpy(data->dv_cap, amdv_cap.c_str());
if (strstr(data->dv_cap, "DolbyVision RX support list") != NULL) {
memset(data->dv_max_mode, 0, sizeof(data->dv_max_mode));
memset(data->dv_deepcolor, 0, sizeof(data->dv_deepcolor));
for (int i = ARRAY_SIZE(DISPLAY_MODE_LIST) - 1; i >= 0; i--) {
if (strstr(data->dv_cap, DISPLAY_MODE_LIST[i]) != NULL) {
if ((strlen(data->dv_max_mode) + strlen(DISPLAY_MODE_LIST[i]) + 1) < sizeof(data->dv_max_mode)) {
strcpy(data->dv_max_mode, DISPLAY_MODE_LIST[i]);
} else {
MESON_LOGE("DisplayMode strcat overflow: src=%s, dst=%s\n", DISPLAY_MODE_LIST[i], data->dv_max_mode);
}
break;
}
}
for (int i = 0; i < sizeof(AMDV_MODE_TYPE)/sizeof(AMDV_MODE_TYPE[0]); i++) {
if (strstr(data->dv_cap, AMDV_MODE_TYPE[i])) {
if ((strlen(data->dv_deepcolor) + strlen(AMDV_MODE_TYPE[i]) + 2) < sizeof(data->dv_deepcolor)) {
strcat(data->dv_deepcolor, AMDV_MODE_TYPE[i]);
strcat(data->dv_deepcolor, ",");
} else {
MESON_LOGE("DisplayMode strcat overflow: src=%s, dst=%s\n", AMDV_MODE_TYPE[i], data->dv_deepcolor);
break;
}
}
}
MESON_LOGI("TV dv info: mode:%s deepcolor: %s\n", data->dv_max_mode, data->dv_deepcolor);
} else {
MESON_LOGE("TV isn't support dv: %s\n", data->dv_cap);
}
}
#endif
void ModePolicy::getHdmiDcCap(char* dc_cap, int32_t len) {
if (!dc_cap) {
MESON_LOGE("%s dc_cap is NULL\n", __FUNCTION__);
return;
}
int count = 0;
while (true) {
sysfs_get_string_original(DISPLAY_HDMI_DEEP_COLOR, dc_cap, len);
if (strlen(dc_cap) > 0)
break;
if (count >= 5) {
MESON_LOGE("read dc_cap fail\n");
break;
}
count++;
usleep(500000);
}
}
int ModePolicy::getHdmiSinkType() {
char sinkType[MESON_MODE_LEN] = {0};
if (sysfs_get_string(DISPLAY_HDMI_SINK_TYPE, sinkType, MESON_MODE_LEN) != 0)
return HDMI_SINK_TYPE_NONE;
if (NULL != strstr(sinkType, "sink")) {
return HDMI_SINK_TYPE_SINK;
} else if (NULL != strstr(sinkType, "repeater")) {
return HDMI_SINK_TYPE_REPEATER;
} else {
return HDMI_SINK_TYPE_NONE;
}
}
void ModePolicy::getHdmiEdidStatus(char* edidstatus, int32_t len) {
if (!edidstatus) {
MESON_LOGE("%s edidstatus is NULL\n", __FUNCTION__);
return;
}
sysfs_get_string(DISPLAY_EDID_STATUS, edidstatus, len);
}
int32_t ModePolicy::setHdrStrategy(int32_t policy, const char *type) {
SYS_LOGI("%s type:%s policy:%s", __func__,
meson_hdrPolicyToString(policy), type);
//1. update env policy
std::string value = std::to_string(policy);
setBootEnv(UBOOTENV_HDR_POLICY, value.c_str());
if (policy == MESON_HDR_POLICY_SOURCE) {
if (isDVEnable()) {
setBootEnv(UBOOTENV_DOLBYSTATUS, "0");
}
} else {
char dvstatus[MESON_MODE_LEN] = {0};
if (isDVEnable()) {
sprintf(dvstatus, "%d", mSceneOutInfo.amdv_type);
setBootEnv(UBOOTENV_DOLBYSTATUS, dvstatus);
}
}
int32_t priority = MESON_HDR10_PRIORITY;
value = std::to_string(MESON_HDR10_PRIORITY);
if (strstr(type, AMDV_DISABLE_FORCE_SDR)) {
priority = MESON_SDR_PRIORITY;
value = std::to_string(MESON_SDR_PRIORITY);
}
//2. set current hdmi mode
meson_mode_set_policy_input(mModeConType, &mConData);
getDisplayMode(mCurrentMode);
if (!meson_mode_support_mode(mModeConType, priority, mCurrentMode)) {
setBootEnv(UBOOTENV_HDR_FORCE_MODE, type);
setSourceOutputMode(mCurrentMode);
} else {
MESON_LOGD("%s mode check failed", __func__);
return -EINVAL;
}
return 0;
}
void ModePolicy::getHdrStrategy(char* value) {
char hdr_policy[MESON_MODE_LEN] = {0};
memset(hdr_policy, 0, MESON_MODE_LEN);
getBootEnv(UBOOTENV_HDR_POLICY, hdr_policy);
if (strstr(hdr_policy, MESON_HDR_POLICY[MESON_HDR_POLICY_SOURCE])) {
strcpy(value, MESON_HDR_POLICY[MESON_HDR_POLICY_SOURCE]);
} else if (strstr(hdr_policy, MESON_HDR_POLICY[MESON_HDR_POLICY_SINK])) {
strcpy(value, MESON_HDR_POLICY[MESON_HDR_POLICY_SINK]);
} else if (strstr(hdr_policy, MESON_HDR_POLICY[MESON_HDR_POLICY_FORCE])) {
strcpy(value, MESON_HDR_POLICY[MESON_HDR_POLICY_FORCE]);
} else if (strstr(hdr_policy, AMDV_POLICY_FORCE_MODE)) {
strcpy(value, AMDV_POLICY_FORCE_MODE);
}
MESON_LOGI("get uboot HdrStrategy is [%s]", value);
}
int32_t ModePolicy::setHdrPriority(int32_t type) {
MESON_LOGI("setHdrPriority is [%s] getHdrPriority is [%s]\n", meson_hdrPriorityToString(type),
meson_hdrPriorityToString(getHdrPriority()));
if (getHdrPriority() != type) {
getConnectorData(&mConData, &mDvInfo);
meson_mode_set_policy_input(mModeConType, &mConData);
getDisplayMode(mCurrentMode);
if (!meson_mode_support_mode(mModeConType, type, mCurrentMode)) {
std::string value = std::to_string(type);
setBootEnv(UBOOTENV_HDR_PRIORITY, value.c_str());
setSourceOutputMode(mCurrentMode);
} else {
MESON_LOGD("%s mode check failed", __func__);
return -EINVAL;
}
} else {
MESON_LOGI("setHdrPriority is [%d] and getHdrPriority [%d],They are equals", type, getHdrPriority());
}
return 0;
}
int32_t ModePolicy::getHdrPriority() {
char hdr_priority[MESON_MODE_LEN] = {0};
meson_hdr_priority_e value = MESON_DOLBY_VISION_PRIORITY;
bool dv_support = isMboxSupportDV();
bool hdr_support = isTvSupportHDR();
meson_hdr_priority_e act_hdr_priority = dv_support ?
MESON_DOLBY_VISION_PRIORITY :
(hdr_support ? MESON_HDR10_PRIORITY : MESON_SDR_PRIORITY);
memset(hdr_priority, 0, MESON_MODE_LEN);
getBootEnv(UBOOTENV_HDR_PRIORITY, hdr_priority);
if (strlen(hdr_priority) == 0) {
return act_hdr_priority;
}
value = (meson_hdr_priority_e)atoi(hdr_priority);
if (value <= MESON_SDR_PRIORITY) {
if (!dv_support && value == MESON_DOLBY_VISION_PRIORITY)
value = MESON_HDR10_PRIORITY;
if (!hdr_support && value == MESON_HDR10_PRIORITY)
value = MESON_SDR_PRIORITY;
value = (act_hdr_priority > value ? act_hdr_priority : value);
} else if (value >= MESON_G_DV_HDR10_HLG) {
switch (value) {
case MESON_G_DV_HDR10_HLG:
value = dv_support ? value : (hdr_support ? MESON_G_HDR10_HLG : MESON_G_SDR);
break;
case MESON_G_DV_HDR10:
value = dv_support ? value : (hdr_support ? MESON_G_HDR10 : MESON_G_SDR);
break;
case MESON_G_DV_HLG:
value = dv_support ? value : (hdr_support ? MESON_G_HLG : MESON_G_SDR);
break;
case MESON_G_DV:
value = dv_support ? value : MESON_G_SDR;
break;
case MESON_G_HDR10_HLG:
case MESON_G_HDR10:
case MESON_G_HLG:
value = hdr_support ? value : MESON_G_SDR;
break;
default:
break;
}
}
if ((value >= MESON_DOLBY_VISION_PRIORITY && value <= MESON_SDR_PRIORITY)
|| (value >= MESON_G_DV_HDR10_HLG && value <= MESON_G_SDR)) {
MESON_LOGI("%s is [%s]", __FUNCTION__, meson_hdrPriorityToString(value));
} else {
MESON_LOGE("%s [%d] is invalid", __FUNCTION__, value);
}
MESON_LOGI("get uboot HdrPriority is [%s]", meson_hdrPriorityToString(value));
return (int32_t)value;
}
int32_t ModePolicy::getCurrentHdrPriority(void) {
meson_hdr_priority_e value = MESON_DOLBY_VISION_PRIORITY;
std::string cur_hdr_priority;
getDisplayAttribute(DISPLAY_HDR_PRIORITY, cur_hdr_priority);
value = (meson_hdr_priority_e)atoi(cur_hdr_priority.c_str());
if ((value >= MESON_DOLBY_VISION_PRIORITY && value <= MESON_SDR_PRIORITY)
|| (value >= MESON_G_DV_HDR10_HLG && value <= MESON_G_SDR)) {
MESON_LOGI("%s is [%s]", __FUNCTION__, meson_hdrPriorityToString(value));
} else {
MESON_LOGE("%s [%d] is invalid", __FUNCTION__, value);
}
return (int32_t)value;
}
void ModePolicy::gethdrforcemode(char* value) {
if (!value) {
MESON_LOGE("%s value is NULL\n", __FUNCTION__);
return;
}
bool ret = false;
char hdr_force_mode[MESON_MODE_LEN] = {0};
memset(hdr_force_mode, 0, MESON_MODE_LEN);
ret = getBootEnv(UBOOTENV_HDR_FORCE_MODE, hdr_force_mode);
if (ret) {
strcpy(value, hdr_force_mode);
} else {
strcpy(value, FORCE_AMDV);
}
MESON_LOGI("get hdr force mode is [%s]", value);
}
bool ModePolicy::isTvDVEnable() {
bool ret = false;
char amdv_enable[MESON_MODE_LEN];
ret = getBootEnv(UBOOTENV_DV_ENABLE, amdv_enable);
if (!ret) {
if (isMboxSupportDV()) {
strcpy(amdv_enable, "1");
} else {
strcpy(amdv_enable, "0");
}
}
MESON_LOGI("dv_enable:%s\n", amdv_enable);
if (!strcmp(amdv_enable, "0")) {
return false;
} else {
return true;
}
}
bool ModePolicy::isDVEnable() {
if (isMboxSupportDV()) {
if (!strcmp(mDvInfo.amdv_enable, "0") ) {
return false;
} else {
return true;
}
} else {
return false;
}
}
/* *
* @Description: Detect Whether TV support dv
* @return: if TV support return true, or false
* if true, mode is the Highest resolution Tv dv supported
* else mode is ""
*/
bool ModePolicy::isTvSupportDV() {
if (DISPLAY_TYPE_TV == mDisplayType) {
MESON_LOGI("Current Device is TV, no dv_cap\n");
return false;
}
if (strstr(mConData.hdr_info.dv_cap, "DolbyVision RX support list") == NULL) {
if (atoi(mConData.hdr_info.dv_cap) == 0)
return false;
}
return true;
}
#ifdef HDR_AMDV_PROPERTY
void ModePolicy::parseHdmiHdrCapabilities(drm_hdr_capabilities & hdrCaps)
{
std::string hdr_cap;
int cap = 0;
getDisplayAttribute(DISPLAY_HDR_CAP, hdr_cap);
MESON_LOGV("parseHdmiHdrCapabilities: hdr cap: %s", hdr_cap.c_str());
memset(&hdrCaps, 0, sizeof(drm_hdr_capabilities));
cap = atoi(hdr_cap.c_str());
if (cap & 0x01)
hdrCaps.HDR10PlusSupported = true;
if (cap & (1 << 3))
hdrCaps.HDR10Supported = true;
if (cap & (1 << 4))
hdrCaps.HLGSupported = true;
}
void ModePolicy::parseDvCapabilities()
{
std::string amdv_cap;
int cap = 0;
getDisplayAttribute(DISPLAY_AMDV_CAP, amdv_cap);
MESON_LOGV("parseDvCapabilities: dv cap: %s", amdv_cap.c_str());
cap = atoi(amdv_cap.c_str());
if (cap != 0 && getDvSupportStatus()) {
mHdrCapabilities.DVSupported = true;
if ((cap & (1 << 2)) == 0)
mHdrCapabilities.AMDV_4K30_Supported = true;
}
}
#else
int32_t getLineValue(const char *lineStr, const char *magicStr) {
int len = 0;
char value[100] = {0};
const char *pos = NULL;
if ((NULL == lineStr) || (NULL == magicStr)) {
MESON_LOGE("line string: %s, magic string: %s\n", lineStr, magicStr);
return 0;
}
if (NULL != (pos = strstr(lineStr, magicStr))) {
pos = pos + strlen(magicStr);
const char* start = pos;
while ((*start <= '9' && *start >= '0') && (strlen(start) > 0))
start++;
len = start - pos;
strncpy(value, pos, len);
value[len] = '\0';
return atoi(value);
}
return 0;
}
void ModePolicy::parseHdmiHdrCapabilities(drm_hdr_capabilities & hdrCaps)
{
std::string hdr_cap;
char buf[1024 + 1] = { 0 };
char* pos = buf;
getDisplayAttribute(DISPLAY_HDR_CAP2, hdr_cap);
MESON_LOGV("parseHdmiHdrCapabilities: hdr cap: %s", hdr_cap.c_str());
strcpy(buf, hdr_cap.c_str());
memset(&hdrCaps, 0, sizeof(drm_hdr_capabilities));
if (pos != NULL) pos = strstr(pos, "HDR10Plus Supported: ");
if ((NULL != pos) && ('1' == *(pos + strlen("HDR10Plus Supported: ")))) {
hdrCaps.HDR10PlusSupported = true;
}
if (pos != NULL) pos = strstr(pos, "SMPTE ST 2084: ");
if ((NULL != pos) && ('1' == *(pos + strlen("SMPTE ST 2084: ")))) {
hdrCaps.HDR10Supported = true;
hdrCaps.maxLuminance = getLineValue(pos, "Max: ");
hdrCaps.avgLuminance = getLineValue(pos, "Avg: ");
hdrCaps.minLuminance = getLineValue(pos, "Min: ");
}
if (pos != NULL) {
char* hybrif = strstr(pos, "Hybrif Log-Gamma: ");
if (NULL != hybrif) {
if ('1' == *(hybrif + strlen("Hybrif Log-Gamma: ")))
hdrCaps.HLGSupported = true;
} else {
/* kernel 5.4, content change to: Hybrid Log-Gamma */
char* hybrid = strstr(pos, "Hybrid Log-Gamma: ");
if ((NULL != hybrid) && ('1' == *(hybrid + strlen("Hybrid Log-Gamma: "))))
hdrCaps.HLGSupported = true;
}
}
}
void ModePolicy::parseDvCapabilities()
{
std::string amdv_cap;
char buf[1024 + 1] = { 0 };
getDisplayAttribute(DISPLAY_AMDV_CAP2, amdv_cap);
MESON_LOGV("parseDvCapabilities: dv cap: %s", amdv_cap.c_str());
strcpy(buf, amdv_cap.c_str());
if (((NULL != strstr(buf, "2160p30hz")) || (NULL != strstr(buf, "2160p60hz"))) &&
getDvSupportStatus()) {
mHdrCapabilities.DVSupported = true;
if (strstr(buf, "2160p30hz"))
mHdrCapabilities.AMDV_4K30_Supported = true;
} else {
mHdrCapabilities.DVSupported = false;
}
}
#endif
void ModePolicy::updateHdrCaps() {
uint32_t type = mConnector ? mConnector->connector_type : 0;
bool supportDv = getDvSupportStatus();
memset(&mHdrCapabilities, 0, sizeof(drm_hdr_capabilities));
if (type == DRM_MODE_CONNECTOR_HDMIA) {
parseHdmiHdrCapabilities(mHdrCapabilities);
parseDvCapabilities();
}
/* for TV product*/
if (type == DRM_MODE_CONNECTOR_MESON_LVDS_A || type == DRM_MODE_CONNECTOR_MESON_LVDS_B ||
type == DRM_MODE_CONNECTOR_MESON_LVDS_C || type == DRM_MODE_CONNECTOR_MESON_VBYONE_A ||
type == DRM_MODE_CONNECTOR_MESON_VBYONE_B || type == DRM_MODE_CONNECTOR_LVDS) {
constexpr int sDefaultMinLumiance = 0;
constexpr int sDefaultMaxLumiance = 500;
mHdrCapabilities.DVSupported = supportDv;
mHdrCapabilities.HLGSupported = true;
mHdrCapabilities.HDR10Supported = true;
mHdrCapabilities.maxLuminance = sDefaultMaxLumiance;
mHdrCapabilities.avgLuminance = sDefaultMaxLumiance;
mHdrCapabilities.minLuminance = sDefaultMinLumiance;
parseDvCapabilities();
MESON_LOGD("dv:%d, hlg:%d, hdr10:%d, hdr10+:%d max:%d, avg:%d, min:%d\n",
mHdrCapabilities.DVSupported ? 1 : 0,
mHdrCapabilities.HLGSupported ? 1 : 0,
mHdrCapabilities.HDR10Supported ? 1 : 0,
mHdrCapabilities.HDR10PlusSupported ? 1 : 0,
mHdrCapabilities.maxLuminance,
mHdrCapabilities.avgLuminance,
mHdrCapabilities.minLuminance);
}
}
void ModePolicy::getHdrCapabilities(drm_hdr_capabilities * caps)
{
if (!caps)
return;
*caps = mHdrCapabilities;
}
bool ModePolicy::isTvSupportHDR() {
if (DISPLAY_TYPE_TV == mDisplayType) {
MESON_LOGI("Current Device is TV, no hdr_cap\n");
return false;
}
drm_hdr_capabilities hdrCaps;
getHdrCapabilities(&hdrCaps);
if (hdrCaps.HLGSupported ||
hdrCaps.HDR10Supported ||
hdrCaps.HDR10PlusSupported) {
return true;
}
return false;
}
bool ModePolicy::isHdrResolutionPriority() {
return sys_get_bool_prop(PROP_HDR_RESOLUTION_PRIORITY, true);
}
bool ModePolicy::isFrameratePriority() {
char frameratePriority[MESON_MODE_LEN] = { 0 };
if (DISPLAY_TYPE_TV == mDisplayType) {
MESON_LOGI("Current Device is TV, no framerate priority\n");
return false;
}
return !getBootEnv(UBOOTENV_FRAMERATE_PRIORITY, frameratePriority) ||
strcmp(frameratePriority, "true") == 0;
}
bool ModePolicy::isSupport4K() {
return sys_get_bool_prop(PROP_SUPPORT_4K, true);
}
bool ModePolicy::isSupport4K30Hz() {
return sys_get_bool_prop(PROP_SUPPORT_OVER_4K30, true);
}
bool ModePolicy::isSupportDeepColor() {
return sys_get_bool_prop(PROP_DEEPCOLOR, true);
}
bool ModePolicy::isLowPowerMode() {
return sys_get_bool_prop(LOW_POWER_DEFAULT_COLOR, false);
}
bool ModePolicy::isMboxSupportDV() {
return getDvSupportStatus();
}
int ModePolicy::parseHdmiHdrStatus() {
std::string HdrStatus;
getDisplayAttribute(DISPLAY_HDMI_HDR_STATUS, HdrStatus);
int hdrMode = atoi(HdrStatus.c_str());
MESON_LOGI("hdr hdmi status: %s conversion result: %d", HdrStatus.c_str(),hdrMode);
return hdrMode;
}
void ModePolicy::getHdrUserInfo(meson_hdr_info_t *data) {
if (!data) {
MESON_LOGE("%s data is NULL\n", __FUNCTION__);
return;
}
int hdrStatus = parseHdmiHdrStatus();
char hdr_force_mode[MESON_MODE_LEN] = {0};
gethdrforcemode(hdr_force_mode);
data->hdr_force_mode = (meson_hdr_force_mode_e)atoi(hdr_force_mode);
char hdr_policy[MESON_MODE_LEN] = {0};
getHdrStrategy(hdr_policy);
data->hdr_policy = (meson_hdr_policy_e)atoi(hdr_policy);
data->hdr_priority = (meson_hdr_priority_e)getHdrPriority();
MESON_LOGI("hdr_policy:%d, hdr_priority :%d(0x%x), hdr_force_mode:%d\n",
data->hdr_policy,
data->hdr_priority, data->hdr_priority,
data->hdr_force_mode);
data->is_amdv_enable = isDVEnable();
data->is_tv_supportDv = isTvSupportDV();
if (data->hdr_policy == 1 && (hdrStatus == HDMI_HDR_STATUS_SDR)) {
data->is_tv_supportHDR = false;
} else {
data->is_tv_supportHDR = isTvSupportHDR();
}
MESON_LOGI("tv_support_hdr status: %d hdrStatus %d", data->is_tv_supportHDR, hdrStatus);
data->is_hdr_resolution_priority = isHdrResolutionPriority();
data->is_lowpower_mode = isLowPowerMode();
char ubootenv_amdv_type[MESON_MODE_LEN];
bool ret = getBootEnv(UBOOTENV_USER_DV_TYPE, ubootenv_amdv_type);
if (ret) {
strcpy(data->ubootenv_dv_type, ubootenv_amdv_type);
} else if (isMboxSupportDV()) {
strcpy(data->ubootenv_dv_type, "1");
} else {
strcpy(data->ubootenv_dv_type, "0");
}
MESON_LOGI("ubootenv_dv_type:%s\n", data->ubootenv_dv_type);
}
bool ModePolicy::initColorAttribute(char* supportedColorList, int len) {
int count = 0;
bool result = false;
if (supportedColorList != NULL) {
memset(supportedColorList, 0, len);
} else {
MESON_LOGE("supportedColorList is NULL\n");
return false;
}
while (true) {
sysfs_get_string(DISPLAY_HDMI_DEEP_COLOR, supportedColorList, len);
if (strlen(supportedColorList) > 0) {
result = true;
break;
}
if (count++ >= 5) {
break;
}
usleep(500000);
}
return result;
}
void ModePolicy::setFilterEdidList(std::map<int, std::string> filterEdidList) {
MESON_LOGI("FormatColorDepth setFilterEdidList size = %" PRIuFAST16 "", filterEdidList.size());
mFilterEdid = filterEdidList;
}
bool ModePolicy::isFilterEdid() {
if (mFilterEdid.empty())
return false;
std::string disPlayEdid = "";
getDisplayAttribute(DISPLAY_EDID_ATTR, disPlayEdid);
MESON_LOGD("edid property: %s\n", disPlayEdid.c_str());
for (int i = 0; i < (int)mFilterEdid.size(); i++) {
if (!strncmp(mFilterEdid[i].c_str(), disPlayEdid.c_str(), strlen(mFilterEdid[i].c_str()))) {
return true;
}
}
return false;
}
bool ModePolicy::isModeSupportDeepColorAttr(const char *mode, const char * color) {
char outputmode[MESON_MODE_LEN] = {0};
strcpy(outputmode, mode);
strcat(outputmode, color);
if (isFilterEdid() && !strstr(color,"8bit")) {
MESON_LOGI("this mode has been filtered");
return false;
}
//try support or not
return sys_set_valid_mode(DISPLAY_HDMI_VALID_MODE, outputmode);
}
bool ModePolicy::isSupportHdmiMode(const char *hdmi_mode, const char *supportedColorList) {
int length = 0;
const char **colorList = NULL;
if (strstr(hdmi_mode, "2160p60hz") != NULL
|| strstr(hdmi_mode,"2160p50hz") != NULL
|| strstr(hdmi_mode,"smpte50hz") != NULL
|| strstr(hdmi_mode,"smpte60hz") != NULL) {
colorList = COLOR_ATTRIBUTE_LIST;
length = ARRAY_SIZE(COLOR_ATTRIBUTE_LIST);
for (int i = 0; i < length; i++) {
if (strstr(supportedColorList, colorList[i]) != NULL) {
if (isModeSupportDeepColorAttr(hdmi_mode, colorList[i])) {
return true;
}
}
}
return false;
} else {
colorList = COLOR_ATTRIBUTE_LIST_8BIT;
length = ARRAY_SIZE(COLOR_ATTRIBUTE_LIST_8BIT);
for (int j = 0; j < length; j++) {
if (strstr(supportedColorList, colorList[j]) != NULL) {
if (isModeSupportDeepColorAttr(hdmi_mode, colorList[j])) {
return true;
}
}
}
return false;
}
}
void ModePolicy::filterHdmiDispcap(meson_connector_info* data) {
char supportedColorList[MESON_MAX_STR_LEN];
if (!(initColorAttribute(supportedColorList, MESON_MAX_STR_LEN))) {
MESON_LOGE("initColorAttribute fail\n");
return;
}
meson_mode_info_t *modes_ptr = data->modes;
for (int i = 0; i < data->modes_size; i++) {
meson_mode_info_t *it = &modes_ptr[i];
MESON_LOGD("before filtered Hdmi support: %s\n", it->name);
if (isSupportHdmiMode(it->name, supportedColorList)) {
MESON_LOGD("after filtered Hdmi support mode : %s\n", it->name);
}
}
}
int32_t ModePolicy::getConnectorData(struct meson_policy_in* data, hdmi_amdv_info_t *dinfo) {
if (!data) {
MESON_LOGE("%s data is NULL\n", __FUNCTION__);
return -EINVAL;
}
getConnectorUserData(data, dinfo);
//get hdmi dv_info
getDvCap(&data->hdr_info);
// get Hdr info
getHdrUserInfo(&data->hdr_info);
//hdmi info
getHdmiEdidStatus(data->con_info.edid_parsing, MESON_MODE_LEN);
//three sink types: sink, repeater, none
data->con_info.sink_type = (meson_sink_type_e)getHdmiSinkType();
MESON_LOGI("display sink type:%d [0:none, 1:sink, 2:repeater]\n", data->con_info.sink_type);
if (HDMI_SINK_TYPE_NONE != data->con_info.sink_type) {
getSupportedModes();
//read hdmi dc_cap
char dc_cap[MESON_MAX_STR_LEN];
getHdmiDcCap(dc_cap, MESON_MAX_STR_LEN);
strcpy(data->con_info.dc_cap, dc_cap);
}
getDisplayMode(data->cur_displaymode);
#if 0
//filter hdmi disp_cap mode for compatibility
filterHdmiDispcap(&data->con_info);
#endif
data->con_info.is_support4k = isSupport4K();
data->con_info.is_support4k30HZ = isSupport4K30Hz();
data->con_info.is_deepcolor = isSupportDeepColor();
data->con_info.isframeratepriority = isFrameratePriority();
return 0;
}
bool ModePolicy::setPolicy(int32_t policy) {
MESON_LOGD("setPolicy %d to %d", mPolicy, policy);
if (DISPLAY_TYPE_TV == mDisplayType)
return true;
if (mPolicy == policy)
return true;
switch (policy) {
case static_cast<int>(MESON_POLICY_BEST):
case static_cast<int>(MESON_POLICY_RESOLUTION):
case static_cast<int>(MESON_POLICY_FRAMERATE):
case static_cast<int>(MESON_POLICY_DV):
mPolicy = static_cast<meson_mode_policy>(policy);
break;
default:
MESON_LOGE("Set invalid policy:%d", policy);
return false;
}
setSourceDisplay(OUTPUT_MODE_STATE_POWER);
applyDisplaySetting(false);
return true;
}
//TODO:: refactor to a thread to handle hotplug
void ModePolicy::onHotplug(bool connected) {
MESON_LOGD("ModePolicy handle hotplug:%d", connected);
//plugout or suspend,set dummy_l
if (!connected) {
setDisplay(OUTPUT_MODE_STATE_POWER);
return;
}
//hdmi edid parse error and hpd = 1
//set default reolsution and color format
if (isHdmiEdidParseOK() == false) {
setDefaultMode();
return;
}
//hdmi edid parse ok
setSourceDisplay(OUTPUT_MODE_STATE_POWER);
applyDisplaySetting(true);
}
void ModePolicy::setActiveConfig(std::string mode) {
mReason = OUTPUT_CHANGE_BY_HWC;
MESON_LOGI("setDisplayed by hwc %s", mode.c_str());
meson_mode_set_policy(mModeConType, MESON_POLICY_INVALID);
setSourceOutputMode(mode.c_str());
meson_mode_set_policy(mModeConType, mPolicy);
mReason = OUTPUT_CHANGE_BY_INIT;
}
int32_t ModePolicy::getPreferredBootConfig(std::string &config) {
if (DISPLAY_TYPE_TV == mDisplayType) {
char curMode[MESON_MODE_LEN] = {0};
getDisplayMode(curMode);
config = curMode;
} else {
#if 0
//1. get hdmi data
hdmi_data_t data;
memset(&data, 0, sizeof(hdmi_data_t));
getHdmiData(&data);
#endif
mConData.state = static_cast<meson_mode_state>(OUTPUT_MODE_STATE_INIT);
mConData.con_info.is_bestcolorspace = true;
//2. scene logic process
meson_mode_set_policy(mModeConType, MESON_POLICY_RESOLUTION);
meson_mode_set_policy_input(mModeConType, &mConData);
meson_mode_get_policy_output(mModeConType, &mSceneOutInfo);
config = mSceneOutInfo.displaymode;
}
MESON_LOGI("getPreferredDisplayConfig [%s]", config.c_str());
meson_mode_set_policy(mModeConType, mPolicy);
return 0;
}
int32_t ModePolicy::setBootConfig(std::string &config) {
MESON_LOGI("set boot display config to %s\n", config.c_str());
setBootEnv(UBOOTENV_ISBESTMODE, "false");
if (mConnectorType == CONN_TYPE_HDMI)
setBootEnv(UBOOTENV_HDMIMODE, config.c_str());
return 0;
}
int32_t ModePolicy::clearBootConfig() {
MESON_LOGI("clear boot display \n");
setBootEnv(UBOOTENV_ISBESTMODE, "true");
//save hdmi resolution to env
// setBootEnv(UBOOTENV_HDMIMODE, "none");
return 0;
}
int32_t ModePolicy::clearUserDisplayConfig() {
SYS_LOGI("clear user display config\n");
//clear user color format
setBootEnv(UBOOTENV_USER_COLORATTRIBUTE, "none");
//clear user dv
setBootEnv(UBOOTENV_USER_DV_TYPE, "none");
//2. set hdmi mode for trigger setting
getDisplayMode(mCurrentMode);
setSourceOutputMode(mCurrentMode);
return 0;
}
int32_t ModePolicy::setColorSpace(std::string &colorspace) {
SYS_LOGI("user change color space to %s\n", colorspace.c_str());
setBootEnv(UBOOTENV_USER_COLORATTRIBUTE, colorspace.c_str());
getDisplayMode(mCurrentMode);
saveDeepColorAttr(mCurrentMode, colorspace.c_str());
//2. set hdmi mode for trigger setting
setSourceOutputMode(mCurrentMode);
return 0;
}
void ModePolicy::getModes(drmModeConnector *connector,
std::map<uint32_t, drm_mode_info_t> &modes)
{
if (!connector)
return;
if (connector->connection != DRM_MODE_CONNECTED)
return;
std::string s_max_output_size;
getDisplayAttribute(DISPLAY_CRTC_MAX_OUTPUT_SIZE, s_max_output_size);
int max_output_size = 0;
int max_output_size_w = 0;
int max_output_size_h = 0;
max_output_size = atoi(s_max_output_size.c_str());
max_output_size_w = max_output_size & 0xffff;
max_output_size_h = max_output_size >> 16;
MESON_LOGD("DISPLAY_CRTC_MAX_OUTPUT_SIZE:%s (%dx%d)",
s_max_output_size.c_str(), max_output_size_w, max_output_size_h);
mConnecterModes.clear();
/*add new display mode list.*/
drmModeModeInfoPtr drmModes = connector->modes;
drm_mode_info_t modeInfo;
memset(&modeInfo, 0, sizeof(modeInfo));
for (int i = 0;i < connector->count_modes; i++) {
if (max_output_size_w != 0 && max_output_size_h != 0
&& drmModes[i].hdisplay > max_output_size_w
&& drmModes[i].vdisplay > max_output_size_h ) {
MESON_LOGD("mode:%dx%d not support", drmModes[i].hdisplay, drmModes[i].vdisplay);
continue;
}
strncpy(modeInfo.name, drmModes[i].name, DRM_DISPLAY_MODE_LEN - 1);
modeInfo.pixelW = drmModes[i].hdisplay;
modeInfo.pixelH = drmModes[i].vdisplay;
if (connector->mmWidth != 0 && connector->mmHeight != 0) {
modeInfo.dpiX = (modeInfo.pixelW * 25.4f) / connector->mmWidth * 1000;
modeInfo.dpiY = (modeInfo.pixelH * 25.4f) / connector->mmHeight * 1000;
}
modeInfo.refreshRate = drmModes[i].vrefresh;
modeInfo.flags = drmModes[i].flags;
bool bNonFractionMode = false;
if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA) {
// default add frac refresh rate config, like 23.976hz, 29.97hz...
if (modeInfo.refreshRate == REFRESH_24kHZ
|| modeInfo.refreshRate == REFRESH_30kHZ
|| modeInfo.refreshRate == REFRESH_60kHZ
|| modeInfo.refreshRate == REFRESH_120kHZ
|| modeInfo.refreshRate == REFRESH_240kHZ) {
if (mFracMode == MODE_ALL || mFracMode == MODE_FRACTION) {
drm_mode_info_t fracMode = modeInfo;
fracMode.refreshRate = (modeInfo.refreshRate * 1000) / (float)1001;
fracMode.groupId = mConnecterModes.size();
mConnecterModes.emplace(mConnecterModes.size(), fracMode);
MESON_LOGD("add fraction display mode (%s)", fracMode.name);
}
} else {
bNonFractionMode = true;
}
}
if (connector->connector_type != DRM_MODE_CONNECTOR_HDMIA ||
mFracMode == MODE_ALL || mFracMode == MODE_NON_FRACTION) {
bNonFractionMode = true;
}
// drm only send frame rate (int)59hz, its real frac refresh rate is 59.94hz
if (modeInfo.refreshRate == 59.00) {
modeInfo.refreshRate = (60 * 1000) / (float)1001;
}
if (bNonFractionMode) {
// add normal refresh rate config, like 24hz, 30hz...
modeInfo.groupId = mConnecterModes.size();
mConnecterModes.emplace(mConnecterModes.size(), modeInfo);
}
MESON_LOGD("add display mode (%s-%s, %dx%d, %f)",
drmModes[i].name, modeInfo.name,
modeInfo.pixelW, modeInfo.pixelH, modeInfo.refreshRate);
}
modes = mConnecterModes;
}
int32_t ModePolicy::bindConnector(drmModeConnector *connector) {
MESON_ASSERT(connector, "ModePolicy bindConnector get null connector!!");
MESON_LOGI("bindConnector: mConnector: %p\n", mConnector);
std::map<uint32_t, drm_mode_info_t> modes;
getModes(connector, modes);
mConnector = connector;
switch (mConnector->connector_type) {
case DRM_MODE_CONNECTOR_HDMIA:
mDisplayType = DISPLAY_TYPE_MBOX;
mConnectorType = CONN_TYPE_HDMI;
mModeConType = MESON_MODE_HDMI;
break;
case LEGACY_NON_DRM_CONNECTOR_PANEL:
case DRM_MODE_CONNECTOR_LVDS:
case DRM_MODE_CONNECTOR_MESON_LVDS_A:
case DRM_MODE_CONNECTOR_MESON_LVDS_B:
case DRM_MODE_CONNECTOR_MESON_LVDS_C:
case DRM_MODE_CONNECTOR_MESON_VBYONE_A:
case DRM_MODE_CONNECTOR_MESON_VBYONE_B:
case DRM_MODE_CONNECTOR_MESON_MIPI_A:
case DRM_MODE_CONNECTOR_MESON_MIPI_B:
case DRM_MODE_CONNECTOR_MESON_EDP_A:
case DRM_MODE_CONNECTOR_MESON_EDP_B:
mDisplayType = DISPLAY_TYPE_TV;
mConnectorType = CONN_TYPE_PANEL;
mModeConType = MESON_MODE_PANEL;
break;
case DRM_MODE_CONNECTOR_TV:
mDisplayType = DISPLAY_TYPE_MBOX;
mConnectorType = CONN_TYPE_CVBS;
mModeConType = MESON_MODE_HDMI;
break;
default:
MESON_LOGE("bindConnector unknown connector type:%d", mConnector->connector_type);
mDisplayType = DISPLAY_TYPE_MBOX;
mConnectorType = CONN_TYPE_HDMI;
mModeConType = MESON_MODE_HDMI;
break;
}
return 0;
}
int32_t ModePolicy::bindCrtc(drmModeCrtcPtr crtc) {
mCrtc = crtc;
mAdapter->initDisplayAttributeInfo(mCrtc, mConnector);
updateHdrCaps();
return 0;
}
/* *
* @Description: init dv graphics priority when bootup.
* */
void ModePolicy::initGraphicsPriority() {
char mode[MESON_MODE_LEN] = {0};
char defVal[MESON_MODE_LEN] = {"1"};
sys_get_string_prop_default(PROP_AMDV_PRIORITY, mode, defVal);
setDisplayAttribute(DISPLAY_AMDV_GRAPHICS_PRIORITY, mode);
sys_set_prop(PROP_AMDV_PRIORITY, mode);
}
/* *
* @Description: set hdr mode
* @params: mode "0":off "1":on "2":auto
* */
void ModePolicy::setHdrMode(const char* mode) {
if ((atoi(mode) >= 0) && (atoi(mode) <= 2)) {
MESON_LOGI("setHdrMode state: %s\n", mode);
setDisplayAttribute(DISPLAY_HDR_MODE, mode);
sys_set_prop(PROP_HDR_MODE_STATE, mode);
}
}
/* *
* @Description: set sdr mode
* @params: mode "0":off "2":auto
* */
void ModePolicy::setSdrMode(const char* mode) {
if ((atoi(mode) == 0) || atoi(mode) == 2) {
MESON_LOGI("setSdrMode state: %s\n", mode);
setDisplayAttribute(DISPLAY_SDR_MODE, mode);
sys_set_prop(PROP_SDR_MODE_STATE, mode);
setBootEnv(UBOOTENV_SDR2HDR, (char *)mode);
}
}
void ModePolicy::initHdrSdrMode() {
char mode[MESON_MODE_LEN] = {0};
char defVal[MESON_MODE_LEN] = {HDR_MODE_AUTO};
sys_get_string_prop_default(PROP_HDR_MODE_STATE, mode, defVal);
setHdrMode(mode);
memset(mode, 0, sizeof(mode));
bool flag = sys_get_bool_prop(PROP_ENABLE_SDR2HDR, false);
if (flag & isDVEnable()) {
strcpy(mode, SDR_MODE_OFF);
} else {
strcpy(defVal, flag ? SDR_MODE_AUTO : SDR_MODE_OFF);
sys_get_string_prop_default(PROP_SDR_MODE_STATE, mode, defVal);
}
setSdrMode(mode);
}
bool ModePolicy::checkDVStatusChanged(int state) {
std::string curDvEnable = "";
std::string curDvLLPolicy = "";
int curDvMode = -1;
getDisplayAttribute(DISPLAY_AMDV_ENABLE, curDvEnable);
getDisplayAttribute(DISPLAY_AMDV_LL_POLICY, curDvLLPolicy);
MESON_LOGI("curDvEnable %s, curDvLLPolicy %s!!\n", curDvEnable.c_str(), curDvLLPolicy.c_str());
if (!strcmp(curDvEnable.c_str(), AMDV_DISABLE) ||
!strcmp(curDvEnable.c_str(), "0"))
curDvMode = AMDV_SET_DISABLE;
else if (!strcmp(curDvLLPolicy.c_str(), "0"))
curDvMode = AMDV_SET_ENABLE;
else if (!strcmp(curDvLLPolicy.c_str(), "1"))
curDvMode = AMDV_SET_ENABLE_LL_YUV;
else if (!strcmp(curDvLLPolicy.c_str(), "2"))
curDvMode = AMDV_SET_ENABLE_LL_RGB;
MESON_LOGI("curDvMode %d, want DvMode %d\n", curDvMode, state);
if (curDvMode != state) {
return true;
} else {
return false;
}
}
//get edid crc value to check edid change
bool ModePolicy::isEdidChange() {
char edid[MESON_MAX_STR_LEN] = {0};
char crcvalue[MESON_MAX_STR_LEN] = {0};
unsigned int crcheadlength = strlen(DEFAULT_EDID_CRCHEAD);
sysfs_get_string(DISPLAY_EDID_VALUE, edid, MESON_MAX_STR_LEN);
char *p = strstr(edid, DEFAULT_EDID_CRCHEAD);
if (p != NULL && strlen(p) > crcheadlength) {
p += crcheadlength;
if (!getBootEnv(UBOOTENV_EDIDCRCVALUE, crcvalue) || strncmp(p, crcvalue, strlen(p))) {
MESON_LOGI("update edidcrc: %s->%s\n", crcvalue, p);
setBootEnv(UBOOTENV_EDIDCRCVALUE, p);
return true;
}
}
return false;
}
void ModePolicy::saveDeepColorAttr(const char* mode, const char* dcValue) {
char ubootvar[100] = {0};
sprintf(ubootvar, "ubootenv.var.%s_deepcolor", mode);
setBootEnv(ubootvar, (char *)dcValue);
}
void ModePolicy::saveHdmiParamToEnv() {
char outputMode[MESON_MODE_LEN] = {0};
char dvenable[MESON_MODE_LEN] = {0};
getDisplayMode(outputMode);
if (strlen(mDvInfo.amdv_enable) > 0)
strcpy(dvenable, mDvInfo.amdv_enable);
// 1. check whether the TV changed or not, if changed save crc
if (isEdidChange()) {
MESON_LOGD("tv sink changed\n");
}
// 2. save coloattr/hdmimode to bootenv if mode is not null or dummy_l
if (strstr(outputMode, "cvbs") != NULL) {
setBootEnv(UBOOTENV_CVBSMODE, (char *)outputMode);
} else if (strcmp(outputMode, "null") && strcmp(outputMode, "dummy_l")) {
std::string colorAttr;
char colorDepth[MESON_MODE_LEN] = {0};
char colorSpace[MESON_MODE_LEN] = {0};
char dvstatus[MESON_MODE_LEN] = {0};
char hdr_policy[MESON_MODE_LEN] = {0};
// 2.1 save color attr
getDisplayAttribute(DISPLAY_HDMI_COLOR_ATTR, colorAttr);
saveDeepColorAttr(outputMode, colorAttr.c_str());
setBootEnv(UBOOTENV_COLORATTRIBUTE, colorAttr.c_str());
//colorDepth&&colorSpace is used for uboot hdmi to find
//best color attributes for the selected hdmi mode when TV changed
char defVal[MESON_MODE_LEN] = {"8"};
sys_get_string_prop_default(PROP_DEEPCOLOR_CTL, colorDepth, defVal);
strcpy(defVal, "auto");
sys_get_string_prop_default(PROP_PIXFMT, colorSpace, defVal);
setBootEnv(UBOOTENV_HDMICOLORDEPTH, colorDepth);
setBootEnv(UBOOTENV_HDMICOLORSPACE, colorSpace);
// 2.2 save output mode,removed, we use hdmimode for hdmi.
// 2.3 save dv status/dv_type
// In follow sink mode: 0:disable 1:STD(or enable dv) 2:LL YUV 3: LL RGB
// In follow source mode: dv is disable in uboot.
if (isMboxSupportDV()) {
char hdr_force_mode[MESON_MODE_LEN] = {0};
memset(hdr_force_mode, 0, MESON_MODE_LEN);
getBootEnv(UBOOTENV_HDR_FORCE_MODE, hdr_force_mode);
getHdrStrategy(hdr_policy);
if (!strcmp(hdr_policy, MESON_HDR_POLICY[MESON_HDR_POLICY_SOURCE]) ||
(!strcmp(hdr_policy, AMDV_POLICY_FORCE_MODE) && !strcmp(hdr_force_mode, FORCE_HDR10))) {
sprintf(dvstatus, "%d", 0);
} else {
sprintf(dvstatus, "%d", mSceneOutInfo.amdv_type);
}
setBootEnv(UBOOTENV_DOLBYSTATUS, dvstatus);
if (strlen(dvenable) > 0)
setBootEnv(UBOOTENV_DV_ENABLE, dvenable);
MESON_LOGI("dvstatus %s dv_type %d dv_enable %s hdr_policy %s hdr_force_mode %s \n",
dvstatus, mSceneOutInfo.amdv_type, mDvInfo.amdv_enable, hdr_policy, hdr_force_mode);
} else {
MESON_LOGI("MBOX is not support dv, dvstatus %s dv_type %d dv_enable %s\n",
dvstatus, mSceneOutInfo.amdv_type, mDvInfo.amdv_enable);
}
MESON_LOGI("colorattr: %s, outputMode %s, cd %s, cs %s\n",
colorAttr.c_str(), outputMode, colorDepth, colorSpace);
}
}
bool ModePolicy::updateEnv()
{
if (mDisplayType == DISPLAY_TYPE_MBOX)
saveHdmiParamToEnv();
return true;
}
void ModePolicy::enableDV(int DvMode) {
if (isMboxSupportDV() == false) {
MESON_LOGI("This platform is not support dv or has no dv ko");
return;
}
MESON_LOGI("DvMode %d", DvMode);
strcpy(mDvInfo.amdv_enable, "1");
//if TV
if (DISPLAY_TYPE_TV == mDisplayType) {
setHdrMode(HDR_MODE_OFF);
setDisplayAttribute(DISPLAY_AMDV_POLICY, AMDV_POLICY_FOLLOW_SINK);
}
//if OTT
char hdr_policy[MESON_MODE_LEN] = {0};
getHdrStrategy(hdr_policy);
if ((DISPLAY_TYPE_MBOX == mDisplayType) || (DISPLAY_TYPE_REPEATER == mDisplayType)) {
switch (DvMode) {
case AMDV_SET_ENABLE:
MESON_LOGI("Dv set Mode [DV_RGB_444_8BIT]\n");
setDisplayAttribute(DISPLAY_AMDV_LL_POLICY, "0");
break;
case AMDV_SET_ENABLE_LL_YUV:
MESON_LOGI("Dv set Mode [LL_YCbCr_422_12BIT]\n");
setDisplayAttribute(DISPLAY_AMDV_LL_POLICY, "0");
setDisplayAttribute(DISPLAY_AMDV_LL_POLICY, "1");
break;
case AMDV_SET_ENABLE_LL_RGB:
setDisplayAttribute(DISPLAY_AMDV_LL_POLICY, "0");
setDisplayAttribute(DISPLAY_AMDV_LL_POLICY, "2");
break;
default:
setDisplayAttribute(DISPLAY_AMDV_LL_POLICY, "0");
}
if (strstr(hdr_policy, MESON_HDR_POLICY[MESON_HDR_POLICY_SINK])) {
setDisplayAttribute(DISPLAY_HDR_POLICY, MESON_HDR_POLICY[MESON_HDR_POLICY_SINK]);
if (isDVEnable()) {
setDisplayAttribute(DISPLAY_AMDV_POLICY, MESON_HDR_POLICY[MESON_HDR_POLICY_SINK]);
}
} else if (strstr(hdr_policy, MESON_HDR_POLICY[MESON_HDR_POLICY_SOURCE])) {
setDisplayAttribute(DISPLAY_HDR_POLICY, MESON_HDR_POLICY[MESON_HDR_POLICY_SOURCE]);
if (isDVEnable()) {
setDisplayAttribute(DISPLAY_AMDV_POLICY, MESON_HDR_POLICY[MESON_HDR_POLICY_SOURCE]);
}
} else if (strstr(hdr_policy, AMDV_POLICY_FORCE_MODE)) {
setDisplayAttribute(DISPLAY_HDR_POLICY, MESON_HDR_POLICY[MESON_HDR_POLICY_FORCE]);
if (isDVEnable()) {
setDisplayAttribute(DISPLAY_AMDV_POLICY, AMDV_POLICY_FORCE_MODE);
}
}
}
setDisplayAttribute(DISPLAY_AMDV_ENABLE, AMDV_ENABLE);
if (strstr(hdr_policy, AMDV_POLICY_FORCE_MODE)) {
char hdr_force_mode[MESON_MODE_LEN] = {0};
gethdrforcemode(hdr_force_mode);
if (strstr(hdr_force_mode, FORCE_AMDV)) {
setDisplayAttribute(DISPLAY_AMDV_MODE, FORCE_AMDV);
} else if (strstr(hdr_force_mode, FORCE_HDR10)) {
setDisplayAttribute(DISPLAY_AMDV_MODE, FORCE_HDR10);
} else if (strstr(hdr_force_mode, AMDV_DISABLE_FORCE_SDR)) {
// 8bit or not
std::string cur_ColorAttribute;
getDisplayAttribute(DISPLAY_HDMI_COLOR_ATTR, cur_ColorAttribute);
if (cur_ColorAttribute.find("8bit", 0) != std::string::npos) {
setDisplayAttribute(DISPLAY_AMDV_MODE, AMDV_ENABLE_FORCE_SDR_8BIT);
} else {
setDisplayAttribute(DISPLAY_AMDV_MODE, AMDV_ENABLE_FORCE_SDR_10BIT);
}
}
} else {
int amdv_prop = DvMode == AMDV_SET_ENABLE_LL_YUV ? 1 : 0;
setDisplayAttribute(DISPLAY_AMDV_MODE, to_string(amdv_prop));
}
if (DISPLAY_TYPE_TV == mDisplayType) {
setHdrMode(HDR_MODE_AUTO);
}
initGraphicsPriority();
}
void ModePolicy::disableDV(int DvMode) {
//char tvmode[MESON_MODE_LEN] = {0};
int check_status_count = 0;
[[maybe_unused]] int amdv_type = DvMode;
MESON_LOGI("amdv_type %d", amdv_type);
strcpy(mDvInfo.amdv_enable, "0");
//2. update sysfs
char hdr_policy[MESON_MODE_LEN] = {0};
getHdrStrategy(hdr_policy);
if (strstr(hdr_policy, MESON_HDR_POLICY[MESON_HDR_POLICY_SINK])) {
setDisplayAttribute(DISPLAY_HDR_POLICY, MESON_HDR_POLICY[MESON_HDR_POLICY_SINK]);
} else if (strstr(hdr_policy, MESON_HDR_POLICY[MESON_HDR_POLICY_SOURCE])) {
setDisplayAttribute(DISPLAY_HDR_POLICY, MESON_HDR_POLICY[MESON_HDR_POLICY_SOURCE]);
}
setDisplayAttribute(DISPLAY_AMDV_POLICY, AMDV_POLICY_FORCE_MODE);
setDisplayAttribute(DISPLAY_AMDV_MODE, AMDV_MODE_BYPASS);
usleep(100000);//100ms
std::string dvstatus = "";
getDisplayAttribute(DISPLAY_AMDV_STATUS, dvstatus);
if (strcmp(dvstatus.c_str(), BYPASS_PROCESS)) {
while (++check_status_count <30) {
usleep(20000);//20ms
getDisplayAttribute(DISPLAY_AMDV_STATUS, dvstatus);
if (!strcmp(dvstatus.c_str(), BYPASS_PROCESS)) {
break;
}
}
}
MESON_LOGI("dvstatus %s, check_status_count [%d]", dvstatus.c_str(), check_status_count);
setDisplayAttribute(DISPLAY_AMDV_ENABLE, AMDV_DISABLE);
if (DISPLAY_TYPE_TV == mDisplayType) {
setHdrMode(HDR_MODE_AUTO);
}
setSdrMode(SDR_MODE_AUTO);
}
void ModePolicy::getPosition(const char* curMode, int *position) {
char keyValue[20] = {0};
char ubootvar[100] = {0};
int defaultWidth = 0;
int defaultHeight = 0;
std::map<uint32_t, drm_mode_info_t> connecterModeList;
drm_mode_info_t mode = {
"null",
0, 0,
0, 0,
60.0,
0
};
if (mConnector->connection == DRM_MODE_CONNECTED) {
getModes(mConnector, connecterModeList);
for (auto it = connecterModeList.begin(); it != connecterModeList.end(); it++) {
if (mConnector->connector_type == DRM_MODE_CONNECTOR_TV) {
if (strstr(curMode, it->second.name)) {
strcpy(keyValue, curMode);
mode = it->second;
break;
}
} else {
if (strstr(curMode, it->second.name)) {
if (strstr(it->second.name, MODE_4K2KSMPTE_PREFIX)) {
strcpy(keyValue, "4k2ksmpte");
} else if (strstr(it->second.name, MODE_PANEL)) {
strcpy(keyValue, MODE_PANEL);
} else if (strchr(curMode,'p')) {
strncpy(keyValue, curMode, strchr(curMode,'p') - curMode + 1);
} else if (strchr(curMode,'i')){
strncpy(keyValue, curMode, strchr(curMode,'i') - curMode + 1);
}
mode = it->second;
break;
}
}
}
}
if (keyValue[0] != '0') {
defaultWidth = mode.pixelW;
defaultHeight = mode.pixelH;
} else {
strcpy(keyValue, MODE_1080P_PREFIX);
defaultWidth = FULL_WIDTH_1080;
defaultHeight = FULL_HEIGHT_1080;
}
pthread_mutex_lock(&mEnvLock);
sprintf(ubootvar, "ubootenv.var.%s_x", keyValue);
position[0] = getBootenvInt(ubootvar, 0);
sprintf(ubootvar, "ubootenv.var.%s_y", keyValue);
position[1] = getBootenvInt(ubootvar, 0);
sprintf(ubootvar, "ubootenv.var.%s_w", keyValue);
position[2] = getBootenvInt(ubootvar, defaultWidth);
sprintf(ubootvar, "ubootenv.var.%s_h", keyValue);
position[3] = getBootenvInt(ubootvar, defaultHeight);
MESON_LOGI("%s curMode:%s position[0]:%d position[1]:%d position[2]:%d position[3]:%d\n", __FUNCTION__, curMode, position[0], position[1], position[2], position[3]);
pthread_mutex_unlock(&mEnvLock);
}
void ModePolicy::setPosition(const char* curMode, int left, int top, int width, int height) {
char x[512] = {0};
char y[512] = {0};
char w[512] = {0};
char h[512] = {0};
sprintf(x, "%d", left);
sprintf(y, "%d", top);
sprintf(w, "%d", width);
sprintf(h, "%d", height);
MESON_LOGI("%s curMode:%s left:%d top:%d width:%d height:%d\n", __FUNCTION__, curMode, left, top, width, height);
char keyValue[20] = {0};
char ubootvar[100] = {0};
bool find = false;
std::map<uint32_t, drm_mode_info_t> connecterModeList;
if (mConnector->connection == DRM_MODE_CONNECTED) {
getModes(mConnector, connecterModeList);
for (auto it = connecterModeList.begin(); it != connecterModeList.end(); it++) {
if (mConnector->connector_type == DRM_MODE_CONNECTOR_TV) {
if (strstr(curMode, it->second.name)) {
strcpy(keyValue, curMode);
find = true;
break;
}
} else {
if (strstr(curMode, it->second.name)) {
if (strstr(it->second.name, MODE_4K2KSMPTE_PREFIX)) {
strcpy(keyValue, "4k2ksmpte");
find = true;
} else if (strstr(it->second.name, MODE_PANEL)) {
strcpy(keyValue, MODE_PANEL);
find = true;
} else if (strchr(curMode,'p')) {
strncpy(keyValue, curMode, strchr(curMode,'p') - curMode + 1);
find = true;
} else if (strchr(curMode,'i')){
strncpy(keyValue, curMode, strchr(curMode,'i') - curMode + 1);
find = true;
}
break;
}
}
}
}
if (!find)
return;
mAdapter->setDisplayRect(left, top, width , height);
}
void ModePolicy::setDigitalMode(const char* mode) {
if (mode == NULL) return;
if (!strcmp("PCM", mode)) {
sysfs_set_string(AUDIO_DSP_DIGITAL_RAW, "0");
sysfs_set_string(AV_HDMI_CONFIG, "audio_on");
} else if (!strcmp("SPDIF passthrough", mode)) {
sysfs_set_string(AUDIO_DSP_DIGITAL_RAW, "1");
sysfs_set_string(AV_HDMI_CONFIG, "audio_on");
} else if (!strcmp("HDMI passthrough", mode)) {
sysfs_set_string(AUDIO_DSP_DIGITAL_RAW, "2");
sysfs_set_string(AV_HDMI_CONFIG, "audio_on");
}
}
bool ModePolicy::getDisplayMode(char* mode) {
bool ret = false;
if (mode != NULL) {
ret = mAdapter->getDisplayMode(mode);
MESON_LOGI("%s mode:%s\n", __FUNCTION__, mode);
} else {
MESON_LOGE("%s mode is NULL\n", __FUNCTION__);
}
return ret;
}
//set hdmi output mode
int32_t ModePolicy::setDisplayMode(std::string &mode) {
MESON_LOGI("%s mode:%s\n", __FUNCTION__, mode.c_str());
mAdapter->setDisplayMode(mode);
return 0;
}
int32_t ModePolicy::setDisplayMode(const char *mode) {
if (!mode) {
MESON_LOGE("ModePolicy::setDisplayMode null mode");
return -EINVAL;
}
std::string displayMode(mode);
return setDisplayMode(displayMode);
}
bool ModePolicy::setDisplayAttribute(const std::string cmd, const std::string attribute) {
return mAdapter->setDisplayAttribute(cmd, attribute);
}
bool ModePolicy::getDisplayAttribute(const std::string cmd, std::string& attribute) {
return mAdapter->getDisplayAttribute(cmd, attribute);
}
bool ModePolicy::isMatchMode(char* curmode, const char* outputmode) {
bool ret = false;
char tmpMode[MESON_MODE_LEN] = {0};
char *pCmp = curmode;
//check line feed key
char *pos = strchr(pCmp, 0x0a);
if (NULL == pos) {
//check return key
char *pos = strchr(pCmp, 0x0d);
if (NULL == pos) {
strcpy(tmpMode, pCmp);
} else {
strncpy(tmpMode, pCmp, pos - pCmp);
}
} else {
strncpy(tmpMode, pCmp, pos - pCmp);
}
MESON_LOGI("curmode:%s, tmpMode:%s, outputmode:%s\n", curmode, tmpMode, outputmode);
if (!strcmp(tmpMode, outputmode)) {
ret = true;
}
return ret;
}
bool ModePolicy::isTvSupportALLM() {
char allm_mode_cap[PROP_VALUE_MAX];
memset(allm_mode_cap, 0, PROP_VALUE_MAX);
int ret = 0;
sysfs_get_string(AUTO_LOW_LATENCY_MODE_CAP, allm_mode_cap, PROP_VALUE_MAX);
for (int i = 0; i < ARRAY_SIZE(ALLM_MODE_CAP); i++) {
if (!strncmp(allm_mode_cap, ALLM_MODE_CAP[i], strlen(ALLM_MODE_CAP[i]))) {
ret = i;
}
}
return (ret == 1) ? true : false;
}
bool ModePolicy::getContentTypeSupport(const char* type) {
char content_type_cap[MESON_MAX_STR_LEN] = {0};
sysfs_get_string(HDMI_CONTENT_TYPE_CAP, content_type_cap, MESON_MAX_STR_LEN);
if (strstr(content_type_cap, type)) {
MESON_LOGI("getContentTypeSupport: %s is true", type);
return true;
}
MESON_LOGI("getContentTypeSupport: %s is false", type);
return false;
}
bool ModePolicy::getGameContentTypeSupport() {
return getContentTypeSupport(CONTENT_TYPE_CAP[3]);
}
bool ModePolicy::getSupportALLMContentTypeList(std::vector<std::string> *supportModes) {
if (isTvSupportALLM()) {
(*supportModes).push_back(std::string("allm"));
}
for (int i = 0; i < ARRAY_SIZE(CONTENT_TYPE_CAP); i++) {
if (getContentTypeSupport(CONTENT_TYPE_CAP[i])) {
(*supportModes).push_back(std::string(CONTENT_TYPE_CAP[i]));
}
}
return true;
}
void ModePolicy::setTvDVEnable() {
//if TV
setHdrMode(HDR_MODE_OFF);
setDisplayAttribute(DISPLAY_AMDV_POLICY, AMDV_POLICY_FOLLOW_SINK);
usleep(100000);//100ms
setDisplayAttribute(DISPLAY_AMDV_ENABLE, AMDV_ENABLE);
usleep(100000);//100ms
setHdrMode(HDR_MODE_AUTO);
initGraphicsPriority();
}
void ModePolicy::setTvDVDisable() {
int check_status_count = 0;
//2. update sysfs
setDisplayAttribute(DISPLAY_HDR_POLICY, MESON_HDR_POLICY[MESON_HDR_POLICY_SINK]);
setDisplayAttribute(DISPLAY_AMDV_POLICY, AMDV_POLICY_FORCE_MODE);
setDisplayAttribute(DISPLAY_AMDV_MODE, AMDV_MODE_BYPASS);
usleep(100000);//100ms
std::string dvstatus = "";
getDisplayAttribute(DISPLAY_AMDV_STATUS, dvstatus);
if (strcmp(dvstatus.c_str(), BYPASS_PROCESS)) {
while (++check_status_count <30) {
usleep(20000);//20ms
getDisplayAttribute(DISPLAY_AMDV_STATUS, dvstatus);
if (!strcmp(dvstatus.c_str(), BYPASS_PROCESS)) {
break;
}
}
}
MESON_LOGI("dvstatus %s, check_status_count [%d]", dvstatus.c_str(), check_status_count);
setDisplayAttribute(DISPLAY_AMDV_ENABLE, AMDV_DISABLE);
setHdrMode(HDR_MODE_AUTO);
setSdrMode(SDR_MODE_AUTO);
}
int32_t ModePolicy::setDvMode(std::string &amdv_mode) {
MESON_LOGI("%s dv mode:%s", __FUNCTION__, amdv_mode.c_str());
if (DISPLAY_TYPE_TV == mDisplayType) {
//1. update prop
strcpy(mConData.hdr_info.ubootenv_dv_type, amdv_mode.c_str());
//2. apply to driver
if (strstr(amdv_mode.c_str(), "0")) {
strcpy(mDvInfo.amdv_enable, "0");
setTvDVDisable();
} else {
strcpy(mDvInfo.amdv_enable, "1");
setTvDVEnable();
}
//3. save env
setBootEnv(UBOOTENV_DV_ENABLE, mDvInfo.amdv_enable);
} else {
//1. update dv env
strcpy(mConData.hdr_info.ubootenv_dv_type, amdv_mode.c_str());
if (strstr(amdv_mode.c_str(), "0")) {
strcpy(mDvInfo.amdv_enable, "0");
} else {
strcpy(mDvInfo.amdv_enable, "1");
}
//Save user prefer dv mode only user change dv through UI
setBootEnv(UBOOTENV_USER_DV_TYPE, mConData.hdr_info.ubootenv_dv_type);
setBootEnv(UBOOTENV_DV_ENABLE, mDvInfo.amdv_enable);
setBootEnv(UBOOTENV_DOLBYSTATUS, amdv_mode.c_str());
//2. set hdmi mode for trigger setting
setSourceOutputMode(mCurrentMode);
}
return 0;
}
/* *
* @Description: this is a temporary solution, should be revert when android.hardware.graphics.composer@2.4 finished
* set the ALLM_Mode
* @params: "0": ALLM disable (VSIF still contain allm info)
* "1": ALLM enable
* "-1":really disable ALLM (VSIF don't contain allm info)
* */
void ModePolicy::setALLMMode(int state) {
/***************************************************************
* Comment for special solution in this func *
***************************************************************
* *
* In HDMI Standard only 0 to disable ALLM and 1 to enable ALLM*
* but ALLM and DV share the same bit in VSIF *
* it cause conflict *
* *
* So in amlogic special solution: *
* we add -1 to *
* 1: disable ALLM *
* 2: clean ALLM info in VSIF conflict bit *
* when user set 0 to ALLM *
* we will force change 0 into -1 here *
* *
***************************************************************/
if (!isTvSupportALLM()) {
SYS_LOGI("setALLMMode: TV not support ALLM\n");
return;
}
int perState = -1;
char cur_allm_state[MESON_MODE_LEN] = {0};
sysfs_get_string(AUTO_LOW_LATENCY_MODE, cur_allm_state, MESON_MODE_LEN);
perState = atoi(cur_allm_state);
if (perState == state) {
SYS_LOGI("setALLMMode: the ALLM_Mode is not changed :%d\n", state);
return;
}
bool isTVSupportDV = isTvSupportDV();
char ubootenv_amdv_enable[MESON_MODE_LEN] = {0};
std::string cur_ColorAttribute;
char ubootenv_amdv_type[MESON_MODE_LEN] = {0};
bool ret = false;
switch (state) {
case -1:
[[fallthrough]];
case 0:
//1. disable allm
sysfs_set_string(AUTO_LOW_LATENCY_MODE, ALLM_MODE[0]);
MESON_LOGI("setALLMMode: ALLM_Mode: %s", ALLM_MODE[0]);
//2.1 get dv status before enable allm
getBootEnv(UBOOTENV_DV_ENABLE, ubootenv_amdv_enable);
//2.2 get current hdmi output resolution
getDisplayMode(mCurrentMode);
//2.3 get current hdmi output color space
getDisplayAttribute(DISPLAY_HDMI_COLOR_ATTR, cur_ColorAttribute);
//2.4 get dv type before enable allm
ret = getBootEnv(UBOOTENV_USER_DV_TYPE, ubootenv_amdv_type);
//3 enable dv
//when TV and current resolution support dv and dv is enable before enable allm
if (isTVSupportDV
&& !strcmp(ubootenv_amdv_enable, "1")
&& !(meson_mode_support_mode(mModeConType, MESON_DOLBY_VISION_PRIORITY, mCurrentMode))) {
// restore doblyvision when set -1/0 to ALLM
if (!ret) {
//best dv policy:sink-led -->source led
if (strstr(mConData.hdr_info.dv_deepcolor, "DV_RGB_444_8BIT") != NULL
&& strstr(cur_ColorAttribute.c_str(), "444,8bit") != NULL) {
enableDV(AMDV_SET_ENABLE);
mSceneOutInfo.amdv_type = AMDV_SET_ENABLE;
} else if (strstr(mConData.hdr_info.dv_deepcolor, "LL_YCbCr_422_12BIT") != NULL
&& strstr(cur_ColorAttribute.c_str(), "422,12bit") != NULL) {
enableDV(AMDV_SET_ENABLE_LL_YUV);
mSceneOutInfo.amdv_type = AMDV_SET_ENABLE_LL_YUV;
} else {
SYS_LOGI("can't enable dv for dv_deepcolor: %s and curColorAttribute: %s\n",
mConData.hdr_info.dv_deepcolor, cur_ColorAttribute.c_str());
}
} else if (!strcmp(ubootenv_amdv_type, "2") && strstr(cur_ColorAttribute.c_str(), "422,12bit") != NULL) {
enableDV(AMDV_SET_ENABLE_LL_YUV);
mSceneOutInfo.amdv_type = AMDV_SET_ENABLE_LL_YUV;
} else if (!strcmp(ubootenv_amdv_type, "1") && strstr(cur_ColorAttribute.c_str(), "444,8bit") != NULL) {
enableDV(AMDV_SET_ENABLE);
mSceneOutInfo.amdv_type = AMDV_SET_ENABLE;
} else {
SYS_LOGI("can't enable dv for curColorAttribute: %s\n", cur_ColorAttribute.c_str());
}
}
break;
case 1:
//when TV support dv and dv is enable
if (isTVSupportDV && isDVEnable()) {
mSceneOutInfo.amdv_type = AMDV_SET_DISABLE;
// disable the doblyvision when ALLM enable
disableDV(AMDV_SET_DISABLE);
}
//2. enable allm
sysfs_set_string(AUTO_LOW_LATENCY_MODE, ALLM_MODE[2]);
MESON_LOGI("setALLMMode: ALLM_Mode: %s", ALLM_MODE[2]);
break;
default:
MESON_LOGE("setALLMMode: ALLM_Mode: error state[%d]", state);
break;
}
}
bool ModePolicy::isTvConnector() {
auto type = mConnector->connector_type;
if (type == DRM_MODE_CONNECTOR_MESON_LVDS_A || type == DRM_MODE_CONNECTOR_MESON_LVDS_B ||
type == DRM_MODE_CONNECTOR_MESON_LVDS_C || type == DRM_MODE_CONNECTOR_MESON_VBYONE_A ||
type == DRM_MODE_CONNECTOR_MESON_VBYONE_B || type == DRM_MODE_CONNECTOR_LVDS ||
type == LEGACY_NON_DRM_CONNECTOR_PANEL)
return true;
return false;
}
int32_t ModePolicy::setAutoLowLatencyMode(bool enabled) {
auto type = mConnector->connector_type;
if (type == DRM_MODE_CONNECTOR_HDMIA) {
if (!isTvSupportALLM()) {
return -1;
}
if (enabled) {
sysfs_set_string(LOW_LATENCY, LOW_LATENCY_ENABLE);
} else {
sysfs_set_string(LOW_LATENCY, LOW_LATENCY_DISABLE);
}
setALLMMode(enabled);
return 0;
}
// do nothing for tv
if (isTvConnector())
return 0;
return -1;
}
void ModePolicy::setAllowedHdrTypes(uint32_t allowedHdrTypes, bool isAuto, bool passThrough) {
//Match content Dynamic range
if (passThrough) {
setBootEnv(UBOOTENV_HDR_PREFERRED_POLICY, MESON_HDR_PREFERRED_POLICY[MESON_HDR_MATCH_CONTENT]);
}
// force SDR when autoAllowedHdrTypes are empty on system-preferred conversion
else if (allowedHdrTypes == 0 && isAuto) {
uint32_t userHdrType = 0;
userHdrType = userHdrType | (1 << HAL_HDR_AMDV);
userHdrType = userHdrType | (1 << HAL_HDR_HDR10);
userHdrType = userHdrType | (1 << HAL_HDR_HLG);
userHdrType = userHdrType | (1 << DRM_INVALID);
string keyValue = std::to_string(userHdrType);
setBootEnv(UBOOTENV_USER_PREFERRED_HDR_TYPE, keyValue.c_str());
setBootEnv(UBOOTENV_HDR_PREFERRED_POLICY, MESON_HDR_PREFERRED_POLICY[MESON_HDR_SYSTEM_PREFERRED]);
return;
} else {
//bit0-bit4 for hdr type and 1 is disable 0 is enable
uint32_t userHdrType = 0;
userHdrType = userHdrType | (1 << HAL_HDR_AMDV);
userHdrType = userHdrType | (1 << HAL_HDR_HDR10);
userHdrType = userHdrType | (1 << HAL_HDR_HLG);
userHdrType = userHdrType | (1 << DRM_INVALID);
allowedHdrTypes ^= userHdrType;
allowedHdrTypes &= userHdrType;
string keyValue = std::to_string(allowedHdrTypes);
setBootEnv(UBOOTENV_USER_PREFERRED_HDR_TYPE, keyValue.c_str());
if (isAuto)
setBootEnv(UBOOTENV_HDR_PREFERRED_POLICY, MESON_HDR_PREFERRED_POLICY[MESON_HDR_SYSTEM_PREFERRED]);
else
setBootEnv(UBOOTENV_HDR_PREFERRED_POLICY, MESON_HDR_PREFERRED_POLICY[MESON_HDR_FORCE]);
MESON_LOGD("%s AllowedHdrType %d isAuto %d keyValue %s \n", __func__, allowedHdrTypes, isAuto, keyValue.c_str());
}
return;
}
int32_t ModePolicy::getPreferredHdrConversionType(void) {
int32_t outHdrConversionType = -1;
char auto_policy[MESON_MODE_LEN] = {0};
memset(auto_policy, 0, MESON_MODE_LEN);
getBootEnv(UBOOTENV_HDR_PREFERRED_POLICY, auto_policy);
//Match content Dynamic range
if (strstr(auto_policy, MESON_HDR_PREFERRED_POLICY[MESON_HDR_MATCH_CONTENT])) {
mHdr_policy = MESON_HDR_POLICY_SOURCE;
mHdr_priority = MESON_G_DV_HDR10_HLG;
}
//System-preferred conversion or Force conversion
else {
bool isAuto = true;
if (strstr(auto_policy, MESON_HDR_PREFERRED_POLICY[MESON_HDR_FORCE])) {
isAuto = false;
}
char user_hdr_type[MESON_MODE_LEN] = {0};
memset(user_hdr_type, 0, MESON_MODE_LEN);
bool ret = getBootEnv(UBOOTENV_USER_PREFERRED_HDR_TYPE, user_hdr_type);
int32_t allowedHdrType = atoi(user_hdr_type);
if (ret) {
allowedHdrType = atoi(user_hdr_type);
} else {
allowedHdrType = 0; //all hdr enable as default
}
//force SDR when autoAllowedHdrTypes are empty on system-preferred conversion
uint32_t userHdrType = 0;
userHdrType = userHdrType | (1 << HAL_HDR_AMDV);
userHdrType = userHdrType | (1 << HAL_HDR_HDR10);
userHdrType = userHdrType | (1 << HAL_HDR_HLG);
userHdrType = userHdrType | (1 << DRM_INVALID);
string keyValue = std::to_string(userHdrType);
if (isAuto && strstr (user_hdr_type, keyValue.c_str())) {
mHdr_priority = MESON_G_SDR;
outHdrConversionType = DRM_INVALID;
} else {
bool containDVType = false, containHDR10Type = false,
containHLGType = false, containSDRType = false;
MESON_LOGD("allowedHdrType 0x%x ", allowedHdrType);
if (!(allowedHdrType & (1 << HAL_HDR_AMDV)))
containDVType = true;
if (!(allowedHdrType & (1 << HAL_HDR_HDR10)))
containHDR10Type = true;
if (!(allowedHdrType & (1 << HAL_HDR_HLG)))
containHLGType = true;
if (!(allowedHdrType & (1 << DRM_INVALID)))
containSDRType = true;
drm_hdr_capabilities hdrCaps;
getHdrCapabilities(&hdrCaps);
if (isAuto) {
if (hdrCaps.DVSupported) {
if (containHLGType && containHDR10Type && containDVType) {
mHdr_policy = MESON_HDR_POLICY_SINK;
mHdr_priority = MESON_G_DV_HDR10_HLG;
outHdrConversionType = static_cast<int32_t>(HAL_HDR_AMDV);
} else if (containHDR10Type && containDVType) {
mHdr_policy = MESON_HDR_POLICY_SINK;
mHdr_priority = MESON_G_DV_HDR10;
outHdrConversionType = static_cast<int32_t>(HAL_HDR_AMDV);
} else if (containHLGType && containDVType) {
mHdr_policy = MESON_HDR_POLICY_SINK;
mHdr_priority = MESON_G_DV_HLG;
outHdrConversionType = static_cast<int32_t>(HAL_HDR_AMDV);
} else if (containHLGType && containHDR10Type) {
mHdr_policy = MESON_HDR_POLICY_SINK;
mHdr_priority = MESON_G_HDR10_HLG;
outHdrConversionType = static_cast<int32_t>(HAL_HDR_HDR10);
} else if (containDVType) {
mHdr_policy = MESON_HDR_POLICY_SINK;
mHdr_priority = MESON_G_DV;
outHdrConversionType = static_cast<int32_t>(HAL_HDR_AMDV);
} else if (containHDR10Type) {
mHdr_policy = MESON_HDR_POLICY_SINK;
mHdr_priority = MESON_G_HDR10;
outHdrConversionType = static_cast<int32_t>(HAL_HDR_HDR10);
} else if (containHLGType) {
mHdr_priority = MESON_G_HLG;
mHdr_policy = MESON_HDR_POLICY_SOURCE; //follow source due to dv can't HLG output
} else {
mHdr_policy = MESON_HDR_POLICY_SINK;
mHdr_priority = MESON_G_SDR;
outHdrConversionType = DRM_INVALID; //force sdr
}
} else {
if (containHLGType && containHDR10Type) {
mHdr_policy = MESON_HDR_POLICY_SINK;
mHdr_priority = MESON_G_HDR10_HLG;
outHdrConversionType = static_cast<int32_t>(HAL_HDR_HDR10);
} else if (containHDR10Type) {
mHdr_policy = MESON_HDR_POLICY_SINK;
mHdr_priority = MESON_G_HDR10;
outHdrConversionType = static_cast<int32_t>(HAL_HDR_HDR10);
} else if (containHLGType) {
mHdr_policy = MESON_HDR_POLICY_SINK;
mHdr_priority = MESON_G_HLG;
outHdrConversionType = static_cast<int32_t>(HAL_HDR_HLG);
} else {
mHdr_policy = MESON_HDR_POLICY_SINK;
mHdr_priority = MESON_G_SDR;
outHdrConversionType = DRM_INVALID; //force sdr
}
}
} else {
if (containDVType) {
if (hdrCaps.DVSupported) {
mHdr_policy = MESON_HDR_POLICY_SINK;
mHdr_priority = MESON_G_DV;
outHdrConversionType = static_cast<int32_t>(HAL_HDR_AMDV);
} else {
mHdr_policy = MESON_HDR_POLICY_SOURCE; //follow source
mHdr_priority = MESON_G_DV_HDR10_HLG;
}
} else if (containHDR10Type) {
if (hdrCaps.HDR10Supported) {
mHdr_policy = MESON_HDR_POLICY_SINK;
mHdr_priority = MESON_G_HDR10;
outHdrConversionType = static_cast<int32_t>(HAL_HDR_HDR10);
} else {
mHdr_policy = MESON_HDR_POLICY_SOURCE; //follow source
mHdr_priority = MESON_G_DV_HDR10_HLG;
}
} else if (containHLGType) {
if (hdrCaps.HLGSupported) {
if (hdrCaps.DVSupported) {
mHdr_policy = MESON_HDR_POLICY_SOURCE; //follow source due to dv can't HLG output
mHdr_priority = MESON_G_DV_HDR10_HLG;
} else {
mHdr_policy = MESON_HDR_POLICY_SINK;
mHdr_priority = MESON_G_HLG;
outHdrConversionType = static_cast<int32_t>(HAL_HDR_HLG);
}
} else {
mHdr_policy = MESON_HDR_POLICY_SOURCE; //follow source
mHdr_priority = MESON_G_DV_HDR10_HLG;
}
} else {
mHdr_policy = MESON_HDR_POLICY_SINK;
mHdr_priority = MESON_G_SDR;
outHdrConversionType = DRM_INVALID; //force sdr
}
}
}
}
MESON_LOGD("hdr_policy:%d hdr_priority:0x%x outHdrConversionType:%d ", mHdr_policy, mHdr_priority, outHdrConversionType);
return outHdrConversionType;
}
int32_t ModePolicy::setHdrConversionPolicy(bool passthrough, int32_t forceType) {
int32_t ret = 0;
MESON_LOGD("%s passthrough %d forceType %d",
__func__, passthrough, forceType);
if (passthrough || (forceType == -1)) {
setBootEnv(UBOOTENV_HDR_POLICY, MESON_HDR_POLICY[MESON_HDR_POLICY_SOURCE]);
char hdr_priority[MESON_MODE_LEN] = {0};
sprintf(hdr_priority, "%d", mHdr_priority);
setBootEnv(UBOOTENV_HDR_PRIORITY, hdr_priority);
// set current hdmi mode
getDisplayMode(mCurrentMode);
setSourceOutputMode(mCurrentMode);
} else {
std::string type = FORCE_AMDV;
meson_hdr_priority_e priority = MESON_DOLBY_VISION_PRIORITY;
switch (forceType) {
case DRM_AMDV: {
priority = MESON_DOLBY_VISION_PRIORITY;
type = FORCE_AMDV;
break;
}
case DRM_HDR10:{
priority = MESON_HDR10_PRIORITY;
type = FORCE_HDR10;
break;
}
case DRM_HLG:{
priority = MESON_HDR10_PRIORITY;
type = FORCE_HLG;
break;
}
case DRM_INVALID: {
priority = MESON_SDR_PRIORITY;
type = AMDV_DISABLE_FORCE_SDR;
break;
}
default:
MESON_LOGE("setHdrConversionStrategy: error type[%d]", forceType);
ret = -1;
break;
}
if (!ret) {
getDisplayMode(mCurrentMode);
meson_mode_set_policy_input(mModeConType, &mConData);
if (!meson_mode_support_mode(mModeConType, priority, mCurrentMode)) {
char hdr_policy[MESON_MODE_LEN] = {0};
sprintf(hdr_policy, "%d", mHdr_policy);
setBootEnv(UBOOTENV_HDR_POLICY, hdr_policy);
char hdr_priority[MESON_MODE_LEN] = {0};
sprintf(hdr_priority, "%d", mHdr_priority);
setBootEnv(UBOOTENV_HDR_PRIORITY, hdr_priority);
setSourceOutputMode(mCurrentMode);
} else {
MESON_LOGW("%s mode check failed\n", __func__);
ret = -EINVAL;
}
}
}
return ret;
}
/*
* apply setting
*/
void ModePolicy::applyDisplaySetting(bool force) {
//quiescent boot need not output
bool quiescent = sys_get_bool_prop("ro_boot_quiescent", false);
MESON_LOGI("quiescent_mode is %d\n", quiescent);
if (quiescent && (mState == OUTPUT_MODE_STATE_INIT)) {
MESON_LOGI("don't need to setting hdmi when quiescent mode\n");
return;
}
//check cvbs mode
bool cvbsMode = false;
if (!strcmp(mSceneOutInfo.displaymode, MODE_480CVBS) || !strcmp(mSceneOutInfo.displaymode, MODE_576CVBS)
|| !strcmp(mSceneOutInfo.displaymode, MODE_PAL_M) || !strcmp(mSceneOutInfo.displaymode, MODE_PAL_N)
|| !strcmp(mSceneOutInfo.displaymode, MODE_NTSC_M)
|| !strcmp(mSceneOutInfo.displaymode, "null") || !strcmp(mSceneOutInfo.displaymode, "dummy_l")
|| !strcmp(mSceneOutInfo.displaymode, MODE_PANEL)) {
cvbsMode = true;
}
/* not enable phy in systemcontrol by default
* as phy will be enabled in driver when set mode
* only enable phy if phy is disabled but not enabled
*/
bool phy_enabled_already = true;
// 1. update hdmi frac_rate_policy
char frac_rate_policy[MESON_MODE_LEN] = {0};
char cur_frac_rate_policy[MESON_MODE_LEN] = {0};
bool frac_rate_policy_change = false;
std::string policy;
if (mReason != OUTPUT_CHANGE_BY_HWC) {
getDisplayAttribute(DISPLAY_FRAC_RATE_POLICY, policy);
strcpy(cur_frac_rate_policy, policy.c_str());
getBootEnv(UBOOTENV_FRAC_RATE_POLICY, frac_rate_policy);
if (strstr(frac_rate_policy, cur_frac_rate_policy) == NULL) {
setDisplayAttribute(DISPLAY_FRAC_RATE_POLICY, frac_rate_policy);
frac_rate_policy_change = true;
} else {
MESON_LOGI("cur frac_rate_policy is equals\n");
}
} else {
getDisplayAttribute(DISPLAY_FRAC_RATE_POLICY, policy);
strcpy(cur_frac_rate_policy, policy.c_str());
char defVal[] = "2";
sys_get_string_prop_default(HDMI_FRC_POLICY_PROP,frac_rate_policy, defVal);
if (strstr(frac_rate_policy,"2")) {
getBootEnv(UBOOTENV_FRAC_RATE_POLICY, frac_rate_policy);
}
MESON_LOGI("get frc policy from hwc is %s and current value is %s\n",frac_rate_policy, cur_frac_rate_policy);
if (strstr(frac_rate_policy, cur_frac_rate_policy) == NULL) {
frac_rate_policy_change = true;
}
}
// 2. set hdmi final color space
char curColorAttribute[MESON_MODE_LEN] = {0};
char final_deepcolor[MESON_MODE_LEN] = {0};
bool attr_change = false;
std::string cur_ColorAttribute;
getDisplayAttribute(DISPLAY_HDMI_COLOR_ATTR, cur_ColorAttribute);
strcpy(curColorAttribute, cur_ColorAttribute.c_str());
strcpy(final_deepcolor, mSceneOutInfo.deepcolor);
MESON_LOGI("curDeepcolor[%s] final_deepcolor[%s]\n", curColorAttribute, final_deepcolor);
if (strstr(curColorAttribute, final_deepcolor) == NULL) {
MESON_LOGI("set color space from:%s to %s\n", curColorAttribute, final_deepcolor);
// setDisplayAttribute(DISPLAY_HDMI_COLOR_ATTR, final_deepcolor);
cur_ColorAttribute = final_deepcolor;
attr_change = true;
} else {
MESON_LOGI("cur deepcolor is equals\n");
}
// 3. update hdr strategy
bool hdr_policy_change = false;
std::string cur_hdr_policy;
getDisplayAttribute(DISPLAY_HDR_POLICY, cur_hdr_policy);
MESON_LOGI("cur hdr policy:%s\n", cur_hdr_policy.c_str());
std::string cur_hdr_force_mode;
getDisplayAttribute(DISPLAY_FORCE_HDR_MODE, cur_hdr_force_mode);
MESON_LOGI("cur hdr force mode:%s\n", cur_hdr_force_mode.c_str());
std::string cur_amdv_mode;
getDisplayAttribute(DISPLAY_AMDV_MODE, cur_amdv_mode);
MESON_LOGI("cur dv mode:%s\n", cur_amdv_mode.c_str());
std::string cur_amdv_policy;
getDisplayAttribute(DISPLAY_AMDV_POLICY, cur_amdv_policy);
MESON_LOGI("cur dv policy:%s\n", cur_amdv_policy.c_str());
char hdr_force_mode[MESON_MODE_LEN] = {0};
gethdrforcemode(hdr_force_mode);
char hdr_policy[MESON_MODE_LEN] = {0};
getHdrStrategy(hdr_policy);
if (!isDVEnable()) {
if (strstr(cur_hdr_policy.c_str(), hdr_policy) == NULL) {
MESON_LOGI("set hdr policy from:%s to %s\n", cur_hdr_policy.c_str(), hdr_policy);
hdr_policy_change = true;
} else if (!strcmp(hdr_policy, MESON_HDR_POLICY[MESON_HDR_POLICY_FORCE]) && (strstr(cur_hdr_force_mode.c_str(), hdr_force_mode) == NULL)) {
MESON_LOGI("set hdr force mode from:%s to %s\n", cur_hdr_force_mode.c_str(), hdr_force_mode);
hdr_policy_change = true;
}
} else {
if (strstr(cur_amdv_policy.c_str(), hdr_policy) == NULL) {
MESON_LOGI("set dv policy from:%s to %s\n", cur_amdv_policy.c_str(), hdr_policy);
hdr_policy_change = true;
} else if ((mSceneOutInfo.amdv_type != AMDV_SET_DISABLE)
&& (!strcmp(hdr_policy, AMDV_POLICY_FORCE_MODE)
&& (strstr(cur_amdv_mode.c_str(), hdr_force_mode) == NULL))) {
MESON_LOGI("set dv force mode from:%s to %s\n", cur_amdv_mode.c_str(), hdr_force_mode);
hdr_policy_change = true;
}
}
//update hdr priority
bool hdr_priority_change = false;
meson_hdr_priority_e cur_hdr_priority;
cur_hdr_priority = (meson_hdr_priority_e)getCurrentHdrPriority();
meson_hdr_priority_e hdr_priority;
hdr_priority = (meson_hdr_priority_e)getHdrPriority();
if (cur_hdr_priority != hdr_priority) {
SYS_LOGI("set hdr priority from:%x to %x\n", cur_hdr_priority, hdr_priority);
hdr_priority_change = true;
}
// 4. check dv
int amdv_type = AMDV_SET_DISABLE;
bool amdv_change = false;
amdv_type = mSceneOutInfo.amdv_type;
amdv_change = checkDVStatusChanged(amdv_type);
if (isMboxSupportDV() && amdv_change) {
//4.1 set avmute when signal change at boot
if ((OUTPUT_MODE_STATE_INIT == mState)
&& (strstr(hdr_policy, MESON_HDR_POLICY[MESON_HDR_POLICY_SINK]))) {
// setDisplayAttribute(DISPLAY_HDMI_AVMUTE, "1");
}
//4.2 set dummy_l mode when dv change at UI switch
if ((OUTPUT_MODE_STATE_SWITCH == mState) && amdv_change) {
setDisplayMode("dummy_l");
}
//4.3 enable or disable dv core
if (AMDV_SET_DISABLE != amdv_type) {
enableDV(amdv_type);
} else {
disableDV(amdv_type);
}
MESON_LOGI("isDVEnable: %d", isDVEnable());
} else {
amdv_change = false;
MESON_LOGI("cur DvMode is equals\n");
}
// 5. check hdmi output mode
char final_displaymode[MESON_MODE_LEN] = {0};
char curDisplayMode[MESON_MODE_LEN] = {0};
bool modeChange = false;
getDisplayMode(curDisplayMode);
strcpy(final_displaymode, mSceneOutInfo.displaymode);
MESON_LOGI("curMode:[%s] ,final_displaymode[%s]\n", curDisplayMode, final_displaymode);
if (!isMatchMode(curDisplayMode, final_displaymode)) {
modeChange = true;
} else {
MESON_LOGI("cur mode is equals\n");
}
//6. check any change
bool isNeedChange = false;
if (amdv_change || modeChange || attr_change || frac_rate_policy_change || hdr_policy_change || hdr_priority_change) {
isNeedChange = true;
} else if (force) {
isNeedChange = true;
MESON_LOGD("force changed");
} else {
MESON_LOGI("nothing need to be changed\n");
}
// 8. set hdmi final output mode
if (isNeedChange) {
//apply hdr policy to driver sysfs
if (hdr_policy_change) {
if (strstr(hdr_policy, MESON_HDR_POLICY[MESON_HDR_POLICY_SINK])) {
setDisplayAttribute(DISPLAY_HDR_POLICY, MESON_HDR_POLICY[MESON_HDR_POLICY_SINK]);
if (isDVEnable()) {
setDisplayAttribute(DISPLAY_AMDV_POLICY, MESON_HDR_POLICY[MESON_HDR_POLICY_SINK]);
}
} else if (strstr(hdr_policy, MESON_HDR_POLICY[MESON_HDR_POLICY_SOURCE])) {
setDisplayAttribute(DISPLAY_HDR_POLICY, MESON_HDR_POLICY[MESON_HDR_POLICY_SOURCE]);
if (isDVEnable()) {
setDisplayAttribute(DISPLAY_AMDV_POLICY, MESON_HDR_POLICY[MESON_HDR_POLICY_SOURCE]);
}
} else if (strstr(hdr_policy, MESON_HDR_POLICY[MESON_HDR_POLICY_FORCE]) || strstr(hdr_policy, AMDV_POLICY_FORCE_MODE)) {
char hdr_force_mode[MESON_MODE_LEN] = {0};
gethdrforcemode(hdr_force_mode);
setDisplayAttribute(DISPLAY_FORCE_HDR_MODE, hdr_force_mode);
setDisplayAttribute(DISPLAY_HDR_POLICY, MESON_HDR_POLICY[MESON_HDR_POLICY_FORCE]);
if (isDVEnable()) {
setDisplayAttribute(DISPLAY_AMDV_POLICY, AMDV_POLICY_FORCE_MODE);
if (strstr(hdr_force_mode, FORCE_AMDV)) {
setDisplayAttribute(DISPLAY_AMDV_MODE, FORCE_AMDV);
} else if (strstr(hdr_force_mode, FORCE_HDR10)) {
setDisplayAttribute(DISPLAY_AMDV_MODE, FORCE_HDR10);
} else if (strstr(hdr_force_mode, AMDV_DISABLE_FORCE_SDR)) {
// 8bit or not
// std::string cur_ColorAttribute;
// getDisplayAttribute(DISPLAY_HDMI_COLOR_ATTR, cur_ColorAttribute);
if (cur_ColorAttribute.find("8bit", 0) != std::string::npos) {
setDisplayAttribute(DISPLAY_AMDV_MODE, AMDV_ENABLE_FORCE_SDR_8BIT);
} else {
setDisplayAttribute(DISPLAY_AMDV_MODE, AMDV_ENABLE_FORCE_SDR_10BIT);
}
}
}
}
}
if (attr_change || modeChange || frac_rate_policy_change || force)
mAdapter->setColorAttribute(final_deepcolor);
//apply hdr priority to driver sysfs
if (hdr_priority_change) {
char tmp[MESON_MODE_LEN] = {0};
sprintf(tmp, "%d", hdr_priority);
setDisplayAttribute(DISPLAY_HDR_PRIORITY, tmp);
}
//set hdmi mode
setDisplayMode(final_displaymode);
setQMSVRR( curDisplayMode, final_displaymode );
/* phy already turned on after write display/mode node */
phy_enabled_already = true;
} else {
MESON_LOGI("curDisplayMode is equal final_displaymode, Do not need set it\n");
}
// graphic
char final_Mode[MESON_MODE_LEN] = {0};
getDisplayMode(final_Mode);
char defVal[] = "0x0";
if (sys_get_bool_prop(PROP_DISPLAY_SIZE_CHECK, true)) {
char resolution[MESON_MODE_LEN] = {0};
char defaultResolution[MESON_MODE_LEN] = {0};
char finalResolution[MESON_MODE_LEN] = {0};
int w = 0, h = 0, w1 =0, h1 = 0;
sysfs_get_string(SYS_DISPLAY_RESOLUTION, resolution, MESON_MODE_LEN);
sys_get_string_prop_default(PROP_DISPLAY_SIZE, defaultResolution, defVal);
sscanf(resolution, "%dx%d", &w, &h);
sscanf(defaultResolution, "%dx%d", &w1, &h1);
if ((w != w1) || (h != h1)) {
if (strstr(final_displaymode, "null") && w1 != 0) {
sprintf(finalResolution, "%dx%d", w1, h1);
} else {
sprintf(finalResolution, "%dx%d", w, h);
}
sys_set_prop(PROP_DISPLAY_SIZE, finalResolution);
}
}
sys_set_prop(PROP_DISPLAY_ALLM, isTvSupportALLM() ? "1" : "0");
sys_set_prop(PROP_DISPLAY_GAME, getGameContentTypeSupport() ? "1" : "0");
char defaultResolution[MESON_MODE_LEN] = {0};
sys_get_string_prop_default(PROP_DISPLAY_SIZE, defaultResolution, defVal);
MESON_LOGI("set display-size:%s\n", defaultResolution);
int position[4] = { 0, 0, 0, 0 };//x,y,w,h
getPosition(final_displaymode, position);
setPosition(final_displaymode, position[0], position[1],position[2], position[3]);
//audio
char value[MESON_MAX_STR_LEN] = {0};
memset(value, 0, sizeof(0));
getBootEnv(UBOOTENV_DIGITAUDIO, value);
setDigitalMode(value);
}
void ModePolicy::getFramebufferSize(int disp, uint32_t & width, uint32_t & height) {
char uiMode[PROPERTY_VALUE_MAX] = {0};
if (disp == 0) {
/*primary display*/
if (sys_get_string_prop_default("persist_vendor_hwc_ui_mode", uiMode, "1080") > 0) {
if (!strncmp(uiMode, "720", 3)) {
width = 1280;
height = 720;
} else if (!strncmp(uiMode, "1080", 4)) {
width = 1920;
height = 1080;
} else {
MESON_ASSERT(0, "%s: get not support mode [%s] from vendor.ui_mode",
__func__, uiMode);
}
} else {
width = 1920;
height = 1080;
}
}
}
int32_t ModePolicy::initialize() {
uint32_t width = 1280;
uint32_t height = 1080;
char log_level[PROPERTY_VALUE_MAX] = { 0 };
sys_get_string_prop_default("WESTON_GL_MODE_POLICY_DEBUG", log_level, "2");
g_activeLevel = atoi(log_level);
mAdapter->setLogLevel(g_activeLevel);
bootenv_init();
getFramebufferSize(mDisplayId, width, height);
mDefaultUI = to_string(height);
mAdapter->initDisplayAttributeInfo(mCrtc, mConnector);
updateHdrCaps();
if (DISPLAY_TYPE_MBOX == mDisplayType) {
// mTxAuth = std::make_shared<HDCPTxAuth>();
setSourceDisplay(OUTPUT_MODE_STATE_INIT);
applyDisplaySetting(false);
} else if (DISPLAY_TYPE_TV == mDisplayType) {
setSinkDisplay(true);
}
#if 0
} else if (DISPLAY_TYPE_TABLET == mDisplayType) {
} else if (DISPLAY_TYPE_REPEATER == mDisplayType) {
setSourceDisplay(OUTPUT_MODE_STATE_INIT);
}
#endif
return 0;
}
void ModePolicy::setSinkDisplay(bool initState) {
char current_mode[MESON_MODE_LEN] = {0};
char outputmode[MESON_MODE_LEN] = {0};
getDisplayMode(current_mode);
getBootEnv(UBOOTENV_OUTPUTMODE, outputmode);
MESON_LOGD("init tv display old outputmode:%s, outputmode:%s\n", current_mode, outputmode);
if (strlen(outputmode) == 0)
strncpy(outputmode, mDefaultUI.c_str(), MESON_MODE_LEN-1);
setSinkOutputMode(outputmode, initState);
}
void ModePolicy::setSinkOutputMode(const char* outputmode, bool initState) {
[[maybe_unused]] bool sinkInitState = initState;
MESON_LOGI("set sink output mode:%s, init state:%d\n", outputmode, sinkInitState);
//set output mode
char curMode[MESON_MODE_LEN] = {0};
getDisplayMode(curMode);
MESON_LOGI("curMode = %s outputmode = %s", curMode, outputmode);
if (strstr(curMode, outputmode) == NULL) {
setDisplayMode(outputmode);
}
char defVal[PROPERTY_VALUE_MAX] = "0x0";
if (sys_get_bool_prop(PROP_DISPLAY_SIZE_CHECK, true)) {
char resolution[MESON_MODE_LEN] = {0};
char defaultResolution[MESON_MODE_LEN] = {0};
char finalResolution[MESON_MODE_LEN] = {0};
int w = 0, h = 0, w1 =0, h1 = 0;
sysfs_get_string(SYS_DISPLAY_RESOLUTION, resolution, MESON_MODE_LEN);
sys_get_string_prop_default(PROP_DISPLAY_SIZE, defaultResolution, defVal);
sscanf(resolution, "%dx%d", &w, &h);
sscanf(defaultResolution, "%dx%d", &w1, &h1);
if ((w != w1) || (h != h1)) {
if (strstr(outputmode, "null") && w1 != 0) {
sprintf(finalResolution, "%dx%d", w1, h1);
} else {
sprintf(finalResolution, "%dx%d", w, h);
}
sys_set_prop(PROP_AMDV_PRIORITY, finalResolution);
}
}
char defaultResolution[MESON_MODE_LEN] = {0};
sys_get_string_prop_default(PROP_DISPLAY_SIZE, defaultResolution, defVal);
MESON_LOGI("set display-size:%s\n", defaultResolution);
//update hwc windows size
int position[4] = { 0, 0, 0, 0 };//x,y,w,h
getPosition(outputmode, position);
setPosition(outputmode, position[0], position[1],position[2], position[3]);
//update hdr policy
if ((isMboxSupportDV() == false)) {
if (sys_get_bool_prop(PROP_AMDV_FEATURE, false)) {
char hdr_policy[MESON_MODE_LEN] = {0};
getHdrStrategy(hdr_policy);
if (strstr(hdr_policy, MESON_HDR_POLICY[MESON_HDR_POLICY_SINK])) {
setDisplayAttribute(DISPLAY_HDR_POLICY, MESON_HDR_POLICY[MESON_HDR_POLICY_SINK]);
} else if (strstr(hdr_policy, MESON_HDR_POLICY[MESON_HDR_POLICY_SOURCE])) {
setDisplayAttribute(DISPLAY_HDR_POLICY, MESON_HDR_POLICY[MESON_HDR_POLICY_SOURCE]);
} else if (strstr(hdr_policy, MESON_HDR_POLICY[MESON_HDR_POLICY_FORCE])) {
setDisplayAttribute(DISPLAY_HDR_POLICY, MESON_HDR_POLICY[MESON_HDR_POLICY_FORCE]);
}
} else {
initHdrSdrMode();
}
}
if (isMboxSupportDV()) {
if (isTvDVEnable()) {
setTvDVEnable();
} else {
setTvDVDisable();
}
}
//audio
char value[MESON_MAX_STR_LEN] = {0};
memset(value, 0, sizeof(0));
getBootEnv(UBOOTENV_DIGITAUDIO, value);
setDigitalMode(value);
//save output mode
char finalMode[MESON_MODE_LEN] = {0};
getDisplayMode(finalMode);
if (DISPLAY_TYPE_TABLET != mDisplayType) {
setBootEnv(UBOOTENV_OUTPUTMODE, (char *)finalMode);
}
if (strstr(finalMode, "cvbs") != NULL) {
setBootEnv(UBOOTENV_CVBSMODE, (char *)finalMode);
} else if (strstr(finalMode, "hz") != NULL) {
setBootEnv(UBOOTENV_HDMIMODE, (char *)finalMode);
}
MESON_LOGI("set output mode:%s done\n", finalMode);
}
bool ModePolicy::isHdmiUsed() {
bool ret = true;
char hdmi_state[MESON_MODE_LEN] = {0};
sysfs_get_string(DISPLAY_HDMI_USED, hdmi_state, MESON_MODE_LEN);
if (strstr(hdmi_state, "1") == NULL) {
ret = false;
}
return ret;
}
bool ModePolicy::isConnected() {
bool ret = ((mConnectorType == CONN_TYPE_HDMI) &&
(mConnector->connection == DRM_MODE_CONNECTED));
return ret;
}
bool ModePolicy::isVMXCertification() {
return sys_get_bool_prop(PROP_VMX, false);
}
bool ModePolicy::isHdmiEdidParseOK() {
bool ret = true;
char edidParsing[MESON_MODE_LEN] = {0};
sysfs_get_string(DISPLAY_EDID_STATUS, edidParsing, MESON_MODE_LEN);
if (strcmp(edidParsing, "ok")) {
ret = false;
}
return ret;
}
bool ModePolicy::isBestPolicy() {
char isBestMode[MESON_MODE_LEN] = {0};
if (DISPLAY_TYPE_TV == mDisplayType) {
return false;
}
return !getBootEnv(UBOOTENV_ISBESTMODE, isBestMode) || strcmp(isBestMode, "true") == 0;
}
bool ModePolicy::isBestColorSpace() {
bool ret = false;
char user_colorattr[MESON_MODE_LEN] = {0};
if (DISPLAY_TYPE_TV == mDisplayType) {
return false;
}
ret = getBootEnv(UBOOTENV_USER_COLORATTRIBUTE, user_colorattr);
if (!ret) {
return true;
} else if (strstr(user_colorattr, "bit") == NULL) {
return true;
}
return false;
}
void ModePolicy::setDefaultMode() {
MESON_LOGE("EDID parsing error detected\n");
// check hdmi output mode
char curDisplayMode[MESON_MODE_LEN] = {0};
getDisplayMode(curDisplayMode);
if (!isMatchMode(curDisplayMode, MESON_DEFAULT_HDMI_MODE)) {
//set default color format
setDisplayAttribute(DISPLAY_HDMI_COLOR_ATTR, MESON_DEFAULT_COLOR_FORMAT);
//set default resolution
setDisplayMode(MESON_DEFAULT_HDMI_MODE);
//update display position
int position[4] = { 0, 0, 0, 0 };//x,y,w,h
getPosition(MESON_DEFAULT_HDMI_MODE, position);
setPosition(MESON_DEFAULT_HDMI_MODE, position[0], position[1],position[2], position[3]);
} else {
MESON_LOGI("cur mode is default mode\n");
}
}
void ModePolicy::setDisplay(output_mode_state state)
{
if ((state == OUTPUT_MODE_STATE_INIT) ||
(state == OUTPUT_MODE_STATE_POWER)) {
memset(&mConData, 0, sizeof(meson_policy_in));
memset(&mDvInfo, 0, sizeof(hdmi_amdv_info_t));
mState = state;
mConData.state = static_cast<meson_mode_state>(state);
getConnectorData(&mConData, &mDvInfo);
if (isTvSupportDV() && isMboxSupportDV()) {
strcpy(mDvInfo.amdv_enable, "1");
mConData.hdr_info.is_amdv_enable = isDVEnable();
}
strcpy(mConData.cur_displaymode, mConData.con_info.ubootenv_hdmimode);
}
// TOD sceneProcess
if (isBestPolicy()) {
if (state == OUTPUT_MODE_STATE_INIT || mPolicy == MESON_POLICY_INVALID) {
mPolicy = MESON_POLICY_MIX;
}
} else {
mPolicy = MESON_POLICY_INVALID;
}
meson_mode_set_policy(mModeConType, mPolicy);
meson_mode_set_policy_input(mModeConType, &mConData);
meson_mode_get_policy_output(mModeConType, &mSceneOutInfo);
//5. apply settings to driver
applyDisplaySetting(state == OUTPUT_MODE_STATE_POWER);
}
/*
* OUTPUT_MODE_STATE_INIT for boot
* OUTPUT_MODE_STATE_POWER for hdmi plug and suspend/resume
*/
void ModePolicy::setSourceDisplay(output_mode_state state) {
std::lock_guard<std::mutex> lock(mMutex);
//1. hdmi used and hpd = 0
//set dummy_l mode
if ((isHdmiUsed() == true) && (isConnected() == false)) {
MESON_LOGD("hdmi usd, set cvbs");
setDisplay(state);
MESON_LOGI("hdmi used but plugout when boot\n");
return;
}
//2. hdmi edid parse error and hpd = 1
//set default reolsution and color format
if ((isHdmiEdidParseOK() == false) &&
(isConnected() == true)) {
setDefaultMode();
return;
}
//3. update hdmi info when boot and hdmi plug/suspend/resume
if ((state == OUTPUT_MODE_STATE_INIT) ||
(state == OUTPUT_MODE_STATE_POWER)) {
memset(&mConData, 0, sizeof(meson_policy_in));
memset(&mDvInfo, 0, sizeof(hdmi_amdv_info_t));
mState = state;
mConData.state = static_cast<meson_mode_state>(state);
getConnectorData(&mConData, &mDvInfo);
if (isTvSupportDV() && isMboxSupportDV()) {
strcpy(mDvInfo.amdv_enable, "1");
mConData.hdr_info.is_amdv_enable = isDVEnable();
}
strcpy(mConData.cur_displaymode, mConData.con_info.ubootenv_hdmimode);
}
// TOD sceneProcess
if (isBestPolicy()) {
if (state == OUTPUT_MODE_STATE_INIT || mPolicy == MESON_POLICY_INVALID) {
mPolicy = MESON_POLICY_MIX;
}
} else {
mPolicy = MESON_POLICY_INVALID;
}
meson_mode_set_policy(mModeConType, mPolicy);
meson_mode_set_policy_input(mModeConType, &mConData);
meson_mode_get_policy_output(mModeConType, &mSceneOutInfo);
}
void ModePolicy::setSourceOutputModeNoLock(const char* outputmode, bool force) {
if (DISPLAY_TYPE_TV == mDisplayType) {
setSinkOutputMode(outputmode, false);
} else {
getConnectorUserData(&mConData, &mDvInfo);
getHdrUserInfo(&mConData.hdr_info);
mState = OUTPUT_MODE_STATE_SWITCH;
mConData.state = static_cast<meson_mode_state>(mState);
strcpy(mConData.cur_displaymode, outputmode);
meson_mode_set_policy_input(mModeConType, &mConData);
meson_mode_get_policy_output(mModeConType, &mSceneOutInfo);
applyDisplaySetting(force);
}
}
void ModePolicy::setSourceOutputMode(const char* outputmode, bool force) {
std::lock_guard<std::mutex> lock(mMutex);
setSourceOutputModeNoLock(outputmode, force);
}
void ModePolicy::getConnectorUserData(struct meson_policy_in* data, hdmi_amdv_info_t *dinfo) {
if (!data || !dinfo) {
MESON_LOGE("%s data is NULL\n", __FUNCTION__);
return;
}
bool ret = false;
//hdmi color space best policy flag
data->con_info.is_bestcolorspace = isBestColorSpace();
MESON_LOGI("isbestColorspace:%d\n",
data->con_info.is_bestcolorspace);
getDisplayMode(mCurrentMode);
ret = getBootEnv(UBOOTENV_HDMIMODE, data->con_info.ubootenv_hdmimode);
if (!ret) {
//if env is null,use none as default value
strcpy(data->con_info.ubootenv_hdmimode, "none");
}
getBootEnv(UBOOTENV_CVBSMODE, data->con_info.ubootenv_cvbsmode);
MESON_LOGI("hdmi_current_mode:%s, ubootenv hdmimode:%s cvbsmode:%s\n",
mCurrentMode,
data->con_info.ubootenv_hdmimode,
data->con_info.ubootenv_cvbsmode);
ret = getBootEnv(UBOOTENV_USER_COLORATTRIBUTE, data->con_info.ubootenv_colorattr);
if (!ret) {
//if env is null,use none as default value
strcpy(data->con_info.ubootenv_colorattr, "none");
}
MESON_LOGI("ubootenv_colorattribute:%s\n",
data->con_info.ubootenv_colorattr);
//if no dolby_status env set to std for enable dv
//if box support dv
char amdv_enable[MESON_MODE_LEN];
ret = getBootEnv(UBOOTENV_DV_ENABLE, amdv_enable);
if (ret) {
strcpy(dinfo->amdv_enable, amdv_enable);
} else if (isMboxSupportDV()) {
strcpy(dinfo->amdv_enable, "1");
} else {
strcpy(dinfo->amdv_enable, "0");
}
MESON_LOGI("dv_enable:%s\n", dinfo->amdv_enable);
char ubootenv_amdv_type[MESON_MODE_LEN];
ret = getBootEnv(UBOOTENV_USER_DV_TYPE, ubootenv_amdv_type);
if (ret) {
strcpy(dinfo->ubootenv_amdv_type, ubootenv_amdv_type);
} else if (isMboxSupportDV()) {
strcpy(dinfo->ubootenv_amdv_type, "1");
} else {
strcpy(dinfo->ubootenv_amdv_type, "0");
}
MESON_LOGI("ubootenv_dv_type:%s\n", dinfo->ubootenv_amdv_type);
}
void ModePolicy::drmMode2MesonMode(meson_mode_info_t &mesonMode, drm_mode_info_t &drmMode) {
strncpy(mesonMode.name, drmMode.name, MESON_MODE_LEN);
mesonMode.dpi_x = drmMode.dpiX;
mesonMode.dpi_y = drmMode.dpiY;
mesonMode.pixel_w = drmMode.pixelW;
mesonMode.pixel_h = drmMode.pixelH;
mesonMode.refresh_rate = drmMode.refreshRate;
mesonMode.group_id = drmMode.groupId;
}
void ModePolicy::getSupportedModes() {
//pthread_mutex_lock(&mEnvLock);
std::map<uint32_t, drm_mode_info_t> connecterModeList;
/* reset ModeList */
mModes.clear();
if (mConnector->connection == DRM_MODE_CONNECTED) {
getModes(mConnector, connecterModeList);
for (auto it = connecterModeList.begin(); it != connecterModeList.end(); it++) {
// All modes are supported
if (isModeSupported(it->second)) {
mModes.emplace(mModes.size(), it->second);
}
}
}
/* transfer to meson_mode_info_t */
auto conPtr = &mConData.con_info;
conPtr->modes_size = mModes.size();
if (conPtr->modes_size > conPtr->modes_capacity) {
// realloc memory
void * buff = realloc(conPtr->modes, conPtr->modes_size * sizeof(meson_mode_info_t));
MESON_ASSERT(buff, "modePolicy realloc but has no memory");
conPtr->modes = (meson_mode_info_t *) buff;
conPtr->modes_capacity = conPtr->modes_size;
}
loadVrrModeGroups();
groupDisplayModes();
int i = 0;
for (auto it = mModes.begin(); it != mModes.end(); it++) {
drmMode2MesonMode(conPtr->modes[i], it->second);
i++;
}
}
bool ModePolicy::getModeNameForPix(char *name,
int32_t width, int32_t height, uint32_t refresh, uint32_t flags)
{
std::map<uint32_t, drm_mode_info_t> connecterModeList;
drm_mode_info_t mode;
int current_interlaced;
bool ret = false;
if (!mConnector || mConnector->connection != DRM_MODE_CONNECTED)
return false;
drmModeModeInfoPtr drmModes = mConnector->modes;
for (int i = 0;i < mConnector->count_modes; i++) {
current_interlaced = (drmModes[i].flags & DRM_MODE_FLAG_INTERLACE);
if (drmModes[i].hdisplay == width && drmModes[i].vdisplay == height &&
drmModes[i].vrefresh == refresh &&
current_interlaced == (flags & DRM_MODE_FLAG_INTERLACE)) {
strcpy(name, drmModes[i].name);
ret = true;
break;
}
}
return ret;
}
bool ModePolicy::isModeSupported(drm_mode_info_t mode) {
bool ret = false;
uint32_t i;
for (i = 0; i < ARRAY_SIZE(DISPLAY_MODE_LIST); i++) {
if (!strcmp(DISPLAY_MODE_LIST[i], mode.name)) {
ret = true;
break;
}
}
return ret;
}
bool ModePolicy::isSeamlessMode(const drm_mode_info_t & mode, const drm_mode_info_t &groupMode)
{
if (mHdrCapabilities.AMDV_4K30_Supported == 1) {
if (mode.pixelW == FB_SIZE_4K_W && mode.pixelH == FB_SIZE_4K_H) {
auto refreshA = ceilf(mode.refreshRate);
auto refreshB = ceilf(groupMode.refreshRate);
if ((refreshA > REFRESH_RATE_30 && refreshB <= REFRESH_RATE_30) ||
(refreshA <= REFRESH_RATE_30 && refreshB > REFRESH_RATE_30)) {
return false;
}
}
}
for (int32_t i = 0; i < mVrrModeGroup.num; i++) {
if (mVrrModeGroup.groups[i].width == mode.pixelW
&& mVrrModeGroup.groups[i].height == mode.pixelH) {
MESON_LOGD("mVrrModeGroup: w %d h %d mode: W %d H %d refreshRate %d\n",
mVrrModeGroup.groups[i].width,mVrrModeGroup.groups[i].height,mode.pixelW,mode.pixelH,mode.refreshRate);
if (((mode.refreshRate - mVrrModeGroup.groups[i].vrr_min) >= 0
//frac refresh rate
|| std::abs(mode.refreshRate - (mVrrModeGroup.groups[i].vrr_min * 1000) / (float)1001) < 0.001)
&& (mode.refreshRate - mVrrModeGroup.groups[i].vrr_max <= 0)) {
if (mVrrModeGroup.groups[i].width == groupMode.pixelW
&& mVrrModeGroup.groups[i].height == groupMode.pixelH) {
MESON_LOGD("groupMode: W %d H %d refreshRate %d\n",
groupMode.pixelW,groupMode.pixelH,groupMode.refreshRate);
if (((groupMode.refreshRate - mVrrModeGroup.groups[i].vrr_min) >= 0
//frac refresh rate
|| std::abs(groupMode.refreshRate - (mVrrModeGroup.groups[i].vrr_min * 1000) / (float)1001) < 0.001)
&& (groupMode.refreshRate - mVrrModeGroup.groups[i].vrr_max <= 0)) {
return true;
} else {
return false;
}
}
}
}
}
return false;
}
bool ModePolicy::supportVrr()
{
std::string vrr_cap;
getDisplayAttribute(DISPLAY_VRR_SUPPORTED, vrr_cap);
if (atoi(vrr_cap.c_str()) == 1)
return true;
return false;
}
int32_t ModePolicy::loadVrrModeGroups()
{
if (!(mDisplayType == DISPLAY_TYPE_TV)) {
if (!(supportVrr()) || !mSeamlessSwitchEnabled) {
return 0;
}
}
memset(&mVrrModeGroup, 0, sizeof(mVrrModeGroup));
mVrrModeGroup.conn_id = mConnector->connector_id;
auto ret = ioctl(mDrmFd, DRM_IOCTL_MESON_GET_VRR_RANGE, &mVrrModeGroup);
MESON_LOGD("\n %s %d conn_id:%d mDrmFd:%d mVrrModeGroup.num:%d\n",__FUNCTION__,__LINE__, mVrrModeGroup.conn_id, mDrmFd, mVrrModeGroup.num);
if (ret) {
MESON_LOGE("DRM_IOCTL_MESON_GET_VRR_RANGE error ret %d %s(%d)", ret, strerror(errno), errno);
return -EINVAL;
}
return 0;
}
bool ModePolicy::isVrrGroupedMode(const drm_mode_info_t & mode)
{
bool ret = true;
int count = 0;
drm_mode_info_t mesonMode = {
.name = "INVALID_MODE",
.dpiX = 0,
.dpiY = 0,
.pixelW = 0,
.pixelH = 0,
.refreshRate = 0,
.groupId = 0,
};
for (auto it = mModes.begin(); it != mModes.end(); ++it) {
MESON_LOGD("\n isVrrGroupedMode:mode name: %s mModes name:%s\n", mode.name, it->second.name);
if (strncmp(it->second.name, mode.name, DRM_DISPLAY_MODE_LEN) == 0) {
mesonMode = it->second;
break;
}
}
for (auto it = mModes.begin(); it != mModes.end(); ++it) {
MESON_LOGD("\n isVrrGroupedMode:mode(%d %d) mModes(%d %d) group id:(%d %d)\n",
mesonMode.pixelW, mesonMode.pixelH, it->second.pixelW, it->second.pixelH, mesonMode.groupId ,it->second.groupId);
if (it->second.pixelW == mesonMode.pixelW && it->second.pixelH == mesonMode.pixelH
&& mesonMode.groupId == it->second.groupId) {
count++;
}
}
if (count <= 1)
ret = false;
return ret;
}
int32_t ModePolicy::getDrmModeInfoFromName(char* name , drm_mode_info_t* drmMode)
{
int ret = -1;
if (!name || !drmMode) {
MESON_LOGE("\n invalid parameter\n");
return ret;
}
for (auto & mode : mModes) {
auto & itMode = mode.second;
if ( strcmp (itMode.name, name) ==0 ) {
*drmMode = itMode;
ret = 0;
break;
}
}
return ret;
}
int32_t ModePolicy::groupDisplayModes()
{
/* no need to regenerate groupId if without QMS/VRR support */
if ( mDisplayType != DISPLAY_TYPE_TV) {
if (!(supportVrr()) || !mSeamlessSwitchEnabled) {
return 0;
}
}
/* clear the old group modes */
mMesonGroupModes.clear();
for (auto & mode : mModes) {
auto & itMode = mode.second;
bool needRegroup = true;
for (auto & groupModes : mMesonGroupModes) {
int groupId = groupModes.first;
auto& itGroupModes = groupModes.second;
// do not check interlace mode,
// interlace mode does not support vrr
if (strstr(itMode.name, "i") != NULL)
break;
// only support resolution >= 720P
if (itMode.pixelW < 1280 || itMode.pixelH < 720)
break;
if (!itGroupModes.empty()) {
/* only need check the first item*/
drm_mode_info_t *gmodePtr = itGroupModes[0];
MESON_LOGD("gmodePtr: W %d H %d itMode: W %d H %d\n",gmodePtr->pixelW,
gmodePtr->pixelH,itMode.pixelW,itMode.pixelH);
if (gmodePtr->pixelW == itMode.pixelW && gmodePtr->pixelH == itMode.pixelH
&& isSeamlessMode(itMode, *gmodePtr)) {
itMode.groupId = groupId;
itGroupModes.push_back(&itMode);
needRegroup = false;
break;
}
}
}
if (needRegroup) {
itMode.groupId = mMesonGroupModes.size();
auto iter = mMesonGroupModes.emplace(mMesonGroupModes.size(),
std::vector<drm_mode_info_t *> ());
auto & modesWithSameGroup = iter.first->second;
modesWithSameGroup.push_back(&itMode);
}
}
return 0;
}
void ModePolicy::updateDrmfd(int drmFd)
{
MESON_LOGD("updateDrmfd:%d\n", drmFd);
if (drmFd >= 0)
mDrmFd = drmFd;
}
void ModePolicy::seamlessSwitchEnabled(bool enable)
{
MESON_LOGD("seamlessSwitchEnabled:%d\n", enable);
mSeamlessSwitchEnabled = enable;
}
void ModePolicy::seamlessSwitchQmsEnabled(bool enable)
{
seamlessSwitchEnabled(enable);
setSourceDisplay(OUTPUT_MODE_STATE_POWER);
applyDisplaySetting(true);
}
void ModePolicy::setQMSVRR(char* curDisplayMode, char* final_displaymode )
{
if (!curDisplayMode || !final_displaymode) {
MESON_LOGE("\n %s %d invalid parameter\n", __FUNCTION__,__LINE__);
return;
}
drm_mode_info_t curDrmMode;
drm_mode_info_t finalDrmMode;
bool isSeamless = false;
getDrmModeInfoFromName(curDisplayMode, &curDrmMode);
getDrmModeInfoFromName(final_displaymode, &finalDrmMode);
isSeamless = (curDrmMode.groupId == finalDrmMode.groupId);
MESON_LOGD("\n %s %d curDisplayMode:%s, final_displaymode:%s isSeamless:%d\n",
__FUNCTION__,__LINE__, curDisplayMode, final_displaymode, isSeamless);
int enableVrr = 0;
int updateBrr = isSeamless ? 0 : 1;
char sEnableVrr[3] = {'\0'};
char sUpdateBrr[3] = {'\0'};
if (supportVrr()) {
bool modeIsVrrMode = true;
if (updateBrr) {
modeIsVrrMode = isVrrGroupedMode(finalDrmMode);
}
enableVrr = (mSeamlessSwitchEnabled && modeIsVrrMode) ? 1 : 0;
sprintf(sUpdateBrr, "%d",updateBrr);
MESON_LOGD("\n %s %d mSeamlessSwitchEnabled:%d, modeIsVrrMode:%d enableVrr:%d, updateBrr:%d\n",
__FUNCTION__,__LINE__, mSeamlessSwitchEnabled, modeIsVrrMode, enableVrr, updateBrr);
setDisplayAttribute(DISPLAY_BRR_UPDATE, sUpdateBrr);
}
sprintf(sEnableVrr, "%d",enableVrr);
setDisplayAttribute(DISPLAY_VRR_ENABLED, sEnableVrr);
setDisplayAttribute(DISPLAY_UPDATE, "1");
}
int32_t bindCrtcAndConnector(drmModeCrtc *crtc, drmModeConnector *conn)
{
int ret = -1;
MESON_LOGI("bindCrtcAndConnector:%p, %p\n", crtc, conn);
if (g_Policy.get()) {
ret = g_Policy->bindConnector(conn);
ret |= g_Policy->bindCrtc(crtc);
}
return ret;
}
void initModePolicyFun(drmModeCrtc *crtc, drmModeConnector *conn, CompositorFunctionCallBack callback)
{
if (!g_Adapter.get())
g_Adapter = std::make_shared<DisplayAdapter>(crtc, conn);
if (!g_Policy.get())
g_Policy = std::make_shared<ModePolicy>(g_Adapter, 0);
if (g_Policy.get() && g_Adapter.get()) {
g_Adapter->registerCallBack(callback);
bindCrtcAndConnector(crtc, conn);
}
}
void initModePolicy(drmModeCrtc *crtc, drmModeConnector *conn, CompositorFunctionCallBack callback)
{
//initModePolicyFun(crtc, conn,callback);
if (g_Policy.get()) {
g_Policy->initialize();
}
}
void onHotplug(bool connected)
{
if (g_Policy.get())
g_Policy->onHotplug(connected);
}
void getPreferredBootConfig(char *name)
{
std::string mode;
if (g_Policy.get()) {
if (g_Policy->getPreferredBootConfig(mode) == 0)
strcpy(name, mode.c_str());
}
}
void setHdrConversionPolicy(bool passthrough, int32_t forceType)
{
if (g_Policy.get())
g_Policy->setHdrConversionPolicy(passthrough, forceType);
}
void setDvMode(int amdv_mode)
{
std::string mode = to_string(amdv_mode);
if (g_Policy.get())
g_Policy->setDvMode(mode);
}
void setColorSpace(char *colorspace)
{
std::string color = colorspace;
if (g_Policy.get())
g_Policy->setColorSpace(color);
}
void setBootConfig(char *mode, bool auto_mode)
{
std::string config = mode;
if (g_Policy.get()) {
if (auto_mode)
g_Policy->clearBootConfig();
else
g_Policy->setBootConfig(config);
}
}
bool setActiveConfig(char *mode)
{
std::string config = mode;
if (g_Policy.get()) {
g_Policy->setActiveConfig(config);
return true;
}
return false;
}
bool setPolicyByAppName(const char *name, int state)
{
MESON_LOGD("\n %s %d name:%s state:%d \n", __FUNCTION__,__LINE__,name,state);
if (g_Policy.get()) {
if (state == 1 && !strcmp(name, "netflix")) {
g_Policy->setPolicy(MESON_POLICY_FRAMERATE);
} else {
g_Policy->setPolicy(MESON_POLICY_MIX);
}
return true;
}
return false;
}
bool updateEnv()
{
if (g_Policy.get())
return g_Policy->updateEnv();
return false;
}
bool getModeNameForPix(char *name,
int32_t width, int32_t height, uint32_t refresh, uint32_t flags)
{
if (g_Policy.get())
return g_Policy->getModeNameForPix(name, width, height, refresh / 1000, flags);
return false;
}
void updateDrmfd(int fd)
{
MESON_LOGD("\n %s %d fd:%d, g_Policy.get():%p\n",__FUNCTION__,__LINE__,fd, g_Policy.get());
if (g_Policy.get())
g_Policy->updateDrmfd(fd);
}
void seamlessSwitchEnabled(bool enable)
{
if (g_Policy.get())
g_Policy->seamlessSwitchEnabled(enable);
}
void seamlessSwitchQmsEnabled(bool enable)
{
if (g_Policy.get())
g_Policy->seamlessSwitchQmsEnabled(enable);
}
int setPriority(int priority)
{
if (g_Policy.get())
return g_Policy->setHdrPriority(priority);
return -1;
}
int getPriority()
{
if (g_Policy.get())
return g_Policy->getHdrPriority();
return 0;
}