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:
@@ -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)
|
||||||
{
|
{
|
||||||
|
@@ -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
|
||||||
|
@@ -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");
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -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;
|
||||||
|
@@ -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 = {
|
||||||
|
Reference in New Issue
Block a user