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

Commit b0b958f2 authored by Dhaval Patel's avatar Dhaval Patel Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drm/msm/sde: enable proper support for split flush" into dev/msm-4.4-drm_kms

parents b97a5e56 e3e50f0c
Loading
Loading
Loading
Loading
+1 −50
Original line number Diff line number Diff line
@@ -379,54 +379,6 @@ void sde_crtc_complete_commit(struct drm_crtc *crtc)
	sde_fence_signal(&to_sde_crtc(crtc)->output_fence, 0);
}

/**
 * _sde_crtc_trigger_kickoff - Iterate through the control paths and trigger
 *	the hw_ctl object to flush any pending flush mask, and trigger
 *	control start if the interface types require it.
 *
 *	This is currently designed to be called only once per crtc, per flush.
 *	It should be called from the encoder, through the
 *	sde_encoder_schedule_kickoff callflow, after all the encoders are ready
 *	to have CTL_START triggered.
 *
 *	It is called from the commit thread context.
 * @data: crtc pointer
 */
static void _sde_crtc_trigger_kickoff(void *data)
{
	struct drm_crtc *crtc = (struct drm_crtc *)data;
	struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
	struct sde_crtc_mixer *mixer;
	struct sde_hw_ctl *ctl;
	int i;

	if (!data) {
		SDE_ERROR("invalid argument\n");
		return;
	}

	MSM_EVT(crtc->dev, crtc->base.id, 0);

	/* Commit all pending flush masks to hardware */
	for (i = 0; i < ARRAY_SIZE(sde_crtc->mixers); i++) {
		ctl = sde_crtc->mixers[i].hw_ctl;
		if (ctl) {
			ctl->ops.trigger_flush(ctl);
			MSM_EVT(crtc->dev, crtc->base.id, ctl->idx);
		}
	}

	/* Signal start to any interface types that require it */
	for (i = 0; i < ARRAY_SIZE(sde_crtc->mixers); i++) {
		mixer = &sde_crtc->mixers[i];
		ctl = mixer->hw_ctl;
		if (ctl && sde_encoder_needs_ctl_start(mixer->encoder)) {
			ctl->ops.trigger_start(ctl);
			MSM_EVT(crtc->dev, crtc->base.id, ctl->idx);
		}
	}
}

/**
 * _sde_crtc_set_input_fence_timeout - update ns version of in fence timeout
 * @cstate: Pointer to sde crtc state
@@ -724,8 +676,7 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc)
		 * Encoder will flush/start now, unless it has a tx pending.
		 * If so, it may delay and flush at an irq event (e.g. ppdone)
		 */
		sde_encoder_schedule_kickoff(encoder, _sde_crtc_trigger_kickoff,
				crtc);
		sde_encoder_schedule_kickoff(encoder);
	}
}

+116 −22
Original line number Diff line number Diff line
@@ -208,24 +208,6 @@ void sde_encoder_get_hw_resources(struct drm_encoder *drm_enc,
	}
}

bool sde_encoder_needs_ctl_start(struct drm_encoder *drm_enc)
{
	struct sde_encoder_virt *sde_enc = NULL;
	struct sde_encoder_phys *phys;

	if (!drm_enc) {
		SDE_ERROR("invalid pointer\n");
		return false;
	}
	sde_enc = to_sde_encoder_virt(drm_enc);
	phys = sde_enc->cur_master;

	if (phys && phys->ops.needs_ctl_start)
		return phys->ops.needs_ctl_start(phys);

	return false;
}

