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)
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];
+}