Merge branch 'display-kernel.lnx.5.10' into display-kernel.lnx.1.0

* waipio_base:
  disp: msm: sde: add new support for digital dimming
  disp: msm: sde: trigger tx_wait if panel resolution switch
  disp: msm: reserve core clock rate during display disable
  disp: msm: dsi: reorder DSI registration
  disp: msm: sde: account for pref lm when exposing avail resources
  disp: msm: reset lm blend stages for missing vsync
  disp: msm: dp: set drm mode clock same as clock value from EDID
  disp: msm: sde: set top left coordinates for noise and attenuation layers
  disp: msm: dp: disable ASSR before link training
  disp: msm: dp: retry the request to set USB mode during bootup
  disp: msm: sde: clear intf mux select on slave encoders
  disp: msm: retry dma buf attach on msm_gem_delayed_import error
  disp: msm: dp: check for aux abort in sim mode
  disp: msm: dsi: add qsync min fps val in dsi display mode priv info
  disp: msm: dp: read DPCD registers using debugfs
  disp: msm: dsi: mark signature for stub appropriately
  disp: msm: dp: check for DP stream during audio teardown
  display: msm: sde: reduce dbg mem usage for tui vm

Change-Id: I285e4557ad258f17fc2948b478198b9b81c18276
Este commit está contenido en:
Jeykumar Sankaran
2021-10-07 15:03:13 -07:00
Se han modificado 33 ficheros con 454 adiciones y 131 borrados

Ver fichero

@@ -7,3 +7,4 @@ export CONFIG_QCOM_MDSS_PLL=y
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
export CONFIG_DISPLAY_BUILD=m
export CONFIG_DRM_SDE_VM=y
export CONFIG_DRM_LOW_MSM_MEM_FOOTPRINT=y

Ver fichero

@@ -13,3 +13,4 @@
#define CONFIG_QCOM_MDSS_PLL 1
#define CONFIG_GKI_DISPLAY 1
#define CONFIG_DRM_SDE_VM 1
#define CONFIG_DRM_MSM_LOW_MEM_FOOTPRINT 1

Ver fichero

