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

Commit a5461ff9 authored by Kyle Yan's avatar Kyle Yan Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drm/msm/sde: add dim layer support" into msm-4.8

parents 6234e2c2 3171ff8f
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -118,6 +118,8 @@ Optional properties:
				control feature is available on each source pipe.
- qcom,sde-has-src-split:	Boolean property to indicate if source split
				feature is available or not.
- qcom,sde-has-dim-layer:	Boolean property to indicate if mixer has dim layer
				feature is available or not.
- qcom,sde-has-mixer-gc:	Boolean property to indicate if mixer has gamma correction
				feature available or not.
- qcom,sde-has-cdp:		Boolean property to indicate if cdp feature is
@@ -340,6 +342,7 @@ Example:
    qcom,sde-panic-per-pipe;
    qcom,sde-has-cdp;
    qcom,sde-has-src-split;
    qcom,sde-has-dim-layer;
    qcom,sde-sspp-src-size = <0x100>;
    qcom,sde-mixer-size = <0x100>;
    qcom,sde-ctl-size = <0x100>;
+1 −0
Original line number Diff line number Diff line
@@ -124,6 +124,7 @@ enum msm_mdp_crtc_property {
	CRTC_PROP_INPUT_FENCE_TIMEOUT = CRTC_PROP_BLOBCOUNT,
	CRTC_PROP_OUTPUT_FENCE,
	CRTC_PROP_OUTPUT_FENCE_OFFSET,
	CRTC_PROP_DIM_LAYER_V1,

	/* total # of properties */
	CRTC_PROP_COUNT
+195 −4
Original line number Diff line number Diff line
@@ -156,15 +156,78 @@ static void _sde_crtc_setup_blend_cfg(struct sde_crtc_mixer *mixer,
		format->alpha_enable, fg_alpha, bg_alpha, blend_op);
}

static void _sde_crtc_setup_dim_layer_cfg(struct drm_crtc *crtc,
		struct sde_crtc *sde_crtc, struct sde_crtc_mixer *mixer,
		struct sde_hw_dim_layer *dim_layer)
{
	struct sde_hw_mixer *lm;
	struct sde_rect mixer_rect;
	struct sde_hw_dim_layer split_dim_layer;
	u32 mixer_width, mixer_height;
	int i;

	if (!dim_layer->rect.w || !dim_layer->rect.h) {
		SDE_DEBUG("empty dim layer\n");
		return;
	}

	mixer_width = get_crtc_split_width(crtc);
	mixer_height = get_crtc_mixer_height(crtc);
	mixer_rect = (struct sde_rect) {0, 0, mixer_width, mixer_height};

	split_dim_layer.stage = dim_layer->stage;
	split_dim_layer.color_fill = dim_layer->color_fill;

	/*
	 * traverse through the layer mixers attached to crtc and find the
	 * intersecting dim layer rect in each LM and program accordingly.
	 */
	for (i = 0; i < sde_crtc->num_mixers; i++) {
		split_dim_layer.flags = dim_layer->flags;
		mixer_rect.x = i * mixer_width;

		sde_kms_rect_intersect(&split_dim_layer.rect, &mixer_rect,
					&dim_layer->rect);
		if (!split_dim_layer.rect.w && !split_dim_layer.rect.h) {
			/*
			 * no extra programming required for non-intersecting
			 * layer mixers with INCLUSIVE dim layer
			 */
			if (split_dim_layer.flags
					& SDE_DRM_DIM_LAYER_INCLUSIVE)
				continue;

			/*
			 * program the other non-intersecting layer mixers with
			 * INCLUSIVE dim layer of full size for uniformity
			 * with EXCLUSIVE dim layer config.
			 */
			split_dim_layer.flags &= ~SDE_DRM_DIM_LAYER_EXCLUSIVE;
			split_dim_layer.flags |= SDE_DRM_DIM_LAYER_INCLUSIVE;
			split_dim_layer.rect = (struct sde_rect) {0, 0,
						mixer_width, mixer_height};

		} else {
			split_dim_layer.rect.x = split_dim_layer.rect.x
							- (i * mixer_width);
		}

		lm = mixer[i].hw_lm;
		mixer[i].mixer_op_mode |= 1 << split_dim_layer.stage;
		lm->ops.setup_dim_layer(lm, &split_dim_layer);
	}
}

