linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [Patch v4 0/8] drm/omap: Add virtual-planes support
@ 2018-10-12 20:16 Benoit Parrot
  2018-10-12 20:16 ` [Patch v4 1/8] drm/omap: Add ability to check if requested plane modes can be supported Benoit Parrot
                   ` (8 more replies)
  0 siblings, 9 replies; 13+ messages in thread
From: Benoit Parrot @ 2018-10-12 20:16 UTC (permalink / raw)
  To: dri-devel, linux-kernel, Laurent Pinchart, Daniel Vetter
  Cc: Tomi Valkeinen, Peter Ujfalusi, Jyri Sarha, Benoit Parrot

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

-- 
2.9.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Patch v4 1/8] drm/omap: Add ability to check if requested plane modes can be supported
  2018-10-12 20:16 [Patch v4 0/8] drm/omap: Add virtual-planes support Benoit Parrot
@ 2018-10-12 20:16 ` Benoit Parrot
  2018-10-12 20:16 ` [Patch v4 2/8] drm/omap: Add ovl checking funcs to dispc_ops Benoit Parrot
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Benoit Parrot @ 2018-10-12 20:16 UTC (permalink / raw)
  To: dri-devel, linux-kernel, Laurent Pinchart, Daniel Vetter
  Cc: Tomi Valkeinen, Peter Ujfalusi, Jyri Sarha, Benoit Parrot

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().

Signed-off-by: Benoit Parrot <bparrot@ti.com>
---
 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(+)

diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c
index fe0b5f6ede72..70c3e3353947 100644
--- a/drivers/gpu/drm/omapdrm/dss/dispc.c
+++ b/drivers/gpu/drm/omapdrm/dss/dispc.c
@@ -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,
diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h
index 1f698a95a94a..45334d5c618e 100644
--- a/drivers/gpu/drm/omapdrm/dss/omapdss.h
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h
@@ -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,
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index 161233cbc9a0..e1e338e76841 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -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;
-- 
2.9.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Patch v4 2/8] drm/omap: Add ovl checking funcs to dispc_ops
  2018-10-12 20:16 [Patch v4 0/8] drm/omap: Add virtual-planes support Benoit Parrot
  2018-10-12 20:16 ` [Patch v4 1/8] drm/omap: Add ability to check if requested plane modes can be supported Benoit Parrot
@ 2018-10-12 20:16 ` Benoit Parrot
  2018-10-12 20:16 ` [Patch v4 3/8] drm/omap: introduce omap_hw_overlay Benoit Parrot
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Benoit Parrot @ 2018-10-12 20:16 UTC (permalink / raw)
  To: dri-devel, linux-kernel, Laurent Pinchart, Daniel Vetter
  Cc: Tomi Valkeinen, Peter Ujfalusi, Jyri Sarha, 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.

Signed-off-by: Benoit Parrot <bparrot@ti.com>
---
 drivers/gpu/drm/omapdrm/dss/dispc.c   | 8 ++++++++
 drivers/gpu/drm/omapdrm/dss/omapdss.h | 4 ++++
 2 files changed, 12 insertions(+)

diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c
index 70c3e3353947..ea8b57003620 100644
--- a/drivers/gpu/drm/omapdrm/dss/dispc.c
+++ b/drivers/gpu/drm/omapdrm/dss/dispc.c
@@ -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,
diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h
index 45334d5c618e..b5640e8479dc 100644
--- a/drivers/gpu/drm/omapdrm/dss/omapdss.h
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h
@@ -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);
 
-- 
2.9.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Patch v4 3/8] drm/omap: introduce omap_hw_overlay
  2018-10-12 20:16 [Patch v4 0/8] drm/omap: Add virtual-planes support Benoit Parrot
  2018-10-12 20:16 ` [Patch v4 1/8] drm/omap: Add ability to check if requested plane modes can be supported Benoit Parrot
  2018-10-12 20:16 ` [Patch v4 2/8] drm/omap: Add ovl checking funcs to dispc_ops Benoit Parrot
@ 2018-10-12 20:16 ` Benoit Parrot
  2018-10-12 20:16 ` [Patch v4 4/8] drm/omap: omap_plane: subclass drm_plane_state Benoit Parrot
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Benoit Parrot @ 2018-10-12 20:16 UTC (permalink / raw)
  To: dri-devel, linux-kernel, Laurent Pinchart, Daniel Vetter
  Cc: Tomi Valkeinen, Peter Ujfalusi, Jyri Sarha, 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.

Signed-off-by: Benoit Parrot <bparrot@ti.com>
---
 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

diff --git a/drivers/gpu/drm/omapdrm/Makefile b/drivers/gpu/drm/omapdrm/Makefile
index f115253115c5..800dfd035360 100644
--- a/drivers/gpu/drm/omapdrm/Makefile
+++ b/drivers/gpu/drm/omapdrm/Makefile
@@ -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 \
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 5e67d58cbc28..2921cc90f2d8 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -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);
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
index bd7f2c227a25..929f04e7cc3b 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.h
+++ b/drivers/gpu/drm/omapdrm/omap_drv.h
@@ -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;
diff --git a/drivers/gpu/drm/omapdrm/omap_overlay.c b/drivers/gpu/drm/omapdrm/omap_overlay.c
new file mode 100644
index 000000000000..7a09b0aa823a
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/omap_overlay.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated -  http://www.ti.com/
+ * Author: Benoit Parrot, <bparrot@ti.com>
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+
+#include "omap_dmm_tiler.h"
+#include "omap_drv.h"
+
+/*
+ * overlay funcs
+ */
+static const char * const overlay_id_to_name[] = {
+	[OMAP_DSS_GFX] = "gfx",
+	[OMAP_DSS_VIDEO1] = "vid1",
+	[OMAP_DSS_VIDEO2] = "vid2",
+	[OMAP_DSS_VIDEO3] = "vid3",
+};
+
+static void omap_overlay_destroy(struct omap_hw_overlay *overlay)
+{
+	kfree(overlay);
+}
+
+static struct omap_hw_overlay *omap_overlay_init(enum omap_plane_id overlay_id,
+						 enum omap_overlay_caps caps)
+{
+	struct omap_hw_overlay *overlay;
+
+	overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
+	if (!overlay)
+		return ERR_PTR(-ENOMEM);
+
+	overlay->name = overlay_id_to_name[overlay_id];
+	overlay->overlay_id = overlay_id;
+	overlay->caps = caps;
+	/*
+	 * When this is called priv->num_crtcs is not known yet.
+	 * Use a safe mask value to start with, it will get updated to the
+	 * proper value after the first use.
+	 */
+	overlay->possible_crtcs = 0xff;
+
+	return overlay;
+}
+
+int omap_hwoverlays_init(struct omap_drm_private *priv)
+{
+	static const enum omap_plane_id hw_plane_ids[] = {
+			OMAP_DSS_GFX, OMAP_DSS_VIDEO1,
+			OMAP_DSS_VIDEO2, OMAP_DSS_VIDEO3,
+	};
+	u32 num_overlays = priv->dispc_ops->get_num_ovls(priv->dispc);
+	enum omap_overlay_caps caps;
+	int i, ret;
+
+	for (i = 0; i < num_overlays; i++) {
+		struct omap_hw_overlay *overlay;
+
+		caps = priv->dispc_ops->ovl_get_caps(priv->dispc, hw_plane_ids[i]);
+		overlay = omap_overlay_init(hw_plane_ids[i], caps);
+		if (IS_ERR(overlay)) {
+			ret = PTR_ERR(overlay);
+			dev_err(priv->dev, "failed to construct overlay for %s (%d)\n",
+				overlay_id_to_name[i], ret);
+			return ret;
+		}
+		overlay->idx = priv->num_ovls;
+		priv->overlays[priv->num_ovls++] = overlay;
+	}
+
+	return 0;
+}
+
+void omap_hwoverlays_destroy(struct omap_drm_private *priv)
+{
+	int i;
+
+	for (i = 0; i < priv->num_ovls; i++) {
+		omap_overlay_destroy(priv->overlays[i]);
+		priv->overlays[i] = NULL;
+	}
+}
diff --git a/drivers/gpu/drm/omapdrm/omap_overlay.h b/drivers/gpu/drm/omapdrm/omap_overlay.h
new file mode 100644
index 000000000000..892fecb67adb
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/omap_overlay.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated -  http://www.ti.com/
+ * Author: Benoit Parrot, <bparrot@ti.com>
+ */
+
+#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__ */
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index e1e338e76841..26c2c78d020f 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -32,6 +32,8 @@ struct omap_plane {
 	struct drm_plane base;
 	enum omap_plane_id id;
 	const char *name;
+
+	struct omap_hw_overlay *overlay;
 };
 
 static int omap_plane_prepare_fb(struct drm_plane *plane,
@@ -57,8 +59,11 @@ static void omap_plane_atomic_update(struct drm_plane *plane,
 	struct omap_plane *omap_plane = to_omap_plane(plane);
 	struct drm_plane_state *state = plane->state;
 	struct omap_overlay_info info;
+	enum omap_plane_id ovl_id = omap_plane->overlay->overlay_id;
 	int ret;
 
+	DBG("[PLANE:%d:%s] overlay_id: %d", plane->base.id, plane->name,
+	    ovl_id);
 	DBG("%s, crtc=%p fb=%p", omap_plane->name, state->crtc, state->fb);
 
 	memset(&info, 0, sizeof(info));
@@ -77,17 +82,17 @@ static void omap_plane_atomic_update(struct drm_plane *plane,
 			&info.paddr, &info.p_uv_addr);
 
 	/* and finally, update omapdss: */
-	ret = priv->dispc_ops->ovl_setup(priv->dispc, omap_plane->id, &info,
+	ret = priv->dispc_ops->ovl_setup(priv->dispc, ovl_id, &info,
 			      omap_crtc_timings(state->crtc), false,
 			      omap_crtc_channel(state->crtc));
 	if (ret) {
 		dev_err(plane->dev->dev, "Failed to setup plane %s\n",
 			omap_plane->name);
-		priv->dispc_ops->ovl_enable(priv->dispc, omap_plane->id, false);
+		priv->dispc_ops->ovl_enable(priv->dispc, ovl_id, false);
 		return;
 	}
 
-	priv->dispc_ops->ovl_enable(priv->dispc, omap_plane->id, true);
+	priv->dispc_ops->ovl_enable(priv->dispc, ovl_id, true);
 }
 
 static void omap_plane_atomic_disable(struct drm_plane *plane,
@@ -95,12 +100,13 @@ static void omap_plane_atomic_disable(struct drm_plane *plane,
 {
 	struct omap_drm_private *priv = plane->dev->dev_private;
 	struct omap_plane *omap_plane = to_omap_plane(plane);
+	enum omap_plane_id ovl_id = omap_plane->overlay->overlay_id;
 
 	plane->state->rotation = DRM_MODE_ROTATE_0;
 	plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY
-			   ? 0 : omap_plane->id;
+			   ? 0 : ovl_id;
 
-	priv->dispc_ops->ovl_enable(priv->dispc, omap_plane->id, false);
+	priv->dispc_ops->ovl_enable(priv->dispc, ovl_id, false);
 }
 
 static int omap_plane_atomic_check(struct drm_plane *plane,
@@ -209,7 +215,7 @@ static void omap_plane_reset(struct drm_plane *plane)
 	 * plane.
 	 */
 	plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY
-			   ? 0 : omap_plane->id;
+			   ? 0 : omap_plane->overlay->overlay_id;
 }
 
 static int omap_plane_atomic_set_property(struct drm_plane *plane,
@@ -260,13 +266,6 @@ static const char *plane_id_to_name[] = {
 	[OMAP_DSS_VIDEO3] = "vid3",
 };
 
-static const enum omap_plane_id plane_idx_to_id[] = {
-	OMAP_DSS_GFX,
-	OMAP_DSS_VIDEO1,
-	OMAP_DSS_VIDEO2,
-	OMAP_DSS_VIDEO3,
-};
-
 /* initialize plane */
 struct drm_plane *omap_plane_init(struct drm_device *dev,
 		int idx, enum drm_plane_type type,
@@ -276,27 +275,29 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
 	unsigned int num_planes = priv->dispc_ops->get_num_ovls(priv->dispc);
 	struct drm_plane *plane;
 	struct omap_plane *omap_plane;
-	enum omap_plane_id id;
 	int ret;
 	u32 nformats;
 	const u32 *formats;
 
-	if (WARN_ON(idx >= ARRAY_SIZE(plane_idx_to_id)))
+	if (WARN_ON(idx >= num_planes))
 		return ERR_PTR(-EINVAL);
 
-	id = plane_idx_to_id[idx];
-
-	DBG("%s: type=%d", plane_id_to_name[id], type);
-
 	omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
 	if (!omap_plane)
 		return ERR_PTR(-ENOMEM);
 
-	formats = priv->dispc_ops->ovl_get_color_modes(priv->dispc, id);
+	omap_plane->id = idx;
+	omap_plane->name = plane_id_to_name[idx];
+	omap_plane->overlay = priv->overlays[idx];
+
+	DBG("%s: type=%d", omap_plane->name, type);
+	DBG("	omap_plane->id: %d", omap_plane->id);
+	DBG("	crtc_mask: 0x%04x", possible_crtcs);
+
+	formats = priv->dispc_ops->ovl_get_color_modes(priv->dispc,
+						       omap_plane->overlay->overlay_id);
 	for (nformats = 0; formats[nformats]; ++nformats)
 		;
-	omap_plane->id = id;
-	omap_plane->name = plane_id_to_name[id];
 
 	plane = &omap_plane->base;
 
@@ -315,7 +316,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
 
 error:
 	dev_err(dev->dev, "%s(): could not create plane: %s\n",
-		__func__, plane_id_to_name[id]);
+		__func__, omap_plane->name);
 
 	kfree(omap_plane);
 	return NULL;
-- 
2.9.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Patch v4 4/8] drm/omap: omap_plane: subclass drm_plane_state
  2018-10-12 20:16 [Patch v4 0/8] drm/omap: Add virtual-planes support Benoit Parrot
                   ` (2 preceding siblings ...)
  2018-10-12 20:16 ` [Patch v4 3/8] drm/omap: introduce omap_hw_overlay Benoit Parrot
@ 2018-10-12 20:16 ` Benoit Parrot
  2018-10-12 20:17 ` [Patch v4 5/8] drm/omap: Add global state as a private atomic object Benoit Parrot
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Benoit Parrot @ 2018-10-12 20:16 UTC (permalink / raw)
  To: dri-devel, linux-kernel, Laurent Pinchart, Daniel Vetter
  Cc: Tomi Valkeinen, Peter Ujfalusi, Jyri Sarha, 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.

Signed-off-by: Benoit Parrot <bparrot@ti.com>
---
 drivers/gpu/drm/omapdrm/omap_plane.c | 48 +++++++++++++++++++++++++++++++++---
 1 file changed, 44 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index 26c2c78d020f..b0e60119c0a1 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -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,
 };
-- 
2.9.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Patch v4 5/8] drm/omap: Add global state as a private atomic object
  2018-10-12 20:16 [Patch v4 0/8] drm/omap: Add virtual-planes support Benoit Parrot
                   ` (3 preceding siblings ...)
  2018-10-12 20:16 ` [Patch v4 4/8] drm/omap: omap_plane: subclass drm_plane_state Benoit Parrot
@ 2018-10-12 20:17 ` Benoit Parrot
  2018-10-16 12:29   ` Daniel Vetter
  2018-10-12 20:17 ` [Patch v4 6/8] drm/omap: dynamically assign hw overlays to planes Benoit Parrot
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 13+ messages in thread
From: Benoit Parrot @ 2018-10-12 20:17 UTC (permalink / raw)
  To: dri-devel, linux-kernel, Laurent Pinchart, Daniel Vetter
  Cc: Tomi Valkeinen, Peter Ujfalusi, Jyri Sarha, 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.

