drm/tegra: plane: Support asynchronous atomic updates
authorDmitry Osipenko <digetx@gmail.com>
Mon, 24 Dec 2018 13:01:57 +0000 (16:01 +0300)
committerDmitry Osipenko <digetx@gmail.com>
Sat, 9 Feb 2019 19:15:23 +0000 (22:15 +0300)
Support asynchronous atomic plane updates which help to avoid blocking
on moving cursor around on Tegra20/30. That will be also very useful for
video displaying once async updates will be exposed to userspace by DRM
core.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/plane.c
drivers/gpu/drm/tegra/plane.h

index 607a6ea..872900e 100644 (file)
@@ -726,10 +726,61 @@ static void tegra_plane_atomic_update(struct drm_plane *plane,
        tegra_dc_setup_window(p, &window);
 }
 
+static int tegra_plane_atomic_async_check(struct drm_plane *plane,
+                                         struct drm_plane_state *state)
+{
+       int err;
+
+       /*
+        * It is not obvious whether it's fine for framebuffer to disappear
+        * while display controller could be accessing it or hardware could
+        * cope with that somehow. Let's just disallow that to happen.
+        */
+       if (!state->fb)
+               return -EINVAL;
+
+       /* the rest should be fine to change asynchronously */
+       err = tegra_plane_atomic_check(plane, state);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static inline void tegra_plane_clear_latching(struct drm_plane *plane)
+{
+       struct tegra_plane *p = to_tegra_plane(plane);
+       struct tegra_dc *dc = p->dc;
+
+       /* clear pending latching request from the previous async update */
+       tegra_dc_writel(dc, 0, DC_CMD_STATE_CONTROL);
+}
+
+static inline void tegra_plane_atomic_flush(struct drm_plane *plane)
+{
+       struct tegra_plane *p = to_tegra_plane(plane);
+       struct tegra_dc *dc = p->dc;
+
+       /* latch updated registers and activate the new state */
+       tegra_dc_writel(dc, 1 << (p->index + 9), DC_CMD_STATE_CONTROL);
+       tegra_dc_writel(dc, 1 << (p->index + 1), DC_CMD_STATE_CONTROL);
+}
+
+static void tegra_plane_atomic_async_update(struct drm_plane *plane,
+                                           struct drm_plane_state *state)
+{
+       tegra_plane_clear_latching(plane);
+       tegra_plane_copy_state(plane, state);
+       tegra_plane_atomic_update(plane, plane->state);
+       tegra_plane_atomic_flush(plane);
+}
+
 static const struct drm_plane_helper_funcs tegra_plane_helper_funcs = {
        .atomic_check = tegra_plane_atomic_check,
        .atomic_disable = tegra_plane_atomic_disable,
        .atomic_update = tegra_plane_atomic_update,
+       .atomic_async_check = tegra_plane_atomic_async_check,
+       .atomic_async_update = tegra_plane_atomic_async_update,
 };
 
 static unsigned long tegra_plane_get_possible_crtcs(struct drm_device *drm)
index cd6f711..56c5f02 100644 (file)
@@ -484,3 +484,38 @@ int tegra_plane_setup_legacy_state(struct tegra_plane *tegra,
 
        return 0;
 }
+
+void tegra_plane_copy_state(struct drm_plane *plane,
+                           struct drm_plane_state *state)
+{
+       struct tegra_plane_state *tegra = to_tegra_plane_state(plane->state);
+       struct tegra_plane_state *tegra_new = to_tegra_plane_state(state);
+       unsigned int i;
+
+       drm_framebuffer_assign(&plane->state->fb, state->fb);
+       plane->state->crtc_x = state->crtc_x;
+       plane->state->crtc_y = state->crtc_y;
+       plane->state->crtc_w = state->crtc_w;
+       plane->state->crtc_h = state->crtc_h;
+       plane->state->src_x = state->src_x;
+       plane->state->src_y = state->src_y;
+       plane->state->src_w = state->src_w;
+       plane->state->src_h = state->src_h;
+       plane->state->src_h = state->src_h;
+       plane->state->alpha = state->alpha;
+       plane->state->rotation = state->rotation;
+       plane->state->zpos = state->zpos;
+       plane->state->normalized_zpos = state->normalized_zpos;
+       plane->state->src = state->src;
+       plane->state->dst = state->dst;
+       plane->state->visible = state->visible;
+
+       tegra->swap = tegra_new->swap;
+       tegra->tiling = tegra_new->tiling;
+       tegra->format = tegra_new->format;
+       tegra->opaque = tegra_new->opaque;
+       tegra->bottom_up = tegra_new->bottom_up;
+
+       for (i = 0; i < 2; i++)
+               tegra->blending[i] = tegra_new->blending[i];
+}
index e79e6b4..4d0ec55 100644 (file)
@@ -71,5 +71,7 @@ int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap);
 bool tegra_plane_format_is_yuv(unsigned int format, bool *planar);
 int tegra_plane_setup_legacy_state(struct tegra_plane *tegra,
                                   struct tegra_plane_state *state);
+void tegra_plane_copy_state(struct drm_plane *plane,
+                           struct drm_plane_state *state);
 
 #endif /* TEGRA_PLANE_H */