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

Commit 7d644122 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: update rotate flush determination"

parents 92769038 1d1979dd
Loading
Loading
Loading
Loading
+79 −37
Original line number Original line Diff line number Diff line
@@ -1404,7 +1404,8 @@ static void _sde_crtc_program_lm_output_roi(struct drm_crtc *crtc)
}
}


static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,
static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,
	struct sde_crtc *sde_crtc, struct sde_crtc_mixer *mixer)
		struct drm_crtc_state *old_state, struct sde_crtc *sde_crtc,
		struct sde_crtc_mixer *mixer)
{
{
	struct drm_plane *plane;
	struct drm_plane *plane;
	struct drm_framebuffer *fb;
	struct drm_framebuffer *fb;
@@ -1424,7 +1425,7 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,
	bool bg_alpha_enable = false;
	bool bg_alpha_enable = false;
	u32 prefill = 0;
	u32 prefill = 0;


	if (!sde_crtc || !mixer) {
	if (!sde_crtc || !crtc->state || !mixer) {
		SDE_ERROR("invalid sde_crtc or mixer\n");
		SDE_ERROR("invalid sde_crtc or mixer\n");
		return;
		return;
	}
	}
@@ -1435,7 +1436,9 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,
	cstate = to_sde_crtc_state(crtc->state);
	cstate = to_sde_crtc_state(crtc->state);


	cstate->sbuf_prefill_line = 0;
	cstate->sbuf_prefill_line = 0;
	sde_crtc->sbuf_flush_mask = 0x0;
	sde_crtc->sbuf_flush_mask_old = sde_crtc->sbuf_flush_mask_all;
	sde_crtc->sbuf_flush_mask_all = 0x0;
	sde_crtc->sbuf_flush_mask_delta = 0x0;


	drm_atomic_crtc_for_each_plane(plane, crtc) {
	drm_atomic_crtc_for_each_plane(plane, crtc) {
		state = plane->state;
		state = plane->state;
@@ -1457,7 +1460,10 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,
		sde_plane_get_ctl_flush(plane, ctl, &flush_mask, &flush_sbuf);
		sde_plane_get_ctl_flush(plane, ctl, &flush_mask, &flush_sbuf);


		/* save sbuf flush value for later */
		/* save sbuf flush value for later */
		sde_crtc->sbuf_flush_mask |= flush_sbuf;
		if (old_state && drm_atomic_get_existing_plane_state(
					old_state->state, plane))
			sde_crtc->sbuf_flush_mask_delta |= flush_sbuf;
		sde_crtc->sbuf_flush_mask_all |= flush_sbuf;


		SDE_DEBUG("crtc %d stage:%d - plane %d sspp %d fb %d\n",
		SDE_DEBUG("crtc %d stage:%d - plane %d sspp %d fb %d\n",
				crtc->base.id,
				crtc->base.id,
@@ -1584,8 +1590,11 @@ static void _sde_crtc_swap_mixers_for_right_partial_update(
/**
/**
 * _sde_crtc_blend_setup - configure crtc mixers
 * _sde_crtc_blend_setup - configure crtc mixers
 * @crtc: Pointer to drm crtc structure
 * @crtc: Pointer to drm crtc structure
 * @old_state: Pointer to old crtc state
 * @add_planes: Whether or not to add planes to mixers
 */
 */
static void _sde_crtc_blend_setup(struct drm_crtc *crtc, bool add_planes)
static void _sde_crtc_blend_setup(struct drm_crtc *crtc,
		struct drm_crtc_state *old_state, bool add_planes)
{
{
	struct sde_crtc *sde_crtc;
	struct sde_crtc *sde_crtc;
	struct sde_crtc_state *sde_crtc_state;
	struct sde_crtc_state *sde_crtc_state;
@@ -1632,7 +1641,7 @@ static void _sde_crtc_blend_setup(struct drm_crtc *crtc, bool add_planes)
	memset(&sde_crtc->stage_cfg, 0, sizeof(struct sde_hw_stage_cfg));
	memset(&sde_crtc->stage_cfg, 0, sizeof(struct sde_hw_stage_cfg));


	if (add_planes)
	if (add_planes)
		_sde_crtc_blend_setup_mixer(crtc, sde_crtc, mixer);
		_sde_crtc_blend_setup_mixer(crtc, old_state, sde_crtc, mixer);


	for (i = 0; i < sde_crtc->num_mixers; i++) {
	for (i = 0; i < sde_crtc->num_mixers; i++) {
		const struct sde_rect *lm_roi = &sde_crtc_state->lm_roi[i];
		const struct sde_rect *lm_roi = &sde_crtc_state->lm_roi[i];
@@ -3198,7 +3207,7 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc,
	if (unlikely(!sde_crtc->num_mixers))
	if (unlikely(!sde_crtc->num_mixers))
		return;
		return;


	_sde_crtc_blend_setup(crtc, true);
	_sde_crtc_blend_setup(crtc, old_state, true);
	_sde_crtc_dest_scaler_setup(crtc);
	_sde_crtc_dest_scaler_setup(crtc);


	/* cancel the idle notify delayed work */
	/* cancel the idle notify delayed work */
@@ -3422,23 +3431,29 @@ static int _sde_crtc_commit_kickoff_rot(struct drm_crtc *crtc,
	sde_crtc = to_sde_crtc(crtc);
	sde_crtc = to_sde_crtc(crtc);


	/*
	/*
	 * Update sbuf configuration and flush bits if a flush
	 * Update sbuf configuration and flush bits if either the rot_op_mode
	 * mask has been defined for either the current or
	 * is different or a rotator commit was performed.
	 * previous commit.
	 *
	 *
	 * Updates are also required for the first commit after
	 * In the case where the rot_op_mode has changed, further require that
	 * sbuf_flush_mask becomes 0x0, to properly transition
	 * the transition is either to or from offline mode unless
	 * the hardware out of sbuf mode.
	 * sbuf_flush_mask_delta is also non-zero (i.e., a corresponding plane
	 * update was provided to the current commit).
	 */
	 */
	if (!sde_crtc->sbuf_flush_mask_old && !sde_crtc->sbuf_flush_mask)
	flush_mask = sde_crtc->sbuf_flush_mask_delta;
	if ((sde_crtc->sbuf_op_mode_old != cstate->sbuf_cfg.rot_op_mode) &&
		(sde_crtc->sbuf_op_mode_old == SDE_CTL_ROT_OP_MODE_OFFLINE ||
		cstate->sbuf_cfg.rot_op_mode == SDE_CTL_ROT_OP_MODE_OFFLINE))
		flush_mask |= sde_crtc->sbuf_flush_mask_all |
			sde_crtc->sbuf_flush_mask_old;

	if (!flush_mask &&
		cstate->sbuf_cfg.rot_op_mode == SDE_CTL_ROT_OP_MODE_OFFLINE)
		return 0;
		return 0;


	flush_mask = sde_crtc->sbuf_flush_mask_old | sde_crtc->sbuf_flush_mask;
	sde_crtc->sbuf_flush_mask_old = sde_crtc->sbuf_flush_mask;

	SDE_ATRACE_BEGIN("crtc_kickoff_rot");
	SDE_ATRACE_BEGIN("crtc_kickoff_rot");


	if (cstate->sbuf_cfg.rot_op_mode != SDE_CTL_ROT_OP_MODE_OFFLINE) {
	if (cstate->sbuf_cfg.rot_op_mode != SDE_CTL_ROT_OP_MODE_OFFLINE &&
			sde_crtc->sbuf_flush_mask_delta) {
		drm_atomic_crtc_for_each_plane(plane, crtc) {
		drm_atomic_crtc_for_each_plane(plane, crtc) {
			rc = sde_plane_kickoff_rot(plane);
			rc = sde_plane_kickoff_rot(plane);
			if (rc) {
			if (rc) {
@@ -3474,12 +3489,16 @@ static int _sde_crtc_commit_kickoff_rot(struct drm_crtc *crtc,
		/* explicitly trigger rotator for async modes */
		/* explicitly trigger rotator for async modes */
		if (cstate->sbuf_cfg.rot_op_mode ==
		if (cstate->sbuf_cfg.rot_op_mode ==
				SDE_CTL_ROT_OP_MODE_INLINE_ASYNC &&
				SDE_CTL_ROT_OP_MODE_INLINE_ASYNC &&
				master_ctl->ops.trigger_rot_start) {
				master_ctl->ops.trigger_rot_start)
			master_ctl->ops.trigger_rot_start(master_ctl);
			master_ctl->ops.trigger_rot_start(master_ctl);
			SDE_EVT32(DRMID(crtc), master_ctl->idx - CTL_0);
		SDE_EVT32(DRMID(crtc), master_ctl->idx - CTL_0,
		}
				sde_crtc->sbuf_flush_mask_all,
				sde_crtc->sbuf_flush_mask_delta);
	}
	}


	/* save this in sde_crtc for next commit cycle */
	sde_crtc->sbuf_op_mode_old = cstate->sbuf_cfg.rot_op_mode;

	SDE_ATRACE_END("crtc_kickoff_rot");
	SDE_ATRACE_END("crtc_kickoff_rot");
	return rc;
	return rc;
}
}
@@ -3492,13 +3511,14 @@ static void _sde_crtc_remove_pipe_flush(struct sde_crtc *sde_crtc)
{
{
	struct sde_crtc_mixer *mixer;
	struct sde_crtc_mixer *mixer;
	struct sde_hw_ctl *ctl;
	struct sde_hw_ctl *ctl;
	u32 i, flush_mask;
	u32 i, n, flush_mask;


	if (!sde_crtc)
	if (!sde_crtc)
		return;
		return;


	mixer = sde_crtc->mixers;
	mixer = sde_crtc->mixers;
	for (i = 0; i < sde_crtc->num_mixers; i++) {
	n = min_t(size_t, sde_crtc->num_mixers, ARRAY_SIZE(sde_crtc->mixers));
	for (i = 0; i < n; i++) {
		ctl = mixer[i].hw_ctl;
		ctl = mixer[i].hw_ctl;
		if (!ctl || !ctl->ops.get_pending_flush ||
		if (!ctl || !ctl->ops.get_pending_flush ||
				!ctl->ops.clear_pending_flush ||
				!ctl->ops.clear_pending_flush ||
@@ -3524,16 +3544,19 @@ static int _sde_crtc_reset_hw(struct drm_crtc *crtc,
{
{
	struct drm_plane *plane_halt[MAX_PLANES];
	struct drm_plane *plane_halt[MAX_PLANES];
	struct drm_plane *plane;
	struct drm_plane *plane;
	struct drm_encoder *encoder;
	const struct drm_plane_state *pstate;
	const struct drm_plane_state *pstate;
	struct sde_crtc *sde_crtc;
	struct sde_crtc *sde_crtc;
	struct sde_crtc_state *cstate;
	struct sde_hw_ctl *ctl;
	struct sde_hw_ctl *ctl;
	enum sde_ctl_rot_op_mode old_rot_op_mode;
	enum sde_ctl_rot_op_mode old_rot_op_mode;
	signed int i, plane_count;
	signed int i, n, plane_count;
	int rc;
	int rc;


	if (!crtc || !old_state)
	if (!crtc || !crtc->dev || !old_state || !crtc->state)
		return -EINVAL;
		return -EINVAL;
	sde_crtc = to_sde_crtc(crtc);
	sde_crtc = to_sde_crtc(crtc);
	cstate = to_sde_crtc_state(crtc->state);


	old_rot_op_mode = to_sde_crtc_state(old_state)->sbuf_cfg.rot_op_mode;
	old_rot_op_mode = to_sde_crtc_state(old_state)->sbuf_cfg.rot_op_mode;
	SDE_EVT32(DRMID(crtc), old_rot_op_mode,
	SDE_EVT32(DRMID(crtc), old_rot_op_mode,
@@ -3545,7 +3568,8 @@ static int _sde_crtc_reset_hw(struct drm_crtc *crtc,
	/* optionally generate a panic instead of performing a h/w reset */
	/* optionally generate a panic instead of performing a h/w reset */
	SDE_DBG_CTRL("stop_ftrace", "reset_hw_panic");
	SDE_DBG_CTRL("stop_ftrace", "reset_hw_panic");


	for (i = 0; i < sde_crtc->num_mixers; ++i) {
	n = min_t(size_t, sde_crtc->num_mixers, ARRAY_SIZE(sde_crtc->mixers));
	for (i = 0; i < n; ++i) {
		ctl = sde_crtc->mixers[i].hw_ctl;
		ctl = sde_crtc->mixers[i].hw_ctl;
		if (!ctl || !ctl->ops.reset)
		if (!ctl || !ctl->ops.reset)
			continue;
			continue;
@@ -3570,14 +3594,13 @@ static int _sde_crtc_reset_hw(struct drm_crtc *crtc,
	 * depending on the rotation mode; don't handle this for now
	 * depending on the rotation mode; don't handle this for now
	 * and just force a hard reset in those cases.
	 * and just force a hard reset in those cases.
	 */
	 */
	if (i == sde_crtc->num_mixers &&
	if (i == n && old_rot_op_mode == SDE_CTL_ROT_OP_MODE_OFFLINE)
			old_rot_op_mode == SDE_CTL_ROT_OP_MODE_OFFLINE)
		return false;
		return false;


	SDE_DEBUG("crtc%d: issuing hard reset\n", DRMID(crtc));
	SDE_DEBUG("crtc%d: issuing hard reset\n", DRMID(crtc));


	/* force all components in the system into reset at the same time */
	/* force all components in the system into reset at the same time */
	for (i = 0; i < sde_crtc->num_mixers; ++i) {
	for (i = 0; i < n; ++i) {
		ctl = sde_crtc->mixers[i].hw_ctl;
		ctl = sde_crtc->mixers[i].hw_ctl;
		if (!ctl || !ctl->ops.hard_reset)
		if (!ctl || !ctl->ops.hard_reset)
			continue;
			continue;
@@ -3613,11 +3636,26 @@ static int _sde_crtc_reset_hw(struct drm_crtc *crtc,
		sde_plane_reset_rot(plane, (struct drm_plane_state *)pstate);
		sde_plane_reset_rot(plane, (struct drm_plane_state *)pstate);
	}
	}


	/* provide safe "border color only" commit configuration for later */
	cstate->sbuf_cfg.rot_op_mode = SDE_CTL_ROT_OP_MODE_OFFLINE;
	_sde_crtc_commit_kickoff_rot(crtc, cstate);
	_sde_crtc_remove_pipe_flush(sde_crtc);
	_sde_crtc_blend_setup(crtc, old_state, false);

	/* take h/w components out of reset */
	/* take h/w components out of reset */
	for (i = plane_count - 1; i >= 0; --i)
	for (i = plane_count - 1; i >= 0; --i)
		sde_plane_halt_requests(plane_halt[i], false);
		sde_plane_halt_requests(plane_halt[i], false);


	for (i = 0; i < sde_crtc->num_mixers; ++i) {
	/* attempt to poll for start of frame cycle before reset release */
	list_for_each_entry(encoder,
			&crtc->dev->mode_config.encoder_list, head) {
		if (encoder->crtc != crtc)
			continue;
		if (sde_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO)
			sde_encoder_poll_line_counts(encoder);
	}

	for (i = 0; i < n; ++i) {
		ctl = sde_crtc->mixers[i].hw_ctl;
		ctl = sde_crtc->mixers[i].hw_ctl;
		if (!ctl || !ctl->ops.hard_reset)
		if (!ctl || !ctl->ops.hard_reset)
			continue;
			continue;
@@ -3625,6 +3663,15 @@ static int _sde_crtc_reset_hw(struct drm_crtc *crtc,
		ctl->ops.hard_reset(ctl, false);
		ctl->ops.hard_reset(ctl, false);
	}
	}


	list_for_each_entry(encoder,
			&crtc->dev->mode_config.encoder_list, head) {
		if (encoder->crtc != crtc)
			continue;

		if (sde_encoder_get_intf_mode(encoder) == INTF_MODE_VIDEO)
			sde_encoder_kickoff(encoder, false);
	}

	return -EAGAIN;
	return -EAGAIN;
}
}


@@ -3649,7 +3696,7 @@ static bool _sde_crtc_prepare_for_kickoff_rot(struct drm_device *dev,
	cstate = to_sde_crtc_state(crtc->state);
	cstate = to_sde_crtc_state(crtc->state);


	/* default to ASYNC mode for inline rotation */
	/* default to ASYNC mode for inline rotation */
	cstate->sbuf_cfg.rot_op_mode = sde_crtc->sbuf_flush_mask ?
	cstate->sbuf_cfg.rot_op_mode = sde_crtc->sbuf_flush_mask_all ?
		SDE_CTL_ROT_OP_MODE_INLINE_ASYNC : SDE_CTL_ROT_OP_MODE_OFFLINE;
		SDE_CTL_ROT_OP_MODE_INLINE_ASYNC : SDE_CTL_ROT_OP_MODE_OFFLINE;


	if (cstate->sbuf_cfg.rot_op_mode == SDE_CTL_ROT_OP_MODE_OFFLINE)
	if (cstate->sbuf_cfg.rot_op_mode == SDE_CTL_ROT_OP_MODE_OFFLINE)
@@ -3749,11 +3796,6 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc,
		if (_sde_crtc_reset_hw(crtc, old_state,
		if (_sde_crtc_reset_hw(crtc, old_state,
					!sde_crtc->reset_request))
					!sde_crtc->reset_request))
			is_error = true;
			is_error = true;

		/* force offline rotation mode since the commit has no pipes */
		if (is_error)
			cstate->sbuf_cfg.rot_op_mode =
				SDE_CTL_ROT_OP_MODE_OFFLINE;
	}
	}
	sde_crtc->reset_request = reset_req;
	sde_crtc->reset_request = reset_req;


@@ -3799,7 +3841,7 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc,


	if (is_error) {
	if (is_error) {
		_sde_crtc_remove_pipe_flush(sde_crtc);
		_sde_crtc_remove_pipe_flush(sde_crtc);
		_sde_crtc_blend_setup(crtc, false);
		_sde_crtc_blend_setup(crtc, old_state, false);
	}
	}


	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+6 −2
Original line number Original line Diff line number Diff line
@@ -215,8 +215,10 @@ struct sde_crtc_event {
 * @misr_enable   : boolean entry indicates misr enable/disable status.
 * @misr_enable   : boolean entry indicates misr enable/disable status.
 * @misr_frame_count  : misr frame count provided by client
 * @misr_frame_count  : misr frame count provided by client
 * @misr_data     : store misr data before turning off the clocks.
 * @misr_data     : store misr data before turning off the clocks.
 * @sbuf_flush_mask: flush mask for inline rotator
 * @sbuf_op_mode_old : inline rotator op mode for previous commit cycle
 * @sbuf_flush_mask_old: inline rotator flush mask for previous commit
 * @sbuf_flush_mask_old: inline rotator flush mask for previous commit
 * @sbuf_flush_mask_all: inline rotator flush mask for all attached planes
 * @sbuf_flush_mask_delta: inline rotator flush mask for current delta state
 * @idle_notify_work: delayed worker to notify idle timeout to user space
 * @idle_notify_work: delayed worker to notify idle timeout to user space
 * @power_event   : registered power event handle
 * @power_event   : registered power event handle
 * @cur_perf      : current performance committed to clock/bandwidth driver
 * @cur_perf      : current performance committed to clock/bandwidth driver
@@ -284,8 +286,10 @@ struct sde_crtc {
	u32 misr_frame_count;
	u32 misr_frame_count;
	u32 misr_data[CRTC_DUAL_MIXERS];
	u32 misr_data[CRTC_DUAL_MIXERS];


	u32 sbuf_flush_mask;
	u32 sbuf_op_mode_old;
	u32 sbuf_flush_mask_old;
	u32 sbuf_flush_mask_old;
	u32 sbuf_flush_mask_all;
	u32 sbuf_flush_mask_delta;
	struct kthread_delayed_work idle_notify_work;
	struct kthread_delayed_work idle_notify_work;


	struct sde_power_event *power_event;
	struct sde_power_event *power_event;
+45 −0
Original line number Original line Diff line number Diff line
@@ -3443,6 +3443,51 @@ static void sde_encoder_vsync_event_work_handler(struct kthread_work *work)
	_sde_encoder_power_enable(sde_enc, false);
	_sde_encoder_power_enable(sde_enc, false);
}
}


int sde_encoder_poll_line_counts(struct drm_encoder *drm_enc)
{
	static const uint64_t timeout_us = 50000;
	static const uint64_t sleep_us = 20;
	struct sde_encoder_virt *sde_enc;
	ktime_t cur_ktime, exp_ktime;
	uint32_t line_count, tmp, i;

	if (!drm_enc) {
		SDE_ERROR("invalid encoder\n");
		return -EINVAL;
	}
	sde_enc = to_sde_encoder_virt(drm_enc);
	if (!sde_enc->cur_master ||
			!sde_enc->cur_master->ops.get_line_count) {
		SDE_DEBUG_ENC(sde_enc, "can't get master line count\n");
		SDE_EVT32(DRMID(drm_enc), SDE_EVTLOG_ERROR);
		return -EINVAL;
	}

	exp_ktime = ktime_add_ms(ktime_get(), timeout_us / 1000);

	line_count = sde_enc->cur_master->ops.get_line_count(
			sde_enc->cur_master);

	for (i = 0; i < (timeout_us * 2 / sleep_us); ++i) {
		tmp = line_count;
		line_count = sde_enc->cur_master->ops.get_line_count(
				sde_enc->cur_master);
		if (line_count < tmp) {
			SDE_EVT32(DRMID(drm_enc), line_count);
			return 0;
		}

		cur_ktime = ktime_get();
		if (ktime_compare_safe(exp_ktime, cur_ktime) <= 0)
			break;

		usleep_range(sleep_us / 2, sleep_us);
	}

	SDE_EVT32(DRMID(drm_enc), line_count, SDE_EVTLOG_ERROR);
	return -ETIMEDOUT;
}

int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
		struct sde_encoder_kickoff_params *params)
		struct sde_encoder_kickoff_params *params)
{
{
+7 −0
Original line number Original line Diff line number Diff line
@@ -107,6 +107,13 @@ void sde_encoder_register_frame_event_callback(struct drm_encoder *encoder,
 */
 */
struct sde_rsc_client *sde_encoder_get_rsc_client(struct drm_encoder *encoder);
struct sde_rsc_client *sde_encoder_get_rsc_client(struct drm_encoder *encoder);


/**
 * sde_encoder_poll_line_counts - poll encoder line counts for start of frame
 * @encoder:	encoder pointer
 * @Returns:	zero on success
 */
int sde_encoder_poll_line_counts(struct drm_encoder *encoder);

/**
/**
 * sde_encoder_prepare_for_kickoff - schedule double buffer flip of the ctl
 * sde_encoder_prepare_for_kickoff - schedule double buffer flip of the ctl
 *	path (i.e. ctl flush and start) at next appropriate time.
 *	path (i.e. ctl flush and start) at next appropriate time.