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

Commit 56a0a47e authored by Dhaval Patel's avatar Dhaval Patel
Browse files

drm/msm/sde: support posted frame trigger for cmd mode



Support posted frame trigger for command mode
panel with queue depth 1. It allows panel vsync time
for frame transfer duration and reduces the MDP clock
and BW requirement. The change also support debugfs
entry support to select the cmd mode frame done wait
between serialize trigger, posted trigger and default
behavior.

Change-Id: I84134a6458665c40e94aa29805e528caa2d91a93
Signed-off-by: default avatarDhaval Patel <pdhaval@codeaurora.org>
parent 39c9b323
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -213,6 +213,8 @@ enum sde_enc_rc_states {
 * @topology:                   topology of the display
 * @vblank_enabled:		boolean to track userspace vblank vote
 * @idle_pc_restore:		flag to indicate idle_pc_restore happened
 * @frame_trigger_mode:		frame trigger mode indication for command
 *				mode display
 * @rsc_config:			rsc configuration for display vtotal, fps, etc.
 * @cur_conn_roi:		current connector roi
 * @prv_conn_roi:		previous connector roi to optimize if unchanged
@@ -266,6 +268,7 @@ struct sde_encoder_virt {
	struct msm_display_topology topology;
	bool vblank_enabled;
	bool idle_pc_restore;
	enum frame_trigger_mode_type frame_trigger_mode;

	struct sde_rsc_cmd_config rsc_config;
	struct sde_rect cur_conn_roi;
@@ -3021,6 +3024,7 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
		phys->comp_type = comp_info->comp_type;
		phys->comp_ratio = comp_info->comp_ratio;
		phys->wide_bus_en = mode_info.wide_bus_en;
		phys->frame_trigger_mode = sde_enc->frame_trigger_mode;
		if (phys != sde_enc->cur_master) {
			/**
			 * on DMS request, the encoder will be enabled
@@ -4782,6 +4786,9 @@ static int _sde_encoder_init_debugfs(struct drm_encoder *drm_enc)
	debugfs_create_bool("idle_power_collapse", 0600, sde_enc->debugfs_root,
			&sde_enc->idle_pc_enabled);

	debugfs_create_u32("frame_trigger_mode", 0600, sde_enc->debugfs_root,
			&sde_enc->frame_trigger_mode);

	for (i = 0; i < sde_enc->num_phys_encs; i++)
		if (sde_enc->phys_encs[i] &&
				sde_enc->phys_encs[i]->ops.late_register)
+1 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@

#include "msm_prop.h"
#include "sde_hw_mdss.h"
#include "sde_kms.h"

#define SDE_ENCODER_FRAME_EVENT_DONE			BIT(0)
#define SDE_ENCODER_FRAME_EVENT_ERROR			BIT(1)
+3 −3
Original line number Diff line number Diff line
@@ -281,6 +281,8 @@ struct sde_encoder_irq {
 * @in_clone_mode		Indicates if encoder is in clone mode ref@CWB
 * @vfp_cached:			cached vertical front porch to be used for
 *				programming ROT and MDP fetch start
 * @frame_trigger_mode:		frame trigger mode indication for command
 *				mode display
 */
struct sde_encoder_phys {
	struct drm_encoder *parent;
@@ -320,6 +322,7 @@ struct sde_encoder_phys {
	bool cont_splash_enabled;
	bool in_clone_mode;
	int vfp_cached;
	enum frame_trigger_mode_type frame_trigger_mode;
};

static inline int sde_encoder_phys_inc_pending(struct sde_encoder_phys *phys)
@@ -359,8 +362,6 @@ struct sde_encoder_phys_cmd_autorefresh {
 * @base:	Baseclass physical encoder structure
 * @intf_idx:	Intf Block index used by this phys encoder
 * @stream_sel:	Stream selection for multi-stream interfaces
 * @serialize_wait4pp:	serialize wait4pp feature waits for pp_done interrupt
 *			after ctl_start instead of before next frame kickoff
 * @pp_timeout_report_cnt: number of pingpong done irq timeout errors
 * @autorefresh: autorefresh feature state
 * @pending_rd_ptr_cnt: atomic counter to indicate if retire fence can be
@@ -374,7 +375,6 @@ struct sde_encoder_phys_cmd_autorefresh {
struct sde_encoder_phys_cmd {
	struct sde_encoder_phys base;
	int stream_sel;
	bool serialize_wait4pp;
	int pp_timeout_report_cnt;
	struct sde_encoder_phys_cmd_autorefresh autorefresh;
	atomic_t pending_rd_ptr_cnt;
+51 −34
Original line number Diff line number Diff line
@@ -196,23 +196,6 @@ static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx)

	SDE_ATRACE_BEGIN("pp_done_irq");

	/* handle rare cases where the ctl_start_irq is not received */
	if (sde_encoder_phys_cmd_is_master(phys_enc)) {
		/*
		 * Reduce the refcount for the retire fence as well
		 * as for the ctl_start if the counters are greater
		 * than zero. If there was a retire fence count pending,
		 * then signal the RETIRE FENCE here.
		 */
		if (atomic_add_unless(&phys_enc->pending_retire_fence_cnt,
				-1, 0))
			phys_enc->parent_ops.handle_frame_done(
				phys_enc->parent,
				phys_enc,
				SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE);
		atomic_add_unless(&phys_enc->pending_ctlstart_cnt, -1, 0);
	}

	/* notify all synchronous clients first, then asynchronous clients */
	if (phys_enc->parent_ops.handle_frame_done)
		phys_enc->parent_ops.handle_frame_done(phys_enc->parent,
@@ -225,6 +208,23 @@ static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx)
	SDE_EVT32_IRQ(DRMID(phys_enc->parent),
			phys_enc->hw_pp->idx - PINGPONG_0, new_cnt, event);

	/*
	 * Reduce the refcount for the retire fence as well as for the ctl_start
	 * if the counters are greater than zero. Signal retire fence if there
	 * was a retire fence count pending and kickoff count is zero.
	 */
	if (sde_encoder_phys_cmd_is_master(phys_enc) && (new_cnt == 0)) {
		while (atomic_add_unless(&phys_enc->pending_retire_fence_cnt,
				-1, 0)) {
			if (phys_enc->parent_ops.handle_frame_done)
				phys_enc->parent_ops.handle_frame_done(
					phys_enc->parent, phys_enc,
				SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE);
			atomic_add_unless(&phys_enc->pending_ctlstart_cnt,
				-1, 0);
		}
	}

	/* Signal any waiting atomic commit thread */
	wake_up_all(&phys_enc->pending_kickoff_wq);
	SDE_ATRACE_END("pp_done_irq");
@@ -519,6 +519,10 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout(
		return -EINVAL;

	conn = phys_enc->connector;

	if (atomic_read(&phys_enc->pending_kickoff_cnt) == 0)
		return 0;

	cmd_enc->pp_timeout_report_cnt++;
	pending_kickoff_cnt = atomic_read(&phys_enc->pending_kickoff_cnt);

@@ -714,7 +718,7 @@ static int _sde_encoder_phys_cmd_wait_for_idle(
			to_sde_encoder_phys_cmd(phys_enc);
	struct sde_encoder_wait_info wait_info;
	bool recovery_events;
	int ret;
	int ret, i, pending_cnt;

	if (!phys_enc) {
		SDE_ERROR("invalid encoder\n");
@@ -734,6 +738,8 @@ static int _sde_encoder_phys_cmd_wait_for_idle(
	ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_PINGPONG,
			&wait_info);
	if (ret == -ETIMEDOUT) {
		pending_cnt = atomic_read(&phys_enc->pending_kickoff_cnt);
		for (i = 0; i < pending_cnt; i++)
			_sde_encoder_phys_cmd_handle_ppdone_timeout(phys_enc,
				recovery_events);
	} else if (!ret) {
@@ -1334,7 +1340,7 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff(
	struct sde_hw_tear_check tc_cfg = {0};
	struct sde_encoder_phys_cmd *cmd_enc =
			to_sde_encoder_phys_cmd(phys_enc);
	int ret;
	int ret = 0;
	u32 extra_frame_trigger_time;

	if (!phys_enc || !phys_enc->hw_pp) {
@@ -1347,18 +1353,20 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff(
			atomic_read(&phys_enc->pending_kickoff_cnt),
			atomic_read(&cmd_enc->autorefresh.kickoff_cnt));

	if (phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_DEFAULT) {
		/*
	 * Mark kickoff request as outstanding. If there are more than one,
	 * outstanding, then we have to wait for the previous one to complete
		 * Mark kickoff request as outstanding. If there are more
		 * than one outstanding frame, then we have to wait for the
		 * previous frame to complete
		 */
		ret = _sde_encoder_phys_cmd_wait_for_idle(phys_enc);
		if (ret) {
		/* force pending_kickoff_cnt 0 to discard failed kickoff */
			atomic_set(&phys_enc->pending_kickoff_cnt, 0);
			SDE_EVT32(DRMID(phys_enc->parent),
					phys_enc->hw_pp->idx - PINGPONG_0);
			SDE_ERROR("failed wait_for_idle: %d\n", ret);
		}
	}

	if (sde_connector_qsync_updated(phys_enc->connector)) {
		tc_cfg.sync_threshold_start =
@@ -1465,9 +1473,18 @@ static int sde_encoder_phys_cmd_wait_for_commit_done(
			cmd_enc->autorefresh.cfg.enable)
		rc = _sde_encoder_phys_cmd_wait_for_autorefresh_done(phys_enc);

	/* required for both controllers */
	if (!rc && cmd_enc->serialize_wait4pp)
		sde_encoder_phys_cmd_prepare_for_kickoff(phys_enc, NULL);
	/* wait for posted start or serialize trigger */
	if ((atomic_read(&phys_enc->pending_kickoff_cnt) > 1) ||
	    (!rc && phys_enc->frame_trigger_mode ==
						FRAME_DONE_WAIT_SERIALIZE)) {
		rc = _sde_encoder_phys_cmd_wait_for_idle(phys_enc);
		if (rc) {
			atomic_set(&phys_enc->pending_kickoff_cnt, 0);
			SDE_EVT32(DRMID(phys_enc->parent),
					phys_enc->hw_pp->idx - PINGPONG_0);
			SDE_ERROR("failed wait_for_idle: %d\n", rc);
		}
	}

	return rc;
}
+14 −0
Original line number Diff line number Diff line
@@ -169,6 +169,20 @@ enum sde_kms_sui_misr_state {
	SUI_MISR_DISABLE_REQ
};

/*
 * @FRAME_DONE_WAIT_DEFAULT:	waits for frame N pp_done interrupt before
 *                              triggering frame N+1.
 * @FRAME_DONE_WAIT_SERIALIZE:	serialize pp_done and ctl_start irq for frame
 *                              N without next frame trigger wait.
 * @FRAME_DONE_WAIT_POSTED_START: Do not wait for pp_done interrupt for any
 *                              frame. Wait will trigger only for error case.
 */
enum frame_trigger_mode_type {
	FRAME_DONE_WAIT_DEFAULT,
	FRAME_DONE_WAIT_SERIALIZE,
	FRAME_DONE_WAIT_POSTED_START,
};

/**
 * struct sde_kms_smmu_state_data: stores the smmu state and transition type
 * @state: current state of smmu context banks