drm: optimize seamless switch between ALLM and QMS [1/1]

PD#SWPL-170739

Problem:
when change mode from ALLM to QMS and mode is same with brr, no need
to do mode change. when change mode from QMS to ALLM and QMS's mode is brr,
it also no need to do mode change.

Solution:
optimize seamless switch between ALLM and QMS

Verify:
s7d

Test:
DRM-OSD-5

Change-Id: Ic5fd113b0d8157ee02e9e33f00e5e85ba7ffcc6c
Signed-off-by: Ao Xu <ao.xu@amlogic.com>
This commit is contained in:
Ao Xu
2024-06-27 14:16:11 +08:00
committed by Luan Yuan
parent b3db485dd6
commit b337ee705b
3 changed files with 135 additions and 43 deletions
+64 -17
View File
@@ -167,6 +167,7 @@ static struct drm_crtc_state *meson_crtc_duplicate_state(struct drm_crtc *crtc)
new_state->attr_changed = false;
new_state->brr_update = false;
new_state->brr = cur_state->brr;
new_state->seamless = false;
strncpy(new_state->brr_mode, cur_state->brr_mode, DRM_DISPLAY_MODE_LEN);
new_state->crtc_bgcolor_flag = cur_state->crtc_bgcolor_flag;
new_state->crtc_bgcolor = cur_state->crtc_bgcolor;
@@ -439,6 +440,7 @@ static void meson_crtc_atomic_print_state(struct drm_printer *p,
drm_printf(p, "\t\tbrr_mode=%s\n", cstate->brr_mode);
drm_printf(p, "\t\tbrr=%u\n", cstate->brr);
drm_printf(p, "\t\tuboot_mode_init=%u\n", cstate->uboot_mode_init);
drm_printf(p, "\t\tseamless=%d\n", cstate->seamless);
drm_printf(p, "\t\tcrtc_hdr_policy:[%u,%u]\n",
cstate->crtc_hdr_process_policy,
cstate->crtc_eotf_type);
@@ -594,6 +596,62 @@ static bool am_meson_crtc_mode_fixup(struct drm_crtc *crtc,
return true;
}
static int meson_crtc_seamless_change(struct drm_crtc *crtc, struct drm_atomic_state *state)
{
char *brr_name;
struct drm_crtc_state *new_state, *old_state;
struct drm_display_mode *new_mode, *old_mode;
struct am_meson_crtc_state *meson_crtc_state, *old_crtc_state;
new_state = drm_atomic_get_new_crtc_state(state, crtc);
old_state = drm_atomic_get_old_crtc_state(state, crtc);
if (!new_state || !old_state) {
DRM_INFO("%s crtc state is NULL!\n", __func__);
return 0;
}
new_mode = &new_state->adjusted_mode;
old_mode = &old_state->adjusted_mode;
meson_crtc_state = to_am_meson_crtc_state(new_state);
old_crtc_state = to_am_meson_crtc_state(old_state);
if (new_mode->hdisplay != old_mode->hdisplay ||
new_mode->vdisplay != old_mode->vdisplay ||
meson_crtc_state->attr_changed ||
meson_crtc_state->brr_update ||
(new_mode->flags & DRM_MODE_FLAG_INTERLACE))
return meson_crtc_state->seamless;
if (new_state->vrr_enabled) {
if (old_state->vrr_enabled) {
/*qms->qms*/
meson_crtc_state->seamless = true;
} else {
/*allm -> qms, new vrr_enable 1brr_update 0*/
brr_name = meson_crtc_state->brr_mode;
if (!strcmp(old_mode->name, brr_name))
meson_crtc_state->seamless = true;
else
meson_crtc_state->seamless = false;
}
} else {
if (old_state->vrr_enabled) {
/*qms->allm*/
brr_name = old_crtc_state->brr_mode;
if (!strcmp(old_mode->name, brr_name) &&
!strcmp(new_mode->name, brr_name))
meson_crtc_state->seamless = true;
else
meson_crtc_state->seamless = false;
} else {
/*none qms-> none qms*/
meson_crtc_state->seamless = false;
}
}
return meson_crtc_state->seamless;
}
static void am_meson_crtc_atomic_enable(struct drm_crtc *crtc,
struct drm_atomic_state *old_atomic_state)
{
@@ -708,12 +766,7 @@ static void am_meson_crtc_atomic_enable(struct drm_crtc *crtc,
if (meson_crtc_state->uboot_mode_init)
mode |= VMODE_INIT_BIT_MASK;
if (crtc->state->vrr_enabled &&
adjusted_mode->hdisplay == old_mode->hdisplay &&
adjusted_mode->vdisplay == old_mode->vdisplay &&
!meson_crtc_state->attr_changed &&
!meson_crtc_state->brr_update &&
!(adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)) {
if (meson_crtc_state->seamless) {
drm_crtc_vblank_on(crtc);
return;
}
@@ -737,7 +790,6 @@ static void am_meson_crtc_atomic_disable(struct drm_crtc *crtc,
struct drm_atomic_state *old_atomic_state)
{
struct am_meson_crtc *amcrtc = to_am_meson_crtc(crtc);
struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
struct drm_crtc_state *old_crtc_state;
struct drm_display_mode *old_mode;
struct am_meson_crtc_state *meson_crtc_state =
@@ -754,16 +806,6 @@ static void am_meson_crtc_atomic_disable(struct drm_crtc *crtc,
old_mode = &old_crtc_state->adjusted_mode;
drm_crtc_vblank_off(crtc);
if (crtc->state->vrr_enabled &&
adjusted_mode->hdisplay == old_mode->hdisplay &&
adjusted_mode->vdisplay == old_mode->vdisplay &&
!meson_crtc_state->attr_changed &&
!meson_crtc_state->brr_update &&
!(adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)) {
DRM_INFO("%s, vrr enable, skip crtc disable\n", __func__);
return;
}
if (crtc->state->event && !crtc->state->active) {
spin_lock_irq(&crtc->dev->event_lock);
drm_crtc_send_vblank_event(crtc, crtc->state->event);
@@ -771,6 +813,11 @@ static void am_meson_crtc_atomic_disable(struct drm_crtc *crtc,
crtc->state->event = NULL;
}
if (meson_crtc_seamless_change(crtc, old_atomic_state)) {
DRM_INFO("skip set vmode to null\n");
return;
}
if ((meson_crtc_state->vmode & VMODE_MASK) == VMODE_LCD &&
!strstr(old_mode->name, "panel")) {
DRM_INFO("%s[%d], lcd skip setting null vmode\n", __func__,
+2
View File
@@ -84,6 +84,8 @@ struct am_meson_crtc_state {
int hdr_conversion_ctrl;
bool attr_changed;
bool brr_update;
bool seamless;
};
struct am_meson_crtc {
+69 -26
View File
@@ -1535,6 +1535,11 @@ static void meson_hdmitx_cal_brr(struct am_hdmi_tx *hdmitx,
if (ret < 0) {
DRM_ERROR("%s, Get hdmi para by vic [%d] failed.\n",
__func__, vic);
}
if (am_hdmi_info.max_vfreq < drm_mode_vrefresh(adj_mode)) {
memset(crtc_state->brr_mode, 0, DRM_DISPLAY_MODE_LEN);
crtc_state->valid_brr = 0;
} else {
strncpy(crtc_state->brr_mode, para.name,
DRM_DISPLAY_MODE_LEN);
@@ -1542,7 +1547,8 @@ static void meson_hdmitx_cal_brr(struct am_hdmi_tx *hdmitx,
crtc_state->valid_brr = 1;
}
DRM_INFO("%s, %d, %d, %s\n", __func__, vic, brr, crtc_state->brr_mode);
DRM_INFO("%s, %d, %d, %s, %d\n", __func__, vic, brr, crtc_state->brr_mode,
crtc_state->valid_brr);
crtc_state->brr = brr;
kfree(groups);
}
@@ -1689,7 +1695,8 @@ int meson_encoder_vrr_change(struct drm_encoder *encoder,
struct drm_crtc *crtc;
struct drm_crtc_state *new_state, *old_state;
struct drm_display_mode *new_mode, *old_mode;
struct am_meson_crtc_state *meson_crtc_state;
struct am_meson_crtc_state *meson_crtc_state, *old_crtc_state;
char *brr_name;
connector = drm_atomic_get_new_connector_for_encoder(state, encoder);
if (!connector)
@@ -1702,22 +1709,54 @@ int meson_encoder_vrr_change(struct drm_encoder *encoder,
crtc = conn_state->crtc;
new_state = drm_atomic_get_new_crtc_state(state, crtc);
old_state = drm_atomic_get_old_crtc_state(state, crtc);
if (!new_state || !old_state) {
DRM_INFO("%s crtc state is NULL!\n", __func__);
return 0;
}
new_mode = &new_state->adjusted_mode;
old_mode = &old_state->adjusted_mode;
meson_crtc_state = to_am_meson_crtc_state(new_state);
old_crtc_state = to_am_meson_crtc_state(old_state);
if (new_state->vrr_enabled &&
new_mode->hdisplay == old_mode->hdisplay &&
new_mode->vdisplay == old_mode->vdisplay &&
!meson_crtc_state->attr_changed &&
!meson_crtc_state->brr_update &&
!(new_mode->flags & DRM_MODE_FLAG_INTERLACE)) {
DRM_INFO("[%s], vrr, skip encoder %s\n", __func__,
status == 1 ? "enable" : "disable");
return 1;
if (new_mode->hdisplay != old_mode->hdisplay ||
new_mode->vdisplay != old_mode->vdisplay ||
meson_crtc_state->attr_changed ||
meson_crtc_state->brr_update ||
(new_mode->flags & DRM_MODE_FLAG_INTERLACE))
return meson_crtc_state->seamless;
if (new_state->vrr_enabled) {
if (old_state->vrr_enabled) {
/*qms->qms*/
meson_crtc_state->seamless = true;
} else {
/*allm -> qms, new vrr_enable 1brr_update 0*/
brr_name = meson_crtc_state->brr_mode;
if (!strcmp(old_mode->name, brr_name))
meson_crtc_state->seamless = true;
else
meson_crtc_state->seamless = false;
}
} else {
if (old_state->vrr_enabled) {
/*qms->allm*/
brr_name = old_crtc_state->brr_mode;
if (!strcmp(old_mode->name, brr_name) &&
!strcmp(new_mode->name, brr_name))
meson_crtc_state->seamless = true;
else
meson_crtc_state->seamless = false;
} else {
/*none qms-> none qms*/
meson_crtc_state->seamless = false;
}
}
return 0;
if (meson_crtc_state->seamless)
DRM_INFO("[%s], vrr, skip encoder %s\n", __func__,
status == 1 ? "enable" : "disable");
return meson_crtc_state->seamless;
}
void meson_hdmitx_encoder_atomic_enable(struct drm_encoder *encoder,
@@ -1736,7 +1775,7 @@ void meson_hdmitx_encoder_atomic_enable(struct drm_encoder *encoder,
struct am_hdmitx_connector_state *old_meson_conn_state =
to_am_hdmitx_connector_state(old_conn_state);
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
int mode_vrefresh = drm_mode_vrefresh(mode);
int dst_vrefresh, mode_vrefresh = drm_mode_vrefresh(mode);
struct am_meson_crtc *amcrtc = to_am_meson_crtc(encoder->crtc);
enum vmode_e vmode = meson_crtc_state->vmode;
struct hdmitx_common *tx_comm = am_hdmi_info.hdmitx_dev->hdmitx_common;
@@ -1748,9 +1787,10 @@ void meson_hdmitx_encoder_atomic_enable(struct drm_encoder *encoder,
return;
}
if (meson_encoder_vrr_change(encoder, state, 1)) {
DRM_INFO("%s, set frame rate: %d\n", __func__, mode_vrefresh);
am_hdmi_info.hdmitx_dev->set_vframe_rate_hint(mode_vrefresh * 100, NULL);
if (meson_crtc_state->seamless) {
dst_vrefresh = meson_crtc_state->base.vrr_enabled ? mode_vrefresh : 0;
DRM_INFO("%s, set frame rate: %d\n", __func__, dst_vrefresh);
am_hdmi_info.hdmitx_dev->set_vframe_rate_hint(dst_vrefresh * 100, NULL);
return;
}
@@ -1758,17 +1798,20 @@ void meson_hdmitx_encoder_atomic_enable(struct drm_encoder *encoder,
meson_conn_state->update != 1)
vmode |= VMODE_INIT_BIT_MASK;
hdmitx_set_hdr_priority(am_hdmi_info.hdmitx_dev->hdmitx_common,
meson_conn_state->hdr_priority);
if (!meson_crtc_state->seamless) {
hdmitx_set_hdr_priority(am_hdmi_info.hdmitx_dev->hdmitx_common,
meson_conn_state->hdr_priority);
meson_vout_notify_mode_change(amcrtc->vout_index,
vmode, EVENT_MODE_SET_START);
meson_conn_state->hcs.mode = vmode;
hdmitx_common_do_mode_setting(am_hdmi_info.hdmitx_dev->hdmitx_common,
&meson_conn_state->hcs, &old_meson_conn_state->hcs);
meson_vout_notify_mode_change(amcrtc->vout_index,
vmode, EVENT_MODE_SET_FINISH);
meson_vout_update_mode_name(amcrtc->vout_index, mode->name, "hdmitx");
meson_vout_notify_mode_change(amcrtc->vout_index,
vmode, EVENT_MODE_SET_START);
meson_conn_state->hcs.mode = vmode;
hdmitx_common_do_mode_setting(am_hdmi_info.hdmitx_dev->hdmitx_common,
&meson_conn_state->hcs,
&old_meson_conn_state->hcs);
meson_vout_notify_mode_change(amcrtc->vout_index,
vmode, EVENT_MODE_SET_FINISH);
meson_vout_update_mode_name(amcrtc->vout_index, mode->name, "hdmitx");
}
am_hdmi_info.hdmitx_on = 1;