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

Commit 55a9ced3 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drm/msm/sde: support left/right only partial updates" into msm-4.9

parents e1e06050 73fb809e
Loading
Loading
Loading
Loading
+75 −28
Original line number Diff line number Diff line
@@ -864,56 +864,83 @@ static int _sde_crtc_set_lm_roi(struct drm_crtc *crtc,
	lm_bounds = &crtc_state->lm_bounds[lm_idx];
	lm_roi = &crtc_state->lm_roi[lm_idx];

	if (!sde_kms_rect_is_null(crtc_roi)) {
		sde_kms_rect_intersect(crtc_roi, lm_bounds, lm_roi);
		if (sde_kms_rect_is_null(lm_roi)) {
			SDE_ERROR("unsupported R/L only partial update\n");
			return -EINVAL;
		}
	} else {
	if (sde_kms_rect_is_null(crtc_roi))
		memcpy(lm_roi, lm_bounds, sizeof(*lm_roi));
	}
	else
		sde_kms_rect_intersect(crtc_roi, lm_bounds, lm_roi);

	SDE_DEBUG("%s: lm%d roi (%d,%d,%d,%d)\n", sde_crtc->name, lm_idx,
			lm_roi->x, lm_roi->y, lm_roi->w, lm_roi->h);

	/* if any dimension is zero, clear all dimensions for clarity */
	if (sde_kms_rect_is_null(lm_roi))
		memset(lm_roi, 0, sizeof(*lm_roi));

	return 0;
}

static u32 _sde_crtc_get_displays_affected(struct drm_crtc *crtc,
		struct drm_crtc_state *state)
{
	struct sde_crtc *sde_crtc;
	struct sde_crtc_state *crtc_state;
	u32 disp_bitmask = 0;
	int i;

	sde_crtc = to_sde_crtc(crtc);
	crtc_state = to_sde_crtc_state(state);

	for (i = 0; i < sde_crtc->num_mixers; i++) {
		if (!sde_kms_rect_is_null(&crtc_state->lm_roi[i]))
			disp_bitmask |= BIT(i);
	}

	SDE_DEBUG("affected displays 0x%x\n", disp_bitmask);

	return disp_bitmask;
}

static int _sde_crtc_check_rois_centered_and_symmetric(struct drm_crtc *crtc,
		struct drm_crtc_state *state)
{
	struct sde_crtc *sde_crtc;
	struct sde_crtc_state *crtc_state;
	const struct sde_rect *roi_prv, *roi_cur;
	int lm_idx;
	const struct sde_rect *roi[CRTC_DUAL_MIXERS];

	if (!crtc || !state)
		return -EINVAL;

	sde_crtc = to_sde_crtc(crtc);
	crtc_state = to_sde_crtc_state(state);

	if (sde_crtc->num_mixers == 1)
		return 0;

	if (sde_crtc->num_mixers > CRTC_DUAL_MIXERS) {
		SDE_ERROR("%s: unsupported number of mixers: %d\n",
				sde_crtc->name, sde_crtc->num_mixers);
		return -EINVAL;
	}

	/*
	 * On certain HW, ROIs must be centered on the split between LMs,
	 * and be of equal width.
	 */
	roi[0] = &crtc_state->lm_roi[0];
	roi[1] = &crtc_state->lm_roi[1];

	sde_crtc = to_sde_crtc(crtc);
	crtc_state = to_sde_crtc_state(state);

	roi_prv = &crtc_state->lm_roi[0];
	for (lm_idx = 1; lm_idx < sde_crtc->num_mixers; lm_idx++) {
		roi_cur = &crtc_state->lm_roi[lm_idx];
	/* if one of the roi is null it's a left/right-only update */
	if (sde_kms_rect_is_null(roi[0]) || sde_kms_rect_is_null(roi[1]))
		return 0;

	/* check lm rois are equal width & first roi ends at 2nd roi */
		if (((roi_prv->x + roi_prv->w) != roi_cur->x) ||
				(roi_prv->w != roi_cur->w)) {
			SDE_ERROR("%s: roi lm%d x %d w %d lm%d x %d w %d\n",
					sde_crtc->name,
					lm_idx-1, roi_prv->x, roi_prv->w,
					lm_idx, roi_cur->x, roi_cur->w);
	if (roi[0]->x + roi[0]->w != roi[1]->x || roi[0]->w != roi[1]->w) {
		SDE_ERROR(
			"%s: rois not centered and symmetric: roi0 x %d w %d roi1 x %d w %d\n",
				sde_crtc->name, roi[0]->x, roi[0]->w,
				roi[1]->x, roi[1]->w);
		return -EINVAL;
	}
		roi_prv = roi_cur;
	}

	return 0;
}
@@ -1188,13 +1215,21 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,
 */
static void _sde_crtc_blend_setup(struct drm_crtc *crtc)
{
	struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
	struct sde_crtc_mixer *mixer = sde_crtc->mixers;
	struct sde_crtc *sde_crtc;
	struct sde_crtc_state *sde_crtc_state;
	struct sde_crtc_mixer *mixer;
	struct sde_hw_ctl *ctl;
	struct sde_hw_mixer *lm;

	int i;

	if (!crtc)
		return;

	sde_crtc = to_sde_crtc(crtc);
	sde_crtc_state = to_sde_crtc_state(crtc->state);
	mixer = sde_crtc->mixers;

	SDE_DEBUG("%s\n", sde_crtc->name);

	if (sde_crtc->num_mixers > CRTC_DUAL_MIXERS) {
@@ -1225,9 +1260,19 @@ static void _sde_crtc_blend_setup(struct drm_crtc *crtc)
	_sde_crtc_blend_setup_mixer(crtc, sde_crtc, mixer);

	for (i = 0; i < sde_crtc->num_mixers; i++) {
		const struct sde_rect *lm_roi = &sde_crtc_state->lm_roi[i];

		ctl = mixer[i].hw_ctl;
		lm = mixer[i].hw_lm;

		if (sde_kms_rect_is_null(lm_roi)) {
			SDE_DEBUG(
				"%s: lm%d leave ctl%d mask 0 since null roi\n",
					sde_crtc->name, lm->idx - LM_0,
					ctl->idx - CTL_0);
			continue;
		}

		lm->ops.setup_alpha_out(lm, mixer[i].mixer_op_mode);

		mixer[i].flush_mask |= ctl->ops.get_bitmask_mixer(ctl,
@@ -1912,6 +1957,8 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc)
		 * If so, it may delay and flush at an irq event (e.g. ppdone)
		 */
		params.inline_rotate_prefill = cstate->sbuf_prefill_line;
		params.affected_displays = _sde_crtc_get_displays_affected(crtc,
				crtc->state);
		sde_encoder_prepare_for_kickoff(encoder, &params);
	}

+3 −3
Original line number Diff line number Diff line
@@ -248,10 +248,10 @@ struct sde_crtc_respool {
 * @num_connectors: Number of associated drm connectors
 * @intf_mode     : Interface mode of the primary connector
 * @rsc_client    : sde rsc client when mode is valid
 * @lm_bounds     : LM boundaries based on current mode full resolution, no ROI.
 *                  Origin top left of CRTC.
 * @crtc_roi      : Current CRTC ROI. Possibly sub-rectangle of mode.
 *                  Origin top left of CRTC.
 * @lm_bounds     : LM boundaries based on current mode full resolution, no ROI.
 *                  Origin top left of CRTC.
 * @lm_roi        : Current LM ROI, possibly sub-rectangle of mode.
 *                  Origin top left of CRTC.
 * @user_roi_list : List of user's requested ROIs as from set property
@@ -274,8 +274,8 @@ struct sde_crtc_state {
	struct sde_rsc_client *rsc_client;
	bool rsc_update;

	struct sde_rect lm_bounds[CRTC_DUAL_MIXERS];
	struct sde_rect crtc_roi;
	struct sde_rect lm_bounds[CRTC_DUAL_MIXERS];
	struct sde_rect lm_roi[CRTC_DUAL_MIXERS];
	struct msm_roi_list user_roi_list;

+82 −4
Original line number Diff line number Diff line
@@ -1463,6 +1463,14 @@ static inline void _sde_encoder_trigger_flush(struct drm_encoder *drm_enc,
		return;
	}

	if (phys->split_role == ENC_ROLE_SKIP) {
		SDE_DEBUG_ENC(to_sde_encoder_virt(phys->parent),
				"skip flush pp%d ctl%d\n",
				phys->hw_pp->idx - PINGPONG_0,
				ctl->idx - CTL_0);
		return;
	}

	pending_kickoff_cnt = sde_encoder_phys_inc_pending(phys);

	if (extra_flush_bits && ctl->ops.update_pending_flush)
@@ -1484,11 +1492,21 @@ static inline void _sde_encoder_trigger_flush(struct drm_encoder *drm_enc,
 */
static inline void _sde_encoder_trigger_start(struct sde_encoder_phys *phys)
{
	struct sde_hw_ctl *ctl;

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

	ctl = phys->hw_ctl;
	if (phys->split_role == ENC_ROLE_SKIP) {
		SDE_DEBUG_ENC(to_sde_encoder_virt(phys->parent),
				"skip start pp%d ctl%d\n",
				phys->hw_pp->idx - PINGPONG_0,
				ctl->idx - CTL_0);
		return;
	}
	if (phys->ops.trigger_start && phys->enable_state != SDE_ENC_DISABLED)
		phys->ops.trigger_start(phys);
}
@@ -1620,9 +1638,13 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc)
			topology = sde_connector_get_topology_name(
					phys->connector);

		/* don't wait on ppsplit slaves, they dont register irqs */
		/*
		 * don't wait on ppsplit slaves or skipped encoders because
		 * they dont receive irqs
		 */
		if (!(topology == SDE_RM_TOPOLOGY_PPSPLIT &&
				phys->split_role == ENC_ROLE_SLAVE))
				phys->split_role == ENC_ROLE_SLAVE) &&
				phys->split_role != ENC_ROLE_SKIP)
			set_bit(i, sde_enc->frame_busy_mask);

		if (!phys->ops.needs_single_flush ||
@@ -1645,6 +1667,60 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc)
	spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags);
}

static void _sde_encoder_update_master(struct drm_encoder *drm_enc,
		struct sde_encoder_kickoff_params *params)
{
	struct sde_encoder_virt *sde_enc;
	struct sde_encoder_phys *phys;
	int i, num_active_phys;
	bool master_assigned = false;

