Message ID | 20240521105817.3301-7-keith.zhao@starfivetech.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | drm/verisilicon : support DC8200 and inno hdmi | expand |
Hi keith, kernel test robot noticed the following build warnings: [auto build test WARNING on drm-misc/drm-misc-next] [also build test WARNING on linus/master next-20240521] [cannot apply to robh/for-next rockchip/for-next v6.9] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/keith/dt-bindings-display-Add-YAML-schema-for-JH7110-display-pipeline/20240521-110316 base: git://anongit.freedesktop.org/drm/drm-misc drm-misc-next patch link: https://lore.kernel.org/r/20240521105817.3301-7-keith.zhao%40starfivetech.com patch subject: [PATCH v4 06/10] drm/vs: add vs plane api config: m68k-randconfig-r133-20240522 (https://download.01.org/0day-ci/archive/20240522/202405220419.2XNzWyBP-lkp@intel.com/config) compiler: m68k-linux-gcc (GCC) 13.2.0 reproduce: (https://download.01.org/0day-ci/archive/20240522/202405220419.2XNzWyBP-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202405220419.2XNzWyBP-lkp@intel.com/ sparse warnings: (new ones prefixed by >>) >> drivers/gpu/drm/verisilicon/vs_plane.c:83:30: sparse: sparse: symbol 'vs_plane_funcs' was not declared. Should it be static? >> drivers/gpu/drm/verisilicon/vs_plane.c:339:37: sparse: sparse: symbol 'primary_plane_helpers' was not declared. Should it be static? >> drivers/gpu/drm/verisilicon/vs_plane.c:345:37: sparse: sparse: symbol 'overlay_plane_helpers' was not declared. Should it be static? >> drivers/gpu/drm/verisilicon/vs_plane.c:351:37: sparse: sparse: symbol 'cursor_plane_helpers' was not declared. Should it be static? vim +/vs_plane_funcs +83 drivers/gpu/drm/verisilicon/vs_plane.c 82 > 83 const struct drm_plane_funcs vs_plane_funcs = { 84 .update_plane = drm_atomic_helper_update_plane, 85 .disable_plane = drm_atomic_helper_disable_plane, 86 .reset = vs_plane_reset, 87 .atomic_duplicate_state = vs_plane_atomic_duplicate_state, 88 .atomic_destroy_state = vs_plane_atomic_destroy_state, 89 .format_mod_supported = vs_format_mod_supported, 90 }; 91
On Tue, May 21, 2024 at 06:58:13PM +0800, keith wrote: > add plane funs and helper funs > add vs drm common struct and funs > > Signed-off-by: keith <keith.zhao@starfivetech.com> > --- > drivers/gpu/drm/verisilicon/Makefile | 3 +- > drivers/gpu/drm/verisilicon/vs_drv.h | 93 +++++ > drivers/gpu/drm/verisilicon/vs_plane.c | 487 +++++++++++++++++++++++++ > drivers/gpu/drm/verisilicon/vs_plane.h | 26 ++ > 4 files changed, 608 insertions(+), 1 deletion(-) > create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.h > create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c > create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h > > diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile > index 536091f37378..1c593b943261 100644 > --- a/drivers/gpu/drm/verisilicon/Makefile > +++ b/drivers/gpu/drm/verisilicon/Makefile > @@ -1,6 +1,7 @@ > # SPDX-License-Identifier: GPL-2.0 > > vs_drm-objs := vs_dc_hw.o \ > - vs_modeset.o > + vs_modeset.o \ > + vs_plane.o > > obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o > diff --git a/drivers/gpu/drm/verisilicon/vs_drv.h b/drivers/gpu/drm/verisilicon/vs_drv.h > new file mode 100644 > index 000000000000..d9f6efa7c8f9 > --- /dev/null > +++ b/drivers/gpu/drm/verisilicon/vs_drv.h > @@ -0,0 +1,93 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd. > + */ > + > +#ifndef __VS_DRV_H__ > +#define __VS_DRV_H__ > + > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/clk.h> > +#include <linux/reset.h> > + > +#include <drm/drm_drv.h> > +#include <drm/drm_fourcc.h> > +#include <drm/drm_gem.h> > +#include <drm/drm_managed.h> > + > +#include "vs_dc_hw.h" > + > +/*@pitch_alignment: buffer pitch alignment required by sub-devices.*/ Is that all the docs you want to add? > +struct vs_drm_device { > + struct drm_device base; > + unsigned int pitch_alignment; > + /* clocks */ > + unsigned int clk_count; > + struct clk_bulk_data *clks; > + struct reset_control *rsts; > + struct vs_dc dc; > + int irq; As usual, please drop unused fields and add them when required. > +}; > + > +static inline struct vs_drm_device * > +to_vs_drm_private(const struct drm_device *dev) > +{ > + return container_of(dev, struct vs_drm_device, base); > +} > + > +struct vs_crtc_state { > + struct drm_crtc_state base; > + > + u32 output_fmt; > + u8 encoder_type; > + u8 bpp; > +}; Not used here, drop. > + > +struct vs_crtc { > + struct drm_crtc base; > + struct device *dev; > +}; > + > +static inline u8 to_vs_display_id(struct vs_dc *dc, struct drm_crtc *crtc) > +{ > + u8 panel_num = dc->hw.info->panel_num; > + u32 index = drm_crtc_index(crtc); > + int i; > + > + for (i = 0; i < panel_num; i++) { > + if (index == dc->crtc[i]->base.index) > + return i; > + } > + > + return 0; > +} > + > +static inline struct vs_crtc_state * > +to_vs_crtc_state(struct drm_crtc_state *state) > +{ > + return container_of(state, struct vs_crtc_state, base); > +} > + > +struct vs_plane_state { > + struct drm_plane_state base; > + dma_addr_t dma_addr[DRM_FORMAT_MAX_PLANES]; > +}; > + > +struct vs_plane { > + struct drm_plane base; > + u8 id; > +}; > + > +static inline struct vs_plane *to_vs_plane(struct drm_plane *plane) > +{ > + return container_of(plane, struct vs_plane, base); > +} > + > +static inline struct vs_plane_state * > +to_vs_plane_state(struct drm_plane_state *state) > +{ > + return container_of(state, struct vs_plane_state, base); > +} > + > +#endif /* __VS_DRV_H__ */ > diff --git a/drivers/gpu/drm/verisilicon/vs_plane.c b/drivers/gpu/drm/verisilicon/vs_plane.c > new file mode 100644 > index 000000000000..653f0ce72ed6 > --- /dev/null > +++ b/drivers/gpu/drm/verisilicon/vs_plane.c > @@ -0,0 +1,487 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd. > + */ > +#include <drm/drm_atomic.h> > +#include <drm/drm_atomic_helper.h> > +#include <drm/drm_blend.h> > +#include <drm/drm_gem_dma_helper.h> > +#include <drm/drm_fb_dma_helper.h> > +#include <drm/drm_framebuffer.h> > +#include <drm/drm_plane.h> > +#include <drm/drm_plane_helper.h> > + > +#include "vs_plane.h" > + > +static void vs_plane_atomic_destroy_state(struct drm_plane *plane, > + struct drm_plane_state *state) > +{ > + struct vs_plane_state *vs_plane_state = to_vs_plane_state(state); > + > + __drm_atomic_helper_plane_destroy_state(state); > + kfree(vs_plane_state); > +} > + > +static void vs_plane_reset(struct drm_plane *plane) > +{ > + struct vs_plane_state *state; > + struct vs_plane *vs_plane = to_vs_plane(plane); > + > + if (plane->state) > + vs_plane_atomic_destroy_state(plane, plane->state); > + > + state = kzalloc(sizeof(*state), GFP_KERNEL); > + if (!state) > + return; > + > + state->base.zpos = vs_plane->id; > + __drm_atomic_helper_plane_reset(plane, &state->base); > +} > + > +static struct drm_plane_state * > +vs_plane_atomic_duplicate_state(struct drm_plane *plane) > +{ > + struct vs_plane_state *state; > + > + if (WARN_ON(!plane->state)) > + return NULL; > + > + state = kzalloc(sizeof(*state), GFP_KERNEL); > + if (!state) > + return NULL; > + > + __drm_atomic_helper_plane_duplicate_state(plane, &state->base); > + > + return &state->base; > +} > + > +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, > + .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 bool vs_dc_mod_supported(const u64 *info_modifiers, u64 modifier) > +{ > + const u64 *mods; > + > + if (!info_modifiers) > + return false; > + > + for (mods = info_modifiers; *mods != DRM_FORMAT_MOD_INVALID; mods++) { > + if (*mods == modifier) > + return true; > + } > + > + return false; > +} > + > +static int vs_primary_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) > +{ > + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); > + struct vs_dc *dc = &priv->dc; > + struct drm_framebuffer *fb = new_state->fb; > + const struct vs_plane_primary_info *primary_info; > + struct drm_crtc_state *crtc_state; > + int i; > + > + if (!new_state->crtc || !new_state->fb) > + return 0; > + for (i = 0; i < dc->hw.info->primary_num; i++) { > + primary_info = (struct vs_plane_primary_info *)&dc->hw.info->primary[i]; > + if (primary_info->id == to_vs_plane(plane)->id) > + break; > + } > + > + primary_info = &dc->hw.info->primary[i]; > + > + if (fb->width < primary_info->min_width || > + fb->width > primary_info->max_width || > + fb->height < primary_info->min_height || > + fb->height > primary_info->max_height) > + drm_err_once(plane->dev, "buffer size may not support on plane%d.\n", > + to_vs_plane(plane)->id); > + > + if (!vs_dc_mod_supported(primary_info->modifiers, fb->modifier)) { > + drm_err(plane->dev, "unsupported modifier on plane%d.\n", to_vs_plane(plane)->id); > + return -EINVAL; > + } > + > + crtc_state = drm_atomic_get_existing_crtc_state(new_state->state, new_state->crtc); > + return drm_atomic_helper_check_plane_state(new_state, crtc_state, > + primary_info->min_scale, > + primary_info->max_scale, > + true, true); > +} > + > +static int vs_overlay_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) > +{ > + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); > + struct vs_dc *dc = &priv->dc; > + struct drm_framebuffer *fb = new_state->fb; > + const struct vs_plane_overlay_info *overlay_info; > + struct drm_crtc_state *crtc_state; > + int i; > + > + if (!new_state->crtc || !new_state->fb) > + return 0; > + > + for (i = 0; i < dc->hw.info->overlay_num; i++) { > + overlay_info = (struct vs_plane_overlay_info *)&dc->hw.info->overlay[i]; > + if (overlay_info->id == to_vs_plane(plane)->id) > + break; > + } > + > + overlay_info = &dc->hw.info->overlay[i]; > + > + if (fb->width < overlay_info->min_width || > + fb->width > overlay_info->max_width || > + fb->height < overlay_info->min_height || > + fb->height > overlay_info->max_height) > + drm_err_once(plane->dev, "buffer size may not support on plane%d.\n", > + to_vs_plane(plane)->id); > + > + if (!vs_dc_mod_supported(overlay_info->modifiers, fb->modifier)) { > + drm_err(plane->dev, "unsupported modifier on plane%d.\n", to_vs_plane(plane)->id); > + return -EINVAL; > +} > + > + crtc_state = drm_atomic_get_existing_crtc_state(new_state->state, new_state->crtc); > + return drm_atomic_helper_check_plane_state(new_state, crtc_state, > + overlay_info->min_scale, > + overlay_info->max_scale, > + true, true); > +} > + > +static int vs_cursor_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) > +{ > + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); > + struct vs_dc *dc = &priv->dc; > + struct drm_framebuffer *fb = new_state->fb; > + const struct vs_plane_cursor_info *cursor_info; > + struct drm_crtc_state *crtc_state; > + int i; > + > + if (!new_state->crtc || !new_state->fb) > + return 0; > + > + for (i = 0; i < dc->hw.info->cursor_num; i++) { > + cursor_info = (struct vs_plane_cursor_info *)&dc->hw.info->cursor[i]; > + if (cursor_info->id == to_vs_plane(plane)->id) > + break; > + } > + > + cursor_info = &dc->hw.info->cursor[i]; > + > + if (fb->width < cursor_info->min_width || > + fb->width > cursor_info->max_width || > + fb->height < cursor_info->min_height || > + fb->height > cursor_info->max_height) > + drm_err_once(plane->dev, "buffer size may not support on plane%d.\n", > + to_vs_plane(plane)->id); > + > + crtc_state = drm_atomic_get_existing_crtc_state(new_state->state, new_state->crtc); > + return drm_atomic_helper_check_plane_state(new_state, crtc_state, > + DRM_PLANE_NO_SCALING, > + DRM_PLANE_NO_SCALING, > + true, true); Looking at these three functions: - Define a common struct for plane info; - Define a single function handling common case; - Extend it as necessary for primary / overlay cases (or just skip the corresponding check for cursor plane type). > +} > + > +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); > + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); > + > + unsigned char i, num_planes, display_id, id; > + u32 format; > + bool is_yuv; > + struct vs_plane *vs_plane = to_vs_plane(plane); > + struct vs_plane_state *plane_state = to_vs_plane_state(new_state); > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); > + struct vs_dc *dc = &priv->dc; > + > + if (!new_state->fb || !new_state->crtc) > + return; > + > + drm_fb_dma_sync_non_coherent(plane->dev, old_state, new_state); > + > + num_planes = vs_get_plane_number(new_state->fb); > + > + for (i = 0; i < num_planes; i++) { > + dma_addr_t dma_addr; > + > + dma_addr = drm_fb_dma_get_gem_addr(new_state->fb, new_state, i); > + plane_state->dma_addr[i] = dma_addr; > + } > + > + display_id = to_vs_display_id(dc, new_state->crtc); > + format = new_state->fb->format->format; > + is_yuv = new_state->fb->format->is_yuv; > + id = vs_plane->id; > + > + plane_hw_update_format_colorspace(dc, format, new_state->color_encoding, id, is_yuv); > + if (new_state->visible) > + plane_hw_update_address(dc, id, format, plane_state->dma_addr, > + new_state->fb, &new_state->src); > + plane_hw_update_format(dc, format, new_state->color_encoding, new_state->rotation, > + new_state->visible, new_state->zpos, id, display_id); > + plane_hw_update_scale(dc, &new_state->src, &new_state->dst, id, > + display_id, new_state->rotation); > + plane_hw_update_blend(dc, new_state->alpha, new_state->pixel_blend_mode, > + id, display_id); > +} > + > +static void vs_cursor_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); > + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, > + plane); > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); > + struct vs_dc *dc = &priv->dc; > + unsigned char display_id; > + u32 crtc_w, crtc_x, crtc_y; > + s32 hotspot_x, hotspot_y; > + dma_addr_t dma_addr; > + > + display_id = to_vs_display_id(dc, new_state->crtc); > + > + if (!new_state->fb || !new_state->crtc) > + return; > + > + drm_fb_dma_sync_non_coherent(new_state->fb->dev, old_state, new_state); > + dma_addr = drm_fb_dma_get_gem_addr(new_state->fb, new_state, 0); > + crtc_w = new_state->crtc_w; > + > + if (new_state->crtc_x > 0) { > + crtc_x = new_state->crtc_x; > + hotspot_x = 0; > + } else { > + hotspot_x = -new_state->crtc_x; > + crtc_x = 0; > + } > + if (new_state->crtc_y > 0) { > + crtc_y = new_state->crtc_y; > + hotspot_y = 0; > + } else { > + hotspot_y = -new_state->crtc_y; > + crtc_y = 0; > + } > + dc_hw_update_cursor(&dc->hw, display_id, dma_addr, crtc_w, crtc_x, > + crtc_y, hotspot_x, hotspot_y); > +} > + > +static void vs_plane_atomic_disable(struct drm_plane *plane, struct drm_atomic_state *state) > +{ > + struct vs_plane *vs_plane = to_vs_plane(plane); > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); > + struct vs_dc *dc = &priv->dc; > + > + dc_hw_disable_plane(dc, vs_plane->id); > +} > + > +static void vs_cursor_plane_atomic_disable(struct drm_plane *plane, struct drm_atomic_state *state) > +{ > + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); > + struct vs_dc *dc = &priv->dc; > + unsigned char display_id; > + > + display_id = to_vs_display_id(dc, old_state->crtc); > + dc_hw_disable_cursor(&dc->hw, display_id); > +} > + > +const struct drm_plane_helper_funcs primary_plane_helpers = { > + .atomic_check = vs_primary_plane_atomic_check, > + .atomic_update = vs_plane_atomic_update, > + .atomic_disable = vs_plane_atomic_disable, > +}; > + > +const struct drm_plane_helper_funcs overlay_plane_helpers = { > + .atomic_check = vs_overlay_plane_atomic_check, > + .atomic_update = vs_plane_atomic_update, > + .atomic_disable = vs_plane_atomic_disable, > +}; > + > +const struct drm_plane_helper_funcs cursor_plane_helpers = { > + .atomic_check = vs_cursor_plane_atomic_check, > + .atomic_update = vs_cursor_plane_atomic_update, > + .atomic_disable = vs_cursor_plane_atomic_disable, > +}; > + > +struct vs_plane *vs_plane_primary_create(struct drm_device *drm_dev, > + struct vs_plane_primary_info *info, > + unsigned int layer_num, > + unsigned int possible_crtcs) > +{ > + struct vs_plane *plane; > + int ret; > + > + if (!info) > + return NULL; > + > + plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base, > + possible_crtcs, > + &vs_plane_funcs, > + info->formats, info->num_formats, > + info->modifiers, DRM_PLANE_TYPE_PRIMARY, > + NULL); > + if (IS_ERR(plane)) > + return ERR_CAST(plane); > + > + drm_plane_helper_add(&plane->base, &primary_plane_helpers); > + > + drm_plane_create_alpha_property(&plane->base); > + drm_plane_create_blend_mode_property(&plane->base, > + BIT(DRM_MODE_BLEND_PIXEL_NONE) | > + BIT(DRM_MODE_BLEND_PREMULTI) | > + BIT(DRM_MODE_BLEND_COVERAGE)); > + > + if (info->color_encoding) { > + ret = drm_plane_create_color_properties(&plane->base, info->color_encoding, > + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), > + DRM_COLOR_YCBCR_BT709, > + DRM_COLOR_YCBCR_LIMITED_RANGE); > + if (ret) > + return NULL; > + } > + > + if (info->rotation) { > + ret = drm_plane_create_rotation_property(&plane->base, > + DRM_MODE_ROTATE_0, > + info->rotation); > + if (ret) > + return NULL; > + } > + > + ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0, layer_num - 1); > + if (ret) > + return NULL; > + > + return plane; > +} > + > +struct vs_plane *vs_plane_overlay_create(struct drm_device *drm_dev, > + struct vs_plane_overlay_info *info, > + unsigned int layer_num, > + unsigned int possible_crtcs) This looks almost like a previous function. Consider merging them. > +{ > + struct vs_plane *plane; > + int ret; > + > + if (!info) > + return NULL; > + > + plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base, > + possible_crtcs, > + &vs_plane_funcs, > + info->formats, info->num_formats, > + info->modifiers, DRM_PLANE_TYPE_OVERLAY, > + NULL); > + if (IS_ERR(plane)) > + return ERR_CAST(plane); > + > + drm_plane_helper_add(&plane->base, &overlay_plane_helpers); > + > + drm_plane_create_alpha_property(&plane->base); > + drm_plane_create_blend_mode_property(&plane->base, > + BIT(DRM_MODE_BLEND_PIXEL_NONE) | > + BIT(DRM_MODE_BLEND_PREMULTI) | > + BIT(DRM_MODE_BLEND_COVERAGE)); > + > + if (info->color_encoding) { > + ret = drm_plane_create_color_properties(&plane->base, info->color_encoding, > + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), > + DRM_COLOR_YCBCR_BT709, > + DRM_COLOR_YCBCR_LIMITED_RANGE); > + if (ret) > + return NULL; > + } > + > + if (info->rotation) { > + ret = drm_plane_create_rotation_property(&plane->base, > + DRM_MODE_ROTATE_0, > + info->rotation); > + if (ret) > + return NULL; > + } > + > + ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0, layer_num - 1); > + if (ret) > + return NULL; > + > + return plane; > +} > + > +struct vs_plane *vs_plane_cursor_create(struct drm_device *drm_dev, > + struct vs_plane_cursor_info *info, > + unsigned int possible_crtcs) > +{ > + struct vs_plane *plane; > + int ret; > + > + if (!info) > + return NULL; > + > + plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base, > + possible_crtcs, > + &vs_plane_funcs, > + info->formats, info->num_formats, > + NULL, DRM_PLANE_TYPE_CURSOR, > + NULL); > + if (IS_ERR(plane)) > + return ERR_CAST(plane); > + > + drm_plane_helper_add(&plane->base, &cursor_plane_helpers); > + > + ret = drm_plane_create_zpos_immutable_property(&plane->base, info->zpos); > + if (ret) > + return NULL; > + > + return plane; > +} > diff --git a/drivers/gpu/drm/verisilicon/vs_plane.h b/drivers/gpu/drm/verisilicon/vs_plane.h > new file mode 100644 > index 000000000000..0416146226a8 > --- /dev/null > +++ b/drivers/gpu/drm/verisilicon/vs_plane.h > @@ -0,0 +1,26 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd. > + */ > + > +#ifndef __VS_PLANE_H__ > +#define __VS_PLANE_H__ > + > +#include <drm/drm_plane_helper.h> > + > +#include "vs_drv.h" > + > +struct vs_plane *vs_plane_primary_create(struct drm_device *drm_dev, > + struct vs_plane_primary_info *info, > + unsigned int layer_num, > + unsigned int possible_crtcs); > + > +struct vs_plane *vs_plane_overlay_create(struct drm_device *drm_dev, > + struct vs_plane_overlay_info *info, > + unsigned int layer_num, > + unsigned int possible_crtcs); > + > +struct vs_plane *vs_plane_cursor_create(struct drm_device *drm_dev, > + struct vs_plane_cursor_info *info, > + unsigned int possible_crtcs); > +#endif /* __VS_PLANE_H__ */ > -- > 2.27.0 >
Hi Dmitry: > -----Original Message----- > From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> > Sent: 2024年5月22日 5:06 > To: Keith Zhao <keith.zhao@starfivetech.com> > Cc: andrzej.hajda@intel.com; neil.armstrong@linaro.org; rfoss@kernel.org; > Laurent.pinchart@ideasonboard.com; jonas@kwiboo.se; > jernej.skrabec@gmail.com; maarten.lankhorst@linux.intel.com; > mripard@kernel.org; tzimmermann@suse.de; airlied@gmail.com; > daniel@ffwll.ch; robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org; > hjc@rock-chips.com; heiko@sntech.de; andy.yan@rock-chips.com; Xingyu Wu > <xingyu.wu@starfivetech.com>; p.zabel@pengutronix.de; Jack Zhu > <jack.zhu@starfivetech.com>; Shengyang Chen > <shengyang.chen@starfivetech.com>; dri-devel@lists.freedesktop.org; > devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; > linux-arm-kernel@lists.infradead.org > Subject: Re: [PATCH v4 06/10] drm/vs: add vs plane api > > On Tue, May 21, 2024 at 06:58:13PM +0800, keith wrote: > > add plane funs and helper funs > > add vs drm common struct and funs > > > > Signed-off-by: keith <keith.zhao@starfivetech.com> > > --- > > drivers/gpu/drm/verisilicon/Makefile | 3 +- > > drivers/gpu/drm/verisilicon/vs_drv.h | 93 +++++ > > drivers/gpu/drm/verisilicon/vs_plane.c | 487 > > +++++++++++++++++++++++++ drivers/gpu/drm/verisilicon/vs_plane.h | > > 26 ++ > > 4 files changed, 608 insertions(+), 1 deletion(-) create mode 100644 > > drivers/gpu/drm/verisilicon/vs_drv.h > > create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c > > create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h > > > > diff --git a/drivers/gpu/drm/verisilicon/Makefile > > b/drivers/gpu/drm/verisilicon/Makefile > > index 536091f37378..1c593b943261 100644 > > --- a/drivers/gpu/drm/verisilicon/Makefile > > +++ b/drivers/gpu/drm/verisilicon/Makefile > > @@ -1,6 +1,7 @@ > > # SPDX-License-Identifier: GPL-2.0 > > > > vs_drm-objs := vs_dc_hw.o \ > > - vs_modeset.o > > + vs_modeset.o \ > > + vs_plane.o > > > > obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o diff --git > > a/drivers/gpu/drm/verisilicon/vs_drv.h > > b/drivers/gpu/drm/verisilicon/vs_drv.h > > new file mode 100644 > > index 000000000000..d9f6efa7c8f9 > > --- /dev/null > > +++ b/drivers/gpu/drm/verisilicon/vs_drv.h > > @@ -0,0 +1,93 @@ > > +/* SPDX-License-Identifier: GPL-2.0 */ > > +/* > > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd. > > + */ > > + > > +#ifndef __VS_DRV_H__ > > +#define __VS_DRV_H__ > > + > > +#include <linux/module.h> > > +#include <linux/platform_device.h> > > +#include <linux/clk.h> > > +#include <linux/reset.h> > > + > > +#include <drm/drm_drv.h> > > +#include <drm/drm_fourcc.h> > > +#include <drm/drm_gem.h> > > +#include <drm/drm_managed.h> > > + > > +#include "vs_dc_hw.h" > > + > > +/*@pitch_alignment: buffer pitch alignment required by sub-devices.*/ > > Is that all the docs you want to add? It should delete the redundant parts which is unused, To make this patch clearer to review > > > +struct vs_drm_device { > > + struct drm_device base; > > + unsigned int pitch_alignment; > > + /* clocks */ > > + unsigned int clk_count; > > + struct clk_bulk_data *clks; > > + struct reset_control *rsts; > > + struct vs_dc dc; > > + int irq; > > As usual, please drop unused fields and add them when required. In principle, I try to split the patch independently according to this. In fact, there is still a lot of room for optimization The subsequent patches will maintain independence and remove redundant parts for decoupling > > > +}; > > + > > +static inline struct vs_drm_device * > > +to_vs_drm_private(const struct drm_device *dev) { > > + return container_of(dev, struct vs_drm_device, base); } > > + > > +struct vs_crtc_state { > > + struct drm_crtc_state base; > > + > > + u32 output_fmt; > > + u8 encoder_type; > > + u8 bpp; > > +}; > > Not used here, drop. > > > + > > +struct vs_crtc { > > + struct drm_crtc base; > > + struct device *dev; > > +}; > > > > + > > +static inline u8 to_vs_display_id(struct vs_dc *dc, struct drm_crtc > > +*crtc) { > > + u8 panel_num = dc->hw.info->panel_num; > > + u32 index = drm_crtc_index(crtc); > > + int i; > > + > > + for (i = 0; i < panel_num; i++) { > > + if (index == dc->crtc[i]->base.index) > > + return i; > > + } > > + > > + return 0; > > +} > > + > > +static inline struct vs_crtc_state * > > +to_vs_crtc_state(struct drm_crtc_state *state) { > > + return container_of(state, struct vs_crtc_state, base); } > > + > > +struct vs_plane_state { > > + struct drm_plane_state base; > > + dma_addr_t dma_addr[DRM_FORMAT_MAX_PLANES]; }; > > + > > +struct vs_plane { > > + struct drm_plane base; > > + u8 id; > > +}; > > + > > +static inline struct vs_plane *to_vs_plane(struct drm_plane *plane) { > > + return container_of(plane, struct vs_plane, base); } > > + > > +static inline struct vs_plane_state * to_vs_plane_state(struct > > +drm_plane_state *state) { > > + return container_of(state, struct vs_plane_state, base); } > > + > > +#endif /* __VS_DRV_H__ */ > > diff --git a/drivers/gpu/drm/verisilicon/vs_plane.c > > b/drivers/gpu/drm/verisilicon/vs_plane.c > > new file mode 100644 > > index 000000000000..653f0ce72ed6 > > --- /dev/null > > +++ b/drivers/gpu/drm/verisilicon/vs_plane.c > > @@ -0,0 +1,487 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd. > > + */ > > +#include <drm/drm_atomic.h> > > +#include <drm/drm_atomic_helper.h> > > +#include <drm/drm_blend.h> > > +#include <drm/drm_gem_dma_helper.h> > > +#include <drm/drm_fb_dma_helper.h> > > +#include <drm/drm_framebuffer.h> > > +#include <drm/drm_plane.h> > > +#include <drm/drm_plane_helper.h> > > + > > +#include "vs_plane.h" > > + > > +static void vs_plane_atomic_destroy_state(struct drm_plane *plane, > > + struct drm_plane_state *state) { > > + struct vs_plane_state *vs_plane_state = to_vs_plane_state(state); > > + > > + __drm_atomic_helper_plane_destroy_state(state); > > + kfree(vs_plane_state); > > +} > > + > > +static void vs_plane_reset(struct drm_plane *plane) { > > + struct vs_plane_state *state; > > + struct vs_plane *vs_plane = to_vs_plane(plane); > > + > > + if (plane->state) > > + vs_plane_atomic_destroy_state(plane, plane->state); > > + > > + state = kzalloc(sizeof(*state), GFP_KERNEL); > > + if (!state) > > + return; > > + > > + state->base.zpos = vs_plane->id; > > + __drm_atomic_helper_plane_reset(plane, &state->base); } > > + > > +static struct drm_plane_state * > > +vs_plane_atomic_duplicate_state(struct drm_plane *plane) { > > + struct vs_plane_state *state; > > + > > + if (WARN_ON(!plane->state)) > > + return NULL; > > + > > + state = kzalloc(sizeof(*state), GFP_KERNEL); > > + if (!state) > > + return NULL; > > + > > + __drm_atomic_helper_plane_duplicate_state(plane, &state->base); > > + > > + return &state->base; > > +} > > + > > +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, > > + .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 bool vs_dc_mod_supported(const u64 *info_modifiers, u64 > > +modifier) { > > + const u64 *mods; > > + > > + if (!info_modifiers) > > + return false; > > + > > + for (mods = info_modifiers; *mods != DRM_FORMAT_MOD_INVALID; > mods++) { > > + if (*mods == modifier) > > + return true; > > + } > > + > > + return false; > > +} > > + > > +static int vs_primary_plane_atomic_check(struct drm_plane *plane, > > +struct drm_atomic_state *state) { > > + struct drm_plane_state *new_state = > drm_atomic_get_new_plane_state(state, plane); > > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); > > + struct vs_dc *dc = &priv->dc; > > + struct drm_framebuffer *fb = new_state->fb; > > + const struct vs_plane_primary_info *primary_info; > > + struct drm_crtc_state *crtc_state; > > + int i; > > + > > + if (!new_state->crtc || !new_state->fb) > > + return 0; > > + for (i = 0; i < dc->hw.info->primary_num; i++) { > > + primary_info = (struct vs_plane_primary_info > *)&dc->hw.info->primary[i]; > > + if (primary_info->id == to_vs_plane(plane)->id) > > + break; > > + } > > + > > + primary_info = &dc->hw.info->primary[i]; > > + > > + if (fb->width < primary_info->min_width || > > + fb->width > primary_info->max_width || > > + fb->height < primary_info->min_height || > > + fb->height > primary_info->max_height) > > + drm_err_once(plane->dev, "buffer size may not support on > plane%d.\n", > > + to_vs_plane(plane)->id); > > + > > + if (!vs_dc_mod_supported(primary_info->modifiers, fb->modifier)) { > > + drm_err(plane->dev, "unsupported modifier on plane%d.\n", > to_vs_plane(plane)->id); > > + return -EINVAL; > > + } > > + > > + crtc_state = drm_atomic_get_existing_crtc_state(new_state->state, > new_state->crtc); > > + return drm_atomic_helper_check_plane_state(new_state, crtc_state, > > + primary_info->min_scale, > > + primary_info->max_scale, > > + true, true); > > +} > > + > > +static int vs_overlay_plane_atomic_check(struct drm_plane *plane, > > +struct drm_atomic_state *state) { > > + struct drm_plane_state *new_state = > drm_atomic_get_new_plane_state(state, plane); > > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); > > + struct vs_dc *dc = &priv->dc; > > + struct drm_framebuffer *fb = new_state->fb; > > + const struct vs_plane_overlay_info *overlay_info; > > + struct drm_crtc_state *crtc_state; > > + int i; > > + > > + if (!new_state->crtc || !new_state->fb) > > + return 0; > > + > > + for (i = 0; i < dc->hw.info->overlay_num; i++) { > > + overlay_info = (struct vs_plane_overlay_info > *)&dc->hw.info->overlay[i]; > > + if (overlay_info->id == to_vs_plane(plane)->id) > > + break; > > + } > > + > > + overlay_info = &dc->hw.info->overlay[i]; > > + > > + if (fb->width < overlay_info->min_width || > > + fb->width > overlay_info->max_width || > > + fb->height < overlay_info->min_height || > > + fb->height > overlay_info->max_height) > > + drm_err_once(plane->dev, "buffer size may not support on > plane%d.\n", > > + to_vs_plane(plane)->id); > > + > > + if (!vs_dc_mod_supported(overlay_info->modifiers, fb->modifier)) { > > + drm_err(plane->dev, "unsupported modifier on plane%d.\n", > to_vs_plane(plane)->id); > > + return -EINVAL; > > +} > > + > > + crtc_state = drm_atomic_get_existing_crtc_state(new_state->state, > new_state->crtc); > > + return drm_atomic_helper_check_plane_state(new_state, crtc_state, > > + overlay_info->min_scale, > > + overlay_info->max_scale, > > + true, true); > > +} > > + > > +static int vs_cursor_plane_atomic_check(struct drm_plane *plane, > > +struct drm_atomic_state *state) { > > + struct drm_plane_state *new_state = > drm_atomic_get_new_plane_state(state, plane); > > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); > > + struct vs_dc *dc = &priv->dc; > > + struct drm_framebuffer *fb = new_state->fb; > > + const struct vs_plane_cursor_info *cursor_info; > > + struct drm_crtc_state *crtc_state; > > + int i; > > + > > + if (!new_state->crtc || !new_state->fb) > > + return 0; > > + > > + for (i = 0; i < dc->hw.info->cursor_num; i++) { > > + cursor_info = (struct vs_plane_cursor_info *)&dc->hw.info->cursor[i]; > > + if (cursor_info->id == to_vs_plane(plane)->id) > > + break; > > + } > > + > > + cursor_info = &dc->hw.info->cursor[i]; > > + > > + if (fb->width < cursor_info->min_width || > > + fb->width > cursor_info->max_width || > > + fb->height < cursor_info->min_height || > > + fb->height > cursor_info->max_height) > > + drm_err_once(plane->dev, "buffer size may not support on > plane%d.\n", > > + to_vs_plane(plane)->id); > > + > > + crtc_state = drm_atomic_get_existing_crtc_state(new_state->state, > new_state->crtc); > > + return drm_atomic_helper_check_plane_state(new_state, crtc_state, > > + DRM_PLANE_NO_SCALING, > > + DRM_PLANE_NO_SCALING, > > + true, true); > > Looking at these three functions: > - Define a common struct for plane info; ok > - Define a single function handling common case; Ok > - Extend it as necessary for primary / overlay cases (or just skip the > corresponding check for cursor plane type). This greatly reduces the duplication of code lines > > > +} > > + > > +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); > > + struct drm_plane_state *old_state = > > +drm_atomic_get_old_plane_state(state, plane); > > + > > + unsigned char i, num_planes, display_id, id; > > + u32 format; > > + bool is_yuv; > > + struct vs_plane *vs_plane = to_vs_plane(plane); > > + struct vs_plane_state *plane_state = to_vs_plane_state(new_state); > > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); > > + struct vs_dc *dc = &priv->dc; > > + > > + if (!new_state->fb || !new_state->crtc) > > + return; > > + > > + drm_fb_dma_sync_non_coherent(plane->dev, old_state, new_state); > > + > > + num_planes = vs_get_plane_number(new_state->fb); > > + > > + for (i = 0; i < num_planes; i++) { > > + dma_addr_t dma_addr; > > + > > + dma_addr = drm_fb_dma_get_gem_addr(new_state->fb, new_state, > i); > > + plane_state->dma_addr[i] = dma_addr; > > + } > > + > > + display_id = to_vs_display_id(dc, new_state->crtc); > > + format = new_state->fb->format->format; > > + is_yuv = new_state->fb->format->is_yuv; > > + id = vs_plane->id; > > + > > + plane_hw_update_format_colorspace(dc, format, > new_state->color_encoding, id, is_yuv); > > + if (new_state->visible) > > + plane_hw_update_address(dc, id, format, plane_state->dma_addr, > > + new_state->fb, &new_state->src); > > + plane_hw_update_format(dc, format, new_state->color_encoding, > new_state->rotation, > > + new_state->visible, new_state->zpos, id, display_id); > > + plane_hw_update_scale(dc, &new_state->src, &new_state->dst, id, > > + display_id, new_state->rotation); > > + plane_hw_update_blend(dc, new_state->alpha, > new_state->pixel_blend_mode, > > + id, display_id); > > +} > > + > > +static void vs_cursor_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); > > + struct drm_plane_state *old_state = > drm_atomic_get_old_plane_state(state, > > + plane); > > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); > > + struct vs_dc *dc = &priv->dc; > > + unsigned char display_id; > > + u32 crtc_w, crtc_x, crtc_y; > > + s32 hotspot_x, hotspot_y; > > + dma_addr_t dma_addr; > > + > > + display_id = to_vs_display_id(dc, new_state->crtc); > > + > > + if (!new_state->fb || !new_state->crtc) > > + return; > > + > > + drm_fb_dma_sync_non_coherent(new_state->fb->dev, old_state, > new_state); > > + dma_addr = drm_fb_dma_get_gem_addr(new_state->fb, new_state, 0); > > + crtc_w = new_state->crtc_w; > > + > > + if (new_state->crtc_x > 0) { > > + crtc_x = new_state->crtc_x; > > + hotspot_x = 0; > > + } else { > > + hotspot_x = -new_state->crtc_x; > > + crtc_x = 0; > > + } > > + if (new_state->crtc_y > 0) { > > + crtc_y = new_state->crtc_y; > > + hotspot_y = 0; > > + } else { > > + hotspot_y = -new_state->crtc_y; > > + crtc_y = 0; > > + } > > + dc_hw_update_cursor(&dc->hw, display_id, dma_addr, crtc_w, crtc_x, > > + crtc_y, hotspot_x, hotspot_y); } > > + > > +static void vs_plane_atomic_disable(struct drm_plane *plane, struct > > +drm_atomic_state *state) { > > + struct vs_plane *vs_plane = to_vs_plane(plane); > > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); > > + struct vs_dc *dc = &priv->dc; > > + > > + dc_hw_disable_plane(dc, vs_plane->id); } > > + > > +static void vs_cursor_plane_atomic_disable(struct drm_plane *plane, > > +struct drm_atomic_state *state) { > > + struct drm_plane_state *old_state = > drm_atomic_get_old_plane_state(state, plane); > > + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); > > + struct vs_dc *dc = &priv->dc; > > + unsigned char display_id; > > + > > + display_id = to_vs_display_id(dc, old_state->crtc); > > + dc_hw_disable_cursor(&dc->hw, display_id); } > > + > > +const struct drm_plane_helper_funcs primary_plane_helpers = { > > + .atomic_check = vs_primary_plane_atomic_check, > > + .atomic_update = vs_plane_atomic_update, > > + .atomic_disable = vs_plane_atomic_disable, }; > > + > > +const struct drm_plane_helper_funcs overlay_plane_helpers = { > > + .atomic_check = vs_overlay_plane_atomic_check, > > + .atomic_update = vs_plane_atomic_update, > > + .atomic_disable = vs_plane_atomic_disable, }; > > + > > +const struct drm_plane_helper_funcs cursor_plane_helpers = { > > + .atomic_check = vs_cursor_plane_atomic_check, > > + .atomic_update = vs_cursor_plane_atomic_update, > > + .atomic_disable = vs_cursor_plane_atomic_disable, }; > > + > > +struct vs_plane *vs_plane_primary_create(struct drm_device *drm_dev, > > + struct vs_plane_primary_info *info, > > + unsigned int layer_num, > > + unsigned int possible_crtcs) > > +{ > > + struct vs_plane *plane; > > + int ret; > > + > > + if (!info) > > + return NULL; > > + > > + plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base, > > + possible_crtcs, > > + &vs_plane_funcs, > > + info->formats, info->num_formats, > > + info->modifiers, DRM_PLANE_TYPE_PRIMARY, > > + NULL); > > + if (IS_ERR(plane)) > > + return ERR_CAST(plane); > > + > > + drm_plane_helper_add(&plane->base, &primary_plane_helpers); > > + > > + drm_plane_create_alpha_property(&plane->base); > > + drm_plane_create_blend_mode_property(&plane->base, > > + BIT(DRM_MODE_BLEND_PIXEL_NONE) | > > + BIT(DRM_MODE_BLEND_PREMULTI) | > > + BIT(DRM_MODE_BLEND_COVERAGE)); > > + > > + if (info->color_encoding) { > > + ret = drm_plane_create_color_properties(&plane->base, > info->color_encoding, > > + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), > > + DRM_COLOR_YCBCR_BT709, > > + DRM_COLOR_YCBCR_LIMITED_RANGE); > > + if (ret) > > + return NULL; > > + } > > + > > + if (info->rotation) { > > + ret = drm_plane_create_rotation_property(&plane->base, > > + DRM_MODE_ROTATE_0, > > + info->rotation); > > + if (ret) > > + return NULL; > > + } > > + > > + ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0, > layer_num - 1); > > + if (ret) > > + return NULL; > > + > > + return plane; > > +} > > + > > +struct vs_plane *vs_plane_overlay_create(struct drm_device *drm_dev, > > + struct vs_plane_overlay_info *info, > > + unsigned int layer_num, > > + unsigned int possible_crtcs) > > This looks almost like a previous function. Consider merging them. Ok ,got it > > > +{ > > + struct vs_plane *plane; > > + int ret; > > + > > + if (!info) > > + return NULL; > > + > > + plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base, > > + possible_crtcs, > > + &vs_plane_funcs, > > + info->formats, info->num_formats, > > + info->modifiers, DRM_PLANE_TYPE_OVERLAY, > > + NULL); > > + if (IS_ERR(plane)) > > + return ERR_CAST(plane); > > + > > + drm_plane_helper_add(&plane->base, &overlay_plane_helpers); > > + > > + drm_plane_create_alpha_property(&plane->base); > > + drm_plane_create_blend_mode_property(&plane->base, > > + BIT(DRM_MODE_BLEND_PIXEL_NONE) | > > + BIT(DRM_MODE_BLEND_PREMULTI) | > > + BIT(DRM_MODE_BLEND_COVERAGE)); > > + > > + if (info->color_encoding) { > > + ret = drm_plane_create_color_properties(&plane->base, > info->color_encoding, > > + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), > > + DRM_COLOR_YCBCR_BT709, > > + DRM_COLOR_YCBCR_LIMITED_RANGE); > > + if (ret) > > + return NULL; > > + } > > + > > + if (info->rotation) { > > + ret = drm_plane_create_rotation_property(&plane->base, > > + DRM_MODE_ROTATE_0, > > + info->rotation); > > + if (ret) > > + return NULL; > > + } > > + > > + ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0, > layer_num - 1); > > + if (ret) > > + return NULL; > > + > > + return plane; > > +} > > + > > +struct vs_plane *vs_plane_cursor_create(struct drm_device *drm_dev, > > + struct vs_plane_cursor_info *info, > > + unsigned int possible_crtcs) > > +{ > > + struct vs_plane *plane; > > + int ret; > > + > > + if (!info) > > + return NULL; > > + > > + plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base, > > + possible_crtcs, > > + &vs_plane_funcs, > > + info->formats, info->num_formats, > > + NULL, DRM_PLANE_TYPE_CURSOR, > > + NULL); > > + if (IS_ERR(plane)) > > + return ERR_CAST(plane); > > + > > + drm_plane_helper_add(&plane->base, &cursor_plane_helpers); > > + > > + ret = drm_plane_create_zpos_immutable_property(&plane->base, > info->zpos); > > + if (ret) > > + return NULL; > > + > > + return plane; > > +} > > diff --git a/drivers/gpu/drm/verisilicon/vs_plane.h > > b/drivers/gpu/drm/verisilicon/vs_plane.h > > new file mode 100644 > > index 000000000000..0416146226a8 > > --- /dev/null > > +++ b/drivers/gpu/drm/verisilicon/vs_plane.h > > @@ -0,0 +1,26 @@ > > +/* SPDX-License-Identifier: GPL-2.0 */ > > +/* > > + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd. > > + */ > > + > > +#ifndef __VS_PLANE_H__ > > +#define __VS_PLANE_H__ > > + > > +#include <drm/drm_plane_helper.h> > > + > > +#include "vs_drv.h" > > + > > +struct vs_plane *vs_plane_primary_create(struct drm_device *drm_dev, > > + struct vs_plane_primary_info *info, > > + unsigned int layer_num, > > + unsigned int possible_crtcs); > > + > > +struct vs_plane *vs_plane_overlay_create(struct drm_device *drm_dev, > > + struct vs_plane_overlay_info *info, > > + unsigned int layer_num, > > + unsigned int possible_crtcs); > > + > > +struct vs_plane *vs_plane_cursor_create(struct drm_device *drm_dev, > > + struct vs_plane_cursor_info *info, > > + unsigned int possible_crtcs); > > +#endif /* __VS_PLANE_H__ */ > > -- > > 2.27.0 > > > > -- > With best wishes > Dmitry
On Sun, Jun 23, 2024 at 07:17:07AM GMT, Keith Zhao wrote: > > > > On Tue, May 21, 2024 at 06:58:13PM +0800, keith wrote: > > > add plane funs and helper funs > > > add vs drm common struct and funs > > > > > > Signed-off-by: keith <keith.zhao@starfivetech.com> > > > --- > > > drivers/gpu/drm/verisilicon/Makefile | 3 +- > > > drivers/gpu/drm/verisilicon/vs_drv.h | 93 +++++ > > > drivers/gpu/drm/verisilicon/vs_plane.c | 487 > > > +++++++++++++++++++++++++ drivers/gpu/drm/verisilicon/vs_plane.h | > > > 26 ++ > > > 4 files changed, 608 insertions(+), 1 deletion(-) create mode 100644 > > > drivers/gpu/drm/verisilicon/vs_drv.h > > > create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c > > > create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h > > > + > > > +/*@pitch_alignment: buffer pitch alignment required by sub-devices.*/ > > > > Is that all the docs you want to add? > It should delete the redundant parts which is unused, > To make this patch clearer to review I'm sorry, I can't understand your comment. > > > > > +struct vs_drm_device { > > > + struct drm_device base; > > > + unsigned int pitch_alignment; > > > + /* clocks */ > > > + unsigned int clk_count; > > > + struct clk_bulk_data *clks; > > > + struct reset_control *rsts; > > > + struct vs_dc dc; > > > + int irq; > > > > As usual, please drop unused fields and add them when required. > > In principle, I try to split the patch independently according to this. > In fact, there is still a lot of room for optimization > The subsequent patches will maintain independence and remove redundant parts for decoupling Yes, please.
diff --git a/drivers/gpu/drm/verisilicon/Makefile b/drivers/gpu/drm/verisilicon/Makefile index 536091f37378..1c593b943261 100644 --- a/drivers/gpu/drm/verisilicon/Makefile +++ b/drivers/gpu/drm/verisilicon/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 vs_drm-objs := vs_dc_hw.o \ - vs_modeset.o + vs_modeset.o \ + vs_plane.o obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o diff --git a/drivers/gpu/drm/verisilicon/vs_drv.h b/drivers/gpu/drm/verisilicon/vs_drv.h new file mode 100644 index 000000000000..d9f6efa7c8f9 --- /dev/null +++ b/drivers/gpu/drm/verisilicon/vs_drv.h @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd. + */ + +#ifndef __VS_DRV_H__ +#define __VS_DRV_H__ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/reset.h> + +#include <drm/drm_drv.h> +#include <drm/drm_fourcc.h> +#include <drm/drm_gem.h> +#include <drm/drm_managed.h> + +#include "vs_dc_hw.h" + +/*@pitch_alignment: buffer pitch alignment required by sub-devices.*/ +struct vs_drm_device { + struct drm_device base; + unsigned int pitch_alignment; + /* clocks */ + unsigned int clk_count; + struct clk_bulk_data *clks; + struct reset_control *rsts; + struct vs_dc dc; + int irq; +}; + +static inline struct vs_drm_device * +to_vs_drm_private(const struct drm_device *dev) +{ + return container_of(dev, struct vs_drm_device, base); +} + +struct vs_crtc_state { + struct drm_crtc_state base; + + u32 output_fmt; + u8 encoder_type; + u8 bpp; +}; + +struct vs_crtc { + struct drm_crtc base; + struct device *dev; +}; + +static inline u8 to_vs_display_id(struct vs_dc *dc, struct drm_crtc *crtc) +{ + u8 panel_num = dc->hw.info->panel_num; + u32 index = drm_crtc_index(crtc); + int i; + + for (i = 0; i < panel_num; i++) { + if (index == dc->crtc[i]->base.index) + return i; + } + + return 0; +} + +static inline struct vs_crtc_state * +to_vs_crtc_state(struct drm_crtc_state *state) +{ + return container_of(state, struct vs_crtc_state, base); +} + +struct vs_plane_state { + struct drm_plane_state base; + dma_addr_t dma_addr[DRM_FORMAT_MAX_PLANES]; +}; + +struct vs_plane { + struct drm_plane base; + u8 id; +}; + +static inline struct vs_plane *to_vs_plane(struct drm_plane *plane) +{ + return container_of(plane, struct vs_plane, base); +} + +static inline struct vs_plane_state * +to_vs_plane_state(struct drm_plane_state *state) +{ + return container_of(state, struct vs_plane_state, base); +} + +#endif /* __VS_DRV_H__ */ diff --git a/drivers/gpu/drm/verisilicon/vs_plane.c b/drivers/gpu/drm/verisilicon/vs_plane.c new file mode 100644 index 000000000000..653f0ce72ed6 --- /dev/null +++ b/drivers/gpu/drm/verisilicon/vs_plane.c @@ -0,0 +1,487 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd. + */ +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_blend.h> +#include <drm/drm_gem_dma_helper.h> +#include <drm/drm_fb_dma_helper.h> +#include <drm/drm_framebuffer.h> +#include <drm/drm_plane.h> +#include <drm/drm_plane_helper.h> + +#include "vs_plane.h" + +static void vs_plane_atomic_destroy_state(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct vs_plane_state *vs_plane_state = to_vs_plane_state(state); + + __drm_atomic_helper_plane_destroy_state(state); + kfree(vs_plane_state); +} + +static void vs_plane_reset(struct drm_plane *plane) +{ + struct vs_plane_state *state; + struct vs_plane *vs_plane = to_vs_plane(plane); + + if (plane->state) + vs_plane_atomic_destroy_state(plane, plane->state); + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return; + + state->base.zpos = vs_plane->id; + __drm_atomic_helper_plane_reset(plane, &state->base); +} + +static struct drm_plane_state * +vs_plane_atomic_duplicate_state(struct drm_plane *plane) +{ + struct vs_plane_state *state; + + if (WARN_ON(!plane->state)) + return NULL; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return NULL; + + __drm_atomic_helper_plane_duplicate_state(plane, &state->base); + + return &state->base; +} + +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, + .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 bool vs_dc_mod_supported(const u64 *info_modifiers, u64 modifier) +{ + const u64 *mods; + + if (!info_modifiers) + return false; + + for (mods = info_modifiers; *mods != DRM_FORMAT_MOD_INVALID; mods++) { + if (*mods == modifier) + return true; + } + + return false; +} + +static int vs_primary_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) +{ + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); + struct vs_dc *dc = &priv->dc; + struct drm_framebuffer *fb = new_state->fb; + const struct vs_plane_primary_info *primary_info; + struct drm_crtc_state *crtc_state; + int i; + + if (!new_state->crtc || !new_state->fb) + return 0; + for (i = 0; i < dc->hw.info->primary_num; i++) { + primary_info = (struct vs_plane_primary_info *)&dc->hw.info->primary[i]; + if (primary_info->id == to_vs_plane(plane)->id) + break; + } + + primary_info = &dc->hw.info->primary[i]; + + if (fb->width < primary_info->min_width || + fb->width > primary_info->max_width || + fb->height < primary_info->min_height || + fb->height > primary_info->max_height) + drm_err_once(plane->dev, "buffer size may not support on plane%d.\n", + to_vs_plane(plane)->id); + + if (!vs_dc_mod_supported(primary_info->modifiers, fb->modifier)) { + drm_err(plane->dev, "unsupported modifier on plane%d.\n", to_vs_plane(plane)->id); + return -EINVAL; + } + + crtc_state = drm_atomic_get_existing_crtc_state(new_state->state, new_state->crtc); + return drm_atomic_helper_check_plane_state(new_state, crtc_state, + primary_info->min_scale, + primary_info->max_scale, + true, true); +} + +static int vs_overlay_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) +{ + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); + struct vs_dc *dc = &priv->dc; + struct drm_framebuffer *fb = new_state->fb; + const struct vs_plane_overlay_info *overlay_info; + struct drm_crtc_state *crtc_state; + int i; + + if (!new_state->crtc || !new_state->fb) + return 0; + + for (i = 0; i < dc->hw.info->overlay_num; i++) { + overlay_info = (struct vs_plane_overlay_info *)&dc->hw.info->overlay[i]; + if (overlay_info->id == to_vs_plane(plane)->id) + break; + } + + overlay_info = &dc->hw.info->overlay[i]; + + if (fb->width < overlay_info->min_width || + fb->width > overlay_info->max_width || + fb->height < overlay_info->min_height || + fb->height > overlay_info->max_height) + drm_err_once(plane->dev, "buffer size may not support on plane%d.\n", + to_vs_plane(plane)->id); + + if (!vs_dc_mod_supported(overlay_info->modifiers, fb->modifier)) { + drm_err(plane->dev, "unsupported modifier on plane%d.\n", to_vs_plane(plane)->id); + return -EINVAL; +} + + crtc_state = drm_atomic_get_existing_crtc_state(new_state->state, new_state->crtc); + return drm_atomic_helper_check_plane_state(new_state, crtc_state, + overlay_info->min_scale, + overlay_info->max_scale, + true, true); +} + +static int vs_cursor_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) +{ + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); + struct vs_dc *dc = &priv->dc; + struct drm_framebuffer *fb = new_state->fb; + const struct vs_plane_cursor_info *cursor_info; + struct drm_crtc_state *crtc_state; + int i; + + if (!new_state->crtc || !new_state->fb) + return 0; + + for (i = 0; i < dc->hw.info->cursor_num; i++) { + cursor_info = (struct vs_plane_cursor_info *)&dc->hw.info->cursor[i]; + if (cursor_info->id == to_vs_plane(plane)->id) + break; + } + + cursor_info = &dc->hw.info->cursor[i]; + + if (fb->width < cursor_info->min_width || + fb->width > cursor_info->max_width || + fb->height < cursor_info->min_height || + fb->height > cursor_info->max_height) + drm_err_once(plane->dev, "buffer size may not support on plane%d.\n", + to_vs_plane(plane)->id); + + crtc_state = drm_atomic_get_existing_crtc_state(new_state->state, new_state->crtc); + return drm_atomic_helper_check_plane_state(new_state, crtc_state, + DRM_PLANE_NO_SCALING, + DRM_PLANE_NO_SCALING, + true, true); +} + +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); + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); + + unsigned char i, num_planes, display_id, id; + u32 format; + bool is_yuv; + struct vs_plane *vs_plane = to_vs_plane(plane); + struct vs_plane_state *plane_state = to_vs_plane_state(new_state); + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); + struct vs_dc *dc = &priv->dc; + + if (!new_state->fb || !new_state->crtc) + return; + + drm_fb_dma_sync_non_coherent(plane->dev, old_state, new_state); + + num_planes = vs_get_plane_number(new_state->fb); + + for (i = 0; i < num_planes; i++) { + dma_addr_t dma_addr; + + dma_addr = drm_fb_dma_get_gem_addr(new_state->fb, new_state, i); + plane_state->dma_addr[i] = dma_addr; + } + + display_id = to_vs_display_id(dc, new_state->crtc); + format = new_state->fb->format->format; + is_yuv = new_state->fb->format->is_yuv; + id = vs_plane->id; + + plane_hw_update_format_colorspace(dc, format, new_state->color_encoding, id, is_yuv); + if (new_state->visible) + plane_hw_update_address(dc, id, format, plane_state->dma_addr, + new_state->fb, &new_state->src); + plane_hw_update_format(dc, format, new_state->color_encoding, new_state->rotation, + new_state->visible, new_state->zpos, id, display_id); + plane_hw_update_scale(dc, &new_state->src, &new_state->dst, id, + display_id, new_state->rotation); + plane_hw_update_blend(dc, new_state->alpha, new_state->pixel_blend_mode, + id, display_id); +} + +static void vs_cursor_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); + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, + plane); + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); + struct vs_dc *dc = &priv->dc; + unsigned char display_id; + u32 crtc_w, crtc_x, crtc_y; + s32 hotspot_x, hotspot_y; + dma_addr_t dma_addr; + + display_id = to_vs_display_id(dc, new_state->crtc); + + if (!new_state->fb || !new_state->crtc) + return; + + drm_fb_dma_sync_non_coherent(new_state->fb->dev, old_state, new_state); + dma_addr = drm_fb_dma_get_gem_addr(new_state->fb, new_state, 0); + crtc_w = new_state->crtc_w; + + if (new_state->crtc_x > 0) { + crtc_x = new_state->crtc_x; + hotspot_x = 0; + } else { + hotspot_x = -new_state->crtc_x; + crtc_x = 0; + } + if (new_state->crtc_y > 0) { + crtc_y = new_state->crtc_y; + hotspot_y = 0; + } else { + hotspot_y = -new_state->crtc_y; + crtc_y = 0; + } + dc_hw_update_cursor(&dc->hw, display_id, dma_addr, crtc_w, crtc_x, + crtc_y, hotspot_x, hotspot_y); +} + +static void vs_plane_atomic_disable(struct drm_plane *plane, struct drm_atomic_state *state) +{ + struct vs_plane *vs_plane = to_vs_plane(plane); + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); + struct vs_dc *dc = &priv->dc; + + dc_hw_disable_plane(dc, vs_plane->id); +} + +static void vs_cursor_plane_atomic_disable(struct drm_plane *plane, struct drm_atomic_state *state) +{ + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); + struct vs_drm_device *priv = to_vs_drm_private(plane->dev); + struct vs_dc *dc = &priv->dc; + unsigned char display_id; + + display_id = to_vs_display_id(dc, old_state->crtc); + dc_hw_disable_cursor(&dc->hw, display_id); +} + +const struct drm_plane_helper_funcs primary_plane_helpers = { + .atomic_check = vs_primary_plane_atomic_check, + .atomic_update = vs_plane_atomic_update, + .atomic_disable = vs_plane_atomic_disable, +}; + +const struct drm_plane_helper_funcs overlay_plane_helpers = { + .atomic_check = vs_overlay_plane_atomic_check, + .atomic_update = vs_plane_atomic_update, + .atomic_disable = vs_plane_atomic_disable, +}; + +const struct drm_plane_helper_funcs cursor_plane_helpers = { + .atomic_check = vs_cursor_plane_atomic_check, + .atomic_update = vs_cursor_plane_atomic_update, + .atomic_disable = vs_cursor_plane_atomic_disable, +}; + +struct vs_plane *vs_plane_primary_create(struct drm_device *drm_dev, + struct vs_plane_primary_info *info, + unsigned int layer_num, + unsigned int possible_crtcs) +{ + struct vs_plane *plane; + int ret; + + if (!info) + return NULL; + + plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base, + possible_crtcs, + &vs_plane_funcs, + info->formats, info->num_formats, + info->modifiers, DRM_PLANE_TYPE_PRIMARY, + NULL); + if (IS_ERR(plane)) + return ERR_CAST(plane); + + drm_plane_helper_add(&plane->base, &primary_plane_helpers); + + drm_plane_create_alpha_property(&plane->base); + drm_plane_create_blend_mode_property(&plane->base, + BIT(DRM_MODE_BLEND_PIXEL_NONE) | + BIT(DRM_MODE_BLEND_PREMULTI) | + BIT(DRM_MODE_BLEND_COVERAGE)); + + if (info->color_encoding) { + ret = drm_plane_create_color_properties(&plane->base, info->color_encoding, + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), + DRM_COLOR_YCBCR_BT709, + DRM_COLOR_YCBCR_LIMITED_RANGE); + if (ret) + return NULL; + } + + if (info->rotation) { + ret = drm_plane_create_rotation_property(&plane->base, + DRM_MODE_ROTATE_0, + info->rotation); + if (ret) + return NULL; + } + + ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0, layer_num - 1); + if (ret) + return NULL; + + return plane; +} + +struct vs_plane *vs_plane_overlay_create(struct drm_device *drm_dev, + struct vs_plane_overlay_info *info, + unsigned int layer_num, + unsigned int possible_crtcs) +{ + struct vs_plane *plane; + int ret; + + if (!info) + return NULL; + + plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base, + possible_crtcs, + &vs_plane_funcs, + info->formats, info->num_formats, + info->modifiers, DRM_PLANE_TYPE_OVERLAY, + NULL); + if (IS_ERR(plane)) + return ERR_CAST(plane); + + drm_plane_helper_add(&plane->base, &overlay_plane_helpers); + + drm_plane_create_alpha_property(&plane->base); + drm_plane_create_blend_mode_property(&plane->base, + BIT(DRM_MODE_BLEND_PIXEL_NONE) | + BIT(DRM_MODE_BLEND_PREMULTI) | + BIT(DRM_MODE_BLEND_COVERAGE)); + + if (info->color_encoding) { + ret = drm_plane_create_color_properties(&plane->base, info->color_encoding, + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE), + DRM_COLOR_YCBCR_BT709, + DRM_COLOR_YCBCR_LIMITED_RANGE); + if (ret) + return NULL; + } + + if (info->rotation) { + ret = drm_plane_create_rotation_property(&plane->base, + DRM_MODE_ROTATE_0, + info->rotation); + if (ret) + return NULL; + } + + ret = drm_plane_create_zpos_property(&plane->base, info->zpos, 0, layer_num - 1); + if (ret) + return NULL; + + return plane; +} + +struct vs_plane *vs_plane_cursor_create(struct drm_device *drm_dev, + struct vs_plane_cursor_info *info, + unsigned int possible_crtcs) +{ + struct vs_plane *plane; + int ret; + + if (!info) + return NULL; + + plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base, + possible_crtcs, + &vs_plane_funcs, + info->formats, info->num_formats, + NULL, DRM_PLANE_TYPE_CURSOR, + NULL); + if (IS_ERR(plane)) + return ERR_CAST(plane); + + drm_plane_helper_add(&plane->base, &cursor_plane_helpers); + + ret = drm_plane_create_zpos_immutable_property(&plane->base, info->zpos); + if (ret) + return NULL; + + return plane; +} diff --git a/drivers/gpu/drm/verisilicon/vs_plane.h b/drivers/gpu/drm/verisilicon/vs_plane.h new file mode 100644 index 000000000000..0416146226a8 --- /dev/null +++ b/drivers/gpu/drm/verisilicon/vs_plane.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2023 VeriSilicon Holdings Co., Ltd. + */ + +#ifndef __VS_PLANE_H__ +#define __VS_PLANE_H__ + +#include <drm/drm_plane_helper.h> + +#include "vs_drv.h" + +struct vs_plane *vs_plane_primary_create(struct drm_device *drm_dev, + struct vs_plane_primary_info *info, + unsigned int layer_num, + unsigned int possible_crtcs); + +struct vs_plane *vs_plane_overlay_create(struct drm_device *drm_dev, + struct vs_plane_overlay_info *info, + unsigned int layer_num, + unsigned int possible_crtcs); + +struct vs_plane *vs_plane_cursor_create(struct drm_device *drm_dev, + struct vs_plane_cursor_info *info, + unsigned int possible_crtcs); +#endif /* __VS_PLANE_H__ */
add plane funs and helper funs add vs drm common struct and funs Signed-off-by: keith <keith.zhao@starfivetech.com> --- drivers/gpu/drm/verisilicon/Makefile | 3 +- drivers/gpu/drm/verisilicon/vs_drv.h | 93 +++++ drivers/gpu/drm/verisilicon/vs_plane.c | 487 +++++++++++++++++++++++++ drivers/gpu/drm/verisilicon/vs_plane.h | 26 ++ 4 files changed, 608 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/verisilicon/vs_drv.h create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.c create mode 100644 drivers/gpu/drm/verisilicon/vs_plane.h