Signed-off-by: Benoit Parrot <bparrot@ti.com>
---
 drivers/gpu/drm/omapdrm/omap_drv.c | 97 +++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/omapdrm/omap_drv.h | 23 +++++++++
 2 files changed, 119 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 2921cc90f2d8..94658ec79c76 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -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);
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
index 929f04e7cc3b..f374dc100447 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.h
+++ b/drivers/gpu/drm/omapdrm/omap_drv.h
@@ -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__ */
-- 
2.9.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Patch v4 6/8] drm/omap: dynamically assign hw overlays to planes
  2018-10-12 20:16 [Patch v4 0/8] drm/omap: Add virtual-planes support Benoit Parrot
                   ` (4 preceding siblings ...)
  2018-10-12 20:17 ` [Patch v4 5/8] drm/omap: Add global state as a private atomic object Benoit Parrot
@ 2018-10-12 20:17 ` Benoit Parrot
  2018-10-12 20:17 ` [Patch v4 7/8] drm/omap: add plane_atomic_print_state support Benoit Parrot
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 13+ messages in thread
From: Benoit Parrot @ 2018-10-12 20:17 UTC (permalink / raw)
  To: dri-devel, linux-kernel, Laurent Pinchart, Daniel Vetter
  Cc: Tomi Valkeinen, Peter Ujfalusi, Jyri Sarha, 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.

Signed-off-by: Benoit Parrot <bparrot@ti.com>
---
 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(-)

diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
index f374dc100447..00326f2a2c2c 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.h
+++ b/drivers/gpu/drm/omapdrm/omap_drv.h
@@ -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 {
diff --git a/drivers/gpu/drm/omapdrm/omap_overlay.c b/drivers/gpu/drm/omapdrm/omap_overlay.c
index 7a09b0aa823a..3a58582cd56f 100644
--- a/drivers/gpu/drm/omapdrm/omap_overlay.c
+++ b/drivers/gpu/drm/omapdrm/omap_overlay.c
@@ -21,6 +21,149 @@ static const char * const overlay_id_to_name[] = {
 	[OMAP_DSS_VIDEO3] = "vid3",
 };
 
+static struct omap_hw_overlay *
+omap_plane_find_free_overlay(struct drm_device *dev,
+			     struct drm_plane *hwoverlay_to_plane[],
+			     u32 caps, u32 fourcc, u32 crtc_mask)
+{
+	struct omap_drm_private *priv = dev->dev_private;
+	const struct dispc_ops *ops = priv->dispc_ops;
+	int i;
+
+	DBG("caps: %x fourcc: %x crtc: %x", caps, fourcc, crtc_mask);
+
+	for (i = 0; i < priv->num_ovls; i++) {
+		struct omap_hw_overlay *cur = priv->overlays[i];
+
+		DBG("%d: id: %d cur->caps: %x cur->crtc: %x",
+		    cur->idx, cur->overlay_id, cur->caps, cur->possible_crtcs);
+
+		/* skip if already in-use */
+		if (hwoverlay_to_plane[cur->idx])
+			continue;
+
+		/* check if allowed on crtc */
+		if (!(cur->possible_crtcs & crtc_mask))
+			continue;
+
+		/* skip if doesn't support some required caps: */
+		if (caps & ~cur->caps)
+			continue;
+
+		/* check supported format */
+		if (!ops->ovl_color_mode_supported(priv->dispc,
+						   cur->overlay_id,
+						   fourcc))
+			continue;
+
+		return cur;
+	}
+
+	DBG("no match");
+	return NULL;
+}
+
+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_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;
+
+	new_global_state = omap_get_global_state(s);
+	if (IS_ERR(new_global_state))
+		return PTR_ERR(new_global_state);
+
+	/*
+	 * grab old_state after omap_get_global_state(),
+	 * since now we hold lock:
+	 */
+	old_global_state = omap_get_existing_global_state(priv);
+	DBG("new_global_state: %p old_global_state: %p",
+	    new_global_state, old_global_state);
+
+	overlay_map = new_global_state->hwoverlay_to_plane;
+
+	if (!*overlay) {
+		ovl = omap_plane_find_free_overlay(s->dev, overlay_map,
+						   caps, fourcc, crtc_mask);
+		if (!ovl)
+			return -ENOMEM;
+
+		ovl->possible_crtcs = crtc_mask;
+		overlay_map[ovl->idx] = plane;
+		*overlay = ovl;
+
+		DBG("%s: assign to plane %s caps %x on crtc %x",
+		    (*overlay)->name, plane->name, caps, crtc_mask);
+	}
+
+	return 0;
+}
+
+void omap_overlay_release(struct drm_atomic_state *s,
+			  struct drm_plane *plane,
+			  struct omap_hw_overlay *overlay)
+{
+	struct omap_global_state *state = omap_get_global_state(s);
+	struct drm_plane **overlay_map = state->hwoverlay_to_plane;
+
+	if (!overlay)
+		return;
+
+	if (WARN_ON(!overlay_map[overlay->idx]))
+		return;
+	/*
+	 * Check that the overlay we are releasing is actually
+	 * assigned to the plane we are trying to release it from.
+	 */
+	if (overlay_map[overlay->idx] == plane) {
+		DBG("%s: release from plane %s", overlay->name, plane->name);
+
+		overlay_map[overlay->idx] = NULL;
+	}
+}
+
+void omap_overlay_disable(struct drm_atomic_state *s,
+			  struct drm_plane *plane,
+			  struct omap_hw_overlay *overlay)
+{
+	struct omap_drm_private *priv = s->dev->dev_private;
+	struct drm_plane **overlay_map;
+	struct omap_global_state *old_state;
+
+	old_state = omap_get_existing_global_state(priv);
+	overlay_map = old_state->hwoverlay_to_plane;
+
+	if (!overlay)
+		return;
+
+	/*
+	 * Check that the overlay we are trying to disable has not
+	 * been re-assigned to another plane already
+	 */
+	if (!overlay_map[overlay->idx]) {
+		DBG("%s: on %s disabled", overlay->name, plane->name);
+
+		/* disable the overlay */
+		priv->dispc_ops->ovl_enable(priv->dispc,
+					    overlay->overlay_id, false);
+
+		/*
+		 * Since we are disabling this overlay in this
+		 * atomic cycle we can reset the available crtcs
+		 * it can be used on
+		 */
+		overlay->possible_crtcs = (1 << priv->num_pipes) - 1;
+	}
+
+	/*
+	 * Otherwise the overlay is still in use so leave it alone
+	 */
+}
+
 static void omap_overlay_destroy(struct omap_hw_overlay *overlay)
 {
 	kfree(overlay);
diff --git a/drivers/gpu/drm/omapdrm/omap_overlay.h b/drivers/gpu/drm/omapdrm/omap_overlay.h
index 892fecb67adb..d5033ee481c2 100644
--- a/drivers/gpu/drm/omapdrm/omap_overlay.h
+++ b/drivers/gpu/drm/omapdrm/omap_overlay.h
@@ -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__ */
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index b0e60119c0a1..224520348fc5 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -30,6 +30,8 @@
 
 struct omap_plane_state {
 	struct drm_plane_state base;
+
+	struct omap_hw_overlay *overlay;
 };
 
 #define to_omap_plane(x) container_of(x, struct omap_plane, base)
@@ -38,8 +40,6 @@ struct omap_plane {
 	struct drm_plane base;
 	enum omap_plane_id id;
 	const char *name;
-
-	struct omap_hw_overlay *overlay;
 };
 
 static int omap_plane_prepare_fb(struct drm_plane *plane,
@@ -64,10 +64,25 @@ static void omap_plane_atomic_update(struct drm_plane *plane,
 	struct omap_drm_private *priv = plane->dev->dev_private;
 	struct omap_plane *omap_plane = to_omap_plane(plane);
 	struct drm_plane_state *state = plane->state;
+	struct omap_plane_state *new_omap_state;
+	struct omap_plane_state *old_omap_state;
 	struct omap_overlay_info info;
-	enum omap_plane_id ovl_id = omap_plane->overlay->overlay_id;
+	enum omap_plane_id ovl_id;
 	int ret;
 
+	new_omap_state = to_omap_plane_state(state);
+	old_omap_state = to_omap_plane_state(old_state);
+
+	/* Cleanup previously held overlay if needed */
+	omap_overlay_disable(old_state->state, plane, old_omap_state->overlay);
+
+	if (!new_omap_state->overlay) {
+		DBG("[PLANE:%d:%s] overlay_id: ??? (%p)", plane->base.id, plane->name,
+		    new_omap_state->overlay);
+		return;
+	}
+
+	ovl_id = new_omap_state->overlay->overlay_id;
 	DBG("[PLANE:%d:%s] overlay_id: %d", plane->base.id, plane->name,
 	    ovl_id);
 	DBG("%s, crtc=%p fb=%p", omap_plane->name, state->crtc, state->fb);
@@ -81,11 +96,11 @@ static void omap_plane_atomic_update(struct drm_plane *plane,
 	/* update scanout: */
 	omap_framebuffer_update_scanout(state->fb, state, &info);
 
-	DBG("%dx%d -> %dx%d (%d)", info.width, info.height,
-			info.out_width, info.out_height,
-			info.screen_width);
+	DBG("%s: %dx%d -> %dx%d (%d)",
+	    new_omap_state->overlay->name, info.width, info.height,
+	    info.out_width, info.out_height, info.screen_width);
 	DBG("%d,%d %pad %pad", info.pos_x, info.pos_y,
-			&info.paddr, &info.p_uv_addr);
+	    &info.paddr, &info.p_uv_addr);
 
 	/* and finally, update omapdss: */
 	ret = priv->dispc_ops->ovl_setup(priv->dispc, ovl_id, &info,
@@ -104,53 +119,62 @@ static void omap_plane_atomic_update(struct drm_plane *plane,
 static void omap_plane_atomic_disable(struct drm_plane *plane,
 				      struct drm_plane_state *old_state)
 {
-	struct omap_drm_private *priv = plane->dev->dev_private;
-	struct omap_plane *omap_plane = to_omap_plane(plane);
-	enum omap_plane_id ovl_id = omap_plane->overlay->overlay_id;
+	struct drm_plane_state *state = plane->state;
+	struct omap_plane_state *new_omap_state;
+	struct omap_plane_state *old_omap_state;
+
+	new_omap_state = to_omap_plane_state(state);
+	old_omap_state = to_omap_plane_state(old_state);
+
+	if (!old_omap_state->overlay)
+		return;
 
 	plane->state->rotation = DRM_MODE_ROTATE_0;
 	plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY
-			   ? 0 : ovl_id;
+			   ? 0 : old_omap_state->overlay->overlay_id;
 
-	priv->dispc_ops->ovl_enable(priv->dispc, ovl_id, false);
+	omap_overlay_disable(old_state->state, plane, old_omap_state->overlay);
+	new_omap_state->overlay = NULL;
 }
 
+#define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
 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 *crtc;
 	struct drm_crtc_state *crtc_state;
 	u16 width, height;
 	u32 width_fp, height_fp;
+	struct drm_plane_state *old_state = plane->state;
+	struct omap_plane_state *omap_state = to_omap_plane_state(state);
+	struct omap_global_state *omap_overlay_global_state;
+	u32 crtc_mask;
+	u32 fourcc;
+	u32 caps = 0;
+	bool new_hw_overlay = false;
+	int min_scale, max_scale;
+	int ret;
 
-	if (!state->fb)
-		return 0;
+	omap_overlay_global_state = omap_get_global_state(state->state);
+	if (IS_ERR(omap_overlay_global_state))
+		return PTR_ERR(omap_overlay_global_state);
+	DBG("%s: omap_overlay_global_state: %p", plane->name,
+	    omap_overlay_global_state);
 
 	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))
+	crtc = state->crtc ? state->crtc : plane->state->crtc;
+	if (!crtc)
 		return 0;
 
-	crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc);
+	crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
 	/* we should have a crtc state if the plane is attached to a crtc */
 	if (WARN_ON(!crtc_state))
 		return 0;
 
-	if (!crtc_state->enable)
-		return 0;
-
-	if (state->crtc_x < 0 || state->crtc_y < 0)
-		return -EINVAL;
-
-	if (state->crtc_x + state->crtc_w > crtc_state->adjusted_mode.hdisplay)
-		return -EINVAL;
-
-	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;
@@ -158,10 +182,76 @@ static int omap_plane_atomic_check(struct drm_plane *plane,
 	if (state->src_w > width_fp || state->crtc_w > width)
 		return -EINVAL;
 
+	min_scale = FRAC_16_16(1, 4);
+	max_scale = FRAC_16_16(8, 1);
+
+	ret = drm_atomic_helper_check_plane_state(state, crtc_state,
+						  min_scale, max_scale,
+						  true, true);
+	if (ret)
+		return ret;
+
 	if (state->rotation != DRM_MODE_ROTATE_0 &&
 	    !omap_framebuffer_supports_rotation(state->fb))
 		return -EINVAL;
 
+	DBG("%s: check (%d -> %d)", plane->name,
+	    old_state->visible, state->visible);
+
+	if (state->visible) {
+		if ((state->src_w >> 16) != state->crtc_w ||
+		    (state->src_h >> 16) != state->crtc_h)
+			caps |= OMAP_DSS_OVL_CAP_SCALE;
+
+		fourcc = state->fb->format->format;
+		crtc_mask = drm_crtc_mask(state->crtc);
+
+		/*
+		 * (re)allocate hw overlay if we don't have one or
+		 * there is a caps mismatch
+		 */
+		if (!omap_state->overlay ||
+		    (caps & ~omap_state->overlay->caps)) {
+			new_hw_overlay = true;
+		} else {
+			/* check if allowed on crtc */
+			if (!(omap_state->overlay->possible_crtcs & crtc_mask))
+				new_hw_overlay = true;
+
+			/* check supported format */
+			if (!priv->dispc_ops->ovl_color_mode_supported(priv->dispc,
+						omap_state->overlay->overlay_id,
+						fourcc))
+				new_hw_overlay = true;
+		}
+
+		if (new_hw_overlay) {
+			struct omap_hw_overlay *old_ovl =
+						omap_state->overlay;
+			struct omap_hw_overlay *new_ovl = NULL;
+
+			omap_overlay_release(state->state, plane, old_ovl);
+
+			ret = omap_overlay_assign(state->state, plane, caps,
+						  fourcc, crtc_mask, &new_ovl);
+			if (ret) {
+				DBG("%s: failed to assign hw_overlay(s)!",
+				    plane->name);
+				omap_state->overlay = NULL;
+				return ret;
+			}
+
+			omap_state->overlay = new_ovl;
+		}
+	} else {
+		omap_overlay_release(state->state, plane, omap_state->overlay);
+		omap_state->overlay = NULL;
+	}
+
+	if (omap_state->overlay)
+		DBG("plane: %s overlay_id: %d", plane->name,
+		    omap_state->overlay->overlay_id);
+
 	return 0;
 }
 
@@ -236,7 +326,7 @@ static void omap_plane_reset(struct drm_plane *plane)
 	 * plane.
 	 */
 	plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY
-			   ? 0 : omap_plane->overlay->overlay_id;
+			   ? 0 : omap_plane->id;
 }
 
 static struct drm_plane_state *
@@ -328,14 +418,13 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
 
 	omap_plane->id = idx;
 	omap_plane->name = plane_id_to_name[idx];
-	omap_plane->overlay = priv->overlays[idx];
 
 	DBG("%s: type=%d", omap_plane->name, type);
 	DBG("	omap_plane->id: %d", omap_plane->id);
 	DBG("	crtc_mask: 0x%04x", possible_crtcs);
 
 	formats = priv->dispc_ops->ovl_get_color_modes(priv->dispc,
-						       omap_plane->overlay->overlay_id);
+						       omap_plane->id);
 	for (nformats = 0; formats[nformats]; ++nformats)
 		;
 
