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

Commit 0ddec51f 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: add support for idle timeout feature"

parents 535b4a26 59d431a2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -147,6 +147,7 @@ enum msm_mdp_crtc_property {
	CRTC_PROP_ROT_CLK,
	CRTC_PROP_ROI_V1,
	CRTC_PROP_SECURITY_LEVEL,
	CRTC_PROP_IDLE_TIME,

	/* total # of properties */
	CRTC_PROP_COUNT
+72 −3
Original line number Diff line number Diff line
@@ -64,6 +64,8 @@ struct sde_crtc_custom_events {

static int sde_crtc_power_interrupt_handler(struct drm_crtc *crtc_drm,
	bool en, struct sde_irq_callback *ad_irq);
static int sde_crtc_idle_interrupt_handler(struct drm_crtc *crtc_drm,
	bool en, struct sde_irq_callback *idle_irq);

static int sde_crtc_pm_event_handler(struct drm_crtc *crtc_drm,
	bool en, struct sde_irq_callback *noirq);
@@ -72,6 +74,7 @@ static struct sde_crtc_custom_events custom_events[] = {
	{DRM_EVENT_AD_BACKLIGHT, sde_cp_ad_interrupt},
	{DRM_EVENT_CRTC_POWER, sde_crtc_power_interrupt_handler},
	{DRM_EVENT_SDE_POWER, sde_crtc_pm_event_handler},
	{DRM_EVENT_IDLE_NOTIFY, sde_crtc_idle_interrupt_handler}
};

/* default input fence timeout, in ms */
@@ -1623,7 +1626,8 @@ int sde_crtc_get_secure_transition_ops(struct drm_crtc *crtc,
		if (encoder->crtc != crtc)
			continue;

		post_commit &= !sde_encoder_is_cmd_mode(encoder);
		post_commit &= sde_encoder_check_mode(encoder,
						MSM_DISPLAY_CAP_VID_MODE);
	}

	drm_atomic_crtc_for_each_plane(plane, crtc) {
@@ -2493,6 +2497,12 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc,
	if (unlikely(!sde_crtc->num_mixers))
		return;

	/* cancel the idle notify delayed work */
	if (sde_encoder_check_mode(sde_crtc->mixers[0].encoder,
					MSM_DISPLAY_CAP_VID_MODE) &&
		kthread_cancel_delayed_work_sync(&sde_crtc->idle_notify_work))
		SDE_DEBUG("idle notify work cancelled\n");

	_sde_crtc_blend_setup(crtc);

	/*
@@ -2522,10 +2532,13 @@ static void sde_crtc_atomic_flush(struct drm_crtc *crtc,
	struct sde_crtc *sde_crtc;
	struct drm_device *dev;
	struct drm_plane *plane;
	struct msm_drm_private *priv;
	struct msm_drm_thread *event_thread;
	unsigned long flags;
	struct sde_crtc_state *cstate;
	int idle_time = 0;

	if (!crtc) {
	if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
		SDE_ERROR("invalid crtc\n");
		return;
	}
@@ -2541,6 +2554,15 @@ static void sde_crtc_atomic_flush(struct drm_crtc *crtc,
	sde_crtc = to_sde_crtc(crtc);
	cstate = to_sde_crtc_state(crtc->state);
	dev = crtc->dev;
	priv = dev->dev_private;

	if (crtc->index >= ARRAY_SIZE(priv->event_thread)) {
		SDE_ERROR("invalid crtc index[%d]\n", crtc->index);
		return;
	}

	event_thread = &priv->event_thread[crtc->index];
	idle_time = sde_crtc_get_property(cstate, CRTC_PROP_IDLE_TIME);

	if (sde_crtc->event) {
		SDE_DEBUG("already received sde_crtc->event\n");
@@ -2571,6 +2593,15 @@ static void sde_crtc_atomic_flush(struct drm_crtc *crtc,
	/* wait for acquire fences before anything else is done */
	_sde_crtc_wait_for_fences(crtc);

	/* schedule the idle notify delayed work */
	if (idle_time && sde_encoder_check_mode(sde_crtc->mixers[0].encoder,
						MSM_DISPLAY_CAP_VID_MODE)) {
		kthread_queue_delayed_work(&event_thread->worker,
					&sde_crtc->idle_notify_work,
					msecs_to_jiffies(idle_time));
		SDE_DEBUG("schedule idle notify work in %dms\n", idle_time);
	}

	if (!cstate->rsc_update) {
		drm_for_each_encoder(encoder, dev) {
			if (encoder->crtc != crtc)
@@ -3769,6 +3800,9 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc,
			sde_kms->perf.max_core_clk_rate,
			CRTC_PROP_ROT_CLK);

	msm_property_install_range(&sde_crtc->property_info,
		"idle_time", 0x0, 0, U64_MAX, 0, CRTC_PROP_IDLE_TIME);

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

@@ -3973,7 +4007,8 @@ static int sde_crtc_atomic_get_property(struct drm_crtc *crtc,
		 */
		drm_for_each_encoder(encoder, crtc->dev) {
			if (encoder->crtc == crtc)
				is_cmd &= sde_encoder_is_cmd_mode(encoder);
				is_cmd = sde_encoder_check_mode(encoder,
						MSM_DISPLAY_CAP_CMD_MODE);
		}

		i = msm_property_index(&sde_crtc->property_info, property);
@@ -4500,6 +4535,31 @@ static int _sde_crtc_init_events(struct sde_crtc *sde_crtc)
	return rc;
}

/*
 * __sde_crtc_idle_notify_work - signal idle timeout to user space
 */
static void __sde_crtc_idle_notify_work(struct kthread_work *work)
{
	struct sde_crtc *sde_crtc = container_of(work, struct sde_crtc,
				idle_notify_work.work);
	struct drm_crtc *crtc;
	struct drm_event event;
	int ret = 0;

	if (!sde_crtc) {
		SDE_ERROR("invalid sde crtc\n");
	} else {
		crtc = &sde_crtc->base;
		event.type = DRM_EVENT_IDLE_NOTIFY;
		event.length = sizeof(u32);
		msm_mode_object_event_notify(&crtc->base, crtc->dev,
				&event, (u8 *)&ret);

		SDE_DEBUG("crtc[%d]: idle timeout notified\n", crtc->base.id);
	}
}


/* initialize crtc */
struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane)
{
@@ -4570,6 +4630,9 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane)
	sde_cp_crtc_init(crtc);
	sde_cp_crtc_install_properties(crtc);

	kthread_init_delayed_work(&sde_crtc->idle_notify_work,
					__sde_crtc_idle_notify_work);

	SDE_DEBUG("%s: successfully initialized crtc\n", sde_crtc->name);
	return crtc;
}
@@ -4715,3 +4778,9 @@ static int sde_crtc_pm_event_handler(struct drm_crtc *crtc, bool en,
	 */
	return 0;
}

static int sde_crtc_idle_interrupt_handler(struct drm_crtc *crtc_drm,
	bool en, struct sde_irq_callback *irq)
{
	return 0;
}
+3 −0
Original line number Diff line number Diff line
@@ -204,6 +204,7 @@ struct sde_crtc_event {
 * @misr_enable   : boolean entry indicates misr enable/disable status.
 * @misr_frame_count  : misr frame count provided by client
 * @misr_data     : store misr data before turning off the clocks.
 * @idle_notify_work: delayed worker to notify idle timeout to user space
 * @power_event   : registered power event handle
 * @cur_perf      : current performance committed to clock/bandwidth driver
 * @rp_lock       : serialization lock for resource pool
@@ -264,6 +265,8 @@ struct sde_crtc {
	u32 misr_frame_count;
	u32 misr_data[CRTC_DUAL_MIXERS];

	struct kthread_delayed_work idle_notify_work;

	struct sde_power_event *power_event;

	struct sde_core_perf_params cur_perf;
+2 −2
Original line number Diff line number Diff line
@@ -2620,7 +2620,7 @@ static void _sde_encoder_update_master(struct drm_encoder *drm_enc,
	}
}

bool sde_encoder_is_cmd_mode(struct drm_encoder *drm_enc)
bool sde_encoder_check_mode(struct drm_encoder *drm_enc, u32 mode)
{
	struct sde_encoder_virt *sde_enc;
	struct msm_display_info *disp_info;
@@ -2633,7 +2633,7 @@ bool sde_encoder_is_cmd_mode(struct drm_encoder *drm_enc)
	sde_enc = to_sde_encoder_virt(drm_enc);
	disp_info = &sde_enc->disp_info;

	return (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE);
	return (disp_info->capabilities & mode);
}

void sde_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc)
+3 −2
Original line number Diff line number Diff line
@@ -175,11 +175,12 @@ bool sde_encoder_is_dsc_enabled(struct drm_encoder *drm_enc);
bool sde_encoder_is_dsc_merge(struct drm_encoder *drm_enc);

/**
 * sde_encoder_is_cmd_mode - check if it is cmd mode
 * sde_encoder_check_mode - check if given mode is supported or not
 * @drm_enc: Pointer to drm encoder object
 * @mode: Mode to be checked
 * @Return: true if it is cmd mode
 */
bool sde_encoder_is_cmd_mode(struct drm_encoder *drm_enc);
bool sde_encoder_check_mode(struct drm_encoder *drm_enc, u32 mode);

/**
 * sde_encoder_init - initialize virtual encoder object
Loading