:p
atchew
Login
struct drm_simple_display_pipe was meant to simplify simple DRM drivers, but instead adds an extra wrapper around normal DRM atomic helper setup. As noted in Documentation/gpu/todo.rst, remaining users should be converted to regular atomic helpers and stop depending on the simple-KMS interfaces. This series converts the following drivers: - arcpgu - aspeed - imx lcdc - mcde - pl111 - gm12u320 - repaper - tve200 - xen frontend Each patch replaces drm_simple_display_pipe_init() with explicit primary plane, CRTC and encoder setup, and moves the old simple-pipe callbacks into regular plane and CRTC helper callbacks named according to local driver conventions. The conversions preserve helper behavior that used to be implicit in drm_simple_kms_helper.c, including plane-state validation, CRTC primary-plane checks, affected-plane propagation, framebuffer prepare handling, and existing event/vblank flow where applicable. Result is less helper indirection and more explicit driver-side atomic wiring, with no remaining simple-KMS dependency in these drivers. These changes are build-tested only. No hardware testing has been performed on the affected devices. This series is based on drm-next-2026-06-27. Thanks, Ze Huang Signed-off-by: Ze Huang <ze.huang@oss.qualcomm.com> --- Ze Huang (9): drm/arcpgu: replace struct drm_simple_display_pipe with regular atomic helpers drm/aspeed: replace struct drm_simple_display_pipe with regular atomic helpers drm/imx: replace struct drm_simple_display_pipe with regular atomic helpers drm/mcde: replace struct drm_simple_display_pipe with regular atomic helpers drm/pl111: replace struct drm_simple_display_pipe with regular atomic helpers drm/gm12u320: replace struct drm_simple_display_pipe with regular atomic helpers drm/repaper: replace struct drm_simple_display_pipe with regular atomic helpers drm/tve200: replace struct drm_simple_display_pipe with regular atomic helpers drm/xen: replace struct drm_simple_display_pipe with regular atomic helpers drivers/gpu/drm/aspeed/aspeed_gfx.h | 5 +- drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c | 156 ++++++++++++++++------ drivers/gpu/drm/aspeed/aspeed_gfx_drv.c | 3 +- drivers/gpu/drm/imx/lcdc/imx-lcdc.c | 178 ++++++++++++++++++------- drivers/gpu/drm/mcde/mcde_display.c | 162 ++++++++++++++++------ drivers/gpu/drm/mcde/mcde_drm.h | 6 +- drivers/gpu/drm/mcde/mcde_drv.c | 3 +- drivers/gpu/drm/pl111/pl111_display.c | 174 ++++++++++++++++++------ drivers/gpu/drm/pl111/pl111_drm.h | 5 +- drivers/gpu/drm/pl111/pl111_drv.c | 3 +- drivers/gpu/drm/tiny/arcpgu.c | 165 ++++++++++++++++++----- drivers/gpu/drm/tiny/gm12u320.c | 128 ++++++++++++++---- drivers/gpu/drm/tiny/repaper.c | 130 ++++++++++++++---- drivers/gpu/drm/tve200/tve200_display.c | 221 +++++++++++++++++++++---------- drivers/gpu/drm/tve200/tve200_drm.h | 6 +- drivers/gpu/drm/tve200/tve200_drv.c | 17 ++- drivers/gpu/drm/xen/xen_drm_front.h | 6 +- drivers/gpu/drm/xen/xen_drm_front_kms.c | 177 +++++++++++++++++++------ 18 files changed, 1164 insertions(+), 381 deletions(-) --- base-commit: 3696d07837d1df13a5603d77f667685e7dfb3c53 change-id: 20260704-drm-simple-kms-removal-01a031c6a129 Best regards, -- Ze Huang <ze.huang@oss.qualcomm.com>
Instantiate plane, CRTC and encoder directly and wire them up with standard atomic helpers. This removes arcpgu's dependency on deprecated simple-KMS display pipe interface. Signed-off-by: Ze Huang <ze.huang@oss.qualcomm.com> --- drivers/gpu/drm/tiny/arcpgu.c | 165 +++++++++++++++++++++++++++++++++--------- 1 file changed, 131 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/tiny/arcpgu.c b/drivers/gpu/drm/tiny/arcpgu.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/tiny/arcpgu.c +++ b/drivers/gpu/drm/tiny/arcpgu.c @@ -XXX,XX +XXX,XX @@ #include <drm/drm_fbdev_dma.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> +#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_module.h> #include <drm/drm_of.h> #include <drm/drm_probe_helper.h> -#include <drm/drm_simple_kms_helper.h> #include <linux/dma-mapping.h> #include <linux/module.h> #include <linux/of_reserved_mem.h> @@ -XXX,XX +XXX,XX @@ struct arcpgu_drm_private { struct drm_device drm; void __iomem *regs; struct clk *clk; - struct drm_simple_display_pipe pipe; + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; struct drm_connector sim_conn; }; #define dev_to_arcpgu(x) container_of(x, struct arcpgu_drm_private, drm) -#define pipe_to_arcpgu_priv(x) container_of(x, struct arcpgu_drm_private, pipe) - static inline void arc_pgu_write(struct arcpgu_drm_private *arcpgu, unsigned int reg, u32 value) { @@ -XXX,XX +XXX,XX @@ static const u32 arc_pgu_supported_formats[] = { static void arc_pgu_set_pxl_fmt(struct arcpgu_drm_private *arcpgu) { - const struct drm_framebuffer *fb = arcpgu->pipe.plane.state->fb; + const struct drm_framebuffer *fb = arcpgu->plane.state->fb; uint32_t pixel_format = fb->format->format; u32 format = DRM_FORMAT_INVALID; int i; @@ -XXX,XX +XXX,XX @@ static void arc_pgu_set_pxl_fmt(struct arcpgu_drm_private *arcpgu) arc_pgu_write(arcpgu, ARCPGU_REG_CTRL, reg_ctrl); } -static enum drm_mode_status arc_pgu_mode_valid(struct drm_simple_display_pipe *pipe, - const struct drm_display_mode *mode) +static enum drm_mode_status arcpgu_crtc_helper_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) { - struct arcpgu_drm_private *arcpgu = pipe_to_arcpgu_priv(pipe); + struct arcpgu_drm_private *arcpgu = dev_to_arcpgu(crtc->dev); long rate, clk_rate = mode->clock * 1000; long diff = clk_rate / 200; /* +-0.5% allowed by HDMI spec */ @@ -XXX,XX +XXX,XX @@ static enum drm_mode_status arc_pgu_mode_valid(struct drm_simple_display_pipe *p static void arc_pgu_mode_set(struct arcpgu_drm_private *arcpgu) { - struct drm_display_mode *m = &arcpgu->pipe.crtc.state->adjusted_mode; + struct drm_display_mode *m = &arcpgu->crtc.state->adjusted_mode; u32 val; arc_pgu_write(arcpgu, ARCPGU_REG_FMT, @@ -XXX,XX +XXX,XX @@ static void arc_pgu_mode_set(struct arcpgu_drm_private *arcpgu) clk_set_rate(arcpgu->clk, m->crtc_clock * 1000); } -static void arc_pgu_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +static void arcpgu_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_commit *state) { - struct arcpgu_drm_private *arcpgu = pipe_to_arcpgu_priv(pipe); + struct arcpgu_drm_private *arcpgu = dev_to_arcpgu(crtc->dev); arc_pgu_mode_set(arcpgu); @@ -XXX,XX +XXX,XX @@ static void arc_pgu_enable(struct drm_simple_display_pipe *pipe, ARCPGU_CTRL_ENABLE_MASK); } -static void arc_pgu_disable(struct drm_simple_display_pipe *pipe) +static void arcpgu_crtc_helper_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_commit *state) { - struct arcpgu_drm_private *arcpgu = pipe_to_arcpgu_priv(pipe); + struct arcpgu_drm_private *arcpgu = dev_to_arcpgu(crtc->dev); clk_disable_unprepare(arcpgu->clk); arc_pgu_write(arcpgu, ARCPGU_REG_CTRL, @@ -XXX,XX +XXX,XX @@ static void arc_pgu_disable(struct drm_simple_display_pipe *pipe) ~ARCPGU_CTRL_ENABLE_MASK); } -static void arc_pgu_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *state) +static void arcpgu_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_commit *state) { struct arcpgu_drm_private *arcpgu; struct drm_gem_dma_object *gem; - if (!pipe->plane.state->fb) + if (!plane->state->fb) return; - arcpgu = pipe_to_arcpgu_priv(pipe); - gem = drm_fb_dma_get_gem_obj(pipe->plane.state->fb, 0); + arcpgu = dev_to_arcpgu(plane->dev); + gem = drm_fb_dma_get_gem_obj(plane->state->fb, 0); arc_pgu_write(arcpgu, ARCPGU_REG_BUF0_ADDR, gem->dma_addr); } -static const struct drm_simple_display_pipe_funcs arc_pgu_pipe_funcs = { - .update = arc_pgu_update, - .mode_valid = arc_pgu_mode_valid, - .enable = arc_pgu_enable, - .disable = arc_pgu_disable, -}; - static const struct drm_mode_config_funcs arcpgu_drm_modecfg_funcs = { - .fb_create = drm_gem_fb_create, + .fb_create = drm_gem_fb_create, .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, }; DEFINE_DRM_GEM_DMA_FOPS(arcpgu_drm_ops); +static int arcpgu_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_commit *state) +{ + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_crtc *crtc = plane_state->crtc; + struct drm_crtc_state *crtc_state = NULL; + int ret; + + if (crtc) + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + + ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); + return ret; +} + +static const struct drm_plane_helper_funcs arcpgu_plane_helper_funcs = { + .prepare_fb = drm_gem_plane_helper_prepare_fb, + .atomic_check = arcpgu_plane_helper_atomic_check, + .atomic_update = arcpgu_plane_helper_atomic_update, +}; + +static bool arcpgu_plane_format_mod_supported(struct drm_plane *plane, + u32 format, + u64 modifier) +{ + return modifier == DRM_FORMAT_MOD_LINEAR; +} + +static const struct drm_plane_funcs arcpgu_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, + .format_mod_supported = arcpgu_plane_format_mod_supported, +}; + +static int arcpgu_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 arcpgu_crtc_helper_funcs = { + .mode_valid = arcpgu_crtc_helper_mode_valid, + .atomic_check = arcpgu_crtc_helper_atomic_check, + .atomic_enable = arcpgu_crtc_helper_atomic_enable, + .atomic_disable = arcpgu_crtc_helper_atomic_disable, +}; + +static const struct drm_crtc_funcs arcpgu_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, +}; + +static const struct drm_encoder_funcs arcpgu_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + static int arcpgu_load(struct arcpgu_drm_private *arcpgu) { struct platform_device *pdev = to_platform_device(arcpgu->drm.dev); @@ -XXX,XX +XXX,XX @@ static int arcpgu_load(struct arcpgu_drm_private *arcpgu) struct device_node *endpoint_node = NULL; struct drm_connector *connector = NULL; struct drm_device *drm = &arcpgu->drm; + struct drm_plane *plane; + struct drm_encoder *encoder; + struct drm_crtc *crtc; int ret; arcpgu->clk = devm_clk_get(drm->dev, "pxlclk"); @@ -XXX,XX +XXX,XX @@ static int arcpgu_load(struct arcpgu_drm_private *arcpgu) return ret; } - ret = drm_simple_display_pipe_init(drm, &arcpgu->pipe, &arc_pgu_pipe_funcs, - arc_pgu_supported_formats, - ARRAY_SIZE(arc_pgu_supported_formats), - NULL, connector); + plane = &arcpgu->plane; + ret = drm_universal_plane_init(drm, plane, 0, + &arcpgu_plane_funcs, + arc_pgu_supported_formats, + ARRAY_SIZE(arc_pgu_supported_formats), + NULL, + DRM_PLANE_TYPE_PRIMARY, NULL); if (ret) return ret; + drm_plane_helper_add(plane, &arcpgu_plane_helper_funcs); + + crtc = &arcpgu->crtc; + ret = drm_crtc_init_with_planes(drm, crtc, plane, NULL, + &arcpgu_crtc_funcs, NULL); + if (ret) + return ret; + drm_crtc_helper_add(crtc, &arcpgu_crtc_helper_funcs); + + encoder = &arcpgu->encoder; + ret = drm_encoder_init(drm, encoder, &arcpgu_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); + + if (connector) { + ret = drm_connector_attach_encoder(connector, encoder); + if (ret) + return ret; + } if (encoder_node) { /* Locate drm bridge from the hdmi encoder DT node */ @@ -XXX,XX +XXX,XX @@ static int arcpgu_load(struct arcpgu_drm_private *arcpgu) if (!bridge) return -EPROBE_DEFER; - ret = drm_simple_display_pipe_attach_bridge(&arcpgu->pipe, bridge); + ret = drm_bridge_attach(encoder, bridge, NULL, 0); if (ret) return ret; } @@ -XXX,XX +XXX,XX @@ static int arcpgu_show_pxlclock(struct seq_file *m, void *arg) struct drm_device *drm = node->minor->dev; struct arcpgu_drm_private *arcpgu = dev_to_arcpgu(drm); unsigned long clkrate = clk_get_rate(arcpgu->clk); - unsigned long mode_clock = arcpgu->pipe.crtc.mode.crtc_clock * 1000; + unsigned long mode_clock = arcpgu->crtc.mode.crtc_clock * 1000; seq_printf(m, "hw : %lu\n", clkrate); seq_printf(m, "mode: %lu\n", mode_clock); -- 2.55.0
Replace simple display pipe with explicit plane, CRTC and encoder objects. Move callbacks to plane and CRTC helpers, with vblank handling through drm_crtc_funcs. This removes intermediate simple-pipe layer and uses standard atomic helper wiring. Signed-off-by: Ze Huang <ze.huang@oss.qualcomm.com> --- drivers/gpu/drm/aspeed/aspeed_gfx.h | 5 +- drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c | 156 +++++++++++++++++++++++-------- drivers/gpu/drm/aspeed/aspeed_gfx_drv.c | 3 +- 3 files changed, 123 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx.h b/drivers/gpu/drm/aspeed/aspeed_gfx.h index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/aspeed/aspeed_gfx.h +++ b/drivers/gpu/drm/aspeed/aspeed_gfx.h @@ -XXX,XX +XXX,XX @@ /* Copyright 2018 IBM Corporation */ #include <drm/drm_device.h> -#include <drm/drm_simple_kms_helper.h> struct aspeed_gfx { struct drm_device drm; @@ -XXX,XX +XXX,XX @@ struct aspeed_gfx { u32 throd_val; u32 scan_line_max; - struct drm_simple_display_pipe pipe; + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; struct drm_connector connector; }; #define to_aspeed_gfx(x) container_of(x, struct aspeed_gfx, drm) diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c +++ b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c @@ -XXX,XX +XXX,XX @@ #include <linux/reset.h> #include <linux/regmap.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_device.h> #include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> @@ -XXX,XX +XXX,XX @@ #include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_dma_helper.h> #include <drm/drm_panel.h> -#include <drm/drm_simple_kms_helper.h> #include <drm/drm_vblank.h> #include "aspeed_gfx.h" -static struct aspeed_gfx * -drm_pipe_to_aspeed_gfx(struct drm_simple_display_pipe *pipe) -{ - return container_of(pipe, struct aspeed_gfx, pipe); -} - static int aspeed_gfx_set_pixel_fmt(struct aspeed_gfx *priv, u32 *bpp) { - struct drm_crtc *crtc = &priv->pipe.crtc; + struct drm_crtc *crtc = &priv->crtc; struct drm_device *drm = crtc->dev; const u32 format = crtc->primary->state->fb->format->format; u32 ctrl1; @@ -XXX,XX +XXX,XX @@ static void aspeed_gfx_disable_controller(struct aspeed_gfx *priv) static void aspeed_gfx_crtc_mode_set_nofb(struct aspeed_gfx *priv) { - struct drm_display_mode *m = &priv->pipe.crtc.state->adjusted_mode; + struct drm_display_mode *m = &priv->crtc.state->adjusted_mode; u32 ctrl1, d_offset, t_count, bpp; int err; @@ -XXX,XX +XXX,XX @@ static void aspeed_gfx_crtc_mode_set_nofb(struct aspeed_gfx *priv) writel(priv->throd_val, priv->base + CRT_THROD); } -static void aspeed_gfx_pipe_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +static void aspeed_gfx_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_commit *state) { - struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); - struct drm_crtc *crtc = &pipe->crtc; + struct aspeed_gfx *priv = container_of(crtc, struct aspeed_gfx, crtc); aspeed_gfx_crtc_mode_set_nofb(priv); aspeed_gfx_enable_controller(priv); drm_crtc_vblank_on(crtc); } -static void aspeed_gfx_pipe_disable(struct drm_simple_display_pipe *pipe) +static void aspeed_gfx_crtc_helper_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_commit *state) { - struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); - struct drm_crtc *crtc = &pipe->crtc; + struct aspeed_gfx *priv = container_of(crtc, struct aspeed_gfx, crtc); drm_crtc_vblank_off(crtc); aspeed_gfx_disable_controller(priv); } -static void aspeed_gfx_pipe_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *plane_state) +static void aspeed_gfx_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_commit *state) { - struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); - struct drm_crtc *crtc = &pipe->crtc; - struct drm_framebuffer *fb = pipe->plane.state->fb; + struct aspeed_gfx *priv = container_of(plane, struct aspeed_gfx, plane); + struct drm_crtc *crtc = &priv->crtc; + struct drm_framebuffer *fb = plane->state->fb; struct drm_pending_vblank_event *event; struct drm_gem_dma_object *gem; @@ -XXX,XX +XXX,XX @@ static void aspeed_gfx_pipe_update(struct drm_simple_display_pipe *pipe, writel(gem->dma_addr, priv->base + CRT_ADDR); } -static int aspeed_gfx_enable_vblank(struct drm_simple_display_pipe *pipe) +static int aspeed_gfx_crtc_enable_vblank(struct drm_crtc *crtc) { - struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); + struct aspeed_gfx *priv = container_of(crtc, struct aspeed_gfx, crtc); u32 reg = readl(priv->base + CRT_CTRL1); /* Clear pending VBLANK IRQ */ @@ -XXX,XX +XXX,XX @@ static int aspeed_gfx_enable_vblank(struct drm_simple_display_pipe *pipe) return 0; } -static void aspeed_gfx_disable_vblank(struct drm_simple_display_pipe *pipe) +static void aspeed_gfx_crtc_disable_vblank(struct drm_crtc *crtc) { - struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); + struct aspeed_gfx *priv = container_of(crtc, struct aspeed_gfx, crtc); u32 reg = readl(priv->base + CRT_CTRL1); reg &= ~CRT_CTRL_VERTICAL_INTR_EN; @@ -XXX,XX +XXX,XX @@ static void aspeed_gfx_disable_vblank(struct drm_simple_display_pipe *pipe) writel(reg | CRT_CTRL_VERTICAL_INTR_STS, priv->base + CRT_CTRL1); } -static const struct drm_simple_display_pipe_funcs aspeed_gfx_funcs = { - .enable = aspeed_gfx_pipe_enable, - .disable = aspeed_gfx_pipe_disable, - .update = aspeed_gfx_pipe_update, - .enable_vblank = aspeed_gfx_enable_vblank, - .disable_vblank = aspeed_gfx_disable_vblank, +static int aspeed_gfx_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_commit *state) +{ + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_crtc *crtc = plane_state->crtc; + struct drm_crtc_state *crtc_state = NULL; + int ret; + + if (crtc) + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + + ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); + return ret; +} + +static const struct drm_plane_helper_funcs aspeed_gfx_plane_helper_funcs = { + .prepare_fb = drm_gem_plane_helper_prepare_fb, + .atomic_check = aspeed_gfx_plane_helper_atomic_check, + .atomic_update = aspeed_gfx_plane_helper_atomic_update, +}; + +static const struct drm_plane_funcs aspeed_gfx_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 int aspeed_gfx_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 aspeed_gfx_crtc_helper_funcs = { + .atomic_check = aspeed_gfx_crtc_helper_atomic_check, + .atomic_enable = aspeed_gfx_crtc_helper_atomic_enable, + .atomic_disable = aspeed_gfx_crtc_helper_atomic_disable, +}; + +static const struct drm_crtc_funcs aspeed_gfx_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 = aspeed_gfx_crtc_enable_vblank, + .disable_vblank = aspeed_gfx_crtc_disable_vblank, +}; + +static const struct drm_encoder_funcs aspeed_gfx_encoder_funcs = { + .destroy = drm_encoder_cleanup, }; static const uint32_t aspeed_gfx_formats[] = { @@ -XXX,XX +XXX,XX @@ static const uint32_t aspeed_gfx_formats[] = { int aspeed_gfx_create_pipe(struct drm_device *drm) { struct aspeed_gfx *priv = to_aspeed_gfx(drm); + struct drm_plane *plane = &priv->plane; + struct drm_crtc *crtc = &priv->crtc; + struct drm_encoder *encoder = &priv->encoder; + int ret; + + ret = drm_universal_plane_init(drm, plane, 0, + &aspeed_gfx_plane_funcs, + aspeed_gfx_formats, + ARRAY_SIZE(aspeed_gfx_formats), + NULL, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + drm_plane_helper_add(plane, &aspeed_gfx_plane_helper_funcs); + + ret = drm_crtc_init_with_planes(drm, crtc, plane, NULL, + &aspeed_gfx_crtc_funcs, NULL); + if (ret) + return ret; + drm_crtc_helper_add(crtc, &aspeed_gfx_crtc_helper_funcs); + + ret = drm_encoder_init(drm, encoder, &aspeed_gfx_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); + + ret = drm_connector_attach_encoder(&priv->connector, encoder); + if (ret) + return ret; - return drm_simple_display_pipe_init(drm, &priv->pipe, &aspeed_gfx_funcs, - aspeed_gfx_formats, - ARRAY_SIZE(aspeed_gfx_formats), - NULL, - &priv->connector); + return 0; } diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c +++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c @@ -XXX,XX +XXX,XX @@ #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_module.h> #include <drm/drm_probe_helper.h> -#include <drm/drm_simple_kms_helper.h> #include <drm/drm_vblank.h> #include <drm/drm_drv.h> @@ -XXX,XX +XXX,XX @@ static irqreturn_t aspeed_gfx_irq_handler(int irq, void *data) reg = readl(priv->base + CRT_CTRL1); if (reg & CRT_CTRL_VERTICAL_INTR_STS) { - drm_crtc_handle_vblank(&priv->pipe.crtc); + drm_crtc_handle_vblank(&priv->crtc); writel(reg, priv->base + priv->int_clr_reg); return IRQ_HANDLED; } -- 2.55.0
Convert i.MX LCDC to explicit primary plane, CRTC and encoder objects. Keep no-scaling plane check and GEM framebuffer prepare callback from simple-KMS path. Only touch hardware state when framebuffer exists, since atomic plane updates can run on disabling transitions. Signed-off-by: Ze Huang <ze.huang@oss.qualcomm.com> --- drivers/gpu/drm/imx/lcdc/imx-lcdc.c | 178 ++++++++++++++++++++++++++---------- 1 file changed, 130 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c +++ b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c @@ -XXX,XX +XXX,XX @@ #include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_of.h> +#include <drm/drm_plane_helper.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> -#include <drm/drm_simple_kms_helper.h> #include <drm/drm_vblank.h> #include <linux/bitfield.h> #include <linux/clk.h> @@ -XXX,XX +XXX,XX @@ struct imx_lcdc { struct drm_device drm; - struct drm_simple_display_pipe pipe; + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; struct drm_connector *connector; void __iomem *base; @@ -XXX,XX +XXX,XX @@ static unsigned int imx_lcdc_get_format(unsigned int drm_format) } } -static void imx_lcdc_update_hw_registers(struct drm_simple_display_pipe *pipe, +static void imx_lcdc_update_hw_registers(struct drm_crtc *crtc, struct drm_plane_state *old_state, bool mode_set) { - struct drm_crtc *crtc = &pipe->crtc; - struct drm_plane_state *new_state = pipe->plane.state; + struct drm_plane_state *new_state = crtc->primary->state; struct drm_framebuffer *fb = new_state->fb; - struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(pipe->crtc.dev); + struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(crtc->dev); u32 lpcr, lvcr, lhcr; u32 framesize; dma_addr_t addr; @@ -XXX,XX +XXX,XX @@ static void imx_lcdc_update_hw_registers(struct drm_simple_display_pipe *pipe, clk_prepare_enable(lcdc->clk_per); } -static void imx_lcdc_pipe_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +static void imx_lcdc_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_commit *state) { int ret; int clk_div; int bpp; - struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(pipe->crtc.dev); - struct drm_display_mode *mode = &pipe->crtc.mode; + struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(crtc->dev); + struct drm_display_mode *mode = &crtc->mode; struct drm_display_info *disp_info = &lcdc->connector->display_info; + struct drm_plane_state *plane_state = crtc->primary->state; const int hsync_pol = (mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : 1; const int vsync_pol = (mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : 1; const int data_enable_pol = @@ -XXX,XX +XXX,XX @@ static void imx_lcdc_pipe_enable(struct drm_simple_display_pipe *pipe, ret = clk_prepare_enable(lcdc->clk_ipg); if (ret) { - dev_err(pipe->crtc.dev->dev, "Cannot enable ipg clock: %pe\n", ERR_PTR(ret)); + dev_err(crtc->dev->dev, "Cannot enable ipg clock: %pe\n", ERR_PTR(ret)); return; } ret = clk_prepare_enable(lcdc->clk_ahb); if (ret) { - dev_err(pipe->crtc.dev->dev, "Cannot enable ahb clock: %pe\n", ERR_PTR(ret)); + dev_err(crtc->dev->dev, "Cannot enable ahb clock: %pe\n", ERR_PTR(ret)); clk_disable_unprepare(lcdc->clk_ipg); return; } - imx_lcdc_update_hw_registers(pipe, NULL, true); + imx_lcdc_update_hw_registers(crtc, NULL, true); /* Enable VBLANK Interrupt */ writel(INTR_EOF, lcdc->base + IMX21LCDC_LIER); } -static void imx_lcdc_pipe_disable(struct drm_simple_display_pipe *pipe) +static void imx_lcdc_crtc_helper_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_commit *state) { - struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(pipe->crtc.dev); - struct drm_crtc *crtc = &lcdc->pipe.crtc; + struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(crtc->dev); struct drm_pending_vblank_event *event; clk_disable_unprepare(lcdc->clk_ahb); clk_disable_unprepare(lcdc->clk_ipg); - if (pipe->crtc.enabled) + if (crtc->enabled) clk_disable_unprepare(lcdc->clk_per); spin_lock_irq(&lcdc->drm.event_lock); @@ -XXX,XX +XXX,XX @@ static void imx_lcdc_pipe_disable(struct drm_simple_display_pipe *pipe) writel(0, lcdc->base + IMX21LCDC_LIER); } -static int imx_lcdc_pipe_check(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *plane_state, - struct drm_crtc_state *crtc_state) +static int imx_lcdc_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); const struct drm_display_mode *mode = &crtc_state->mode; - const struct drm_display_mode *old_mode = &pipe->crtc.state->mode; + const struct drm_display_mode *old_mode = &crtc->state->mode; + int ret; if (mode->hdisplay < LCDC_MIN_XRES || mode->hdisplay > LCDC_MAX_XRES || mode->vdisplay < LCDC_MIN_YRES || mode->vdisplay > LCDC_MAX_YRES || mode->hdisplay % 0x10) { /* must be multiple of 16 */ - drm_err(pipe->crtc.dev, "unsupported display mode (%u x %u)\n", + drm_err(crtc->dev, "unsupported display mode (%u x %u)\n", mode->hdisplay, mode->vdisplay); return -EINVAL; } @@ -XXX,XX +XXX,XX @@ static int imx_lcdc_pipe_check(struct drm_simple_display_pipe *pipe, old_mode->hdisplay != mode->hdisplay || old_mode->vdisplay != mode->vdisplay; - return 0; + 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 void imx_lcdc_pipe_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_state) +static void imx_lcdc_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_commit *state) { - struct drm_crtc *crtc = &pipe->crtc; - struct drm_pending_vblank_event *event = crtc->state->event; - struct drm_plane_state *new_state = pipe->plane.state; + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); + struct drm_plane_state *new_state = plane->state; + struct drm_crtc *crtc = new_state->crtc ?: old_state->crtc; + struct drm_pending_vblank_event *event; struct drm_framebuffer *fb = new_state->fb; struct drm_framebuffer *old_fb = old_state->fb; struct drm_crtc *old_crtc = old_state->crtc; bool mode_changed = false; - if (old_fb && old_fb->format != fb->format) - mode_changed = true; - else if (old_crtc != crtc) - mode_changed = true; + if (!crtc) + return; - imx_lcdc_update_hw_registers(pipe, old_state, mode_changed); + if (fb) { + if (old_fb && old_fb->format != fb->format) + mode_changed = true; + else if (old_crtc != crtc) + mode_changed = true; + imx_lcdc_update_hw_registers(crtc, old_state, mode_changed); + } + + event = crtc->state->event; if (event) { crtc->state->event = NULL; @@ -XXX,XX +XXX,XX @@ static void imx_lcdc_pipe_update(struct drm_simple_display_pipe *pipe, } } -static const struct drm_simple_display_pipe_funcs imx_lcdc_pipe_funcs = { - .enable = imx_lcdc_pipe_enable, - .disable = imx_lcdc_pipe_disable, - .check = imx_lcdc_pipe_check, - .update = imx_lcdc_pipe_update, +static int imx_lcdc_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_commit *state) +{ + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_crtc *crtc = plane_state->crtc; + struct drm_crtc_state *crtc_state = NULL; + int ret; + + if (crtc) + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + + ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); + return ret; +} + +static const struct drm_plane_helper_funcs imx_lcdc_plane_helper_funcs = { + .prepare_fb = drm_gem_plane_helper_prepare_fb, + .atomic_check = imx_lcdc_plane_helper_atomic_check, + .atomic_update = imx_lcdc_plane_helper_atomic_update, +}; + +static const struct drm_plane_funcs imx_lcdc_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 const struct drm_crtc_helper_funcs imx_lcdc_crtc_helper_funcs = { + .atomic_check = imx_lcdc_crtc_helper_atomic_check, + .atomic_enable = imx_lcdc_crtc_helper_atomic_enable, + .atomic_disable = imx_lcdc_crtc_helper_atomic_disable, +}; + +static const struct drm_crtc_funcs imx_lcdc_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, +}; + +static const struct drm_encoder_funcs imx_lcdc_encoder_funcs = { + .destroy = drm_encoder_cleanup, }; static const struct drm_mode_config_funcs imx_lcdc_mode_config_funcs = { @@ -XXX,XX +XXX,XX @@ MODULE_DEVICE_TABLE(of, imx_lcdc_of_dev_id); static irqreturn_t imx_lcdc_irq_handler(int irq, void *arg) { struct imx_lcdc *lcdc = arg; - struct drm_crtc *crtc = &lcdc->pipe.crtc; + struct drm_crtc *crtc = &lcdc->crtc; unsigned int status; status = readl(lcdc->base + IMX21LCDC_LISR); @@ -XXX,XX +XXX,XX @@ static int imx_lcdc_probe(struct platform_device *pdev) struct imx_lcdc *lcdc; struct drm_device *drm; struct drm_bridge *bridge; + struct drm_plane *plane; + struct drm_crtc *crtc; + struct drm_encoder *encoder; int irq; int ret; struct device *dev = &pdev->dev; @@ -XXX,XX +XXX,XX @@ static int imx_lcdc_probe(struct platform_device *pdev) if (ret) return dev_err_probe(dev, ret, "Cannot initialize mode configuration structure\n"); - /* CRTC, Plane, Encoder */ - ret = drm_simple_display_pipe_init(drm, &lcdc->pipe, - &imx_lcdc_pipe_funcs, - imx_lcdc_formats, - ARRAY_SIZE(imx_lcdc_formats), NULL, NULL); + plane = &lcdc->plane; + ret = drm_universal_plane_init(drm, plane, 0, + &imx_lcdc_plane_funcs, + imx_lcdc_formats, + ARRAY_SIZE(imx_lcdc_formats), + NULL, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret < 0) + return dev_err_probe(drm->dev, ret, "Cannot initialize primary plane\n"); + drm_plane_helper_add(plane, &imx_lcdc_plane_helper_funcs); + + crtc = &lcdc->crtc; + ret = drm_crtc_init_with_planes(drm, crtc, plane, NULL, + &imx_lcdc_crtc_funcs, NULL); + if (ret < 0) + return dev_err_probe(drm->dev, ret, "Cannot initialize CRTC\n"); + drm_crtc_helper_add(crtc, &imx_lcdc_crtc_helper_funcs); + + encoder = &lcdc->encoder; + ret = drm_encoder_init(drm, encoder, &imx_lcdc_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); if (ret < 0) - return dev_err_probe(drm->dev, ret, "Cannot setup simple display pipe\n"); + return dev_err_probe(drm->dev, ret, "Cannot initialize encoder\n"); + encoder->possible_crtcs = drm_crtc_mask(crtc); ret = drm_vblank_init(drm, drm->mode_config.num_crtc); if (ret < 0) return dev_err_probe(drm->dev, ret, "Failed to initialize vblank\n"); - ret = drm_bridge_attach(&lcdc->pipe.encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); + ret = drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); if (ret) return dev_err_probe(drm->dev, ret, "Cannot attach bridge\n"); - lcdc->connector = drm_bridge_connector_init(drm, &lcdc->pipe.encoder); + lcdc->connector = drm_bridge_connector_init(drm, encoder); if (IS_ERR(lcdc->connector)) return dev_err_probe(drm->dev, PTR_ERR(lcdc->connector), "Cannot init bridge connector\n"); -- 2.55.0
Convert MCDE to explicit plane, CRTC and encoder objects. Keep FIFO, event and framebuffer update sequencing intact, and install GEM framebuffer prepare callback explicitly. Signed-off-by: Ze Huang <ze.huang@oss.qualcomm.com> --- drivers/gpu/drm/mcde/mcde_display.c | 162 +++++++++++++++++++++++++++--------- drivers/gpu/drm/mcde/mcde_drm.h | 6 +- drivers/gpu/drm/mcde/mcde_drv.c | 3 +- 3 files changed, 129 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/mcde/mcde_display.c b/drivers/gpu/drm/mcde/mcde_display.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/mcde/mcde_display.c +++ b/drivers/gpu/drm/mcde/mcde_display.c @@ -XXX,XX +XXX,XX @@ #include <linux/regulator/consumer.h> #include <linux/media-bus-format.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_device.h> #include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> @@ -XXX,XX +XXX,XX @@ #include <drm/drm_gem_dma_helper.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_print.h> -#include <drm/drm_simple_kms_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_vblank.h> #include <video/mipi_display.h> @@ -XXX,XX +XXX,XX @@ void mcde_display_irq(struct mcde *mcde) writel(mispp, mcde->regs + MCDE_RISPP); if (vblank) - drm_crtc_handle_vblank(&mcde->pipe.crtc); + drm_crtc_handle_vblank(&mcde->crtc); if (misovl) dev_info(mcde->dev, "some stray overlay IRQ %08x\n", misovl); @@ -XXX,XX +XXX,XX @@ void mcde_display_disable_irqs(struct mcde *mcde) writel(0xFFFFFFFF, mcde->regs + MCDE_RISCHNL); } -static int mcde_display_check(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *pstate, - struct drm_crtc_state *cstate) +static int mcde_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; + const struct drm_display_mode *mode; + struct drm_framebuffer *old_fb = plane->state->fb; struct drm_framebuffer *fb = pstate->fb; + int ret; + + if (!crtc) + return 0; + + cstate = drm_atomic_get_new_crtc_state(state, crtc); + if (!cstate) + return 0; + + 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; + + mode = &cstate->mode; if (fb) { u32 offset = drm_fb_dma_get_gem_addr(fb, pstate, 0); @@ -XXX,XX +XXX,XX @@ static void mcde_setup_dsi(struct mcde *mcde, const struct drm_display_mode *mod *dsi_formatter_frame = formatter_frame; } -static void mcde_display_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *cstate, - struct drm_plane_state *plane_state) +static void mcde_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 mcde *mcde = to_mcde(drm); + struct drm_crtc_state *cstate = crtc->state; const struct drm_display_mode *mode = &cstate->mode; - struct drm_framebuffer *fb = plane->state->fb; + struct drm_framebuffer *fb = mcde->plane.state->fb; u32 format = fb->format->format; int dsi_pkt_size; int fifo_wtrmrk; @@ -XXX,XX +XXX,XX @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe, dev_info(drm->dev, "MCDE display is enabled\n"); } -static void mcde_display_disable(struct drm_simple_display_pipe *pipe) +static void mcde_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 mcde *mcde = to_mcde(drm); struct drm_pending_vblank_event *event; @@ -XXX,XX +XXX,XX @@ static void mcde_set_extsrc(struct mcde *mcde, u32 buffer_address) writel(buffer_address + mcde->stride, mcde->regs + MCDE_EXTSRCXA1); } -static void mcde_display_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_pstate) +static void mcde_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_commit *state) { - struct drm_crtc *crtc = &pipe->crtc; - struct drm_device *drm = crtc->dev; - struct mcde *mcde = to_mcde(drm); - struct drm_pending_vblank_event *event = crtc->state->event; - struct drm_plane *plane = &pipe->plane; + struct drm_crtc *crtc = plane->state->crtc; + struct drm_device *drm; + struct mcde *mcde; + 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; + mcde = to_mcde(drm); + event = crtc->state->event; + /* * Handle any pending event first, we need to arm the vblank * interrupt before sending any update to the display so we don't @@ -XXX,XX +XXX,XX @@ static void mcde_display_update(struct drm_simple_display_pipe *pipe, } } -static int mcde_display_enable_vblank(struct drm_simple_display_pipe *pipe) +static int mcde_crtc_enable_vblank(struct drm_crtc *crtc) { - struct drm_crtc *crtc = &pipe->crtc; struct drm_device *drm = crtc->dev; struct mcde *mcde = to_mcde(drm); u32 val; @@ -XXX,XX +XXX,XX @@ static int mcde_display_enable_vblank(struct drm_simple_display_pipe *pipe) return 0; } -static void mcde_display_disable_vblank(struct drm_simple_display_pipe *pipe) +static void mcde_crtc_disable_vblank(struct drm_crtc *crtc) { - struct drm_crtc *crtc = &pipe->crtc; struct drm_device *drm = crtc->dev; struct mcde *mcde = to_mcde(drm); @@ -XXX,XX +XXX,XX @@ static void mcde_display_disable_vblank(struct drm_simple_display_pipe *pipe) writel(0xFFFFFFFF, mcde->regs + MCDE_RISPP); } -static struct drm_simple_display_pipe_funcs mcde_display_funcs = { - .check = mcde_display_check, - .enable = mcde_display_enable, - .disable = mcde_display_disable, - .update = mcde_display_update, - .enable_vblank = mcde_display_enable_vblank, - .disable_vblank = mcde_display_disable_vblank, +static int mcde_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_funcs mcde_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 = mcde_crtc_enable_vblank, + .disable_vblank = mcde_crtc_disable_vblank, +}; + +static const struct drm_crtc_helper_funcs mcde_crtc_helper_funcs = { + .atomic_check = mcde_crtc_helper_atomic_check, + .atomic_enable = mcde_crtc_helper_atomic_enable, + .atomic_disable = mcde_crtc_helper_atomic_disable, +}; + +static const struct drm_plane_funcs mcde_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .reset = drm_atomic_helper_plane_reset, + .destroy = drm_plane_cleanup, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static const struct drm_plane_helper_funcs mcde_plane_helper_funcs = { + .prepare_fb = drm_gem_plane_helper_prepare_fb, + .atomic_check = mcde_plane_helper_atomic_check, + .atomic_update = mcde_plane_helper_atomic_update, +}; + +static const struct drm_encoder_funcs mcde_encoder_funcs = { + .destroy = drm_encoder_cleanup, }; int mcde_display_init(struct drm_device *drm) @@ -XXX,XX +XXX,XX @@ int mcde_display_init(struct drm_device *drm) if (ret) return ret; - ret = drm_simple_display_pipe_init(drm, &mcde->pipe, - &mcde_display_funcs, - formats, ARRAY_SIZE(formats), - NULL, - mcde->connector); + ret = drm_universal_plane_init(drm, &mcde->plane, 0, + &mcde_plane_funcs, + formats, ARRAY_SIZE(formats), + NULL, DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + + drm_plane_helper_add(&mcde->plane, &mcde_plane_helper_funcs); + + ret = drm_crtc_init_with_planes(drm, &mcde->crtc, &mcde->plane, + NULL, &mcde_crtc_funcs, NULL); + if (ret) + return ret; + + drm_crtc_helper_add(&mcde->crtc, &mcde_crtc_helper_funcs); + + ret = drm_encoder_init(drm, &mcde->encoder, &mcde_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + + mcde->encoder.possible_crtcs = drm_crtc_mask(&mcde->crtc); + + ret = drm_connector_attach_encoder(mcde->connector, &mcde->encoder); if (ret) return ret; diff --git a/drivers/gpu/drm/mcde/mcde_drm.h b/drivers/gpu/drm/mcde/mcde_drm.h index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/mcde/mcde_drm.h +++ b/drivers/gpu/drm/mcde/mcde_drm.h @@ -XXX,XX +XXX,XX @@ * Parts of this file were based on the MCDE driver by Marcus Lorentzon * (C) ST-Ericsson SA 2013 */ -#include <drm/drm_simple_kms_helper.h> +#include <drm/drm_encoder.h> #ifndef _MCDE_DRM_H_ #define _MCDE_DRM_H_ @@ -XXX,XX +XXX,XX @@ struct mcde { struct drm_panel *panel; struct drm_bridge *bridge; struct drm_connector *connector; - struct drm_simple_display_pipe pipe; + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; struct mipi_dsi_device *mdsi; bool dpi_output; s16 stride; diff --git a/drivers/gpu/drm/mcde/mcde_drv.c b/drivers/gpu/drm/mcde/mcde_drv.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/mcde/mcde_drv.c +++ b/drivers/gpu/drm/mcde/mcde_drv.c @@ -XXX,XX +XXX,XX @@ static int mcde_modeset_init(struct drm_device *drm) } /* Attach the bridge. */ - ret = drm_simple_display_pipe_attach_bridge(&mcde->pipe, - mcde->bridge); + ret = drm_bridge_attach(&mcde->encoder, mcde->bridge, NULL, 0); if (ret) { dev_err(drm->dev, "failed to attach display output bridge\n"); return ret; -- 2.55.0
Replace PL111 simple display pipe with explicit plane, CRTC and encoder objects. Keep existing hardware programming and vblank behavior, and install GEM framebuffer prepare helper explicitly. Signed-off-by: Ze Huang <ze.huang@oss.qualcomm.com> --- drivers/gpu/drm/pl111/pl111_display.c | 174 ++++++++++++++++++++++++++-------- drivers/gpu/drm/pl111/pl111_drm.h | 5 +- drivers/gpu/drm/pl111/pl111_drv.c | 3 +- 3 files changed, 136 insertions(+), 46 deletions(-) diff --git a/drivers/gpu/drm/pl111/pl111_display.c b/drivers/gpu/drm/pl111/pl111_display.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/pl111/pl111_display.c +++ b/drivers/gpu/drm/pl111/pl111_display.c @@ -XXX,XX +XXX,XX @@ #include <linux/media-bus-format.h> #include <linux/of_graph.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> @@ -XXX,XX +XXX,XX @@ irqreturn_t pl111_irq(int irq, void *data) return IRQ_NONE; if (irq_stat & CLCD_IRQ_NEXTBASE_UPDATE) { - drm_crtc_handle_vblank(&priv->pipe.crtc); + drm_crtc_handle_vblank(&priv->crtc); status = IRQ_HANDLED; } @@ -XXX,XX +XXX,XX @@ irqreturn_t pl111_irq(int irq, void *data) } static enum drm_mode_status -pl111_mode_valid(struct drm_simple_display_pipe *pipe, - const struct drm_display_mode *mode) +pl111_crtc_helper_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) { - struct drm_device *drm = pipe->crtc.dev; + struct drm_device *drm = crtc->dev; struct pl111_drm_dev_private *priv = drm->dev_private; u32 cpp = DIV_ROUND_UP(priv->variant->fb_depth, 8); u64 bw; @@ -XXX,XX +XXX,XX @@ pl111_mode_valid(struct drm_simple_display_pipe *pipe, return MODE_OK; } -static int pl111_display_check(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *pstate, - struct drm_crtc_state *cstate) +static int pl111_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; + const struct drm_display_mode *mode; + struct drm_framebuffer *old_fb = plane->state->fb; struct drm_framebuffer *fb = pstate->fb; + int ret; + + if (!crtc) + return 0; + + cstate = drm_atomic_get_new_crtc_state(state, crtc); + if (!cstate) + return 0; + + 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; + + mode = &cstate->mode; if (mode->hdisplay % 16) return -EINVAL; @@ -XXX,XX +XXX,XX @@ static int pl111_display_check(struct drm_simple_display_pipe *pipe, return 0; } -static void pl111_display_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *cstate, - struct drm_plane_state *plane_state) +static void pl111_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 pl111_drm_dev_private *priv = drm->dev_private; + struct drm_crtc_state *cstate = crtc->state; const struct drm_display_mode *mode = &cstate->mode; - struct drm_framebuffer *fb = plane->state->fb; + struct drm_framebuffer *fb = priv->plane.state->fb; struct drm_connector *connector = priv->connector; struct drm_bridge *bridge = priv->bridge; bool grayscale = false; @@ -XXX,XX +XXX,XX @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe, drm_crtc_vblank_on(crtc); } -static void pl111_display_disable(struct drm_simple_display_pipe *pipe) +static void pl111_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 pl111_drm_dev_private *priv = drm->dev_private; u32 cntl; @@ -XXX,XX +XXX,XX @@ static void pl111_display_disable(struct drm_simple_display_pipe *pipe) clk_disable_unprepare(priv->clk); } -static void pl111_display_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_pstate) +static void pl111_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_commit *state) { - struct drm_crtc *crtc = &pipe->crtc; - struct drm_device *drm = crtc->dev; - struct pl111_drm_dev_private *priv = drm->dev_private; - struct drm_pending_vblank_event *event = crtc->state->event; - struct drm_plane *plane = &pipe->plane; + struct drm_crtc *crtc = plane->state->crtc; + struct drm_device *drm; + struct pl111_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) { u32 addr = drm_fb_dma_get_gem_addr(fb, pstate, 0); @@ -XXX,XX +XXX,XX @@ static void pl111_display_update(struct drm_simple_display_pipe *pipe, } } -static int pl111_display_enable_vblank(struct drm_simple_display_pipe *pipe) +static int pl111_display_enable_vblank(struct drm_crtc *crtc) { - struct drm_crtc *crtc = &pipe->crtc; struct drm_device *drm = crtc->dev; struct pl111_drm_dev_private *priv = drm->dev_private; @@ -XXX,XX +XXX,XX @@ static int pl111_display_enable_vblank(struct drm_simple_display_pipe *pipe) return 0; } -static void pl111_display_disable_vblank(struct drm_simple_display_pipe *pipe) +static void pl111_display_disable_vblank(struct drm_crtc *crtc) { - struct drm_crtc *crtc = &pipe->crtc; struct drm_device *drm = crtc->dev; struct pl111_drm_dev_private *priv = drm->dev_private; writel(0, priv->regs + priv->ienb); } -static struct drm_simple_display_pipe_funcs pl111_display_funcs = { - .mode_valid = pl111_mode_valid, - .check = pl111_display_check, - .enable = pl111_display_enable, - .disable = pl111_display_disable, - .update = pl111_display_update, +static int pl111_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 struct drm_crtc_funcs pl111_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, +}; + +static const struct drm_crtc_helper_funcs pl111_crtc_helper_funcs = { + .mode_valid = pl111_crtc_helper_mode_valid, + .atomic_check = pl111_crtc_helper_atomic_check, + .atomic_enable = pl111_crtc_helper_atomic_enable, + .atomic_disable = pl111_crtc_helper_atomic_disable, +}; + +static const struct drm_plane_funcs pl111_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .reset = drm_atomic_helper_plane_reset, + .destroy = drm_plane_cleanup, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static const struct drm_plane_helper_funcs pl111_plane_helper_funcs = { + .prepare_fb = drm_gem_plane_helper_prepare_fb, + .atomic_check = pl111_plane_helper_atomic_check, + .atomic_update = pl111_plane_helper_atomic_update, +}; + +static const struct drm_encoder_funcs pl111_encoder_funcs = { + .destroy = drm_encoder_cleanup, }; static int pl111_clk_div_choose_div(struct clk_hw *hw, unsigned long rate, @@ -XXX,XX +XXX,XX @@ int pl111_display_init(struct drm_device *drm) return ret; if (!priv->variant->broken_vblank) { - pl111_display_funcs.enable_vblank = pl111_display_enable_vblank; - pl111_display_funcs.disable_vblank = pl111_display_disable_vblank; + pl111_crtc_funcs.enable_vblank = pl111_display_enable_vblank; + pl111_crtc_funcs.disable_vblank = pl111_display_disable_vblank; } - ret = drm_simple_display_pipe_init(drm, &priv->pipe, - &pl111_display_funcs, - priv->variant->formats, - priv->variant->nformats, - NULL, - priv->connector); + ret = drm_universal_plane_init(drm, &priv->plane, 0, + &pl111_plane_funcs, + priv->variant->formats, + priv->variant->nformats, + NULL, DRM_PLANE_TYPE_PRIMARY, NULL); if (ret) return ret; + drm_plane_helper_add(&priv->plane, &pl111_plane_helper_funcs); + + ret = drm_crtc_init_with_planes(drm, &priv->crtc, &priv->plane, + NULL, &pl111_crtc_funcs, NULL); + if (ret) + return ret; + + drm_crtc_helper_add(&priv->crtc, &pl111_crtc_helper_funcs); + + ret = drm_encoder_init(drm, &priv->encoder, &pl111_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + + priv->encoder.possible_crtcs = drm_crtc_mask(&priv->crtc); + + if (priv->connector) { + ret = drm_connector_attach_encoder(priv->connector, + &priv->encoder); + if (ret) + return ret; + } + return 0; } diff --git a/drivers/gpu/drm/pl111/pl111_drm.h b/drivers/gpu/drm/pl111/pl111_drm.h index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/pl111/pl111_drm.h +++ b/drivers/gpu/drm/pl111/pl111_drm.h @@ -XXX,XX +XXX,XX @@ #include <drm/drm_encoder.h> #include <drm/drm_gem.h> #include <drm/drm_panel.h> -#include <drm/drm_simple_kms_helper.h> /* * CLCD Controller Internal Register addresses @@ -XXX,XX +XXX,XX @@ struct pl111_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; u32 memory_bw; diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/pl111/pl111_drv.c +++ b/drivers/gpu/drm/pl111/pl111_drv.c @@ -XXX,XX +XXX,XX @@ static int pl111_modeset_init(struct drm_device *dev) goto out_bridge; } - ret = drm_simple_display_pipe_attach_bridge(&priv->pipe, - bridge); + ret = drm_bridge_attach(&priv->encoder, bridge, NULL, 0); if (ret) return ret; -- 2.55.0
Convert gm12u320 to direct primary plane, CRTC and encoder setup. Keep shadow-plane helper state, framebuffer access helpers and no-scaling plane-state check from simple-KMS path. Signed-off-by: Ze Huang <ze.huang@oss.qualcomm.com> --- drivers/gpu/drm/tiny/gm12u320.c | 128 ++++++++++++++++++++++++++++++++-------- 1 file changed, 104 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/tiny/gm12u320.c b/drivers/gpu/drm/tiny/gm12u320.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/tiny/gm12u320.c +++ b/drivers/gpu/drm/tiny/gm12u320.c @@ -XXX,XX +XXX,XX @@ #include <linux/usb.h> #include <drm/clients/drm_client_setup.h> +#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_state_helper.h> #include <drm/drm_connector.h> @@ -XXX,XX +XXX,XX @@ #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> -#include <drm/drm_simple_kms_helper.h> static bool eco_mode; module_param(eco_mode, bool, 0644); @@ -XXX,XX +XXX,XX @@ MODULE_PARM_DESC(eco_mode, "Turn on Eco mode (less bright, more silent)"); struct gm12u320_device { struct drm_device dev; - struct drm_simple_display_pipe pipe; + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; struct drm_connector conn; unsigned char *cmd_buf; unsigned char *data_buf[GM12U320_BLOCK_COUNT]; @@ -XXX,XX +XXX,XX @@ static int gm12u320_conn_init(struct gm12u320_device *gm12u320) } /* ------------------------------------------------------------------ */ -/* gm12u320 (simple) display pipe */ +/* gm12u320 display pipe */ -static void gm12u320_pipe_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +static void gm12u320_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) { struct drm_rect rect = { 0, 0, GM12U320_USER_WIDTH, GM12U320_HEIGHT }; - struct gm12u320_device *gm12u320 = to_gm12u320(pipe->crtc.dev); + struct gm12u320_device *gm12u320 = to_gm12u320(crtc->dev); + struct drm_plane_state *plane_state = crtc->primary->state; struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); gm12u320->fb_update.draw_status_timeout = FIRST_FRAME_TIMEOUT; gm12u320_fb_mark_dirty(plane_state->fb, &shadow_plane_state->data[0], &rect); } -static void gm12u320_pipe_disable(struct drm_simple_display_pipe *pipe) +static void gm12u320_crtc_helper_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) { - struct gm12u320_device *gm12u320 = to_gm12u320(pipe->crtc.dev); + struct gm12u320_device *gm12u320 = to_gm12u320(crtc->dev); gm12u320_stop_fb_update(gm12u320); } -static void gm12u320_pipe_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_state) +static void gm12u320_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_commit *commit) { - struct drm_plane_state *state = pipe->plane.state; + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(commit, plane); + struct drm_plane_state *state = plane->state; struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state); struct drm_rect rect; @@ -XXX,XX +XXX,XX @@ static void gm12u320_pipe_update(struct drm_simple_display_pipe *pipe, gm12u320_fb_mark_dirty(state->fb, &shadow_plane_state->data[0], &rect); } -static const struct drm_simple_display_pipe_funcs gm12u320_pipe_funcs = { - .enable = gm12u320_pipe_enable, - .disable = gm12u320_pipe_disable, - .update = gm12u320_pipe_update, - DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, +static const struct drm_plane_funcs gm12u320_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + DRM_GEM_SHADOW_PLANE_FUNCS, +}; + +static int gm12u320_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_commit *state) +{ + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_crtc *crtc = plane_state->crtc; + struct drm_crtc_state *crtc_state = NULL; + int ret; + + if (crtc) + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + + ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); + return ret; +} + +static const struct drm_plane_helper_funcs gm12u320_plane_helper_funcs = { + DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, + .atomic_check = gm12u320_plane_helper_atomic_check, + .atomic_update = gm12u320_plane_helper_atomic_update, +}; + +static int gm12u320_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 gm12u320_crtc_helper_funcs = { + .atomic_check = gm12u320_crtc_helper_atomic_check, + .atomic_enable = gm12u320_crtc_helper_atomic_enable, + .atomic_disable = gm12u320_crtc_helper_atomic_disable, +}; + +static const struct drm_crtc_funcs gm12u320_crtc_funcs = { + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .reset = drm_atomic_helper_crtc_reset, + .destroy = drm_crtc_cleanup, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, +}; + +static const struct drm_encoder_funcs gm12u320_encoder_funcs = { + .destroy = drm_encoder_cleanup, }; static const uint32_t gm12u320_pipe_formats[] = { @@ -XXX,XX +XXX,XX @@ static int gm12u320_usb_probe(struct usb_interface *interface, if (ret) return ret; - ret = drm_simple_display_pipe_init(&gm12u320->dev, - &gm12u320->pipe, - &gm12u320_pipe_funcs, - gm12u320_pipe_formats, - ARRAY_SIZE(gm12u320_pipe_formats), - gm12u320_pipe_modifiers, - &gm12u320->conn); + ret = drm_universal_plane_init(dev, &gm12u320->plane, 0, + &gm12u320_plane_funcs, + gm12u320_pipe_formats, + ARRAY_SIZE(gm12u320_pipe_formats), + gm12u320_pipe_modifiers, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + drm_plane_helper_add(&gm12u320->plane, &gm12u320_plane_helper_funcs); + + ret = drm_crtc_init_with_planes(dev, &gm12u320->crtc, &gm12u320->plane, NULL, + &gm12u320_crtc_funcs, NULL); + if (ret) + return ret; + drm_crtc_helper_add(&gm12u320->crtc, &gm12u320_crtc_helper_funcs); + + ret = drm_encoder_init(dev, &gm12u320->encoder, &gm12u320_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + gm12u320->encoder.possible_crtcs = drm_crtc_mask(&gm12u320->crtc); + + ret = drm_connector_attach_encoder(&gm12u320->conn, &gm12u320->encoder); if (ret) return ret; -- 2.55.0
Convert repaper to explicit primary plane, CRTC and encoder objects. Keep shadow-plane helpers, framebuffer access handling and no-scaling plane-state validation from simple-KMS path. Signed-off-by: Ze Huang <ze.huang@oss.qualcomm.com> --- drivers/gpu/drm/tiny/repaper.c | 130 +++++++++++++++++++++++++++++++++-------- 1 file changed, 105 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/tiny/repaper.c b/drivers/gpu/drm/tiny/repaper.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/tiny/repaper.c +++ b/drivers/gpu/drm/tiny/repaper.c @@ -XXX,XX +XXX,XX @@ #include <linux/thermal.h> #include <drm/clients/drm_client_setup.h> +#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_connector.h> #include <drm/drm_damage_helper.h> @@ -XXX,XX +XXX,XX @@ #include <drm/drm_rect.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> -#include <drm/drm_simple_kms_helper.h> #define REPAPER_RID_G2_COG_ID 0x12 @@ -XXX,XX +XXX,XX @@ enum repaper_epd_border_byte { struct repaper_epd { struct drm_device drm; - struct drm_simple_display_pipe pipe; + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; const struct drm_display_mode *mode; struct drm_connector connector; struct spi_device *spi; @@ -XXX,XX +XXX,XX @@ static void power_off(struct repaper_epd *epd) gpiod_set_value_cansleep(epd->discharge, 0); } -static enum drm_mode_status repaper_pipe_mode_valid(struct drm_simple_display_pipe *pipe, - const struct drm_display_mode *mode) +static enum drm_mode_status repaper_crtc_helper_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) { - struct drm_crtc *crtc = &pipe->crtc; struct repaper_epd *epd = drm_to_epd(crtc->dev); return drm_crtc_helper_mode_valid_fixed(crtc, mode, epd->mode); } -static void repaper_pipe_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +static void repaper_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) { - struct repaper_epd *epd = drm_to_epd(pipe->crtc.dev); + struct repaper_epd *epd = drm_to_epd(crtc->dev); struct spi_device *spi = epd->spi; struct device *dev = &spi->dev; bool dc_ok = false; int i, ret, idx; - if (!drm_dev_enter(pipe->crtc.dev, &idx)) + if (!drm_dev_enter(crtc->dev, &idx)) return; DRM_DEBUG_DRIVER("\n"); @@ -XXX,XX +XXX,XX @@ static void repaper_pipe_enable(struct drm_simple_display_pipe *pipe, drm_dev_exit(idx); } -static void repaper_pipe_disable(struct drm_simple_display_pipe *pipe) +static void repaper_crtc_helper_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) { - struct repaper_epd *epd = drm_to_epd(pipe->crtc.dev); + struct repaper_epd *epd = drm_to_epd(crtc->dev); struct spi_device *spi = epd->spi; unsigned int line; @@ -XXX,XX +XXX,XX @@ static void repaper_pipe_disable(struct drm_simple_display_pipe *pipe) power_off(epd); } -static void repaper_pipe_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_state) +static void repaper_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_commit *commit) { - struct drm_plane_state *state = pipe->plane.state; + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(commit, plane); + struct drm_plane_state *state = plane->state; struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state); struct drm_rect rect; - if (!pipe->crtc.state->active) + if (!state->crtc || !state->crtc->state->active) return; if (drm_atomic_helper_damage_merged(old_state, state, &rect)) @@ -XXX,XX +XXX,XX @@ static void repaper_pipe_update(struct drm_simple_display_pipe *pipe, &shadow_plane_state->fmtcnv_state); } -static const struct drm_simple_display_pipe_funcs repaper_pipe_funcs = { - .mode_valid = repaper_pipe_mode_valid, - .enable = repaper_pipe_enable, - .disable = repaper_pipe_disable, - .update = repaper_pipe_update, - DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, +static const struct drm_plane_funcs repaper_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + DRM_GEM_SHADOW_PLANE_FUNCS, +}; + +static int repaper_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_commit *state) +{ + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_crtc *crtc = plane_state->crtc; + struct drm_crtc_state *crtc_state = NULL; + int ret; + + if (crtc) + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + + ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); + return ret; +} + +static const struct drm_plane_helper_funcs repaper_plane_helper_funcs = { + DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, + .atomic_check = repaper_plane_helper_atomic_check, + .atomic_update = repaper_plane_helper_atomic_update, +}; + +static int repaper_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 repaper_crtc_helper_funcs = { + .mode_valid = repaper_crtc_helper_mode_valid, + .atomic_check = repaper_crtc_helper_atomic_check, + .atomic_enable = repaper_crtc_helper_atomic_enable, + .atomic_disable = repaper_crtc_helper_atomic_disable, +}; + +static const struct drm_crtc_funcs repaper_crtc_funcs = { + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .reset = drm_atomic_helper_crtc_reset, + .destroy = drm_crtc_cleanup, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, +}; + +static const struct drm_encoder_funcs repaper_encoder_funcs = { + .destroy = drm_encoder_cleanup, }; static int repaper_connector_get_modes(struct drm_connector *connector) @@ -XXX,XX +XXX,XX @@ static int repaper_probe(struct spi_device *spi) if (ret) return ret; - ret = drm_simple_display_pipe_init(drm, &epd->pipe, &repaper_pipe_funcs, - repaper_formats, ARRAY_SIZE(repaper_formats), - NULL, &epd->connector); + ret = drm_universal_plane_init(drm, &epd->plane, 0, + &repaper_plane_funcs, + repaper_formats, ARRAY_SIZE(repaper_formats), + NULL, DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + drm_plane_helper_add(&epd->plane, &repaper_plane_helper_funcs); + + ret = drm_crtc_init_with_planes(drm, &epd->crtc, &epd->plane, NULL, + &repaper_crtc_funcs, NULL); + if (ret) + return ret; + drm_crtc_helper_add(&epd->crtc, &repaper_crtc_helper_funcs); + + ret = drm_encoder_init(drm, &epd->encoder, &repaper_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + epd->encoder.possible_crtcs = drm_crtc_mask(&epd->crtc); + + ret = drm_connector_attach_encoder(&epd->connector, &epd->encoder); if (ret) return ret; -- 2.55.0
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@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 XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/tve200/tve200_display.c +++ b/drivers/gpu/drm/tve200/tve200_display.c @@ -XXX,XX +XXX,XX @@ #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> @@ -XXX,XX +XXX,XX @@ 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 { @@ -XXX,XX +XXX,XX @@ 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. @@ -XXX,XX +XXX,XX @@ 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; @@ -XXX,XX +XXX,XX @@ 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; @@ -XXX,XX +XXX,XX @@ 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; @@ -XXX,XX +XXX,XX @@ 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) @@ -XXX,XX +XXX,XX @@ 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 XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/tve200/tve200_drm.h +++ b/drivers/gpu/drm/tve200/tve200_drm.h @@ -XXX,XX +XXX,XX @@ #include <linux/irqreturn.h> -#include <drm/drm_simple_kms_helper.h> - struct clk; struct drm_bridge; struct drm_connector; @@ -XXX,XX +XXX,XX @@ 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 XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/tve200/tve200_drv.c +++ b/drivers/gpu/drm/tve200/tve200_drv.c @@ -XXX,XX +XXX,XX @@ 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
Replace Xen frontend simple display pipe with explicit plane, CRTC and encoder objects for each pipeline. Keep generic plane-state validation before Xen-specific checks, and install GEM framebuffer prepare helper explicitly. Signed-off-by: Ze Huang <ze.huang@oss.qualcomm.com> --- drivers/gpu/drm/xen/xen_drm_front.h | 6 +- drivers/gpu/drm/xen/xen_drm_front_kms.c | 177 ++++++++++++++++++++++++-------- 2 files changed, 138 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/xen/xen_drm_front.h b/drivers/gpu/drm/xen/xen_drm_front.h index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/xen/xen_drm_front.h +++ b/drivers/gpu/drm/xen/xen_drm_front.h @@ -XXX,XX +XXX,XX @@ #include <linux/scatterlist.h> #include <drm/drm_connector.h> -#include <drm/drm_simple_kms_helper.h> +#include <drm/drm_encoder.h> #include "xen_drm_front_cfg.h" @@ -XXX,XX +XXX,XX @@ struct xen_drm_front_drm_pipeline { int index; - struct drm_simple_display_pipe pipe; + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; struct drm_connector conn; /* These are only for connector mode checking */ diff --git a/drivers/gpu/drm/xen/xen_drm_front_kms.c b/drivers/gpu/drm/xen/xen_drm_front_kms.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/xen/xen_drm_front_kms.c +++ b/drivers/gpu/drm/xen/xen_drm_front_kms.c @@ -XXX,XX +XXX,XX @@ #define FRAME_DONE_TO_MS (XEN_DRM_FRONT_WAIT_BACK_MS + 100) static struct xen_drm_front_drm_pipeline * -to_xen_drm_pipeline(struct drm_simple_display_pipe *pipe) +to_xen_drm_pipeline(struct drm_crtc *crtc) { - return container_of(pipe, struct xen_drm_front_drm_pipeline, pipe); + return container_of(crtc, struct xen_drm_front_drm_pipeline, crtc); } static void fb_destroy(struct drm_framebuffer *fb) @@ -XXX,XX +XXX,XX @@ static const struct drm_mode_config_funcs mode_config_funcs = { static void send_pending_event(struct xen_drm_front_drm_pipeline *pipeline) { - struct drm_crtc *crtc = &pipeline->pipe.crtc; + struct drm_crtc *crtc = &pipeline->crtc; struct drm_device *dev = crtc->dev; unsigned long flags; @@ -XXX,XX +XXX,XX @@ static void send_pending_event(struct xen_drm_front_drm_pipeline *pipeline) spin_unlock_irqrestore(&dev->event_lock, flags); } -static void display_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +static void xen_drm_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_commit *state) { - struct xen_drm_front_drm_pipeline *pipeline = - to_xen_drm_pipeline(pipe); - struct drm_crtc *crtc = &pipe->crtc; + struct xen_drm_front_drm_pipeline *pipeline = to_xen_drm_pipeline(crtc); + struct drm_plane_state *plane_state = pipeline->plane.state; struct drm_framebuffer *fb = plane_state->fb; int ret, idx; - if (!drm_dev_enter(pipe->crtc.dev, &idx)) + if (!drm_dev_enter(crtc->dev, &idx)) return; ret = xen_drm_front_mode_set(pipeline, crtc->x, crtc->y, @@ -XXX,XX +XXX,XX @@ static void display_enable(struct drm_simple_display_pipe *pipe, drm_dev_exit(idx); } -static void display_disable(struct drm_simple_display_pipe *pipe) +static void xen_drm_crtc_helper_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_commit *state) { - struct xen_drm_front_drm_pipeline *pipeline = - to_xen_drm_pipeline(pipe); + struct xen_drm_front_drm_pipeline *pipeline = to_xen_drm_pipeline(crtc); int ret = 0, idx; - if (drm_dev_enter(pipe->crtc.dev, &idx)) { + if (drm_dev_enter(crtc->dev, &idx)) { ret = xen_drm_front_mode_set(pipeline, 0, 0, 0, 0, 0, xen_drm_front_fb_to_cookie(NULL)); drm_dev_exit(idx); @@ -XXX,XX +XXX,XX @@ static void pflip_to_worker(struct work_struct *work) send_pending_event(pipeline); } -static bool display_send_page_flip(struct drm_simple_display_pipe *pipe, +static bool display_send_page_flip(struct xen_drm_front_drm_pipeline *pipeline, + struct drm_atomic_commit *state, struct drm_plane_state *old_plane_state) { struct drm_plane_state *plane_state = - drm_atomic_get_new_plane_state(old_plane_state->state, - &pipe->plane); + drm_atomic_get_new_plane_state(state, + &pipeline->plane); /* * If old_plane_state->fb is NULL and plane_state->fb is not, @@ -XXX,XX +XXX,XX @@ static bool display_send_page_flip(struct drm_simple_display_pipe *pipe, * sent to the backend as a part of display_set_config call. */ if (old_plane_state->fb && plane_state->fb) { - struct xen_drm_front_drm_pipeline *pipeline = - to_xen_drm_pipeline(pipe); struct xen_drm_front_drm_info *drm_info = pipeline->drm_info; int ret; @@ -XXX,XX +XXX,XX @@ static bool display_send_page_flip(struct drm_simple_display_pipe *pipe, return false; } -static int display_check(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *plane_state, - struct drm_crtc_state *crtc_state) +static int xen_drm_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_commit *state) { + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane); + struct drm_crtc *crtc = plane_state->crtc; + struct drm_crtc_state *crtc_state = NULL; + int ret; + + if (crtc) + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + + ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); + if (ret) + return ret; + + if (!plane_state->visible) + return 0; + + if (!crtc_state) + return 0; + /* * Xen doesn't initialize vblanking via drm_vblank_init(), so * DRM helpers assume that it doesn't handle vblanking and start @@ -XXX,XX +XXX,XX @@ static int display_check(struct drm_simple_display_pipe *pipe, return 0; } -static void display_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_plane_state) +static void xen_drm_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_commit *state) { - struct xen_drm_front_drm_pipeline *pipeline = - to_xen_drm_pipeline(pipe); - struct drm_crtc *crtc = &pipe->crtc; + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane); + struct drm_crtc *crtc = plane->state->crtc ?: old_plane_state->crtc; + struct xen_drm_front_drm_pipeline *pipeline; struct drm_pending_vblank_event *event; int idx; + if (!crtc) + return; + + pipeline = to_xen_drm_pipeline(crtc); event = crtc->state->event; if (event) { struct drm_device *dev = crtc->dev; @@ -XXX,XX +XXX,XX @@ static void display_update(struct drm_simple_display_pipe *pipe, spin_unlock_irqrestore(&dev->event_lock, flags); } - if (!drm_dev_enter(pipe->crtc.dev, &idx)) { + if (!drm_dev_enter(crtc->dev, &idx)) { send_pending_event(pipeline); return; } @@ -XXX,XX +XXX,XX @@ static void display_update(struct drm_simple_display_pipe *pipe, * If this is not a page flip, e.g. no flip done event from the backend * is expected, then send now. */ - if (!display_send_page_flip(pipe, old_plane_state)) + if (!display_send_page_flip(pipeline, state, old_plane_state)) send_pending_event(pipeline); drm_dev_exit(idx); } static enum drm_mode_status -display_mode_valid(struct drm_simple_display_pipe *pipe, - const struct drm_display_mode *mode) +xen_drm_crtc_helper_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) { struct xen_drm_front_drm_pipeline *pipeline = - container_of(pipe, struct xen_drm_front_drm_pipeline, - pipe); + container_of(crtc, struct xen_drm_front_drm_pipeline, + crtc); if (mode->hdisplay != pipeline->width) return MODE_ERROR; @@ -XXX,XX +XXX,XX @@ display_mode_valid(struct drm_simple_display_pipe *pipe, return MODE_OK; } -static const struct drm_simple_display_pipe_funcs display_funcs = { - .mode_valid = display_mode_valid, - .enable = display_enable, - .disable = display_disable, - .check = display_check, - .update = display_update, +static int xen_drm_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_plane_helper_funcs display_plane_helper_funcs = { + .prepare_fb = drm_gem_plane_helper_prepare_fb, + .atomic_check = xen_drm_plane_helper_atomic_check, + .atomic_update = xen_drm_plane_helper_atomic_update, +}; + +static const struct drm_plane_funcs display_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 const struct drm_crtc_helper_funcs display_crtc_helper_funcs = { + .mode_valid = xen_drm_crtc_helper_mode_valid, + .atomic_check = xen_drm_crtc_helper_atomic_check, + .atomic_enable = xen_drm_crtc_helper_atomic_enable, + .atomic_disable = xen_drm_crtc_helper_atomic_disable, +}; + +static const struct drm_crtc_funcs display_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, +}; + +static const struct drm_encoder_funcs display_encoder_funcs = { + .destroy = drm_encoder_cleanup, }; static int display_pipe_init(struct xen_drm_front_drm_info *drm_info, @@ -XXX,XX +XXX,XX @@ static int display_pipe_init(struct xen_drm_front_drm_info *drm_info, formats = xen_drm_front_conn_get_formats(&format_count); - return drm_simple_display_pipe_init(dev, &pipeline->pipe, - &display_funcs, formats, - format_count, NULL, - &pipeline->conn); + ret = drm_universal_plane_init(dev, &pipeline->plane, 1, + &display_plane_funcs, + formats, format_count, + NULL, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + + drm_plane_helper_add(&pipeline->plane, &display_plane_helper_funcs); + + ret = drm_crtc_init_with_planes(dev, &pipeline->crtc, + &pipeline->plane, NULL, + &display_crtc_funcs, NULL); + if (ret) + return ret; + + drm_crtc_helper_add(&pipeline->crtc, &display_crtc_helper_funcs); + + ret = drm_encoder_init(dev, &pipeline->encoder, + &display_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + + pipeline->encoder.possible_crtcs = drm_crtc_mask(&pipeline->crtc); + + ret = drm_connector_attach_encoder(&pipeline->conn, &pipeline->encoder); + if (ret) + return ret; + + return 0; } int xen_drm_front_kms_init(struct xen_drm_front_drm_info *drm_info) -- 2.55.0
struct drm_simple_display_pipe was meant to simplify simple DRM drivers, but instead adds an extra wrapper around normal DRM atomic helper setup. As noted in Documentation/gpu/todo.rst, remaining users should be converted to regular atomic helpers and stop depending on the simple-KMS interfaces. This series converts the following drivers: - arcpgu - aspeed - mcde - pl111 - gm12u320 - repaper - tve200 - xen frontend Each patch replaces drm_simple_display_pipe_init() with explicit primary plane, CRTC and encoder setup, and moves the old simple-pipe callbacks into regular plane and CRTC helper callbacks named according to local driver conventions. The conversions preserve helper behavior that used to be implicit in drm_simple_kms_helper.c, including plane-state validation, CRTC primary-plane checks, affected-plane propagation, framebuffer prepare handling, and existing event/vblank flow where applicable. Result is less helper indirection and more explicit driver-side atomic wiring, with no remaining simple-KMS dependency in these drivers. Except for gm12u320, no hardware testing was performed. This series is based on drm-next-2026-06-27. AI usage disclosure: - I wrote the first two commits myself. The remaining patches were completed with assistance from AI tools. - AI tools were also used to review the code and suggest code changes for the DRM atomic conversion. Thanks, Ze Huang Signed-off-by: Ze Huang <ze.huang@oss.qualcomm.com> --- Changes in v3: - Use atomic state from the commit path consistently in converted helpers: fetch new CRTC/plane state from the commit in enable/update/flush paths, and use drm_atomic_get_crtc_state() with PTR_ERR() handling in plane atomic_check hooks before drm_atomic_helper_check_plane_state(). - Move MCDE one-shot flow start from plane atomic_update() to CRTC atomic_flush(), after pending vblank event handling. - Fix repaper damage update path to skip updates unless CRTC is active. - Fix arcpgu missing remote encoder node handling and lock CRTC state access in debugfs. - Make container helpers static inline. - Link to v2: https://lore.kernel.org/r/20260716-drm-simple-kms-removal-v2-0-1133a8fc3785@oss.qualcomm.com Changes in v2: - common changes: - create upcast helpers - use 'commit' as name of struct drm_atomic_commit in atomic helpers - improve control flow in *_crtc_helper_atomic_check() and *_plane_helper_atomic_check() - Moved page-flip/vblank event handling out of plane update paths and into CRTC atomic_flush(), using atomic_flush and disable paths for mcde, pl111 and tve200 - arcpgu: - remove reduntant mod_supported helper - change obsolete mode field to crtc->state->mode - mcde: - drop attach of unused encoder - tve200: - reorder connector/bridge attach - xen: - change possible_crtcs mask to 0 - Link to v1: https://patch.msgid.link/20260705-drm-simple-kms-removal-v1-0-b4e1ca053623@oss.qualcomm.com --- Ze Huang (8): drm/arcpgu: replace struct drm_simple_display_pipe with regular atomic helpers drm/aspeed: replace struct drm_simple_display_pipe with regular atomic helpers drm/mcde: replace struct drm_simple_display_pipe with regular atomic helpers drm/pl111: replace struct drm_simple_display_pipe with regular atomic helpers drm/gm12u320: replace struct drm_simple_display_pipe with regular atomic helpers drm/repaper: replace struct drm_simple_display_pipe with regular atomic helpers drm/tve200: replace struct drm_simple_display_pipe with regular atomic helpers drm/xen: replace struct drm_simple_display_pipe with regular atomic helpers drivers/gpu/drm/aspeed/aspeed_gfx.h | 11 +- drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c | 203 ++++++++++++++++++------- drivers/gpu/drm/aspeed/aspeed_gfx_drv.c | 3 +- drivers/gpu/drm/mcde/mcde_display.c | 248 ++++++++++++++++++++----------- drivers/gpu/drm/mcde/mcde_drm.h | 12 +- drivers/gpu/drm/mcde/mcde_drv.c | 3 +- drivers/gpu/drm/pl111/pl111_display.c | 199 ++++++++++++++++++------- drivers/gpu/drm/pl111/pl111_drm.h | 5 +- drivers/gpu/drm/pl111/pl111_drv.c | 3 +- drivers/gpu/drm/tiny/arcpgu.c | 201 +++++++++++++++++++------ drivers/gpu/drm/tiny/gm12u320.c | 138 +++++++++++++---- drivers/gpu/drm/tiny/repaper.c | 138 +++++++++++++---- drivers/gpu/drm/tve200/tve200_display.c | 219 ++++++++++++++++++--------- drivers/gpu/drm/tve200/tve200_drm.h | 6 +- drivers/gpu/drm/tve200/tve200_drv.c | 12 +- drivers/gpu/drm/xen/xen_drm_front.h | 6 +- drivers/gpu/drm/xen/xen_drm_front_kms.c | 188 ++++++++++++++++------- 17 files changed, 1155 insertions(+), 440 deletions(-) --- base-commit: 3696d07837d1df13a5603d77f667685e7dfb3c53 change-id: 20260704-drm-simple-kms-removal-01a031c6a129 Best regards, -- Ze Huang <ze.huang@oss.qualcomm.com>
Instantiate the primary plane, CRTC and encoder directly and wire them up with standard atomic helpers. Move the simple-pipe callbacks into explicit plane and CRTC helper callbacks. Use commit-local CRTC and plane state in the CRTC enable path for mode and pixel-format programming. Handle missing remote encoder nodes explicitly and take the CRTC modeset lock while reading CRTC state from debugfs. Signed-off-by: Ze Huang <ze.huang@oss.qualcomm.com> --- Changes in v3: - Use commit-local CRTC and plane state in the CRTC enable path. - Handle missing remote encoder nodes explicitly. - Lock CRTC state access in debugfs. --- drivers/gpu/drm/tiny/arcpgu.c | 201 ++++++++++++++++++++++++++++++++---------- 1 file changed, 152 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/tiny/arcpgu.c b/drivers/gpu/drm/tiny/arcpgu.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/tiny/arcpgu.c +++ b/drivers/gpu/drm/tiny/arcpgu.c @@ -XXX,XX +XXX,XX @@ #include <linux/clk.h> #include <drm/clients/drm_client_setup.h> +#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_debugfs.h> #include <drm/drm_device.h> @@ -XXX,XX +XXX,XX @@ #include <drm/drm_fbdev_dma.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> +#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_dma_helper.h> #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_module.h> #include <drm/drm_of.h> +#include <drm/drm_plane.h> #include <drm/drm_probe_helper.h> -#include <drm/drm_simple_kms_helper.h> #include <linux/dma-mapping.h> #include <linux/module.h> #include <linux/of_reserved_mem.h> @@ -XXX,XX +XXX,XX @@ struct arcpgu_drm_private { struct drm_device drm; void __iomem *regs; struct clk *clk; - struct drm_simple_display_pipe pipe; + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; struct drm_connector sim_conn; }; -#define dev_to_arcpgu(x) container_of(x, struct arcpgu_drm_private, drm) - -#define pipe_to_arcpgu_priv(x) container_of(x, struct arcpgu_drm_private, pipe) +static inline struct arcpgu_drm_private *dev_to_arcpgu(struct drm_device *drm) +{ + return container_of(drm, struct arcpgu_drm_private, drm); +} static inline void arc_pgu_write(struct arcpgu_drm_private *arcpgu, unsigned int reg, u32 value) @@ -XXX,XX +XXX,XX @@ static const u32 arc_pgu_supported_formats[] = { DRM_FORMAT_ARGB8888, }; -static void arc_pgu_set_pxl_fmt(struct arcpgu_drm_private *arcpgu) +static void arc_pgu_set_pxl_fmt(struct arcpgu_drm_private *arcpgu, + const struct drm_plane_state *plane_state) { - const struct drm_framebuffer *fb = arcpgu->pipe.plane.state->fb; + const struct drm_framebuffer *fb = plane_state->fb; uint32_t pixel_format = fb->format->format; u32 format = DRM_FORMAT_INVALID; int i; @@ -XXX,XX +XXX,XX @@ static void arc_pgu_set_pxl_fmt(struct arcpgu_drm_private *arcpgu) arc_pgu_write(arcpgu, ARCPGU_REG_CTRL, reg_ctrl); } -static enum drm_mode_status arc_pgu_mode_valid(struct drm_simple_display_pipe *pipe, - const struct drm_display_mode *mode) +static enum drm_mode_status arcpgu_crtc_helper_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) { - struct arcpgu_drm_private *arcpgu = pipe_to_arcpgu_priv(pipe); + struct arcpgu_drm_private *arcpgu = dev_to_arcpgu(crtc->dev); long rate, clk_rate = mode->clock * 1000; long diff = clk_rate / 200; /* +-0.5% allowed by HDMI spec */ @@ -XXX,XX +XXX,XX @@ static enum drm_mode_status arc_pgu_mode_valid(struct drm_simple_display_pipe *p return MODE_NOCLOCK; } -static void arc_pgu_mode_set(struct arcpgu_drm_private *arcpgu) +static void arc_pgu_mode_set(struct arcpgu_drm_private *arcpgu, + struct drm_crtc_state *crtc_state, + struct drm_plane_state *plane_state) { - struct drm_display_mode *m = &arcpgu->pipe.crtc.state->adjusted_mode; + struct drm_display_mode *m = &crtc_state->adjusted_mode; u32 val; arc_pgu_write(arcpgu, ARCPGU_REG_FMT, @@ -XXX,XX +XXX,XX @@ static void arc_pgu_mode_set(struct arcpgu_drm_private *arcpgu) arc_pgu_write(arcpgu, ARCPGU_REG_STRIDE, 0); arc_pgu_write(arcpgu, ARCPGU_REG_START_SET, 1); - arc_pgu_set_pxl_fmt(arcpgu); + arc_pgu_set_pxl_fmt(arcpgu, plane_state); clk_set_rate(arcpgu->clk, m->crtc_clock * 1000); } -static void arc_pgu_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +static void arcpgu_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) { - struct arcpgu_drm_private *arcpgu = pipe_to_arcpgu_priv(pipe); + struct arcpgu_drm_private *arcpgu = dev_to_arcpgu(crtc->dev); + struct drm_plane_state *pstate = drm_atomic_get_new_plane_state(commit, &arcpgu->plane); + struct drm_crtc_state *cstate = drm_atomic_get_new_crtc_state(commit, crtc); - arc_pgu_mode_set(arcpgu); + arc_pgu_mode_set(arcpgu, cstate, pstate); clk_prepare_enable(arcpgu->clk); arc_pgu_write(arcpgu, ARCPGU_REG_CTRL, @@ -XXX,XX +XXX,XX @@ static void arc_pgu_enable(struct drm_simple_display_pipe *pipe, ARCPGU_CTRL_ENABLE_MASK); } -static void arc_pgu_disable(struct drm_simple_display_pipe *pipe) +static void arcpgu_crtc_helper_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) { - struct arcpgu_drm_private *arcpgu = pipe_to_arcpgu_priv(pipe); + struct arcpgu_drm_private *arcpgu = dev_to_arcpgu(crtc->dev); clk_disable_unprepare(arcpgu->clk); arc_pgu_write(arcpgu, ARCPGU_REG_CTRL, @@ -XXX,XX +XXX,XX @@ static void arc_pgu_disable(struct drm_simple_display_pipe *pipe) ~ARCPGU_CTRL_ENABLE_MASK); } -static void arc_pgu_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *state) +static void arcpgu_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_commit *commit) { + struct drm_plane_state *pstate = drm_atomic_get_new_plane_state(commit, plane); struct arcpgu_drm_private *arcpgu; struct drm_gem_dma_object *gem; - if (!pipe->plane.state->fb) + if (!pstate->fb) return; - arcpgu = pipe_to_arcpgu_priv(pipe); - gem = drm_fb_dma_get_gem_obj(pipe->plane.state->fb, 0); + arcpgu = dev_to_arcpgu(plane->dev); + gem = drm_fb_dma_get_gem_obj(pstate->fb, 0); arc_pgu_write(arcpgu, ARCPGU_REG_BUF0_ADDR, gem->dma_addr); } -static const struct drm_simple_display_pipe_funcs arc_pgu_pipe_funcs = { - .update = arc_pgu_update, - .mode_valid = arc_pgu_mode_valid, - .enable = arc_pgu_enable, - .disable = arc_pgu_disable, -}; - static const struct drm_mode_config_funcs arcpgu_drm_modecfg_funcs = { .fb_create = drm_gem_fb_create, .atomic_check = drm_atomic_helper_check, @@ -XXX,XX +XXX,XX @@ static const struct drm_mode_config_funcs arcpgu_drm_modecfg_funcs = { DEFINE_DRM_GEM_DMA_FOPS(arcpgu_drm_ops); +static int arcpgu_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_commit *commit) +{ + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(commit, plane); + struct drm_crtc_state *crtc_state = NULL; + + if (plane_state->crtc) { + crtc_state = drm_atomic_get_crtc_state(commit, plane_state->crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + } + + return drm_atomic_helper_check_plane_state(plane_state, crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); +} + +static const struct drm_plane_helper_funcs arcpgu_plane_helper_funcs = { + .prepare_fb = drm_gem_plane_helper_prepare_fb, + .atomic_check = arcpgu_plane_helper_atomic_check, + .atomic_update = arcpgu_plane_helper_atomic_update, +}; + +static const struct drm_plane_funcs arcpgu_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 int arcpgu_crtc_helper_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) +{ + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(commit, crtc); + int ret; + + if (crtc_state->enable) { + ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state); + if (ret) + return ret; + } + + return drm_atomic_add_affected_planes(commit, crtc); +} + +static const struct drm_crtc_helper_funcs arcpgu_crtc_helper_funcs = { + .mode_valid = arcpgu_crtc_helper_mode_valid, + .atomic_check = arcpgu_crtc_helper_atomic_check, + .atomic_enable = arcpgu_crtc_helper_atomic_enable, + .atomic_disable = arcpgu_crtc_helper_atomic_disable, +}; + +static const struct drm_crtc_funcs arcpgu_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, +}; + +static const struct drm_encoder_funcs arcpgu_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + static int arcpgu_load(struct arcpgu_drm_private *arcpgu) { struct platform_device *pdev = to_platform_device(arcpgu->drm.dev); @@ -XXX,XX +XXX,XX @@ static int arcpgu_load(struct arcpgu_drm_private *arcpgu) struct device_node *endpoint_node = NULL; struct drm_connector *connector = NULL; struct drm_device *drm = &arcpgu->drm; + struct drm_plane *plane; + struct drm_encoder *encoder; + struct drm_crtc *crtc; int ret; arcpgu->clk = devm_clk_get(drm->dev, "pxlclk"); @@ -XXX,XX +XXX,XX @@ static int arcpgu_load(struct arcpgu_drm_private *arcpgu) if (dma_set_mask_and_coherent(drm->dev, DMA_BIT_MASK(32))) return -ENODEV; + plane = &arcpgu->plane; + ret = drm_universal_plane_init(drm, plane, 0, + &arcpgu_plane_funcs, + arc_pgu_supported_formats, + ARRAY_SIZE(arc_pgu_supported_formats), + NULL, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + drm_plane_helper_add(plane, &arcpgu_plane_helper_funcs); + + crtc = &arcpgu->crtc; + ret = drm_crtc_init_with_planes(drm, crtc, plane, NULL, + &arcpgu_crtc_funcs, NULL); + if (ret) + return ret; + drm_crtc_helper_add(crtc, &arcpgu_crtc_helper_funcs); + + encoder = &arcpgu->encoder; + ret = drm_encoder_init(drm, encoder, &arcpgu_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); + /* * There is only one output port inside each device. It is linked with * encoder endpoint. @@ -XXX,XX +XXX,XX @@ static int arcpgu_load(struct arcpgu_drm_private *arcpgu) if (endpoint_node) { encoder_node = of_graph_get_remote_port_parent(endpoint_node); of_node_put(endpoint_node); - } else { - connector = &arcpgu->sim_conn; - dev_info(drm->dev, "no encoder found. Assumed virtual LCD on simulation platform\n"); - ret = arcpgu_drm_sim_init(drm, connector); - if (ret < 0) - return ret; - } + if (!encoder_node) + return -ENODEV; - ret = drm_simple_display_pipe_init(drm, &arcpgu->pipe, &arc_pgu_pipe_funcs, - arc_pgu_supported_formats, - ARRAY_SIZE(arc_pgu_supported_formats), - NULL, connector); - if (ret) - return ret; - - if (encoder_node) { /* Locate drm bridge from the hdmi encoder DT node */ struct drm_bridge *bridge __free(drm_bridge_put) = of_drm_find_and_get_bridge(encoder_node); if (!bridge) return -EPROBE_DEFER; - ret = drm_simple_display_pipe_attach_bridge(&arcpgu->pipe, bridge); + ret = drm_bridge_attach(encoder, bridge, NULL, 0); + if (ret) + return ret; + } else { + connector = &arcpgu->sim_conn; + dev_info(drm->dev, "no encoder found. Assumed virtual LCD on simulation platform\n"); + ret = arcpgu_drm_sim_init(drm, connector); + if (ret < 0) + return ret; + + ret = drm_connector_attach_encoder(connector, encoder); if (ret) return ret; } @@ -XXX,XX +XXX,XX @@ static int arcpgu_show_pxlclock(struct seq_file *m, void *arg) struct drm_device *drm = node->minor->dev; struct arcpgu_drm_private *arcpgu = dev_to_arcpgu(drm); unsigned long clkrate = clk_get_rate(arcpgu->clk); - unsigned long mode_clock = arcpgu->pipe.crtc.mode.crtc_clock * 1000; + unsigned long mode_clock; + int ret; + + ret = drm_modeset_lock_single_interruptible(&arcpgu->crtc.mutex); + if (ret) + return ret; + mode_clock = arcpgu->crtc.state->mode.crtc_clock * 1000; + drm_modeset_unlock(&arcpgu->crtc.mutex); seq_printf(m, "hw : %lu\n", clkrate); seq_printf(m, "mode: %lu\n", mode_clock); -- 2.43.0
Replace the simple display pipe with explicit plane, CRTC and encoder objects. Move callbacks to plane and CRTC helpers, and wire vblank handling through drm_crtc_funcs. Move page-flip event handling from plane atomic_update() to CRTC atomic_flush(). Use commit-local CRTC and plane state when programming mode and pixel format in the CRTC enable path. Signed-off-by: Ze Huang <ze.huang@oss.qualcomm.com> --- Changes in v3: - Use commit-local CRTC and plane state in the CRTC enable path. - Make the aspeed container helper static inline. --- drivers/gpu/drm/aspeed/aspeed_gfx.h | 11 +- drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c | 203 ++++++++++++++++++++++--------- drivers/gpu/drm/aspeed/aspeed_gfx_drv.c | 3 +- 3 files changed, 157 insertions(+), 60 deletions(-) diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx.h b/drivers/gpu/drm/aspeed/aspeed_gfx.h index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/aspeed/aspeed_gfx.h +++ b/drivers/gpu/drm/aspeed/aspeed_gfx.h @@ -XXX,XX +XXX,XX @@ /* Copyright 2018 IBM Corporation */ #include <drm/drm_device.h> -#include <drm/drm_simple_kms_helper.h> struct aspeed_gfx { struct drm_device drm; @@ -XXX,XX +XXX,XX @@ struct aspeed_gfx { u32 throd_val; u32 scan_line_max; - struct drm_simple_display_pipe pipe; + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; struct drm_connector connector; }; -#define to_aspeed_gfx(x) container_of(x, struct aspeed_gfx, drm) + +static inline struct aspeed_gfx *to_aspeed_gfx(struct drm_device *drm) +{ + return container_of(drm, struct aspeed_gfx, drm); +} int aspeed_gfx_create_pipe(struct drm_device *drm); int aspeed_gfx_create_output(struct drm_device *drm); diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c +++ b/drivers/gpu/drm/aspeed/aspeed_gfx_crtc.c @@ -XXX,XX +XXX,XX @@ #include <linux/reset.h> #include <linux/regmap.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_device.h> #include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> @@ -XXX,XX +XXX,XX @@ #include <drm/drm_gem_atomic_helper.h> #include <drm/drm_gem_dma_helper.h> #include <drm/drm_panel.h> -#include <drm/drm_simple_kms_helper.h> #include <drm/drm_vblank.h> #include "aspeed_gfx.h" -static struct aspeed_gfx * -drm_pipe_to_aspeed_gfx(struct drm_simple_display_pipe *pipe) +static int aspeed_gfx_set_pixel_fmt(struct aspeed_gfx *priv, + struct drm_plane_state *plane_state, + u32 *bpp) { - return container_of(pipe, struct aspeed_gfx, pipe); -} - -static int aspeed_gfx_set_pixel_fmt(struct aspeed_gfx *priv, u32 *bpp) -{ - struct drm_crtc *crtc = &priv->pipe.crtc; + struct drm_crtc *crtc = &priv->crtc; struct drm_device *drm = crtc->dev; - const u32 format = crtc->primary->state->fb->format->format; + const u32 format = plane_state->fb->format->format; u32 ctrl1; ctrl1 = readl(priv->base + CRT_CTRL1); @@ -XXX,XX +XXX,XX @@ static void aspeed_gfx_disable_controller(struct aspeed_gfx *priv) regmap_update_bits(priv->scu, priv->dac_reg, BIT(16), 0); } -static void aspeed_gfx_crtc_mode_set_nofb(struct aspeed_gfx *priv) +static void aspeed_gfx_crtc_mode_set_nofb(struct aspeed_gfx *priv, + struct drm_crtc_state *crtc_state, + struct drm_plane_state *plane_state) { - struct drm_display_mode *m = &priv->pipe.crtc.state->adjusted_mode; + struct drm_display_mode *m = &crtc_state->adjusted_mode; u32 ctrl1, d_offset, t_count, bpp; int err; - err = aspeed_gfx_set_pixel_fmt(priv, &bpp); + err = aspeed_gfx_set_pixel_fmt(priv, plane_state, &bpp); if (err) return; @@ -XXX,XX +XXX,XX @@ static void aspeed_gfx_crtc_mode_set_nofb(struct aspeed_gfx *priv) writel(priv->throd_val, priv->base + CRT_THROD); } -static void aspeed_gfx_pipe_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +static void aspeed_gfx_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) { - struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); - struct drm_crtc *crtc = &pipe->crtc; + struct aspeed_gfx *priv = to_aspeed_gfx(crtc->dev); + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(commit, crtc); + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(commit, &priv->plane); - aspeed_gfx_crtc_mode_set_nofb(priv); + aspeed_gfx_crtc_mode_set_nofb(priv, crtc_state, plane_state); aspeed_gfx_enable_controller(priv); drm_crtc_vblank_on(crtc); } -static void aspeed_gfx_pipe_disable(struct drm_simple_display_pipe *pipe) +static void aspeed_gfx_crtc_helper_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) { - struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); - struct drm_crtc *crtc = &pipe->crtc; + struct aspeed_gfx *priv = to_aspeed_gfx(crtc->dev); drm_crtc_vblank_off(crtc); aspeed_gfx_disable_controller(priv); } -static void aspeed_gfx_pipe_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *plane_state) +static void aspeed_gfx_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_commit *commit) { - struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); - struct drm_crtc *crtc = &pipe->crtc; - struct drm_framebuffer *fb = pipe->plane.state->fb; - struct drm_pending_vblank_event *event; + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(commit, plane); + struct aspeed_gfx *priv = to_aspeed_gfx(plane->dev); + struct drm_framebuffer *fb = new_plane_state->fb; struct drm_gem_dma_object *gem; - spin_lock_irq(&crtc->dev->event_lock); - event = crtc->state->event; - if (event) { - crtc->state->event = NULL; - - if (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); - if (!fb) return; @@ -XXX,XX +XXX,XX @@ static void aspeed_gfx_pipe_update(struct drm_simple_display_pipe *pipe, writel(gem->dma_addr, priv->base + CRT_ADDR); } -static int aspeed_gfx_enable_vblank(struct drm_simple_display_pipe *pipe) +static int aspeed_gfx_crtc_enable_vblank(struct drm_crtc *crtc) { - struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); + struct aspeed_gfx *priv = to_aspeed_gfx(crtc->dev); u32 reg = readl(priv->base + CRT_CTRL1); /* Clear pending VBLANK IRQ */ @@ -XXX,XX +XXX,XX @@ static int aspeed_gfx_enable_vblank(struct drm_simple_display_pipe *pipe) return 0; } -static void aspeed_gfx_disable_vblank(struct drm_simple_display_pipe *pipe) +static void aspeed_gfx_crtc_disable_vblank(struct drm_crtc *crtc) { - struct aspeed_gfx *priv = drm_pipe_to_aspeed_gfx(pipe); + struct aspeed_gfx *priv = to_aspeed_gfx(crtc->dev); u32 reg = readl(priv->base + CRT_CTRL1); reg &= ~CRT_CTRL_VERTICAL_INTR_EN; @@ -XXX,XX +XXX,XX @@ static void aspeed_gfx_disable_vblank(struct drm_simple_display_pipe *pipe) writel(reg | CRT_CTRL_VERTICAL_INTR_STS, priv->base + CRT_CTRL1); } -static const struct drm_simple_display_pipe_funcs aspeed_gfx_funcs = { - .enable = aspeed_gfx_pipe_enable, - .disable = aspeed_gfx_pipe_disable, - .update = aspeed_gfx_pipe_update, - .enable_vblank = aspeed_gfx_enable_vblank, - .disable_vblank = aspeed_gfx_disable_vblank, +static int aspeed_gfx_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_commit *commit) +{ + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(commit, plane); + struct drm_crtc_state *crtc_state = NULL; + + if (plane_state->crtc) { + crtc_state = drm_atomic_get_crtc_state(commit, plane_state->crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + } + + return drm_atomic_helper_check_plane_state(plane_state, crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); +} + +static const struct drm_plane_helper_funcs aspeed_gfx_plane_helper_funcs = { + .prepare_fb = drm_gem_plane_helper_prepare_fb, + .atomic_check = aspeed_gfx_plane_helper_atomic_check, + .atomic_update = aspeed_gfx_plane_helper_atomic_update, +}; + +static const struct drm_plane_funcs aspeed_gfx_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 int aspeed_gfx_crtc_helper_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) +{ + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(commit, crtc); + int ret; + + if (crtc_state->enable) { + ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state); + if (ret) + return ret; + } + + return drm_atomic_add_affected_planes(commit, crtc); +} + +static void aspeed_gfx_crtc_helper_atomic_flush(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) +{ + struct drm_crtc_state *new_crtc_state = drm_atomic_get_new_crtc_state(commit, crtc); + struct drm_pending_vblank_event *event = new_crtc_state->event; + + if (!event) + return; + + new_crtc_state->event = NULL; + + spin_lock_irq(&crtc->dev->event_lock); + if (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_crtc_helper_funcs aspeed_gfx_crtc_helper_funcs = { + .atomic_check = aspeed_gfx_crtc_helper_atomic_check, + .atomic_enable = aspeed_gfx_crtc_helper_atomic_enable, + .atomic_disable = aspeed_gfx_crtc_helper_atomic_disable, + .atomic_flush = aspeed_gfx_crtc_helper_atomic_flush, +}; + +static const struct drm_crtc_funcs aspeed_gfx_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 = aspeed_gfx_crtc_enable_vblank, + .disable_vblank = aspeed_gfx_crtc_disable_vblank, +}; + +static const struct drm_encoder_funcs aspeed_gfx_encoder_funcs = { + .destroy = drm_encoder_cleanup, }; static const uint32_t aspeed_gfx_formats[] = { @@ -XXX,XX +XXX,XX @@ static const uint32_t aspeed_gfx_formats[] = { int aspeed_gfx_create_pipe(struct drm_device *drm) { struct aspeed_gfx *priv = to_aspeed_gfx(drm); + struct drm_plane *plane = &priv->plane; + struct drm_crtc *crtc = &priv->crtc; + struct drm_encoder *encoder = &priv->encoder; + int ret; + + ret = drm_universal_plane_init(drm, plane, 0, + &aspeed_gfx_plane_funcs, + aspeed_gfx_formats, + ARRAY_SIZE(aspeed_gfx_formats), + NULL, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + drm_plane_helper_add(plane, &aspeed_gfx_plane_helper_funcs); + + ret = drm_crtc_init_with_planes(drm, crtc, plane, NULL, + &aspeed_gfx_crtc_funcs, NULL); + if (ret) + return ret; + drm_crtc_helper_add(crtc, &aspeed_gfx_crtc_helper_funcs); + + ret = drm_encoder_init(drm, encoder, &aspeed_gfx_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + encoder->possible_crtcs = drm_crtc_mask(crtc); + + ret = drm_connector_attach_encoder(&priv->connector, encoder); + if (ret) + return ret; - return drm_simple_display_pipe_init(drm, &priv->pipe, &aspeed_gfx_funcs, - aspeed_gfx_formats, - ARRAY_SIZE(aspeed_gfx_formats), - NULL, - &priv->connector); + return 0; } diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c +++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c @@ -XXX,XX +XXX,XX @@ #include <drm/drm_gem_framebuffer_helper.h> #include <drm/drm_module.h> #include <drm/drm_probe_helper.h> -#include <drm/drm_simple_kms_helper.h> #include <drm/drm_vblank.h> #include <drm/drm_drv.h> @@ -XXX,XX +XXX,XX @@ static irqreturn_t aspeed_gfx_irq_handler(int irq, void *data) reg = readl(priv->base + CRT_CTRL1); if (reg & CRT_CTRL_VERTICAL_INTR_STS) { - drm_crtc_handle_vblank(&priv->pipe.crtc); + drm_crtc_handle_vblank(&priv->crtc); writel(reg, priv->base + priv->int_clr_reg); return IRQ_HANDLED; } -- 2.43.0
Convert MCDE to explicit plane, CRTC and encoder objects. Handle pending page-flip events from the CRTC atomic flush path using the commit-local CRTC state, and avoid manual connector/encoder attachment before the connector has been created by the bridge path. Signed-off-by: Ze Huang <ze.huang@oss.qualcomm.com> --- Changes in v3: - Move the one-shot flow start to CRTC atomic_flush(), after pending event handling. - Move the MCDE container helper to the header as static inline. --- drivers/gpu/drm/mcde/mcde_display.c | 248 +++++++++++++++++++++++------------- drivers/gpu/drm/mcde/mcde_drm.h | 12 +- drivers/gpu/drm/mcde/mcde_drv.c | 3 +- 3 files changed, 172 insertions(+), 91 deletions(-) diff --git a/drivers/gpu/drm/mcde/mcde_display.c b/drivers/gpu/drm/mcde/mcde_display.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/mcde/mcde_display.c +++ b/drivers/gpu/drm/mcde/mcde_display.c @@ -XXX,XX +XXX,XX @@ #include <linux/regulator/consumer.h> #include <linux/media-bus-format.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_device.h> #include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> @@ -XXX,XX +XXX,XX @@ #include <drm/drm_gem_dma_helper.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_print.h> -#include <drm/drm_simple_kms_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_vblank.h> #include <video/mipi_display.h> @@ -XXX,XX +XXX,XX @@ void mcde_display_irq(struct mcde *mcde) writel(mispp, mcde->regs + MCDE_RISPP); if (vblank) - drm_crtc_handle_vblank(&mcde->pipe.crtc); + drm_crtc_handle_vblank(&mcde->crtc); if (misovl) dev_info(mcde->dev, "some stray overlay IRQ %08x\n", misovl); @@ -XXX,XX +XXX,XX @@ void mcde_display_disable_irqs(struct mcde *mcde) writel(0xFFFFFFFF, mcde->regs + MCDE_RISCHNL); } -static int mcde_display_check(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *pstate, - struct drm_crtc_state *cstate) +static int mcde_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_commit *commit) { - 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(commit, plane); + struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(commit, plane); + struct drm_crtc_state *cstate = NULL; + const struct drm_display_mode *mode; + struct drm_framebuffer *old_fb = old_pstate->fb; struct drm_framebuffer *fb = pstate->fb; + int ret; - if (fb) { - u32 offset = drm_fb_dma_get_gem_addr(fb, pstate, 0); + if (pstate->crtc) { + cstate = drm_atomic_get_crtc_state(commit, pstate->crtc); + if (IS_ERR(cstate)) + return PTR_ERR(cstate); + } - /* FB base address must be dword aligned. */ - if (offset & 3) { - DRM_DEBUG_KMS("FB not 32-bit aligned\n"); - return -EINVAL; - } + ret = drm_atomic_helper_check_plane_state(pstate, cstate, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); + if (ret) + return ret; - /* - * There's no pitch register, the mode's hdisplay - * controls this. - */ - if (fb->pitches[0] != mode->hdisplay * fb->format->cpp[0]) { - DRM_DEBUG_KMS("can't handle pitches\n"); - return -EINVAL; - } + if (!pstate->visible || !fb) + return 0; - /* - * We can't change the FB format in a flicker-free - * manner (and only update it during CRTC enable). - */ - if (old_fb && old_fb->format != fb->format) - cstate->mode_changed = true; + mode = &cstate->mode; + + u32 offset = drm_fb_dma_get_gem_addr(fb, pstate, 0); + + /* FB base address must be dword aligned. */ + if (offset & 3) { + DRM_DEBUG_KMS("FB not 32-bit aligned\n"); + return -EINVAL; } + /* + * There's no pitch register, the mode's hdisplay + * controls this. + */ + if (fb->pitches[0] != mode->hdisplay * fb->format->cpp[0]) { + DRM_DEBUG_KMS("can't handle pitches\n"); + return -EINVAL; + } + + /* + * We can't change the FB format in a flicker-free + * manner (and only update it during CRTC enable). + */ + if (old_fb && old_fb->format != fb->format) + cstate->mode_changed = true; + return 0; } @@ -XXX,XX +XXX,XX @@ static void mcde_setup_dsi(struct mcde *mcde, const struct drm_display_mode *mod *dsi_formatter_frame = formatter_frame; } -static void mcde_display_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *cstate, - struct drm_plane_state *plane_state) +static void mcde_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) { - struct drm_crtc *crtc = &pipe->crtc; - struct drm_plane *plane = &pipe->plane; struct drm_device *drm = crtc->dev; struct mcde *mcde = to_mcde(drm); + struct drm_crtc_state *cstate = drm_atomic_get_new_crtc_state(commit, crtc); + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(commit, &mcde->plane); const struct drm_display_mode *mode = &cstate->mode; - struct drm_framebuffer *fb = plane->state->fb; + struct drm_framebuffer *fb = plane_state->fb; u32 format = fb->format->format; int dsi_pkt_size; int fifo_wtrmrk; @@ -XXX,XX +XXX,XX @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe, dev_info(drm->dev, "MCDE display is enabled\n"); } -static void mcde_display_disable(struct drm_simple_display_pipe *pipe) +static void mcde_crtc_helper_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) { - struct drm_crtc *crtc = &pipe->crtc; + struct drm_crtc_state *cstate = drm_atomic_get_new_crtc_state(commit, crtc); struct drm_device *drm = crtc->dev; struct mcde *mcde = to_mcde(drm); struct drm_pending_vblank_event *event; @@ -XXX,XX +XXX,XX @@ static void mcde_display_disable(struct drm_simple_display_pipe *pipe) mcde_dsi_disable(mcde->bridge); } - event = crtc->state->event; + event = cstate->event; if (event) { - crtc->state->event = NULL; + cstate->event = NULL; spin_lock_irq(&crtc->dev->event_lock); drm_crtc_send_vblank_event(crtc, event); @@ -XXX,XX +XXX,XX @@ static void mcde_set_extsrc(struct mcde *mcde, u32 buffer_address) writel(buffer_address + mcde->stride, mcde->regs + MCDE_EXTSRCXA1); } -static void mcde_display_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_pstate) +static void mcde_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_commit *commit) { - struct drm_crtc *crtc = &pipe->crtc; - struct drm_device *drm = crtc->dev; - struct mcde *mcde = to_mcde(drm); - struct drm_pending_vblank_event *event = crtc->state->event; - struct drm_plane *plane = &pipe->plane; - struct drm_plane_state *pstate = plane->state; + struct drm_plane_state *pstate = drm_atomic_get_new_plane_state(commit, plane); + struct mcde *mcde = to_mcde(plane->dev); struct drm_framebuffer *fb = pstate->fb; + /* + * We do not start sending framebuffer updates before the + * display is enabled. Update events will however be dispatched + * from the DRM core before the display is enabled. + */ + if (fb) { + mcde_set_extsrc(mcde, drm_fb_dma_get_gem_addr(fb, pstate, 0)); + dev_info_once(mcde->dev, "first update of display contents\n"); + } else { + /* + * If an update is receieved before the MCDE is enabled + * (before mcde_display_enable() is called) we can't really + * do much with that buffer. + */ + dev_info(mcde->dev, "ignored a display update\n"); + } +} + +static void mcde_crtc_helper_atomic_flush(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) +{ + struct mcde *mcde = to_mcde(crtc->dev); + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(commit, &mcde->plane); + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(commit, crtc); + struct drm_pending_vblank_event *event = crtc_state->event; + /* * Handle any pending event first, we need to arm the vblank * interrupt before sending any update to the display so we don't * miss the interrupt. */ if (event) { - crtc->state->event = NULL; + crtc_state->event = NULL; spin_lock_irq(&crtc->dev->event_lock); /* @@ -XXX,XX +XXX,XX @@ static void mcde_display_update(struct drm_simple_display_pipe *pipe, * until we get an update. If MCDE output isn't yet enabled, * we just send a vblank dummy event back. */ - if (crtc->state->active && drm_crtc_vblank_get(crtc) == 0) { + if (crtc_state->active && drm_crtc_vblank_get(crtc) == 0) { dev_dbg(mcde->dev, "arm vblank event\n"); drm_crtc_arm_vblank_event(crtc, event); } else { @@ -XXX,XX +XXX,XX @@ static void mcde_display_update(struct drm_simple_display_pipe *pipe, spin_unlock_irq(&crtc->dev->event_lock); } - /* - * We do not start sending framebuffer updates before the - * display is enabled. Update events will however be dispatched - * from the DRM core before the display is enabled. - */ - if (fb) { - mcde_set_extsrc(mcde, drm_fb_dma_get_gem_addr(fb, pstate, 0)); - dev_info_once(mcde->dev, "first update of display contents\n"); - /* - * Usually the flow is already active, unless we are in - * oneshot mode, then we need to kick the flow right here. - */ - if (mcde->flow_active == 0) - mcde_start_flow(mcde); - } else { - /* - * If an update is receieved before the MCDE is enabled - * (before mcde_display_enable() is called) we can't really - * do much with that buffer. - */ - dev_info(mcde->dev, "ignored a display update\n"); - } + if (crtc_state->active && plane_state && plane_state->fb && mcde->flow_active == 0) + mcde_start_flow(mcde); } -static int mcde_display_enable_vblank(struct drm_simple_display_pipe *pipe) +static int mcde_crtc_enable_vblank(struct drm_crtc *crtc) { - struct drm_crtc *crtc = &pipe->crtc; struct drm_device *drm = crtc->dev; struct mcde *mcde = to_mcde(drm); u32 val; @@ -XXX,XX +XXX,XX @@ static int mcde_display_enable_vblank(struct drm_simple_display_pipe *pipe) return 0; } -static void mcde_display_disable_vblank(struct drm_simple_display_pipe *pipe) +static void mcde_crtc_disable_vblank(struct drm_crtc *crtc) { - struct drm_crtc *crtc = &pipe->crtc; struct drm_device *drm = crtc->dev; struct mcde *mcde = to_mcde(drm); @@ -XXX,XX +XXX,XX @@ static void mcde_display_disable_vblank(struct drm_simple_display_pipe *pipe) writel(0xFFFFFFFF, mcde->regs + MCDE_RISPP); } -static struct drm_simple_display_pipe_funcs mcde_display_funcs = { - .check = mcde_display_check, - .enable = mcde_display_enable, - .disable = mcde_display_disable, - .update = mcde_display_update, - .enable_vblank = mcde_display_enable_vblank, - .disable_vblank = mcde_display_disable_vblank, +static int mcde_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_commit *commit) +{ + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(commit, crtc); + int ret; + + if (crtc_state->enable) { + ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state); + if (ret) + return ret; + } + + return drm_atomic_add_affected_planes(commit, crtc); +} + +static const struct drm_crtc_funcs mcde_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 = mcde_crtc_enable_vblank, + .disable_vblank = mcde_crtc_disable_vblank, +}; + +static const struct drm_crtc_helper_funcs mcde_crtc_helper_funcs = { + .atomic_check = mcde_crtc_helper_atomic_check, + .atomic_enable = mcde_crtc_helper_atomic_enable, + .atomic_disable = mcde_crtc_helper_atomic_disable, + .atomic_flush = mcde_crtc_helper_atomic_flush, +}; + +static const struct drm_plane_funcs mcde_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .reset = drm_atomic_helper_plane_reset, + .destroy = drm_plane_cleanup, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static const struct drm_plane_helper_funcs mcde_plane_helper_funcs = { + .prepare_fb = drm_gem_plane_helper_prepare_fb, + .atomic_check = mcde_plane_helper_atomic_check, + .atomic_update = mcde_plane_helper_atomic_update, +}; + +static const struct drm_encoder_funcs mcde_encoder_funcs = { + .destroy = drm_encoder_cleanup, }; int mcde_display_init(struct drm_device *drm) @@ -XXX,XX +XXX,XX @@ int mcde_display_init(struct drm_device *drm) if (ret) return ret; - ret = drm_simple_display_pipe_init(drm, &mcde->pipe, - &mcde_display_funcs, - formats, ARRAY_SIZE(formats), - NULL, - mcde->connector); + ret = drm_universal_plane_init(drm, &mcde->plane, 0, + &mcde_plane_funcs, + formats, ARRAY_SIZE(formats), + NULL, DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + + drm_plane_helper_add(&mcde->plane, &mcde_plane_helper_funcs); + + ret = drm_crtc_init_with_planes(drm, &mcde->crtc, &mcde->plane, + NULL, &mcde_crtc_funcs, NULL); if (ret) return ret; + drm_crtc_helper_add(&mcde->crtc, &mcde_crtc_helper_funcs); + + ret = drm_encoder_init(drm, &mcde->encoder, &mcde_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + + mcde->encoder.possible_crtcs = drm_crtc_mask(&mcde->crtc); + return 0; } EXPORT_SYMBOL_GPL(mcde_display_init); diff --git a/drivers/gpu/drm/mcde/mcde_drm.h b/drivers/gpu/drm/mcde/mcde_drm.h index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/mcde/mcde_drm.h +++ b/drivers/gpu/drm/mcde/mcde_drm.h @@ -XXX,XX +XXX,XX @@ * Parts of this file were based on the MCDE driver by Marcus Lorentzon * (C) ST-Ericsson SA 2013 */ -#include <drm/drm_simple_kms_helper.h> +#include <drm/drm_encoder.h> #ifndef _MCDE_DRM_H_ #define _MCDE_DRM_H_ @@ -XXX,XX +XXX,XX @@ struct mcde { struct drm_panel *panel; struct drm_bridge *bridge; struct drm_connector *connector; - struct drm_simple_display_pipe pipe; + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; struct mipi_dsi_device *mdsi; bool dpi_output; s16 stride; @@ -XXX,XX +XXX,XX @@ struct mcde { struct regulator *vana; }; -#define to_mcde(dev) container_of(dev, struct mcde, drm) +static inline struct mcde *to_mcde(struct drm_device *dev) +{ + return container_of(dev, struct mcde, drm); +} + static inline bool mcde_flow_is_video(struct mcde *mcde) { diff --git a/drivers/gpu/drm/mcde/mcde_drv.c b/drivers/gpu/drm/mcde/mcde_drv.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/mcde/mcde_drv.c +++ b/drivers/gpu/drm/mcde/mcde_drv.c @@ -XXX,XX +XXX,XX @@ static int mcde_modeset_init(struct drm_device *drm) } /* Attach the bridge. */ - ret = drm_simple_display_pipe_attach_bridge(&mcde->pipe, - mcde->bridge); + ret = drm_bridge_attach(&mcde->encoder, mcde->bridge, NULL, 0); if (ret) { dev_err(drm->dev, "failed to attach display output bridge\n"); return ret; -- 2.43.0
Replace the PL111 simple display pipe with explicit plane, CRTC and encoder objects. Move the existing timing, format and pitch validation into explicit atomic check paths. Use commit-local plane state in the CRTC enable path when reading framebuffer format state. Move page-flip event handling to the CRTC commit path. Signed-off-by: Ze Huang <ze.huang@oss.qualcomm.com> --- Changes in v3: - Use commit-local plane state in the CRTC enable path. --- drivers/gpu/drm/pl111/pl111_display.c | 199 ++++++++++++++++++++++++---------- drivers/gpu/drm/pl111/pl111_drm.h | 5 +- drivers/gpu/drm/pl111/pl111_drv.c | 3 +- 3 files changed, 148 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/pl111/pl111_display.c b/drivers/gpu/drm/pl111/pl111_display.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/pl111/pl111_display.c +++ b/drivers/gpu/drm/pl111/pl111_display.c @@ -XXX,XX +XXX,XX @@ #include <linux/media-bus-format.h> #include <linux/of_graph.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_fb_dma_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_framebuffer.h> @@ -XXX,XX +XXX,XX @@ irqreturn_t pl111_irq(int irq, void *data) return IRQ_NONE; if (irq_stat & CLCD_IRQ_NEXTBASE_UPDATE) { - drm_crtc_handle_vblank(&priv->pipe.crtc); + drm_crtc_handle_vblank(&priv->crtc); status = IRQ_HANDLED; } @@ -XXX,XX +XXX,XX @@ irqreturn_t pl111_irq(int irq, void *data) } static enum drm_mode_status -pl111_mode_valid(struct drm_simple_display_pipe *pipe, - const struct drm_display_mode *mode) +pl111_crtc_helper_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) { - struct drm_device *drm = pipe->crtc.dev; + struct drm_device *drm = crtc->dev; struct pl111_drm_dev_private *priv = drm->dev_private; u32 cpp = DIV_ROUND_UP(priv->variant->fb_depth, 8); u64 bw; @@ -XXX,XX +XXX,XX @@ pl111_mode_valid(struct drm_simple_display_pipe *pipe, return MODE_OK; } -static int pl111_display_check(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *pstate, - struct drm_crtc_state *cstate) +static int pl111_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_commit *commit) { - 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(commit, plane); + struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(commit, plane); + struct drm_crtc_state *cstate = NULL; + const struct drm_display_mode *mode; + struct drm_framebuffer *old_fb = old_pstate->fb; struct drm_framebuffer *fb = pstate->fb; + int ret; + + if (pstate->crtc) { + cstate = drm_atomic_get_crtc_state(commit, pstate->crtc); + if (IS_ERR(cstate)) + return PTR_ERR(cstate); + } + + 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; + + mode = &cstate->mode; if (mode->hdisplay % 16) return -EINVAL; @@ -XXX,XX +XXX,XX @@ static int pl111_display_check(struct drm_simple_display_pipe *pipe, return 0; } -static void pl111_display_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *cstate, - struct drm_plane_state *plane_state) +static void pl111_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) { - struct drm_crtc *crtc = &pipe->crtc; - struct drm_plane *plane = &pipe->plane; struct drm_device *drm = crtc->dev; struct pl111_drm_dev_private *priv = drm->dev_private; + struct drm_crtc_state *cstate = drm_atomic_get_new_crtc_state(commit, crtc); + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(commit, &priv->plane); const struct drm_display_mode *mode = &cstate->mode; - struct drm_framebuffer *fb = plane->state->fb; + struct drm_framebuffer *fb = plane_state->fb; struct drm_connector *connector = priv->connector; struct drm_bridge *bridge = priv->bridge; bool grayscale = false; @@ -XXX,XX +XXX,XX @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe, drm_crtc_vblank_on(crtc); } -static void pl111_display_disable(struct drm_simple_display_pipe *pipe) +static void pl111_crtc_helper_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) { - struct drm_crtc *crtc = &pipe->crtc; struct drm_device *drm = crtc->dev; struct pl111_drm_dev_private *priv = drm->dev_private; u32 cntl; @@ -XXX,XX +XXX,XX @@ static void pl111_display_disable(struct drm_simple_display_pipe *pipe) clk_disable_unprepare(priv->clk); } -static void pl111_display_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_pstate) +static void pl111_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_commit *commit) { - struct drm_crtc *crtc = &pipe->crtc; - struct drm_device *drm = crtc->dev; + struct drm_device *drm = plane->dev; struct pl111_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_plane_state *pstate = drm_atomic_get_new_plane_state(commit, plane); struct drm_framebuffer *fb = pstate->fb; - if (fb) { - u32 addr = drm_fb_dma_get_gem_addr(fb, pstate, 0); + if (!fb) + return; - writel(addr, priv->regs + CLCD_UBAS); - } + u32 addr = drm_fb_dma_get_gem_addr(fb, pstate, 0); - if (event) { - crtc->state->event = NULL; + writel(addr, priv->regs + CLCD_UBAS); +} - 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 void pl111_crtc_helper_atomic_flush(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) +{ + struct drm_crtc_state *cstate = drm_atomic_get_new_crtc_state(commit, crtc); + struct drm_pending_vblank_event *event = cstate->event; + + if (!event) + return; + + cstate->event = NULL; + + spin_lock_irq(&crtc->dev->event_lock); + if (cstate->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 pl111_display_enable_vblank(struct drm_simple_display_pipe *pipe) +static int pl111_display_enable_vblank(struct drm_crtc *crtc) { - struct drm_crtc *crtc = &pipe->crtc; struct drm_device *drm = crtc->dev; struct pl111_drm_dev_private *priv = drm->dev_private; @@ -XXX,XX +XXX,XX @@ static int pl111_display_enable_vblank(struct drm_simple_display_pipe *pipe) return 0; } -static void pl111_display_disable_vblank(struct drm_simple_display_pipe *pipe) +static void pl111_display_disable_vblank(struct drm_crtc *crtc) { - struct drm_crtc *crtc = &pipe->crtc; struct drm_device *drm = crtc->dev; struct pl111_drm_dev_private *priv = drm->dev_private; writel(0, priv->regs + priv->ienb); } -static struct drm_simple_display_pipe_funcs pl111_display_funcs = { - .mode_valid = pl111_mode_valid, - .check = pl111_display_check, - .enable = pl111_display_enable, - .disable = pl111_display_disable, - .update = pl111_display_update, +static int pl111_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_commit *commit) +{ + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(commit, crtc); + int ret; + + if (crtc_state->enable) { + ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state); + if (ret) + return ret; + } + + return drm_atomic_add_affected_planes(commit, crtc); +} + +static struct drm_crtc_funcs pl111_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, +}; + +static const struct drm_crtc_helper_funcs pl111_crtc_helper_funcs = { + .mode_valid = pl111_crtc_helper_mode_valid, + .atomic_check = pl111_crtc_helper_atomic_check, + .atomic_enable = pl111_crtc_helper_atomic_enable, + .atomic_disable = pl111_crtc_helper_atomic_disable, + .atomic_flush = pl111_crtc_helper_atomic_flush, +}; + +static const struct drm_plane_funcs pl111_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .reset = drm_atomic_helper_plane_reset, + .destroy = drm_plane_cleanup, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static const struct drm_plane_helper_funcs pl111_plane_helper_funcs = { + .prepare_fb = drm_gem_plane_helper_prepare_fb, + .atomic_check = pl111_plane_helper_atomic_check, + .atomic_update = pl111_plane_helper_atomic_update, +}; + +static const struct drm_encoder_funcs pl111_encoder_funcs = { + .destroy = drm_encoder_cleanup, }; static int pl111_clk_div_choose_div(struct clk_hw *hw, unsigned long rate, @@ -XXX,XX +XXX,XX @@ int pl111_display_init(struct drm_device *drm) return ret; if (!priv->variant->broken_vblank) { - pl111_display_funcs.enable_vblank = pl111_display_enable_vblank; - pl111_display_funcs.disable_vblank = pl111_display_disable_vblank; + pl111_crtc_funcs.enable_vblank = pl111_display_enable_vblank; + pl111_crtc_funcs.disable_vblank = pl111_display_disable_vblank; } - ret = drm_simple_display_pipe_init(drm, &priv->pipe, - &pl111_display_funcs, - priv->variant->formats, - priv->variant->nformats, - NULL, - priv->connector); + ret = drm_universal_plane_init(drm, &priv->plane, 0, + &pl111_plane_funcs, + priv->variant->formats, + priv->variant->nformats, + NULL, DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + + drm_plane_helper_add(&priv->plane, &pl111_plane_helper_funcs); + + ret = drm_crtc_init_with_planes(drm, &priv->crtc, &priv->plane, + NULL, &pl111_crtc_funcs, NULL); + if (ret) + return ret; + + drm_crtc_helper_add(&priv->crtc, &pl111_crtc_helper_funcs); + + ret = drm_encoder_init(drm, &priv->encoder, &pl111_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); if (ret) return ret; + priv->encoder.possible_crtcs = drm_crtc_mask(&priv->crtc); + + if (priv->connector) { + ret = drm_connector_attach_encoder(priv->connector, + &priv->encoder); + if (ret) + return ret; + } + return 0; } diff --git a/drivers/gpu/drm/pl111/pl111_drm.h b/drivers/gpu/drm/pl111/pl111_drm.h index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/pl111/pl111_drm.h +++ b/drivers/gpu/drm/pl111/pl111_drm.h @@ -XXX,XX +XXX,XX @@ #include <drm/drm_encoder.h> #include <drm/drm_gem.h> #include <drm/drm_panel.h> -#include <drm/drm_simple_kms_helper.h> /* * CLCD Controller Internal Register addresses @@ -XXX,XX +XXX,XX @@ struct pl111_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; u32 memory_bw; diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/pl111/pl111_drv.c +++ b/drivers/gpu/drm/pl111/pl111_drv.c @@ -XXX,XX +XXX,XX @@ static int pl111_modeset_init(struct drm_device *dev) goto out_bridge; } - ret = drm_simple_display_pipe_attach_bridge(&priv->pipe, - bridge); + ret = drm_bridge_attach(&priv->encoder, bridge, NULL, 0); if (ret) return ret; -- 2.43.0
Convert gm12u320 to direct primary plane, CRTC and encoder setup. Keep shadow-plane helper state, framebuffer access helpers and no-scaling plane-state check from simple-KMS path. Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de> Tested-by: Thomas Zimmermann <tzimmermann@suse.de> Signed-off-by: Ze Huang <ze.huang@oss.qualcomm.com> --- Changes in v3: - Use commit-local plane state in the CRTC enable path when marking the first frame dirty. - Make the gm12u320 container helper static inline. --- drivers/gpu/drm/tiny/gm12u320.c | 138 ++++++++++++++++++++++++++++++++-------- 1 file changed, 111 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/tiny/gm12u320.c b/drivers/gpu/drm/tiny/gm12u320.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/tiny/gm12u320.c +++ b/drivers/gpu/drm/tiny/gm12u320.c @@ -XXX,XX +XXX,XX @@ #include <linux/usb.h> #include <drm/clients/drm_client_setup.h> +#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_state_helper.h> #include <drm/drm_connector.h> @@ -XXX,XX +XXX,XX @@ #include <drm/drm_modeset_helper_vtables.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> -#include <drm/drm_simple_kms_helper.h> static bool eco_mode; module_param(eco_mode, bool, 0644); @@ -XXX,XX +XXX,XX @@ MODULE_PARM_DESC(eco_mode, "Turn on Eco mode (less bright, more silent)"); struct gm12u320_device { struct drm_device dev; - struct drm_simple_display_pipe pipe; + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; struct drm_connector conn; unsigned char *cmd_buf; unsigned char *data_buf[GM12U320_BLOCK_COUNT]; @@ -XXX,XX +XXX,XX @@ struct gm12u320_device { } fb_update; }; -#define to_gm12u320(__dev) container_of(__dev, struct gm12u320_device, dev) +static inline struct gm12u320_device *to_gm12u320(struct drm_device *__dev) +{ + return container_of(__dev, struct gm12u320_device, dev); +} static const char cmd_data[CMD_SIZE] = { 0x55, 0x53, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, @@ -XXX,XX +XXX,XX @@ static int gm12u320_conn_init(struct gm12u320_device *gm12u320) } /* ------------------------------------------------------------------ */ -/* gm12u320 (simple) display pipe */ +/* gm12u320 display pipe */ -static void gm12u320_pipe_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +static void gm12u320_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) { struct drm_rect rect = { 0, 0, GM12U320_USER_WIDTH, GM12U320_HEIGHT }; - struct gm12u320_device *gm12u320 = to_gm12u320(pipe->crtc.dev); - struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); + struct gm12u320_device *gm12u320 = to_gm12u320(crtc->dev); + struct drm_plane_state *pstate = drm_atomic_get_new_plane_state(commit, &gm12u320->plane); + struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(pstate); gm12u320->fb_update.draw_status_timeout = FIRST_FRAME_TIMEOUT; - gm12u320_fb_mark_dirty(plane_state->fb, &shadow_plane_state->data[0], &rect); + gm12u320_fb_mark_dirty(pstate->fb, &shadow_plane_state->data[0], &rect); } -static void gm12u320_pipe_disable(struct drm_simple_display_pipe *pipe) +static void gm12u320_crtc_helper_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) { - struct gm12u320_device *gm12u320 = to_gm12u320(pipe->crtc.dev); + struct gm12u320_device *gm12u320 = to_gm12u320(crtc->dev); gm12u320_stop_fb_update(gm12u320); } -static void gm12u320_pipe_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_state) +static void gm12u320_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_commit *commit) { - struct drm_plane_state *state = pipe->plane.state; + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(commit, plane); + struct drm_plane_state *state = drm_atomic_get_new_plane_state(commit, plane); struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state); struct drm_rect rect; + if (!state->fb) + return; + if (drm_atomic_helper_damage_merged(old_state, state, &rect)) gm12u320_fb_mark_dirty(state->fb, &shadow_plane_state->data[0], &rect); } -static const struct drm_simple_display_pipe_funcs gm12u320_pipe_funcs = { - .enable = gm12u320_pipe_enable, - .disable = gm12u320_pipe_disable, - .update = gm12u320_pipe_update, - DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, +static const struct drm_plane_funcs gm12u320_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + DRM_GEM_SHADOW_PLANE_FUNCS, +}; + +static int gm12u320_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_commit *commit) +{ + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(commit, plane); + struct drm_crtc_state *crtc_state = NULL; + + if (plane_state->crtc) { + crtc_state = drm_atomic_get_crtc_state(commit, plane_state->crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + } + + return drm_atomic_helper_check_plane_state(plane_state, crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); +} + +static const struct drm_plane_helper_funcs gm12u320_plane_helper_funcs = { + DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, + .atomic_check = gm12u320_plane_helper_atomic_check, + .atomic_update = gm12u320_plane_helper_atomic_update, +}; + +static int gm12u320_crtc_helper_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) +{ + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(commit, crtc); + int ret; + + if (crtc_state->enable) { + ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state); + if (ret) + return ret; + } + + return drm_atomic_add_affected_planes(commit, crtc); +} + +static const struct drm_crtc_helper_funcs gm12u320_crtc_helper_funcs = { + .atomic_check = gm12u320_crtc_helper_atomic_check, + .atomic_enable = gm12u320_crtc_helper_atomic_enable, + .atomic_disable = gm12u320_crtc_helper_atomic_disable, +}; + +static const struct drm_crtc_funcs gm12u320_crtc_funcs = { + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .reset = drm_atomic_helper_crtc_reset, + .destroy = drm_crtc_cleanup, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, +}; + +static const struct drm_encoder_funcs gm12u320_encoder_funcs = { + .destroy = drm_encoder_cleanup, }; static const uint32_t gm12u320_pipe_formats[] = { @@ -XXX,XX +XXX,XX @@ static int gm12u320_usb_probe(struct usb_interface *interface, if (ret) return ret; - ret = drm_simple_display_pipe_init(&gm12u320->dev, - &gm12u320->pipe, - &gm12u320_pipe_funcs, - gm12u320_pipe_formats, - ARRAY_SIZE(gm12u320_pipe_formats), - gm12u320_pipe_modifiers, - &gm12u320->conn); + ret = drm_universal_plane_init(dev, &gm12u320->plane, 0, + &gm12u320_plane_funcs, + gm12u320_pipe_formats, + ARRAY_SIZE(gm12u320_pipe_formats), + gm12u320_pipe_modifiers, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + drm_plane_helper_add(&gm12u320->plane, &gm12u320_plane_helper_funcs); + + ret = drm_crtc_init_with_planes(dev, &gm12u320->crtc, &gm12u320->plane, NULL, + &gm12u320_crtc_funcs, NULL); + if (ret) + return ret; + drm_crtc_helper_add(&gm12u320->crtc, &gm12u320_crtc_helper_funcs); + + ret = drm_encoder_init(dev, &gm12u320->encoder, &gm12u320_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + gm12u320->encoder.possible_crtcs = drm_crtc_mask(&gm12u320->crtc); + + ret = drm_connector_attach_encoder(&gm12u320->conn, &gm12u320->encoder); if (ret) return ret; -- 2.43.0
Convert repaper to explicit primary plane, CRTC and encoder objects. Keep the shadow-plane helpers, framebuffer access handling and no-scaling plane-state validation from the simple-KMS path. Signed-off-by: Ze Huang <ze.huang@oss.qualcomm.com> --- Changes in v3: - Skip damage updates unless the CRTC state exists and is active. --- drivers/gpu/drm/tiny/repaper.c | 138 ++++++++++++++++++++++++++++++++--------- 1 file changed, 110 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/tiny/repaper.c b/drivers/gpu/drm/tiny/repaper.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/tiny/repaper.c +++ b/drivers/gpu/drm/tiny/repaper.c @@ -XXX,XX +XXX,XX @@ #include <linux/thermal.h> #include <drm/clients/drm_client_setup.h> +#include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_connector.h> #include <drm/drm_damage_helper.h> @@ -XXX,XX +XXX,XX @@ #include <drm/drm_rect.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> -#include <drm/drm_simple_kms_helper.h> #define REPAPER_RID_G2_COG_ID 0x12 @@ -XXX,XX +XXX,XX @@ enum repaper_epd_border_byte { struct repaper_epd { struct drm_device drm; - struct drm_simple_display_pipe pipe; + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; const struct drm_display_mode *mode; struct drm_connector connector; struct spi_device *spi; @@ -XXX,XX +XXX,XX @@ static void power_off(struct repaper_epd *epd) gpiod_set_value_cansleep(epd->discharge, 0); } -static enum drm_mode_status repaper_pipe_mode_valid(struct drm_simple_display_pipe *pipe, - const struct drm_display_mode *mode) +static enum drm_mode_status repaper_crtc_helper_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) { - struct drm_crtc *crtc = &pipe->crtc; struct repaper_epd *epd = drm_to_epd(crtc->dev); return drm_crtc_helper_mode_valid_fixed(crtc, mode, epd->mode); } -static void repaper_pipe_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +static void repaper_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) { - struct repaper_epd *epd = drm_to_epd(pipe->crtc.dev); + struct repaper_epd *epd = drm_to_epd(crtc->dev); struct spi_device *spi = epd->spi; struct device *dev = &spi->dev; bool dc_ok = false; int i, ret, idx; - if (!drm_dev_enter(pipe->crtc.dev, &idx)) + if (!drm_dev_enter(crtc->dev, &idx)) return; DRM_DEBUG_DRIVER("\n"); @@ -XXX,XX +XXX,XX @@ static void repaper_pipe_enable(struct drm_simple_display_pipe *pipe, drm_dev_exit(idx); } -static void repaper_pipe_disable(struct drm_simple_display_pipe *pipe) +static void repaper_crtc_helper_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) { - struct repaper_epd *epd = drm_to_epd(pipe->crtc.dev); + struct repaper_epd *epd = drm_to_epd(crtc->dev); struct spi_device *spi = epd->spi; unsigned int line; @@ -XXX,XX +XXX,XX @@ static void repaper_pipe_disable(struct drm_simple_display_pipe *pipe) power_off(epd); } -static void repaper_pipe_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_state) +static void repaper_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_commit *commit) { - struct drm_plane_state *state = pipe->plane.state; - struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(state); + struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(commit, plane); + struct drm_plane_state *pstate = drm_atomic_get_new_plane_state(commit, plane); + struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(pstate); + struct drm_crtc_state *cstate = NULL; struct drm_rect rect; - if (!pipe->crtc.state->active) + if (pstate->crtc) + cstate = drm_atomic_get_new_crtc_state(commit, pstate->crtc); + + if (!cstate || !cstate->active) return; - if (drm_atomic_helper_damage_merged(old_state, state, &rect)) - repaper_fb_dirty(state->fb, shadow_plane_state->data, + if (drm_atomic_helper_damage_merged(old_pstate, pstate, &rect)) + repaper_fb_dirty(pstate->fb, shadow_plane_state->data, &shadow_plane_state->fmtcnv_state); } -static const struct drm_simple_display_pipe_funcs repaper_pipe_funcs = { - .mode_valid = repaper_pipe_mode_valid, - .enable = repaper_pipe_enable, - .disable = repaper_pipe_disable, - .update = repaper_pipe_update, - DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, +static const struct drm_plane_funcs repaper_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + DRM_GEM_SHADOW_PLANE_FUNCS, +}; + +static int repaper_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_commit *commit) +{ + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(commit, plane); + struct drm_crtc_state *crtc_state = NULL; + + if (plane_state->crtc) { + crtc_state = drm_atomic_get_crtc_state(commit, plane_state->crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + } + + return drm_atomic_helper_check_plane_state(plane_state, crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); +} + +static const struct drm_plane_helper_funcs repaper_plane_helper_funcs = { + DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, + .atomic_check = repaper_plane_helper_atomic_check, + .atomic_update = repaper_plane_helper_atomic_update, +}; + +static int repaper_crtc_helper_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) +{ + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(commit, crtc); + int ret; + + if (crtc_state->enable) { + ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state); + if (ret) + return ret; + } + + return drm_atomic_add_affected_planes(commit, crtc); +} + +static const struct drm_crtc_helper_funcs repaper_crtc_helper_funcs = { + .mode_valid = repaper_crtc_helper_mode_valid, + .atomic_check = repaper_crtc_helper_atomic_check, + .atomic_enable = repaper_crtc_helper_atomic_enable, + .atomic_disable = repaper_crtc_helper_atomic_disable, +}; + +static const struct drm_crtc_funcs repaper_crtc_funcs = { + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .reset = drm_atomic_helper_crtc_reset, + .destroy = drm_crtc_cleanup, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, +}; + +static const struct drm_encoder_funcs repaper_encoder_funcs = { + .destroy = drm_encoder_cleanup, }; static int repaper_connector_get_modes(struct drm_connector *connector) @@ -XXX,XX +XXX,XX @@ static int repaper_probe(struct spi_device *spi) if (ret) return ret; - ret = drm_simple_display_pipe_init(drm, &epd->pipe, &repaper_pipe_funcs, - repaper_formats, ARRAY_SIZE(repaper_formats), - NULL, &epd->connector); + ret = drm_universal_plane_init(drm, &epd->plane, 0, + &repaper_plane_funcs, + repaper_formats, ARRAY_SIZE(repaper_formats), + NULL, DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + drm_plane_helper_add(&epd->plane, &repaper_plane_helper_funcs); + + ret = drm_crtc_init_with_planes(drm, &epd->crtc, &epd->plane, NULL, + &repaper_crtc_funcs, NULL); + if (ret) + return ret; + drm_crtc_helper_add(&epd->crtc, &repaper_crtc_helper_funcs); + + ret = drm_encoder_init(drm, &epd->encoder, &repaper_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + epd->encoder.possible_crtcs = drm_crtc_mask(&epd->crtc); + + ret = drm_connector_attach_encoder(&epd->connector, &epd->encoder); if (ret) return ret; -- 2.43.0
Convert TVE200 to explicit plane, CRTC and encoder objects. Keep generic plane-state validation before TVE200-specific mode, alignment, pitch and format-change checks. Install the GEM framebuffer prepare helper explicitly. Use commit-local plane state in the CRTC enable path when programming framebuffer format state. Move page-flip event handling to the CRTC commit path and wire the CRTC vblank callbacks explicitly. Signed-off-by: Ze Huang <ze.huang@oss.qualcomm.com> --- Changes in v3: - Use commit-local plane state in the CRTC enable path. --- drivers/gpu/drm/tve200/tve200_display.c | 219 ++++++++++++++++++++++---------- drivers/gpu/drm/tve200/tve200_drm.h | 6 +- drivers/gpu/drm/tve200/tve200_drv.c | 12 +- 3 files changed, 163 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/tve200/tve200_display.c b/drivers/gpu/drm/tve200/tve200_display.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/tve200/tve200_display.c +++ b/drivers/gpu/drm/tve200/tve200_display.c @@ -XXX,XX +XXX,XX @@ #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> @@ -XXX,XX +XXX,XX @@ 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 { @@ -XXX,XX +XXX,XX @@ 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 *commit) { - 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(commit, plane); + struct drm_plane_state *old_pstate = drm_atomic_get_old_plane_state(commit, plane); + struct drm_crtc_state *cstate = NULL; + const struct drm_display_mode *mode; + struct drm_framebuffer *old_fb = old_pstate->fb; struct drm_framebuffer *fb = pstate->fb; + int ret; + + if (pstate->crtc) { + cstate = drm_atomic_get_crtc_state(commit, pstate->crtc); + if (IS_ERR(cstate)) + return PTR_ERR(cstate); + } + + 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 || !cstate) + return 0; + + mode = &cstate->mode; /* * We support these specific resolutions and nothing else. @@ -XXX,XX +XXX,XX @@ 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 *commit) +{ + struct tve200_drm_dev_private *priv = plane->dev->dev_private; + struct drm_plane_state *pstate = drm_atomic_get_new_plane_state(commit, plane); + struct drm_framebuffer *fb = pstate->fb; + + if (!fb) + return; + + /* 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); + } +} + +static void tve200_crtc_helper_atomic_flush(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) +{ + struct drm_crtc_state *cstate = drm_atomic_get_new_crtc_state(commit, crtc); + struct drm_pending_vblank_event *event = cstate->event; + + if (!event) + return; + + cstate->event = NULL; + + spin_lock_irq(&crtc->dev->event_lock); + if (cstate->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 *commit) { - 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(commit, crtc); const struct drm_display_mode *mode = &cstate->mode; - struct drm_framebuffer *fb = plane->state->fb; + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(commit, &priv->plane); + struct drm_framebuffer *fb = plane_state->fb; struct drm_connector *connector = priv->connector; u32 format = fb->format->format; u32 ctrl1 = 0; @@ -XXX,XX +XXX,XX @@ 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 *commit) { - struct drm_crtc *crtc = &pipe->crtc; struct drm_device *drm = crtc->dev; struct tve200_drm_dev_private *priv = drm->dev_private; @@ -XXX,XX +XXX,XX @@ 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) +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; - 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) -{ - struct drm_crtc *crtc = &pipe->crtc; struct drm_device *drm = crtc->dev; struct tve200_drm_dev_private *priv = drm->dev_private; @@ -XXX,XX +XXX,XX @@ 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 *commit) +{ + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(commit, crtc); + int ret; + + if (crtc_state->enable) { + ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state); + if (ret) + return ret; + } + + return drm_atomic_add_affected_planes(commit, 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, + .atomic_flush = tve200_crtc_helper_atomic_flush, +}; + +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) @@ -XXX,XX +XXX,XX @@ 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 XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/tve200/tve200_drm.h +++ b/drivers/gpu/drm/tve200/tve200_drm.h @@ -XXX,XX +XXX,XX @@ #include <linux/irqreturn.h> -#include <drm/drm_simple_kms_helper.h> - struct clk; struct drm_bridge; struct drm_connector; @@ -XXX,XX +XXX,XX @@ 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 XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/tve200/tve200_drv.c +++ b/drivers/gpu/drm/tve200/tve200_drv.c @@ -XXX,XX +XXX,XX @@ 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->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; } - priv->panel = panel; priv->connector = drm_panel_bridge_connector(bridge); - priv->bridge = bridge; + if (!priv->connector) { + ret = -ENODEV; + goto out_bridge; + } dev_info(dev->dev, "attached to panel %s\n", dev_name(panel->dev)); -- 2.43.0
Replace the Xen frontend simple display pipe with explicit plane, CRTC and encoder objects for each pipeline. Keep generic plane-state validation before Xen-specific checks, and install the GEM framebuffer prepare helper explicitly. Use commit-local plane state in the CRTC enable path and pass the new plane source position to the backend mode-set request. Handle pending page-flip events through the commit-local CRTC state in the plane update path. Signed-off-by: Ze Huang <ze.huang@oss.qualcomm.com> --- Changes in v3: - Use commit-local plane state in the CRTC enable path. - Pass the new plane source position to the xen_drm_front_mode_set. - Make the container helpers static inline. --- drivers/gpu/drm/xen/xen_drm_front.h | 6 +- drivers/gpu/drm/xen/xen_drm_front_kms.c | 188 +++++++++++++++++++++++--------- 2 files changed, 142 insertions(+), 52 deletions(-) diff --git a/drivers/gpu/drm/xen/xen_drm_front.h b/drivers/gpu/drm/xen/xen_drm_front.h index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/xen/xen_drm_front.h +++ b/drivers/gpu/drm/xen/xen_drm_front.h @@ -XXX,XX +XXX,XX @@ #include <linux/scatterlist.h> #include <drm/drm_connector.h> -#include <drm/drm_simple_kms_helper.h> +#include <drm/drm_encoder.h> #include "xen_drm_front_cfg.h" @@ -XXX,XX +XXX,XX @@ struct xen_drm_front_drm_pipeline { int index; - struct drm_simple_display_pipe pipe; + struct drm_plane plane; + struct drm_crtc crtc; + struct drm_encoder encoder; struct drm_connector conn; /* These are only for connector mode checking */ diff --git a/drivers/gpu/drm/xen/xen_drm_front_kms.c b/drivers/gpu/drm/xen/xen_drm_front_kms.c index XXXXXXX..XXXXXXX 100644 --- a/drivers/gpu/drm/xen/xen_drm_front_kms.c +++ b/drivers/gpu/drm/xen/xen_drm_front_kms.c @@ -XXX,XX +XXX,XX @@ */ #define FRAME_DONE_TO_MS (XEN_DRM_FRONT_WAIT_BACK_MS + 100) -static struct xen_drm_front_drm_pipeline * -to_xen_drm_pipeline(struct drm_simple_display_pipe *pipe) +static inline struct xen_drm_front_drm_pipeline * +xen_drm_pipeline_from_crtc(struct drm_crtc *crtc) { - return container_of(pipe, struct xen_drm_front_drm_pipeline, pipe); + return container_of(crtc, struct xen_drm_front_drm_pipeline, crtc); +} + +static inline struct xen_drm_front_drm_pipeline * +xen_drm_pipeline_from_plane(struct drm_plane *plane) +{ + return container_of(plane, struct xen_drm_front_drm_pipeline, plane); } static void fb_destroy(struct drm_framebuffer *fb) @@ -XXX,XX +XXX,XX @@ static const struct drm_mode_config_funcs mode_config_funcs = { static void send_pending_event(struct xen_drm_front_drm_pipeline *pipeline) { - struct drm_crtc *crtc = &pipeline->pipe.crtc; + struct drm_crtc *crtc = &pipeline->crtc; struct drm_device *dev = crtc->dev; unsigned long flags; @@ -XXX,XX +XXX,XX @@ static void send_pending_event(struct xen_drm_front_drm_pipeline *pipeline) spin_unlock_irqrestore(&dev->event_lock, flags); } -static void display_enable(struct drm_simple_display_pipe *pipe, - struct drm_crtc_state *crtc_state, - struct drm_plane_state *plane_state) +static void xen_drm_crtc_helper_atomic_enable(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) { - struct xen_drm_front_drm_pipeline *pipeline = - to_xen_drm_pipeline(pipe); - struct drm_crtc *crtc = &pipe->crtc; - struct drm_framebuffer *fb = plane_state->fb; + struct xen_drm_front_drm_pipeline *pipeline = xen_drm_pipeline_from_crtc(crtc); + struct drm_plane_state *pstate = drm_atomic_get_new_plane_state(commit, &pipeline->plane); + struct drm_framebuffer *fb = pstate->fb; int ret, idx; - if (!drm_dev_enter(pipe->crtc.dev, &idx)) + if (!drm_dev_enter(crtc->dev, &idx)) return; - ret = xen_drm_front_mode_set(pipeline, crtc->x, crtc->y, + ret = xen_drm_front_mode_set(pipeline, pstate->crtc_x, pstate->crtc_y, fb->width, fb->height, fb->format->cpp[0] * 8, xen_drm_front_fb_to_cookie(fb)); - if (ret) { DRM_ERROR("Failed to enable display: %d\n", ret); pipeline->conn_connected = false; @@ -XXX,XX +XXX,XX @@ static void display_enable(struct drm_simple_display_pipe *pipe, drm_dev_exit(idx); } -static void display_disable(struct drm_simple_display_pipe *pipe) +static void xen_drm_crtc_helper_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_commit *commit) { - struct xen_drm_front_drm_pipeline *pipeline = - to_xen_drm_pipeline(pipe); + struct xen_drm_front_drm_pipeline *pipeline = xen_drm_pipeline_from_crtc(crtc); int ret = 0, idx; - if (drm_dev_enter(pipe->crtc.dev, &idx)) { + if (drm_dev_enter(crtc->dev, &idx)) { ret = xen_drm_front_mode_set(pipeline, 0, 0, 0, 0, 0, xen_drm_front_fb_to_cookie(NULL)); drm_dev_exit(idx); @@ -XXX,XX +XXX,XX @@ static void pflip_to_worker(struct work_struct *work) send_pending_event(pipeline); } -static bool display_send_page_flip(struct drm_simple_display_pipe *pipe, +static bool display_send_page_flip(struct xen_drm_front_drm_pipeline *pipeline, + struct drm_atomic_commit *commit, struct drm_plane_state *old_plane_state) { struct drm_plane_state *plane_state = - drm_atomic_get_new_plane_state(old_plane_state->state, - &pipe->plane); + drm_atomic_get_new_plane_state(commit, + &pipeline->plane); /* * If old_plane_state->fb is NULL and plane_state->fb is not, @@ -XXX,XX +XXX,XX @@ static bool display_send_page_flip(struct drm_simple_display_pipe *pipe, * sent to the backend as a part of display_set_config call. */ if (old_plane_state->fb && plane_state->fb) { - struct xen_drm_front_drm_pipeline *pipeline = - to_xen_drm_pipeline(pipe); struct xen_drm_front_drm_info *drm_info = pipeline->drm_info; int ret; @@ -XXX,XX +XXX,XX @@ static bool display_send_page_flip(struct drm_simple_display_pipe *pipe, return false; } -static int display_check(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *plane_state, - struct drm_crtc_state *crtc_state) +static int xen_drm_plane_helper_atomic_check(struct drm_plane *plane, + struct drm_atomic_commit *commit) { + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(commit, plane); + struct drm_crtc_state *crtc_state = NULL; + int ret; + + if (plane_state->crtc) { + crtc_state = drm_atomic_get_crtc_state(commit, plane_state->crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + } + + ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + false, false); + if (ret) + return ret; + + if (!plane_state->visible || !crtc_state) + return 0; + /* * Xen doesn't initialize vblanking via drm_vblank_init(), so * DRM helpers assume that it doesn't handle vblanking and start @@ -XXX,XX +XXX,XX @@ static int display_check(struct drm_simple_display_pipe *pipe, return 0; } -static void display_update(struct drm_simple_display_pipe *pipe, - struct drm_plane_state *old_plane_state) +static void xen_drm_plane_helper_atomic_update(struct drm_plane *plane, + struct drm_atomic_commit *commit) { - struct xen_drm_front_drm_pipeline *pipeline = - to_xen_drm_pipeline(pipe); - struct drm_crtc *crtc = &pipe->crtc; + struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(commit, plane); + struct xen_drm_front_drm_pipeline *pipeline = xen_drm_pipeline_from_plane(plane); + struct drm_crtc *crtc = &pipeline->crtc; + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(commit, crtc); struct drm_pending_vblank_event *event; int idx; - event = crtc->state->event; + event = crtc_state ? crtc_state->event : NULL; if (event) { struct drm_device *dev = crtc->dev; unsigned long flags; @@ -XXX,XX +XXX,XX @@ static void display_update(struct drm_simple_display_pipe *pipe, WARN_ON(pipeline->pending_event); spin_lock_irqsave(&dev->event_lock, flags); - crtc->state->event = NULL; + crtc_state->event = NULL; pipeline->pending_event = event; spin_unlock_irqrestore(&dev->event_lock, flags); } - if (!drm_dev_enter(pipe->crtc.dev, &idx)) { + if (!drm_dev_enter(crtc->dev, &idx)) { send_pending_event(pipeline); return; } @@ -XXX,XX +XXX,XX @@ static void display_update(struct drm_simple_display_pipe *pipe, * If this is not a page flip, e.g. no flip done event from the backend * is expected, then send now. */ - if (!display_send_page_flip(pipe, old_plane_state)) + if (!display_send_page_flip(pipeline, commit, old_plane_state)) send_pending_event(pipeline); drm_dev_exit(idx); } static enum drm_mode_status -display_mode_valid(struct drm_simple_display_pipe *pipe, - const struct drm_display_mode *mode) +xen_drm_crtc_helper_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) { - struct xen_drm_front_drm_pipeline *pipeline = - container_of(pipe, struct xen_drm_front_drm_pipeline, - pipe); + struct xen_drm_front_drm_pipeline *pipeline = xen_drm_pipeline_from_crtc(crtc); if (mode->hdisplay != pipeline->width) return MODE_ERROR; @@ -XXX,XX +XXX,XX @@ display_mode_valid(struct drm_simple_display_pipe *pipe, return MODE_OK; } -static const struct drm_simple_display_pipe_funcs display_funcs = { - .mode_valid = display_mode_valid, - .enable = display_enable, - .disable = display_disable, - .check = display_check, - .update = display_update, +static int xen_drm_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_commit *commit) +{ + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(commit, crtc); + int ret; + + if (crtc_state->enable) { + ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state); + if (ret) + return ret; + } + + return drm_atomic_add_affected_planes(commit, crtc); +} + +static const struct drm_plane_helper_funcs display_plane_helper_funcs = { + .prepare_fb = drm_gem_plane_helper_prepare_fb, + .atomic_check = xen_drm_plane_helper_atomic_check, + .atomic_update = xen_drm_plane_helper_atomic_update, +}; + +static const struct drm_plane_funcs display_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 const struct drm_crtc_helper_funcs display_crtc_helper_funcs = { + .mode_valid = xen_drm_crtc_helper_mode_valid, + .atomic_check = xen_drm_crtc_helper_atomic_check, + .atomic_enable = xen_drm_crtc_helper_atomic_enable, + .atomic_disable = xen_drm_crtc_helper_atomic_disable, +}; + +static const struct drm_crtc_funcs display_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, +}; + +static const struct drm_encoder_funcs display_encoder_funcs = { + .destroy = drm_encoder_cleanup, }; static int display_pipe_init(struct xen_drm_front_drm_info *drm_info, @@ -XXX,XX +XXX,XX @@ static int display_pipe_init(struct xen_drm_front_drm_info *drm_info, formats = xen_drm_front_conn_get_formats(&format_count); - return drm_simple_display_pipe_init(dev, &pipeline->pipe, - &display_funcs, formats, - format_count, NULL, - &pipeline->conn); + ret = drm_universal_plane_init(dev, &pipeline->plane, 0, + &display_plane_funcs, + formats, format_count, + NULL, + DRM_PLANE_TYPE_PRIMARY, NULL); + if (ret) + return ret; + + drm_plane_helper_add(&pipeline->plane, &display_plane_helper_funcs); + + ret = drm_crtc_init_with_planes(dev, &pipeline->crtc, + &pipeline->plane, NULL, + &display_crtc_funcs, NULL); + if (ret) + return ret; + + drm_crtc_helper_add(&pipeline->crtc, &display_crtc_helper_funcs); + + ret = drm_encoder_init(dev, &pipeline->encoder, + &display_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); + if (ret) + return ret; + + pipeline->encoder.possible_crtcs = drm_crtc_mask(&pipeline->crtc); + + ret = drm_connector_attach_encoder(&pipeline->conn, &pipeline->encoder); + if (ret) + return ret; + + return 0; } int xen_drm_front_kms_init(struct xen_drm_front_drm_info *drm_info) -- 2.43.0