-- 
2.9.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Patch v4 7/8] drm/omap: add plane_atomic_print_state support
  2018-10-12 20:16 [Patch v4 0/8] drm/omap: Add virtual-planes support Benoit Parrot
                   ` (5 preceding siblings ...)
  2018-10-12 20:17 ` [Patch v4 6/8] drm/omap: dynamically assign hw overlays to planes Benoit Parrot
@ 2018-10-12 20:17 ` Benoit Parrot
  2018-10-12 20:17 ` [Patch v4 8/8] drm/omap: Add a 'right overlay' to plane state Benoit Parrot
  2018-11-19 16:02 ` [Patch v4 0/8] drm/omap: Add virtual-planes support Benoit Parrot
  8 siblings, 0 replies; 13+ messages in thread
From: Benoit Parrot @ 2018-10-12 20:17 UTC (permalink / raw)
  To: dri-devel, linux-kernel, Laurent Pinchart, Daniel Vetter
  Cc: Tomi Valkeinen, Peter Ujfalusi, Jyri Sarha, 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.

Signed-off-by: Benoit Parrot <bparrot@ti.com>
---
 drivers/gpu/drm/omapdrm/omap_plane.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index 224520348fc5..116071982a0e 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -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[] = {
-- 
2.9.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Patch v4 8/8] drm/omap: Add a 'right overlay' to plane state
  2018-10-12 20:16 [Patch v4 0/8] drm/omap: Add virtual-planes support Benoit Parrot
                   ` (6 preceding siblings ...)
  2018-10-12 20:17 ` [Patch v4 7/8] drm/omap: add plane_atomic_print_state support Benoit Parrot
@ 2018-10-12 20:17 ` Benoit Parrot
  2018-11-19 16:02 ` [Patch v4 0/8] drm/omap: Add virtual-planes support Benoit Parrot
  8 siblings, 0 replies; 13+ messages in thread
From: Benoit Parrot @ 2018-10-12 20:17 UTC (permalink / raw)
  To: dri-devel, linux-kernel, Laurent Pinchart, Daniel Vetter
  Cc: Tomi Valkeinen, Peter Ujfalusi, Jyri Sarha, 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.

Signed-off-by: Benoit Parrot <bparrot@ti.com>
---
 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(-)

diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 94658ec79c76..307cd905fd02 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -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,
 };
 
diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c
index 4d264fd554d8..13d7fa7b31fc 100644
--- a/drivers/gpu/drm/omapdrm/omap_fb.c
+++ b/drivers/gpu/drm/omapdrm/omap_fb.c
@@ -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: */
diff --git a/drivers/gpu/drm/omapdrm/omap_fb.h b/drivers/gpu/drm/omapdrm/omap_fb.h
index c20cb4bc714d..a649fce0f0f1 100644
--- a/drivers/gpu/drm/omapdrm/omap_fb.h
+++ b/drivers/gpu/drm/omapdrm/omap_fb.h
@@ -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);
 
diff --git a/drivers/gpu/drm/omapdrm/omap_overlay.c b/drivers/gpu/drm/omapdrm/omap_overlay.c
index 3a58582cd56f..d27b4c3d769b 100644
--- a/drivers/gpu/drm/omapdrm/omap_overlay.c
+++ b/drivers/gpu/drm/omapdrm/omap_overlay.c
@@ -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;
diff --git a/drivers/gpu/drm/omapdrm/omap_overlay.h b/drivers/gpu/drm/omapdrm/omap_overlay.h
index d5033ee481c2..a800468511f1 100644
--- a/drivers/gpu/drm/omapdrm/omap_overlay.h
+++ b/drivers/gpu/drm/omapdrm/omap_overlay.h
@@ -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);
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index 116071982a0e..7fe11c1929d8 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -32,6 +32,7 @@ struct omap_plane_state {
 	struct drm_plane_state base;
 
 	struct omap_hw_overlay *overlay;
+	struct omap_hw_overlay *r_overlay;  /* right overlay */
 };
 
 #define to_omap_plane(x) container_of(x, struct omap_plane, base)
@@ -42,6 +43,13 @@ struct omap_plane {
 	const char *name;
 };
 
+bool is_omap_plane_dual_overlay(struct drm_plane_state *state)
+{
+	struct omap_plane_state *omap_state = to_omap_plane_state(state);
+
+	return !!omap_state->r_overlay;
+}
+
 static int omap_plane_prepare_fb(struct drm_plane *plane,
 				 struct drm_plane_state *new_state)
 {
@@ -66,15 +74,20 @@ static void omap_plane_atomic_update(struct drm_plane *plane,
 	struct drm_plane_state *state = plane->state;
 	struct omap_plane_state *new_omap_state;
 	struct omap_plane_state *old_omap_state;
-	struct omap_overlay_info info;
-	enum omap_plane_id ovl_id;
+	struct omap_overlay_info info, r_info;
+	enum omap_plane_id ovl_id, r_ovl_id;
 	int ret;
+	bool dual_ovl;
 
 	new_omap_state = to_omap_plane_state(state);
 	old_omap_state = to_omap_plane_state(old_state);
 
+	dual_ovl = is_omap_plane_dual_overlay(state);
+
 	/* Cleanup previously held overlay if needed */
 	omap_overlay_disable(old_state->state, plane, old_omap_state->overlay);
+	omap_overlay_disable(old_state->state, plane,
+			     old_omap_state->r_overlay);
 
 	if (!new_omap_state->overlay) {
 		DBG("[PLANE:%d:%s] overlay_id: ??? (%p)", plane->base.id, plane->name,
@@ -93,8 +106,11 @@ static void omap_plane_atomic_update(struct drm_plane *plane,
 	info.global_alpha = 0xff;
 	info.zorder = state->normalized_zpos;
 
+	r_info = info;
+
 	/* update scanout: */
-	omap_framebuffer_update_scanout(state->fb, state, &info);
+	omap_framebuffer_update_scanout(state->fb, state, &info,
+					dual_ovl ? &r_info : NULL);
 
 	DBG("%s: %dx%d -> %dx%d (%d)",
 	    new_omap_state->overlay->name, info.width, info.height,
@@ -102,18 +118,50 @@ static void omap_plane_atomic_update(struct drm_plane *plane,
 	DBG("%d,%d %pad %pad", info.pos_x, info.pos_y,
 	    &info.paddr, &info.p_uv_addr);
 
+	if (dual_ovl) {
+		r_ovl_id = new_omap_state->r_overlay->overlay_id;
+		/*
+		 * If the current plane uses 2 hw planes the very next
+		 * zorder is used by the r_overlay so we just use the
+		 * main overlay zorder + 1
+		 */
+		r_info.zorder = info.zorder + 1;
+
+		DBG("%s: %dx%d -> %dx%d (%d)",
+		    new_omap_state->r_overlay->name,
+		    r_info.width, r_info.height,
+		    r_info.out_width, r_info.out_height, r_info.screen_width);
+		DBG("%d,%d %pad %pad", r_info.pos_x, r_info.pos_y,
+		    &r_info.paddr, &r_info.p_uv_addr);
+	}
+
 	/* and finally, update omapdss: */
 	ret = priv->dispc_ops->ovl_setup(priv->dispc, ovl_id, &info,
 			      omap_crtc_timings(state->crtc), false,
 			      omap_crtc_channel(state->crtc));
 	if (ret) {
-		dev_err(plane->dev->dev, "Failed to setup plane %s\n",
+		dev_err(plane->dev->dev, "Failed to setup plane1 %s\n",
 			omap_plane->name);
 		priv->dispc_ops->ovl_enable(priv->dispc, ovl_id, false);
 		return;
 	}
 
 	priv->dispc_ops->ovl_enable(priv->dispc, ovl_id, true);
+
+	if (dual_ovl) {
+		ret = priv->dispc_ops->ovl_setup(priv->dispc, r_ovl_id, &r_info,
+				      omap_crtc_timings(state->crtc), false,
+				      omap_crtc_channel(state->crtc));
+		if (ret) {
+			dev_err(plane->dev->dev, "Failed to setup plane2 %s\n",
+				omap_plane->name);
+			priv->dispc_ops->ovl_enable(priv->dispc, r_ovl_id, false);
+			priv->dispc_ops->ovl_enable(priv->dispc, ovl_id, false);
+			return;
+		}
+
+		priv->dispc_ops->ovl_enable(priv->dispc, r_ovl_id, true);
+	}
 }
 
 static void omap_plane_atomic_disable(struct drm_plane *plane,
@@ -135,6 +183,11 @@ static void omap_plane_atomic_disable(struct drm_plane *plane,
 
 	omap_overlay_disable(old_state->state, plane, old_omap_state->overlay);
 	new_omap_state->overlay = NULL;
+	if (is_omap_plane_dual_overlay(old_state)) {
+		omap_overlay_disable(old_state->state, plane,
+				     old_omap_state->r_overlay);
+		new_omap_state->r_overlay = NULL;
+	}
 }
 
 #define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
@@ -153,6 +206,8 @@ static int omap_plane_atomic_check(struct drm_plane *plane,
 	u32 fourcc;
 	u32 caps = 0;
 	bool new_hw_overlay = false;
+	bool new_r_hw_overlay = false;
+	bool is_fourcc_yuv = false;
 	int min_scale, max_scale;
 	int ret;
 
@@ -179,8 +234,31 @@ static int omap_plane_atomic_check(struct drm_plane *plane,
 	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->fb)
+		is_fourcc_yuv = state->fb->format->is_yuv;
+
+	if (state->src_w > width_fp || state->crtc_w > width) {
+		if (is_fourcc_yuv &&
+		    (((state->src_w >> 16) / 2 & 1) ||
+		     state->crtc_w / 2 & 1)) {
+			/*
+			 * When calculating the split overlay width
+			 * and it yield an odd value we will need to adjust
+			 * the indivual width +/- 1. So make sure it fits
+			 */
+			if (state->src_w <= ((2 * width - 1) << 16) &&
+			    state->crtc_w <= (2 * width - 1))
+				new_r_hw_overlay = true;
+			else
+				return -EINVAL;
+		} else {
+			if (state->src_w <= (2 * width_fp) &&
+			    state->crtc_w <= (2 * width))
+				new_r_hw_overlay = true;
+			else
+				return -EINVAL;
+		}
+	}
 
 	min_scale = FRAC_16_16(1, 4);
 	max_scale = FRAC_16_16(8, 1);
@@ -224,33 +302,57 @@ static int omap_plane_atomic_check(struct drm_plane *plane,
 						fourcc))
 				new_hw_overlay = true;
 		}
+		/*
+		 * check if we need two overlays and only have 1 or
+		 * if we had 2 overlays but will only need 1
+		 */
+		if ((new_r_hw_overlay && !omap_state->r_overlay) ||
+		    (!new_r_hw_overlay && omap_state->r_overlay))
+			new_hw_overlay = true;
 
 		if (new_hw_overlay) {
 			struct omap_hw_overlay *old_ovl =
 						omap_state->overlay;
+			struct omap_hw_overlay *old_r_ovl =
+						omap_state->r_overlay;
 			struct omap_hw_overlay *new_ovl = NULL;
+			struct omap_hw_overlay *new_r_ovl = NULL;
 
 			omap_overlay_release(state->state, plane, old_ovl);
+			omap_overlay_release(state->state, plane, old_r_ovl);
 
 			ret = omap_overlay_assign(state->state, plane, caps,
-						  fourcc, crtc_mask, &new_ovl);
+						  fourcc, crtc_mask, &new_ovl,
+						  new_r_hw_overlay ?
+						  &new_r_ovl : NULL);
 			if (ret) {
 				DBG("%s: failed to assign hw_overlay(s)!",
 				    plane->name);
 				omap_state->overlay = NULL;
+				omap_state->r_overlay = NULL;
 				return ret;
 			}
 
 			omap_state->overlay = new_ovl;
+			if (new_r_hw_overlay)
+				omap_state->r_overlay = new_r_ovl;
+			else
+				omap_state->r_overlay = NULL;
 		}
 	} else {
 		omap_overlay_release(state->state, plane, omap_state->overlay);
+		omap_overlay_release(state->state, plane,
+				     omap_state->r_overlay);
 		omap_state->overlay = NULL;
+		omap_state->r_overlay = NULL;
 	}
 
 	if (omap_state->overlay)
 		DBG("plane: %s overlay_id: %d", plane->name,
 		    omap_state->overlay->overlay_id);
+	if (omap_state->r_overlay)
+		DBG("plane: %s r_overlay_id: %d", plane->name,
+		    omap_state->r_overlay->overlay_id);
 
 	return 0;
 }
@@ -363,6 +465,18 @@ static void omap_plane_atomic_print_state(struct drm_printer *p,
 		drm_printf(p, "\t\tpossible_crtcs=0x%x\n",
 			   omap_state->overlay->possible_crtcs);
 	}
+
+	drm_printf(p, "\tr_overlay=%s\n", omap_state->r_overlay ?
+					  omap_state->r_overlay->name :
+					  "(null)");
+	if (omap_state->r_overlay) {
+		drm_printf(p, "\t\tidx=%d\n", omap_state->r_overlay->idx);
+		drm_printf(p, "\t\toverlay_id=%d\n",
+			   omap_state->r_overlay->overlay_id);
+		drm_printf(p, "\t\tcaps=0x%x\n", omap_state->r_overlay->caps);
+		drm_printf(p, "\t\tpossible_crtcs=0x%x\n",
+			   omap_state->r_overlay->possible_crtcs);
+	}
 }
 
 static int omap_plane_atomic_set_property(struct drm_plane *plane,
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.h b/drivers/gpu/drm/omapdrm/omap_plane.h
index dc5e82ad061d..ea31af8b6aa6 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.h
+++ b/drivers/gpu/drm/omapdrm/omap_plane.h
@@ -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__ */
-- 
2.9.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [Patch v4 5/8] drm/omap: Add global state as a private atomic object
  2018-10-12 20:17 ` [Patch v4 5/8] drm/omap: Add global state as a private atomic object Benoit Parrot
@ 2018-10-16 12:29   ` Daniel Vetter
  2018-10-18 13:11     ` Benoit Parrot
  0 siblings, 1 reply; 13+ messages in thread
From: Daniel Vetter @ 2018-10-16 12:29 UTC (permalink / raw)
  To: Benoit Parrot
  Cc: dri-devel, linux-kernel, Laurent Pinchart, Daniel Vetter,
	Tomi Valkeinen, Peter Ujfalusi, Jyri Sarha

On Fri, Oct 12, 2018 at 03:17:00PM -0500, Benoit Parrot wrote:
> 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.
> 
> Signed-off-by: Benoit Parrot <bparrot@ti.com>
> ---
>  drivers/gpu/drm/omapdrm/omap_drv.c | 97 +++++++++++++++++++++++++++++++++++++-
>  drivers/gpu/drm/omapdrm/omap_drv.h | 23 +++++++++
>  2 files changed, 119 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
> index 2921cc90f2d8..94658ec79c76 100644
> --- a/drivers/gpu/drm/omapdrm/omap_drv.c
> +++ b/drivers/gpu/drm/omapdrm/omap_drv.c
> @@ -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);

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

> +	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);
> diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
> index 929f04e7cc3b..f374dc100447 100644
> --- a/drivers/gpu/drm/omapdrm/omap_drv.h
> +++ b/drivers/gpu/drm/omapdrm/omap_drv.h
> @@ -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__ */
> -- 
> 2.9.0
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Patch v4 5/8] drm/omap: Add global state as a private atomic object
  2018-10-16 12:29   ` Daniel Vetter
@ 2018-10-18 13:11     ` Benoit Parrot
  2018-10-19  7:10       ` Daniel Vetter
  0 siblings, 1 reply; 13+ messages in thread
From: Benoit Parrot @ 2018-10-18 13:11 UTC (permalink / raw)
  To: dri-devel, linux-kernel, Laurent Pinchart, Tomi Valkeinen,
	Peter Ujfalusi, Jyri Sarha

Daniel Vetter <daniel@ffwll.ch> wrote on Tue [2018-Oct-16 14:29:46 +0200]:
> On Fri, Oct 12, 2018 at 03:17:00PM -0500, Benoit Parrot wrote:
> > 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.
> > 
> > Signed-off-by: Benoit Parrot <bparrot@ti.com>
> > ---
> >  drivers/gpu/drm/omapdrm/omap_drv.c | 97 +++++++++++++++++++++++++++++++++++++-
> >  drivers/gpu/drm/omapdrm/omap_drv.h | 23 +++++++++
> >  2 files changed, 119 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
> > index 2921cc90f2d8..94658ec79c76 100644
> > --- a/drivers/gpu/drm/omapdrm/omap_drv.c
> > +++ b/drivers/gpu/drm/omapdrm/omap_drv.c
> > @@ -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);
> 
> 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

> 
> Just a drive-by refactor idea.
> -Daniel

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Patch v4 5/8] drm/omap: Add global state as a private atomic object
  2018-10-18 13:11     ` Benoit Parrot
