[PATCH 8/9] drm/tve200: replace struct drm_simple_display_pipe with regular atomic helpers
Ze Huang
ze.huang at oss.qualcomm.com
Sat Jul 4 11:31:17 PDT 2026
Convert TVE200 to explicit plane, CRTC and encoder objects.
Keep generic plane-state validation before TVE200-specific mode,
alignment, pitch and format-change checks, and install GEM framebuffer
prepare helper explicitly.
Signed-off-by: Ze Huang <ze.huang at oss.qualcomm.com>
---
drivers/gpu/drm/tve200/tve200_display.c | 221 ++++++++++++++++++++++----------
drivers/gpu/drm/tve200/tve200_drm.h | 6 +-
drivers/gpu/drm/tve200/tve200_drv.c | 17 ++-
3 files changed, 168 insertions(+), 76 deletions(-)
diff --git a/drivers/gpu/drm/tve200/tve200_display.c b/drivers/gpu/drm/tve200/tve200_display.c
index 26b6c65ef6fd..8fdf69e8e126 100644
--- a/drivers/gpu/drm/tve200/tve200_display.c
+++ b/drivers/gpu/drm/tve200/tve200_display.c
@@ -15,6 +15,8 @@
#include <linux/of_graph.h>
#include <linux/delay.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_dma_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
@@ -52,7 +54,7 @@ irqreturn_t tve200_irq(int irq, void *data)
val = readl(priv->regs + TVE200_CTRL);
/* We have an actual start of vsync */
if (!(val & TVE200_VSTSTYPE_BITS)) {
- drm_crtc_handle_vblank(&priv->pipe.crtc);
+ drm_crtc_handle_vblank(&priv->crtc);
/* Toggle trigger to start of active image */
val |= TVE200_VSTSTYPE_VAI;
} else {
@@ -69,13 +71,34 @@ irqreturn_t tve200_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static int tve200_display_check(struct drm_simple_display_pipe *pipe,
- struct drm_plane_state *pstate,
- struct drm_crtc_state *cstate)
+static int tve200_plane_helper_atomic_check(struct drm_plane *plane,
+ struct drm_atomic_commit *state)
{
- const struct drm_display_mode *mode = &cstate->mode;
- struct drm_framebuffer *old_fb = pipe->plane.state->fb;
+ struct drm_plane_state *pstate = drm_atomic_get_new_plane_state(state, plane);
+ struct drm_crtc *crtc = pstate->crtc;
+ struct drm_crtc_state *cstate = NULL;
+ const struct drm_display_mode *mode;
+ struct drm_framebuffer *old_fb = plane->state->fb;
struct drm_framebuffer *fb = pstate->fb;
+ int ret;
+
+ if (crtc)
+ cstate = drm_atomic_get_new_crtc_state(state, crtc);
+
+ ret = drm_atomic_helper_check_plane_state(pstate, cstate,
+ DRM_PLANE_NO_SCALING,
+ DRM_PLANE_NO_SCALING,
+ false, false);
+ if (ret)
+ return ret;
+
+ if (!pstate->visible)
+ return 0;
+
+ if (!cstate)
+ return 0;
+
+ mode = &cstate->mode;
/*
* We support these specific resolutions and nothing else.
@@ -119,16 +142,73 @@ static int tve200_display_check(struct drm_simple_display_pipe *pipe,
return 0;
}
-static void tve200_display_enable(struct drm_simple_display_pipe *pipe,
- struct drm_crtc_state *cstate,
- struct drm_plane_state *plane_state)
+static void tve200_plane_helper_atomic_update(struct drm_plane *plane,
+ struct drm_atomic_commit *state)
+{
+ struct drm_crtc *crtc = plane->state->crtc;
+ struct drm_device *drm;
+ struct tve200_drm_dev_private *priv;
+ struct drm_pending_vblank_event *event;
+ struct drm_plane_state *pstate = plane->state;
+ struct drm_framebuffer *fb = pstate->fb;
+
+ if (!crtc)
+ return;
+
+ drm = crtc->dev;
+ priv = drm->dev_private;
+ event = crtc->state->event;
+
+ if (fb) {
+ /* For RGB, the Y component is used as base address */
+ writel(drm_fb_dma_get_gem_addr(fb, pstate, 0),
+ priv->regs + TVE200_Y_FRAME_BASE_ADDR);
+
+ /* For three plane YUV we need two more addresses */
+ if (fb->format->format == DRM_FORMAT_YUV420) {
+ writel(drm_fb_dma_get_gem_addr(fb, pstate, 1),
+ priv->regs + TVE200_U_FRAME_BASE_ADDR);
+ writel(drm_fb_dma_get_gem_addr(fb, pstate, 2),
+ priv->regs + TVE200_V_FRAME_BASE_ADDR);
+ }
+ }
+
+ if (event) {
+ crtc->state->event = NULL;
+
+ spin_lock_irq(&crtc->dev->event_lock);
+ if (crtc->state->active && drm_crtc_vblank_get(crtc) == 0)
+ drm_crtc_arm_vblank_event(crtc, event);
+ else
+ drm_crtc_send_vblank_event(crtc, event);
+ spin_unlock_irq(&crtc->dev->event_lock);
+ }
+}
+
+static const struct drm_plane_helper_funcs tve200_plane_helper_funcs = {
+ .prepare_fb = drm_gem_plane_helper_prepare_fb,
+ .atomic_check = tve200_plane_helper_atomic_check,
+ .atomic_update = tve200_plane_helper_atomic_update,
+};
+
+static const struct drm_plane_funcs tve200_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = drm_plane_cleanup,
+ .reset = drm_atomic_helper_plane_reset,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+
+static void tve200_crtc_helper_atomic_enable(struct drm_crtc *crtc,
+ struct drm_atomic_commit *state)
{
- struct drm_crtc *crtc = &pipe->crtc;
- struct drm_plane *plane = &pipe->plane;
struct drm_device *drm = crtc->dev;
struct tve200_drm_dev_private *priv = drm->dev_private;
+ struct drm_crtc_state *cstate = drm_atomic_get_new_crtc_state(state, crtc);
const struct drm_display_mode *mode = &cstate->mode;
- struct drm_framebuffer *fb = plane->state->fb;
+ struct drm_plane_state *plane_state = priv->plane.state;
+ struct drm_framebuffer *fb = plane_state->fb;
struct drm_connector *connector = priv->connector;
u32 format = fb->format->format;
u32 ctrl1 = 0;
@@ -240,9 +320,9 @@ static void tve200_display_enable(struct drm_simple_display_pipe *pipe,
drm_crtc_vblank_on(crtc);
}
-static void tve200_display_disable(struct drm_simple_display_pipe *pipe)
+static void tve200_crtc_helper_atomic_disable(struct drm_crtc *crtc,
+ struct drm_atomic_commit *state)
{
- struct drm_crtc *crtc = &pipe->crtc;
struct drm_device *drm = crtc->dev;
struct tve200_drm_dev_private *priv = drm->dev_private;
@@ -255,46 +335,8 @@ static void tve200_display_disable(struct drm_simple_display_pipe *pipe)
clk_disable_unprepare(priv->clk);
}
-static void tve200_display_update(struct drm_simple_display_pipe *pipe,
- struct drm_plane_state *old_pstate)
-{
- struct drm_crtc *crtc = &pipe->crtc;
- struct drm_device *drm = crtc->dev;
- struct tve200_drm_dev_private *priv = drm->dev_private;
- struct drm_pending_vblank_event *event = crtc->state->event;
- struct drm_plane *plane = &pipe->plane;
- struct drm_plane_state *pstate = plane->state;
- struct drm_framebuffer *fb = pstate->fb;
-
- if (fb) {
- /* For RGB, the Y component is used as base address */
- writel(drm_fb_dma_get_gem_addr(fb, pstate, 0),
- priv->regs + TVE200_Y_FRAME_BASE_ADDR);
-
- /* For three plane YUV we need two more addresses */
- if (fb->format->format == DRM_FORMAT_YUV420) {
- writel(drm_fb_dma_get_gem_addr(fb, pstate, 1),
- priv->regs + TVE200_U_FRAME_BASE_ADDR);
- writel(drm_fb_dma_get_gem_addr(fb, pstate, 2),
- priv->regs + TVE200_V_FRAME_BASE_ADDR);
- }
- }
-
- if (event) {
- crtc->state->event = NULL;
-
- spin_lock_irq(&crtc->dev->event_lock);
- if (crtc->state->active && drm_crtc_vblank_get(crtc) == 0)
- drm_crtc_arm_vblank_event(crtc, event);
- else
- drm_crtc_send_vblank_event(crtc, event);
- spin_unlock_irq(&crtc->dev->event_lock);
- }
-}
-
-static int tve200_display_enable_vblank(struct drm_simple_display_pipe *pipe)
+static int tve200_crtc_enable_vblank(struct drm_crtc *crtc)
{
- struct drm_crtc *crtc = &pipe->crtc;
struct drm_device *drm = crtc->dev;
struct tve200_drm_dev_private *priv = drm->dev_private;
@@ -304,22 +346,49 @@ static int tve200_display_enable_vblank(struct drm_simple_display_pipe *pipe)
return 0;
}
-static void tve200_display_disable_vblank(struct drm_simple_display_pipe *pipe)
+static void tve200_crtc_disable_vblank(struct drm_crtc *crtc)
{
- struct drm_crtc *crtc = &pipe->crtc;
struct drm_device *drm = crtc->dev;
struct tve200_drm_dev_private *priv = drm->dev_private;
writel(0, priv->regs + TVE200_INT_EN);
}
-static const struct drm_simple_display_pipe_funcs tve200_display_funcs = {
- .check = tve200_display_check,
- .enable = tve200_display_enable,
- .disable = tve200_display_disable,
- .update = tve200_display_update,
- .enable_vblank = tve200_display_enable_vblank,
- .disable_vblank = tve200_display_disable_vblank,
+static int tve200_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_commit *state)
+{
+ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+ int ret;
+
+ if (!crtc_state->enable)
+ goto out;
+
+ ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state);
+ if (ret)
+ return ret;
+
+out:
+ return drm_atomic_add_affected_planes(state, crtc);
+}
+
+static const struct drm_crtc_helper_funcs tve200_crtc_helper_funcs = {
+ .atomic_check = tve200_crtc_helper_atomic_check,
+ .atomic_enable = tve200_crtc_helper_atomic_enable,
+ .atomic_disable = tve200_crtc_helper_atomic_disable,
+};
+
+static const struct drm_crtc_funcs tve200_crtc_funcs = {
+ .reset = drm_atomic_helper_crtc_reset,
+ .destroy = drm_crtc_cleanup,
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+ .enable_vblank = tve200_crtc_enable_vblank,
+ .disable_vblank = tve200_crtc_disable_vblank,
+};
+
+static const struct drm_encoder_funcs tve200_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
};
int tve200_display_init(struct drm_device *drm)
@@ -346,13 +415,31 @@ int tve200_display_init(struct drm_device *drm)
DRM_FORMAT_YUV420,
};
- ret = drm_simple_display_pipe_init(drm, &priv->pipe,
- &tve200_display_funcs,
- formats, ARRAY_SIZE(formats),
- NULL,
- priv->connector);
+ ret = drm_universal_plane_init(drm, &priv->plane, 0,
+ &tve200_plane_funcs,
+ formats, ARRAY_SIZE(formats),
+ NULL,
+ DRM_PLANE_TYPE_PRIMARY, NULL);
+ if (ret)
+ return ret;
+
+ drm_plane_helper_add(&priv->plane, &tve200_plane_helper_funcs);
+
+ ret = drm_crtc_init_with_planes(drm, &priv->crtc,
+ &priv->plane, NULL,
+ &tve200_crtc_funcs, NULL);
+ if (ret)
+ return ret;
+
+ drm_crtc_helper_add(&priv->crtc, &tve200_crtc_helper_funcs);
+
+ ret = drm_encoder_init(drm, &priv->encoder,
+ &tve200_encoder_funcs,
+ DRM_MODE_ENCODER_NONE, NULL);
if (ret)
return ret;
+ priv->encoder.possible_crtcs = drm_crtc_mask(&priv->crtc);
+
return 0;
}
diff --git a/drivers/gpu/drm/tve200/tve200_drm.h b/drivers/gpu/drm/tve200/tve200_drm.h
index 5420b52ea16b..631a9f5d9aa6 100644
--- a/drivers/gpu/drm/tve200/tve200_drm.h
+++ b/drivers/gpu/drm/tve200/tve200_drm.h
@@ -15,8 +15,6 @@
#include <linux/irqreturn.h>
-#include <drm/drm_simple_kms_helper.h>
-
struct clk;
struct drm_bridge;
struct drm_connector;
@@ -107,7 +105,9 @@ struct tve200_drm_dev_private {
struct drm_connector *connector;
struct drm_panel *panel;
struct drm_bridge *bridge;
- struct drm_simple_display_pipe pipe;
+ struct drm_plane plane;
+ struct drm_crtc crtc;
+ struct drm_encoder encoder;
void *regs;
struct clk *pclk;
diff --git a/drivers/gpu/drm/tve200/tve200_drv.c b/drivers/gpu/drm/tve200/tve200_drv.c
index 562f3f11812a..e2e8346acbb8 100644
--- a/drivers/gpu/drm/tve200/tve200_drv.c
+++ b/drivers/gpu/drm/tve200/tve200_drv.c
@@ -105,16 +105,21 @@ static int tve200_modeset_init(struct drm_device *dev)
goto out_bridge;
}
- ret = drm_simple_display_pipe_attach_bridge(&priv->pipe,
- bridge);
+ priv->panel = panel;
+ priv->connector = drm_panel_bridge_connector(bridge);
+ priv->bridge = bridge;
+
+ ret = drm_connector_attach_encoder(priv->connector, &priv->encoder);
if (ret) {
- dev_err(dev->dev, "failed to attach bridge\n");
+ dev_err(dev->dev, "failed to attach encoder\n");
goto out_bridge;
}
- priv->panel = panel;
- priv->connector = drm_panel_bridge_connector(bridge);
- priv->bridge = bridge;
+ ret = drm_bridge_attach(&priv->encoder, bridge, NULL, 0);
+ if (ret) {
+ dev_err(dev->dev, "failed to attach bridge\n");
+ goto out_bridge;
+ }
dev_info(dev->dev, "attached to panel %s\n",
dev_name(panel->dev));
--
2.55.0
More information about the linux-arm-kernel
mailing list