Merge "disp: msm: sde: add multi-mode RFI support"
This commit is contained in:

committed by
Gerrit - the friendly Code Review server

commit
7d1ca7c295
@@ -587,6 +587,16 @@ struct dsi_host_config {
|
|||||||
struct dsi_lane_map lane_map;
|
struct dsi_lane_map lane_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct dyn_clk_list - list of dynamic clock rates.
|
||||||
|
* @rates: list of supported clock rates
|
||||||
|
* @count: number of supported clock rates
|
||||||
|
*/
|
||||||
|
struct dyn_clk_list {
|
||||||
|
u32 *rates;
|
||||||
|
u32 count;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct dsi_display_mode_priv_info - private mode info that will be attached
|
* struct dsi_display_mode_priv_info - private mode info that will be attached
|
||||||
* with each drm mode
|
* with each drm mode
|
||||||
@@ -600,6 +610,7 @@ struct dsi_host_config {
|
|||||||
* @dsi_transfer_time_us: Specifies the dsi transfer time for cmd panels.
|
* @dsi_transfer_time_us: Specifies the dsi transfer time for cmd panels.
|
||||||
* @clk_rate_hz: DSI bit clock per lane in hz.
|
* @clk_rate_hz: DSI bit clock per lane in hz.
|
||||||
* @min_dsi_clk_hz: Min dsi clk per lane to transfer frame in vsync time.
|
* @min_dsi_clk_hz: Min dsi clk per lane to transfer frame in vsync time.
|
||||||
|
* @bit_clk_list: List of dynamic bit clock rates supported.
|
||||||
* @topology: Topology selected for the panel
|
* @topology: Topology selected for the panel
|
||||||
* @dsc: DSC compression info
|
* @dsc: DSC compression info
|
||||||
* @vdc: VDC compression info
|
* @vdc: VDC compression info
|
||||||
@@ -623,6 +634,7 @@ struct dsi_display_mode_priv_info {
|
|||||||
u32 dsi_transfer_time_us;
|
u32 dsi_transfer_time_us;
|
||||||
u64 clk_rate_hz;
|
u64 clk_rate_hz;
|
||||||
u64 min_dsi_clk_hz;
|
u64 min_dsi_clk_hz;
|
||||||
|
struct dyn_clk_list bit_clk_list;
|
||||||
|
|
||||||
struct msm_display_topology topology;
|
struct msm_display_topology topology;
|
||||||
struct msm_display_dsc_info dsc;
|
struct msm_display_dsc_info dsc;
|
||||||
|
@@ -6678,12 +6678,11 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display,
|
|||||||
src = &display->modes[i];
|
src = &display->modes[i];
|
||||||
if (!src)
|
if (!src)
|
||||||
return;
|
return;
|
||||||
/*
|
|
||||||
* TODO: currently setting the first bit rate in
|
if (!src->priv_info->bit_clk_list.count)
|
||||||
* the list as preferred rate. But ideally should
|
continue;
|
||||||
* be based on user or device tree preferrence.
|
|
||||||
*/
|
src->timing.clk_rate_hz = src->priv_info->bit_clk_list.rates[0];
|
||||||
src->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[0];
|
|
||||||
|
|
||||||
dsi_display_adjust_mode_timing(display, src, lanes, bpp);
|
dsi_display_adjust_mode_timing(display, src, lanes, bpp);
|
||||||
|
|
||||||
@@ -6726,6 +6725,37 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int dsi_display_restore_bit_clk(struct dsi_display *display, struct dsi_display_mode *mode)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
u32 clk_rate_hz = 0;
|
||||||
|
|
||||||
|
if (!display || !mode || !mode->priv_info) {
|
||||||
|
DSI_ERR("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
clk_rate_hz = display->cached_clk_rate;
|
||||||
|
|
||||||
|
if (mode->priv_info->bit_clk_list.count) {
|
||||||
|
/* use first entry as the default bit clk rate */
|
||||||
|
clk_rate_hz = mode->priv_info->bit_clk_list.rates[0];
|
||||||
|
|
||||||
|
for (i = 0; i < mode->priv_info->bit_clk_list.count; i++) {
|
||||||
|
if (display->dyn_bit_clk == mode->priv_info->bit_clk_list.rates[i])
|
||||||
|
clk_rate_hz = display->dyn_bit_clk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mode->timing.clk_rate_hz = clk_rate_hz;
|
||||||
|
mode->priv_info->clk_rate_hz = clk_rate_hz;
|
||||||
|
|
||||||
|
SDE_EVT32(clk_rate_hz, display->cached_clk_rate, display->dyn_bit_clk);
|
||||||
|
DSI_DEBUG("clk_rate_hz:%u, cached_clk_rate:%u, dyn_bit_clk:%u\n",
|
||||||
|
clk_rate_hz, display->cached_clk_rate, display->dyn_bit_clk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void dsi_display_put_mode(struct dsi_display *display,
|
void dsi_display_put_mode(struct dsi_display *display,
|
||||||
struct dsi_display_mode *mode)
|
struct dsi_display_mode *mode)
|
||||||
{
|
{
|
||||||
@@ -7237,9 +7267,11 @@ int dsi_display_set_mode(struct dsi_display *display,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*For dynamic DSI setting, use specified clock rate */
|
rc = dsi_display_restore_bit_clk(display, &adj_mode);
|
||||||
if (display->cached_clk_rate > 0)
|
if (rc) {
|
||||||
adj_mode.priv_info->clk_rate_hz = display->cached_clk_rate;
|
DSI_ERR("[%s] bit clk rate cannot be restored\n", display->name);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
rc = dsi_display_validate_mode_set(display, &adj_mode, flags);
|
rc = dsi_display_validate_mode_set(display, &adj_mode, flags);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
@@ -7253,11 +7285,13 @@ int dsi_display_set_mode(struct dsi_display *display,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
DSI_INFO("mdp_transfer_time=%d, hactive=%d, vactive=%d, fps=%d\n",
|
DSI_INFO("mdp_transfer_time=%d, hactive=%d, vactive=%d, fps=%d, clk_rate=%llu\n",
|
||||||
adj_mode.priv_info->mdp_transfer_time_us,
|
adj_mode.priv_info->mdp_transfer_time_us,
|
||||||
timing.h_active, timing.v_active, timing.refresh_rate);
|
timing.h_active, timing.v_active, timing.refresh_rate,
|
||||||
|
adj_mode.priv_info->clk_rate_hz);
|
||||||
SDE_EVT32(adj_mode.priv_info->mdp_transfer_time_us,
|
SDE_EVT32(adj_mode.priv_info->mdp_transfer_time_us,
|
||||||
timing.h_active, timing.v_active, timing.refresh_rate);
|
timing.h_active, timing.v_active, timing.refresh_rate,
|
||||||
|
adj_mode.priv_info->clk_rate_hz);
|
||||||
|
|
||||||
memcpy(display->panel->cur_mode, &adj_mode, sizeof(adj_mode));
|
memcpy(display->panel->cur_mode, &adj_mode, sizeof(adj_mode));
|
||||||
error:
|
error:
|
||||||
@@ -8366,6 +8400,67 @@ int dsi_display_update_pps(char *pps_cmd, void *disp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int dsi_display_update_dyn_bit_clk(struct dsi_display *display,
|
||||||
|
struct dsi_display_mode *mode)
|
||||||
|
{
|
||||||
|
struct dsi_dyn_clk_caps *dyn_clk_caps;
|
||||||
|
struct dsi_host_common_cfg *host_cfg;
|
||||||
|
int bpp, lanes = 0;
|
||||||
|
|
||||||
|
if (!display || !mode) {
|
||||||
|
DSI_ERR("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dyn_clk_caps = &(display->panel->dyn_clk_caps);
|
||||||
|
if (!dyn_clk_caps->dyn_clk_support) {
|
||||||
|
DSI_DEBUG("dynamic bit clock support not enabled\n");
|
||||||
|
return 0;
|
||||||
|
} else if (!display->dyn_bit_clk_pending) {
|
||||||
|
DSI_DEBUG("dynamic bit clock rate not updated\n");
|
||||||
|
return 0;
|
||||||
|
} else if (!display->dyn_bit_clk) {
|
||||||
|
DSI_DEBUG("dynamic bit clock rate cleared\n");
|
||||||
|
return 0;
|
||||||
|
} else if (display->dyn_bit_clk < mode->priv_info->min_dsi_clk_hz) {
|
||||||
|
DSI_ERR("dynamic bit clock rate %llu smaller than minimum value:%llu\n",
|
||||||
|
display->dyn_bit_clk, mode->priv_info->min_dsi_clk_hz);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update mode clk rate with user value */
|
||||||
|
mode->timing.clk_rate_hz = display->dyn_bit_clk;
|
||||||
|
mode->priv_info->clk_rate_hz = display->dyn_bit_clk;
|
||||||
|
|
||||||
|
host_cfg = &(display->panel->host_config);
|
||||||
|
bpp = dsi_pixel_format_to_bpp(host_cfg->dst_format);
|
||||||
|
|
||||||
|
if (host_cfg->data_lanes & DSI_DATA_LANE_0)
|
||||||
|
lanes++;
|
||||||
|
if (host_cfg->data_lanes & DSI_DATA_LANE_1)
|
||||||
|
lanes++;
|
||||||
|
if (host_cfg->data_lanes & DSI_DATA_LANE_2)
|
||||||
|
lanes++;
|
||||||
|
if (host_cfg->data_lanes & DSI_DATA_LANE_3)
|
||||||
|
lanes++;
|
||||||
|
|
||||||
|
dsi_display_adjust_mode_timing(display, mode, lanes, bpp);
|
||||||
|
|
||||||
|
/* adjust pixel clock based on dynamic bit clock */
|
||||||
|
mode->pixel_clk_khz = div_u64(mode->timing.clk_rate_hz * lanes, bpp);
|
||||||
|
do_div(mode->pixel_clk_khz, 1000);
|
||||||
|
mode->pixel_clk_khz *= display->ctrl_count;
|
||||||
|
|
||||||
|
SDE_EVT32(display->dyn_bit_clk, mode->priv_info->min_dsi_clk_hz, mode->pixel_clk_khz);
|
||||||
|
DSI_DEBUG("dynamic bit clk:%u, min dsi clk:%llu, lanes:%d, bpp:%d, pck:%d Khz\n",
|
||||||
|
display->dyn_bit_clk, mode->priv_info->min_dsi_clk_hz, lanes, bpp,
|
||||||
|
mode->pixel_clk_khz);
|
||||||
|
|
||||||
|
display->dyn_bit_clk_pending = false;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int dsi_display_dump_clks_state(struct dsi_display *display)
|
int dsi_display_dump_clks_state(struct dsi_display *display)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
@@ -154,6 +154,8 @@ struct dsi_display_ext_bridge {
|
|||||||
* index into the ctrl[MAX_DSI_CTRLS_PER_DISPLAY] array.
|
* index into the ctrl[MAX_DSI_CTRLS_PER_DISPLAY] array.
|
||||||
* @cmd_master_idx: The master controller for sending DSI commands to panel.
|
* @cmd_master_idx: The master controller for sending DSI commands to panel.
|
||||||
* @video_master_idx: The master controller for enabling video engine.
|
* @video_master_idx: The master controller for enabling video engine.
|
||||||
|
* @dyn_bit_clk: The DSI bit clock rate dynamically set by user mode client.
|
||||||
|
* @dyn_bit_clk_pending: Flag indicating the pending DSI dynamic bit clock rate change.
|
||||||
* @cached_clk_rate: The cached DSI clock rate set dynamically by sysfs.
|
* @cached_clk_rate: The cached DSI clock rate set dynamically by sysfs.
|
||||||
* @clkrate_change_pending: Flag indicating the pending DSI clock re-enabling.
|
* @clkrate_change_pending: Flag indicating the pending DSI clock re-enabling.
|
||||||
* @clock_info: Clock sourcing for DSI display.
|
* @clock_info: Clock sourcing for DSI display.
|
||||||
@@ -225,7 +227,9 @@ struct dsi_display {
|
|||||||
u32 video_master_idx;
|
u32 video_master_idx;
|
||||||
|
|
||||||
/* dynamic DSI clock info*/
|
/* dynamic DSI clock info*/
|
||||||
u32 cached_clk_rate;
|
u32 dyn_bit_clk;
|
||||||
|
bool dyn_bit_clk_pending;
|
||||||
|
u32 cached_clk_rate;
|
||||||
atomic_t clkrate_change_pending;
|
atomic_t clkrate_change_pending;
|
||||||
|
|
||||||
struct dsi_display_clk_info clock_info;
|
struct dsi_display_clk_info clock_info;
|
||||||
@@ -776,4 +780,21 @@ int dsi_display_get_panel_vfp(void *display,
|
|||||||
*/
|
*/
|
||||||
int dsi_display_dump_clks_state(struct dsi_display *display);
|
int dsi_display_dump_clks_state(struct dsi_display *display);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dsi_display_update_dyn_bit_clk() - update mode timing to compensate for dynamic bit clock
|
||||||
|
* @display: Handle to display
|
||||||
|
* @mode: Mode to be updated
|
||||||
|
* Return: Zero on Success
|
||||||
|
*/
|
||||||
|
int dsi_display_update_dyn_bit_clk(struct dsi_display *display, struct dsi_display_mode *mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dsi_display_restore_bit_clk() - restore mode bit clock rate value from dynamic bit clock
|
||||||
|
* @display: Handle to display
|
||||||
|
* @mode: Mode to be updated
|
||||||
|
* Return: Zero on Success
|
||||||
|
*/
|
||||||
|
int dsi_display_restore_bit_clk(struct dsi_display *display, struct dsi_display_mode *mode);
|
||||||
|
|
||||||
|
|
||||||
#endif /* _DSI_DISPLAY_H_ */
|
#endif /* _DSI_DISPLAY_H_ */
|
||||||
|
@@ -342,7 +342,9 @@ static void dsi_bridge_mode_set(struct drm_bridge *bridge,
|
|||||||
const struct drm_display_mode *mode,
|
const struct drm_display_mode *mode,
|
||||||
const struct drm_display_mode *adjusted_mode)
|
const struct drm_display_mode *adjusted_mode)
|
||||||
{
|
{
|
||||||
struct dsi_bridge *c_bridge = to_dsi_bridge(bridge);
|
int rc = 0;
|
||||||
|
struct dsi_bridge *c_bridge = NULL;
|
||||||
|
struct dsi_display *display;
|
||||||
struct drm_connector *conn;
|
struct drm_connector *conn;
|
||||||
struct sde_connector_state *conn_state;
|
struct sde_connector_state *conn_state;
|
||||||
|
|
||||||
@@ -351,6 +353,18 @@ static void dsi_bridge_mode_set(struct drm_bridge *bridge,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c_bridge = to_dsi_bridge(bridge);
|
||||||
|
if (!c_bridge) {
|
||||||
|
DSI_ERR("invalid dsi bridge\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
display = c_bridge->display;
|
||||||
|
if (!display || !display->drm_conn || !display->drm_conn->state) {
|
||||||
|
DSI_ERR("invalid display\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
memset(&(c_bridge->dsi_mode), 0x0, sizeof(struct dsi_display_mode));
|
memset(&(c_bridge->dsi_mode), 0x0, sizeof(struct dsi_display_mode));
|
||||||
convert_to_dsi_mode(adjusted_mode, &(c_bridge->dsi_mode));
|
convert_to_dsi_mode(adjusted_mode, &(c_bridge->dsi_mode));
|
||||||
conn = sde_encoder_get_connector(bridge->dev, bridge->encoder);
|
conn = sde_encoder_get_connector(bridge->dev, bridge->encoder);
|
||||||
@@ -366,9 +380,11 @@ static void dsi_bridge_mode_set(struct drm_bridge *bridge,
|
|||||||
msm_parse_mode_priv_info(&conn_state->msm_mode,
|
msm_parse_mode_priv_info(&conn_state->msm_mode,
|
||||||
&(c_bridge->dsi_mode));
|
&(c_bridge->dsi_mode));
|
||||||
|
|
||||||
/* restore bit_clk_rate also for dynamic clk use cases */
|
rc = dsi_display_restore_bit_clk(display, &c_bridge->dsi_mode);
|
||||||
c_bridge->dsi_mode.timing.clk_rate_hz =
|
if (rc) {
|
||||||
dsi_drm_find_bit_clk_rate(c_bridge->display, adjusted_mode);
|
DSI_ERR("[%s] bit clk rate cannot be restored\n", display->name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
DSI_DEBUG("clk_rate: %llu\n", c_bridge->dsi_mode.timing.clk_rate_hz);
|
DSI_DEBUG("clk_rate: %llu\n", c_bridge->dsi_mode.timing.clk_rate_hz);
|
||||||
}
|
}
|
||||||
@@ -436,6 +452,18 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
|
|||||||
dsi_mode.timing.dsc_enabled = dsi_mode.priv_info->dsc_enabled;
|
dsi_mode.timing.dsc_enabled = dsi_mode.priv_info->dsc_enabled;
|
||||||
dsi_mode.timing.dsc = &dsi_mode.priv_info->dsc;
|
dsi_mode.timing.dsc = &dsi_mode.priv_info->dsc;
|
||||||
|
|
||||||
|
rc = dsi_display_restore_bit_clk(display, &dsi_mode);
|
||||||
|
if (rc) {
|
||||||
|
DSI_ERR("[%s] bit clk rate cannot be restored\n", display->name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = dsi_display_update_dyn_bit_clk(display, &dsi_mode);
|
||||||
|
if (rc) {
|
||||||
|
DSI_ERR("[%s] failed to update bit clock\n", display->name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
rc = dsi_display_validate_mode(c_bridge->display, &dsi_mode,
|
rc = dsi_display_validate_mode(c_bridge->display, &dsi_mode,
|
||||||
DSI_VALIDATE_FLAG_ALLOW_ADJUST);
|
DSI_VALIDATE_FLAG_ALLOW_ADJUST);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
@@ -517,33 +545,6 @@ u32 dsi_drm_get_dfps_maxfps(void *display)
|
|||||||
return dfps_maxfps;
|
return dfps_maxfps;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 dsi_drm_find_bit_clk_rate(void *display,
|
|
||||||
const struct drm_display_mode *drm_mode)
|
|
||||||
{
|
|
||||||
int i = 0, count = 0;
|
|
||||||
struct dsi_display *dsi_display = display;
|
|
||||||
struct dsi_display_mode *dsi_mode;
|
|
||||||
u64 bit_clk_rate = 0;
|
|
||||||
|
|
||||||
if (!dsi_display || !drm_mode)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
dsi_display_get_mode_count(dsi_display, &count);
|
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
dsi_mode = &dsi_display->modes[i];
|
|
||||||
if ((dsi_mode->timing.v_active == drm_mode->vdisplay) &&
|
|
||||||
(dsi_mode->timing.h_active == drm_mode->hdisplay) &&
|
|
||||||
(dsi_mode->pixel_clk_khz == drm_mode->clock) &&
|
|
||||||
(dsi_mode->timing.refresh_rate == drm_mode_vrefresh(drm_mode))) {
|
|
||||||
bit_clk_rate = dsi_mode->timing.clk_rate_hz;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bit_clk_rate;
|
|
||||||
}
|
|
||||||
|
|
||||||
int dsi_conn_get_mode_info(struct drm_connector *connector,
|
int dsi_conn_get_mode_info(struct drm_connector *connector,
|
||||||
const struct drm_display_mode *drm_mode,
|
const struct drm_display_mode *drm_mode,
|
||||||
struct msm_mode_info *mode_info,
|
struct msm_mode_info *mode_info,
|
||||||
@@ -578,6 +579,13 @@ int dsi_conn_get_mode_info(struct drm_connector *connector,
|
|||||||
memcpy(&mode_info->topology, &dsi_mode->priv_info->topology,
|
memcpy(&mode_info->topology, &dsi_mode->priv_info->topology,
|
||||||
sizeof(struct msm_display_topology));
|
sizeof(struct msm_display_topology));
|
||||||
|
|
||||||
|
if (dsi_mode->priv_info->bit_clk_list.count) {
|
||||||
|
mode_info->bit_clk_rates =
|
||||||
|
dsi_mode->priv_info->bit_clk_list.rates;
|
||||||
|
mode_info->bit_clk_count =
|
||||||
|
dsi_mode->priv_info->bit_clk_list.count;
|
||||||
|
}
|
||||||
|
|
||||||
if (dsi_mode->priv_info->dsc_enabled) {
|
if (dsi_mode->priv_info->dsc_enabled) {
|
||||||
mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_DSC;
|
mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_DSC;
|
||||||
mode_info->topology.comp_type = MSM_DISPLAY_COMPRESSION_DSC;
|
mode_info->topology.comp_type = MSM_DISPLAY_COMPRESSION_DSC;
|
||||||
@@ -1296,3 +1304,25 @@ void dsi_conn_set_allowed_mode_switch(struct drm_connector *connector,
|
|||||||
mode_idx++;
|
mode_idx++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int dsi_conn_set_dyn_bit_clk(struct drm_connector *connector, uint64_t value)
|
||||||
|
{
|
||||||
|
struct sde_connector *c_conn = NULL;
|
||||||
|
struct dsi_display *display;
|
||||||
|
|
||||||
|
if (!connector) {
|
||||||
|
DSI_ERR("invalid connector\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
c_conn = to_sde_connector(connector);
|
||||||
|
display = (struct dsi_display *) c_conn->display;
|
||||||
|
|
||||||
|
display->dyn_bit_clk = value;
|
||||||
|
display->dyn_bit_clk_pending = true;
|
||||||
|
|
||||||
|
SDE_EVT32(display->dyn_bit_clk);
|
||||||
|
DSI_DEBUG("update dynamic bit clock rate to %llu\n", display->dyn_bit_clk);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _DSI_DRM_H_
|
#ifndef _DSI_DRM_H_
|
||||||
@@ -134,9 +134,6 @@ int dsi_conn_post_kickoff(struct drm_connector *connector,
|
|||||||
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,
|
||||||
struct drm_display_mode *drm_mode);
|
struct drm_display_mode *drm_mode);
|
||||||
|
|
||||||
u64 dsi_drm_find_bit_clk_rate(void *display,
|
|
||||||
const struct drm_display_mode *drm_mode);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dsi_conn_prepare_commit - program pre commit time features
|
* dsi_conn_prepare_commit - program pre commit time features
|
||||||
* @display: Pointer to private display structure
|
* @display: Pointer to private display structure
|
||||||
@@ -154,4 +151,13 @@ int dsi_conn_prepare_commit(void *display,
|
|||||||
void dsi_conn_set_allowed_mode_switch(struct drm_connector *connector,
|
void dsi_conn_set_allowed_mode_switch(struct drm_connector *connector,
|
||||||
void *display);
|
void *display);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dsi_conn_set_dyn_bit_clk - set target dynamic clock rate
|
||||||
|
* @connector: Pointer to drm connector structure
|
||||||
|
* @value: Target dynamic clock rate
|
||||||
|
* Returns: Zero on success
|
||||||
|
*/
|
||||||
|
int dsi_conn_set_dyn_bit_clk(struct drm_connector *connector,
|
||||||
|
uint64_t value);
|
||||||
|
|
||||||
#endif /* _DSI_DRM_H_ */
|
#endif /* _DSI_DRM_H_ */
|
||||||
|
@@ -1326,13 +1326,48 @@ error:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dsi_panel_parse_dyn_clk_list(struct dsi_display_mode *mode,
|
||||||
|
struct dsi_parser_utils *utils)
|
||||||
|
{
|
||||||
|
int i, rc = 0;
|
||||||
|
struct dyn_clk_list *bit_clk_list;
|
||||||
|
|
||||||
|
if (!mode || !mode->priv_info) {
|
||||||
|
DSI_ERR("invalid arguments\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bit_clk_list = &mode->priv_info->bit_clk_list;
|
||||||
|
|
||||||
|
bit_clk_list->count = utils->count_u32_elems(utils->data, "qcom,dsi-dyn-clk-list");
|
||||||
|
if (bit_clk_list->count < 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
bit_clk_list->rates = kcalloc(bit_clk_list->count, sizeof(u32), GFP_KERNEL);
|
||||||
|
if (!bit_clk_list->rates) {
|
||||||
|
DSI_ERR("failed to allocate space for bit clock list\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = utils->read_u32_array(utils->data, "qcom,dsi-dyn-clk-list",
|
||||||
|
bit_clk_list->rates, bit_clk_list->count);
|
||||||
|
if (rc) {
|
||||||
|
DSI_ERR("failed to parse supported bit clk list, rc=%d\n", rc);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < bit_clk_list->count; i++)
|
||||||
|
DSI_DEBUG("bit clk rate[%d]:%d\n", i, bit_clk_list->rates[i]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel)
|
static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
bool supported = false;
|
bool supported = false;
|
||||||
struct dsi_dyn_clk_caps *dyn_clk_caps = &panel->dyn_clk_caps;
|
struct dsi_dyn_clk_caps *dyn_clk_caps = &panel->dyn_clk_caps;
|
||||||
struct dsi_parser_utils *utils = &panel->utils;
|
struct dsi_parser_utils *utils = &panel->utils;
|
||||||
const char *name = panel->name;
|
|
||||||
const char *type;
|
const char *type;
|
||||||
|
|
||||||
supported = utils->read_bool(utils->data, "qcom,dsi-dyn-clk-enable");
|
supported = utils->read_bool(utils->data, "qcom,dsi-dyn-clk-enable");
|
||||||
@@ -1342,28 +1377,6 @@ static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
dyn_clk_caps->bit_clk_list_len = utils->count_u32_elems(utils->data,
|
|
||||||
"qcom,dsi-dyn-clk-list");
|
|
||||||
|
|
||||||
if (dyn_clk_caps->bit_clk_list_len < 1) {
|
|
||||||
DSI_ERR("[%s] failed to get supported bit clk list\n", name);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
dyn_clk_caps->bit_clk_list = kcalloc(dyn_clk_caps->bit_clk_list_len,
|
|
||||||
sizeof(u32), GFP_KERNEL);
|
|
||||||
if (!dyn_clk_caps->bit_clk_list)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
rc = utils->read_u32_array(utils->data, "qcom,dsi-dyn-clk-list",
|
|
||||||
dyn_clk_caps->bit_clk_list,
|
|
||||||
dyn_clk_caps->bit_clk_list_len);
|
|
||||||
|
|
||||||
if (rc) {
|
|
||||||
DSI_ERR("[%s] failed to parse supported bit clk list\n", name);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
dyn_clk_caps->dyn_clk_support = true;
|
dyn_clk_caps->dyn_clk_support = true;
|
||||||
|
|
||||||
type = utils->get_property(utils->data,
|
type = utils->get_property(utils->data,
|
||||||
@@ -4032,6 +4045,12 @@ int dsi_panel_get_mode(struct dsi_panel *panel,
|
|||||||
goto parse_fail;
|
goto parse_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (panel->dyn_clk_caps.dyn_clk_support) {
|
||||||
|
rc = dsi_panel_parse_dyn_clk_list(mode, utils);
|
||||||
|
if (rc)
|
||||||
|
DSI_ERR("failed to parse dynamic clk rates, rc=%d\n", rc);
|
||||||
|
}
|
||||||
|
|
||||||
rc = dsi_panel_parse_dsc_params(mode, utils);
|
rc = dsi_panel_parse_dsc_params(mode, utils);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
DSI_ERR("failed to parse dsc params, rc=%d\n", rc);
|
DSI_ERR("failed to parse dsc params, rc=%d\n", rc);
|
||||||
|
@@ -97,8 +97,6 @@ struct dsi_qsync_capabilities {
|
|||||||
|
|
||||||
struct dsi_dyn_clk_caps {
|
struct dsi_dyn_clk_caps {
|
||||||
bool dyn_clk_support;
|
bool dyn_clk_support;
|
||||||
u32 *bit_clk_list;
|
|
||||||
u32 bit_clk_list_len;
|
|
||||||
enum dsi_dyn_clk_feature_type type;
|
enum dsi_dyn_clk_feature_type type;
|
||||||
bool maintain_const_fps;
|
bool maintain_const_fps;
|
||||||
};
|
};
|
||||||
|
@@ -211,6 +211,7 @@ enum msm_mdp_conn_property {
|
|||||||
CONNECTOR_PROP_BL_SCALE,
|
CONNECTOR_PROP_BL_SCALE,
|
||||||
CONNECTOR_PROP_SV_BL_SCALE,
|
CONNECTOR_PROP_SV_BL_SCALE,
|
||||||
CONNECTOR_PROP_SUPPORTED_COLORSPACES,
|
CONNECTOR_PROP_SUPPORTED_COLORSPACES,
|
||||||
|
CONNECTOR_PROP_DYN_BIT_CLK,
|
||||||
|
|
||||||
/* enum/bitmask properties */
|
/* enum/bitmask properties */
|
||||||
CONNECTOR_PROP_TOPOLOGY_NAME,
|
CONNECTOR_PROP_TOPOLOGY_NAME,
|
||||||
@@ -702,6 +703,8 @@ struct msm_display_topology {
|
|||||||
* @mdp_transfer_time_us Specifies the mdp transfer time for command mode
|
* @mdp_transfer_time_us Specifies the mdp transfer time for command mode
|
||||||
* panels in microseconds.
|
* panels in microseconds.
|
||||||
* @allowed_mode_switches: bit mask to indicate supported mode switch.
|
* @allowed_mode_switches: bit mask to indicate supported mode switch.
|
||||||
|
* @bit_clk_rates: list of supported bit clock rates
|
||||||
|
* @bit_clk_count: number of supported bit clock rates
|
||||||
*/
|
*/
|
||||||
struct msm_mode_info {
|
struct msm_mode_info {
|
||||||
uint32_t frame_rate;
|
uint32_t frame_rate;
|
||||||
@@ -718,6 +721,8 @@ struct msm_mode_info {
|
|||||||
u32 panel_mode_caps;
|
u32 panel_mode_caps;
|
||||||
u32 mdp_transfer_time_us;
|
u32 mdp_transfer_time_us;
|
||||||
u32 allowed_mode_switches;
|
u32 allowed_mode_switches;
|
||||||
|
u32 *bit_clk_rates;
|
||||||
|
u32 bit_clk_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -292,6 +292,9 @@ static inline bool msm_is_private_mode_changed(
|
|||||||
if (msm_is_mode_seamless_poms(msm_mode))
|
if (msm_is_mode_seamless_poms(msm_mode))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (msm_is_mode_seamless_dyn_clk(msm_mode))
|
||||||
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1595,6 +1595,15 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector,
|
|||||||
c_conn->expected_panel_mode =
|
c_conn->expected_panel_mode =
|
||||||
MSM_DISPLAY_CMD_MODE;
|
MSM_DISPLAY_CMD_MODE;
|
||||||
break;
|
break;
|
||||||
|
case CONNECTOR_PROP_DYN_BIT_CLK:
|
||||||
|
if (!c_conn->ops.set_dyn_bit_clk)
|
||||||
|
break;
|
||||||
|
|
||||||
|
rc = c_conn->ops.set_dyn_bit_clk(connector, val);
|
||||||
|
if (rc)
|
||||||
|
SDE_ERROR_CONN(c_conn, "dynamic bit clock set failed, rc: %d", rc);
|
||||||
|
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2614,6 +2623,12 @@ static int sde_connector_populate_mode_info(struct drm_connector *conn,
|
|||||||
sde_kms_info_add_keyint(info, "bit_clk_rate",
|
sde_kms_info_add_keyint(info, "bit_clk_rate",
|
||||||
mode_info.clk_rate);
|
mode_info.clk_rate);
|
||||||
|
|
||||||
|
if (mode_info.bit_clk_count > 0)
|
||||||
|
sde_kms_info_add_list(info, "dyn_bitclk_list",
|
||||||
|
mode_info.bit_clk_rates,
|
||||||
|
mode_info.bit_clk_count);
|
||||||
|
|
||||||
|
|
||||||
topology_idx = (int)sde_rm_get_topology_name(&sde_kms->rm,
|
topology_idx = (int)sde_rm_get_topology_name(&sde_kms->rm,
|
||||||
mode_info.topology);
|
mode_info.topology);
|
||||||
if (topology_idx < SDE_RM_TOPOLOGY_MAX) {
|
if (topology_idx < SDE_RM_TOPOLOGY_MAX) {
|
||||||
@@ -2788,6 +2803,12 @@ static int _sde_connector_install_properties(struct drm_device *dev,
|
|||||||
CONNECTOR_PROP_HDR_INFO);
|
CONNECTOR_PROP_HDR_INFO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dsi_display && dsi_display->panel &&
|
||||||
|
dsi_display->panel->dyn_clk_caps.dyn_clk_support)
|
||||||
|
msm_property_install_range(&c_conn->property_info, "dyn_bit_clk",
|
||||||
|
0x0, 0, ~0, 0, CONNECTOR_PROP_DYN_BIT_CLK);
|
||||||
|
|
||||||
|
|
||||||
mutex_lock(&c_conn->base.dev->mode_config.mutex);
|
mutex_lock(&c_conn->base.dev->mode_config.mutex);
|
||||||
sde_connector_fill_modes(&c_conn->base,
|
sde_connector_fill_modes(&c_conn->base,
|
||||||
dev->mode_config.max_width,
|
dev->mode_config.max_width,
|
||||||
|
@@ -374,6 +374,14 @@ struct sde_connector_ops {
|
|||||||
void (*set_allowed_mode_switch)(struct drm_connector *connector,
|
void (*set_allowed_mode_switch)(struct drm_connector *connector,
|
||||||
void *display);
|
void *display);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set_dyn_bit_clk - set target dynamic clock rate
|
||||||
|
* @connector: Pointer to drm connector structure
|
||||||
|
* @value: Target dynamic clock rate
|
||||||
|
* Returns: Zero on success
|
||||||
|
*/
|
||||||
|
int (*set_dyn_bit_clk)(struct drm_connector *connector, uint64_t value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get_qsync_min_fps - Get qsync min fps from qsync-min-fps-list
|
* get_qsync_min_fps - Get qsync min fps from qsync-min-fps-list
|
||||||
* @display: Pointer to private display structure
|
* @display: Pointer to private display structure
|
||||||
@@ -961,6 +969,14 @@ int sde_connector_set_blob_data(struct drm_connector *conn,
|
|||||||
*/
|
*/
|
||||||
int sde_connector_roi_v1_check_roi(struct drm_connector_state *conn_state);
|
int sde_connector_roi_v1_check_roi(struct drm_connector_state *conn_state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sde_connector_set_dyn_bit_clk - set dynamic bit clock
|
||||||
|
* @conn: Pointer to drm_connector struct
|
||||||
|
* @value: Property value
|
||||||
|
* Returns: Zero on success
|
||||||
|
*/
|
||||||
|
int sde_connector_set_dyn_bit_clk(struct drm_connector *conn, uint64_t value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sde_connector_schedule_status_work - manage ESD thread
|
* sde_connector_schedule_status_work - manage ESD thread
|
||||||
* conn: Pointer to drm_connector struct
|
* conn: Pointer to drm_connector struct
|
||||||
|
@@ -1736,6 +1736,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
|
|||||||
.cmd_receive = dsi_display_cmd_receive,
|
.cmd_receive = dsi_display_cmd_receive,
|
||||||
.install_properties = NULL,
|
.install_properties = NULL,
|
||||||
.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,
|
||||||
.get_qsync_min_fps = dsi_display_get_qsync_min_fps,
|
.get_qsync_min_fps = dsi_display_get_qsync_min_fps,
|
||||||
.prepare_commit = dsi_conn_prepare_commit,
|
.prepare_commit = dsi_conn_prepare_commit,
|
||||||
};
|
};
|
||||||
@@ -1756,6 +1757,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
|
|||||||
.get_panel_vfp = NULL,
|
.get_panel_vfp = NULL,
|
||||||
.cmd_receive = NULL,
|
.cmd_receive = NULL,
|
||||||
.install_properties = NULL,
|
.install_properties = NULL,
|
||||||
|
.set_dyn_bit_clk = NULL,
|
||||||
.set_allowed_mode_switch = NULL,
|
.set_allowed_mode_switch = NULL,
|
||||||
};
|
};
|
||||||
static const struct sde_connector_ops dp_ops = {
|
static const struct sde_connector_ops dp_ops = {
|
||||||
@@ -1778,6 +1780,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
|
|||||||
.cmd_receive = NULL,
|
.cmd_receive = NULL,
|
||||||
.install_properties = dp_connector_install_properties,
|
.install_properties = dp_connector_install_properties,
|
||||||
.set_allowed_mode_switch = NULL,
|
.set_allowed_mode_switch = NULL,
|
||||||
|
.set_dyn_bit_clk = NULL,
|
||||||
};
|
};
|
||||||
struct msm_display_info info;
|
struct msm_display_info info;
|
||||||
struct drm_encoder *encoder;
|
struct drm_encoder *encoder;
|
||||||
|
@@ -611,6 +611,16 @@ void sde_kms_info_append_format(struct sde_kms_info *info,
|
|||||||
*/
|
*/
|
||||||
void sde_kms_info_stop(struct sde_kms_info *info);
|
void sde_kms_info_stop(struct sde_kms_info *info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sde_kms_info_add_list - add a space separated list to 'sde_kms_info'
|
||||||
|
* @info: Pointer to sde_kms_info structure
|
||||||
|
* @key: Pointer to key string
|
||||||
|
* @item: Pointer to array of integer values
|
||||||
|
* @size: Number of integers to parse
|
||||||
|
*/
|
||||||
|
void sde_kms_info_add_list(struct sde_kms_info *info,
|
||||||
|
const char *key, uint32_t *item, size_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sde_kms_rect_intersect - intersect two rectangles
|
* sde_kms_rect_intersect - intersect two rectangles
|
||||||
* @r1: first rectangle
|
* @r1: first rectangle
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define pr_fmt(fmt) "sde-kms_utils:[%s] " fmt, __func__
|
#define pr_fmt(fmt) "sde-kms_utils:[%s] " fmt, __func__
|
||||||
@@ -91,6 +91,28 @@ void sde_kms_info_append(struct sde_kms_info *info,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sde_kms_info_add_list(struct sde_kms_info *info, const char *key, uint32_t *value, size_t size)
|
||||||
|
{
|
||||||
|
uint32_t i, len;
|
||||||
|
|
||||||
|
if (!info || !key || !value || !size)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sde_kms_info_start(info, key);
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
len = scnprintf(info->data + info->staged_len,
|
||||||
|
SDE_KMS_INFO_MAX_SIZE - info->len, "%d ",
|
||||||
|
value[i]);
|
||||||
|
|
||||||
|
/* check if snprintf truncated the string */
|
||||||
|
if ((info->staged_len + len) < SDE_KMS_INFO_MAX_SIZE) {
|
||||||
|
info->staged_len += len;
|
||||||
|
info->start = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sde_kms_info_stop(info);
|
||||||
|
}
|
||||||
|
|
||||||
void sde_kms_info_append_format(struct sde_kms_info *info,
|
void sde_kms_info_append_format(struct sde_kms_info *info,
|
||||||
uint32_t pixel_format,
|
uint32_t pixel_format,
|
||||||
uint64_t modifier)
|
uint64_t modifier)
|
||||||
|
Reference in New Issue
Block a user