@@ -719,6 +719,8 @@ struct drm_msm_fp16_csc {
__u32 cfg_param_1[FP16_CSC_CFG1_PARAM_LEN];
};
#define DIMMING_ENABLE (1 << 0)
#define DIMMING_MIN_BL_VALID (1 << 1)
struct drm_msm_backlight_info {
__u32 brightness_max;
__u32 brightness;
@@ -726,6 +728,8 @@ struct drm_msm_backlight_info {
__u32 bl_level;
__u32 bl_scale;
__u32 bl_scale_sv;
__u32 status;
__u32 min_bl;
};
#define DIMMING_BL_LUT_LEN 8192

Ver fichero

@@ -43,7 +43,7 @@ enum dp_altmode_pin_assignment {
static int dp_altmode_set_usb_dp_mode(struct dp_altmode_private *altmode)
{
int rc;
int rc = 0;
struct device_node *np;
struct device_node *usb_node;
struct platform_device *usb_pdev;
@@ -71,7 +71,7 @@ static int dp_altmode_set_usb_dp_mode(struct dp_altmode_private *altmode)
while (timeout) {
rc = dwc3_msm_set_dp_mode(&usb_pdev->dev, altmode->connected, altmode->lanes);
if (rc != -EBUSY)
if (rc != -EBUSY && rc != -EAGAIN)
break;
DP_WARN("USB busy, retry\n");

Ver fichero

@@ -505,6 +505,12 @@ static void dp_audio_teardown_done(struct platform_device *pdev)
return;
}
if (audio->panel->stream_id >= DP_STREAM_MAX) {
DP_WARN("invalid stream id: %d\n",
audio->panel->stream_id);
return;
}
mutex_lock(&audio->ops_lock);
dp_audio_enable(audio, false);
mutex_unlock(&audio->ops_lock);

Ver fichero

@@ -560,6 +560,15 @@ static ssize_t dp_aux_transfer_debug(struct drm_dp_aux *drm_aux,
struct dp_aux_private *aux = container_of(drm_aux,
struct dp_aux_private, drm_aux);
ssize_t size;
int aborted;
mutex_lock(&aux->mutex);
aborted = atomic_read(&aux->aborted);
mutex_unlock(&aux->mutex);
if (aborted) {
size = -ETIMEDOUT;
goto end;
}
if (aux->sim_in_transfer) {
if (aux->aux_bridge && aux->aux_bridge->transfer)
@@ -572,7 +581,7 @@ static ssize_t dp_aux_transfer_debug(struct drm_dp_aux *drm_aux,
drm_aux, msg);
aux->sim_in_transfer = false;
}
end:
return size;
}

Ver fichero

@@ -1084,7 +1084,12 @@ static void dp_catalog_ctrl_config_ctrl(struct dp_catalog_ctrl *ctrl, u8 ln_cnt)
io_data = catalog->io.dp_link;
cfg = dp_read(DP_CONFIGURATION_CTRL);
cfg &= ~(BIT(4) | BIT(5));
/*
* Reset ASSR (alternate scrambler seed reset) by resetting BIT(10).
* ASSR should be set to disable for TPS4 link training pattern.
* Forcing it to 0 as the power on reset value of register enables it.
*/
cfg &= ~(BIT(4) | BIT(5) | BIT(10));
cfg |= (ln_cnt - 1) << 4;
dp_write(DP_CONFIGURATION_CTRL, cfg);

Ver fichero

@@ -212,7 +212,7 @@ static ssize_t dp_debug_write_dpcd(struct file *file,
size = min_t(size_t, count, SZ_2K);
if (size <= 4)
if (size < 4)
goto bail;
buf = kzalloc(size, GFP_KERNEL);
@@ -231,9 +231,10 @@ static ssize_t dp_debug_write_dpcd(struct file *file,
DP_ERR("offset kstrtoint error\n");
goto bail;
}
debug->dpcd_offset = offset;
size -= 4;
if (size == 0)
if (size < char_to_nib)
goto bail;
dpcd_size = size / char_to_nib;
@@ -277,7 +278,6 @@ static ssize_t dp_debug_write_dpcd(struct file *file,
dp_sim_write_dpcd_reg(debug->sim_bridge,
dpcd, dpcd_buf_index, offset);
debug->dpcd_offset = offset;
debug->dpcd_size = dpcd_buf_index;
bail:
@@ -315,21 +315,27 @@ static ssize_t dp_debug_read_dpcd(struct file *file,
/*
* In simulation mode, this function returns the last written DPCD node.
* For a real monitor plug in, it always dumps the first 16 DPCD registers.
* For a real monitor plug in, it dumps the first byte at the last written DPCD address
* unless the address is 0, in which case the first 20 bytes are dumped
*/
if (debug->dp_debug.sim_mode) {
dp_sim_read_dpcd_reg(debug->sim_bridge, dpcd, debug->dpcd_size, debug->dpcd_offset);
} else {
debug->dpcd_size = sizeof(debug->panel->dpcd);
debug->dpcd_offset = 0;
memcpy(dpcd, debug->panel->dpcd, debug->dpcd_size);
if (debug->dpcd_offset) {
debug->dpcd_size = 1;
if (drm_dp_dpcd_read(debug->aux->drm_aux, debug->dpcd_offset, dpcd,
debug->dpcd_size) != 1)
goto bail;
} else {
debug->dpcd_size = sizeof(debug->panel->dpcd);
memcpy(dpcd, debug->panel->dpcd, debug->dpcd_size);
}
}
len += scnprintf(buf, buf_size, "%04x: ", debug->dpcd_offset);
len += scnprintf(buf + len , buf_size - len, "%04x: ", debug->dpcd_offset);
while (offset < debug->dpcd_size)
len += scnprintf(buf + len, buf_size - len, "%02x ",
dpcd[debug->dpcd_offset + offset++]);
len += scnprintf(buf + len, buf_size - len, "%02x ", dpcd[offset++]);
kfree(dpcd);

Ver fichero

@@ -40,8 +40,7 @@ void convert_to_drm_mode(const struct dp_display_mode *dp_mode,
dp_mode->timing.v_sync_width;
drm_mode->vtotal = drm_mode->vsync_end + dp_mode->timing.v_back_porch;
drm_mode->clock = drm_mode->htotal * drm_mode->vtotal * dp_mode->timing.refresh_rate;
drm_mode->clock /= 1000;
drm_mode->clock = dp_mode->timing.pixel_clk_khz;
if (dp_mode->timing.h_active_low)
flags |= DRM_MODE_FLAG_NHSYNC;

Ver fichero

@@ -611,6 +611,7 @@ struct dsi_host_config {
* @mdp_transfer_time_us: Specifies the mdp transfer time for command mode
* panels in microseconds.
* @dsi_transfer_time_us: Specifies the dsi transfer time for cmd panels.
* @qsync_min_fps: Qsync min fps value for the mode
* @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.
* @bit_clk_list: List of dynamic bit clock rates supported.
@@ -636,6 +637,7 @@ struct dsi_display_mode_priv_info {
u32 panel_prefill_lines;
u32 mdp_transfer_time_us;
u32 dsi_transfer_time_us;
u32 qsync_min_fps;
u64 clk_rate_hz;
u64 min_dsi_clk_hz;
struct msm_dyn_clk_list bit_clk_list;

Ver fichero

@@ -249,7 +249,7 @@ int dsi_display_set_backlight(struct drm_connector *connector,
/* use bl_temp as index of dimming bl lut to find the dimming panel backlight */
if (bl_temp != 0 && panel->bl_config.dimming_bl_lut &&
bl_temp < panel->bl_config.dimming_bl_lut->length) {
pr_debug("before dimming bl_temp = %u, after dimming bl_temp = %lu\n",
DSI_DEBUG("before dimming bl_temp = %u, after dimming bl_temp = %lu\n",
bl_temp, panel->bl_config.dimming_bl_lut->mapped_bl[bl_temp]);
bl_temp = panel->bl_config.dimming_bl_lut->mapped_bl[bl_temp];
}
@@ -257,10 +257,10 @@ int dsi_display_set_backlight(struct drm_connector *connector,
if (bl_temp > panel->bl_config.bl_max_level)
bl_temp = panel->bl_config.bl_max_level;
if (bl_temp && (bl_temp < panel->bl_config.bl_min_level))
bl_temp = panel->bl_config.bl_min_level;
if (bl_temp && (bl_temp < panel->bl_config.bl_min_level))
bl_temp = panel->bl_config.bl_min_level;
pr_debug("bl_scale = %u, bl_scale_sv = %u, bl_lvl = %u\n",
DSI_DEBUG("bl_scale = %u, bl_scale_sv = %u, bl_lvl = %u\n",
bl_scale, bl_scale_sv, (u32)bl_temp);
rc = dsi_panel_set_backlight(panel, (u32)bl_temp);
@@ -6978,6 +6978,11 @@ int dsi_display_get_modes(struct dsi_display *display,
if (!sub_mode->timing.qsync_min_fps && qsync_caps->qsync_min_fps)
sub_mode->timing.qsync_min_fps = qsync_caps->qsync_min_fps;
/*
* Qsync min fps for the mode will be populated in the timing info
* in dsi_panel_get_mode function.
*/
sub_mode->priv_info->qsync_min_fps = sub_mode->timing.qsync_min_fps;
if (!dfps_caps.dfps_support || !support_video_mode)
continue;
@@ -6986,8 +6991,10 @@ int dsi_display_get_modes(struct dsi_display *display,
sub_mode->timing.refresh_rate = dfps_caps.dfps_list[i];
/* Override with qsync min fps list in dfps usecases */
if (qsync_caps->qsync_min_fps && qsync_caps->qsync_min_fps_list_len)
if (qsync_caps->qsync_min_fps && qsync_caps->qsync_min_fps_list_len) {
sub_mode->timing.qsync_min_fps = qsync_caps->qsync_min_fps_list[i];
sub_mode->priv_info->qsync_min_fps = sub_mode->timing.qsync_min_fps;
}
dsi_display_get_dfps_timing(display, sub_mode,
curr_refresh_rate);

Ver fichero

@@ -706,30 +706,21 @@ int dsi_conn_set_avr_step_info(struct dsi_panel *panel, void *info)
return 0;
}
int dsi_conn_get_qsync_min_fps(void *display_dsi, struct drm_connector_state *conn_state)
int dsi_conn_get_qsync_min_fps(struct drm_connector_state *conn_state)
{
struct dsi_display *display = (struct dsi_display *)display_dsi;
int rc = 0;
struct dsi_display_mode partial_dsi_mode, *dsi_mode;
struct msm_sub_mode new_sub_mode;
struct sde_connector_state *sde_conn_state;
struct drm_display_mode *drm_mode;
struct sde_connector_state *sde_conn_state = to_sde_connector_state(conn_state);
struct msm_display_mode *msm_mode;
struct dsi_display_mode_priv_info *priv_info;
if (!display || !display->drm_conn || !conn_state)
if (!sde_conn_state)
return -EINVAL;
sde_conn_state = to_sde_connector_state(conn_state);
drm_mode = sde_conn_state->msm_mode.base;
convert_to_dsi_mode(drm_mode, &partial_dsi_mode);
new_sub_mode.dsc_mode = sde_connector_get_property(conn_state, CONNECTOR_PROP_DSC_MODE);
msm_mode = &sde_conn_state->msm_mode;
if (!msm_mode || !msm_mode->private)
return -EINVAL;
rc = dsi_display_find_mode(display, &partial_dsi_mode, &new_sub_mode, &dsi_mode);
if (rc) {
DSI_ERR("invalid mode\n");
return rc;
}
return dsi_mode->timing.qsync_min_fps;
priv_info = (struct dsi_display_mode_priv_info *)(msm_mode->private);
return priv_info->qsync_min_fps;
}
int dsi_conn_set_info_blob(struct drm_connector *connector,

Ver fichero

@@ -174,10 +174,9 @@ void dsi_conn_set_submode_blob_info(struct drm_connector *conn,
/**
* dsi_conn_get_qsync_min_fps() - get qsync min fps for given fps
* @display: Handle to display.
* @conn_state: Pointer to drm_connector_state structure
*
* Return: Qsync min fps rate or -ve error code.
*/
int dsi_conn_get_qsync_min_fps(void *dsi_display, struct drm_connector_state *conn_state);
int dsi_conn_get_qsync_min_fps(struct drm_connector_state *conn_state);
#endif /* _DSI_DRM_H_ */

Ver fichero

@@ -2445,6 +2445,9 @@ static int dsi_panel_parse_bl_config(struct dsi_panel *panel)
panel->bl_config.bl_scale = MAX_BL_SCALE_LEVEL;
panel->bl_config.bl_scale_sv = MAX_SV_BL_SCALE_LEVEL;
panel->bl_config.dimming_min_bl = 0;
panel->bl_config.dimming_status = DIMMING_ENABLE;
panel->bl_config.user_disable_notification = false;
rc = utils->read_u32(utils->data, "qcom,mdss-dsi-bl-min-level", &val);
if (rc) {

Ver fichero

@@ -13,6 +13,7 @@
#include <linux/backlight.h>
#include <drm/drm_panel.h>
#include <drm/msm_drm.h>
#include <drm/msm_drm_pp.h>
#include "dsi_defs.h"
#include "dsi_ctrl_hw.h"
@@ -134,6 +135,9 @@ struct dsi_backlight_config {
bool bl_inverted_dbv;
/* digital dimming backlight LUT */
struct drm_msm_dimming_bl_lut *dimming_bl_lut;
u32 dimming_min_bl;
u32 dimming_status;
bool user_disable_notification;
int en_gpio;
/* PWM params */

Ver fichero

@@ -92,7 +92,7 @@ static inline int dsi_parser_read_u32(const struct device_node *np,
return -ENODEV;
}
int dsi_parser_read_u32_index(const struct device_node *np,
static inline int dsi_parser_read_u32_index(const struct device_node *np,
const char *propname, u32 index, u32 *out_value)
{
return -ENODEV;

Ver fichero

@@ -2188,21 +2188,21 @@ static int __init msm_drm_register(void)
DBG("init");
sde_rsc_rpmh_register();
sde_rsc_register();
msm_smmu_driver_init();
sde_wb_register();
platform_driver_register(&msm_platform_driver);
dsi_display_register();
msm_hdcp_register();
dp_display_register();
msm_smmu_driver_init();
msm_dsi_register();
msm_edp_register();
msm_hdmi_register();
sde_wb_register();
return platform_driver_register(&msm_platform_driver);
return 0;
}
static void __exit msm_drm_unregister(void)
{
DBG("fini");
platform_driver_unregister(&msm_platform_driver);
sde_wb_unregister();
msm_hdmi_unregister();
msm_edp_unregister();
@@ -2214,6 +2214,7 @@ static void __exit msm_drm_unregister(void)
dp_display_unregister();
dsi_display_unregister();
sde_rsc_unregister();
platform_driver_unregister(&msm_platform_driver);
}
module_init(msm_drm_register);

Ver fichero

@@ -216,6 +216,8 @@ enum msm_mdp_conn_property {
CONNECTOR_PROP_SV_BL_SCALE,
CONNECTOR_PROP_SUPPORTED_COLORSPACES,
CONNECTOR_PROP_DYN_BIT_CLK,
CONNECTOR_PROP_DIMMING_CTRL,
CONNECTOR_PROP_DIMMING_MIN_BL,
/* enum/bitmask properties */
CONNECTOR_PROP_TOPOLOGY_NAME,

Ver fichero

@@ -481,6 +481,7 @@ static int msm_gem_get_iova_locked(struct drm_gem_object *obj,
if (ret) {
DRM_ERROR("delayed dma-buf import failed %d\n",
ret);
msm_obj->obj_dirty = true;
return ret;
}
}

Ver fichero

@@ -106,7 +106,10 @@ static void sde_dimming_bl_notify(struct sde_connector *conn, struct dsi_backlig
if (!conn || !config)
return;
if (!conn->dimming_bl_notify_enabled)
SDE_DEBUG("bl_config.dimming_status 0x%x user_disable_notify %d\n",
config->dimming_status, config->user_disable_notification);
if (!conn->dimming_bl_notify_enabled || config->user_disable_notification)
return;
bl_info.brightness_max = config->brightness_max_level;
@@ -115,10 +118,13 @@ static void sde_dimming_bl_notify(struct sde_connector *conn, struct dsi_backlig
bl_info.bl_level = config->bl_level;
bl_info.bl_scale = config->bl_scale;
bl_info.bl_scale_sv = config->bl_scale_sv;
bl_info.status = config->dimming_status;
bl_info.min_bl = config->dimming_min_bl;
event.type = DRM_EVENT_DIMMING_BL;
event.length = sizeof(bl_info);
SDE_DEBUG("dimming BL event bl_level %d bl_scale %d, bl_scale_sv = %d\n",
bl_info.bl_level, bl_info.bl_scale, bl_info.bl_scale_sv);
SDE_DEBUG("dimming BL event bl_level %d bl_scale %d, bl_scale_sv = %d "
"min_bl %d status 0x%x\n", bl_info.bl_level, bl_info.bl_scale,
bl_info.bl_scale_sv, bl_info.min_bl, bl_info.status);
msm_mode_object_event_notify(&conn->base.base, conn->base.dev, &event, (u8 *)&bl_info);
}
@@ -181,7 +187,8 @@ static int sde_backlight_device_update_status(struct backlight_device *bd)
}
rc = c_conn->ops.set_backlight(&c_conn->base,
c_conn->display, bl_lvl);
sde_dimming_bl_notify(c_conn, &display->panel->bl_config);
if (!rc)
sde_dimming_bl_notify(c_conn, &display->panel->bl_config);
c_conn->unset_bl_level = 0;
}
@@ -693,6 +700,7 @@ static int _sde_connector_update_dimming_bl_lut(struct sde_connector *c_conn,
size_t sz = 0;
struct dsi_display *dsi_display;
struct dsi_backlight_config *bl_config;
int rc = 0;
if (!c_conn || !c_state) {
SDE_ERROR("invalid arguments\n");
@@ -716,6 +724,81 @@ static int _sde_connector_update_dimming_bl_lut(struct sde_connector *c_conn,
bl_config = &dsi_display->panel->bl_config;
bl_config->dimming_bl_lut = msm_property_get_blob(&c_conn->property_info,
&c_state->property_state, &sz, CONNECTOR_PROP_DIMMING_BL_LUT);
rc = c_conn->ops.set_backlight(&c_conn->base,
dsi_display, bl_config->bl_level);
if (!rc)
c_conn->unset_bl_level = 0;
return 0;
}
static int _sde_connector_update_dimming_ctrl(struct sde_connector *c_conn,
struct sde_connector_state *c_state, uint64_t val)
{
struct dsi_display *dsi_display;
struct dsi_backlight_config *bl_config;
bool prev, curr = (bool)val;
if (!c_conn || !c_state) {
SDE_ERROR("invalid arguments\n");
return -EINVAL;
}
dsi_display = c_conn->display;
if (!dsi_display || !dsi_display->panel) {
SDE_ERROR("Invalid params(s) dsi_display %pK, panel %pK\n",
dsi_display,
((dsi_display) ? dsi_display->panel : NULL));
return -EINVAL;
}
bl_config = &dsi_display->panel->bl_config;
prev = (bool)(bl_config->dimming_status & DIMMING_ENABLE);
if (curr == prev)
return 0;
if(val) {
bl_config->dimming_status |= DIMMING_ENABLE;
} else {
bl_config->dimming_status &= ~DIMMING_ENABLE;
}
bl_config->user_disable_notification = false;
sde_dimming_bl_notify(c_conn, bl_config);
if (!val)
bl_config->user_disable_notification = true;
return 0;
}
static int _sde_connector_update_dimming_min_bl(struct sde_connector *c_conn,
struct sde_connector_state *c_state, uint64_t val)
{
struct dsi_display *dsi_display;
struct dsi_backlight_config *bl_config;
uint32_t tmp = 0;
if (!c_conn || !c_state) {
SDE_ERROR("invalid arguments\n");
return -EINVAL;
}
dsi_display = c_conn->display;
if (!dsi_display || !dsi_display->panel) {
SDE_ERROR("Invalid params(s) dsi_display %pK, panel %pK\n",
dsi_display,
((dsi_display) ? dsi_display->panel : NULL));
return -EINVAL;
}
bl_config = &dsi_display->panel->bl_config;
tmp = (uint32_t)val;
if (tmp == bl_config->dimming_min_bl)
return 0;
bl_config->dimming_min_bl = tmp;
bl_config->dimming_status |= DIMMING_MIN_BL_VALID;
sde_dimming_bl_notify(c_conn, bl_config);
bl_config->dimming_status &= ~DIMMING_MIN_BL_VALID;
return 0;
}
@@ -1673,6 +1756,12 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector,
case CONNECTOR_PROP_DIMMING_BL_LUT:
rc = _sde_connector_update_dimming_bl_lut(c_conn, c_state);
break;
case CONNECTOR_PROP_DIMMING_CTRL:
rc = _sde_connector_update_dimming_ctrl(c_conn, c_state, val);
break;
case CONNECTOR_PROP_DIMMING_MIN_BL:
rc = _sde_connector_update_dimming_min_bl(c_conn, c_state, val);
break;
case CONNECTOR_PROP_HDR_METADATA:
rc = _sde_connector_set_ext_hdr_info(c_conn,
c_state, (void *)(uintptr_t)val);
@@ -2911,10 +3000,16 @@ static int _sde_connector_install_properties(struct drm_device *dev,
if (connector_type == DRM_MODE_CONNECTOR_DSI) {
dsi_display = (struct dsi_display *)(display);
if (dsi_display && dsi_display->panel)
if (dsi_display && dsi_display->panel) {
msm_property_install_blob(&c_conn->property_info,
"dimming_bl_lut", DRM_MODE_PROP_BLOB,
CONNECTOR_PROP_DIMMING_BL_LUT);
msm_property_install_range(&c_conn->property_info, "dimming_dyn_ctrl",
0x0, 0, ~0, 0, CONNECTOR_PROP_DIMMING_CTRL);
msm_property_install_range(&c_conn->property_info, "dimming_min_bl",
0x0, 0, dsi_display->panel->bl_config.brightness_max_level, 0,
CONNECTOR_PROP_DIMMING_MIN_BL);
}
if (dsi_display && dsi_display->panel &&
dsi_display->panel->hdr_props.hdr_enabled == true) {

Ver fichero

@@ -399,11 +399,10 @@ struct sde_connector_ops {
/**
* get_qsync_min_fps - Get qsync min fps from qsync-min-fps-list
* @display: Pointer to private display structure
* @conn_state: Pointer to drm_connector_state structure
* Returns: Qsync min fps value on success
*/
int (*get_qsync_min_fps)(void *display, struct drm_connector_state *conn_state);
int (*get_qsync_min_fps)(struct drm_connector_state *conn_state);
/**
* get_avr_step_req - Get the required avr_step for given fps rate

Ver fichero

@@ -829,6 +829,31 @@ void sde_core_perf_crtc_release_bw(struct drm_crtc *crtc)
}
}
void sde_core_perf_crtc_reserve_res(struct drm_crtc *crtc, u64 reserve_rate)
{
struct sde_crtc *sde_crtc;
struct sde_kms *kms;
struct msm_drm_private *priv;
if (!crtc) {
SDE_ERROR("invalid crtc\n");
return;
}
/* use current perf, which are the values voted */
sde_crtc = to_sde_crtc(crtc);
kms = _sde_crtc_get_kms(crtc);
priv = kms->dev->dev_private;
kms->perf.core_clk_reserve_rate = max(kms->perf.core_clk_reserve_rate, reserve_rate);
kms->perf.core_clk_reserve_rate = min(kms->perf.core_clk_reserve_rate,
kms->perf.max_core_clk_rate);
sde_power_clk_reserve_rate(&priv->phandle, kms->perf.clk_name,
kms->perf.core_clk_reserve_rate);
SDE_DEBUG("reserve clk:%llu\n", kms->perf.core_clk_reserve_rate);
}
static u64 _sde_core_perf_get_core_clk_rate(struct sde_kms *kms)
{
u64 clk_rate = kms->perf.perf_tune.min_core_clk;

Ver fichero

@@ -1,6 +1,6 @@
/* 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 _SDE_CORE_PERF_H_
@@ -78,6 +78,7 @@ struct sde_core_perf_tune {
* @uidle_enabled: indicates if uidle is already enabled
* @idle_sys_cache_enabled: override system cache enable state
* for idle usecase
* @core_clk_reserve_rate: reserve core clk rate for built-in display
*/
struct sde_core_perf {
struct drm_device *dev;
@@ -99,6 +100,7 @@ struct sde_core_perf {
bool llcc_active[SDE_SYS_CACHE_MAX];
bool uidle_enabled;
bool idle_sys_cache_enabled;
u64 core_clk_reserve_rate;
};
/**
@@ -131,6 +133,13 @@ void sde_core_perf_crtc_update(struct drm_crtc *crtc,
*/
void sde_core_perf_crtc_release_bw(struct drm_crtc *crtc);
/**
* sde_core_perf_reserve_res - reserve core clock resource for built-in displays.
* @crtc: Pointer to crtc
* @reserve_rate: core clock rate for built-in display
*/
void sde_core_perf_crtc_reserve_res(struct drm_crtc *crtc, u64 reserve_rate);
/**
* sde_core_perf_crtc_update_uidle - attempts to enable uidle of the given crtc
* @crtc: Pointer to crtc

Ver fichero

@@ -3979,7 +3979,7 @@ int sde_crtc_reset_hw(struct drm_crtc *crtc, struct drm_crtc_state *old_state,
continue;
if (sde_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO)
sde_encoder_kickoff(encoder, false, true);
sde_encoder_kickoff(encoder, true);
}
/* panic the device if VBIF is not in good state */
@@ -4086,7 +4086,7 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc,
if (encoder->crtc != crtc)
continue;
sde_encoder_kickoff(encoder, false, true);
sde_encoder_kickoff(encoder, true);
}
sde_crtc->kickoff_in_progress = false;
@@ -4160,6 +4160,43 @@ static int _sde_crtc_vblank_enable(
return 0;
}
static void _sde_crtc_reserve_resource(struct drm_crtc *crtc, struct drm_connector *conn)
{
u32 min_transfer_time = 0, lm_count = 1;
u64 mode_clock_hz = 0, updated_fps = 0, topology_id;
struct drm_encoder *encoder;
if (!crtc || !conn)
return;
encoder = conn->state->best_encoder;
if (!sde_encoder_is_built_in_display(encoder))
return;
if (sde_encoder_check_curr_mode(encoder, MSM_DISPLAY_CMD_MODE))
sde_encoder_get_transfer_time(encoder, &min_transfer_time);
if (min_transfer_time)
updated_fps = DIV_ROUND_UP(1000000, min_transfer_time);
else
updated_fps = drm_mode_vrefresh(&crtc->mode);
topology_id = sde_connector_get_topology_name(conn);
if (TOPOLOGY_DUALPIPE_MODE(topology_id))
lm_count = 2;
else if (TOPOLOGY_QUADPIPE_MODE(topology_id))
lm_count = 4;
/* mode clock = [(h * v * fps * 1.05) / (num_lm)] */
mode_clock_hz = mult_frac(crtc->mode.htotal * crtc->mode.vtotal * updated_fps, 105, 100);
mode_clock_hz = div_u64(mode_clock_hz, lm_count);
SDE_DEBUG("[%s] h=%d v=%d fps=%d lm=%d mode_clk=%u\n",
crtc->mode.name, crtc->mode.htotal, crtc->mode.vtotal,
updated_fps, lm_count, mode_clock_hz);
sde_core_perf_crtc_reserve_res(crtc, mode_clock_hz);
}
/**
* sde_crtc_duplicate_state - state duplicate hook
* @crtc: Pointer to drm crtc structure
@@ -4666,8 +4703,10 @@ static void sde_crtc_enable(struct drm_crtc *crtc,
sde_crtc_handle_power_event, crtc, sde_crtc->name);
/* Enable ESD thread */
for (i = 0; i < cstate->num_connectors; i++)
for (i = 0; i < cstate->num_connectors; i++) {
sde_connector_schedule_status_work(cstate->connectors[i], true);
_sde_crtc_reserve_resource(crtc, cstate->connectors[i]);
}
}
/* no input validation - caller API has all the checks */
@@ -7061,7 +7100,7 @@ void __sde_crtc_static_cache_read_work(struct kthread_work *work)
sde_plane_ctl_flush(plane, ctl, true);
/* kickoff encoder and wait for VBLANK */
sde_encoder_kickoff(drm_enc, false, false);
sde_encoder_kickoff(drm_enc, false);
sde_encoder_wait_for_event(drm_enc, MSM_ENC_VBLANK);
SDE_EVT32(DRMID(crtc), SDE_EVTLOG_FUNC_EXIT);

Ver fichero

@@ -342,6 +342,15 @@ bool sde_encoder_is_primary_display(struct drm_encoder *drm_enc)
SDE_CONNECTOR_PRIMARY);
}
bool sde_encoder_is_built_in_display(struct drm_encoder *drm_enc)
{
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
return sde_enc &&
(sde_enc->disp_info.display_type == SDE_CONNECTOR_PRIMARY ||
sde_enc->disp_info.display_type == SDE_CONNECTOR_SECONDARY);
}
bool sde_encoder_is_dsi_display(struct drm_encoder *drm_enc)
{
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
@@ -1053,7 +1062,7 @@ static void _sde_encoder_get_qsync_fps_callback(struct drm_encoder *drm_enc,
sde_conn = to_sde_connector(sde_enc->cur_master->connector);
if (sde_conn->ops.get_qsync_min_fps)
rc = sde_conn->ops.get_qsync_min_fps(sde_conn->display, conn_state);
rc = sde_conn->ops.get_qsync_min_fps(conn_state);
if (rc < 0) {
SDE_ERROR("invalid qsync min fps %d\n", rc);
@@ -2430,17 +2439,33 @@ static void _sde_encoder_virt_populate_hw_res(struct drm_encoder *drm_enc)
}
static int sde_encoder_virt_modeset_rc(struct drm_encoder *drm_enc,
struct msm_display_mode *msm_mode, bool pre_modeset)
struct drm_display_mode *adj_mode, struct msm_display_mode *msm_mode, bool pre_modeset)
{
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
enum sde_intf_mode intf_mode;
struct drm_display_mode *old_adj_mode = NULL;
int ret;
bool is_cmd_mode = false;
bool is_cmd_mode = false, res_switch = false;
if (sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE))
is_cmd_mode = true;
if (pre_modeset) {
if (sde_enc->cur_master)
old_adj_mode = &sde_enc->cur_master->cached_mode;
if (old_adj_mode && is_cmd_mode)
res_switch = !drm_mode_match(old_adj_mode, adj_mode, DRM_MODE_MATCH_TIMINGS);
if (res_switch) {
/* avoid early tear check reconfigure for resolution switch */
ret = sde_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE);
if (ret && ret != -EWOULDBLOCK) {
SDE_ERROR_ENC(sde_enc, "wait for idle failed %d\n", ret);
SDE_EVT32(DRMID(drm_enc), ret, SDE_EVTLOG_ERROR);
return ret;
}
}
intf_mode = sde_encoder_get_intf_mode(drm_enc);
if (msm_is_mode_seamless_dms(msm_mode) ||
(msm_is_mode_seamless_dyn_clk(msm_mode) &&
@@ -2545,7 +2570,7 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
/* release resources before seamless mode change */
msm_mode = &c_state->msm_mode;
ret = sde_encoder_virt_modeset_rc(drm_enc, msm_mode, true);
ret = sde_encoder_virt_modeset_rc(drm_enc, adj_mode, msm_mode, true);
if (ret)
return;
@@ -2584,7 +2609,7 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
}
/* update resources after seamless mode change */
sde_encoder_virt_modeset_rc(drm_enc, msm_mode, false);
sde_encoder_virt_modeset_rc(drm_enc, adj_mode, msm_mode, false);
}
void sde_encoder_control_te(struct drm_encoder *drm_enc, bool enable)
@@ -3163,10 +3188,13 @@ void sde_encoder_helper_phys_disable(struct sde_encoder_phys *phys_enc,
struct sde_encoder_virt *sde_enc;
struct sde_hw_ctl *ctl = phys_enc->hw_ctl;
struct sde_ctl_flush_cfg cfg;
int i;
ctl->ops.reset(ctl);
sde_encoder_helper_reset_mixers(phys_enc, NULL);
sde_enc = to_sde_encoder_virt(phys_enc->parent);
if (wb_enc) {
if (wb_enc->hw_wb->ops.bind_pingpong_blk) {
wb_enc->hw_wb->ops.bind_pingpong_blk(wb_enc->hw_wb,
@@ -3177,14 +3205,16 @@ void sde_encoder_helper_phys_disable(struct sde_encoder_phys *phys_enc,
wb_enc->hw_wb->idx, true);
}
} else {
if (phys_enc->hw_intf->ops.bind_pingpong_blk) {
phys_enc->hw_intf->ops.bind_pingpong_blk(
phys_enc->hw_intf, false,
phys_enc->hw_pp->idx);
for (i = 0; i < sde_enc->num_phys_encs; i++) {
if (sde_enc->phys_encs[i] && phys_enc->hw_intf->ops.bind_pingpong_blk) {
phys_enc->hw_intf->ops.bind_pingpong_blk(
sde_enc->phys_encs[i]->hw_intf, false,
sde_enc->phys_encs[i]->hw_pp->idx);
if (ctl->ops.update_bitmask)
ctl->ops.update_bitmask(ctl, SDE_HW_FLUSH_INTF,
phys_enc->hw_intf->idx, true);
if (ctl->ops.update_bitmask)
ctl->ops.update_bitmask(ctl, SDE_HW_FLUSH_INTF,
sde_enc->phys_encs[i]->hw_intf->idx, true);
}
}
}
@@ -3206,8 +3236,6 @@ void sde_encoder_helper_phys_disable(struct sde_encoder_phys *phys_enc,
phys_enc->hw_cdm->idx, true);
}
sde_enc = to_sde_encoder_virt(phys_enc->parent);
if (phys_enc == sde_enc->cur_master && phys_enc->hw_pp &&
ctl->ops.reset_post_disable)
ctl->ops.reset_post_disable(ctl, &phys_enc->intf_cfg_v1,
@@ -3222,6 +3250,19 @@ void sde_encoder_helper_phys_disable(struct sde_encoder_phys *phys_enc,
ctl->ops.clear_pending_flush(ctl);
}
void sde_encoder_helper_phys_reset(struct sde_encoder_phys *phys_enc)
{
struct sde_hw_ctl *ctl = phys_enc->hw_ctl;
struct sde_ctl_flush_cfg cfg;
ctl->ops.reset(ctl);
sde_encoder_helper_reset_mixers(phys_enc, NULL);
ctl->ops.get_pending_flush(ctl, &cfg);
SDE_EVT32(DRMID(phys_enc->parent), cfg.pending_flush_mask);
ctl->ops.trigger_flush(ctl);
ctl->ops.trigger_start(ctl);
}
static enum sde_intf sde_encoder_get_intf(struct sde_mdss_cfg *catalog,
enum sde_intf_type type, u32 controller_id)
{
@@ -4354,47 +4395,7 @@ end:
return ret;
}
/**
* _sde_encoder_reset_ctl_hw - reset h/w configuration for all ctl's associated
* with the specified encoder, and unstage all pipes from it
* @encoder: encoder pointer
* Returns: 0 on success
*/
static int _sde_encoder_reset_ctl_hw(struct drm_encoder *drm_enc)
{
struct sde_encoder_virt *sde_enc;
struct sde_encoder_phys *phys;
unsigned int i;
int rc = 0;
if (!drm_enc) {
SDE_ERROR("invalid encoder\n");
return -EINVAL;
}
sde_enc = to_sde_encoder_virt(drm_enc);
SDE_ATRACE_BEGIN("encoder_release_lm");
SDE_DEBUG_ENC(sde_enc, "\n");
for (i = 0; i < sde_enc->num_phys_encs; i++) {
phys = sde_enc->phys_encs[i];
if (!phys)
continue;
SDE_EVT32(DRMID(drm_enc), phys->intf_idx - INTF_0);
rc = sde_encoder_helper_reset_mixers(phys, NULL);
if (rc)
SDE_EVT32(DRMID(drm_enc), rc, SDE_EVTLOG_ERROR);
}
SDE_ATRACE_END("encoder_release_lm");
return rc;
}
void sde_encoder_kickoff(struct drm_encoder *drm_enc, bool is_error,
bool config_changed)
void sde_encoder_kickoff(struct drm_encoder *drm_enc, bool config_changed)
{
struct sde_encoder_virt *sde_enc;
struct sde_encoder_phys *phys;
@@ -4409,10 +4410,6 @@ void sde_encoder_kickoff(struct drm_encoder *drm_enc, bool is_error,
SDE_DEBUG_ENC(sde_enc, "\n");
/* create a 'no pipes' commit to release buffers on errors */
if (is_error)
_sde_encoder_reset_ctl_hw(drm_enc);
if (sde_enc->delay_kickoff) {
u32 loop_count = 20;
u32 sleep = DELAY_KICKOFF_POLL_TIMEOUT_US / loop_count;

Ver fichero

@@ -325,12 +325,9 @@ void sde_encoder_trigger_kickoff_pending(struct drm_encoder *encoder);
* sde_encoder_kickoff - trigger a double buffer flip of the ctl path
* (i.e. ctl flush and start) immediately.
* @encoder: encoder pointer
* @is_error: whether the current commit needs to be aborted and replaced
* with a 'safe' commit
* @config_changed: if true new configuration is applied on the control path
*/
void sde_encoder_kickoff(struct drm_encoder *encoder, bool is_error,
bool config_changed);
void sde_encoder_kickoff(struct drm_encoder *encoder, bool config_changed);
/**
* sde_encoder_wait_for_event - Waits for encoder events
@@ -515,15 +512,23 @@ bool sde_encoder_is_cwb_disabling(struct drm_encoder *drm_enc,
* sde_encoder_is_primary_display - checks if underlying display is primary
* display or not.
* @drm_enc: Pointer to drm encoder structure
* @Return: true if it is primary display. false if secondary display
* @Return: true if it is primary display. false otherwise
*/
bool sde_encoder_is_primary_display(struct drm_encoder *enc);
/**
* sde_encoder_is_built_in_display - checks if underlying display is built in
* display or not.
* @drm_enc: Pointer to drm encoder structure
* @Return: true if it is a built in display. false otherwise
*/
bool sde_encoder_is_built_in_display(struct drm_encoder *enc);
/**
* sde_encoder_is_dsi_display - checks if underlying display is DSI
* display or not.
* @drm_enc: Pointer to drm encoder structure
* @Return: true if it is primary display. false if secondary display
* @Return: true if it is a dsi display. false otherwise
*/
bool sde_encoder_is_dsi_display(struct drm_encoder *enc);

Ver fichero

@@ -804,6 +804,13 @@ static inline bool sde_encoder_phys_needs_single_flush(
void sde_encoder_helper_phys_disable(struct sde_encoder_phys *phys_enc,
struct sde_encoder_phys_wb *wb_enc);
/**
* sde_encoder_helper_phys_reset - helper function to reset virt encoder
* if vsync is missing on phys encoder
* @phys_enc: Pointer to physical encoder structure
*/
void sde_encoder_helper_phys_reset(struct sde_encoder_phys *phys_enc);
/**
* sde_encoder_helper_setup_misr - helper function to setup misr
* @phys_enc: Pointer to physical encoder structure

Ver fichero

@@ -920,6 +920,18 @@ static int sde_encoder_phys_vid_wait_for_vblank(
return _sde_encoder_phys_vid_wait_for_vblank(phys_enc, true);
}
static int sde_encoder_phys_vid_wait_for_commit_done(
struct sde_encoder_phys *phys_enc)
{
int rc;
rc = _sde_encoder_phys_vid_wait_for_vblank(phys_enc, true);
if (rc)
sde_encoder_helper_phys_reset(phys_enc);
return rc;
}
static int sde_encoder_phys_vid_wait_for_vblank_no_notify(
struct sde_encoder_phys *phys_enc)
{
@@ -1310,7 +1322,7 @@ static void sde_encoder_phys_vid_init_ops(struct sde_encoder_phys_ops *ops)
ops->destroy = sde_encoder_phys_vid_destroy;
ops->get_hw_resources = sde_encoder_phys_vid_get_hw_resources;
ops->control_vblank_irq = sde_encoder_phys_vid_control_vblank_irq;
ops->wait_for_commit_done = sde_encoder_phys_vid_wait_for_vblank;
ops->wait_for_commit_done = sde_encoder_phys_vid_wait_for_commit_done;
ops->wait_for_vblank = sde_encoder_phys_vid_wait_for_vblank_no_notify;
ops->wait_for_tx_complete = sde_encoder_phys_vid_wait_for_vblank;
ops->irq_control = sde_encoder_phys_vid_irq_control;

Ver fichero

@@ -337,6 +337,8 @@ static int sde_hw_lm_setup_noise_layer(struct sde_hw_mixer *ctx,
SDE_REG_WRITE(c, LM_BLEND0_CONST_ALPHA + stage_off, alpha);
val = ctx->cfg.out_width | (ctx->cfg.out_height << 16);
SDE_REG_WRITE(c, LM_FG_COLOR_FILL_SIZE + stage_off, val);
/* partial update is not supported in noise layer */
SDE_REG_WRITE(c, LM_FG_COLOR_FILL_XY + stage_off, 0);
val = SDE_REG_READ(c, LM_OP_MODE);
val = (1 << cfg->noise_blend_stage) | val;
SDE_REG_WRITE(c, LM_OP_MODE, val);
@@ -359,6 +361,8 @@ static int sde_hw_lm_setup_noise_layer(struct sde_hw_mixer *ctx,
SDE_REG_WRITE(c, LM_OP_MODE, val);
val = ctx->cfg.out_width | (ctx->cfg.out_height << 16);
SDE_REG_WRITE(c, LM_FG_COLOR_FILL_SIZE + stage_off, val);
/* partial update is not supported in noise layer */
SDE_REG_WRITE(c, LM_FG_COLOR_FILL_XY + stage_off, 0);
val = 1;
if (mixer->right_mixer)

Ver fichero

@@ -277,19 +277,40 @@ void sde_rm_get_resource_info(struct sde_rm *rm,
struct sde_rm_hw_blk *blk;
enum sde_hw_blk_type type;
struct sde_rm_rsvp rsvp;
const struct sde_lm_cfg *lm_cfg;
bool is_built_in, is_pref;
u32 lm_pref = (BIT(SDE_DISP_PRIMARY_PREF) | BIT(SDE_DISP_SECONDARY_PREF));
/* Get all currently available resources */
memcpy(avail_res, &rm->avail_res,
sizeof(rm->avail_res));
if (!drm_enc)
return;
is_built_in = sde_encoder_is_built_in_display(drm_enc);
rsvp.enc_id = drm_enc->base.id;
for (type = 0; type < SDE_HW_BLK_MAX; type++)
list_for_each_entry(blk, &rm->hw_blks[type], list)
for (type = 0; type < SDE_HW_BLK_MAX; type++) {
list_for_each_entry(blk, &rm->hw_blks[type], list) {
/* Add back resources allocated to the given encoder */
if (blk->rsvp && blk->rsvp->enc_id == rsvp.enc_id)
_sde_rm_inc_resource_info(rm, avail_res, blk);
/**
* Remove unallocated preferred lms that cannot reserved
* by non built-in displays.
*/
if (type == SDE_HW_BLK_LM) {
lm_cfg = to_sde_hw_mixer(blk->hw)->cap;
is_pref = lm_cfg->features & lm_pref;
if (!blk->rsvp && !is_built_in && is_pref)
_sde_rm_dec_resource_info(rm, avail_res, blk);
}
}
}
}
static void _sde_rm_print_rsvps(

Ver fichero

@@ -119,11 +119,11 @@ enum sde_dbg_dump_context {
* entry array access.
*/
#if IS_ENABLED(CONFIG_DRM_SDE_VM)
#if IS_ENABLED(CONFIG_DRM_MSM_LOW_MEM_FOOTPRINT)
#define SDE_EVTLOG_ENTRY (SDE_EVTLOG_PRINT_ENTRY * 8)
#else
#define SDE_EVTLOG_ENTRY (SDE_EVTLOG_PRINT_ENTRY * 32)
#endif /* IS_ENABLED(CONFIG_DRM_SDE_VM) */
#endif /* IS_ENABLED(CONFIG_DRM_MSM_LOW_MEM_FOOTPRINT) */
#define SDE_EVTLOG_MAX_DATA 15
#define SDE_EVTLOG_BUF_MAX 512
@@ -169,11 +169,11 @@ extern struct sde_dbg_evtlog *sde_dbg_base_evtlog;
* number must be greater than number of possible writes in at least one
* single commit.
*/
#if IS_ENABLED(CONFIG_DRM_SDE_VM)
#if IS_ENABLED(CONFIG_DRM_MSM_LOW_MEM_FOOTPRINT)
#define SDE_REGLOG_ENTRY 256
#else
#define SDE_REGLOG_ENTRY 1024
#endif /* IS_ENABLED(CONFIG_DRM_SDE_VM) */
#endif /* IS_ENABLED(CONFIG_DRM_MSM_LOW_MEM_FOOTPRINT) */
struct sde_dbg_reglog_log {
s64 time;

Ver fichero

@@ -800,6 +800,32 @@ void sde_power_resource_deinit(struct platform_device *pdev,
sde_rsc_client_destroy(phandle->rsc_client);
}
static void sde_power_mmrm_reserve(struct sde_power_handle *phandle)
{
int i;
struct dss_module_power *mp = &phandle->mp;
u64 rate = phandle->mmrm_reserve.clk_rate;
if (!phandle->mmrm_enable)
return;
for (i = 0; i < mp->num_clk; i++) {
if (!strcmp(mp->clk_config[i].clk_name, phandle->mmrm_reserve.clk_name)) {
if (mp->clk_config[i].max_rate)
rate = min(rate, (u64)mp->clk_config[i].max_rate);
mp->clk_config[i].rate = rate;
mp->clk_config[i].mmrm.flags =
MMRM_CLIENT_DATA_FLAG_RESERVE_ONLY;
SDE_ATRACE_BEGIN("sde_clk_set_rate");
msm_dss_single_clk_set_rate(&mp->clk_config[i]);
SDE_ATRACE_END("sde_clk_set_rate");
break;
}
}
}
int sde_power_scale_reg_bus(struct sde_power_handle *phandle,
u32 usecase_ndx, bool skip_lock)
{
@@ -897,6 +923,7 @@ int sde_power_resource_enable(struct sde_power_handle *phandle, bool enable)
SDE_EVT32_VERBOSE(enable, SDE_EVTLOG_FUNC_CASE2);
sde_power_rsc_update(phandle, false);
sde_power_mmrm_reserve(phandle);
msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
sde_power_scale_reg_bus(phandle, VOTE_INDEX_DISABLE, true);
@@ -936,6 +963,25 @@ vreg_err:
return rc;
}
int sde_power_clk_reserve_rate(struct sde_power_handle *phandle, char *clock_name, u64 rate)
{
if (!phandle) {
pr_err("invalid input power handle\n");
return -EINVAL;
} else if (!phandle->mmrm_enable) {
pr_debug("mmrm disabled, return early\n");
return 0;
}
mutex_lock(&phandle->phandle_lock);
phandle->mmrm_reserve.clk_rate = rate;
strlcpy(phandle->mmrm_reserve.clk_name, clock_name,
sizeof(phandle->mmrm_reserve.clk_name));
mutex_unlock(&phandle->phandle_lock);
return 0;
}
int sde_power_clk_set_rate(struct sde_power_handle *phandle, char *clock_name,
u64 rate, u32 flags)
{

Ver fichero

@@ -147,6 +147,16 @@ struct sde_power_event {
bool active;
};
/*
* struct sde_power_mmrm_reserve - mmrm resource reservation for clk and bw
* @clk_name: name of resource reservation clock
* @clk_rate: resource reservation clock rate
*/
struct sde_power_mmrm_reserve {
char clk_name[32];
u64 clk_rate;
};
/**
* struct sde_power_handle: power handle main struct
* @mp: module power for clock and regulator
@@ -159,6 +169,7 @@ struct sde_power_event {
* @rsc_client_init: boolean to control rsc client create
* @mmrm_enable: boolean to indicate if mmrm is enabled
* @ib_quota: ib quota of the given bus
* @mmrm_reserve: mmrm resource reservation
*/
struct sde_power_handle {
struct dss_module_power mp;
@@ -173,6 +184,8 @@ struct sde_power_handle {
bool rsc_client_init;
bool mmrm_enable;
u64 ib_quota[SDE_POWER_HANDLE_DBUS_ID_MAX];
struct sde_power_mmrm_reserve mmrm_reserve;
};
/**
@@ -226,6 +239,16 @@ int sde_power_scale_reg_bus(struct sde_power_handle *phandle,
int sde_power_data_bus_state_update(struct sde_power_handle *phandle,
bool enable);
/**
* sde_power_clk_reserve_rate() - reserve the clock rate with mmrm
* @pdata: power handle containing the resources
* @clock_name: clock name which needs rate update.
* @rate: Requested rate.
*
* Return: error code.
*/
int sde_power_clk_reserve_rate(struct sde_power_handle *pdata, char *clock_name, u64 rate);
/**
* sde_power_clk_set_rate() - set the clock rate
* @pdata: power handle containing the resources