disp: msm: restrict AVR_STEP based on panel requirement

Some panels require a fixed step rate for a particular mode.
This change allows DSI panels to specify a single supported
step rate for each nominal fps rate which SDE will enforce
during atomic check of AVR parameters.

Change-Id: I049415449bc88ccd396fced16d4534251eac3a06
Signed-off-by: Steve Cohen <cohens@codeaurora.org>
This commit is contained in:
Steve Cohen
2021-02-02 19:16:55 -05:00
parent cf86c94f8e
commit e5fa459062
9 changed files with 135 additions and 8 deletions

View File

@@ -6609,11 +6609,9 @@ int dsi_display_get_info(struct drm_connector *connector,
info->height_mm = phy_props.panel_height_mm; info->height_mm = phy_props.panel_height_mm;
info->max_width = 1920; info->max_width = 1920;
info->max_height = 1080; info->max_height = 1080;
info->qsync_min_fps = info->qsync_min_fps = display->panel->qsync_caps.qsync_min_fps;
display->panel->qsync_caps.qsync_min_fps; info->has_qsync_min_fps_list = (display->panel->qsync_caps.qsync_min_fps_list_len > 0);
info->has_qsync_min_fps_list = info->has_avr_step_req = (display->panel->avr_caps.avr_step_fps_list_len > 0);
(display->panel->qsync_caps.qsync_min_fps_list_len > 0) ?
true : false;
info->poms_align_vsync = display->panel->poms_align_vsync; info->poms_align_vsync = display->panel->poms_align_vsync;
switch (display->panel->panel_mode) { switch (display->panel->panel_mode) {
@@ -7080,6 +7078,31 @@ int dsi_display_get_qsync_min_fps(void *display_dsi, u32 mode_fps)
return -EINVAL; return -EINVAL;
} }
int dsi_display_get_avr_step_req_fps(void *display_dsi, u32 mode_fps)
{
struct dsi_display *display = (struct dsi_display *)display_dsi;
struct dsi_panel *panel;
u32 i, step = 0;
if (!display || !display->panel)
return -EINVAL;
panel = display->panel;
/* support a single fixed rate, or rate corresponding to dfps list entry */
if (panel->avr_caps.avr_step_fps_list_len == 1) {
step = panel->avr_caps.avr_step_fps_list[0];
} else if (panel->avr_caps.avr_step_fps_list_len > 1) {
for (i = 0; i < panel->dfps_caps.dfps_list_len; i++) {
if (panel->dfps_caps.dfps_list[i] == mode_fps)
step = panel->avr_caps.avr_step_fps_list[i];
}
}
DSI_DEBUG("mode_fps %u, avr_step fps %u\n", mode_fps, step);
return step;
}
static bool dsi_display_match_timings(const struct dsi_display_mode *mode1, static bool dsi_display_match_timings(const struct dsi_display_mode *mode1,
struct dsi_display_mode *mode2) struct dsi_display_mode *mode2)
{ {
@@ -7095,7 +7118,6 @@ static bool dsi_display_match_timings(const struct dsi_display_mode *mode1,
mode1->timing.refresh_rate == mode2->timing.refresh_rate; mode1->timing.refresh_rate == mode2->timing.refresh_rate;
} }
static bool dsi_display_mode_match(const struct dsi_display_mode *mode1, static bool dsi_display_mode_match(const struct dsi_display_mode *mode1,
struct dsi_display_mode *mode2, unsigned int match_flags) struct dsi_display_mode *mode2, unsigned int match_flags)
{ {

View File

@@ -419,10 +419,18 @@ int dsi_display_get_default_lms(void *dsi_display, u32 *num_lm);
* @display: Handle to display. * @display: Handle to display.
* @mode_fps: Fps value of current mode * @mode_fps: Fps value of current mode
* *
* Return: error code. * Return: Qsync min fps rate or -ve error code.
*/ */
int dsi_display_get_qsync_min_fps(void *dsi_display, u32 mode_fps); int dsi_display_get_qsync_min_fps(void *dsi_display, u32 mode_fps);
/**
* dsi_display_get_avr_step_req_fps() - get avr step rate for given fps
* @display: Handle to display.
* @mode_fps: Fps value of current mode
*
* Return: AVR step rate or -ve error code.
*/
int dsi_display_get_avr_step_req_fps(void *dsi_display, u32 mode_fps);
/** /**
* dsi_display_find_mode() - retrieve cached DSI mode given relevant params * dsi_display_find_mode() - retrieve cached DSI mode given relevant params

View File

@@ -626,6 +626,28 @@ static const struct drm_bridge_funcs dsi_bridge_ops = {
.mode_set = dsi_bridge_mode_set, .mode_set = dsi_bridge_mode_set,
}; };
int dsi_conn_set_avr_step_info(struct dsi_panel *panel, void *info)
{
u32 i;
int idx = 0;
size_t buff_sz = PAGE_SIZE;
char *buff;
buff = kzalloc(buff_sz, GFP_KERNEL);
if (!buff)
return -ENOMEM;
for (i = 0; i < panel->avr_caps.avr_step_fps_list_len && (idx < (buff_sz - 1)); i++)
idx += scnprintf(&buff[idx], buff_sz - idx, "%u@%u ",
panel->avr_caps.avr_step_fps_list[i],
panel->dfps_caps.dfps_list[i]);
sde_kms_info_add_keystr(info, "avr step requirement", buff);
kfree(buff);
return 0;
}
int dsi_conn_set_info_blob(struct drm_connector *connector, int dsi_conn_set_info_blob(struct drm_connector *connector,
void *info, void *display, struct msm_mode_info *mode_info) void *info, void *display, struct msm_mode_info *mode_info)
{ {
@@ -674,6 +696,8 @@ int dsi_conn_set_info_blob(struct drm_connector *connector,
switch (panel->panel_mode) { switch (panel->panel_mode) {
case DSI_OP_VIDEO_MODE: case DSI_OP_VIDEO_MODE:
sde_kms_info_add_keystr(info, "panel mode", "video"); sde_kms_info_add_keystr(info, "panel mode", "video");
if (panel->avr_caps.avr_step_fps_list_len)
dsi_conn_set_avr_step_info(panel, info);
break; break;
case DSI_OP_CMD_MODE: case DSI_OP_CMD_MODE:
sde_kms_info_add_keystr(info, "panel mode", "command"); sde_kms_info_add_keystr(info, "panel mode", "command");

View File

@@ -1239,6 +1239,38 @@ error:
return rc; return rc;
} }
static int dsi_panel_parse_avr_caps(struct dsi_panel *panel,
struct device_node *of_node)
{
struct dsi_avr_capabilities *avr_caps = &panel->avr_caps;
struct dsi_parser_utils *utils = &panel->utils;
int val, rc = 0;
val = utils->count_u32_elems(utils->data, "qcom,dsi-qsync-avr-step-list");
if (val <= 0) {
DSI_DEBUG("[%s] optional avr step list not defined, val:%d\n", panel->name, val);
return rc;
} else if (val > 1 && val != panel->dfps_caps.dfps_list_len) {
DSI_ERR("[%s] avr step list size %d not same as dfps list %d\n",
val, panel->dfps_caps.dfps_list_len);
return -EINVAL;
}
avr_caps->avr_step_fps_list = kcalloc(val, sizeof(u32), GFP_KERNEL);
if (!avr_caps->avr_step_fps_list)
return -ENOMEM;
rc = utils->read_u32_array(utils->data, "qcom,dsi-qsync-avr-step-list",
avr_caps->avr_step_fps_list, val);
if (rc) {
kfree(avr_caps->avr_step_fps_list);
return rc;
}
avr_caps->avr_step_fps_list_len = val;
return rc;
}
static int dsi_panel_parse_qsync_caps(struct dsi_panel *panel, static int dsi_panel_parse_qsync_caps(struct dsi_panel *panel,
struct device_node *of_node) struct device_node *of_node)
{ {
@@ -3509,6 +3541,10 @@ struct dsi_panel *dsi_panel_get(struct device *parent,
if (rc) if (rc)
DSI_DEBUG("failed to parse qsync features, rc=%d\n", rc); DSI_DEBUG("failed to parse qsync features, rc=%d\n", rc);
rc = dsi_panel_parse_avr_caps(panel, of_node);
if (rc)
DSI_ERR("failed to parse AVR features, rc=%d\n", rc);
rc = dsi_panel_parse_dyn_clk_caps(panel); rc = dsi_panel_parse_dyn_clk_caps(panel);
if (rc) if (rc)
DSI_ERR("failed to parse dynamic clk config, rc=%d\n", rc); DSI_ERR("failed to parse dynamic clk config, rc=%d\n", rc);
@@ -3594,6 +3630,7 @@ void dsi_panel_put(struct dsi_panel *panel)
/* free resources allocated for ESD check */ /* free resources allocated for ESD check */
dsi_panel_esd_config_deinit(&panel->esd_config); dsi_panel_esd_config_deinit(&panel->esd_config);
kfree(panel->avr_caps.avr_step_fps_list);
kfree(panel); kfree(panel);
} }

View File

@@ -95,6 +95,11 @@ struct dsi_qsync_capabilities {
int qsync_min_fps_list_len; int qsync_min_fps_list_len;
}; };
struct dsi_avr_capabilities {
u32 *avr_step_fps_list;
u32 avr_step_fps_list_len;
};
struct dsi_dyn_clk_caps { struct dsi_dyn_clk_caps {
bool dyn_clk_support; bool dyn_clk_support;
enum dsi_dyn_clk_feature_type type; enum dsi_dyn_clk_feature_type type;
@@ -247,6 +252,7 @@ struct dsi_panel {
bool panel_initialized; bool panel_initialized;
bool te_using_watchdog_timer; bool te_using_watchdog_timer;
struct dsi_qsync_capabilities qsync_caps; struct dsi_qsync_capabilities qsync_caps;
struct dsi_avr_capabilities avr_caps;
char dce_pps_cmd[DSI_CMD_PPS_SIZE]; char dce_pps_cmd[DSI_CMD_PPS_SIZE];
enum dsi_dms_mode dms_mode; enum dsi_dms_mode dms_mode;

View File

@@ -767,6 +767,7 @@ struct msm_resource_caps_info {
* @roi_caps: Region of interest capability info * @roi_caps: Region of interest capability info
* @qsync_min_fps Minimum fps supported by Qsync feature * @qsync_min_fps Minimum fps supported by Qsync feature
* @has_qsync_min_fps_list True if dsi-supported-qsync-min-fps-list exits * @has_qsync_min_fps_list True if dsi-supported-qsync-min-fps-list exits
* @has_avr_step_req Panel has defined requirement for AVR steps
* @te_source vsync source pin information * @te_source vsync source pin information
* @dsc_count: max dsc hw blocks used by display (only available * @dsc_count: max dsc hw blocks used by display (only available
* for dsi display) * for dsi display)
@@ -796,6 +797,7 @@ struct msm_display_info {
uint32_t qsync_min_fps; uint32_t qsync_min_fps;
bool has_qsync_min_fps_list; bool has_qsync_min_fps_list;
bool has_avr_step_req;
uint32_t te_source; uint32_t te_source;

View File

@@ -389,6 +389,14 @@ struct sde_connector_ops {
* Returns: Qsync min fps value on success * Returns: Qsync min fps value on success
*/ */
int (*get_qsync_min_fps)(void *display, u32 mode_fps); int (*get_qsync_min_fps)(void *display, u32 mode_fps);
/**
* get_avr_step_req - Get the required avr_step for given fps rate
* @display: Pointer to private display structure
* @mode_fps: Fps value in dfps list
* Returns: AVR step fps value on success
*/
int (*get_avr_step_req)(void *display, u32 mode_fps);
}; };
/** /**

View File

@@ -1042,9 +1042,28 @@ static void _sde_encoder_get_qsync_fps_callback(
static int _sde_encoder_avr_step_check(struct sde_connector *sde_conn, static int _sde_encoder_avr_step_check(struct sde_connector *sde_conn,
struct sde_connector_state *sde_conn_state, u32 step) struct sde_connector_state *sde_conn_state, u32 step)
{ {
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(sde_conn_state->base.best_encoder);
u32 nom_fps = drm_mode_vrefresh(sde_conn_state->msm_mode.base); u32 nom_fps = drm_mode_vrefresh(sde_conn_state->msm_mode.base);
u32 min_fps; u32 min_fps, req_fps = 0;
u32 vtotal = sde_conn_state->msm_mode.base->vtotal; u32 vtotal = sde_conn_state->msm_mode.base->vtotal;
bool has_panel_req = sde_enc->disp_info.has_avr_step_req;
u32 qsync_mode = sde_connector_get_property(&sde_conn_state->base,
CONNECTOR_PROP_QSYNC_MODE);
if (has_panel_req) {
if (!sde_conn->ops.get_avr_step_req) {
SDE_ERROR("unable to retrieve required step rate\n");
return -EINVAL;
}
req_fps = sde_conn->ops.get_avr_step_req(sde_conn->display, nom_fps);
/* when qsync is enabled, the step fps *must* be set to the panel requirement */
if (qsync_mode && req_fps != step) {
SDE_ERROR("invalid avr_step %u, panel requires %u at nominal %u fps\n",
step, req_fps, nom_fps);
return -EINVAL;
}
}
if (!step) if (!step)
return 0; return 0;

View File

@@ -1748,6 +1748,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
.set_allowed_mode_switch = dsi_conn_set_allowed_mode_switch, .set_allowed_mode_switch = dsi_conn_set_allowed_mode_switch,
.set_dyn_bit_clk = dsi_conn_set_dyn_bit_clk, .set_dyn_bit_clk = dsi_conn_set_dyn_bit_clk,
.get_qsync_min_fps = dsi_display_get_qsync_min_fps, .get_qsync_min_fps = dsi_display_get_qsync_min_fps,
.get_avr_step_req = dsi_display_get_avr_step_req_fps,
.prepare_commit = dsi_conn_prepare_commit, .prepare_commit = dsi_conn_prepare_commit,
}; };
static const struct sde_connector_ops wb_ops = { static const struct sde_connector_ops wb_ops = {