public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: keith zhao <keith.zhao@starfivetech.com>
To: devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org
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, simona@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,
	william.qiu@starfivetech.com, xingyu.wu@starfivetech.com,
	kernel@esmil.dk, paul.walmsley@sifive.com, palmer@dabbelt.com,
	aou@eecs.berkeley.edu, p.zabel@pengutronix.de,
	changhuang.liang@starfivetech.com, keith.zhao@starfivetech.com,
	jack.zhu@starfivetech.com, linux-kernel@vger.kernel.org
Subject: [PATCH v5 7/9] drm/vs: Add VS Plane API
Date: Wed, 20 Nov 2024 14:18:46 +0800	[thread overview]
Message-ID: <20241120061848.196754-8-keith.zhao@starfivetech.com> (raw)
In-Reply-To: <20241120061848.196754-1-keith.zhao@starfivetech.com>

This commit introduces plane functions and helper functions
for the VS DRM subsystem, enhancing support for managing
display planes and their configurations.

Signed-off-by: keith zhao <keith.zhao@starfivetech.com>
---
 drivers/gpu/drm/verisilicon/Makefile   |   3 +-
 drivers/gpu/drm/verisilicon/vs_plane.c | 358 +++++++++++++++++++++++++
 drivers/gpu/drm/verisilicon/vs_plane.h |  27 ++
 3 files changed, 387 insertions(+), 1 deletion(-)
 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 37f6a4db2a12..1a0e46f38ae8 100644
--- a/drivers/gpu/drm/verisilicon/Makefile
+++ b/drivers/gpu/drm/verisilicon/Makefile
@@ -2,6 +2,7 @@
 
 vs_drm-objs := vs_dc_hw.o \
 	       vs_modeset.o \
-	       vs_crtc.o
+	       vs_crtc.o \
+	       vs_plane.o
 
 obj-$(CONFIG_DRM_VERISILICON_DC8200) += vs_drm.o