static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,
	struct sde_crtc *sde_crtc, struct sde_crtc_mixer *mixer)
{
	struct drm_plane *plane;

	struct sde_crtc_state *cstate;
	struct sde_plane_state *pstate = NULL;
	struct sde_format *format;
	struct sde_hw_ctl *ctl = mixer->hw_ctl;
	struct sde_hw_stage_cfg *stage_cfg = &sde_crtc->stage_cfg;
	struct sde_hw_ctl *ctl;
	struct sde_hw_mixer *lm;
	struct sde_hw_stage_cfg *stage_cfg;

	u32 flush_mask = 0, crtc_split_width;
	uint32_t lm_idx = LEFT_MIXER, idx;
@@ -172,7 +235,16 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,
	bool lm_right = false;
	int left_crtc_zpos_cnt[SDE_STAGE_MAX + 1] = {0};
	int right_crtc_zpos_cnt[SDE_STAGE_MAX + 1] = {0};
	int i;

	if (!sde_crtc || !mixer) {
		SDE_ERROR("invalid sde_crtc or mixer\n");
		return;
	}

	ctl = mixer->hw_ctl;
	lm = mixer->hw_lm;
	stage_cfg = &sde_crtc->stage_cfg;
	crtc_split_width = get_crtc_split_width(crtc);

	drm_atomic_crtc_for_each_plane(plane, crtc) {
@@ -246,6 +318,13 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,
			}
		}
	}

	if (lm && lm->ops.setup_dim_layer) {
		cstate = to_sde_crtc_state(crtc->state);
		for (i = 0; i < cstate->num_dim_layers; i++)
			_sde_crtc_setup_dim_layer_cfg(crtc, sde_crtc,
					mixer, &cstate->dim_layer[i]);
	}
}

/**
@@ -278,6 +357,11 @@ static void _sde_crtc_blend_setup(struct drm_crtc *crtc)
		if (mixer[i].hw_ctl->ops.clear_all_blendstages)
			mixer[i].hw_ctl->ops.clear_all_blendstages(
					mixer[i].hw_ctl);

		/* clear dim_layer settings */
		lm = mixer[i].hw_lm;
		if (lm->ops.clear_dim_layer)
			lm->ops.clear_dim_layer(lm);
	}

	/* initialize stage cfg */
@@ -432,6 +516,62 @@ static void _sde_crtc_set_input_fence_timeout(struct sde_crtc_state *cstate)
	cstate->input_fence_timeout_ns *= NSEC_PER_MSEC;
}

/**
 * _sde_crtc_set_dim_layer_v1 - copy dim layer settings from userspace
 * @cstate:      Pointer to sde crtc state
 * @user_ptr:    User ptr for sde_drm_dim_layer_v1 struct
 */
static void _sde_crtc_set_dim_layer_v1(struct sde_crtc_state *cstate,
		void *usr_ptr)
{
	struct sde_drm_dim_layer_v1 dim_layer_v1;
	struct sde_drm_dim_layer_cfg *user_cfg;
	u32 count, i;

	if (!cstate) {
		SDE_ERROR("invalid cstate\n");
		return;
	}

	if (!usr_ptr) {
		SDE_DEBUG("dim layer data removed\n");
		return;
	}

	if (copy_from_user(&dim_layer_v1, usr_ptr, sizeof(dim_layer_v1))) {
		SDE_ERROR("failed to copy dim layer data\n");
		return;
	}

	count = dim_layer_v1.num_layers;
	if (!count || (count > SDE_MAX_DIM_LAYERS)) {
		SDE_ERROR("invalid number of Dim Layers:%d", count);
		return;
	}

	/* populate from user space */
	cstate->num_dim_layers = count;
	for (i = 0; i < count; i++) {
		user_cfg = &dim_layer_v1.layer_cfg[i];
		cstate->dim_layer[i].flags = user_cfg->flags;
		cstate->dim_layer[i].stage = user_cfg->stage + SDE_STAGE_0;

		cstate->dim_layer[i].rect.x = user_cfg->rect.x1;
		cstate->dim_layer[i].rect.y = user_cfg->rect.y1;
		cstate->dim_layer[i].rect.w = user_cfg->rect.x2 -
						user_cfg->rect.x1 + 1;
		cstate->dim_layer[i].rect.h = user_cfg->rect.y2 -
						user_cfg->rect.y1 + 1;

		cstate->dim_layer[i].color_fill = (struct sde_mdss_color) {
				user_cfg->color_fill.color_0,
				user_cfg->color_fill.color_1,
				user_cfg->color_fill.color_2,
				user_cfg->color_fill.color_3,
		};
	}
}

