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

Commit 7fbd5d78 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'imx-drm-next-2019-02-22' of git://git.pengutronix.de/pza/linux into drm-next



drm/imx: handle pending updates better, add plane zpos property support

- Add a mechanism to only send commit done events once all pending
  updates have been applied. This closes a small race window where
  already armed events could fire even though the double buffered
  hardware update just missed the update window.
- Add plane zpos property support to allow placing the overlay plane
  behind the primary plane.
- Allow building imx-drm on all platforms under COMPILE_TEST.

Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Philipp Zabel <pza@pengutronix.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20190222112350.m3ucezilqx6cyest@pengutronix.de
parents fbac3c48 a0ea4fff
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@ config DRM_IMX
	select VIDEOMODE_HELPERS
	select DRM_GEM_CMA_HELPER
	select DRM_KMS_CMA_HELPER
	depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM)
	depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM || COMPILE_TEST)
	depends on IMX_IPUV3_CORE
	help
	  enable i.MX graphics support
@@ -18,6 +18,7 @@ config DRM_IMX_PARALLEL_DISPLAY
config DRM_IMX_TVE
	tristate "Support for TV and VGA displays"
	depends on DRM_IMX
	depends on COMMON_CLK
	select REGMAP_MMIO
	help
	  Choose this to enable the internal Television Encoder (TVe)