@ 2018-10-19  7:10       ` Daniel Vetter
  0 siblings, 0 replies; 13+ messages in thread
From: Daniel Vetter @ 2018-10-19  7:10 UTC (permalink / raw)
  To: Benoit Parrot
  Cc: dri-devel, linux-kernel, Laurent Pinchart, Tomi Valkeinen,
	Peter Ujfalusi, Jyri Sarha

On Thu, Oct 18, 2018 at 08:11:30AM -0500, Benoit Parrot wrote:
> Daniel Vetter <daniel@ffwll.ch> wrote on Tue [2018-Oct-16 14:29:46 +0200]:
> > On Fri, Oct 12, 2018 at 03:17:00PM -0500, Benoit Parrot wrote:
> > > 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.
> > > 
> > > Signed-off-by: Benoit Parrot <bparrot@ti.com>
> > > ---
> > >  drivers/gpu/drm/omapdrm/omap_drv.c | 97 +++++++++++++++++++++++++++++++++++++-
> > >  drivers/gpu/drm/omapdrm/omap_drv.h | 23 +++++++++
> > >  2 files changed, 119 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
> > > index 2921cc90f2d8..94658ec79c76 100644
> > > --- a/drivers/gpu/drm/omapdrm/omap_drv.c
> > > +++ b/drivers/gpu/drm/omapdrm/omap_drv.c
> > > @@ -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);
> > 
> > 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 :) 

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
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Patch v4 0/8] drm/omap: Add virtual-planes support
  2018-10-12 20:16 [Patch v4 0/8] drm/omap: Add virtual-planes support Benoit Parrot
                   ` (7 preceding siblings ...)
  2018-10-12 20:17 ` [Patch v4 8/8] drm/omap: Add a 'right overlay' to plane state Benoit Parrot
@ 2018-11-19 16:02 ` Benoit Parrot
  8 siblings, 0 replies; 13+ messages in thread