diff --git a/drivers/gpu/drm/verisilicon/vs_plane.c b/drivers/gpu/drm/verisilicon/vs_plane.c
new file mode 100644
index 000000000000..ba47d0185fc6
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_plane.c
@@ -0,0 +1,358 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 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_helper.h>
+
+#include "vs_plane.h"
+#include "vs_drv.h"
+#include "vs_crtc.h"
+
+static inline struct vs_plane_state *
+to_vs_plane_state(struct drm_plane_state *state)
+{
+	return container_of(state, struct vs_plane_state, base);
+}
+
+static inline struct vs_plane *to_vs_plane(struct drm_plane *plane)
+{
+	return container_of(plane, struct vs_plane, base);
+}
+
+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;
+
+	if (plane->state)
+		vs_plane_atomic_destroy_state(plane, plane->state);
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return;
+
+	__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;
+}
+
+static 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 struct vs_plane_info *vs_info, u64 modifier)
+{
+	const u64 *mods;
+
+	if (vs_info->type == DRM_PLANE_TYPE_CURSOR)
+		return 0;
+
+	if (!vs_info->data->modifiers)
+		return false;
+
+	for (mods = vs_info->data->modifiers; *mods != DRM_FORMAT_MOD_INVALID; mods++) {
+		if (*mods == modifier)
+			return true;
+	}
+
+	return false;
+}
+
+static int vs_common_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_info *plane_info;
+	struct drm_crtc_state *crtc_state;
+
+	if (!new_state->crtc || !new_state->fb)
+		return 0;
+
+	plane_info = (struct vs_plane_info *)&dc->hw.info->info[to_vs_plane(plane)->id];
+
+	if (fb->width < plane_info->data->min_width ||
+	    fb->width > plane_info->data->max_width ||
+	    fb->height < plane_info->data->min_height ||
+	    fb->height > plane_info->data->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(plane_info, 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,
+						   plane_info->data->min_scale,
+						   plane_info->data->max_scale,
+						   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(new_state->crtc);
+	format = new_state->fb->format->format;
+	is_yuv = new_state->fb->format->is_yuv;
+	id = vs_plane->id;
+
+	dc_plane_hw_update_format_colorspace(dc, format, new_state->color_encoding, id, is_yuv);
+	if (new_state->visible)
+		dc_plane_hw_update_address(dc, id, format, plane_state->dma_addr,
+					   new_state->fb, &new_state->src);
+	dc_plane_hw_update_format(dc, format, new_state->color_encoding, new_state->rotation,
+				  new_state->visible, new_state->zpos, id, display_id);
+	dc_plane_hw_update_scale(dc, &new_state->src, &new_state->dst, id,
+				 display_id, new_state->rotation);
+	dc_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(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(old_state->crtc);
+	dc_hw_disable_cursor(&dc->hw, display_id);
+}
+
+static const struct drm_plane_helper_funcs vs_primary_plane_helpers = {
+	.atomic_check	= vs_common_plane_atomic_check,
+	.atomic_update	= vs_plane_atomic_update,
+	.atomic_disable = vs_plane_atomic_disable,
+};
+
+static const struct drm_plane_helper_funcs vs_overlay_plane_helpers = {
+	.atomic_check	= vs_common_plane_atomic_check,
+	.atomic_update	= vs_plane_atomic_update,
+	.atomic_disable = vs_plane_atomic_disable,
+};
+
+static const struct drm_plane_helper_funcs vs_cursor_plane_helpers = {
+	.atomic_check	= vs_common_plane_atomic_check,
+	.atomic_update	= vs_cursor_plane_atomic_update,
+	.atomic_disable = vs_cursor_plane_atomic_disable,
+};
+
+struct vs_plane *vs_plane_create(struct drm_device *drm_dev,
+				 struct vs_plane_info *info,
+				 unsigned int layer_num,
+				 unsigned int possible_crtcs)
+{
+	struct vs_plane *plane;
+	const struct vs_plane_data *data = info->data;
+	int ret;
+
+	if (!info)
+		return NULL;
+
+	plane = drmm_universal_plane_alloc(drm_dev, struct vs_plane, base,
+					   possible_crtcs,
+					   &vs_plane_funcs,
+					   data->formats, data->num_formats,
+					   data->modifiers, info->type,
+					   NULL);
+	if (IS_ERR(plane))
+		return ERR_CAST(plane);
+
+	if (info->type == DRM_PLANE_TYPE_PRIMARY)
+		drm_plane_helper_add(&plane->base, &vs_primary_plane_helpers);
+	else if (info->type == DRM_PLANE_TYPE_OVERLAY)
+		drm_plane_helper_add(&plane->base, &vs_overlay_plane_helpers);
+	else
+		drm_plane_helper_add(&plane->base, &vs_cursor_plane_helpers);
+
+	if (data->blend_mode) {
+		ret = drm_plane_create_alpha_property(&plane->base);
+		if (ret)
+			return NULL;
+
+		ret = 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 (ret)
+			return NULL;
+	}
+
+	if (data->color_encoding) {
+		ret = drm_plane_create_color_properties(&plane->base, data->color_encoding,
+							BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
+							DRM_COLOR_YCBCR_BT709,
+							DRM_COLOR_YCBCR_LIMITED_RANGE);
+		if (ret)
+			return NULL;
+	}
+
+	if (data->rotation) {
+		ret = drm_plane_create_rotation_property(&plane->base,
+							 DRM_MODE_ROTATE_0,
+							 data->rotation);
+		if (ret)
+			return NULL;
+	}
+
+	if (data->zpos != 255) {
+		ret = drm_plane_create_zpos_property(&plane->base, data->zpos, 0, layer_num - 1);
+		if (ret)
+			return NULL;
+	} else {
+		ret = drm_plane_create_zpos_immutable_property(&plane->base, data->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..60d45b69e30a
--- /dev/null
+++ b/drivers/gpu/drm/verisilicon/vs_plane.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) VeriSilicon Holdings Co., Ltd.
+ */
+
+#ifndef __VS_PLANE_H__
+#define __VS_PLANE_H__
+
+#include <drm/drm_plane.h>
+
+struct vs_plane_info;
+
+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;
+};
+
+struct vs_plane *vs_plane_create(struct drm_device *drm_dev,
+				 struct vs_plane_info *info,
+				 unsigned int layer_num,
+				 unsigned int possible_crtcs);
+#endif /* __VS_PLANE_H__ */
-- 
2.34.1


  parent reply	other threads:[~2024-11-20  6:21 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-11-20  6:18 [PATCH v5 0/9] drm/verisilicon : support DC8200 and inno hdmi keith zhao
2024-11-20  6:18 ` [PATCH v5 2/9] riscv: dts: Add display property keith zhao
2024-11-20  6:18 ` [PATCH v5 3/9] drm: bridge: inno-hdmi: add inno bridge driver keith zhao
2024-11-20  7:38   ` Krzysztof Kozlowski
2024-11-20  6:18 ` [PATCH v5 4/9] drm/vs: Add Hardware Functions for VS DC8200 keith zhao
2024-11-20  6:18 ` [PATCH v5 5/9] drm/vs: Add Base API for VS Mode Configuration keith zhao
2024-11-20  6:18 ` [PATCH v5 6/9] drm/vs: Add CRTC Functions keith zhao
2024-11-20  6:18 ` keith zhao [this message]
2024-11-20  6:18 ` [PATCH v5 8/9] drm/vs: Add Innosilicon HDMI Support keith zhao

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20241120061848.196754-8-keith.zhao@starfivetech.com \
    --to=keith.zhao@starfivetech.com \
    --cc=Laurent.pinchart@ideasonboard.com \
    --cc=airlied@gmail.com \
    --cc=andrzej.hajda@intel.com \
    --cc=andy.yan@rock-chips.com \
    --cc=aou@eecs.berkeley.edu \
    --cc=changhuang.liang@starfivetech.com \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=heiko@sntech.de \
    --cc=hjc@rock-chips.com \
    --cc=jack.zhu@starfivetech.com \
    --cc=jernej.skrabec@gmail.com \
    --cc=jonas@kwiboo.se \
    --cc=kernel@esmil.dk \
    --cc=krzk+dt@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=mripard@kernel.org \
    --cc=neil.armstrong@linaro.org \
    --cc=p.zabel@pengutronix.de \
    --cc=palmer@dabbelt.com \
    --cc=paul.walmsley@sifive.com \
    --cc=rfoss@kernel.org \
    --cc=robh@kernel.org \
    --cc=simona@ffwll.ch \
    --cc=tzimmermann@suse.de \
    --cc=william.qiu@starfivetech.com \
    --cc=xingyu.wu@starfivetech.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox