Skip to contentSkip to conversation

drm/omap: Add virtual-planes support

PATCH In review Benoit Parrot 2 participants 13 messages Oct 12, 2018 – Nov 19, 2018

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

v4 cover drm/omap: Add virtual-planes support

This patch series adds virtual-plane support to omapdrm driver to allow the use of display wider than 2048 pixels.

In order to do so we introduce the concept of hw_overlay which can then be dynamically allocated to a plane. When the requested output width exceed what be supported by one overlay a second is then allocated if possible to handle display wider then 2048.

This series replaces an earlier series which was DT based and using statically allocated resources.

This implementation is inspired from the work done in msm/disp/mdp5 driver.

Benoit Parrot (8):
drm/omap: Add ability to check if requested plane modes can be
supported
drm/omap: Add ovl checking funcs to dispc_ops drm/omap: introduce omap_hw_overlay
drm/omap: omap_plane: subclass drm_plane_state drm/omap: Add global state as a private atomic object drm/omap: dynamically assign hw overlays to planes drm/omap: add plane_atomic_print_state support drm/omap: Add a 'right overlay' to plane state

 drivers/gpu/drm/omapdrm/Makefile       |   1 +
 drivers/gpu/drm/omapdrm/dss/dispc.c    |  32 +++
 drivers/gpu/drm/omapdrm/dss/omapdss.h  |   6 +
 drivers/gpu/drm/omapdrm/omap_drv.c     | 196 ++++++++++++++++-
 drivers/gpu/drm/omapdrm/omap_drv.h     |  30 +++
 drivers/gpu/drm/omapdrm/omap_fb.c      |  33 ++-
 drivers/gpu/drm/omapdrm/omap_fb.h      |   4 +-
 drivers/gpu/drm/omapdrm/omap_overlay.c | 257 ++++++++++++++++++++++
 drivers/gpu/drm/omapdrm/omap_overlay.h |  41 ++++
 drivers/gpu/drm/omapdrm/omap_plane.c   | 374 ++++++++++++++++++++++++++++-----
 drivers/gpu/drm/omapdrm/omap_plane.h   |   1 +
 11 files changed, 922 insertions(+), 53 deletions(-)
 create mode 100644 drivers/gpu/drm/omapdrm/omap_overlay.c
 create mode 100644 drivers/gpu/drm/omapdrm/omap_overlay.h
Signature · 1 line
2.9.0
#1 lore raw

PATCH v4 1/8 drm/omap: Add ability to check if requested plane modes can be supported

We currently assume that an overlay has the same maximum width and maximum height as the overlay manager. This assumption is incorrect. On some variants the overlay manager maximum width is twice the maximum width that the overlay can handle. We need to add the appropriate data per variant as well as export a helper function to retrieve the data so check can be made dynamically in omap_plane_atomic_check().

---
 drivers/gpu/drm/omapdrm/dss/dispc.c   | 24 ++++++++++++++++++++++++
 drivers/gpu/drm/omapdrm/dss/omapdss.h |  2 ++
 drivers/gpu/drm/omapdrm/omap_plane.c  | 14 ++++++++++++++
 3 files changed, 40 insertions(+)
drivers/gpu/drm/omapdrm/dss/dispc.c +24 -0
index fe0b5f6ede72..70c3e3353947 100644
@@ -103,6 +103,8 @@ struct dispc_features {
 	u8 mgr_height_start;
 	u16 mgr_width_max;
 	u16 mgr_height_max;
+	u16 ovl_width_max;
+	u16 ovl_height_max;
 	unsigned long max_lcd_pclk;
 	unsigned long max_tv_pclk;
 	unsigned int max_downscale;
@@ -2596,6 +2598,13 @@ static int dispc_ovl_calc_scaling(struct dispc_device *dispc,
 	return 0;
 }
 
+static void dispc_ovl_get_max_size(struct dispc_device *dispc,
+				   u16 *width, u16 *height)
+{
+	*width = dispc->feat->ovl_width_max;
+	*height = dispc->feat->ovl_height_max;
+}
+
 static int dispc_ovl_setup_common(struct dispc_device *dispc,
 				  enum omap_plane_id plane,
 				  enum omap_overlay_caps caps,
@@ -4247,6 +4256,8 @@ static const struct dispc_features omap24xx_dispc_feats = {
 	.mgr_height_start	=	26,
 	.mgr_width_max		=	2048,
 	.mgr_height_max		=	2048,
+	.ovl_width_max		=	2048,
+	.ovl_height_max		=	2048,
 	.max_lcd_pclk		=	66500000,
 	.max_downscale		=	2,
 	/*
@@ -4284,6 +4295,8 @@ static const struct dispc_features omap34xx_rev1_0_dispc_feats = {
 	.mgr_height_start	=	26,
 	.mgr_width_max		=	2048,
 	.mgr_height_max		=	2048,
+	.ovl_width_max		=	2048,
+	.ovl_height_max		=	2048,
 	.max_lcd_pclk		=	173000000,
 	.max_tv_pclk		=	59000000,
 	.max_downscale		=	4,
@@ -4318,6 +4331,8 @@ static const struct dispc_features omap34xx_rev3_0_dispc_feats = {
 	.mgr_height_start	=	26,
 	.mgr_width_max		=	2048,
 	.mgr_height_max		=	2048,
+	.ovl_width_max		=	2048,
+	.ovl_height_max		=	2048,
 	.max_lcd_pclk		=	173000000,
 	.max_tv_pclk		=	59000000,
 	.max_downscale		=	4,
@@ -4352,6 +4367,8 @@ static const struct dispc_features omap36xx_dispc_feats = {
 	.mgr_height_start	=	26,
 	.mgr_width_max		=	2048,
 	.mgr_height_max		=	2048,
+	.ovl_width_max		=	2048,
+	.ovl_height_max		=	2048,
 	.max_lcd_pclk		=	173000000,
 	.max_tv_pclk		=	59000000,
 	.max_downscale		=	4,
@@ -4386,6 +4403,8 @@ static const struct dispc_features am43xx_dispc_feats = {
 	.mgr_height_start	=	26,
 	.mgr_width_max		=	2048,
 	.mgr_height_max		=	2048,
+	.ovl_width_max		=	2048,
+	.ovl_height_max		=	2048,
 	.max_lcd_pclk		=	173000000,
 	.max_tv_pclk		=	59000000,
 	.max_downscale		=	4,
@@ -4420,6 +4439,8 @@ static const struct dispc_features omap44xx_dispc_feats = {
 	.mgr_height_start	=	26,
 	.mgr_width_max		=	2048,
 	.mgr_height_max		=	2048,
+	.ovl_width_max		=	2048,
+	.ovl_height_max		=	2048,
 	.max_lcd_pclk		=	170000000,
 	.max_tv_pclk		=	185625000,
 	.max_downscale		=	4,
@@ -4459,6 +4480,8 @@ static const struct dispc_features omap54xx_dispc_feats = {
 	.mgr_height_start	=	27,
 	.mgr_width_max		=	4096,
 	.mgr_height_max		=	4096,
+	.ovl_width_max		=	2048,
+	.ovl_height_max		=	4096,
 	.max_lcd_pclk		=	170000000,
 	.max_tv_pclk		=	192000000,
 	.max_downscale		=	4,
@@ -4734,6 +4757,7 @@ static const struct dispc_ops dispc_ops = {
 	.ovl_enable = dispc_ovl_enable,
 	.ovl_setup = dispc_ovl_setup,
 	.ovl_get_color_modes = dispc_ovl_get_color_modes,
+	.ovl_get_max_size = dispc_ovl_get_max_size,
 
 	.wb_get_framedone_irq = dispc_wb_get_framedone_irq,
 	.wb_setup = dispc_wb_setup,
drivers/gpu/drm/omapdrm/dss/omapdss.h +2 -0
index 1f698a95a94a..45334d5c618e 100644
@@ -632,6 +632,8 @@ struct dispc_ops {
 
 	const u32 *(*ovl_get_color_modes)(struct dispc_device *dispc,
 					  enum omap_plane_id plane);
+	void (*ovl_get_max_size)(struct dispc_device *dispc,
+				 u16 *width, u16 *height);
 
 	u32 (*wb_get_framedone_irq)(struct dispc_device *dispc);
 	int (*wb_setup)(struct dispc_device *dispc,
drivers/gpu/drm/omapdrm/omap_plane.c +14 -0
index 161233cbc9a0..e1e338e76841 100644
@@ -106,11 +106,18 @@ static void omap_plane_atomic_disable(struct drm_plane *plane,
 static int omap_plane_atomic_check(struct drm_plane *plane,
 				   struct drm_plane_state *state)
 {
+	struct omap_drm_private *priv = plane->dev->dev_private;
 	struct drm_crtc_state *crtc_state;
+	u16 width, height;
+	u32 width_fp, height_fp;
 
 	if (!state->fb)
 		return 0;
 
+	priv->dispc_ops->ovl_get_max_size(priv->dispc, &width, &height);
+	width_fp = width << 16;
+	height_fp = height << 16;
+
 	/* crtc should only be NULL when disabling (i.e., !state->fb) */
 	if (WARN_ON(!state->crtc))
 		return 0;
@@ -132,6 +139,13 @@ static int omap_plane_atomic_check(struct drm_plane *plane,
 	if (state->crtc_y + state->crtc_h > crtc_state->adjusted_mode.vdisplay)
 		return -EINVAL;
 
+	/* Make sure dimensions are within bounds. */
+	if (state->src_h > height_fp || state->crtc_h > height)
+		return -EINVAL;
+
+	if (state->src_w > width_fp || state->crtc_w > width)
+		return -EINVAL;
+
 	if (state->rotation != DRM_MODE_ROTATE_0 &&
 	    !omap_framebuffer_supports_rotation(state->fb))
 		return -EINVAL;
Signature · 1 line
2.9.0
#2 lore raw

PATCH v4 2/8 drm/omap: Add ovl checking funcs to dispc_ops

In reply to Benoit Parrot

In order to be able to dynamically assign overlays to planes we need to be able to asses the overlay capabilities.

Add a helper function to be able to retrieve the supported capabilities of an overlay.

And export the function to check if a fourcc is supported on a given overlay.

---
 drivers/gpu/drm/omapdrm/dss/dispc.c   | 8 ++++++++
 drivers/gpu/drm/omapdrm/dss/omapdss.h | 4 ++++
 2 files changed, 12 insertions(+)
drivers/gpu/drm/omapdrm/dss/dispc.c +8 -0
index 70c3e3353947..ea8b57003620 100644
@@ -2499,6 +2499,12 @@ static int dispc_ovl_calc_scaling_44xx(struct dispc_device *dispc,
 	return 0;
 }
 
+static enum omap_overlay_caps dispc_ovl_get_caps(struct dispc_device *dispc,
+						 enum omap_plane_id plane)
+{
+	return dispc->feat->overlay_caps[plane];
+}
+
 #define DIV_FRAC(dividend, divisor) \
 	((dividend) * 100 / (divisor) - ((dividend) / (divisor) * 100))
 
@@ -4757,6 +4763,8 @@ static const struct dispc_ops dispc_ops = {
 	.ovl_enable = dispc_ovl_enable,
 	.ovl_setup = dispc_ovl_setup,
 	.ovl_get_color_modes = dispc_ovl_get_color_modes,
+	.ovl_color_mode_supported = dispc_ovl_color_mode_supported,
+	.ovl_get_caps = dispc_ovl_get_caps,
 	.ovl_get_max_size = dispc_ovl_get_max_size,
 
 	.wb_get_framedone_irq = dispc_wb_get_framedone_irq,
drivers/gpu/drm/omapdrm/dss/omapdss.h +4 -0
index 45334d5c618e..b5640e8479dc 100644
@@ -632,6 +632,10 @@ struct dispc_ops {
 
 	const u32 *(*ovl_get_color_modes)(struct dispc_device *dispc,
 					  enum omap_plane_id plane);
+	bool (*ovl_color_mode_supported)(struct dispc_device *dispc,
+					 enum omap_plane_id plane, u32 fourcc);
+	enum omap_overlay_caps (*ovl_get_caps)(struct dispc_device *dispc,
+					       enum omap_plane_id plane);
 	void (*ovl_get_max_size)(struct dispc_device *dispc,
 				 u16 *width, u16 *height);
 
Signature · 6 lines
2.9.0

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#3 lore raw

PATCH v4 3/8 drm/omap: introduce omap_hw_overlay

In reply to Benoit Parrot

Split out the hardware overlay specifics from omap_plane. To start, the hw overlays are statically assigned to planes.

The goal is to eventually assign hw overlays dynamically to planes during plane->atomic_check() based on requested caps (scaling, YUV, etc). And then perform hw overlay re-assignment if required.

---
 drivers/gpu/drm/omapdrm/Makefile       |  1 +
 drivers/gpu/drm/omapdrm/omap_drv.c     | 10 +++-
 drivers/gpu/drm/omapdrm/omap_drv.h     |  4 ++
 drivers/gpu/drm/omapdrm/omap_overlay.c | 87 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/omapdrm/omap_overlay.h | 31 ++++++++++++
 drivers/gpu/drm/omapdrm/omap_plane.c   | 47 +++++++++---------
 6 files changed, 156 insertions(+), 24 deletions(-)
 create mode 100644 drivers/gpu/drm/omapdrm/omap_overlay.c
 create mode 100644 drivers/gpu/drm/omapdrm/omap_overlay.h
drivers/gpu/drm/omapdrm/Makefile +1 -0
index f115253115c5..800dfd035360 100644
@@ -12,6 +12,7 @@ omapdrm-y := omap_drv.o \
 	omap_debugfs.o \
 	omap_crtc.o \
 	omap_plane.o \
+	omap_overlay.o \
 	omap_encoder.o \
 	omap_connector.o \
 	omap_fb.o \
drivers/gpu/drm/omapdrm/omap_drv.c +9 -1
index 5e67d58cbc28..2921cc90f2d8 100644
@@ -569,10 +569,14 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
 
 	omap_gem_init(ddev);
 
+	ret = omap_hwoverlays_init(priv);
+	if (ret)
+		goto err_gem_deinit;
+
 	ret = omap_modeset_init(ddev);
 	if (ret) {
 		dev_err(priv->dev, "omap_modeset_init failed: ret=%d\n", ret);
-		goto err_gem_deinit;
+		goto err_free_overlays;
 	}
 
 	/* Initialize vblank handling, start with all CRTCs disabled. */
@@ -608,6 +612,8 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
 err_cleanup_modeset:
 	drm_mode_config_cleanup(ddev);
 	omap_drm_irq_uninstall(ddev);
+err_free_overlays:
+	omap_hwoverlays_destroy(priv);
 err_gem_deinit:
 	omap_gem_deinit(ddev);
 	destroy_workqueue(priv->wq);
@@ -638,6 +644,8 @@ static void omapdrm_cleanup(struct omap_drm_private *priv)
 	omap_drm_irq_uninstall(ddev);
 	omap_gem_deinit(ddev);
 
+	omap_hwoverlays_destroy(priv);
+
 	destroy_workqueue(priv->wq);
 
 	omap_disconnect_pipelines(ddev);
drivers/gpu/drm/omapdrm/omap_drv.h +4 -0
index bd7f2c227a25..929f04e7cc3b 100644
@@ -37,6 +37,7 @@
 #include "omap_gem.h"
 #include "omap_irq.h"
 #include "omap_plane.h"
+#include "omap_overlay.h"
 
 #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
 #define VERB(fmt, ...) if (0) DRM_DEBUG(fmt, ##__VA_ARGS__) /* verbose debug */
@@ -69,6 +70,9 @@ struct omap_drm_private {
 	unsigned int num_planes;
 	struct drm_plane *planes[8];
 
+	unsigned int num_ovls;
+	struct omap_hw_overlay *overlays[8];
+
 	struct drm_fb_helper *fbdev;
 
 	struct workqueue_struct *wq;
drivers/gpu/drm/omapdrm/omap_overlay.c new file +87 -0

87 lines not on this page · raw message

drivers/gpu/drm/omapdrm/omap_overlay.h new file +31 -0
new file mode 100644
index 000000000000..892fecb67adb
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated -  http://www.ti.com/
+ * Author: Benoit Parrot, <[email protected]>
+ */
+
+#ifndef __OMAPDRM_OVERLAY_H__
+#define __OMAPDRM_OVERLAY_H__
+
+#include <linux/types.h>
+
+enum drm_plane_type;
+
+struct drm_device;
+struct drm_mode_object;
+struct drm_plane;
+
+/* Used to associate a HW overlay/plane to a plane */
+struct omap_hw_overlay {
+	int idx;
+
+	const char *name;
+	enum omap_plane_id overlay_id;
+
+	enum omap_overlay_caps caps;
+	u32 possible_crtcs;
+};
+
+int omap_hwoverlays_init(struct omap_drm_private *priv);
+void omap_hwoverlays_destroy(struct omap_drm_private *priv);
+#endif /* __OMAPDRM_OVERLAY_H__ */
drivers/gpu/drm/omapdrm/omap_plane.c +24 -23

121 lines not on this page · raw message

Signature · 1 line
2.9.0
#4 lore raw

PATCH v4 4/8 drm/omap: omap_plane: subclass drm_plane_state

In reply to Benoit Parrot

In preparation to add omap plane state specific extensions we need to subclass drm_plane_state and add the relevant helpers.

The addition of specific extension will be done separately.

---
 drivers/gpu/drm/omapdrm/omap_plane.c | 48 +++++++++++++++++++++++++++++++++---
 1 file changed, 44 insertions(+), 4 deletions(-)
drivers/gpu/drm/omapdrm/omap_plane.c +44 -4
index 26c2c78d020f..b0e60119c0a1 100644
@@ -26,6 +26,12 @@
  * plane funcs
  */
 
+#define to_omap_plane_state(x) container_of(x, struct omap_plane_state, base)
+
+struct omap_plane_state {
+	struct drm_plane_state base;
+};
+
 #define to_omap_plane(x) container_of(x, struct omap_plane, base)
 
 struct omap_plane {
@@ -202,14 +208,29 @@ void omap_plane_install_properties(struct drm_plane *plane,
 	drm_object_attach_property(obj, priv->zorder_prop, 0);
 }
 
+static void omap_plane_atomic_destroy_state(struct drm_plane *plane,
+					    struct drm_plane_state *state)
+{
+	__drm_atomic_helper_plane_destroy_state(state);
+	kfree(to_omap_plane_state(state));
+}
+
 static void omap_plane_reset(struct drm_plane *plane)
 {
 	struct omap_plane *omap_plane = to_omap_plane(plane);
+	struct omap_plane_state *omap_state;
 
-	drm_atomic_helper_plane_reset(plane);
-	if (!plane->state)
+	if (plane->state)
+		omap_plane_atomic_destroy_state(plane, plane->state);
+
+	omap_state = kzalloc(sizeof(*omap_state), GFP_KERNEL);
+	if (!omap_state)
 		return;
 
+	omap_state->base.plane = plane;
+	plane->state = &omap_state->base;
+	plane->state->plane = plane;
+	plane->state->rotation = DRM_MODE_ROTATE_0;
 	/*
 	 * Set the zpos default depending on whether we are a primary or overlay
 	 * plane.
@@ -218,6 +239,25 @@ static void omap_plane_reset(struct drm_plane *plane)
 			   ? 0 : omap_plane->overlay->overlay_id;
 }
 
+static struct drm_plane_state *
+omap_plane_atomic_duplicate_state(struct drm_plane *plane)
+{
+	struct omap_plane_state *state;
+	struct omap_plane_state *copy;
+
+	if (WARN_ON(!plane->state))
+		return NULL;
+
+	state = to_omap_plane_state(plane->state);
+	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
+	if (!copy)
+		return NULL;
+
+	__drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
+
+	return &copy->base;
+}
+
 static int omap_plane_atomic_set_property(struct drm_plane *plane,
 					  struct drm_plane_state *state,
 					  struct drm_property *property,
@@ -253,8 +293,8 @@ static const struct drm_plane_funcs omap_plane_funcs = {
 	.disable_plane = drm_atomic_helper_disable_plane,
 	.reset = omap_plane_reset,
 	.destroy = omap_plane_destroy,
-	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
-	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+	.atomic_duplicate_state = omap_plane_atomic_duplicate_state,
+	.atomic_destroy_state = omap_plane_atomic_destroy_state,
 	.atomic_set_property = omap_plane_atomic_set_property,
 	.atomic_get_property = omap_plane_atomic_get_property,
 };
Signature · 1 line
2.9.0
#5 lore raw

PATCH v4 5/8 drm/omap: Add global state as a private atomic object

In reply to Benoit Parrot

Global shared resources (like hw overlays) for omapdrm are implemented as a part of atomic state using the drm_private_obj infrastructure available in the atomic core.

omap_global_state is introduced as a drm atomic private object. The two funcs omap_get_global_state() and omap_get_existing_global_state() are the two variants that will be used to access omap_global_state.

---
 drivers/gpu/drm/omapdrm/omap_drv.c | 97 +++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/omapdrm/omap_drv.h | 23 +++++++++
 2 files changed, 119 insertions(+), 1 deletion(-)
drivers/gpu/drm/omapdrm/omap_drv.c +96 -1
index 2921cc90f2d8..94658ec79c76 100644
@@ -129,6 +129,94 @@ static const struct drm_mode_config_funcs omap_mode_config_funcs = {
 	.atomic_commit = drm_atomic_helper_commit,
 };
 
+/* Global/shared object state funcs */
+
+/*
+ * This is a helper that returns the private state currently in operation.
+ * Note that this would return the "old_state" if called in the atomic check
+ * path, and the "new_state" after the atomic swap has been done.
+ */
+struct omap_global_state *
+omap_get_existing_global_state(struct omap_drm_private *priv)
+{
+	return to_omap_global_state(priv->glob_obj.state);
+}
+
+/*
+ * This acquires the modeset lock set aside for global state, creates
+ * a new duplicated private object state.
+ */
+struct omap_global_state *__must_check
+omap_get_global_state(struct drm_atomic_state *s)
+{
+	struct omap_drm_private *priv = s->dev->dev_private;
+	struct drm_private_state *priv_state;
+	int ret;
+
+	if (!drm_modeset_is_locked(&priv->glob_obj_lock)) {
+		ret = drm_modeset_lock(&priv->glob_obj_lock, s->acquire_ctx);
+		if (ret) {
+			DBG("getting priv->glob_obj_lock (%p) failed %d",
+			    &priv->glob_obj_lock, ret);
+			return ERR_PTR(ret);
+		}
+	}
+
+	priv_state = drm_atomic_get_private_obj_state(s, &priv->glob_obj);
+	if (IS_ERR(priv_state))
+		return ERR_CAST(priv_state);
+
+	return to_omap_global_state(priv_state);
+}
+
+static struct drm_private_state *
+omap_global_duplicate_state(struct drm_private_obj *obj)
+{
+	struct omap_global_state *state;
+
+	state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
+
+	return &state->base;
+}
+
+static void omap_global_destroy_state(struct drm_private_obj *obj,
+				      struct drm_private_state *state)
+{
+	struct omap_global_state *omap_state = to_omap_global_state(state);
+
+	kfree(omap_state);
+}
+
+static const struct drm_private_state_funcs omap_global_state_funcs = {
+	.atomic_duplicate_state = omap_global_duplicate_state,
+	.atomic_destroy_state = omap_global_destroy_state,
+};
+
+static int omap_global_obj_init(struct omap_drm_private *priv)
+{
+	struct omap_global_state *state;
+
+	drm_modeset_lock_init(&priv->glob_obj_lock);
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	drm_atomic_private_obj_init(&priv->glob_obj, &state->base,
+				    &omap_global_state_funcs);
+	return 0;
+}
+
+static void omap_global_obj_fini(struct omap_drm_private *priv)
+{
+	drm_atomic_private_obj_fini(&priv->glob_obj);
+	drm_modeset_lock_fini(&priv->glob_obj_lock);
+}
+
 static void omap_disconnect_pipelines(struct drm_device *ddev)
 {
 	struct omap_drm_private *priv = ddev->dev_private;
@@ -569,10 +657,14 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
 
 	omap_gem_init(ddev);
 
-	ret = omap_hwoverlays_init(priv);
+	ret = omap_global_obj_init(priv);
 	if (ret)
 		goto err_gem_deinit;
 
+	ret = omap_hwoverlays_init(priv);
+	if (ret)
+		goto err_free_priv_obj;
+
 	ret = omap_modeset_init(ddev);
 	if (ret) {
 		dev_err(priv->dev, "omap_modeset_init failed: ret=%d\n", ret);
@@ -612,6 +704,8 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
 err_cleanup_modeset:
 	drm_mode_config_cleanup(ddev);
 	omap_drm_irq_uninstall(ddev);
+err_free_priv_obj:
+	omap_global_obj_fini(priv);
 err_free_overlays:
 	omap_hwoverlays_destroy(priv);
 err_gem_deinit:
@@ -644,6 +738,7 @@ static void omapdrm_cleanup(struct omap_drm_private *priv)
 	omap_drm_irq_uninstall(ddev);
 	omap_gem_deinit(ddev);
 
+	omap_global_obj_fini(priv);
 	omap_hwoverlays_destroy(priv);
 
 	destroy_workqueue(priv->wq);
drivers/gpu/drm/omapdrm/omap_drv.h +23 -0
index 929f04e7cc3b..f374dc100447 100644
@@ -23,6 +23,7 @@
 #include <linux/workqueue.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_gem.h>
 #include <drm/omap_drm.h>
@@ -54,6 +55,17 @@ struct omap_drm_pipeline {
 	struct omap_dss_device *display;
 };
 
+/*
+ * Global private object state for tracking resources that are shared across
+ * multiple kms objects (planes/crtcs/etc).
+ */
+#define to_omap_global_state(x) container_of(x, struct omap_global_state, base)
+struct omap_global_state {
+	struct drm_private_state base;
+
+	struct drm_atomic_state *state;
+};
+
 struct omap_drm_private {
 	struct drm_device *ddev;
 	struct device *dev;
@@ -73,6 +85,13 @@ struct omap_drm_private {
 	unsigned int num_ovls;
 	struct omap_hw_overlay *overlays[8];
 
+	/*
+	 * Global private object state, Do not access directly, use
+	 * omap_global_get_state()
+	 */
+	struct drm_modeset_lock glob_obj_lock;
+	struct drm_private_obj glob_obj;
+
 	struct drm_fb_helper *fbdev;
 
 	struct workqueue_struct *wq;
@@ -100,5 +119,9 @@ struct omap_drm_private {
 
 
 int omap_debugfs_init(struct drm_minor *minor);
+struct omap_global_state *__must_check
+omap_get_global_state(struct drm_atomic_state *s);
+struct omap_global_state *
+omap_get_existing_global_state(struct omap_drm_private *priv);
 
 #endif /* __OMAPDRM_DRV_H__ */
Signature · 1 line
2.9.0
#6 lore raw

Re: [Patch v4 5/8] drm/omap: Add global state as a private atomic object

Quoted 46 lines · Benoit Parrot

Global shared resources (like hw overlays) for omapdrm are implemented as a part of atomic state using the drm_private_obj infrastructure available in the atomic core.

omap_global_state is introduced as a drm atomic private object. The two funcs omap_get_global_state() and omap_get_existing_global_state() are the two variants that will be used to access omap_global_state.

---
 drivers/gpu/drm/omapdrm/omap_drv.c | 97 +++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/omapdrm/omap_drv.h | 23 +++++++++
 2 files changed, 119 insertions(+), 1 deletion(-)
drivers/gpu/drm/omapdrm/omap_drv.c +24 -0
index 2921cc90f2d8..94658ec79c76 100644
@@ -129,6 +129,94 @@ static const struct drm_mode_config_funcs omap_mode_config_funcs = {
 	.atomic_commit = drm_atomic_helper_commit,
 };
 
+/* Global/shared object state funcs */
+
+/*
+ * This is a helper that returns the private state currently in operation.
+ * Note that this would return the "old_state" if called in the atomic check
+ * path, and the "new_state" after the atomic swap has been done.
+ */
+struct omap_global_state *
+omap_get_existing_global_state(struct omap_drm_private *priv)
+{
+	return to_omap_global_state(priv->glob_obj.state);
+}
+
+/*
+ * This acquires the modeset lock set aside for global state, creates
+ * a new duplicated private object state.
+ */
+struct omap_global_state *__must_check
+omap_get_global_state(struct drm_atomic_state *s)
+{
+	struct omap_drm_private *priv = s->dev->dev_private;
+	struct drm_private_state *priv_state;
+	int ret;
+

drivers/gpu/drm/omapdrm/omap_drv.c static const struct drm_mode_config_funcs omap_mode_config_funcs = { · line 165

Quoted 10 lines
drivers/gpu/drm/omapdrm/omap_drv.c +10 -0
+	if (!drm_modeset_is_locked(&priv->glob_obj_lock)) {
+		ret = drm_modeset_lock(&priv->glob_obj_lock, s->acquire_ctx);
+		if (ret) {
+			DBG("getting priv->glob_obj_lock (%p) failed %d",
+			    &priv->glob_obj_lock, ret);
+			return ERR_PTR(ret);
+		}
+	}
+
+	priv_state = drm_atomic_get_private_obj_state(s, &priv->glob_obj);

One of the refactors I had in mind (and which would be possible now that private state structs are implemented as properly structs, instead of void
* pointers): Add a drm_modeset_lock to drm_private_obj and avoid having to duplicate that over all implementations. Not everyone wants a per-obj lock, but no one will be hurt by having a per-obj lock - drm_modeset_lock is very extensible in that way. And we could drop the custom locking code everyone has to roll themselves.

Just a drive-by refactor idea.
-Daniel

Quoted 147 lines
drivers/gpu/drm/omapdrm/omap_drv.c +62 -1
+	if (IS_ERR(priv_state))
+		return ERR_CAST(priv_state);
+
+	return to_omap_global_state(priv_state);
+}
+
+static struct drm_private_state *
+omap_global_duplicate_state(struct drm_private_obj *obj)
+{
+	struct omap_global_state *state;
+
+	state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
+
+	return &state->base;
+}
+
+static void omap_global_destroy_state(struct drm_private_obj *obj,
+				      struct drm_private_state *state)
+{
+	struct omap_global_state *omap_state = to_omap_global_state(state);
+
+	kfree(omap_state);
+}
+
+static const struct drm_private_state_funcs omap_global_state_funcs = {
+	.atomic_duplicate_state = omap_global_duplicate_state,
+	.atomic_destroy_state = omap_global_destroy_state,
+};
+
+static int omap_global_obj_init(struct omap_drm_private *priv)
+{
+	struct omap_global_state *state;
+
+	drm_modeset_lock_init(&priv->glob_obj_lock);
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return -ENOMEM;
+
+	drm_atomic_private_obj_init(&priv->glob_obj, &state->base,
+				    &omap_global_state_funcs);
+	return 0;
+}
+
+static void omap_global_obj_fini(struct omap_drm_private *priv)
+{
+	drm_atomic_private_obj_fini(&priv->glob_obj);
+	drm_modeset_lock_fini(&priv->glob_obj_lock);
+}
+
 static void omap_disconnect_pipelines(struct drm_device *ddev)
 {
 	struct omap_drm_private *priv = ddev->dev_private;
@@ -569,10 +657,14 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
 
 	omap_gem_init(ddev);
 
-	ret = omap_hwoverlays_init(priv);
+	ret = omap_global_obj_init(priv);
 	if (ret)
 		goto err_gem_deinit;
 
+	ret = omap_hwoverlays_init(priv);
+	if (ret)
+		goto err_free_priv_obj;
+
 	ret = omap_modeset_init(ddev);
 	if (ret) {
 		dev_err(priv->dev, "omap_modeset_init failed: ret=%d\n", ret);
@@ -612,6 +704,8 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
 err_cleanup_modeset:
 	drm_mode_config_cleanup(ddev);
 	omap_drm_irq_uninstall(ddev);
+err_free_priv_obj:
+	omap_global_obj_fini(priv);
 err_free_overlays:
 	omap_hwoverlays_destroy(priv);
 err_gem_deinit:
@@ -644,6 +738,7 @@ static void omapdrm_cleanup(struct omap_drm_private *priv)
 	omap_drm_irq_uninstall(ddev);
 	omap_gem_deinit(ddev);
 
+	omap_global_obj_fini(priv);
 	omap_hwoverlays_destroy(priv);
 
 	destroy_workqueue(priv->wq);
drivers/gpu/drm/omapdrm/omap_drv.h +23 -0
index 929f04e7cc3b..f374dc100447 100644
@@ -23,6 +23,7 @@
 #include <linux/workqueue.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_gem.h>
 #include <drm/omap_drm.h>
@@ -54,6 +55,17 @@ struct omap_drm_pipeline {
 	struct omap_dss_device *display;
 };
 
+/*
+ * Global private object state for tracking resources that are shared across
+ * multiple kms objects (planes/crtcs/etc).
+ */
+#define to_omap_global_state(x) container_of(x, struct omap_global_state, base)
+struct omap_global_state {
+	struct drm_private_state base;
+
+	struct drm_atomic_state *state;
+};
+
 struct omap_drm_private {
 	struct drm_device *ddev;
 	struct device *dev;
@@ -73,6 +85,13 @@ struct omap_drm_private {
 	unsigned int num_ovls;
 	struct omap_hw_overlay *overlays[8];
 
+	/*
+	 * Global private object state, Do not access directly, use
+	 * omap_global_get_state()
+	 */
+	struct drm_modeset_lock glob_obj_lock;
+	struct drm_private_obj glob_obj;
+
 	struct drm_fb_helper *fbdev;
 
 	struct workqueue_struct *wq;
@@ -100,5 +119,9 @@ struct omap_drm_private {
 
 
 int omap_debugfs_init(struct drm_minor *minor);
+struct omap_global_state *__must_check
+omap_get_global_state(struct drm_atomic_state *s);
+struct omap_global_state *
+omap_get_existing_global_state(struct omap_drm_private *priv);
 
 #endif /* __OMAPDRM_DRV_H__ */
Signature · 1 line
2.9.0
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
#7 lore raw

Re: [Patch v4 5/8] drm/omap: Add global state as a private atomic object

Daniel Vetter <[email protected]> wrote on Tue [2018-Oct-16 14:29:46 +0200]:

Quoted 58 lines · Benoit Parrot
Quoted 46 lines

Global shared resources (like hw overlays) for omapdrm are implemented as a part of atomic state using the drm_private_obj infrastructure available in the atomic core.

omap_global_state is introduced as a drm atomic private object. The two funcs omap_get_global_state() and omap_get_existing_global_state() are the two variants that will be used to access omap_global_state.

---
 drivers/gpu/drm/omapdrm/omap_drv.c | 97 +++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/omapdrm/omap_drv.h | 23 +++++++++
 2 files changed, 119 insertions(+), 1 deletion(-)
drivers/gpu/drm/omapdrm/omap_drv.c +24 -0
index 2921cc90f2d8..94658ec79c76 100644
@@ -129,6 +129,94 @@ static const struct drm_mode_config_funcs omap_mode_config_funcs = {
 	.atomic_commit = drm_atomic_helper_commit,
 };
 
+/* Global/shared object state funcs */
+
+/*
+ * This is a helper that returns the private state currently in operation.
+ * Note that this would return the "old_state" if called in the atomic check
+ * path, and the "new_state" after the atomic swap has been done.
+ */
+struct omap_global_state *
+omap_get_existing_global_state(struct omap_drm_private *priv)
+{
+	return to_omap_global_state(priv->glob_obj.state);
+}
+
+/*
+ * This acquires the modeset lock set aside for global state, creates
+ * a new duplicated private object state.
+ */
+struct omap_global_state *__must_check
+omap_get_global_state(struct drm_atomic_state *s)
+{
+	struct omap_drm_private *priv = s->dev->dev_private;
+	struct drm_private_state *priv_state;
+	int ret;
+

drivers/gpu/drm/omapdrm/omap_drv.c static const struct drm_mode_config_funcs omap_mode_config_funcs = { · line 165

Quoted 10 lines
drivers/gpu/drm/omapdrm/omap_drv.c +10 -0
+	if (!drm_modeset_is_locked(&priv->glob_obj_lock)) {
+		ret = drm_modeset_lock(&priv->glob_obj_lock, s->acquire_ctx);
+		if (ret) {
+			DBG("getting priv->glob_obj_lock (%p) failed %d",
+			    &priv->glob_obj_lock, ret);
+			return ERR_PTR(ret);
+		}
+	}
+
+	priv_state = drm_atomic_get_private_obj_state(s, &priv->glob_obj);
Quoted 7 lines

One of the refactors I had in mind (and which would be possible now that private state structs are implemented as properly structs, instead of void
* pointers): Add a drm_modeset_lock to drm_private_obj and avoid having to duplicate that over all implementations. Not everyone wants a per-obj lock, but no one will be hurt by having a per-obj lock - drm_modeset_lock is very extensible in that way. And we could drop the custom locking code everyone has to roll themselves.

Thanks for the feedback. I was wondering the same when I was "duplicating" this code. I will take this under advisement, but I would probably see that as a separate patch set, either before or after this one :)

Benoit

Quoted 3 lines

Just a drive-by refactor idea.
-Daniel

#8 lore raw

Re: [Patch v4 5/8] drm/omap: Add global state as a private atomic object

Quoted 67 lines · Benoit Parrot

Daniel Vetter <[email protected]> wrote on Tue [2018-Oct-16 14:29:46 +0200]:

Quoted 58 lines · Benoit Parrot
Quoted 46 lines

Global shared resources (like hw overlays) for omapdrm are implemented as a part of atomic state using the drm_private_obj infrastructure available in the atomic core.

omap_global_state is introduced as a drm atomic private object. The two funcs omap_get_global_state() and omap_get_existing_global_state() are the two variants that will be used to access omap_global_state.

---
 drivers/gpu/drm/omapdrm/omap_drv.c | 97 +++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/omapdrm/omap_drv.h | 23 +++++++++
 2 files changed, 119 insertions(+), 1 deletion(-)
drivers/gpu/drm/omapdrm/omap_drv.c +24 -0
index 2921cc90f2d8..94658ec79c76 100644
@@ -129,6 +129,94 @@ static const struct drm_mode_config_funcs omap_mode_config_funcs = {
 	.atomic_commit = drm_atomic_helper_commit,
 };
 
+/* Global/shared object state funcs */
+
+/*
+ * This is a helper that returns the private state currently in operation.
+ * Note that this would return the "old_state" if called in the atomic check
+ * path, and the "new_state" after the atomic swap has been done.
+ */
+struct omap_global_state *
+omap_get_existing_global_state(struct omap_drm_private *priv)
+{
+	return to_omap_global_state(priv->glob_obj.state);
+}
+
+/*
+ * This acquires the modeset lock set aside for global state, creates
+ * a new duplicated private object state.
+ */
+struct omap_global_state *__must_check
+omap_get_global_state(struct drm_atomic_state *s)
+{
+	struct omap_drm_private *priv = s->dev->dev_private;
+	struct drm_private_state *priv_state;
+	int ret;
+

drivers/gpu/drm/omapdrm/omap_drv.c static const struct drm_mode_config_funcs omap_mode_config_funcs = { · line 165

Quoted 10 lines
drivers/gpu/drm/omapdrm/omap_drv.c +10 -0
+	if (!drm_modeset_is_locked(&priv->glob_obj_lock)) {
+		ret = drm_modeset_lock(&priv->glob_obj_lock, s->acquire_ctx);
+		if (ret) {
+			DBG("getting priv->glob_obj_lock (%p) failed %d",
+			    &priv->glob_obj_lock, ret);
+			return ERR_PTR(ret);
+		}
+	}
+
+	priv_state = drm_atomic_get_private_obj_state(s, &priv->glob_obj);
Quoted 7 lines

One of the refactors I had in mind (and which would be possible now that private state structs are implemented as properly structs, instead of void
* pointers): Add a drm_modeset_lock to drm_private_obj and avoid having to duplicate that over all implementations. Not everyone wants a per-obj lock, but no one will be hurt by having a per-obj lock - drm_modeset_lock is very extensible in that way. And we could drop the custom locking code everyone has to roll themselves.

Quoted 3 lines

Thanks for the feedback. I was wondering the same when I was "duplicating" this code. I will take this under advisement, but I would probably see that as a separate patch set, either before or after this one :)

Sure. Also note that this came up with a recent vc4 patch series by Boris Brezillion "[RFC PATCH] drm/vc4: Add a load tracker to prevent HVS underflow errors", so maybe you folks can work together. -Daniel

Signature · 7 lines
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#9 lore raw

PATCH v4 6/8 drm/omap: dynamically assign hw overlays to planes

In reply to Benoit Parrot

(re)assign the hw overlays to planes based on required caps, and to handle situations where we could not modify an in-use plane.

This means all planes advertise the superset of formats and properties. Userspace must (as always) use atomic TEST_ONLY step for atomic updates, as not all planes may be available for use on every frame.

The mapping of hwoverlays to plane is stored in omap_global_state, so that state updates are atomically committed in the same way that plane/etc state updates are managed. This is needed because the omap_plane_state keeps a pointer to the hwoverlay, and we don't want global state to become out of sync with the plane state if an atomic update fails, we hit deadlock/ backoff scenario, etc. The use of global_state_lock keeps multiple parallel updates which both re-assign hwoverlays properly serialized.

---
 drivers/gpu/drm/omapdrm/omap_drv.h     |   3 +
 drivers/gpu/drm/omapdrm/omap_overlay.c | 143 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/omapdrm/omap_overlay.h |   9 ++
 drivers/gpu/drm/omapdrm/omap_plane.c   | 153 ++++++++++++++++++++++++++-------
 4 files changed, 276 insertions(+), 32 deletions(-)
drivers/gpu/drm/omapdrm/omap_drv.h +3 -0
index f374dc100447..00326f2a2c2c 100644
@@ -64,6 +64,9 @@ struct omap_global_state {
 	struct drm_private_state base;
 
 	struct drm_atomic_state *state;
+
+	/* global atomic state of assignment between overlays and planes */
+	struct drm_plane *hwoverlay_to_plane[8];
 };
 
 struct omap_drm_private {
drivers/gpu/drm/omapdrm/omap_overlay.c +143 -0

149 lines not on this page · raw message

drivers/gpu/drm/omapdrm/omap_overlay.h +9 -0
index 892fecb67adb..d5033ee481c2 100644
@@ -28,4 +28,13 @@ struct omap_hw_overlay {
 
 int omap_hwoverlays_init(struct omap_drm_private *priv);
 void omap_hwoverlays_destroy(struct omap_drm_private *priv);
+int omap_overlay_assign(struct drm_atomic_state *s, struct drm_plane *plane,
+			u32 caps, u32 fourcc, u32 crtc_mask,
+			struct omap_hw_overlay **overlay);
+void omap_overlay_release(struct drm_atomic_state *s,
+			  struct drm_plane *plane,
+			  struct omap_hw_overlay *overlay);
+void omap_overlay_disable(struct drm_atomic_state *s,
+			  struct drm_plane *plane,
+			  struct omap_hw_overlay *overlay);
 #endif /* __OMAPDRM_OVERLAY_H__ */
drivers/gpu/drm/omapdrm/omap_plane.c +121 -32

240 lines not on this page · raw message

Signature · 6 lines
2.9.0

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#10 lore raw

PATCH v4 7/8 drm/omap: add plane_atomic_print_state support

In reply to Benoit Parrot

Now that we added specific item to our subclassed drm_plane_state we can add omap_plane_atomic_print_state() helper to dump out our own driver specific plane state.

---
 drivers/gpu/drm/omapdrm/omap_plane.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
drivers/gpu/drm/omapdrm/omap_plane.c +18 -0
index 224520348fc5..116071982a0e 100644
@@ -348,6 +348,23 @@ omap_plane_atomic_duplicate_state(struct drm_plane *plane)
 	return &copy->base;
 }
 
+static void omap_plane_atomic_print_state(struct drm_printer *p,
+					  const struct drm_plane_state *state)
+{
+	struct omap_plane_state *omap_state = to_omap_plane_state(state);
+
+	drm_printf(p, "\toverlay=%s\n", omap_state->overlay ?
+					omap_state->overlay->name : "(null)");
+	if (omap_state->overlay) {
+		drm_printf(p, "\t\tidx=%d\n", omap_state->overlay->idx);
+		drm_printf(p, "\t\toverlay_id=%d\n",
+			   omap_state->overlay->overlay_id);
+		drm_printf(p, "\t\tcaps=0x%x\n", omap_state->overlay->caps);
+		drm_printf(p, "\t\tpossible_crtcs=0x%x\n",
+			   omap_state->overlay->possible_crtcs);
+	}
+}
+
 static int omap_plane_atomic_set_property(struct drm_plane *plane,
 					  struct drm_plane_state *state,
 					  struct drm_property *property,
@@ -387,6 +404,7 @@ static const struct drm_plane_funcs omap_plane_funcs = {
 	.atomic_destroy_state = omap_plane_atomic_destroy_state,
 	.atomic_set_property = omap_plane_atomic_set_property,
 	.atomic_get_property = omap_plane_atomic_get_property,
+	.atomic_print_state = omap_plane_atomic_print_state,
 };
 
 static const char *plane_id_to_name[] = {
Signature · 1 line
2.9.0
#11 lore raw

PATCH v4 8/8 drm/omap: Add a 'right overlay' to plane state

In reply to Benoit Parrot

If the drm_plane has a source width that's greater than the max width supported by a single hw overlay, then we assign a 'r_overlay' to it in omap_plane_atomic_check().

Both overlays should have the capabilities required to handle the source framebuffer. The only parameters that vary between the left and right hwoverlays are the src_w, crtc_w, src_x and crtc_x as we just even chop the fb into left and right halves.

We also take care of not creating odd width size when dealing with YUV formats.

Since both halves need to be 'appear' side by side the zpos is recalculated when dealing with dual overlay cases so that the other planes zpos is consistent.

Depending on user space usage it is possible that on occasion the number of requested planes exceeds the numbers of overlays required to display them. In that case a failure would be returned for the plane that cannot be handled at that time. It is up to user space to make sure the H/W resource are not over-subscribed.

---
 drivers/gpu/drm/omapdrm/omap_drv.c     |  91 ++++++++++++++++++++++-
 drivers/gpu/drm/omapdrm/omap_fb.c      |  33 ++++++++-
 drivers/gpu/drm/omapdrm/omap_fb.h      |   4 +-
 drivers/gpu/drm/omapdrm/omap_overlay.c |  31 +++++++-
 drivers/gpu/drm/omapdrm/omap_overlay.h |   3 +-
 drivers/gpu/drm/omapdrm/omap_plane.c   | 128 +++++++++++++++++++++++++++++++--
 drivers/gpu/drm/omapdrm/omap_plane.h   |   1 +
 7 files changed, 278 insertions(+), 13 deletions(-)
drivers/gpu/drm/omapdrm/omap_drv.c +90 -1
index 94658ec79c76..307cd905fd02 100644
@@ -118,6 +118,95 @@ static void omap_atomic_commit_tail(struct drm_atomic_state *old_state)
 	priv->dispc_ops->runtime_put(priv->dispc);
 }
 
+static int drm_atomic_state_normalized_zpos_cmp(const void *a, const void *b)
+{
+	const struct drm_plane_state *sa = *(struct drm_plane_state **)a;
+	const struct drm_plane_state *sb = *(struct drm_plane_state **)b;
+
+	if (sa->normalized_zpos != sb->normalized_zpos)
+		return sa->normalized_zpos - sb->normalized_zpos;
+	else
+		return sa->plane->base.id - sb->plane->base.id;
+}
+
+static int omap_atomic_update_normalize_zpos(struct drm_device *dev,
+					     struct drm_atomic_state *state)
+{
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *old_state, *new_state;
+	struct drm_plane *plane;
+	int c, i, n, inc;
+	int total_planes = dev->mode_config.num_total_plane;
+	struct drm_plane_state **states;
+	int ret = 0;
+
+	states = kmalloc_array(total_planes, sizeof(*states), GFP_KERNEL);
+	if (!states)
+		return -ENOMEM;
+
+	for_each_oldnew_crtc_in_state(state, crtc, old_state, new_state, c) {
+		if (old_state->plane_mask == new_state->plane_mask &&
+		    !new_state->zpos_changed)
+			continue;
+
+		/* Reset plane increment and index value for every crtc */
+		n = 0;
+
+		/*
+		 * Normalization process might create new states for planes
+		 * which normalized_zpos has to be recalculated.
+		 */
+		drm_for_each_plane_mask(plane, dev, new_state->plane_mask) {
+			struct drm_plane_state *plane_state =
+				drm_atomic_get_plane_state(new_state->state,
+							   plane);
+			if (IS_ERR(plane_state)) {
+				ret = PTR_ERR(plane_state);
+				goto done;
+			}
+			states[n++] = plane_state;
+		}
+
+		sort(states, n, sizeof(*states),
+		     drm_atomic_state_normalized_zpos_cmp, NULL);
+
+		for (i = 0, inc = 0; i < n; i++) {
+			plane = states[i]->plane;
+
+			states[i]->normalized_zpos = i + inc;
+			DRM_DEBUG_ATOMIC("[PLANE:%d:%s] updated normalized zpos value %d\n",
+					 plane->base.id, plane->name,
+					 states[i]->normalized_zpos);
+
+			if (is_omap_plane_dual_overlay(states[i]))
+				inc++;
+		}
+		new_state->zpos_changed = true;
+	}
+
+done:
+	kfree(states);
+	return ret;
+}
+
+static int omap_atomic_check(struct drm_device *dev,
+			     struct drm_atomic_state *state)
+{
+	int ret;
+
+	ret = drm_atomic_helper_check(dev, state);
+	if (ret)
+		return ret;
+
+	if (dev->mode_config.normalize_zpos) {
+		ret = omap_atomic_update_normalize_zpos(dev, state);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 static const struct drm_mode_config_helper_funcs omap_mode_config_helper_funcs = {
 	.atomic_commit_tail = omap_atomic_commit_tail,
 };
@@ -125,7 +214,7 @@ static const struct drm_mode_config_helper_funcs omap_mode_config_helper_funcs =
 static const struct drm_mode_config_funcs omap_mode_config_funcs = {
 	.fb_create = omap_framebuffer_create,
 	.output_poll_changed = drm_fb_helper_output_poll_changed,
-	.atomic_check = drm_atomic_helper_check,
+	.atomic_check = omap_atomic_check,
 	.atomic_commit = drm_atomic_helper_commit,
 };
 
drivers/gpu/drm/omapdrm/omap_fb.c +32 -1
index 4d264fd554d8..13d7fa7b31fc 100644
@@ -123,7 +123,9 @@ static u32 drm_rotation_to_tiler(unsigned int drm_rot)
 /* update ovl info for scanout, handles cases of multi-planar fb's, etc.
  */
 void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
-		struct drm_plane_state *state, struct omap_overlay_info *info)
+		struct drm_plane_state *state,
+		struct omap_overlay_info *info,
+		struct omap_overlay_info *r_info)
 {
 	struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
 	const struct drm_format_info *format = omap_fb->format;
@@ -213,6 +215,35 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
 	} else {
 		info->p_uv_addr = 0;
 	}
+
+	if (r_info) {
+		info->width /= 2;
+		info->out_width /= 2;
+
+		*r_info = *info;
+
+		if (fb->format->is_yuv) {
+			if (info->width & 1) {
+				info->width++;
+				r_info->width--;
+			}
+
+			if (info->out_width & 1) {
+				info->out_width++;
+				r_info->out_width--;
+			}
+		}
+
+		r_info->pos_x = info->pos_x + info->out_width;
+
+		r_info->paddr =	get_linear_addr(fb, format, 0,
+						x + info->width, y);
+		if (fb->format->format == DRM_FORMAT_NV12) {
+			r_info->p_uv_addr =
+				get_linear_addr(fb, format, 1,
+						x + info->width, y);
+		}
+	}
 }
 
 /* pin, prepare for scanout: */
drivers/gpu/drm/omapdrm/omap_fb.h +3 -1
index c20cb4bc714d..a649fce0f0f1 100644
@@ -37,7 +37,9 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
 int omap_framebuffer_pin(struct drm_framebuffer *fb);
 void omap_framebuffer_unpin(struct drm_framebuffer *fb);
 void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
-		struct drm_plane_state *state, struct omap_overlay_info *info);
+		struct drm_plane_state *state,
+		struct omap_overlay_info *info,
+		struct omap_overlay_info *r_info);
 bool omap_framebuffer_supports_rotation(struct drm_framebuffer *fb);
 void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m);
 
drivers/gpu/drm/omapdrm/omap_overlay.c +29 -2
index 3a58582cd56f..d27b4c3d769b 100644
@@ -65,12 +65,14 @@ omap_plane_find_free_overlay(struct drm_device *dev,
 
 int omap_overlay_assign(struct drm_atomic_state *s, struct drm_plane *plane,
 			u32 caps, u32 fourcc, u32 crtc_mask,
-			struct omap_hw_overlay **overlay)
+			struct omap_hw_overlay **overlay,
+			struct omap_hw_overlay **r_overlay)
 {
 	struct omap_drm_private *priv = s->dev->dev_private;
 	struct omap_global_state *new_global_state, *old_global_state;
 	struct drm_plane **overlay_map;
-	struct omap_hw_overlay *ovl;
+	struct omap_hw_overlay *ovl, *r_ovl;
+	u32 save_possible_crtcs;
 
 	new_global_state = omap_get_global_state(s);
 	if (IS_ERR(new_global_state))
@@ -92,12 +94,37 @@ int omap_overlay_assign(struct drm_atomic_state *s, struct drm_plane *plane,
 		if (!ovl)
 			return -ENOMEM;
 
+		/* in case we need to backtrack */
+		save_possible_crtcs = ovl->possible_crtcs;
+
 		ovl->possible_crtcs = crtc_mask;
 		overlay_map[ovl->idx] = plane;
 		*overlay = ovl;
 
+		if (r_overlay) {
+			r_ovl = omap_plane_find_free_overlay(s->dev,
+							     overlay_map,
+							     caps, fourcc,
+							     crtc_mask);
+			if (!r_ovl) {
+				ovl->possible_crtcs = save_possible_crtcs;
+				overlay_map[ovl->idx] = NULL;
+				*overlay = NULL;
+				return -ENOMEM;
+			}
+
+			r_ovl->possible_crtcs = crtc_mask;
+			overlay_map[r_ovl->idx] = plane;
+			*r_overlay = r_ovl;
+		}
+
 		DBG("%s: assign to plane %s caps %x on crtc %x",
 		    (*overlay)->name, plane->name, caps, crtc_mask);
+
+		if (r_overlay) {
+			DBG("%s: assign to right of plane %s caps %x on crtc %x",
+			    (*r_overlay)->name, plane->name, caps, crtc_mask);
+		}
 	}
 
 	return 0;
drivers/gpu/drm/omapdrm/omap_overlay.h +2 -1
index d5033ee481c2..a800468511f1 100644
@@ -30,7 +30,8 @@ int omap_hwoverlays_init(struct omap_drm_private *priv);
 void omap_hwoverlays_destroy(struct omap_drm_private *priv);
 int omap_overlay_assign(struct drm_atomic_state *s, struct drm_plane *plane,
 			u32 caps, u32 fourcc, u32 crtc_mask,
-			struct omap_hw_overlay **overlay);
+			struct omap_hw_overlay **overlay,
+			struct omap_hw_overlay **r_overlay);
 void omap_overlay_release(struct drm_atomic_state *s,
 			  struct drm_plane *plane,
 			  struct omap_hw_overlay *overlay);
drivers/gpu/drm/omapdrm/omap_plane.c +121 -7

233 lines not on this page · raw message

drivers/gpu/drm/omapdrm/omap_plane.h +1 -0
index dc5e82ad061d..ea31af8b6aa6 100644
@@ -33,5 +33,6 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
 		u32 possible_crtcs);
 void omap_plane_install_properties(struct drm_plane *plane,
 		struct drm_mode_object *obj);
+bool is_omap_plane_dual_overlay(struct drm_plane_state *state);
 
 #endif /* __OMAPDRM_PLANE_H__ */
Signature · 1 line
2.9.0
#12 lore raw
In reply to Benoit Parrot

Ping.

Benoit

Benoit Parrot <[email protected]> wrote on Fri [2018-Oct-12 15:16:55 -0500]:

Quoted 25 lines

This patch series adds virtual-plane support to omapdrm driver to allow the use of display wider than 2048 pixels.

In order to do so we introduce the concept of hw_overlay which can then be dynamically allocated to a plane. When the requested output width exceed what be supported by one overlay a second is then allocated if possible to handle display wider then 2048.

This series replaces an earlier series which was DT based and using statically allocated resources.

This implementation is inspired from the work done in msm/disp/mdp5 driver.

Benoit Parrot (8):
drm/omap: Add ability to check if requested plane modes can be
supported
drm/omap: Add ovl checking funcs to dispc_ops drm/omap: introduce omap_hw_overlay
drm/omap: omap_plane: subclass drm_plane_state drm/omap: Add global state as a private atomic object drm/omap: dynamically assign hw overlays to planes drm/omap: add plane_atomic_print_state support drm/omap: Add a 'right overlay' to plane state

Quoted 18 lines
 drivers/gpu/drm/omapdrm/Makefile       |   1 +
 drivers/gpu/drm/omapdrm/dss/dispc.c    |  32 +++
 drivers/gpu/drm/omapdrm/dss/omapdss.h  |   6 +
 drivers/gpu/drm/omapdrm/omap_drv.c     | 196 ++++++++++++++++-
 drivers/gpu/drm/omapdrm/omap_drv.h     |  30 +++
 drivers/gpu/drm/omapdrm/omap_fb.c      |  33 ++-
 drivers/gpu/drm/omapdrm/omap_fb.h      |   4 +-
 drivers/gpu/drm/omapdrm/omap_overlay.c | 257 ++++++++++++++++++++++
 drivers/gpu/drm/omapdrm/omap_overlay.h |  41 ++++
 drivers/gpu/drm/omapdrm/omap_plane.c   | 374 ++++++++++++++++++++++++++++-----
 drivers/gpu/drm/omapdrm/omap_plane.h   |   1 +
 11 files changed, 922 insertions(+), 53 deletions(-)
 create mode 100644 drivers/gpu/drm/omapdrm/omap_overlay.c
 create mode 100644 drivers/gpu/drm/omapdrm/omap_overlay.h
Signature · 1 line
2.9.0

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel