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

Commit 49ec5b2e authored by Rob Clark's avatar Rob Clark
Browse files

drm/msm/mdp5: handle SMP block allocations "atomically"



Previously, SMP block allocation was not checked in the plane's
atomic_check() fxn, so we could fail allocation SMP block allocation at
atomic_update() time.  Re-work the block allocation to request blocks
during atomic_check(), but not update the hw until committing the atomic
update.

Since SMP blocks allocated at atomic_check() time, we need to manage the
SMP state as part of mdp5_state (global atomic state).  This actually
ends up significantly simplifying the SMP management, as the SMP module
does not need to manage the intermediate state between assigning new
blocks before setting flush bits and releasing old blocks after vblank.
(The SMP registers and SMP allocation is not double-buffered, so newly
allocated blocks need to be updated in kms->prepare_commit() released
blocks in kms->complete_commit().)

Signed-off-by: default avatarRob Clark <robdclark@gmail.com>
parent 4a0f012d
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -93,6 +93,8 @@ struct mdp5_state *mdp5_get_state(struct drm_atomic_state *s)

	/* Copy state: */
	new_state->hwpipe = mdp5_kms->state->hwpipe;
	if (mdp5_kms->smp)
		new_state->smp = mdp5_kms->state->smp;

	state->state = new_state;

@@ -108,7 +110,11 @@ static void mdp5_swap_state(struct msm_kms *kms, struct drm_atomic_state *state)
static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state)
{
	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));

	mdp5_enable(mdp5_kms);

	if (mdp5_kms->smp)
		mdp5_smp_prepare_commit(mdp5_kms->smp, &mdp5_kms->state->smp);
}

static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state)
@@ -121,6 +127,9 @@ static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *s
	for_each_plane_in_state(state, plane, plane_state, i)
		mdp5_plane_complete_commit(plane, plane_state);

	if (mdp5_kms->smp)
		mdp5_smp_complete_commit(mdp5_kms->smp, &mdp5_kms->state->smp);

	mdp5_disable(mdp5_kms);
}

@@ -825,7 +834,7 @@ static int mdp5_init(struct platform_device *pdev, struct drm_device *dev)
	 * this section initializes the SMP:
	 */
	if (mdp5_kms->caps & MDP_CAP_SMP) {
		mdp5_kms->smp = mdp5_smp_init(mdp5_kms->dev, &config->hw->smp);
		mdp5_kms->smp = mdp5_smp_init(mdp5_kms, &config->hw->smp);
		if (IS_ERR(mdp5_kms->smp)) {
			ret = PTR_ERR(mdp5_kms->smp);
			mdp5_kms->smp = NULL;
+1 −0
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ struct mdp5_kms {
 */
struct mdp5_state {
	struct mdp5_hw_pipe_state hwpipe;
	struct mdp5_smp_state smp;
};

struct mdp5_state *__must_check
+20 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@
#include "mdp5_kms.h"

struct mdp5_hw_pipe *mdp5_pipe_assign(struct drm_atomic_state *s,
		struct drm_plane *plane, uint32_t caps)
		struct drm_plane *plane, uint32_t caps, uint32_t blkcfg)
{
	struct msm_drm_private *priv = s->dev->dev_private;
	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
@@ -64,6 +64,18 @@ struct mdp5_hw_pipe *mdp5_pipe_assign(struct drm_atomic_state *s,
	if (!hwpipe)
		return ERR_PTR(-ENOMEM);

	if (mdp5_kms->smp) {
		int ret;

		DBG("%s: alloc SMP blocks", hwpipe->name);
		ret = mdp5_smp_assign(mdp5_kms->smp, &state->smp,
				hwpipe->pipe, blkcfg);
		if (ret)
			return ERR_PTR(-ENOMEM);

		hwpipe->blkcfg = blkcfg;
	}

	DBG("%s: assign to plane %s for caps %x",
			hwpipe->name, plane->name, caps);
	new_state->hwpipe_to_plane[hwpipe->idx] = plane;
@@ -73,6 +85,8 @@ struct mdp5_hw_pipe *mdp5_pipe_assign(struct drm_atomic_state *s,

void mdp5_pipe_release(struct drm_atomic_state *s, struct mdp5_hw_pipe *hwpipe)
{
	struct msm_drm_private *priv = s->dev->dev_private;
	struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(priv->kms));
	struct mdp5_state *state = mdp5_get_state(s);
	struct mdp5_hw_pipe_state *new_state = &state->hwpipe;

@@ -85,6 +99,11 @@ void mdp5_pipe_release(struct drm_atomic_state *s, struct mdp5_hw_pipe *hwpipe)
	DBG("%s: release from plane %s", hwpipe->name,
		new_state->hwpipe_to_plane[hwpipe->idx]->name);

	if (mdp5_kms->smp) {
		DBG("%s: free SMP blocks", hwpipe->name);
		mdp5_smp_release(mdp5_kms->smp, &state->smp, hwpipe->pipe);
	}

	new_state->hwpipe_to_plane[hwpipe->idx] = NULL;
}

+6 −1
Original line number Diff line number Diff line
@@ -32,6 +32,11 @@ struct mdp5_hw_pipe {
	uint32_t caps;

	uint32_t flush_mask;      /* used to commit pipe registers */

	/* number of smp blocks per plane, ie:
	 *   nblks_y | (nblks_u << 8) | (nblks_v << 16)
	 */
	uint32_t blkcfg;
};

/* global atomic state of assignment between pipes and planes: */
@@ -41,7 +46,7 @@ struct mdp5_hw_pipe_state {

struct mdp5_hw_pipe *__must_check
mdp5_pipe_assign(struct drm_atomic_state *s, struct drm_plane *plane,
		uint32_t caps);
		uint32_t caps, uint32_t blkcfg);
void mdp5_pipe_release(struct drm_atomic_state *s, struct mdp5_hw_pipe *hwpipe);

struct mdp5_hw_pipe *mdp5_pipe_init(enum mdp5_pipe pipe,
+13 −49
Original line number Diff line number Diff line
@@ -296,6 +296,8 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane,
	if (plane_enabled(state)) {
		unsigned int rotation;
		const struct mdp_format *format;
		struct mdp5_kms *mdp5_kms = get_kms(plane);
		uint32_t blkcfg = 0;

		format = to_mdp_format(msm_framebuffer_format(state->fb));
		if (MDP_FORMAT_IS_YUV(format))
@@ -320,24 +322,16 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane,
		if (!mdp5_state->hwpipe || (caps & ~mdp5_state->hwpipe->caps))
			new_hwpipe = true;

		if (plane_enabled(old_state)) {
			bool full_modeset = false;
			if (state->fb->pixel_format != old_state->fb->pixel_format) {
				DBG("%s: pixel_format change!", plane->name);
				full_modeset = true;
			}
			if (state->src_w != old_state->src_w) {
				DBG("%s: src_w change!", plane->name);
				full_modeset = true;
			}
			if (full_modeset) {
				/* cannot change SMP block allocation during
				 * scanout:
				 */
				if (get_kms(plane)->smp)
		if (mdp5_kms->smp) {
			const struct mdp_format *format =
				to_mdp_format(msm_framebuffer_format(state->fb));

			blkcfg = mdp5_smp_calculate(mdp5_kms->smp, format,
					state->src_w >> 16, false);

			if (mdp5_state->hwpipe && (mdp5_state->hwpipe->blkcfg != blkcfg))
				new_hwpipe = true;
		}
		}

		/* (re)assign hwpipe if needed, otherwise keep old one: */
		if (new_hwpipe) {
@@ -346,8 +340,8 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane,
			 * it available for other planes?
			 */
			struct mdp5_hw_pipe *old_hwpipe = mdp5_state->hwpipe;
			mdp5_state->hwpipe =
				mdp5_pipe_assign(state->state, plane, caps);
			mdp5_state->hwpipe = mdp5_pipe_assign(state->state,
					plane, caps, blkcfg);
			if (IS_ERR(mdp5_state->hwpipe)) {
				DBG("%s: failed to assign hwpipe!", plane->name);
				return PTR_ERR(mdp5_state->hwpipe);
@@ -711,23 +705,6 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
			fb->base.id, src_x, src_y, src_w, src_h,
			crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);

	/* Request some memory from the SMP: */
	if (mdp5_kms->smp) {
		ret = mdp5_smp_request(mdp5_kms->smp, pipe,
				format, src_w, false);
		if (ret)
			return ret;
	}

	/*
	 * Currently we update the hw for allocations/requests immediately,
	 * but once atomic modeset/pageflip is in place, the allocation
	 * would move into atomic->check_plane_state(), while updating the
	 * hw would remain here:
	 */
	if (mdp5_kms->smp)
		mdp5_smp_configure(mdp5_kms->smp, pipe);

	ret = calc_scalex_steps(plane, pix_format, src_w, crtc_w, phasex_step);
	if (ret)
		return ret;
@@ -865,21 +842,8 @@ uint32_t mdp5_plane_get_flush(struct drm_plane *plane)
void mdp5_plane_complete_commit(struct drm_plane *plane,
	struct drm_plane_state *state)
{
	struct mdp5_kms *mdp5_kms = get_kms(plane);
	struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state);

	if (mdp5_kms->smp && pstate->hwpipe) {
		enum mdp5_pipe pipe = pstate->hwpipe->pipe;

		if (plane_enabled(plane->state)) {
			DBG("%s: complete flip", plane->name);
			mdp5_smp_commit(mdp5_kms->smp, pipe);
		} else {
			DBG("%s: free SMP", plane->name);
			mdp5_smp_release(mdp5_kms->smp, pipe);
		}
	}

	pstate->pending = false;
}

Loading