static void sde_encoder_destroy(struct drm_encoder *drm_enc)
{
	struct sde_encoder_virt *sde_enc = NULL;
@@ -550,8 +532,121 @@ static void sde_encoder_handle_phys_enc_ready_for_kickoff(
	wake_up_all(&sde_enc->pending_kickoff_wq);
}

void sde_encoder_schedule_kickoff(struct drm_encoder *drm_enc,
		void (*kickoff_cb)(void *), void *kickoff_data)
/**
 * _sde_encoder_trigger_flush - trigger flush for a physical encoder
 * drm_enc: Pointer to drm encoder structure
 * phys: Pointer to physical encoder structure
 * extra_flush_bits: Additional bit mask to include in flush trigger
 */
static inline void _sde_encoder_trigger_flush(struct drm_encoder *drm_enc,
		struct sde_encoder_phys *phys, uint32_t extra_flush_bits)
{
	struct sde_hw_ctl *ctl;

	if (!drm_enc || !phys) {
		SDE_ERROR("invalid argument(s), drm_enc %d, phys_enc %d\n",
				drm_enc != 0, phys != 0);
		return;
	}

	ctl = phys->hw_ctl;
	if (!ctl || !ctl->ops.trigger_flush) {
		SDE_ERROR("missing trigger cb\n");
		return;
	}

	if (extra_flush_bits && ctl->ops.update_pending_flush)
		ctl->ops.update_pending_flush(ctl, extra_flush_bits);

	ctl->ops.trigger_flush(ctl);
	MSM_EVT(drm_enc->dev, drm_enc->base.id, ctl->idx);
}

/**
 * _sde_encoder_trigger_start - trigger start for a physical encoder
 * phys: Pointer to physical encoder structure
 */
static inline void _sde_encoder_trigger_start(struct sde_encoder_phys *phys)
{
	if (!phys) {
		SDE_ERROR("invalid encoder\n");
		return;
	}

	if (phys->ops.trigger_start && phys->enable_state != SDE_ENC_DISABLED)
		phys->ops.trigger_start(phys);
}

void sde_encoder_helper_trigger_start(struct sde_encoder_phys *phys_enc)
{
	struct sde_hw_ctl *ctl;
	int ctl_idx = -1;

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

	ctl = phys_enc->hw_ctl;
	if (ctl && ctl->ops.trigger_start) {
		ctl->ops.trigger_start(ctl);
		ctl_idx = ctl->idx;
	}

	if (phys_enc && phys_enc->parent)
		MSM_EVT(phys_enc->parent->dev,
				phys_enc->parent->base.id,
				ctl_idx);
}

/**
 * _sde_encoder_kickoff_phys - handle physical encoder kickoff
 *	Iterate through the physical encoders and perform consolidated flush
 *	and/or control start triggering as needed. This is done in the virtual
 *	encoder rather than the individual physical ones in order to handle
 *	use cases that require visibility into multiple physical encoders at
 *	a time.
 * sde_enc: Pointer to virtual encoder structure
 */
static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc)
{
	struct sde_hw_ctl *ctl;
	uint32_t i, pending_flush;

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

	pending_flush = 0x0;

	/* don't perform flush/start operations for slave encoders */
	for (i = 0; i < sde_enc->num_phys_encs; i++) {
		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];

		ctl = phys->hw_ctl;
		if (!ctl || phys->enable_state == SDE_ENC_DISABLED)
			continue;

		if (!phys->ops.needs_split_flush ||
				!phys->ops.needs_split_flush(phys))
			_sde_encoder_trigger_flush(&sde_enc->base, phys, 0x0);
		else if (ctl->ops.get_pending_flush)
			pending_flush |= ctl->ops.get_pending_flush(ctl);
	}

	/* for split flush, combine pending flush masks and send to master */
	if (pending_flush && sde_enc->cur_master) {
		_sde_encoder_trigger_flush(
				&sde_enc->base,
				sde_enc->cur_master,
				pending_flush);
	}

	_sde_encoder_trigger_start(sde_enc->cur_master);
}

