weston: add QMS flow [1/1]
PD#SWPL-172026
Problem:
add QMS flow
Solution:
add QMS flow
Verify:
s7d
Change-Id: I05de5006973b20228908134b62962c6d2fbbfb12
Signed-off-by: limin.tian <limin.tian@amlogic.com>
diff --git a/libweston/modepolicy/DisplayAdapter.cpp b/libweston/modepolicy/DisplayAdapter.cpp
index d0fedc3..03fb3b8 100644
--- a/libweston/modepolicy/DisplayAdapter.cpp
+++ b/libweston/modepolicy/DisplayAdapter.cpp
@@ -121,6 +121,9 @@
DA_DEFINE(FORCE_HDR_MODE, "0", update_sys_node_by_file);
DA_DEFINE(EDID_ATTR, "0", update_sys_node_by_property);
DA_DEFINE(FRAC_RATE_POLICY, "0", update_sys_node_by_property);
+ DA_DEFINE(VRR_SUPPORTED, "0", update_sys_node_by_property);
+ DA_DEFINE(VRR_ENABLED, "0", update_sys_node_by_property);
+ DA_DEFINE(BRR_UPDATE, "0", update_sys_node_by_property);
#define DA_SET_NODE(ID, NODE) \
display_attrs[DA_##ID].sysfs_node = NODE
@@ -154,6 +157,9 @@
DA_SET_NODE(FORCE_HDR_MODE, "/sys/module/aml_media/parameters/force_output");
DA_SET_NODE(EDID_ATTR, "EDID");
DA_SET_NODE(FRAC_RATE_POLICY, "FRAC_RATE_POLICY");
+ DA_SET_NODE(VRR_SUPPORTED, "vrr_capable");
+ DA_SET_NODE(VRR_ENABLED, "VRR_ENABLED");
+ DA_SET_NODE(BRR_UPDATE, "brr_update");
#define DA_SET_READ_ONLY(ID) \
display_attrs[DA_##ID].is_read_only = true
@@ -162,6 +168,7 @@
DA_SET_READ_ONLY(AMDV_STATUS);
DA_SET_READ_ONLY(HDR_CAP);
DA_SET_READ_ONLY(HDR_CAP2);
+ DA_SET_READ_ONLY(VRR_SUPPORTED);
#define DA_SET_WRITE_ONLY(ID) \
display_attrs[DA_##ID].is_write_only= true
// DA_SET_WRITE_ONLY(AMDV_MODE);
@@ -176,11 +183,14 @@
DA_SET_OBJ_ID(EDID_ATTR, conn->connector_id);
DA_SET_OBJ_ID(FRAC_RATE_POLICY, conn->connector_id);
DA_SET_OBJ_ID(HDMI_COLOR_ATTR, conn->connector_id);
+ DA_SET_OBJ_ID(VRR_SUPPORTED, conn->connector_id);
}
if (crtc) {
DA_SET_OBJ_ID(AMDV_MODE, crtc->crtc_id);
DA_SET_OBJ_ID(HDR_POLICY, crtc->crtc_id);
DA_SET_OBJ_ID(AMDV_ENABLE, crtc->crtc_id);
+ DA_SET_OBJ_ID(VRR_ENABLED, crtc->crtc_id);
+ DA_SET_OBJ_ID(BRR_UPDATE, crtc->crtc_id);
}
}
diff --git a/libweston/modepolicy/DisplayAdapter.h b/libweston/modepolicy/DisplayAdapter.h
index 6eb4699..578e775 100644
--- a/libweston/modepolicy/DisplayAdapter.h
+++ b/libweston/modepolicy/DisplayAdapter.h
@@ -80,6 +80,11 @@
#define DISPLAY_FORCE_HDR_MODE "FORCE HDR Mode"
#define DISPLAY_EDID_ATTR "HDMI EDID"
#define DISPLAY_FRAC_RATE_POLICY "FRAC RATE POLICY"
+#define DISPLAY_VRR_SUPPORTED "VRR_SUPPORTED"
+#define DISPLAY_VRR_ENABLED "VRR_ENABLED"
+#define DISPLAY_BRR_UPDATE "BRR_UPDATE"
+
+
#define MAX_BUF_LEN MESON_MAX_STR_LEN
@@ -104,6 +109,9 @@
DA_FORCE_HDR_MODE,
DA_EDID_ATTR,
DA_FRAC_RATE_POLICY,
+ DA_VRR_SUPPORTED,
+ DA_VRR_ENABLED,
+ DA_BRR_UPDATE,
DA_DISPLAY_ATTRIBUTE__COUNT
};
diff --git a/libweston/modepolicy/ModePolicy.cpp b/libweston/modepolicy/ModePolicy.cpp
index da65cca..5ef7fed 100644
--- a/libweston/modepolicy/ModePolicy.cpp
+++ b/libweston/modepolicy/ModePolicy.cpp
@@ -12,6 +12,8 @@
#include <inttypes.h>
#include <sys/utsname.h>
#include <memory>
+#include <sys/ioctl.h>
+
//#include <systemcontrol.h>
static int g_activeLevel= 3;
@@ -96,6 +98,7 @@
mDisplayHeight = 0;
mFracMode = MODE_FRACTION;
mEnvLock = PTHREAD_MUTEX_INITIALIZER;
+ mSeamlessSwitchEnabled = true;
}
ModePolicy::ModePolicy(std::shared_ptr<DisplayAdapter> adapter, const uint32_t displayId) {
@@ -114,6 +117,7 @@
mDisplayHeight = 0;
mFracMode = MODE_FRACTION;
mEnvLock = PTHREAD_MUTEX_INITIALIZER;
+ mSeamlessSwitchEnabled = true;
}
ModePolicy::~ModePolicy() {
@@ -1126,6 +1130,7 @@
mModeConType = MESON_MODE_HDMI;
break;
}
+
return 0;
}
@@ -2427,6 +2432,8 @@
//set hdmi mode
setDisplayMode(final_displaymode);
+ setQMSVRR( curDisplayMode, final_displaymode );
+
/* phy already turned on after write display/mode node */
phy_enabled_already = true;
} else {
@@ -2931,6 +2938,9 @@
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);
@@ -2978,6 +2988,222 @@
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) {
+ 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) {
+ 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];
+ 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::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);
+
+}
int32_t bindCrtcAndConnector(drmModeCrtc *crtc, drmModeConnector *conn)
{
int ret = -1;
@@ -3094,3 +3320,15 @@
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);
+}
+
diff --git a/libweston/modepolicy/ModePolicy.h b/libweston/modepolicy/ModePolicy.h
index d6d73cf..8cc64e5 100644
--- a/libweston/modepolicy/ModePolicy.h
+++ b/libweston/modepolicy/ModePolicy.h
@@ -30,6 +30,7 @@
#include "modepolicyfunc.h"
#include <ubootenv.h>
#include "DisplayAdapter.h"
+#include <linux/amlogic/drm/meson_drm.h>
using namespace std;
@@ -195,6 +196,10 @@
#define FULL_WIDTH_1080 1920
#define FULL_HEIGHT_1080 1080
+#define FB_SIZE_4K_W 3840
+#define FB_SIZE_4K_H 2160
+#define REFRESH_RATE_30 (30)
+
static const char *PROFIX_UBOOTENV_VAR = "ubootenv.var.";
#ifndef PROPERTY_VALUE_MAX
@@ -347,6 +352,8 @@
bool updateEnv();
bool getModeNameForPix(char *name,
int32_t width, int32_t height, uint32_t refresh, uint32_t flags);
+ void updateDrmfd(int drmFd);
+ void seamlessSwitchEnabled(bool enable);
// void dump(String8 &dumpstr) override;
@@ -454,6 +461,13 @@
void getSupportedModes();
bool isModeSupported(drm_mode_info_t mode);
void setDisplay(output_mode_state state);
+ bool isSeamlessMode(const drm_mode_info_t & mode, const drm_mode_info_t &groupMode);
+ bool supportVrr();
+ int32_t loadVrrModeGroups();
+ bool isVrrGroupedMode(const drm_mode_info_t & mode);
+ int32_t getDrmModeInfoFromName(char* name , drm_mode_info_t* drmMode);
+ int32_t groupDisplayModes();
+ void setQMSVRR(char* curDisplayMode, char* final_displaymode );
protected:
static void * threadMain(void * data);
@@ -504,4 +518,8 @@
int32_t mFracMode;
// std::shared_ptr<HDCPTxAuth> mTxAuth;
// for hdr control
+ struct drm_vrr_mode_groups mVrrModeGroup;
+ std::map<uint32_t, std::vector<drm_mode_info_t *>> mMesonGroupModes;
+ int mDrmFd;
+ bool mSeamlessSwitchEnabled;
};
diff --git a/libweston/modepolicy/modepolicy_aml.cpp b/libweston/modepolicy/modepolicy_aml.cpp
index cea57b6..5c1e26a 100644
--- a/libweston/modepolicy/modepolicy_aml.cpp
+++ b/libweston/modepolicy/modepolicy_aml.cpp
@@ -12,6 +12,7 @@
"color_space",
"color_depth"
};
+static int weston_set_property(int id, const char *name, int value);
static weston_ctx_list *weston_get_ctx_list()
{
@@ -763,7 +764,10 @@
if (!ctx) {
ctx = (weston_ctx *)calloc(1, sizeof(*ctx));
ctx->scaling = -1;
+ ctx->enableVrr = true;
ctx->state = ctx_list->state;
+ ctx->drm_fd = fd;
+ MESON_LOGD("\n init_mode_policy_without_mode :%d\n", fd);
wl_list_init(&ctx->prop_list);
wl_list_insert(&ctx_list->ctx_list, &ctx->link);
}
@@ -891,6 +895,8 @@
return NULL;
initModePolicyFun(ctx->crtc, ctx->conn, callback);
+ updateDrmfd(ctx->drm_fd);
+ seamlessSwitchEnabled(ctx->enableVrr);
if (mode) {
if (get_mode_name_for_weston_mode(ctx, mode, name))
setActiveConfig(name);
diff --git a/libweston/modepolicy/modepolicy_aml.h b/libweston/modepolicy/modepolicy_aml.h
index cf9bf86..4de2f48 100644
--- a/libweston/modepolicy/modepolicy_aml.h
+++ b/libweston/modepolicy/modepolicy_aml.h
@@ -35,6 +35,7 @@
uint32_t state;
struct wl_list prop_list;
struct wl_list link;
+ bool enableVrr;
} weston_ctx;
typedef struct _weston_ctx_list {
diff --git a/libweston/modepolicy/modepolicyfunc.h b/libweston/modepolicy/modepolicyfunc.h
index 8701f90..d4749d7 100644
--- a/libweston/modepolicy/modepolicyfunc.h
+++ b/libweston/modepolicy/modepolicyfunc.h
@@ -42,6 +42,8 @@
bool updateEnv();
bool getModeNameForPix(char *name,
int32_t width, int32_t height, uint32_t refresh, uint32_t flags);
+void seamlessSwitchEnabled(bool enable);
+void updateDrmfd(int fd);
#ifdef __cplusplus
}