+2 −5
Original line number Diff line number Diff line
@@ -49,11 +49,7 @@ static int imx_drm_atomic_check(struct drm_device *dev,
{
	int ret;

	ret = drm_atomic_helper_check_modeset(dev, state);
	if (ret)
		return ret;

	ret = drm_atomic_helper_check_planes(dev, state);
	ret = drm_atomic_helper_check(dev, state);
	if (ret)
		return ret;

@@ -229,6 +225,7 @@ static int imx_drm_bind(struct device *dev)
	drm->mode_config.funcs = &imx_drm_mode_config_funcs;
	drm->mode_config.helper_private = &imx_drm_mode_config_helpers;
	drm->mode_config.allow_fb_modifiers = true;
	drm->mode_config.normalize_zpos = true;

	drm_mode_config_init(drm);

+28 −2
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ struct ipu_crtc {
	struct ipu_dc		*dc;
	struct ipu_di		*di;
	int			irq;
	struct drm_pending_vblank_event *event;
};

static inline struct ipu_crtc *to_ipu_crtc(struct drm_crtc *crtc)
@@ -173,8 +174,31 @@ static const struct drm_crtc_funcs ipu_crtc_funcs = {
static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
{
	struct ipu_crtc *ipu_crtc = dev_id;
	struct drm_crtc *crtc = &ipu_crtc->base;
	unsigned long flags;
	int i;

	drm_crtc_handle_vblank(crtc);

	if (ipu_crtc->event) {
		for (i = 0; i < ARRAY_SIZE(ipu_crtc->plane); i++) {
			struct ipu_plane *plane = ipu_crtc->plane[i];

			if (!plane)
				continue;

			if (ipu_plane_atomic_update_pending(&plane->base))
				break;
		}

	drm_crtc_handle_vblank(&ipu_crtc->base);
		if (i == ARRAY_SIZE(ipu_crtc->plane)) {
			spin_lock_irqsave(&crtc->dev->event_lock, flags);
			drm_crtc_send_vblank_event(crtc, ipu_crtc->event);
			ipu_crtc->event = NULL;
			drm_crtc_vblank_put(crtc);
			spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
		}
	}

	return IRQ_HANDLED;
}
@@ -223,8 +247,10 @@ static void ipu_crtc_atomic_flush(struct drm_crtc *crtc,
{
	spin_lock_irq(&crtc->dev->event_lock);
	if (crtc->state->event) {
		struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);

		WARN_ON(drm_crtc_vblank_get(crtc));
		drm_crtc_arm_vblank_event(crtc, crtc->state->event);
		ipu_crtc->event = crtc->state->event;
		crtc->state->event = NULL;
	}
	spin_unlock_irq(&crtc->dev->event_lock);
+51 −25
Original line number Diff line number Diff line
@@ -273,6 +273,7 @@ static void ipu_plane_destroy(struct drm_plane *plane)

static void ipu_plane_state_reset(struct drm_plane *plane)
{
	unsigned int zpos = (plane->type == DRM_PLANE_TYPE_PRIMARY) ? 0 : 1;
	struct ipu_plane_state *ipu_state;

	if (plane->state) {
@@ -284,8 +285,11 @@ static void ipu_plane_state_reset(struct drm_plane *plane)

	ipu_state = kzalloc(sizeof(*ipu_state), GFP_KERNEL);

	if (ipu_state)
	if (ipu_state) {
		__drm_atomic_helper_plane_reset(plane, &ipu_state->base);
		ipu_state->base.zpos = zpos;
		ipu_state->base.normalized_zpos = zpos;
	}
}

static struct drm_plane_state *
@@ -560,6 +564,25 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
	if (ipu_plane->dp_flow == IPU_DP_FLOW_SYNC_FG)
		ipu_dp_set_window_pos(ipu_plane->dp, dst->x1, dst->y1);

	switch (ipu_plane->dp_flow) {
	case IPU_DP_FLOW_SYNC_BG:
		if (state->normalized_zpos == 1) {
			ipu_dp_set_global_alpha(ipu_plane->dp,
						!fb->format->has_alpha, 0xff,
						true);
		} else {
			ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
		}
		break;
	case IPU_DP_FLOW_SYNC_FG:
		if (state->normalized_zpos == 1) {
			ipu_dp_set_global_alpha(ipu_plane->dp,
						!fb->format->has_alpha, 0xff,
						false);
		}
		break;
	}

	eba = drm_plane_state_to_eba(state, 0);

	/*
@@ -582,6 +605,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
		active = ipu_idmac_get_current_buffer(ipu_plane->ipu_ch);
		ipu_cpmem_set_buffer(ipu_plane->ipu_ch, !active, eba);
		ipu_idmac_select_buffer(ipu_plane->ipu_ch, !active);
		ipu_plane->next_buf = !active;
		if (ipu_plane_separate_alpha(ipu_plane)) {
			active = ipu_idmac_get_current_buffer(ipu_plane->alpha_ch);
			ipu_cpmem_set_buffer(ipu_plane->alpha_ch, !active,
@@ -595,34 +619,11 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
	switch (ipu_plane->dp_flow) {
	case IPU_DP_FLOW_SYNC_BG:
		ipu_dp_setup_channel(ipu_plane->dp, ics, IPUV3_COLORSPACE_RGB);
		ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
		break;
	case IPU_DP_FLOW_SYNC_FG:
		ipu_dp_setup_channel(ipu_plane->dp, ics,
					IPUV3_COLORSPACE_UNKNOWN);
		/* Enable local alpha on partial plane */
		switch (fb->format->format) {
		case DRM_FORMAT_ARGB1555:
		case DRM_FORMAT_ABGR1555:
		case DRM_FORMAT_RGBA5551:
		case DRM_FORMAT_BGRA5551:
		case DRM_FORMAT_ARGB4444:
		case DRM_FORMAT_ARGB8888:
		case DRM_FORMAT_ABGR8888:
		case DRM_FORMAT_RGBA8888:
		case DRM_FORMAT_BGRA8888:
		case DRM_FORMAT_RGB565_A8:
		case DRM_FORMAT_BGR565_A8:
		case DRM_FORMAT_RGB888_A8:
		case DRM_FORMAT_BGR888_A8:
		case DRM_FORMAT_RGBX8888_A8:
		case DRM_FORMAT_BGRX8888_A8:
			ipu_dp_set_global_alpha(ipu_plane->dp, false, 0, false);
		break;
		default:
			ipu_dp_set_global_alpha(ipu_plane->dp, true, 0, true);
			break;
		}
	}

	ipu_dmfc_config_wait4eot(ipu_plane->dmfc, drm_rect_width(dst));
@@ -709,6 +710,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane,
	ipu_cpmem_set_buffer(ipu_plane->ipu_ch, 1, eba);
	ipu_idmac_lock_enable(ipu_plane->ipu_ch, num_bursts);
	ipu_plane_enable(ipu_plane);
	ipu_plane->next_buf = -1;
}

static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = {
@@ -718,6 +720,24 @@ static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = {
	.atomic_update = ipu_plane_atomic_update,
};

bool ipu_plane_atomic_update_pending(struct drm_plane *plane)
{
	struct ipu_plane *ipu_plane = to_ipu_plane(plane);
	struct drm_plane_state *state = plane->state;
	struct ipu_plane_state *ipu_state = to_ipu_plane_state(state);

	/* disabled crtcs must not block the update */
	if (!state->crtc)
		return false;

	if (ipu_state->use_pre)
		return ipu_prg_channel_configure_pending(ipu_plane->ipu_ch);
	else if (ipu_plane->next_buf >= 0)
		return ipu_idmac_get_current_buffer(ipu_plane->ipu_ch) !=
		       ipu_plane->next_buf;

	return false;
}
int ipu_planes_assign_pre(struct drm_device *dev,
			  struct drm_atomic_state *state)
{
@@ -806,6 +826,7 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
{
	struct ipu_plane *ipu_plane;
	const uint64_t *modifiers = ipu_format_modifiers;
	unsigned int zpos = (type == DRM_PLANE_TYPE_PRIMARY) ? 0 : 1;
	int ret;

	DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
@@ -836,5 +857,10 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,

	drm_plane_helper_add(&ipu_plane->base, &ipu_plane_helper_funcs);

	if (dp == IPU_DP_FLOW_SYNC_BG || dp == IPU_DP_FLOW_SYNC_FG)
		drm_plane_create_zpos_property(&ipu_plane->base, zpos, 0, 1);
	else
		drm_plane_create_zpos_immutable_property(&ipu_plane->base, 0);

	return ipu_plane;
}
+2 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ struct ipu_plane {
	int			dp_flow;

	bool			disabling;
	int			next_buf;
};

struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
@@ -48,5 +49,6 @@ int ipu_plane_irq(struct ipu_plane *plane);

void ipu_plane_disable(struct ipu_plane *ipu_plane, bool disable_dp_channel);
void ipu_plane_disable_deferred(struct drm_plane *plane);
bool ipu_plane_atomic_update_pending(struct drm_plane *plane);

#endif
Loading