Merge "disp: msm: Add support for seamless panel operating mode switch"
This commit is contained in:

committed by
Gerrit - the friendly Code Review server

commit
d54b69e258
@@ -74,6 +74,8 @@ enum dsi_op_mode {
|
|||||||
* @DSI_MODE_FLAG_DMS: Seamless transition is dynamic mode switch
|
* @DSI_MODE_FLAG_DMS: Seamless transition is dynamic mode switch
|
||||||
* @DSI_MODE_FLAG_VRR: Seamless transition is DynamicFPS.
|
* @DSI_MODE_FLAG_VRR: Seamless transition is DynamicFPS.
|
||||||
* New timing values are sent from DAL.
|
* New timing values are sent from DAL.
|
||||||
|
* @DSI_MODE_FLAG_POMS:
|
||||||
|
* Seamless transition is dynamic panel operating mode switch
|
||||||
*/
|
*/
|
||||||
enum dsi_mode_flags {
|
enum dsi_mode_flags {
|
||||||
DSI_MODE_FLAG_SEAMLESS = BIT(0),
|
DSI_MODE_FLAG_SEAMLESS = BIT(0),
|
||||||
@@ -81,6 +83,7 @@ enum dsi_mode_flags {
|
|||||||
DSI_MODE_FLAG_VBLANK_PRE_MODESET = BIT(2),
|
DSI_MODE_FLAG_VBLANK_PRE_MODESET = BIT(2),
|
||||||
DSI_MODE_FLAG_DMS = BIT(3),
|
DSI_MODE_FLAG_DMS = BIT(3),
|
||||||
DSI_MODE_FLAG_VRR = BIT(4),
|
DSI_MODE_FLAG_VRR = BIT(4),
|
||||||
|
DSI_MODE_FLAG_POMS = BIT(5),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -555,12 +558,14 @@ struct dsi_display_mode_priv_info {
|
|||||||
* @timing: Timing parameters for the panel.
|
* @timing: Timing parameters for the panel.
|
||||||
* @pixel_clk_khz: Pixel clock in Khz.
|
* @pixel_clk_khz: Pixel clock in Khz.
|
||||||
* @dsi_mode_flags: Flags to signal other drm components via private flags
|
* @dsi_mode_flags: Flags to signal other drm components via private flags
|
||||||
|
* @panel_mode: Panel mode
|
||||||
* @priv_info: Mode private info
|
* @priv_info: Mode private info
|
||||||
*/
|
*/
|
||||||
struct dsi_display_mode {
|
struct dsi_display_mode {
|
||||||
struct dsi_mode_info timing;
|
struct dsi_mode_info timing;
|
||||||
u32 pixel_clk_khz;
|
u32 pixel_clk_khz;
|
||||||
u32 dsi_mode_flags;
|
u32 dsi_mode_flags;
|
||||||
|
enum dsi_op_mode panel_mode;
|
||||||
struct dsi_display_mode_priv_info *priv_info;
|
struct dsi_display_mode_priv_info *priv_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -3971,6 +3971,10 @@ static int dsi_display_set_mode_sub(struct dsi_display *display,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mode->dsi_mode_flags & DSI_MODE_FLAG_POMS) {
|
||||||
|
display->config.panel_mode = mode->panel_mode;
|
||||||
|
display->panel->panel_mode = mode->panel_mode;
|
||||||
|
}
|
||||||
rc = dsi_panel_get_host_cfg_for_mode(display->panel,
|
rc = dsi_panel_get_host_cfg_for_mode(display->panel,
|
||||||
mode,
|
mode,
|
||||||
&display->config);
|
&display->config);
|
||||||
@@ -5039,7 +5043,8 @@ static int dsi_display_ext_get_info(struct drm_connector *connector,
|
|||||||
info->is_primary = false;
|
info->is_primary = false;
|
||||||
|
|
||||||
info->capabilities |= (MSM_DISPLAY_CAP_VID_MODE |
|
info->capabilities |= (MSM_DISPLAY_CAP_VID_MODE |
|
||||||
MSM_DISPLAY_CAP_EDID | MSM_DISPLAY_CAP_HOT_PLUG);
|
MSM_DISPLAY_CAP_EDID | MSM_DISPLAY_CAP_HOT_PLUG);
|
||||||
|
info->curr_panel_mode = MSM_DISPLAY_VIDEO_MODE;
|
||||||
|
|
||||||
mutex_unlock(&display->display_lock);
|
mutex_unlock(&display->display_lock);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -5403,10 +5408,16 @@ int dsi_display_get_info(struct drm_connector *connector,
|
|||||||
|
|
||||||
switch (display->panel->panel_mode) {
|
switch (display->panel->panel_mode) {
|
||||||
case DSI_OP_VIDEO_MODE:
|
case DSI_OP_VIDEO_MODE:
|
||||||
|
info->curr_panel_mode = MSM_DISPLAY_VIDEO_MODE;
|
||||||
info->capabilities |= MSM_DISPLAY_CAP_VID_MODE;
|
info->capabilities |= MSM_DISPLAY_CAP_VID_MODE;
|
||||||
|
if (display->panel->panel_mode_switch_enabled)
|
||||||
|
info->capabilities |= MSM_DISPLAY_CAP_CMD_MODE;
|
||||||
break;
|
break;
|
||||||
case DSI_OP_CMD_MODE:
|
case DSI_OP_CMD_MODE:
|
||||||
|
info->curr_panel_mode = MSM_DISPLAY_CMD_MODE;
|
||||||
info->capabilities |= MSM_DISPLAY_CAP_CMD_MODE;
|
info->capabilities |= MSM_DISPLAY_CAP_CMD_MODE;
|
||||||
|
if (display->panel->panel_mode_switch_enabled)
|
||||||
|
info->capabilities |= MSM_DISPLAY_CAP_VID_MODE;
|
||||||
info->is_te_using_watchdog_timer =
|
info->is_te_using_watchdog_timer =
|
||||||
display->panel->te_using_watchdog_timer |
|
display->panel->te_using_watchdog_timer |
|
||||||
display->sw_te_using_wd;
|
display->sw_te_using_wd;
|
||||||
@@ -5704,7 +5715,8 @@ int dsi_display_find_mode(struct dsi_display *display,
|
|||||||
|
|
||||||
if (cmp->timing.v_active == m->timing.v_active &&
|
if (cmp->timing.v_active == m->timing.v_active &&
|
||||||
cmp->timing.h_active == m->timing.h_active &&
|
cmp->timing.h_active == m->timing.h_active &&
|
||||||
cmp->timing.refresh_rate == m->timing.refresh_rate) {
|
cmp->timing.refresh_rate == m->timing.refresh_rate &&
|
||||||
|
cmp->panel_mode == m->panel_mode) {
|
||||||
*out_mode = m;
|
*out_mode = m;
|
||||||
rc = 0;
|
rc = 0;
|
||||||
break;
|
break;
|
||||||
@@ -6314,7 +6326,8 @@ int dsi_display_prepare(struct dsi_display *display)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!display->is_cont_splash_enabled) {
|
if (!(mode->dsi_mode_flags & DSI_MODE_FLAG_POMS) &&
|
||||||
|
(!display->is_cont_splash_enabled)) {
|
||||||
/*
|
/*
|
||||||
* For continuous splash usecase we skip panel
|
* For continuous splash usecase we skip panel
|
||||||
* pre prepare since the regulator vote is already
|
* pre prepare since the regulator vote is already
|
||||||
@@ -6403,11 +6416,13 @@ int dsi_display_prepare(struct dsi_display *display)
|
|||||||
goto error_ctrl_link_off;
|
goto error_ctrl_link_off;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = dsi_panel_prepare(display->panel);
|
if (!(mode->dsi_mode_flags & DSI_MODE_FLAG_POMS)) {
|
||||||
if (rc) {
|
rc = dsi_panel_prepare(display->panel);
|
||||||
pr_err("[%s] panel prepare failed, rc=%d\n",
|
if (rc) {
|
||||||
display->name, rc);
|
pr_err("[%s] panel prepare failed, rc=%d\n",
|
||||||
goto error_ctrl_link_off;
|
display->name, rc);
|
||||||
|
goto error_ctrl_link_off;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
goto error;
|
goto error;
|
||||||
@@ -6728,7 +6743,8 @@ int dsi_display_enable(struct dsi_display *display)
|
|||||||
display->name, rc);
|
display->name, rc);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (!(display->panel->cur_mode->dsi_mode_flags &
|
||||||
|
DSI_MODE_FLAG_POMS)){
|
||||||
rc = dsi_panel_enable(display->panel);
|
rc = dsi_panel_enable(display->panel);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
pr_err("[%s] failed to enable DSI panel, rc=%d\n",
|
pr_err("[%s] failed to enable DSI panel, rc=%d\n",
|
||||||
@@ -6757,6 +6773,7 @@ int dsi_display_enable(struct dsi_display *display)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (display->config.panel_mode == DSI_OP_VIDEO_MODE) {
|
if (display->config.panel_mode == DSI_OP_VIDEO_MODE) {
|
||||||
|
pr_debug("%s:enable video timing eng\n", __func__);
|
||||||
rc = dsi_display_vid_engine_enable(display);
|
rc = dsi_display_vid_engine_enable(display);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
pr_err("[%s]failed to enable DSI video engine, rc=%d\n",
|
pr_err("[%s]failed to enable DSI video engine, rc=%d\n",
|
||||||
@@ -6764,6 +6781,7 @@ int dsi_display_enable(struct dsi_display *display)
|
|||||||
goto error_disable_panel;
|
goto error_disable_panel;
|
||||||
}
|
}
|
||||||
} else if (display->config.panel_mode == DSI_OP_CMD_MODE) {
|
} else if (display->config.panel_mode == DSI_OP_CMD_MODE) {
|
||||||
|
pr_debug("%s:enable command timing eng\n", __func__);
|
||||||
rc = dsi_display_cmd_engine_enable(display);
|
rc = dsi_display_cmd_engine_enable(display);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
pr_err("[%s]failed to enable DSI cmd engine, rc=%d\n",
|
pr_err("[%s]failed to enable DSI cmd engine, rc=%d\n",
|
||||||
@@ -6797,10 +6815,18 @@ int dsi_display_post_enable(struct dsi_display *display)
|
|||||||
|
|
||||||
mutex_lock(&display->display_lock);
|
mutex_lock(&display->display_lock);
|
||||||
|
|
||||||
rc = dsi_panel_post_enable(display->panel);
|
if (display->panel->cur_mode->dsi_mode_flags & DSI_MODE_FLAG_POMS) {
|
||||||
if (rc)
|
if (display->config.panel_mode == DSI_OP_CMD_MODE)
|
||||||
pr_err("[%s] panel post-enable failed, rc=%d\n",
|
dsi_panel_mode_switch_to_cmd(display->panel);
|
||||||
display->name, rc);
|
|
||||||
|
if (display->config.panel_mode == DSI_OP_VIDEO_MODE)
|
||||||
|
dsi_panel_mode_switch_to_vid(display->panel);
|
||||||
|
} else {
|
||||||
|
rc = dsi_panel_post_enable(display->panel);
|
||||||
|
if (rc)
|
||||||
|
pr_err("[%s] panel post-enable failed, rc=%d\n",
|
||||||
|
display->name, rc);
|
||||||
|
}
|
||||||
|
|
||||||
/* remove the clk vote for CMD mode panels */
|
/* remove the clk vote for CMD mode panels */
|
||||||
if (display->config.panel_mode == DSI_OP_CMD_MODE)
|
if (display->config.panel_mode == DSI_OP_CMD_MODE)
|
||||||
@@ -6826,12 +6852,18 @@ int dsi_display_pre_disable(struct dsi_display *display)
|
|||||||
if (display->config.panel_mode == DSI_OP_CMD_MODE)
|
if (display->config.panel_mode == DSI_OP_CMD_MODE)
|
||||||
dsi_display_clk_ctrl(display->dsi_clk_handle,
|
dsi_display_clk_ctrl(display->dsi_clk_handle,
|
||||||
DSI_ALL_CLKS, DSI_CLK_ON);
|
DSI_ALL_CLKS, DSI_CLK_ON);
|
||||||
|
if (display->poms_pending) {
|
||||||
|
if (display->config.panel_mode == DSI_OP_CMD_MODE)
|
||||||
|
dsi_panel_pre_mode_switch_to_video(display->panel);
|
||||||
|
|
||||||
rc = dsi_panel_pre_disable(display->panel);
|
if (display->config.panel_mode == DSI_OP_VIDEO_MODE)
|
||||||
if (rc)
|
dsi_panel_pre_mode_switch_to_cmd(display->panel);
|
||||||
pr_err("[%s] panel pre-disable failed, rc=%d\n",
|
} else {
|
||||||
display->name, rc);
|
rc = dsi_panel_pre_disable(display->panel);
|
||||||
|
if (rc)
|
||||||
|
pr_err("[%s] panel pre-disable failed, rc=%d\n",
|
||||||
|
display->name, rc);
|
||||||
|
}
|
||||||
mutex_unlock(&display->display_lock);
|
mutex_unlock(&display->display_lock);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -6868,11 +6900,12 @@ int dsi_display_disable(struct dsi_display *display)
|
|||||||
rc = -EINVAL;
|
rc = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = dsi_panel_disable(display->panel);
|
if (!display->poms_pending) {
|
||||||
if (rc)
|
rc = dsi_panel_disable(display->panel);
|
||||||
pr_err("[%s] failed to disable DSI panel, rc=%d\n",
|
if (rc)
|
||||||
display->name, rc);
|
pr_err("[%s] failed to disable DSI panel, rc=%d\n",
|
||||||
|
display->name, rc);
|
||||||
|
}
|
||||||
mutex_unlock(&display->display_lock);
|
mutex_unlock(&display->display_lock);
|
||||||
SDE_EVT32(SDE_EVTLOG_FUNC_EXIT);
|
SDE_EVT32(SDE_EVTLOG_FUNC_EXIT);
|
||||||
return rc;
|
return rc;
|
||||||
@@ -6911,12 +6944,12 @@ int dsi_display_unprepare(struct dsi_display *display)
|
|||||||
if (rc)
|
if (rc)
|
||||||
pr_err("[%s] display wake up failed, rc=%d\n",
|
pr_err("[%s] display wake up failed, rc=%d\n",
|
||||||
display->name, rc);
|
display->name, rc);
|
||||||
|
if (!display->poms_pending) {
|
||||||
rc = dsi_panel_unprepare(display->panel);
|
rc = dsi_panel_unprepare(display->panel);
|
||||||
if (rc)
|
if (rc)
|
||||||
pr_err("[%s] panel unprepare failed, rc=%d\n",
|
pr_err("[%s] panel unprepare failed, rc=%d\n",
|
||||||
display->name, rc);
|
display->name, rc);
|
||||||
|
}
|
||||||
rc = dsi_display_ctrl_host_disable(display);
|
rc = dsi_display_ctrl_host_disable(display);
|
||||||
if (rc)
|
if (rc)
|
||||||
pr_err("[%s] failed to disable DSI host, rc=%d\n",
|
pr_err("[%s] failed to disable DSI host, rc=%d\n",
|
||||||
@@ -6949,10 +6982,12 @@ int dsi_display_unprepare(struct dsi_display *display)
|
|||||||
/* destrory dsi isr set up */
|
/* destrory dsi isr set up */
|
||||||
dsi_display_ctrl_isr_configure(display, false);
|
dsi_display_ctrl_isr_configure(display, false);
|
||||||
|
|
||||||
rc = dsi_panel_post_unprepare(display->panel);
|
if (!display->poms_pending) {
|
||||||
if (rc)
|
rc = dsi_panel_post_unprepare(display->panel);
|
||||||
pr_err("[%s] panel post-unprepare failed, rc=%d\n",
|
if (rc)
|
||||||
display->name, rc);
|
pr_err("[%s] panel post-unprepare failed, rc=%d\n",
|
||||||
|
display->name, rc);
|
||||||
|
}
|
||||||
|
|
||||||
mutex_unlock(&display->display_lock);
|
mutex_unlock(&display->display_lock);
|
||||||
|
|
||||||
|
@@ -166,6 +166,7 @@ struct dsi_display_ext_bridge {
|
|||||||
* @cmdline_topology: Display topology shared from kernel command line.
|
* @cmdline_topology: Display topology shared from kernel command line.
|
||||||
* @cmdline_timing: Display timing shared from kernel command line.
|
* @cmdline_timing: Display timing shared from kernel command line.
|
||||||
* @is_tpg_enabled: TPG state.
|
* @is_tpg_enabled: TPG state.
|
||||||
|
* @poms_pending; Flag indicating the pending panel operating mode switch.
|
||||||
* @ulps_enabled: ulps state.
|
* @ulps_enabled: ulps state.
|
||||||
* @clamp_enabled: clamp state.
|
* @clamp_enabled: clamp state.
|
||||||
* @phy_idle_power_off: PHY power state.
|
* @phy_idle_power_off: PHY power state.
|
||||||
@@ -226,6 +227,7 @@ struct dsi_display {
|
|||||||
int cmdline_topology;
|
int cmdline_topology;
|
||||||
int cmdline_timing;
|
int cmdline_timing;
|
||||||
bool is_tpg_enabled;
|
bool is_tpg_enabled;
|
||||||
|
bool poms_pending;
|
||||||
bool ulps_enabled;
|
bool ulps_enabled;
|
||||||
bool clamp_enabled;
|
bool clamp_enabled;
|
||||||
bool phy_idle_power_off;
|
bool phy_idle_power_off;
|
||||||
|
@@ -71,11 +71,18 @@ static void convert_to_dsi_mode(const struct drm_display_mode *drm_mode,
|
|||||||
dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DMS;
|
dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DMS;
|
||||||
if (msm_is_mode_seamless_vrr(drm_mode))
|
if (msm_is_mode_seamless_vrr(drm_mode))
|
||||||
dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR;
|
dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR;
|
||||||
|
if (msm_is_mode_seamless_poms(drm_mode))
|
||||||
|
dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_POMS;
|
||||||
|
|
||||||
dsi_mode->timing.h_sync_polarity =
|
dsi_mode->timing.h_sync_polarity =
|
||||||
!!(drm_mode->flags & DRM_MODE_FLAG_PHSYNC);
|
!!(drm_mode->flags & DRM_MODE_FLAG_PHSYNC);
|
||||||
dsi_mode->timing.v_sync_polarity =
|
dsi_mode->timing.v_sync_polarity =
|
||||||
!!(drm_mode->flags & DRM_MODE_FLAG_PVSYNC);
|
!!(drm_mode->flags & DRM_MODE_FLAG_PVSYNC);
|
||||||
|
|
||||||
|
if (drm_mode->flags & DRM_MODE_FLAG_VID_MODE_PANEL)
|
||||||
|
dsi_mode->panel_mode = DSI_OP_VIDEO_MODE;
|
||||||
|
if (drm_mode->flags & DRM_MODE_FLAG_CMD_MODE_PANEL)
|
||||||
|
dsi_mode->panel_mode = DSI_OP_CMD_MODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
|
void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
|
||||||
@@ -113,12 +120,19 @@ void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
|
|||||||
drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DMS;
|
drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DMS;
|
||||||
if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR)
|
if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR)
|
||||||
drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_VRR;
|
drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_VRR;
|
||||||
|
if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_POMS)
|
||||||
|
drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_POMS;
|
||||||
|
|
||||||
if (dsi_mode->timing.h_sync_polarity)
|
if (dsi_mode->timing.h_sync_polarity)
|
||||||
drm_mode->flags |= DRM_MODE_FLAG_PHSYNC;
|
drm_mode->flags |= DRM_MODE_FLAG_PHSYNC;
|
||||||
if (dsi_mode->timing.v_sync_polarity)
|
if (dsi_mode->timing.v_sync_polarity)
|
||||||
drm_mode->flags |= DRM_MODE_FLAG_PVSYNC;
|
drm_mode->flags |= DRM_MODE_FLAG_PVSYNC;
|
||||||
|
|
||||||
|
if (dsi_mode->panel_mode == DSI_OP_VIDEO_MODE)
|
||||||
|
drm_mode->flags |= DRM_MODE_FLAG_VID_MODE_PANEL;
|
||||||
|
if (dsi_mode->panel_mode == DSI_OP_CMD_MODE)
|
||||||
|
drm_mode->flags |= DRM_MODE_FLAG_CMD_MODE_PANEL;
|
||||||
|
|
||||||
drm_mode_set_name(drm_mode);
|
drm_mode_set_name(drm_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,8 +247,18 @@ static void dsi_bridge_disable(struct drm_bridge *bridge)
|
|||||||
}
|
}
|
||||||
display = c_bridge->display;
|
display = c_bridge->display;
|
||||||
|
|
||||||
if (display && display->drm_conn)
|
if (display && display->drm_conn) {
|
||||||
sde_connector_helper_bridge_disable(display->drm_conn);
|
if (bridge->encoder->crtc->state->adjusted_mode.private_flags &
|
||||||
|
MSM_MODE_FLAG_SEAMLESS_POMS) {
|
||||||
|
display->poms_pending = true;
|
||||||
|
/* Disable ESD thread, during panel mode switch */
|
||||||
|
sde_connector_schedule_status_work(display->drm_conn,
|
||||||
|
false);
|
||||||
|
} else {
|
||||||
|
display->poms_pending = false;
|
||||||
|
sde_connector_helper_bridge_disable(display->drm_conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rc = dsi_display_pre_disable(c_bridge->display);
|
rc = dsi_display_pre_disable(c_bridge->display);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
@@ -363,9 +387,17 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
|
|||||||
|
|
||||||
cur_mode = crtc_state->crtc->mode;
|
cur_mode = crtc_state->crtc->mode;
|
||||||
|
|
||||||
|
/* No panel mode switch when drm pipeline is changing */
|
||||||
|
if ((dsi_mode.panel_mode != cur_dsi_mode.panel_mode) &&
|
||||||
|
(!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR)) &&
|
||||||
|
(!crtc_state->active_changed ||
|
||||||
|
display->is_cont_splash_enabled))
|
||||||
|
dsi_mode.dsi_mode_flags |= DSI_MODE_FLAG_POMS;
|
||||||
|
|
||||||
/* No DMS/VRR when drm pipeline is changing */
|
/* No DMS/VRR when drm pipeline is changing */
|
||||||
if (!drm_mode_equal(&cur_mode, adjusted_mode) &&
|
if (!drm_mode_equal(&cur_mode, adjusted_mode) &&
|
||||||
(!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR)) &&
|
(!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR)) &&
|
||||||
|
(!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_POMS)) &&
|
||||||
(!crtc_state->active_changed ||
|
(!crtc_state->active_changed ||
|
||||||
display->is_cont_splash_enabled))
|
display->is_cont_splash_enabled))
|
||||||
dsi_mode.dsi_mode_flags |= DSI_MODE_FLAG_DMS;
|
dsi_mode.dsi_mode_flags |= DSI_MODE_FLAG_DMS;
|
||||||
|
@@ -1365,6 +1365,7 @@ static int dsi_panel_parse_panel_mode(struct dsi_panel *panel)
|
|||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct dsi_parser_utils *utils = &panel->utils;
|
struct dsi_parser_utils *utils = &panel->utils;
|
||||||
|
bool panel_mode_switch_enabled;
|
||||||
enum dsi_op_mode panel_mode;
|
enum dsi_op_mode panel_mode;
|
||||||
const char *mode;
|
const char *mode;
|
||||||
|
|
||||||
@@ -1383,7 +1384,13 @@ static int dsi_panel_parse_panel_mode(struct dsi_panel *panel)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (panel_mode == DSI_OP_VIDEO_MODE) {
|
panel_mode_switch_enabled = utils->read_bool(utils->data,
|
||||||
|
"qcom,mdss-dsi-panel-mode-switch");
|
||||||
|
|
||||||
|
pr_info("%s: panel operating mode switch feature %s\n", __func__,
|
||||||
|
(panel_mode_switch_enabled ? "enabled" : "disabled"));
|
||||||
|
|
||||||
|
if (panel_mode == DSI_OP_VIDEO_MODE || panel_mode_switch_enabled) {
|
||||||
rc = dsi_panel_parse_video_host_config(&panel->video_config,
|
rc = dsi_panel_parse_video_host_config(&panel->video_config,
|
||||||
utils,
|
utils,
|
||||||
panel->name);
|
panel->name);
|
||||||
@@ -1394,7 +1401,7 @@ static int dsi_panel_parse_panel_mode(struct dsi_panel *panel)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (panel_mode == DSI_OP_CMD_MODE) {
|
if (panel_mode == DSI_OP_CMD_MODE || panel_mode_switch_enabled) {
|
||||||
rc = dsi_panel_parse_cmd_host_config(&panel->cmd_config,
|
rc = dsi_panel_parse_cmd_host_config(&panel->cmd_config,
|
||||||
utils,
|
utils,
|
||||||
panel->name);
|
panel->name);
|
||||||
@@ -1406,6 +1413,7 @@ static int dsi_panel_parse_panel_mode(struct dsi_panel *panel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
panel->panel_mode = panel_mode;
|
panel->panel_mode = panel_mode;
|
||||||
|
panel->panel_mode_switch_enabled = panel_mode_switch_enabled;
|
||||||
error:
|
error:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -2663,6 +2671,33 @@ static int dsi_panel_parse_partial_update_caps(struct dsi_display_mode *mode,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dsi_panel_parse_panel_mode_caps(struct dsi_display_mode *mode,
|
||||||
|
struct dsi_parser_utils *utils)
|
||||||
|
{
|
||||||
|
bool vid_mode_support, cmd_mode_support;
|
||||||
|
|
||||||
|
if (!mode || !mode->priv_info) {
|
||||||
|
pr_err("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
vid_mode_support = utils->read_bool(utils->data,
|
||||||
|
"qcom,mdss-dsi-video-mode");
|
||||||
|
|
||||||
|
cmd_mode_support = utils->read_bool(utils->data,
|
||||||
|
"qcom,mdss-dsi-cmd-mode");
|
||||||
|
|
||||||
|
if (cmd_mode_support)
|
||||||
|
mode->panel_mode = DSI_OP_CMD_MODE;
|
||||||
|
else if (vid_mode_support)
|
||||||
|
mode->panel_mode = DSI_OP_VIDEO_MODE;
|
||||||
|
else
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static int dsi_panel_parse_dms_info(struct dsi_panel *panel)
|
static int dsi_panel_parse_dms_info(struct dsi_panel *panel)
|
||||||
{
|
{
|
||||||
int dms_enabled;
|
int dms_enabled;
|
||||||
@@ -3349,6 +3384,17 @@ int dsi_panel_get_mode(struct dsi_panel *panel,
|
|||||||
rc = dsi_panel_parse_partial_update_caps(mode, utils);
|
rc = dsi_panel_parse_partial_update_caps(mode, utils);
|
||||||
if (rc)
|
if (rc)
|
||||||
pr_err("failed to partial update caps, rc=%d\n", rc);
|
pr_err("failed to partial update caps, rc=%d\n", rc);
|
||||||
|
|
||||||
|
if (panel->panel_mode_switch_enabled) {
|
||||||
|
rc = dsi_panel_parse_panel_mode_caps(mode, utils);
|
||||||
|
if (rc) {
|
||||||
|
pr_err("PMS: failed to parse panel mode\n");
|
||||||
|
rc = 0;
|
||||||
|
mode->panel_mode = panel->panel_mode;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mode->panel_mode = panel->panel_mode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
@@ -3707,6 +3753,86 @@ int dsi_panel_send_roi_dcs(struct dsi_panel *panel, int ctrl_idx,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int dsi_panel_pre_mode_switch_to_video(struct dsi_panel *panel)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (!panel) {
|
||||||
|
pr_err("Invalid params\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&panel->panel_lock);
|
||||||
|
|
||||||
|
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_CMD_TO_VID_SWITCH);
|
||||||
|
if (rc)
|
||||||
|
pr_err("[%s] failed to send DSI_CMD_SET_CMD_TO_VID_SWITCH cmds, rc=%d\n",
|
||||||
|
panel->name, rc);
|
||||||
|
|
||||||
|
mutex_unlock(&panel->panel_lock);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dsi_panel_pre_mode_switch_to_cmd(struct dsi_panel *panel)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (!panel) {
|
||||||
|
pr_err("Invalid params\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&panel->panel_lock);
|
||||||
|
|
||||||
|
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_VID_TO_CMD_SWITCH);
|
||||||
|
if (rc)
|
||||||
|
pr_err("[%s] failed to send DSI_CMD_SET_CMD_TO_VID_SWITCH cmds, rc=%d\n",
|
||||||
|
panel->name, rc);
|
||||||
|
|
||||||
|
mutex_unlock(&panel->panel_lock);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dsi_panel_mode_switch_to_cmd(struct dsi_panel *panel)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (!panel) {
|
||||||
|
pr_err("Invalid params\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&panel->panel_lock);
|
||||||
|
|
||||||
|
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_VID_TO_CMD_SWITCH);
|
||||||
|
if (rc)
|
||||||
|
pr_err("[%s] failed to send DSI_CMD_SET_CMD_TO_VID_SWITCH cmds, rc=%d\n",
|
||||||
|
panel->name, rc);
|
||||||
|
|
||||||
|
mutex_unlock(&panel->panel_lock);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dsi_panel_mode_switch_to_vid(struct dsi_panel *panel)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (!panel) {
|
||||||
|
pr_err("Invalid params\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&panel->panel_lock);
|
||||||
|
|
||||||
|
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_POST_CMD_TO_VID_SWITCH);
|
||||||
|
if (rc)
|
||||||
|
pr_err("[%s] failed to send DSI_CMD_SET_CMD_TO_VID_SWITCH cmds, rc=%d\n",
|
||||||
|
panel->name, rc);
|
||||||
|
|
||||||
|
mutex_unlock(&panel->panel_lock);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
int dsi_panel_switch(struct dsi_panel *panel)
|
int dsi_panel_switch(struct dsi_panel *panel)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
@@ -156,6 +156,7 @@ struct dsi_panel {
|
|||||||
struct dsi_video_engine_cfg video_config;
|
struct dsi_video_engine_cfg video_config;
|
||||||
struct dsi_cmd_engine_cfg cmd_config;
|
struct dsi_cmd_engine_cfg cmd_config;
|
||||||
enum dsi_op_mode panel_mode;
|
enum dsi_op_mode panel_mode;
|
||||||
|
bool panel_mode_switch_enabled;
|
||||||
|
|
||||||
struct dsi_dfps_capabilities dfps_caps;
|
struct dsi_dfps_capabilities dfps_caps;
|
||||||
struct dsi_panel_phy_props phy_props;
|
struct dsi_panel_phy_props phy_props;
|
||||||
@@ -277,6 +278,11 @@ int dsi_panel_send_qsync_off_dcs(struct dsi_panel *panel,
|
|||||||
int dsi_panel_send_roi_dcs(struct dsi_panel *panel, int ctrl_idx,
|
int dsi_panel_send_roi_dcs(struct dsi_panel *panel, int ctrl_idx,
|
||||||
struct dsi_rect *roi);
|
struct dsi_rect *roi);
|
||||||
|
|
||||||
|
int dsi_panel_pre_mode_switch_to_video(struct dsi_panel *panel);
|
||||||
|
int dsi_panel_pre_mode_switch_to_cmd(struct dsi_panel *panel);
|
||||||
|
int dsi_panel_mode_switch_to_cmd(struct dsi_panel *panel);
|
||||||
|
int dsi_panel_mode_switch_to_vid(struct dsi_panel *panel);
|
||||||
|
|
||||||
int dsi_panel_switch(struct dsi_panel *panel);
|
int dsi_panel_switch(struct dsi_panel *panel);
|
||||||
|
|
||||||
int dsi_panel_post_switch(struct dsi_panel *panel);
|
int dsi_panel_post_switch(struct dsi_panel *panel);
|
||||||
|
@@ -86,7 +86,8 @@ static inline bool _msm_seamless_for_crtc(struct drm_atomic_state *state,
|
|||||||
int conn_cnt = 0;
|
int conn_cnt = 0;
|
||||||
|
|
||||||
if (msm_is_mode_seamless(&crtc_state->mode) ||
|
if (msm_is_mode_seamless(&crtc_state->mode) ||
|
||||||
msm_is_mode_seamless_vrr(&crtc_state->adjusted_mode))
|
msm_is_mode_seamless_vrr(&crtc_state->adjusted_mode) ||
|
||||||
|
msm_is_mode_seamless_poms(&crtc_state->adjusted_mode))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (msm_is_mode_seamless_dms(&crtc_state->adjusted_mode) && !enable)
|
if (msm_is_mode_seamless_dms(&crtc_state->adjusted_mode) && !enable)
|
||||||
|
@@ -248,6 +248,18 @@ enum msm_display_caps {
|
|||||||
MSM_DISPLAY_CAP_MST_MODE = BIT(5),
|
MSM_DISPLAY_CAP_MST_MODE = BIT(5),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum panel_mode - panel operation mode
|
||||||
|
* @MSM_DISPLAY_VIDEO_MODE: video mode panel
|
||||||
|
* @MSM_DISPLAY_CMD_MODE: Command mode panel
|
||||||
|
* @MODE_MAX:
|
||||||
|
*/
|
||||||
|
enum panel_op_mode {
|
||||||
|
MSM_DISPLAY_VIDEO_MODE = 0,
|
||||||
|
MSM_DISPLAY_CMD_MODE,
|
||||||
|
MSM_DISPLAY_MODE_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enum msm_event_wait - type of HW events to wait for
|
* enum msm_event_wait - type of HW events to wait for
|
||||||
* @MSM_ENC_COMMIT_DONE - wait for the driver to flush the registers to HW
|
* @MSM_ENC_COMMIT_DONE - wait for the driver to flush the registers to HW
|
||||||
@@ -484,7 +496,7 @@ struct msm_mode_info {
|
|||||||
struct msm_display_info {
|
struct msm_display_info {
|
||||||
int intf_type;
|
int intf_type;
|
||||||
uint32_t capabilities;
|
uint32_t capabilities;
|
||||||
|
enum panel_op_mode curr_panel_mode;
|
||||||
uint32_t num_of_h_tiles;
|
uint32_t num_of_h_tiles;
|
||||||
uint32_t h_tile_instance[MAX_H_TILES_PER_DISPLAY];
|
uint32_t h_tile_instance[MAX_H_TILES_PER_DISPLAY];
|
||||||
|
|
||||||
|
@@ -38,6 +38,8 @@
|
|||||||
#define MSM_MODE_FLAG_SEAMLESS_DMS (1<<2)
|
#define MSM_MODE_FLAG_SEAMLESS_DMS (1<<2)
|
||||||
/* Request to switch the fps */
|
/* Request to switch the fps */
|
||||||
#define MSM_MODE_FLAG_SEAMLESS_VRR (1<<3)
|
#define MSM_MODE_FLAG_SEAMLESS_VRR (1<<3)
|
||||||
|
/* Request to switch the panel mode */
|
||||||
|
#define MSM_MODE_FLAG_SEAMLESS_POMS (1<<4)
|
||||||
|
|
||||||
/* As there are different display controller blocks depending on the
|
/* As there are different display controller blocks depending on the
|
||||||
* snapdragon version, the kms support is split out and the appropriate
|
* snapdragon version, the kms support is split out and the appropriate
|
||||||
@@ -212,6 +214,13 @@ static inline bool msm_is_mode_seamless_vrr(const struct drm_display_mode *mode)
|
|||||||
: false;
|
: false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool msm_is_mode_seamless_poms(
|
||||||
|
const struct drm_display_mode *mode)
|
||||||
|
{
|
||||||
|
return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_POMS)
|
||||||
|
: false;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool msm_needs_vblank_pre_modeset(
|
static inline bool msm_needs_vblank_pre_modeset(
|
||||||
const struct drm_display_mode *mode)
|
const struct drm_display_mode *mode)
|
||||||
{
|
{
|
||||||
|
@@ -1795,8 +1795,8 @@ int sde_crtc_get_secure_transition_ops(struct drm_crtc *crtc,
|
|||||||
*/
|
*/
|
||||||
drm_for_each_encoder_mask(encoder, crtc->dev,
|
drm_for_each_encoder_mask(encoder, crtc->dev,
|
||||||
crtc->state->encoder_mask) {
|
crtc->state->encoder_mask) {
|
||||||
post_commit |= sde_encoder_check_mode(encoder,
|
post_commit |= sde_encoder_check_curr_mode(encoder,
|
||||||
MSM_DISPLAY_CAP_VID_MODE);
|
MSM_DISPLAY_VIDEO_MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDE_DEBUG("crtc%d: secure_level %d old_valid_fb %d post_commit %d\n",
|
SDE_DEBUG("crtc%d: secure_level %d old_valid_fb %d post_commit %d\n",
|
||||||
@@ -3136,8 +3136,8 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc,
|
|||||||
_sde_crtc_dest_scaler_setup(crtc);
|
_sde_crtc_dest_scaler_setup(crtc);
|
||||||
|
|
||||||
/* cancel the idle notify delayed work */
|
/* cancel the idle notify delayed work */
|
||||||
if (sde_encoder_check_mode(sde_crtc->mixers[0].encoder,
|
if (sde_encoder_check_curr_mode(sde_crtc->mixers[0].encoder,
|
||||||
MSM_DISPLAY_CAP_VID_MODE) &&
|
MSM_DISPLAY_VIDEO_MODE) &&
|
||||||
kthread_cancel_delayed_work_sync(&sde_crtc->idle_notify_work))
|
kthread_cancel_delayed_work_sync(&sde_crtc->idle_notify_work))
|
||||||
SDE_DEBUG("idle notify work cancelled\n");
|
SDE_DEBUG("idle notify work cancelled\n");
|
||||||
|
|
||||||
@@ -3253,8 +3253,9 @@ static void sde_crtc_atomic_flush(struct drm_crtc *crtc,
|
|||||||
_sde_crtc_wait_for_fences(crtc);
|
_sde_crtc_wait_for_fences(crtc);
|
||||||
|
|
||||||
/* schedule the idle notify delayed work */
|
/* schedule the idle notify delayed work */
|
||||||
if (idle_time && sde_encoder_check_mode(sde_crtc->mixers[0].encoder,
|
if (idle_time && sde_encoder_check_curr_mode(
|
||||||
MSM_DISPLAY_CAP_VID_MODE)) {
|
sde_crtc->mixers[0].encoder,
|
||||||
|
MSM_DISPLAY_VIDEO_MODE)) {
|
||||||
kthread_queue_delayed_work(&event_thread->worker,
|
kthread_queue_delayed_work(&event_thread->worker,
|
||||||
&sde_crtc->idle_notify_work,
|
&sde_crtc->idle_notify_work,
|
||||||
msecs_to_jiffies(idle_time));
|
msecs_to_jiffies(idle_time));
|
||||||
@@ -4322,8 +4323,8 @@ static int _sde_crtc_check_secure_state_smmu_translation(struct drm_crtc *crtc,
|
|||||||
|
|
||||||
drm_for_each_encoder_mask(encoder, crtc->dev,
|
drm_for_each_encoder_mask(encoder, crtc->dev,
|
||||||
crtc->state->encoder_mask) {
|
crtc->state->encoder_mask) {
|
||||||
is_video_mode |= sde_encoder_check_mode(encoder,
|
is_video_mode |= sde_encoder_check_curr_mode(encoder,
|
||||||
MSM_DISPLAY_CAP_VID_MODE);
|
MSM_DISPLAY_VIDEO_MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -5007,8 +5008,9 @@ static int _sde_crtc_get_output_fence(struct drm_crtc *crtc,
|
|||||||
cstate = to_sde_crtc_state(state);
|
cstate = to_sde_crtc_state(state);
|
||||||
|
|
||||||
drm_for_each_encoder_mask(encoder, crtc->dev, state->encoder_mask) {
|
drm_for_each_encoder_mask(encoder, crtc->dev, state->encoder_mask) {
|
||||||
is_vid |= sde_encoder_check_mode(encoder,
|
if (sde_encoder_check_curr_mode(encoder,
|
||||||
MSM_DISPLAY_CAP_VID_MODE);
|
MSM_DISPLAY_VIDEO_MODE))
|
||||||
|
is_vid = true;
|
||||||
if (is_vid)
|
if (is_vid)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -170,6 +170,8 @@ enum sde_enc_rc_states {
|
|||||||
* @te_source: vsync source pin information
|
* @te_source: vsync source pin information
|
||||||
* @num_phys_encs: Actual number of physical encoders contained.
|
* @num_phys_encs: Actual number of physical encoders contained.
|
||||||
* @phys_encs: Container of physical encoders managed.
|
* @phys_encs: Container of physical encoders managed.
|
||||||
|
* @phys_vid_encs: Video physical encoders for panel mode switch.
|
||||||
|
* @phys_cmd_encs: Command physical encoders for panel mode switch.
|
||||||
* @cur_master: Pointer to the current master in this mode. Optimization
|
* @cur_master: Pointer to the current master in this mode. Optimization
|
||||||
* Only valid after enable. Cleared as disable.
|
* Only valid after enable. Cleared as disable.
|
||||||
* @hw_pp Handle to the pingpong blocks used for the display. No.
|
* @hw_pp Handle to the pingpong blocks used for the display. No.
|
||||||
@@ -236,6 +238,8 @@ struct sde_encoder_virt {
|
|||||||
|
|
||||||
unsigned int num_phys_encs;
|
unsigned int num_phys_encs;
|
||||||
struct sde_encoder_phys *phys_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL];
|
struct sde_encoder_phys *phys_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL];
|
||||||
|
struct sde_encoder_phys *phys_vid_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL];
|
||||||
|
struct sde_encoder_phys *phys_cmd_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL];
|
||||||
struct sde_encoder_phys *cur_master;
|
struct sde_encoder_phys *cur_master;
|
||||||
struct sde_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
|
struct sde_hw_pingpong *hw_pp[MAX_CHANNELS_PER_ENC];
|
||||||
struct sde_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC];
|
struct sde_hw_dsc *hw_dsc[MAX_CHANNELS_PER_ENC];
|
||||||
@@ -677,8 +681,16 @@ void sde_encoder_destroy(struct drm_encoder *drm_enc)
|
|||||||
sde_rsc_client_destroy(sde_enc->rsc_client);
|
sde_rsc_client_destroy(sde_enc->rsc_client);
|
||||||
|
|
||||||
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
||||||
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
|
struct sde_encoder_phys *phys;
|
||||||
|
|
||||||
|
phys = sde_enc->phys_vid_encs[i];
|
||||||
|
if (phys && phys->ops.destroy) {
|
||||||
|
phys->ops.destroy(phys);
|
||||||
|
--sde_enc->num_phys_encs;
|
||||||
|
sde_enc->phys_encs[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
phys = sde_enc->phys_cmd_encs[i];
|
||||||
if (phys && phys->ops.destroy) {
|
if (phys && phys->ops.destroy) {
|
||||||
phys->ops.destroy(phys);
|
phys->ops.destroy(phys);
|
||||||
--sde_enc->num_phys_encs;
|
--sde_enc->num_phys_encs;
|
||||||
@@ -1687,7 +1699,7 @@ static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) {
|
if (sde_encoder_check_curr_mode(&sde_enc->base, MSM_DISPLAY_CMD_MODE)) {
|
||||||
if (is_dummy)
|
if (is_dummy)
|
||||||
vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_0 -
|
vsync_source = SDE_VSYNC_SOURCE_WD_TIMER_0 -
|
||||||
sde_enc->te_source;
|
sde_enc->te_source;
|
||||||
@@ -1892,9 +1904,9 @@ static int _sde_encoder_update_rsc_client(
|
|||||||
if (sde_encoder_in_clone_mode(drm_enc) || !disp_info->is_primary ||
|
if (sde_encoder_in_clone_mode(drm_enc) || !disp_info->is_primary ||
|
||||||
(disp_info->is_primary && qsync_mode))
|
(disp_info->is_primary && qsync_mode))
|
||||||
rsc_state = enable ? SDE_RSC_CLK_STATE : SDE_RSC_IDLE_STATE;
|
rsc_state = enable ? SDE_RSC_CLK_STATE : SDE_RSC_IDLE_STATE;
|
||||||
else if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE)
|
else if (sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE))
|
||||||
rsc_state = enable ? SDE_RSC_CMD_STATE : SDE_RSC_IDLE_STATE;
|
rsc_state = enable ? SDE_RSC_CMD_STATE : SDE_RSC_IDLE_STATE;
|
||||||
else if (disp_info->capabilities & MSM_DISPLAY_CAP_VID_MODE)
|
else if (sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_VIDEO_MODE))
|
||||||
rsc_state = enable ? SDE_RSC_VID_STATE : SDE_RSC_IDLE_STATE;
|
rsc_state = enable ? SDE_RSC_VID_STATE : SDE_RSC_IDLE_STATE;
|
||||||
|
|
||||||
SDE_EVT32(rsc_state, qsync_mode);
|
SDE_EVT32(rsc_state, qsync_mode);
|
||||||
@@ -2032,14 +2044,15 @@ static int _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc,
|
|||||||
struct sde_kms *sde_kms;
|
struct sde_kms *sde_kms;
|
||||||
struct sde_encoder_virt *sde_enc;
|
struct sde_encoder_virt *sde_enc;
|
||||||
int rc;
|
int rc;
|
||||||
bool is_cmd_mode, is_primary;
|
bool is_cmd_mode = false, is_primary;
|
||||||
|
|
||||||
sde_enc = to_sde_encoder_virt(drm_enc);
|
sde_enc = to_sde_encoder_virt(drm_enc);
|
||||||
priv = drm_enc->dev->dev_private;
|
priv = drm_enc->dev->dev_private;
|
||||||
sde_kms = to_sde_kms(priv->kms);
|
sde_kms = to_sde_kms(priv->kms);
|
||||||
|
|
||||||
is_cmd_mode = sde_enc->disp_info.capabilities &
|
if (sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE))
|
||||||
MSM_DISPLAY_CAP_CMD_MODE;
|
is_cmd_mode = true;
|
||||||
|
|
||||||
is_primary = sde_enc->disp_info.is_primary;
|
is_primary = sde_enc->disp_info.is_primary;
|
||||||
|
|
||||||
SDE_DEBUG_ENC(sde_enc, "enable:%d\n", enable);
|
SDE_DEBUG_ENC(sde_enc, "enable:%d\n", enable);
|
||||||
@@ -2612,9 +2625,8 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc,
|
|||||||
}
|
}
|
||||||
sde_enc = to_sde_encoder_virt(drm_enc);
|
sde_enc = to_sde_encoder_virt(drm_enc);
|
||||||
priv = drm_enc->dev->dev_private;
|
priv = drm_enc->dev->dev_private;
|
||||||
is_vid_mode = sde_enc->disp_info.capabilities &
|
if (sde_encoder_check_curr_mode(&sde_enc->base, MSM_DISPLAY_VIDEO_MODE))
|
||||||
MSM_DISPLAY_CAP_VID_MODE;
|
is_vid_mode = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* when idle_pc is not supported, process only KICKOFF, STOP and MODESET
|
* when idle_pc is not supported, process only KICKOFF, STOP and MODESET
|
||||||
* events and return early for other events (ie wb display).
|
* events and return early for other events (ie wb display).
|
||||||
@@ -2673,6 +2685,32 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sde_encoder_virt_mode_switch(enum sde_intf_mode intf_mode,
|
||||||
|
struct sde_encoder_virt *sde_enc,
|
||||||
|
struct drm_display_mode *adj_mode)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (intf_mode == INTF_MODE_CMD) {
|
||||||
|
for (i = 0; i < sde_enc->num_phys_encs; i++)
|
||||||
|
sde_enc->phys_encs[i] = sde_enc->phys_vid_encs[i];
|
||||||
|
sde_enc->disp_info.curr_panel_mode = MSM_DISPLAY_VIDEO_MODE;
|
||||||
|
SDE_DEBUG_ENC(sde_enc, "switch to video physical encoder\n");
|
||||||
|
SDE_EVT32(DRMID(&sde_enc->base), intf_mode,
|
||||||
|
msm_is_mode_seamless_poms(adj_mode),
|
||||||
|
SDE_EVTLOG_FUNC_CASE1);
|
||||||
|
}
|
||||||
|
if (intf_mode == INTF_MODE_VIDEO) {
|
||||||
|
for (i = 0; i < sde_enc->num_phys_encs; i++)
|
||||||
|
sde_enc->phys_encs[i] = sde_enc->phys_cmd_encs[i];
|
||||||
|
sde_enc->disp_info.curr_panel_mode = MSM_DISPLAY_CMD_MODE;
|
||||||
|
SDE_EVT32(DRMID(&sde_enc->base), intf_mode,
|
||||||
|
msm_is_mode_seamless_poms(adj_mode),
|
||||||
|
SDE_EVTLOG_FUNC_CASE2);
|
||||||
|
SDE_DEBUG_ENC(sde_enc, "switch to command physical encoder\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
|
static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
|
||||||
struct drm_display_mode *mode,
|
struct drm_display_mode *mode,
|
||||||
struct drm_display_mode *adj_mode)
|
struct drm_display_mode *adj_mode)
|
||||||
@@ -2686,6 +2724,8 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
|
|||||||
struct sde_connector *sde_conn = NULL;
|
struct sde_connector *sde_conn = NULL;
|
||||||
struct sde_rm_hw_iter dsc_iter, pp_iter;
|
struct sde_rm_hw_iter dsc_iter, pp_iter;
|
||||||
struct sde_rm_hw_request request_hw;
|
struct sde_rm_hw_request request_hw;
|
||||||
|
enum sde_intf_mode intf_mode;
|
||||||
|
|
||||||
int i = 0, ret;
|
int i = 0, ret;
|
||||||
|
|
||||||
if (!drm_enc) {
|
if (!drm_enc) {
|
||||||
@@ -2742,6 +2782,11 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
intf_mode = sde_encoder_get_intf_mode(drm_enc);
|
||||||
|
|
||||||
|
/* Switch pysical encoder */
|
||||||
|
if (msm_is_mode_seamless_poms(adj_mode))
|
||||||
|
sde_encoder_virt_mode_switch(intf_mode, sde_enc, adj_mode);
|
||||||
|
|
||||||
/* release resources before seamless mode change */
|
/* release resources before seamless mode change */
|
||||||
if (msm_is_mode_seamless_dms(adj_mode)) {
|
if (msm_is_mode_seamless_dms(adj_mode)) {
|
||||||
@@ -3151,8 +3196,8 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
|
|||||||
phys->ops.enable(phys);
|
phys->ops.enable(phys);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sde_enc->misr_enable && (sde_enc->disp_info.capabilities &
|
if (sde_enc->misr_enable && phys->ops.setup_misr &&
|
||||||
MSM_DISPLAY_CAP_VID_MODE) && phys->ops.setup_misr)
|
(sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_VIDEO_MODE)))
|
||||||
phys->ops.setup_misr(phys, true,
|
phys->ops.setup_misr(phys, true,
|
||||||
sde_enc->misr_frame_count);
|
sde_enc->misr_frame_count);
|
||||||
}
|
}
|
||||||
@@ -3509,7 +3554,8 @@ static void sde_encoder_frame_done_callback(
|
|||||||
{
|
{
|
||||||
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
bool trigger = true, is_cmd_mode;
|
bool trigger = true;
|
||||||
|
bool is_cmd_mode = false;
|
||||||
enum sde_rm_topology_name topology = SDE_RM_TOPOLOGY_NONE;
|
enum sde_rm_topology_name topology = SDE_RM_TOPOLOGY_NONE;
|
||||||
|
|
||||||
if (!drm_enc || !sde_enc->cur_master) {
|
if (!drm_enc || !sde_enc->cur_master) {
|
||||||
@@ -3520,8 +3566,8 @@ static void sde_encoder_frame_done_callback(
|
|||||||
|
|
||||||
sde_enc->crtc_frame_event_cb_data.connector =
|
sde_enc->crtc_frame_event_cb_data.connector =
|
||||||
sde_enc->cur_master->connector;
|
sde_enc->cur_master->connector;
|
||||||
is_cmd_mode = sde_enc->disp_info.capabilities &
|
if (sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE))
|
||||||
MSM_DISPLAY_CAP_CMD_MODE;
|
is_cmd_mode = true;
|
||||||
|
|
||||||
if (event & (SDE_ENCODER_FRAME_EVENT_DONE
|
if (event & (SDE_ENCODER_FRAME_EVENT_DONE
|
||||||
| SDE_ENCODER_FRAME_EVENT_ERROR
|
| SDE_ENCODER_FRAME_EVENT_ERROR
|
||||||
@@ -3840,8 +3886,8 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
is_vid_mode = sde_enc->disp_info.capabilities &
|
if (sde_encoder_check_curr_mode(&sde_enc->base, MSM_DISPLAY_VIDEO_MODE))
|
||||||
MSM_DISPLAY_CAP_VID_MODE;
|
is_vid_mode = true;
|
||||||
|
|
||||||
/* don't perform flush/start operations for slave encoders */
|
/* don't perform flush/start operations for slave encoders */
|
||||||
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
||||||
@@ -4047,7 +4093,7 @@ static void _sde_encoder_update_master(struct drm_encoder *drm_enc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sde_encoder_check_mode(struct drm_encoder *drm_enc, u32 mode)
|
bool sde_encoder_check_curr_mode(struct drm_encoder *drm_enc, u32 mode)
|
||||||
{
|
{
|
||||||
struct sde_encoder_virt *sde_enc;
|
struct sde_encoder_virt *sde_enc;
|
||||||
struct msm_display_info *disp_info;
|
struct msm_display_info *disp_info;
|
||||||
@@ -4060,7 +4106,7 @@ bool sde_encoder_check_mode(struct drm_encoder *drm_enc, u32 mode)
|
|||||||
sde_enc = to_sde_encoder_virt(drm_enc);
|
sde_enc = to_sde_encoder_virt(drm_enc);
|
||||||
disp_info = &sde_enc->disp_info;
|
disp_info = &sde_enc->disp_info;
|
||||||
|
|
||||||
return (disp_info->capabilities & mode);
|
return (disp_info->curr_panel_mode == mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sde_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc)
|
void sde_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc)
|
||||||
@@ -4094,8 +4140,9 @@ void sde_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc)
|
|||||||
|
|
||||||
/* update only for command mode primary ctl */
|
/* update only for command mode primary ctl */
|
||||||
if ((phys == sde_enc->cur_master) &&
|
if ((phys == sde_enc->cur_master) &&
|
||||||
(disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE)
|
(sde_encoder_check_curr_mode(drm_enc,
|
||||||
&& ctl->ops.trigger_pending)
|
MSM_DISPLAY_CMD_MODE))
|
||||||
|
&& ctl->ops.trigger_pending)
|
||||||
ctl->ops.trigger_pending(ctl);
|
ctl->ops.trigger_pending(ctl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4583,7 +4630,7 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
|
|||||||
|
|
||||||
|
|
||||||
if (sde_enc->cur_master && sde_enc->cur_master->connector &&
|
if (sde_enc->cur_master && sde_enc->cur_master->connector &&
|
||||||
disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE)
|
sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE))
|
||||||
sde_enc->frame_trigger_mode = sde_connector_get_property(
|
sde_enc->frame_trigger_mode = sde_connector_get_property(
|
||||||
sde_enc->cur_master->connector->state,
|
sde_enc->cur_master->connector->state,
|
||||||
CONNECTOR_PROP_CMD_FRAME_TRIGGER_MODE);
|
CONNECTOR_PROP_CMD_FRAME_TRIGGER_MODE);
|
||||||
@@ -5115,11 +5162,12 @@ static void sde_encoder_early_unregister(struct drm_encoder *encoder)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int sde_encoder_virt_add_phys_encs(
|
static int sde_encoder_virt_add_phys_encs(
|
||||||
u32 display_caps,
|
struct msm_display_info *disp_info,
|
||||||
struct sde_encoder_virt *sde_enc,
|
struct sde_encoder_virt *sde_enc,
|
||||||
struct sde_enc_phys_init_params *params)
|
struct sde_enc_phys_init_params *params)
|
||||||
{
|
{
|
||||||
struct sde_encoder_phys *enc = NULL;
|
struct sde_encoder_phys *enc = NULL;
|
||||||
|
u32 display_caps = disp_info->capabilities;
|
||||||
|
|
||||||
SDE_DEBUG_ENC(sde_enc, "\n");
|
SDE_DEBUG_ENC(sde_enc, "\n");
|
||||||
|
|
||||||
@@ -5143,8 +5191,7 @@ static int sde_encoder_virt_add_phys_encs(
|
|||||||
return !enc ? -EINVAL : PTR_ERR(enc);
|
return !enc ? -EINVAL : PTR_ERR(enc);
|
||||||
}
|
}
|
||||||
|
|
||||||
sde_enc->phys_encs[sde_enc->num_phys_encs] = enc;
|
sde_enc->phys_vid_encs[sde_enc->num_phys_encs] = enc;
|
||||||
++sde_enc->num_phys_encs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (display_caps & MSM_DISPLAY_CAP_CMD_MODE) {
|
if (display_caps & MSM_DISPLAY_CAP_CMD_MODE) {
|
||||||
@@ -5155,11 +5202,18 @@ static int sde_encoder_virt_add_phys_encs(
|
|||||||
PTR_ERR(enc));
|
PTR_ERR(enc));
|
||||||
return !enc ? -EINVAL : PTR_ERR(enc);
|
return !enc ? -EINVAL : PTR_ERR(enc);
|
||||||
}
|
}
|
||||||
|
sde_enc->phys_cmd_encs[sde_enc->num_phys_encs] = enc;
|
||||||
sde_enc->phys_encs[sde_enc->num_phys_encs] = enc;
|
|
||||||
++sde_enc->num_phys_encs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (disp_info->curr_panel_mode == MSM_DISPLAY_VIDEO_MODE)
|
||||||
|
sde_enc->phys_encs[sde_enc->num_phys_encs] =
|
||||||
|
sde_enc->phys_vid_encs[sde_enc->num_phys_encs];
|
||||||
|
else
|
||||||
|
sde_enc->phys_encs[sde_enc->num_phys_encs] =
|
||||||
|
sde_enc->phys_cmd_encs[sde_enc->num_phys_encs];
|
||||||
|
|
||||||
|
++sde_enc->num_phys_encs;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5308,7 +5362,7 @@ static int sde_encoder_setup_display(struct sde_encoder_virt *sde_enc,
|
|||||||
&phys_params);
|
&phys_params);
|
||||||
else
|
else
|
||||||
ret = sde_encoder_virt_add_phys_encs(
|
ret = sde_encoder_virt_add_phys_encs(
|
||||||
disp_info->capabilities,
|
disp_info,
|
||||||
sde_enc,
|
sde_enc,
|
||||||
&phys_params);
|
&phys_params);
|
||||||
if (ret)
|
if (ret)
|
||||||
@@ -5318,12 +5372,19 @@ static int sde_encoder_setup_display(struct sde_encoder_virt *sde_enc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
||||||
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
|
struct sde_encoder_phys *vid_phys = sde_enc->phys_vid_encs[i];
|
||||||
|
struct sde_encoder_phys *cmd_phys = sde_enc->phys_cmd_encs[i];
|
||||||
|
|
||||||
if (phys) {
|
if (vid_phys) {
|
||||||
atomic_set(&phys->vsync_cnt, 0);
|
atomic_set(&vid_phys->vsync_cnt, 0);
|
||||||
atomic_set(&phys->underrun_cnt, 0);
|
atomic_set(&vid_phys->underrun_cnt, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cmd_phys) {
|
||||||
|
atomic_set(&cmd_phys->vsync_cnt, 0);
|
||||||
|
atomic_set(&cmd_phys->underrun_cnt, 0);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
mutex_unlock(&sde_enc->enc_lock);
|
mutex_unlock(&sde_enc->enc_lock);
|
||||||
|
|
||||||
@@ -5398,7 +5459,7 @@ struct drm_encoder *sde_encoder_init(
|
|||||||
sde_enc->rsc_client = NULL;
|
sde_enc->rsc_client = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) {
|
if (disp_info->curr_panel_mode == MSM_DISPLAY_CMD_MODE) {
|
||||||
ret = _sde_encoder_input_handler(sde_enc);
|
ret = _sde_encoder_input_handler(sde_enc);
|
||||||
if (ret)
|
if (ret)
|
||||||
SDE_ERROR(
|
SDE_ERROR(
|
||||||
|
@@ -201,12 +201,12 @@ void sde_encoder_virt_restore(struct drm_encoder *encoder);
|
|||||||
bool sde_encoder_is_dsc_merge(struct drm_encoder *drm_enc);
|
bool sde_encoder_is_dsc_merge(struct drm_encoder *drm_enc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sde_encoder_check_mode - check if given mode is supported or not
|
* sde_encoder_check_curr_mode - check if given mode is supported or not
|
||||||
* @drm_enc: Pointer to drm encoder object
|
* @drm_enc: Pointer to drm encoder object
|
||||||
* @mode: Mode to be checked
|
* @mode: Mode to be checked
|
||||||
* @Return: true if it is cmd mode
|
* @Return: true if it is cmd mode
|
||||||
*/
|
*/
|
||||||
bool sde_encoder_check_mode(struct drm_encoder *drm_enc, u32 mode);
|
bool sde_encoder_check_curr_mode(struct drm_encoder *drm_enc, u32 mode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sde_encoder_init - initialize virtual encoder object
|
* sde_encoder_init - initialize virtual encoder object
|
||||||
|
Reference in New Issue
Block a user