	if (!drm_enc || !params)
		return;

	sde_enc = to_sde_encoder_virt(drm_enc);

	if (sde_enc->num_phys_encs <= 1)
		return;

	/* count bits set */
	num_active_phys = hweight_long(params->affected_displays);

	SDE_DEBUG_ENC(sde_enc, "affected_displays 0x%lx num_active_phys %d\n",
			params->affected_displays, num_active_phys);

	for (i = 0; i < sde_enc->num_phys_encs; i++) {
		enum sde_enc_split_role prv_role, new_role;
		bool active;

		phys = sde_enc->phys_encs[i];
		if (!phys || !phys->ops.update_split_role)
			continue;

		active = test_bit(i, &params->affected_displays);
		prv_role = phys->split_role;

		if (active && num_active_phys == 1)
			new_role = ENC_ROLE_SOLO;
		else if (active && !master_assigned)
			new_role = ENC_ROLE_MASTER;
		else if (active)
			new_role = ENC_ROLE_SLAVE;
		else
			new_role = ENC_ROLE_SKIP;

		phys->ops.update_split_role(phys, new_role);
		if (new_role == ENC_ROLE_SOLO || new_role == ENC_ROLE_MASTER) {
			sde_enc->cur_master = phys;
			master_assigned = true;
		}

		SDE_DEBUG_ENC(sde_enc, "pp %d role prv %d new %d active %d\n",
				phys->hw_pp->idx - PINGPONG_0, prv_role,
				phys->split_role, active);
	}
}

void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
		struct sde_encoder_kickoff_params *params)
{
@@ -1654,8 +1730,8 @@ void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
	unsigned int i;
	int rc;

	if (!drm_enc) {
		SDE_ERROR("invalid encoder\n");
	if (!drm_enc || !params) {
		SDE_ERROR("invalid args\n");
		return;
	}
	sde_enc = to_sde_encoder_virt(drm_enc);
@@ -1685,6 +1761,8 @@ void sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
		}
	}

	_sde_encoder_update_master(drm_enc, params);

	if (sde_enc->cur_master && sde_enc->cur_master->connector) {
		rc = sde_connector_pre_kickoff(sde_enc->cur_master->connector);
		if (rc)
+3 −0
Original line number Diff line number Diff line
@@ -47,9 +47,12 @@ struct sde_encoder_hw_resources {
/**
 * sde_encoder_kickoff_params - info encoder requires at kickoff
 * @inline_rotate_prefill: number of lines to prefill for inline rotation
 * @affected_displays:  bitmask, bit set means the ROI of the commit lies within
 *                      the bounds of the physical display at the bit index
 */
struct sde_encoder_kickoff_params {
	u32 inline_rotate_prefill;
	unsigned long affected_displays;
};

/**
+6 −2
Original line number Diff line number Diff line
@@ -41,11 +41,13 @@
 * @ENC_ROLE_SOLO:	This is the one and only panel. This encoder is master.
 * @ENC_ROLE_MASTER:	This encoder is the master of a split panel config.
 * @ENC_ROLE_SLAVE:	This encoder is not the master of a split panel config.
 * @ENC_ROLE_SKIP:	This encoder is not participating in kickoffs
 */
enum sde_enc_split_role {
	ENC_ROLE_SOLO,
	ENC_ROLE_MASTER,
	ENC_ROLE_SLAVE
	ENC_ROLE_SLAVE,
	ENC_ROLE_SKIP
};

/**
@@ -118,6 +120,7 @@ struct sde_encoder_virt_ops {
 * @hw_reset:			Issue HW recovery such as CTL reset and clear
 *				SDE_ENC_ERR_NEEDS_HW_RESET state
 * @irq_control:		Handler to enable/disable all the encoder IRQs
 * @update_split_role:		Update the split role of the phys enc
 */

struct sde_encoder_phys_ops {
@@ -152,6 +155,8 @@ struct sde_encoder_phys_ops {
	u32 (*collect_misr)(struct sde_encoder_phys *phys_enc);
	void (*hw_reset)(struct sde_encoder_phys *phys_enc);
	void (*irq_control)(struct sde_encoder_phys *phys, bool enable);
	void (*update_split_role)(struct sde_encoder_phys *phys_enc,
			enum sde_enc_split_role role);
};

/**
@@ -265,7 +270,6 @@ struct sde_encoder_phys_vid {
 */
struct sde_encoder_phys_cmd {
	struct sde_encoder_phys base;
	int intf_idx;
	int stream_sel;
	int irq_idx[INTR_IDX_MAX];
	struct sde_irq_callback irq_cb[INTR_IDX_MAX];
Loading