/**
 * _sde_crtc_wait_for_fences - wait for incoming framebuffer sync fences
 * @crtc: Pointer to CRTC object
@@ -889,6 +1029,7 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc,
{
	struct sde_crtc *sde_crtc;
	struct plane_state pstates[SDE_STAGE_MAX * 2];
	struct sde_crtc_state *cstate;

	const struct drm_plane_state *pstate;
	struct drm_plane *plane;
@@ -910,6 +1051,7 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc,
	}

	sde_crtc = to_sde_crtc(crtc);
	cstate = to_sde_crtc_state(state);
	mode = &state->adjusted_mode;
	SDE_DEBUG("%s: check", sde_crtc->name);

@@ -930,6 +1072,18 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc,
		pstates[cnt].drm_pstate = pstate;
		pstates[cnt].stage = sde_plane_get_property(
				pstates[cnt].sde_pstate, PLANE_PROP_ZPOS);

		/* check dim layer stage with every plane */
		for (i = 0; i < cstate->num_dim_layers; i++) {
			if (pstates[cnt].stage == cstate->dim_layer[i].stage) {
				SDE_ERROR("plane%d/dimlayer in same stage:%d\n",
						plane->base.id,
						cstate->dim_layer[i].stage);
				rc = -EINVAL;
				goto end;
			}
		}

		cnt++;

		if (CHECK_LAYER_BOUNDS(pstate->crtc_y, pstate->crtc_h,
@@ -945,6 +1099,28 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc,
		}
	}

	/* Check dim layer rect bounds and stage */
	for (i = 0; i < cstate->num_dim_layers; i++) {
		if ((CHECK_LAYER_BOUNDS(cstate->dim_layer[i].rect.y,
			cstate->dim_layer[i].rect.h, mode->vdisplay)) ||
		    (CHECK_LAYER_BOUNDS(cstate->dim_layer[i].rect.x,
			cstate->dim_layer[i].rect.w, mode->hdisplay)) ||
		    (cstate->dim_layer[i].stage >= SDE_STAGE_MAX) ||
		    (!cstate->dim_layer[i].rect.w) ||
		    (!cstate->dim_layer[i].rect.h)) {
			SDE_ERROR("invalid dim_layer:{%d,%d,%d,%d}, stage:%d\n",
					cstate->dim_layer[i].rect.x,
					cstate->dim_layer[i].rect.y,
					cstate->dim_layer[i].rect.w,
					cstate->dim_layer[i].rect.h,
					cstate->dim_layer[i].stage);
			SDE_ERROR("display: %dx%d\n", mode->hdisplay,
					mode->vdisplay);
			rc = -E2BIG;
			goto end;
		}
	}

	if (!sde_is_custom_client()) {
		int stage_old = pstates[0].stage;

@@ -1080,6 +1256,12 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc,

	msm_property_install_blob(&sde_crtc->property_info, "capabilities",
		DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO);

	if (catalog->has_dim_layer) {
		msm_property_install_volatile_range(&sde_crtc->property_info,
			"dim_layer_v1", 0x0, 0, ~0, 0, CRTC_PROP_DIM_LAYER_V1);
	}

	sde_kms_info_reset(info);

	sde_kms_info_add_keyint(info, "hw_version", catalog->hwversion);
@@ -1126,8 +1308,17 @@ static int sde_crtc_atomic_set_property(struct drm_crtc *crtc,
		if (!ret) {
			idx = msm_property_index(&sde_crtc->property_info,
					property);
			if (idx == CRTC_PROP_INPUT_FENCE_TIMEOUT)
			switch (idx) {
			case CRTC_PROP_INPUT_FENCE_TIMEOUT:
				_sde_crtc_set_input_fence_timeout(cstate);
				break;
			case CRTC_PROP_DIM_LAYER_V1:
				_sde_crtc_set_dim_layer_v1(cstate, (void *)val);
				break;
			default:
				/* nothing to do */
				break;
			}
		} else {
			ret = sde_cp_crtc_set_property(crtc,
					property, val);
+16 −1
Original line number Diff line number Diff line
@@ -112,6 +112,8 @@ struct sde_crtc {
 * @property_values: Current crtc property values
 * @input_fence_timeout_ns : Cached input fence timeout, in ns
 * @property_blobs: Reference pointers for blob properties
 * @num_dim_layers: Number of dim layers
 * @dim_layer: Dim layer configs
 */
struct sde_crtc_state {
	struct drm_crtc_state base;
@@ -123,6 +125,8 @@ struct sde_crtc_state {
	uint64_t property_values[CRTC_PROP_COUNT];
	uint64_t input_fence_timeout_ns;
	struct drm_property_blob *property_blobs[CRTC_PROP_COUNT];
	uint32_t num_dim_layers;
	struct sde_hw_dim_layer dim_layer[SDE_MAX_DIM_LAYERS];
};

#define to_sde_crtc_state(x) \
@@ -152,7 +156,7 @@ static inline uint32_t get_crtc_split_width(struct drm_crtc *crtc)
	struct drm_display_mode *mode;
	struct sde_crtc *sde_crtc;

	if (!crtc)
	if (!crtc || !crtc->state)
		return 0;

	sde_crtc = to_sde_crtc(crtc);
@@ -160,6 +164,17 @@ static inline uint32_t get_crtc_split_width(struct drm_crtc *crtc)
	return sde_crtc_mixer_width(sde_crtc, mode);
}

static inline uint32_t get_crtc_mixer_height(struct drm_crtc *crtc)
{
	struct drm_display_mode *mode;

	if (!crtc || !crtc->state)
		return 0;

	mode = &crtc->state->adjusted_mode;
	return mode->vdisplay;
}

/**
 * sde_crtc_vblank - enable or disable vblanks for this crtc
 * @crtc: Pointer to drm crtc object
+5 −0
Original line number Diff line number Diff line
@@ -105,6 +105,7 @@ enum sde_prop {
	PANIC_PER_PIPE,
	CDP,
	SRC_SPLIT,
	DIM_LAYER,
	SDE_PROP_MAX,
};

@@ -268,6 +269,7 @@ static struct sde_prop_type sde_prop[] = {
	{PANIC_PER_PIPE, "qcom,sde-panic-per-pipe", false, PROP_TYPE_BOOL},
	{CDP, "qcom,sde-has-cdp", false, PROP_TYPE_BOOL},
	{SRC_SPLIT, "qcom,sde-has-src-split", false, PROP_TYPE_BOOL},
	{DIM_LAYER, "qcom,sde-has-dim-layer", false, PROP_TYPE_BOOL},
};

static struct sde_prop_type sspp_prop[] = {
@@ -1089,6 +1091,8 @@ static int sde_mixer_parse_dt(struct device_node *np,
			ARRAY_SIZE(blend_reg_base), max_blendstages)));
		if (sde_cfg->has_src_split)
			set_bit(SDE_MIXER_SOURCESPLIT, &mixer->features);
		if (sde_cfg->has_dim_layer)
			set_bit(SDE_DIM_LAYER, &mixer->features);

		if ((i < ROT_LM_OFFSET) || (i >= LINE_LM_OFFSET)) {
			mixer->pingpong = pp_count > 0 ? pp_idx + PINGPONG_0
@@ -1832,6 +1836,7 @@ static int sde_parse_dt(struct device_node *np, struct sde_mdss_cfg *cfg)
		cfg->csc_type = SDE_SSPP_CSC_10BIT;

	cfg->has_src_split = PROP_VALUE_ACCESS(prop_value, SRC_SPLIT, 0);
	cfg->has_dim_layer = PROP_VALUE_ACCESS(prop_value, DIM_LAYER, 0);
end:
	kfree(prop_value);
	return rc;
Loading