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

Commit 13924778 authored by Steve Cohen's avatar Steve Cohen Committed by Dhaval Patel
Browse files

drm/msm/sde: add drm property for multirect mode



Since SDE DRM client is responsible for clock bandwidth
calculation and voting, the client must always be in
sync with the multirect mode programmed to hardware
in order to honor the vote.  This patch allows the
client to select the desired mode. It will fallback
to sde driver multirect mode selection if client
does not set property but uses the multirect plane.

Change-Id: I33ada26b5d0aa8ecffbb7e90dc345d57fb4a74e0
Signed-off-by: default avatarSteve Cohen <cohens@codeaurora.org>
Signed-off-by: default avatarDhaval Patel <pdhaval@codeaurora.org>
parent 87b21110
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -122,6 +122,7 @@ enum msm_mdp_plane_property {
	PLANE_PROP_BLEND_OP,
	PLANE_PROP_SRC_CONFIG,
	PLANE_PROP_FB_TRANSLATION_MODE,
	PLANE_PROP_MULTIRECT_MODE,

	/* total # of properties */
	PLANE_PROP_COUNT
+108 −41
Original line number Diff line number Diff line
@@ -58,6 +58,9 @@

#define SDE_PLANE_COLOR_FILL_FLAG	BIT(31)

#define TIME_MULTIPLEX_RECT(r0, r1, buffer_lines) \
	 ((r0).y >= ((r1).y + (r1).h + buffer_lines))

/* multirect rect index */
enum {
	R0,
@@ -2780,6 +2783,12 @@ void sde_plane_clear_multirect(const struct drm_plane_state *drm_state)
	pstate->multirect_mode = SDE_SSPP_MULTIRECT_NONE;
}

/**
 * multi_rect validate API allows to validate only R0 and R1 RECT
 * passing for each plane. Client of this API must not pass multiple
 * plane which are not sharing same XIN client. Such calls will fail
 * even though kernel client is passing valid multirect configuration.
 */
int sde_plane_validate_multirect_v2(struct sde_multirect_plane_states *plane)
{
	struct sde_plane_state *pstate[R_MAX];
@@ -2787,37 +2796,44 @@ int sde_plane_validate_multirect_v2(struct sde_multirect_plane_states *plane)
	struct sde_rect src[R_MAX], dst[R_MAX];
	struct sde_plane *sde_plane[R_MAX];
	const struct sde_format *fmt[R_MAX];
	int xin_id[R_MAX];
	bool q16_data = true;
	int i, buffer_lines;
	int i, j, buffer_lines, width_threshold[R_MAX];
	unsigned int max_tile_height = 1;
	bool parallel_fetch_qualified = true;
	bool has_tiled_rect = false;

	for (i = 0; i < R_MAX; i++) {
	enum sde_sspp_multirect_mode mode = SDE_SSPP_MULTIRECT_NONE;
	const struct msm_format *msm_fmt;

	for (i = 0; i < R_MAX; i++) {
		drm_state[i] = i ? plane->r1 : plane->r0;
		msm_fmt = msm_framebuffer_format(drm_state[i]->fb);
		fmt[i] = to_sde_format(msm_fmt);

		if (SDE_FORMAT_IS_UBWC(fmt[i])) {
			has_tiled_rect = true;
			if (fmt[i]->tile_height > max_tile_height)
				max_tile_height = fmt[i]->tile_height;
		}
		if (!drm_state[i]) {
			SDE_ERROR("drm plane state is NULL\n");
			return -EINVAL;
		}

	for (i = 0; i < R_MAX; i++) {
		int width_threshold;

		pstate[i] = to_sde_plane_state(drm_state[i]);
		sde_plane[i] = to_sde_plane(drm_state[i]->plane);
		xin_id[i] = sde_plane[i]->pipe_hw->cap->xin_id;

		if (pstate[i] == NULL) {
			SDE_ERROR("SDE plane state of plane id %d is NULL\n",
				drm_state[i]->plane->base.id);
		for (j = 0; j < i; j++) {
			if (xin_id[i] != xin_id[j]) {
				SDE_ERROR_PLANE(sde_plane[i],
					"invalid multirect validate call base:%d xin_id:%d curr:%d xin:%d\n",
					j, xin_id[j], i, xin_id[i]);
				return -EINVAL;
			}
		}

		msm_fmt = msm_framebuffer_format(drm_state[i]->fb);
		if (!msm_fmt) {
			SDE_ERROR_PLANE(sde_plane[i], "null fb\n");
			return -EINVAL;
		}
		fmt[i] = to_sde_format(msm_fmt);

		if (SDE_FORMAT_IS_UBWC(fmt[i]) &&
		    (fmt[i]->tile_height > max_tile_height))
			max_tile_height = fmt[i]->tile_height;

		POPULATE_RECT(&src[i], drm_state[i]->src_x, drm_state[i]->src_y,
			drm_state[i]->src_w, drm_state[i]->src_h, q16_data);
@@ -2844,41 +2860,81 @@ int sde_plane_validate_multirect_v2(struct sde_multirect_plane_states *plane)
		 * So we cannot support more than half of the supported SSPP
		 * width for tiled formats.
		 */
		width_threshold = sde_plane[i]->pipe_sblk->maxlinewidth;
		if (has_tiled_rect)
			width_threshold /= 2;
		width_threshold[i] = sde_plane[i]->pipe_sblk->maxlinewidth;
		if (SDE_FORMAT_IS_UBWC(fmt[i]))
			width_threshold[i] /= 2;

		if (parallel_fetch_qualified && src[i].w > width_threshold)
		if (parallel_fetch_qualified && src[i].w > width_threshold[i])
			parallel_fetch_qualified = false;

		if (sde_plane[i]->is_virtual)
			mode = sde_plane_get_property(pstate[i],
					PLANE_PROP_MULTIRECT_MODE);
	}

	/* Validate RECT's and set the mode */

	/* Prefer PARALLEL FETCH Mode over TIME_MX Mode */
	if (parallel_fetch_qualified) {
		pstate[R0]->multirect_mode = SDE_SSPP_MULTIRECT_PARALLEL;
		pstate[R1]->multirect_mode = SDE_SSPP_MULTIRECT_PARALLEL;

		goto done;
	}

	/* TIME_MX Mode */
	buffer_lines = 2 * max_tile_height;

	if ((dst[R1].y >= dst[R0].y + dst[R0].h + buffer_lines) ||
		(dst[R0].y >= dst[R1].y + dst[R1].h + buffer_lines)) {
		pstate[R0]->multirect_mode = SDE_SSPP_MULTIRECT_TIME_MX;
		pstate[R1]->multirect_mode = SDE_SSPP_MULTIRECT_TIME_MX;
	} else {
	/**
	 * fallback to driver mode selection logic if client is using
	 * multirect plane without setting property.
	 *
	 * validate multirect mode configuration based on rectangle
	 */
	switch (mode) {
	case SDE_SSPP_MULTIRECT_NONE:
		if (parallel_fetch_qualified)
			mode = SDE_SSPP_MULTIRECT_PARALLEL;
		else if (TIME_MULTIPLEX_RECT(dst[R1], dst[R0], buffer_lines) ||
			 TIME_MULTIPLEX_RECT(dst[R0], dst[R1], buffer_lines))
			mode = SDE_SSPP_MULTIRECT_TIME_MX;
		else
			SDE_ERROR(
			"No multirect mode possible for the planes (%d - %d)\n",
				"planes(%d - %d) multirect mode selection fail\n",
				drm_state[R0]->plane->base.id,
				drm_state[R1]->plane->base.id);
		return -EINVAL;
		break;

	case SDE_SSPP_MULTIRECT_PARALLEL:
		if (!parallel_fetch_qualified) {
			SDE_ERROR("R0 plane:%d width_threshold:%d src_w:%d\n",
				drm_state[R0]->plane->base.id,
				width_threshold[R0],  src[R0].w);
			SDE_ERROR("R1 plane:%d width_threshold:%d src_w:%d\n",
				drm_state[R1]->plane->base.id,
				width_threshold[R1],  src[R1].w);
			SDE_ERROR("parallel fetch not qualified\n");
			mode = SDE_SSPP_MULTIRECT_NONE;
		}
		break;

	case SDE_SSPP_MULTIRECT_TIME_MX:
		if (!TIME_MULTIPLEX_RECT(dst[R1], dst[R0], buffer_lines) &&
		    !TIME_MULTIPLEX_RECT(dst[R0], dst[R1], buffer_lines)) {
			SDE_ERROR(
				"buffer_lines:%d R0 plane:%d dst_y:%d dst_h:%d\n",
				buffer_lines, drm_state[R0]->plane->base.id,
				dst[R0].y, dst[R0].h);
			SDE_ERROR(
				"buffer_lines:%d R1 plane:%d dst_y:%d dst_h:%d\n",
				buffer_lines, drm_state[R1]->plane->base.id,
				dst[R1].y, dst[R1].h);
			SDE_ERROR("time multiplexed fetch not qualified\n");
			mode = SDE_SSPP_MULTIRECT_NONE;
		}
		break;

	default:
		SDE_ERROR("bad mode:%d selection\n", mode);
		mode = SDE_SSPP_MULTIRECT_NONE;
		break;
	}

	for (i = 0; i < R_MAX; i++)
		pstate[i]->multirect_mode = mode;

	if (mode == SDE_SSPP_MULTIRECT_NONE)
		return -EINVAL;

done:
	if (sde_plane[R0]->is_virtual) {
		pstate[R0]->multirect_index = SDE_SSPP_RECT_1;
		pstate[R1]->multirect_index = SDE_SSPP_RECT_0;
@@ -2891,6 +2947,7 @@ int sde_plane_validate_multirect_v2(struct sde_multirect_plane_states *plane)
		pstate[R0]->multirect_mode, pstate[R0]->multirect_index);
	SDE_DEBUG_PLANE(sde_plane[R1], "R1: %d - %d\n",
		pstate[R1]->multirect_mode, pstate[R1]->multirect_index);

	return 0;
}

@@ -3602,6 +3659,7 @@ static int sde_plane_sspp_atomic_update(struct drm_plane *plane,
		case PLANE_PROP_CSC_V1:
			pstate->dirty |= SDE_PLANE_DIRTY_FORMAT;
			break;
		case PLANE_PROP_MULTIRECT_MODE:
		case PLANE_PROP_COLOR_FILL:
			/* potentially need to refresh everything */
			pstate->dirty = SDE_PLANE_DIRTY_ALL;
@@ -4022,6 +4080,11 @@ static void _sde_plane_install_properties(struct drm_plane *plane,
		{SDE_DRM_FB_NON_SEC_DIR_TRANS, "non_sec_direct_translation"},
		{SDE_DRM_FB_SEC_DIR_TRANS, "sec_direct_translation"},
	};
	static const struct drm_prop_enum_list e_multirect_mode[] = {
		{SDE_SSPP_MULTIRECT_NONE, "none"},
		{SDE_SSPP_MULTIRECT_PARALLEL, "parallel"},
		{SDE_SSPP_MULTIRECT_TIME_MX,  "serial"},
	};
	const struct sde_format_extended *format_list;
	struct sde_kms_info *info;
	struct sde_plane *psde = to_sde_plane(plane);
@@ -4171,6 +4234,10 @@ static void _sde_plane_install_properties(struct drm_plane *plane,
		format_list = psde->pipe_sblk->virt_format_list;
		sde_kms_info_add_keyint(info, "primary_smart_plane_id",
						master_plane_id);
		msm_property_install_enum(&psde->property_info,
			"multirect_mode", 0x0, 0, e_multirect_mode,
			ARRAY_SIZE(e_multirect_mode),
			PLANE_PROP_MULTIRECT_MODE);
	}

	if (format_list) {