Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a9f975ad authored by Jeykumar Sankaran's avatar Jeykumar Sankaran Committed by Steve Cohen
Browse files

drm/msm/sde: add connector property to expose custom mode info



SDE DRM doesn't expose custom mode info of a display mode by default.
It populates the information only after the client selects the mode
for the display. This forces the client to invoke a dummy atomic commit
just to set the mode and re-read the connector properties to know the
custom mode info. This change avoids the dummy commit by exposing the
custom mode info of all the display modes through a separate blob
property.

Change-Id: I08b5c5f14b7134364827a55f1b41fbfd7b92a980
Signed-off-by: default avatarJeykumar Sankaran <jsanka@codeaurora.org>
Signed-off-by: default avatarLloyd Atkinson <latkinso@codeaurora.org>
parent b45d0f25
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -162,6 +162,7 @@ enum msm_mdp_crtc_property {
enum msm_mdp_conn_property {
	/* blob properties, always put these first */
	CONNECTOR_PROP_SDE_INFO,
	CONNECTOR_PROP_MODE_INFO,
	CONNECTOR_PROP_HDR_INFO,
	CONNECTOR_PROP_EXT_HDR_INFO,
	CONNECTOR_PROP_PP_DITHER,
+178 −36
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include "dsi_drm.h"
#include "dsi_display.h"
#include "sde_crtc.h"
#include "sde_rm.h"

#define BL_NODE_NAME_SIZE 32

@@ -618,6 +619,8 @@ static void sde_connector_destroy(struct drm_connector *connector)
		drm_property_unreference_blob(c_conn->blob_hdr);
	if (c_conn->blob_dither)
		drm_property_unreference_blob(c_conn->blob_dither);
	if (c_conn->blob_mode_info)
		drm_property_unreference_blob(c_conn->blob_mode_info);
	msm_property_destroy(&c_conn->property_info);

	if (c_conn->bl_device)
@@ -1352,12 +1355,39 @@ static void sde_connector_early_unregister(struct drm_connector *connector)
	/* debugfs under connector->debugfs are deleted by drm_debugfs */
}

static int sde_connector_fill_modes(struct drm_connector *connector,
		uint32_t max_width, uint32_t max_height)
{
	int rc, mode_count = 0;
	struct sde_connector *sde_conn = NULL;

	sde_conn = to_sde_connector(connector);
	if (!sde_conn) {
		SDE_ERROR("invalid arguments\n");
		return 0;
	}

	mode_count = drm_helper_probe_single_connector_modes(connector,
			max_width, max_height);

	rc = sde_connector_set_blob_data(connector,
				connector->state,
				CONNECTOR_PROP_MODE_INFO);
	if (rc) {
		SDE_ERROR_CONN(sde_conn,
			"failed to setup mode info prop, rc = %d\n", rc);
		return 0;
	}

	return mode_count;
}

static const struct drm_connector_funcs sde_connector_ops = {
	.dpms =                   sde_connector_dpms,
	.reset =                  sde_connector_atomic_reset,
	.detect =                 sde_connector_detect,
	.destroy =                sde_connector_destroy,
	.fill_modes =             drm_helper_probe_single_connector_modes,
	.fill_modes =             sde_connector_fill_modes,
	.atomic_duplicate_state = sde_connector_atomic_duplicate_state,
	.atomic_destroy_state =   sde_connector_atomic_destroy_state,
	.atomic_set_property =    sde_connector_atomic_set_property,
@@ -1370,7 +1400,7 @@ static const struct drm_connector_funcs sde_connector_ops = {
static int sde_connector_get_modes(struct drm_connector *connector)
{
	struct sde_connector *c_conn;
	int ret = 0;
	int mode_count = 0;

	if (!connector) {
		SDE_ERROR("invalid connector\n");
@@ -1382,11 +1412,16 @@ static int sde_connector_get_modes(struct drm_connector *connector)
		SDE_DEBUG("missing get_modes callback\n");
		return 0;
	}
	ret = c_conn->ops.get_modes(connector, c_conn->display);
	if (ret)

	mode_count = c_conn->ops.get_modes(connector, c_conn->display);
	if (!mode_count) {
		SDE_ERROR_CONN(c_conn, "failed to get modes\n");
		return 0;
	}

	sde_connector_update_hdr_props(connector);

	return ret;
	return mode_count;
}

static enum drm_mode_status
@@ -1483,13 +1518,90 @@ static const struct drm_connector_helper_funcs sde_connector_helper_ops = {
	.best_encoder = sde_connector_best_encoder,
};

int sde_connector_set_info(struct drm_connector *conn,
				struct drm_connector_state *state)
static int sde_connector_populate_mode_info(struct drm_connector *conn,
	struct sde_kms_info *info)
{
	struct msm_drm_private *priv;
	struct sde_kms *sde_kms;
	struct sde_connector *c_conn = NULL;
	struct drm_display_mode *mode;
	struct msm_mode_info mode_info;
	int rc = 0;

	if (!conn || !conn->dev || !conn->dev->dev_private) {
		SDE_ERROR("invalid arguments\n");
		return -EINVAL;
	}

	priv = conn->dev->dev_private;
	sde_kms = to_sde_kms(priv->kms);

	c_conn = to_sde_connector(conn);
	if (!c_conn->ops.get_mode_info) {
		SDE_ERROR_CONN(c_conn, "get_mode_info not defined\n");
		return -EINVAL;
	}

	list_for_each_entry(mode, &conn->modes, head) {
		int topology_idx = 0;

		memset(&mode_info, 0, sizeof(mode_info));

		rc = c_conn->ops.get_mode_info(mode, &mode_info,
			sde_kms->catalog->max_mixer_width,
			c_conn->display);
		if (rc) {
			SDE_ERROR_CONN(c_conn,
				"failed to get mode info for mode %s\n",
				mode->name);
			continue;
		}

		sde_kms_info_add_keystr(info, "mode_name", mode->name);

		topology_idx = (int)sde_rm_get_topology_name(
							mode_info.topology);
		if (topology_idx < SDE_RM_TOPOLOGY_MAX) {
			sde_kms_info_add_keystr(info, "topology",
					e_topology_name[topology_idx].name);
		} else {
			SDE_ERROR_CONN(c_conn, "invalid topology\n");
			continue;
		}

		if (!mode_info.roi_caps.num_roi)
			continue;

		sde_kms_info_add_keyint(info, "partial_update_num_roi",
			mode_info.roi_caps.num_roi);
		sde_kms_info_add_keyint(info, "partial_update_xstart",
			mode_info.roi_caps.align.xstart_pix_align);
		sde_kms_info_add_keyint(info, "partial_update_walign",
			mode_info.roi_caps.align.width_pix_align);
		sde_kms_info_add_keyint(info, "partial_update_wmin",
			mode_info.roi_caps.align.min_width);
		sde_kms_info_add_keyint(info, "partial_update_ystart",
			mode_info.roi_caps.align.ystart_pix_align);
		sde_kms_info_add_keyint(info, "partial_update_halign",
			mode_info.roi_caps.align.height_pix_align);
		sde_kms_info_add_keyint(info, "partial_update_hmin",
			mode_info.roi_caps.align.min_height);
		sde_kms_info_add_keyint(info, "partial_update_roimerge",
			mode_info.roi_caps.merge_rois);
	}

	return rc;
}

int sde_connector_set_blob_data(struct drm_connector *conn,
		struct drm_connector_state *state,
		enum msm_mdp_conn_property prop_id)
{
	struct sde_kms_info *info;
	struct sde_connector *c_conn = NULL;
	struct sde_connector_state *sde_conn_state = NULL;
	struct msm_mode_info mode_info;
	struct drm_property_blob *blob = NULL;
	int rc = 0;

	c_conn = to_sde_connector(conn);
@@ -1498,43 +1610,64 @@ int sde_connector_set_info(struct drm_connector *conn,
		return -EINVAL;
	}

	if (!c_conn->ops.post_init) {
		SDE_DEBUG_CONN(c_conn, "post_init not defined\n");
		return 0;
	}

	memset(&mode_info, 0, sizeof(mode_info));

	info = kzalloc(sizeof(*info), GFP_KERNEL);
	if (!info)
		return -ENOMEM;

	sde_kms_info_reset(info);

	switch (prop_id) {
	case CONNECTOR_PROP_SDE_INFO:
		memset(&mode_info, 0, sizeof(mode_info));

		if (state) {
			sde_conn_state = to_sde_connector_state(state);
			memcpy(&mode_info, &sde_conn_state->mode_info,
					sizeof(sde_conn_state->mode_info));
		} else {
			/**
		 * connector state is assigned only on first atomic_commit.
		 * But this function is allowed to be invoked during
		 * probe/init sequence. So not throwing an error.
			 * connector state is assigned only on first
			 * atomic_commit. But this function is allowed to be
			 * invoked during probe/init sequence. So not throwing
			 * an error.
			 */
			SDE_DEBUG_CONN(c_conn, "invalid connector state\n");
		}

	sde_kms_info_reset(info);
	rc = c_conn->ops.post_init(&c_conn->base, info,
			c_conn->display, &mode_info);
		if (!c_conn->ops.post_init) {
			SDE_ERROR_CONN(c_conn, "post_init not defined\n");
			goto exit;
		}

		rc = c_conn->ops.post_init(conn, info, c_conn->display,
				&mode_info);
		if (rc) {
			SDE_ERROR_CONN(c_conn, "post-init failed, %d\n", rc);
			goto exit;
		}

		blob = c_conn->blob_caps;
	break;
	case CONNECTOR_PROP_MODE_INFO:
		rc = sde_connector_populate_mode_info(conn, info);
		if (rc) {
			SDE_ERROR_CONN(c_conn,
					"mode info population failed, %d\n",
					rc);
			goto exit;
		}
		blob = c_conn->blob_mode_info;
	break;
	default:
		SDE_ERROR_CONN(c_conn, "invalid prop_id: %d\n", prop_id);
		goto exit;
	};

	msm_property_set_blob(&c_conn->property_info,
			&c_conn->blob_caps,
			&blob,
			SDE_KMS_INFO_DATA(info),
			SDE_KMS_INFO_DATALEN(info),
			CONNECTOR_PROP_SDE_INFO);
			prop_id);
exit:
	kfree(info);

@@ -1652,13 +1785,20 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,
			DRM_MODE_PROP_IMMUTABLE,
			CONNECTOR_PROP_SDE_INFO);

	rc = sde_connector_set_info(&c_conn->base, c_conn->base.state);
	rc = sde_connector_set_blob_data(&c_conn->base,
			NULL,
			CONNECTOR_PROP_SDE_INFO);
	if (rc) {
		SDE_ERROR_CONN(c_conn,
			"failed to setup connector info, rc = %d\n", rc);
		goto error_cleanup_fence;
	}

	msm_property_install_blob(&c_conn->property_info,
			"mode_properties",
			DRM_MODE_PROP_IMMUTABLE,
			CONNECTOR_PROP_MODE_INFO);

	if (connector_type == DRM_MODE_CONNECTOR_DSI) {
		dsi_display = (struct dsi_display *)(display);
		if (dsi_display && dsi_display->panel &&
@@ -1753,6 +1893,8 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,
		drm_property_unreference_blob(c_conn->blob_hdr);
	if (c_conn->blob_dither)
		drm_property_unreference_blob(c_conn->blob_dither);
	if (c_conn->blob_mode_info)
		drm_property_unreference_blob(c_conn->blob_mode_info);

	msm_property_destroy(&c_conn->property_info);
error_cleanup_fence:
+7 −3
Original line number Diff line number Diff line
@@ -271,6 +271,7 @@ struct sde_connector_evt {
 * @blob_hdr: Pointer to blob structure for 'hdr_properties' property
 * @blob_ext_hdr: Pointer to blob structure for 'ext_hdr_properties' property
 * @blob_dither: Pointer to blob structure for default dither config
 * @blob_mode_info: Pointer to blob structure for mode info
 * @fb_kmap: true if kernel mapping of framebuffer is requested
 * @event_table: Array of registered events
 * @event_lock: Lock object for event_table
@@ -304,6 +305,7 @@ struct sde_connector {
	struct drm_property_blob *blob_hdr;
	struct drm_property_blob *blob_ext_hdr;
	struct drm_property_blob *blob_dither;
	struct drm_property_blob *blob_mode_info;

	bool fb_kmap;
	struct sde_connector_evt event_table[SDE_CONN_EVENT_COUNT];
@@ -644,13 +646,15 @@ int sde_connector_get_dither_cfg(struct drm_connector *conn,
		struct drm_connector_state *state, void **cfg, size_t *len);

/**
 * sde_connector_set_info - set connector property value
 * sde_connector_set_blob_data - set connector blob property data
 * @conn: Pointer to drm_connector struct
 * @state: Pointer to the drm_connector_state struct
 * @prop_id: property id to be populated
 * Returns: Zero on success
 */
int sde_connector_set_info(struct drm_connector *conn,
		struct drm_connector_state *state);
int sde_connector_set_blob_data(struct drm_connector *conn,
		struct drm_connector_state *state,
		enum msm_mdp_conn_property prop_id);

/**
 * sde_connector_roi_v1_check_roi - validate connector ROI
+3 −1
Original line number Diff line number Diff line
@@ -882,7 +882,9 @@ static int sde_encoder_virt_atomic_check(
			return ret;
		}

		ret = sde_connector_set_info(conn_state->connector, conn_state);
		ret = sde_connector_set_blob_data(conn_state->connector,
				conn_state,
				CONNECTOR_PROP_SDE_INFO);
		if (ret) {
			SDE_ERROR_ENC(sde_enc,
				"connector failed to update info, rc: %d\n",
+12 −0
Original line number Diff line number Diff line
@@ -175,6 +175,18 @@ void sde_rm_init_hw_iter(
	iter->type = type;
}

enum sde_rm_topology_name sde_rm_get_topology_name(
	struct msm_display_topology topology)
{
	int i;

	for (i = 0; i < SDE_RM_TOPOLOGY_MAX; i++)
		if (RM_IS_TOPOLOGY_MATCH(g_top_table[i], topology))
			return g_top_table[i].top_name;

	return SDE_RM_TOPOLOGY_NONE;
}

static bool _sde_rm_get_hw_locked(struct sde_rm *rm, struct sde_rm_hw_iter *i)
{
	struct list_head *blk_list;
Loading