From: Benoit Parrot @ 2018-11-19 16:02 UTC (permalink / raw)
  To: dri-devel, linux-kernel, Laurent Pinchart, Daniel Vetter
  Cc: Tomi Valkeinen, Peter Ujfalusi, Jyri Sarha

Ping.

Benoit

Benoit Parrot <bparrot@ti.com> wrote on Fri [2018-Oct-12 15:16:55 -0500]:
> 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
> 
> -- 
> 2.9.0
> 

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2018-11-19 16:02 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-12 20:16 [Patch v4 0/8] drm/omap: Add virtual-planes support Benoit Parrot
2018-10-12 20:16 ` [Patch v4 1/8] drm/omap: Add ability to check if requested plane modes can be supported Benoit Parrot
2018-10-12 20:16 ` [Patch v4 2/8] drm/omap: Add ovl checking funcs to dispc_ops Benoit Parrot
2018-10-12 20:16 ` [Patch v4 3/8] drm/omap: introduce omap_hw_overlay Benoit Parrot
2018-10-12 20:16 ` [Patch v4 4/8] drm/omap: omap_plane: subclass drm_plane_state Benoit Parrot
2018-10-12 20:17 ` [Patch v4 5/8] drm/omap: Add global state as a private atomic object Benoit Parrot
2018-10-16 12:29   ` Daniel Vetter
2018-10-18 13:11     ` Benoit Parrot
2018-10-19  7:10       ` Daniel Vetter
2018-10-12 20:17 ` [Patch v4 6/8] drm/omap: dynamically assign hw overlays to planes Benoit Parrot
2018-10-12 20:17 ` [Patch v4 7/8] drm/omap: add plane_atomic_print_state support Benoit Parrot
2018-10-12 20:17 ` [Patch v4 8/8] drm/omap: Add a 'right overlay' to plane state Benoit Parrot
2018-11-19 16:02 ` [Patch v4 0/8] drm/omap: Add virtual-planes support Benoit Parrot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).