On Wed, 15 Nov 2023 at 15:30, Keith Zhao <keith.zhao@xxxxxxxxxxxxxxxx> wrote: > > > > On 2023/11/14 18:59, Dmitry Baryshkov wrote: > > On Tue, 14 Nov 2023 at 12:42, Keith Zhao <keith.zhao@xxxxxxxxxxxxxxxx> wrote: > >> > >> > >> > >> On 2023/10/26 3:28, Dmitry Baryshkov wrote: > >> > On 25/10/2023 13:39, Keith Zhao wrote: > >> >> add 2 crtcs and 8 planes in vs-drm > >> >> > >> >> Signed-off-by: Keith Zhao <keith.zhao@xxxxxxxxxxxxxxxx> > >> >> --- > >> >> drivers/gpu/drm/verisilicon/Makefile | 8 +- > >> >> drivers/gpu/drm/verisilicon/vs_crtc.c | 257 ++++ > >> >> drivers/gpu/drm/verisilicon/vs_crtc.h | 43 + > >> >> drivers/gpu/drm/verisilicon/vs_dc.c | 1002 ++++++++++++ > >> >> drivers/gpu/drm/verisilicon/vs_dc.h | 80 + > >> >> drivers/gpu/drm/verisilicon/vs_dc_hw.c | 1959 ++++++++++++++++++++++++ > >> >> drivers/gpu/drm/verisilicon/vs_dc_hw.h | 492 ++++++ > >> >> drivers/gpu/drm/verisilicon/vs_drv.c | 2 + > >> >> drivers/gpu/drm/verisilicon/vs_plane.c | 526 +++++++ > >> >> drivers/gpu/drm/verisilicon/vs_plane.h | 58 + > >> >> drivers/gpu/drm/verisilicon/vs_type.h | 69 + > >> >> 11 files changed, 4494 insertions(+), 2 deletions(-) > >> >> create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.c > >> >> create mode 100644 drivers/gpu/drm/verisilicon/vs_crtc.h > >> >> create mode 100644 drivers/gpu/drm/verisilicon/vs_dc.c > >> >> create mode 100644 drivers/gpu/drm/verisilicon/vs_dc.h > >> >> create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.c > >> >> create mode 100644 drivers/gpu/drm/verisilicon/vs_dc_hw.h > >> >> create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c > >> >> create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h > >> >> create mode 100644 drivers/gpu/drm/verisilicon/vs_type.h > >> >> > >> >> diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile > >> >> index 7d3be305b..1d48016ca 100644 > >> >> --- a/drivers/gpu/drm/verisilicon/Makefile > >> >> +++ b/drivers/gpu/drm/verisilicon/Makefile > >> >> @@ -1,7 +1,11 @@ > >> >> # SPDX-License-Identifier: GPL-2.0 > >> >> > >> >> -vs_drm-objs := vs_drv.o \ > >> >> - vs_modeset.o > >> >> +vs_drm-objs := vs_dc_hw.o \ > >> >> + vs_dc.o \ > >> >> + vs_crtc.o \ > >> >> + vs_drv.o \ > >> >> + vs_modeset.o \ > >> >> + vs_plane.o > >> >> > >> >> obj-$(CONFIG_DRM_VERISILICON) += vs_drm.o > >> >> > >> >> diff --git a/drivers/gpu/drm/verisilicon/vs_crtc.c b/drivers/gpu/drm/verisilicon/vs_crtc.c > >> >> new file mode 100644 > >> >> index 000000000..8a658ea77 > >> >> --- /dev/null > >> >> +++ b/drivers/gpu/drm/verisilicon/vs_crtc.c > >> >> @@ -0,0 +1,257 @@ > >> >> +// SPDX-License-Identifier: GPL-2.0 > >> >> +/* > >> >> + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd. > >> >> + * > >> >> + */ > >> >> + > >> >> +#include <linux/clk.h> > >> >> +#include <linux/debugfs.h> > >> >> +#include <linux/media-bus-format.h> > >> >> + > >> >> +#include <drm/drm_atomic_helper.h> > >> >> +#include <drm/drm_atomic.h> > >> >> +#include <drm/drm_crtc.h> > >> >> +#include <drm/drm_gem_atomic_helper.h> > >> >> +#include <drm/drm_vblank.h> > >> >> +#include <drm/vs_drm.h> > >> >> + > >> >> +#include "vs_crtc.h" > >> >> +#include "vs_dc.h" > >> >> +#include "vs_drv.h" > >> >> + > >> >> +static void vs_crtc_reset(struct drm_crtc *crtc) > >> >> +{ > >> >> + struct vs_crtc_state *state; > >> >> + > >> >> + if (crtc->state) { > >> >> + __drm_atomic_helper_crtc_destroy_state(crtc->state); > >> >> + > >> >> + state = to_vs_crtc_state(crtc->state); > >> >> + kfree(state); > >> >> + crtc->state = NULL; > >> >> + } > >> > > >> > You can call your crtc_destroy_state function directly here. > >> > > >> >> + > >> >> + state = kzalloc(sizeof(*state), GFP_KERNEL); > >> >> + if (!state) > >> >> + return; > >> >> + > >> >> + __drm_atomic_helper_crtc_reset(crtc, &state->base); > >> >> +} > >> >> + > >> >> +static struct drm_crtc_state * > >> >> +vs_crtc_atomic_duplicate_state(struct drm_crtc *crtc) > >> >> +{ > >> >> + struct vs_crtc_state *ori_state; > >> > > >> > It might be a matter of taste, but it is usually old_state. > >> > > >> >> + struct vs_crtc_state *state; > >> >> + > >> >> + if (!crtc->state) > >> >> + return NULL; > >> >> + > >> >> + ori_state = to_vs_crtc_state(crtc->state); > >> >> + state = kzalloc(sizeof(*state), GFP_KERNEL); > >> >> + if (!state) > >> >> + return NULL; > >> >> + > >> >> + __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base); > >> >> + > >> >> + state->output_fmt = ori_state->output_fmt; > >> >> + state->encoder_type = ori_state->encoder_type; > >> >> + state->bpp = ori_state->bpp; > >> >> + state->underflow = ori_state->underflow; > >> > > >> > Can you use kmemdup instead? > >> > > >> >> + > >> >> + return &state->base; > >> >> +} > >> >> + > >> >> +static void vs_crtc_atomic_destroy_state(struct drm_crtc *crtc, > >> >> + struct drm_crtc_state *state) > >> >> +{ > >> >> + __drm_atomic_helper_crtc_destroy_state(state); > >> >> + kfree(to_vs_crtc_state(state)); > >> >> +} > >> >> + > >> >> +static int vs_crtc_enable_vblank(struct drm_crtc *crtc) > >> >> +{ > >> >> + struct vs_crtc *vs_crtc = to_vs_crtc(crtc); > >> >> + struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev); > >> >> + > >> >> + vs_dc_enable_vblank(dc, true); > >> >> + > >> >> + return 0; > >> >> +} > >> >> + > >> >> +static void vs_crtc_disable_vblank(struct drm_crtc *crtc) > >> >> +{ > >> >> + struct vs_crtc *vs_crtc = to_vs_crtc(crtc); > >> >> + struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev); > >> >> + > >> >> + vs_dc_enable_vblank(dc, false); > >> >> +} > >> >> + > >> >> +static const struct drm_crtc_funcs vs_crtc_funcs = { > >> >> + .set_config = drm_atomic_helper_set_config, > >> >> + .page_flip = drm_atomic_helper_page_flip, > >> > > >> > destroy is required, see drm_mode_config_cleanup() > >> > >> hi Dmitry: > >> if define destroy in drm_crtc_funcs, > >> it will make __drmm_crtc_init_with_planes unhappy > > > > Ack, I missed that you have been using drmm_crtc_init. BTW, I checked > > your code, you should be able to switch drm > > drmm_crtc_alloc_with_planes(). > > > yes > I done the replace and it can work well. > > >> > >> see: > >> __printf(6, 0) > >> static int __drmm_crtc_init_with_planes(struct drm_device *dev, > >> struct drm_crtc *crtc, > >> struct drm_plane *primary, > >> struct drm_plane *cursor, > >> const struct drm_crtc_funcs *funcs, > >> const char *name, > >> va_list args) > >> { > >> int ret; > >> > >> drm_WARN_ON(dev, funcs && funcs->destroy); > >> > >> ........ > >> } > >> > >> It should not need to be defined here, I think > >> > >> > > >> >> + .reset = vs_crtc_reset, > >> >> + .atomic_duplicate_state = vs_crtc_atomic_duplicate_state, > >> >> + .atomic_destroy_state = vs_crtc_atomic_destroy_state, > >> > > >> > please consider adding atomic_print_state to output driver-specific bits. > >> > > >> >> + .enable_vblank = vs_crtc_enable_vblank, > >> >> + .disable_vblank = vs_crtc_disable_vblank, > >> >> +}; > >> >> + > >> >> +static u8 cal_pixel_bits(u32 bus_format) > >> > > >> > This looks like a generic helper code, which can go to a common place. > I don't know if I understand correctly > Here I remove static > Add 2 lines in vs_drv.h > > /* vs_crtc.c */ > u8 cal_pixel_bits(u32 bus_format); > > to make it common I mean, move it to a generic location, like include/media/ > > >> > > >> >> +{ > >> >> + u8 bpp; > >> >> + > >> >> + switch (bus_format) { > >> >> + case MEDIA_BUS_FMT_RGB565_1X16: > >> >> + case MEDIA_BUS_FMT_UYVY8_1X16: > >> >> + bpp = 16; > >> >> + break; > >> >> + case MEDIA_BUS_FMT_RGB666_1X18: > >> >> + case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: > >> >> + bpp = 18; > >> >> + break; > >> >> + case MEDIA_BUS_FMT_UYVY10_1X20: > >> >> + bpp = 20; > >> >> + break; > >> >> + case MEDIA_BUS_FMT_BGR888_1X24: > >> >> + case MEDIA_BUS_FMT_UYYVYY8_0_5X24: > >> >> + case MEDIA_BUS_FMT_YUV8_1X24: > >> >> + bpp = 24; > >> >> + break; > >> >> + case MEDIA_BUS_FMT_RGB101010_1X30: > >> >> + case MEDIA_BUS_FMT_UYYVYY10_0_5X30: > >> >> + case MEDIA_BUS_FMT_YUV10_1X30: > >> >> + bpp = 30; > >> >> + break; > >> >> + default: > >> >> + bpp = 24; > >> >> + break; > >> >> + } > >> >> + > >> >> + return bpp; > >> >> +} > >> >> + [skipped] > >> >> +struct vs_crtc *vs_crtc_create(struct drm_device *drm_dev, > >> >> + struct vs_dc_info *info) > >> >> +{ > >> >> + struct vs_crtc *crtc; > >> >> + int ret; > >> >> + > >> >> + if (!info) > >> >> + return NULL; > >> >> + > >> >> + crtc = drmm_kzalloc(drm_dev, sizeof(*crtc), GFP_KERNEL); > >> >> + if (!crtc) > >> >> + return NULL; > >> >> + > >> >> + ret = drmm_crtc_init_with_planes(drm_dev, &crtc->base, > >> >> + NULL, NULL, &vs_crtc_funcs, > >> >> + info->name ? info->name : NULL); > >> > > >> > It might be better to add drmm_crtc_init() helper. > drmm_crtc_alloc_with_planes used: > ... > struct vs_crtc *crtc; > int ret; > > if (!info) > return NULL; > > crtc = drmm_crtc_alloc_with_planes(drm_dev, struct vs_crtc, base, > NULL, NULL, > &vs_crtc_funcs, info->name ? info->name : NULL); > ... Ack. > > >> > > >> >> + if (ret) > >> >> + return NULL; > >> >> + > >> >> + drm_crtc_helper_add(&crtc->base, &vs_crtc_helper_funcs); > >> >> + > >> >> + if (info->gamma_size) { > >> >> + ret = drm_mode_crtc_set_gamma_size(&crtc->base, > >> >> + info->gamma_size); > >> >> + if (ret) > >> >> + return NULL; > >> >> + > >> >> + drm_crtc_enable_color_mgmt(&crtc->base, 0, false, > >> >> + info->gamma_size); > >> >> + } > >> >> + > >> >> + crtc->max_bpc = info->max_bpc; > >> >> + crtc->color_formats = info->color_formats; > >> >> + return crtc; > >> >> +} > >> >> +const struct component_ops dc_component_ops = { > >> >> + .bind = dc_bind, > >> >> + .unbind = dc_unbind, > >> >> +}; > >> >> + > >> >> +static const struct of_device_id dc_driver_dt_match[] = { > >> >> + { .compatible = "starfive,jh7110-dc8200", }, > >> >> + {}, > >> >> +}; > >> >> +MODULE_DEVICE_TABLE(of, dc_driver_dt_match); > >> >> + > >> >> +static int dc_probe(struct platform_device *pdev) > >> >> +{ > >> >> + struct device *dev = &pdev->dev; > >> >> + struct vs_dc *dc; > >> >> + int irq, ret, i; > >> >> + > >> >> + dc = devm_kzalloc(dev, sizeof(*dc), GFP_KERNEL); > >> >> + if (!dc) > >> >> + return -ENOMEM; > >> >> + > >> >> + dc->hw.hi_base = devm_platform_ioremap_resource(pdev, 0); > >> >> + if (IS_ERR(dc->hw.hi_base)) > >> >> + return PTR_ERR(dc->hw.hi_base); > >> >> + > >> >> + dc->hw.reg_base = devm_platform_ioremap_resource(pdev, 1); > >> >> + if (IS_ERR(dc->hw.reg_base)) > >> >> + return PTR_ERR(dc->hw.reg_base); > >> >> + > >> >> + dc->nclks = ARRAY_SIZE(dc->clk_vout); > >> >> + for (i = 0; i < dc->nclks; ++i) > >> >> + dc->clk_vout[i].id = vout_clocks[i]; > >> >> + ret = devm_clk_bulk_get(dev, dc->nclks, dc->clk_vout); > >> >> + if (ret) { > >> >> + dev_err(dev, "Failed to get clk controls\n"); > >> >> + return ret; > >> >> + } > >> >> + > >> >> + dc->nrsts = ARRAY_SIZE(dc->rst_vout); > >> >> + for (i = 0; i < dc->nrsts; ++i) > >> >> + dc->rst_vout[i].id = vout_resets[i]; > >> >> + ret = devm_reset_control_bulk_get_shared(dev, dc->nrsts, > >> >> + dc->rst_vout); > >> >> + if (ret) { > >> >> + dev_err(dev, "Failed to get reset controls\n"); > >> >> + return ret; > >> >> + } > >> >> + > >> >> + irq = platform_get_irq(pdev, 0); > >> >> + > >> >> + ret = devm_request_irq(dev, irq, dc_isr, 0, dev_name(dev), dc); > >> > > >> > Are you ready to handle the IRQ at this point? > Do you have some good suggestions? > Are there any hidden dangers in doing so? If your driver is not ready, stray interrupt can crash your driver. For pm_runtime-enabled devices it is even more important: the interrupt handled might try accessing device which is powered off. > Hope to get good opinions The usual suggestion is: request the interrupt when your data is fully set up. Or request_irq with IRQF_NO_AUTOEN and then enable_irq() / disable_irq() as required. > > >> > > >> >> + if (ret < 0) { > >> >> + dev_err(dev, "Failed to install irq:%u.\n", irq); > >> >> + return ret; > >> >> + } > >> >> + > >> >> + dev_set_drvdata(dev, dc); > >> >> + > >> >> + return component_add(dev, &dc_component_ops); > >> >> +} > >> >> + [skipped] > >> >> +static int vs_plane_atomic_get_property(struct drm_plane *plane, > >> >> + const struct drm_plane_state *state, > >> >> + struct drm_property *property, > >> >> + uint64_t *val) > >> >> +{ > >> >> + struct vs_plane *vs_plane = to_vs_plane(plane); > >> >> + const struct vs_plane_state *vs_plane_state = > >> >> + container_of(state, const struct vs_plane_state, base); > >> >> + > >> >> + if (property == vs_plane->degamma_mode) > >> >> + *val = vs_plane_state->degamma; > >> >> + else if (property == vs_plane->watermark_prop) > >> >> + *val = (vs_plane_state->watermark) ? > >> >> + vs_plane_state->watermark->base.id : 0; > >> >> + else if (property == vs_plane->color_mgmt_prop) > >> >> + *val = (vs_plane_state->color_mgmt) ? > >> >> + vs_plane_state->color_mgmt->base.id : 0; > >> > > >> > degamma and color management should use standard properties. > > hello Dmitry: > There is a question that troubles me > > drm_plane include such standard properties. > { > struct drm_property *alpha_property; > struct drm_property *zpos_property; > struct drm_property *rotation_property; > struct drm_property *blend_mode_property; > struct drm_property *color_encoding_property; > struct drm_property *color_range_property; > struct drm_property *scaling_filter_property; > } > > it doesn't include degamma and color management properties Which is because they are not standardised yet. > > >> > > >> >> + else if (property == vs_plane->roi_prop) > >> >> + *val = (vs_plane_state->roi) ? > >> >> + vs_plane_state->roi->base.id : 0; > >> >> + else > >> >> + return -EINVAL; > >> >> + > >> >> + return 0; > >> >> +} > >> >> + > >> >> +static bool vs_format_mod_supported(struct drm_plane *plane, > >> >> + u32 format, > >> >> + u64 modifier) > >> >> +{ > >> >> + int i; > >> >> + > >> >> + /* We always have to allow these modifiers: > >> >> + * 1. Core DRM checks for LINEAR support if userspace does not provide modifiers. > >> >> + * 2. Not passing any modifiers is the same as explicitly passing INVALID. > >> >> + */ > >> >> + if (modifier == DRM_FORMAT_MOD_LINEAR) > >> >> + return true; > >> >> + > >> >> + /* Check that the modifier is on the list of the plane's supported modifiers. */ > >> >> + for (i = 0; i < plane->modifier_count; i++) { > >> >> + if (modifier == plane->modifiers[i]) > >> >> + break; > >> >> + } > >> >> + > >> >> + if (i == plane->modifier_count) > >> >> + return false; > >> >> + > >> >> + return true; > >> >> +} > >> >> + > >> >> +const struct drm_plane_funcs vs_plane_funcs = { > >> >> + .update_plane = drm_atomic_helper_update_plane, > >> >> + .disable_plane = drm_atomic_helper_disable_plane, > >> >> + .reset = vs_plane_reset, > >> >> + .atomic_duplicate_state = vs_plane_atomic_duplicate_state, > >> >> + .atomic_destroy_state = vs_plane_atomic_destroy_state, > >> >> + .atomic_set_property = vs_plane_atomic_set_property, > >> >> + .atomic_get_property = vs_plane_atomic_get_property, > >> >> + .format_mod_supported = vs_format_mod_supported, > >> >> +}; > >> >> + > >> >> +static unsigned char vs_get_plane_number(struct drm_framebuffer *fb) > >> >> +{ > >> >> + const struct drm_format_info *info; > >> >> + > >> >> + if (!fb) > >> >> + return 0; > >> >> + > >> >> + info = drm_format_info(fb->format->format); > >> >> + if (!info || info->num_planes > DRM_FORMAT_MAX_PLANES) > >> >> + return 0; > >> >> + > >> >> + return info->num_planes; > >> >> +} > >> >> + > >> >> +static int vs_plane_atomic_check(struct drm_plane *plane, > >> >> + struct drm_atomic_state *state) > >> >> +{ > >> >> + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, > >> >> + plane); > >> >> + unsigned char i, num_planes; > >> >> + struct drm_framebuffer *fb = new_plane_state->fb; > >> >> + struct drm_crtc *crtc = new_plane_state->crtc; > >> >> + struct vs_crtc *vs_crtc = to_vs_crtc(crtc); > >> >> + struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev); > >> >> + struct vs_plane_state *plane_state = to_vs_plane_state(new_plane_state); > >> >> + > >> >> + if (!crtc || !fb) > >> >> + return 0; > >> >> + > >> >> + num_planes = vs_get_plane_number(fb); > >> >> + > >> >> + for (i = 0; i < num_planes; i++) { > >> >> + dma_addr_t dma_addr; > >> >> + > >> >> + dma_addr = drm_fb_dma_get_gem_addr(fb, new_plane_state, i); > >> >> + plane_state->dma_addr[i] = dma_addr; > >> >> + } > >> >> + > >> >> + return vs_dc_check_plane(dc, plane, state); > >> >> +} > >> >> + > >> >> +static int vs_cursor_plane_atomic_check(struct drm_plane *plane, > >> >> + struct drm_atomic_state *state) > >> >> +{ > >> >> + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, > >> >> + plane); > >> >> + unsigned char i, num_planes; > >> >> + struct drm_framebuffer *fb = new_plane_state->fb; > >> >> + struct drm_crtc *crtc = new_plane_state->crtc; > >> >> + struct vs_crtc *vs_crtc = to_vs_crtc(crtc); > >> >> + struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev); > >> >> + struct vs_plane_state *plane_state = to_vs_plane_state(new_plane_state); > >> >> + > >> >> + if (!crtc || !fb) > >> >> + return 0; > >> >> + > >> >> + num_planes = vs_get_plane_number(fb); > >> >> + > >> >> + for (i = 0; i < num_planes; i++) { > >> >> + dma_addr_t dma_addr; > >> >> + > >> >> + dma_addr = drm_fb_dma_get_gem_addr(fb, new_plane_state, i); > >> >> + plane_state->dma_addr[i] = dma_addr; > >> >> + } > >> >> + > >> >> + return vs_dc_check_cursor_plane(dc, plane, state); > >> >> +} > >> >> + > >> >> +static void vs_plane_atomic_update(struct drm_plane *plane, > >> >> + struct drm_atomic_state *state) > >> >> +{ > >> >> + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, > >> >> + plane); > >> > > >> > New line after the equal sign will be better. > >> > > >> >> + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, > >> >> + plane); > >> >> + > >> >> + unsigned char i, num_planes; > >> >> + struct drm_framebuffer *fb; > >> >> + struct vs_plane *vs_plane = to_vs_plane(plane); > >> >> + struct vs_crtc *vs_crtc = to_vs_crtc(new_state->crtc); > >> >> + struct vs_plane_state *plane_state = to_vs_plane_state(new_state); > >> >> + struct vs_dc *dc = dev_get_drvdata(vs_crtc->dev); > >> >> + > >> >> + if (!new_state->fb || !new_state->crtc) > >> >> + return; > >> > > >> > if (!new_state->visible) ? > > no matter what value it is ? the driver will handle it > in func > > static void update_fb(struct vs_plane *plane, u8 display_id, > struct dc_hw_fb *fb, struct drm_plane_state *state) > { > struct vs_plane_state *plane_state = to_vs_plane_state(state); > struct drm_framebuffer *drm_fb = state->fb; > struct drm_rect *src = &state->src; > > ....... > fb->enable = state->visible; > ....... > } > > so no need add "if (!new_state->visible)" i think I mean instead of fb&&crtc check. Otherwise you are duplicating checks in drm_atomic_helper_check_plane_state(). And with the pixel_source being on their way this condition becomes legacy. > > >> > > >> >> + > >> >> + fb = new_state->fb; > >> >> + > >> >> + drm_fb_dma_sync_non_coherent(fb->dev, old_state, new_state); > >> >> + > >> >> + num_planes = vs_get_plane_number(fb); > >> >> + > >> >> + for (i = 0; i < num_planes; i++) { > >> >> + dma_addr_t dma_addr; > >> >> + > >> >> + dma_addr = drm_fb_dma_get_gem_addr(fb, new_state, i); > >> >> + plane_state->dma_addr[i] = dma_addr; > >> >> + } > >> >> + > >> >> + plane_state->status.src = drm_plane_state_src(new_state); > >> >> + plane_state->status.dest = drm_plane_state_dest(new_state); > >> >> + > >> >> + vs_dc_update_plane(dc, vs_plane, plane, state); > >> >> +} > >> >> + -- With best wishes Dmitry