void sde_encoder_schedule_kickoff(struct drm_encoder *drm_enc)
{
	struct sde_encoder_virt *sde_enc;
	struct sde_encoder_phys *phys;
@@ -607,8 +702,7 @@ void sde_encoder_schedule_kickoff(struct drm_encoder *drm_enc,
	}

	/* All phys encs are ready to go, trigger the kickoff */
	if (kickoff_cb)
		kickoff_cb(kickoff_data);
	_sde_encoder_kickoff_phys(sde_enc);

	/* Allow phys encs to handle any post-kickoff business */
	for (i = 0; i < sde_enc->num_phys_encs; i++) {
+12 −2
Original line number Diff line number Diff line
@@ -79,7 +79,8 @@ struct sde_encoder_virt_ops {
 *				triggering the next kickoff
 *				(ie for previous tx to complete)
 * @handle_post_kickoff:	Do any work necessary post-kickoff work
 * @needs_ctl_start:		Whether encoder type needs ctl_start
 * @trigger_start:		Process start event on physical encoder
 * @needs_split_flush:		Whether encoder type needs split flush
 */

struct sde_encoder_phys_ops {
@@ -104,7 +105,8 @@ struct sde_encoder_phys_ops {
	void (*prepare_for_kickoff)(struct sde_encoder_phys *phys_enc,
			bool *wait_until_ready);
	void (*handle_post_kickoff)(struct sde_encoder_phys *phys_enc);
	bool (*needs_ctl_start)(struct sde_encoder_phys *phys_enc);
	void (*trigger_start)(struct sde_encoder_phys *phys_enc);
	bool (*needs_split_flush)(struct sde_encoder_phys *phys_enc);
};

/**
@@ -301,4 +303,12 @@ void sde_encoder_phys_setup_cdm(struct sde_encoder_phys *phys_enc,
		struct drm_framebuffer *fb, const struct sde_format *format,
		struct sde_rect *wb_roi);

/**
 * sde_encoder_helper_trigger_start - control start helper function
 *	This helper function may be optionally specified by physical
 *	encoders if they require ctl_start triggering.
 * @phys_enc: Pointer to physical encoder structure
 */
void sde_encoder_helper_trigger_start(struct sde_encoder_phys *phys_enc);

#endif /* __sde_encoder_phys_H__ */
+10 −8
Original line number Diff line number Diff line
@@ -335,6 +335,12 @@ static void sde_encoder_phys_cmd_pingpong_config(
	sde_encoder_phys_cmd_tearcheck_config(phys_enc);
}

static bool sde_encoder_phys_cmd_needs_split_flush(
		struct sde_encoder_phys *phys_enc)
{
	return false;
}

static void sde_encoder_phys_cmd_split_config(
		struct sde_encoder_phys *phys_enc, bool enable)
{
@@ -352,7 +358,8 @@ static void sde_encoder_phys_cmd_split_config(
	cfg.en = enable;
	cfg.mode = INTF_MODE_CMD;
	cfg.intf = cmd_enc->intf_idx;
	cfg.split_flush_en = enable;
	cfg.split_flush_en = enable &&
		sde_encoder_phys_cmd_needs_split_flush(phys_enc);

	if (hw_mdptop && hw_mdptop->ops.setup_split_pipe)
		hw_mdptop->ops.setup_split_pipe(hw_mdptop, &cfg);
@@ -539,12 +546,6 @@ static void sde_encoder_phys_cmd_prepare_for_kickoff(
	MSM_EVT(DEV(phys_enc), cmd_enc->hw_pp->idx, new_pending_cnt);
}

static bool sde_encoder_phys_cmd_needs_ctl_start(
		struct sde_encoder_phys *phys_enc)
{
	return true;
}

static void sde_encoder_phys_cmd_init_ops(
		struct sde_encoder_phys_ops *ops)
{
@@ -558,7 +559,8 @@ static void sde_encoder_phys_cmd_init_ops(
	ops->control_vblank_irq = sde_encoder_phys_cmd_control_vblank_irq;
	ops->wait_for_commit_done = sde_encoder_phys_cmd_wait_for_commit_done;
	ops->prepare_for_kickoff = sde_encoder_phys_cmd_prepare_for_kickoff;
	ops->needs_ctl_start = sde_encoder_phys_cmd_needs_ctl_start;
	ops->trigger_start = sde_encoder_helper_trigger_start;
	ops->needs_split_flush = sde_encoder_phys_cmd_needs_split_flush;
}

struct sde_encoder_phys *sde_encoder_phys_cmd_init(
+9 −8
Original line number Diff line number Diff line
@@ -315,6 +315,12 @@ static void sde_encoder_phys_vid_vblank_irq(void *arg, int irq_idx)
	complete_all(&vid_enc->vblank_completion);
}

static bool sde_encoder_phys_vid_needs_split_flush(
		struct sde_encoder_phys *phys_enc)
{
	return phys_enc && phys_enc->split_role != ENC_ROLE_SOLO;
}

static void _sde_encoder_phys_vid_split_config(
		struct sde_encoder_phys *phys_enc, bool enable)
{
@@ -328,7 +334,8 @@ static void _sde_encoder_phys_vid_split_config(
	cfg.en = enable;
	cfg.mode = INTF_MODE_VIDEO;
	cfg.intf = vid_enc->hw_intf->idx;
	cfg.split_flush_en = enable;
	cfg.split_flush_en = enable &&
		sde_encoder_phys_vid_needs_split_flush(phys_enc);

	/* Configure split pipe control to handle master/slave triggering */
	if (hw_mdptop && hw_mdptop->ops.setup_split_pipe) {
@@ -664,12 +671,6 @@ static void sde_encoder_phys_vid_handle_post_kickoff(
	}
}

static bool sde_encoder_phys_vid_needs_ctl_start(
		struct sde_encoder_phys *phys_enc)
{
	return false;
}

static void sde_encoder_phys_vid_init_ops(struct sde_encoder_phys_ops *ops)
{
	ops->is_master = sde_encoder_phys_vid_is_master;
@@ -683,7 +684,7 @@ static void sde_encoder_phys_vid_init_ops(struct sde_encoder_phys_ops *ops)
	ops->wait_for_commit_done = sde_encoder_phys_vid_wait_for_commit_done;
	ops->prepare_for_kickoff = sde_encoder_phys_vid_prepare_for_kickoff;
	ops->handle_post_kickoff = sde_encoder_phys_vid_handle_post_kickoff;
	ops->needs_ctl_start = sde_encoder_phys_vid_needs_ctl_start;
	ops->needs_split_flush = sde_encoder_phys_vid_needs_split_flush;
}

struct sde_encoder_phys *sde_encoder_phys_vid_init(
Loading