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

Commit 96a4194a authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drm/msm/sde: delay reset frame by a frame for posted trigger"

parents b7431862 aaa7ca42
Loading
Loading
Loading
Loading
+10 −11
Original line number Diff line number Diff line
@@ -3148,14 +3148,13 @@ static void _sde_crtc_remove_pipe_flush(struct drm_crtc *crtc)
}

/**
 * _sde_crtc_reset_hw - attempt hardware reset on errors
 * sde_crtc_reset_hw - attempt hardware reset on errors
 * @crtc: Pointer to DRM crtc instance
 * @old_state: Pointer to crtc state for previous commit
 * @recovery_events: Whether or not recovery events are enabled
 * Returns: Zero if current commit should still be attempted
 */
static int _sde_crtc_reset_hw(struct drm_crtc *crtc,
		struct drm_crtc_state *old_state,
int sde_crtc_reset_hw(struct drm_crtc *crtc, struct drm_crtc_state *old_state,
	bool recovery_events)
{
	struct drm_plane *plane_halt[MAX_PLANES];
@@ -3265,9 +3264,10 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc,
	struct msm_drm_private *priv;
	struct sde_kms *sde_kms;
	struct sde_crtc_state *cstate;
	bool is_error = false, reset_req, recovery_events;
	bool is_error = false, reset_req;
	unsigned long flags;
	enum sde_crtc_idle_pc_state idle_pc_state;
	struct sde_encoder_kickoff_params params = { 0 };

	if (!crtc) {
		SDE_ERROR("invalid argument\n");
@@ -3299,8 +3299,6 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc,
	idle_pc_state = sde_crtc_get_property(cstate, CRTC_PROP_IDLE_PC_STATE);

	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
		struct sde_encoder_kickoff_params params = { 0 };

		if (encoder->crtc != crtc)
			continue;

@@ -3313,9 +3311,6 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc,
		if (sde_encoder_prepare_for_kickoff(encoder, &params))
			reset_req = true;

		recovery_events =
			sde_encoder_recovery_events_enabled(encoder);

		if (idle_pc_state != IDLE_PC_NONE)
			sde_encoder_control_idle_pc(encoder,
			    (idle_pc_state == IDLE_PC_ENABLE) ? true : false);
@@ -3326,7 +3321,11 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc,
	 * preparing for the kickoff
	 */
	if (reset_req) {
		if (_sde_crtc_reset_hw(crtc, old_state, recovery_events))
		sde_crtc->frame_trigger_mode = params.frame_trigger_mode;
		if (sde_crtc->frame_trigger_mode
					!= FRAME_DONE_WAIT_POSTED_START &&
		    sde_crtc_reset_hw(crtc, old_state,
						params.recovery_events_enabled))
			is_error = true;
	}

+26 −0
Original line number Diff line number Diff line
@@ -219,6 +219,7 @@ struct sde_crtc_fps_info {
 * @power_event   : registered power event handle
 * @cur_perf      : current performance committed to clock/bandwidth driver
 * @plane_mask_old: keeps track of the planes used in the previous commit
 * @frame_trigger_mode: frame trigger mode
 */
struct sde_crtc {
	struct drm_crtc base;
@@ -289,6 +290,7 @@ struct sde_crtc {

	/* blob for histogram data */
	struct drm_property_blob *hist_blob;
	enum frame_trigger_mode_type frame_trigger_mode;
};

#define to_sde_crtc(x) container_of(x, struct sde_crtc, base)
@@ -441,6 +443,30 @@ static inline int sde_crtc_frame_pending(struct drm_crtc *crtc)
	return atomic_read(&sde_crtc->frame_pending);
}

/**
 * sde_crtc_reset_hw - attempt hardware reset on errors
 * @crtc: Pointer to DRM crtc instance
 * @old_state: Pointer to crtc state for previous commit
 * @recovery_events: Whether or not recovery events are enabled
 * Returns: Zero if current commit should still be attempted
 */
int sde_crtc_reset_hw(struct drm_crtc *crtc, struct drm_crtc_state *old_state,
	bool recovery_events);

/**
 * sde_crtc_request_frame_reset - requests for next frame reset
 * @crtc: Pointer to drm crtc object
 */
static inline int sde_crtc_request_frame_reset(struct drm_crtc *crtc)
{
	struct sde_crtc *sde_crtc = to_sde_crtc(crtc);

	if (sde_crtc->frame_trigger_mode == FRAME_DONE_WAIT_POSTED_START)
		sde_crtc_reset_hw(crtc, crtc->state, false);

	return 0;
}

/**
 * sde_crtc_vblank - enable or disable vblanks for this crtc
 * @crtc: Pointer to drm crtc object
+55 −46
Original line number Diff line number Diff line
@@ -189,9 +189,8 @@ enum sde_enc_rc_states {
 * @debugfs_root:		Debug file system root file node
 * @enc_lock:			Lock around physical encoder create/destroy and
				access.
 * @frame_busy_mask:		Bitmask tracking which phys_enc we are still
 *				busy processing current command.
 *				Bit0 = phys_encs[0] etc.
 * @frame_done_cnt:		Atomic counter for tracking which phys_enc is
 *				done with frame processing.
 * @crtc_frame_event_cb:	callback handler for frame event
 * @crtc_frame_event_cb_data:	callback handler private data
 * @vsync_event_timer:		vsync timer
@@ -214,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
@@ -244,7 +245,7 @@ struct sde_encoder_virt {

	struct dentry *debugfs_root;
	struct mutex enc_lock;
	DECLARE_BITMAP(frame_busy_mask, MAX_PHYS_ENCODERS_PER_VIRTUAL);
	atomic_t frame_done_cnt[MAX_PHYS_ENCODERS_PER_VIRTUAL];
	void (*crtc_frame_event_cb)(void *data, u32 event);
	struct sde_crtc_frame_event_cb_data crtc_frame_event_cb_data;

@@ -267,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;
@@ -2255,6 +2257,17 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc,
			return -EINVAL;
		}

		/*
		 * schedule off work item only when there are no
		 * frames pending
		 */
		if (sde_crtc_frame_pending(sde_enc->crtc) > 1) {
			SDE_DEBUG_ENC(sde_enc, "skip schedule work");
			SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
				SDE_EVTLOG_FUNC_CASE2);
			return 0;
		}

		if (sde_enc->crtc->index >= ARRAY_SIZE(priv->disp_thread)) {
			SDE_ERROR("invalid crtc index :%u\n",
					sde_enc->crtc->index);
@@ -2276,17 +2289,6 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc,
			return -EINVAL;
		}

		/*
		 * schedule off work item only when there are no
		 * frames pending
		 */
		if (sde_crtc_frame_pending(sde_enc->crtc) > 1) {
			SDE_DEBUG_ENC(sde_enc, "skip schedule work");
			SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
				SDE_EVTLOG_FUNC_CASE2);
			return 0;
		}

		/* schedule delayed off work if autorefresh is disabled */
		if (sde_enc->cur_master &&
			sde_enc->cur_master->ops.is_autorefresh_enabled)
@@ -2487,17 +2489,10 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc,
					SDE_EVTLOG_ERROR);
			mutex_unlock(&sde_enc->rc_lock);
			return 0;
		}

		/*
		 * if we are in ON but a frame was just kicked off,
		 * ignore the IDLE event, it's probably a stale timer event
		 */
		if (sde_enc->frame_busy_mask[0]) {
			SDE_ERROR_ENC(sde_enc,
					"sw_event:%d, rc:%d frame pending\n",
					sw_event, sde_enc->rc_state);
		} else if (sde_crtc_frame_pending(sde_enc->crtc) > 1) {
			SDE_DEBUG_ENC(sde_enc, "skip idle entry");
			SDE_EVT32(DRMID(drm_enc), sw_event, sde_enc->rc_state,
				sde_crtc_frame_pending(sde_enc->crtc),
				SDE_EVTLOG_ERROR);
			mutex_unlock(&sde_enc->rc_lock);
			return 0;
@@ -3045,6 +3040,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
@@ -3414,6 +3410,8 @@ static void sde_encoder_frame_done_callback(
{
	struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
	unsigned int i;
	bool trigger = true;
	enum sde_rm_topology_name topology = SDE_RM_TOPOLOGY_NONE;

	if (!drm_enc || !sde_enc->cur_master) {
		SDE_ERROR("invalid param: drm_enc %x, cur_master %x\n",
@@ -3428,25 +3426,34 @@ static void sde_encoder_frame_done_callback(
			| SDE_ENCODER_FRAME_EVENT_ERROR
			| SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)) {

		if (!sde_enc->frame_busy_mask[0]) {
			/**
			 * suppress frame_done without waiter,
			 * likely autorefresh
			 */
			SDE_EVT32(DRMID(drm_enc), event, ready_phys->intf_idx);
			return;
		}
		if (ready_phys->connector)
			topology = sde_connector_get_topology_name(
							ready_phys->connector);

		/* One of the physical encoders has become idle */
		for (i = 0; i < sde_enc->num_phys_encs; i++) {
			if (sde_enc->phys_encs[i] == ready_phys) {
				clear_bit(i, sde_enc->frame_busy_mask);
			if ((sde_enc->phys_encs[i] == ready_phys) ||
			     (event & SDE_ENCODER_FRAME_EVENT_ERROR)) {
				SDE_EVT32_VERBOSE(DRMID(drm_enc), i,
					sde_enc->frame_busy_mask[0]);
				     atomic_read(&sde_enc->frame_done_cnt[i]));
				if (!atomic_add_unless(
					&sde_enc->frame_done_cnt[i], 1, 1)) {
					SDE_EVT32(DRMID(drm_enc), event,
						ready_phys->intf_idx,
						SDE_EVTLOG_ERROR);
					SDE_ERROR_ENC(sde_enc,
						"intf idx:%d, event:%d\n",
						ready_phys->intf_idx, event);
					return;
				}
			}

			if (topology != SDE_RM_TOPOLOGY_PPSPLIT &&
			    atomic_read(&sde_enc->frame_done_cnt[i]) != 1)
				trigger = false;
		}

		if (!sde_enc->frame_busy_mask[0]) {
		if (trigger) {
			sde_encoder_resource_control(drm_enc,
					SDE_ENC_RC_EVENT_FRAME_DONE);

@@ -3454,6 +3461,8 @@ static void sde_encoder_frame_done_callback(
				sde_enc->crtc_frame_event_cb(
					&sde_enc->crtc_frame_event_cb_data,
					event);
			for (i = 0; i < sde_enc->num_phys_encs; i++)
				atomic_set(&sde_enc->frame_done_cnt[i], 0);
		}
	} else {
		if (sde_enc->crtc_frame_event_cb)
@@ -3770,14 +3779,6 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc)
		if (phys->connector)
			topology = sde_connector_get_topology_name(
					phys->connector);
		/*
		 * 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_SKIP)
			set_bit(i, sde_enc->frame_busy_mask);

		if (!phys->ops.needs_single_flush ||
				!phys->ops.needs_single_flush(phys)) {
@@ -4415,6 +4416,9 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
	for (i = 0; i < sde_enc->num_phys_encs; i++) {
		phys = sde_enc->phys_encs[i];
		params->is_primary = sde_enc->disp_info.is_primary;
		params->frame_trigger_mode = sde_enc->frame_trigger_mode;
		params->recovery_events_enabled =
					sde_enc->recovery_events_enabled;
		if (phys) {
			if (phys->ops.prepare_for_kickoff) {
				rc = phys->ops.prepare_for_kickoff(
@@ -4855,6 +4859,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)
@@ -5152,6 +5159,8 @@ struct drm_encoder *sde_encoder_init(
	sde_enc->cur_master = NULL;
	spin_lock_init(&sde_enc->enc_spinlock);
	mutex_init(&sde_enc->vblank_ctl_lock);
	for (i = 0; i < MAX_PHYS_ENCODERS_PER_VIRTUAL; i++)
		atomic_set(&sde_enc->frame_done_cnt[i], 0);
	drm_enc = &sde_enc->base;
	drm_encoder_init(dev, drm_enc, &sde_encoder_funcs, drm_enc_mode, NULL);
	drm_encoder_helper_add(drm_enc, &sde_encoder_helper_funcs);
+3 −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)
@@ -58,11 +59,13 @@ struct sde_encoder_hw_resources {
 * @affected_displays:  bitmask, bit set means the ROI of the commit lies within
 *                      the bounds of the physical display at the bit index
 * @recovery_events_enabled: indicates status of client for recoovery events
 * @frame_trigger_mode: indicates frame trigger mode
 */
struct sde_encoder_kickoff_params {
	u32 is_primary;
	unsigned long affected_displays;
	bool recovery_events_enabled;
	enum frame_trigger_mode_type frame_trigger_mode;
};

/**
+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;
Loading