[PATCH v2] drm: xlnx: zynqmp_dpsub: Enable plane in atomic update

2024-05-23 Thread Anatoliy Klymenko
Unconditionally enable the DPSUB layer in the corresponding atomic plane
update callback. Setting the new display mode may require disabling and
re-enabling the CRTC. This effectively resets DPSUB to the default state
with all layers disabled. The original implementation of the plane atomic
update enables the corresponding DPSUB layer only if the framebuffer
format has changed. This would leave the layer disabled after switching to
a different display mode with the same framebuffer format.

Signed-off-by: Anatoliy Klymenko 
---
Changes in v2:
- Added comment around DPSUB layer enablement explaining why it should be
  done unconditionally.
- Link to v1: 
https://lore.kernel.org/r/20240520-dp-layer-enable-v1-1-c9b481209...@amd.com
---
 drivers/gpu/drm/xlnx/zynqmp_kms.c | 10 +++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c 
b/drivers/gpu/drm/xlnx/zynqmp_kms.c
index 43bf416b33d5..0b57ab5451a9 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_kms.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c
@@ -120,9 +120,13 @@ static void zynqmp_dpsub_plane_atomic_update(struct 
drm_plane *plane,
zynqmp_disp_blend_set_global_alpha(dpsub->disp, true,
   plane->state->alpha >> 8);
 
-   /* Enable or re-enable the plane if the format has changed. */
-   if (format_changed)
-   zynqmp_disp_layer_enable(layer);
+   /*
+* Unconditionally enable the layer, as it may have been disabled
+* previously either explicitly to reconfigure layer format, or
+* implicitly after DPSUB reset during display mode change. DRM
+* framework calls this callback for enabled planes only.
+*/
+   zynqmp_disp_layer_enable(layer);
 }
 
 static const struct drm_plane_helper_funcs zynqmp_dpsub_plane_helper_funcs = {

---
base-commit: 673087d8b023faf34b84e8faf63bbeea3da87bab
change-id: 20240520-dp-layer-enable-7b561af29ca8

Best regards,
-- 
Anatoliy Klymenko 



[PATCH] drm: xlnx: zynqmp_dpsub: Enable plane in atomic update

2024-05-20 Thread Anatoliy Klymenko
Unconditionally enable the DPSUB layer in the corresponding atomic plane
update callback. Setting the new display mode may require disabling and
re-enabling the CRTC. This effectively resets DPSUB to the default state
with all layers disabled. The original implementation of the plane atomic
update enables the corresponding DPSUB layer only if the framebuffer
format has changed. This would leave the layer disabled after switching to
a different display mode with the same framebuffer format.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_kms.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c 
b/drivers/gpu/drm/xlnx/zynqmp_kms.c
index 43bf416b33d5..c4f038e34814 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_kms.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c
@@ -120,9 +120,8 @@ static void zynqmp_dpsub_plane_atomic_update(struct 
drm_plane *plane,
zynqmp_disp_blend_set_global_alpha(dpsub->disp, true,
   plane->state->alpha >> 8);
 
-   /* Enable or re-enable the plane if the format has changed. */
-   if (format_changed)
-   zynqmp_disp_layer_enable(layer);
+   /* Enable or re-enable the plane. */
+   zynqmp_disp_layer_enable(layer);
 }
 
 static const struct drm_plane_helper_funcs zynqmp_dpsub_plane_helper_funcs = {

---
base-commit: 673087d8b023faf34b84e8faf63bbeea3da87bab
change-id: 20240520-dp-layer-enable-7b561af29ca8

Best regards,
-- 
Anatoliy Klymenko 



[PATCH v3 1/2] drm: xlnx: zynqmp_dpsub: Fix few function comments

2024-04-26 Thread Anatoliy Klymenko
Fix arguments description for zynqmp_disp_layer_find_live_format() and
zynqmp_disp_layer_set_live_format().

Reported-by: kernel test robot 
Closes: 
https://lore.kernel.org/oe-kbuild-all/202404260616.kfgdpcdn-...@intel.com/

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 13157da0089e..423f5f4943cc 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -940,7 +940,7 @@ zynqmp_disp_layer_find_format(struct zynqmp_disp_layer 
*layer,
  * zynqmp_disp_layer_find_live_format - Find format information for given
  * media bus format
  * @layer: The layer
- * @drm_fmt: Media bus format to search
+ * @media_bus_format: Media bus format to search
  *
  * Search display subsystem format information corresponding to the given media
  * bus format @media_bus_format for the @layer, and return a pointer to the
@@ -1117,7 +1117,7 @@ void zynqmp_disp_layer_set_format(struct 
zynqmp_disp_layer *layer,
 /**
  * zynqmp_disp_layer_set_live_format - Set the live video layer format
  * @layer: The layer
- * @info: The format info
+ * @media_bus_format: Media bus format to set
  *
  * NOTE: This function should not be used to set format for non-live video
  * layer. Use zynqmp_disp_layer_set_format() instead.

-- 
2.25.1



[PATCH v3 2/2] drm: xlnx: zynqmp_dpsub: Fix compilation error

2024-04-26 Thread Anatoliy Klymenko
Fix W=1 clang 19 compilation error in zynqmp_disp_layer_drm_formats().

Reported-by: kernel test robot 
Closes: 
https://lore.kernel.org/oe-kbuild-all/202404260946.4ozxvhd2-...@intel.com/

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 423f5f4943cc..c9fb432d4cbd 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -981,7 +981,7 @@ u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer 
*layer,
unsigned int i;
u32 *formats;
 
-   if (WARN_ON(!layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE)) {
+   if (WARN_ON(layer->mode != ZYNQMP_DPSUB_LAYER_NONLIVE)) {
*num_formats = 0;
return NULL;
}

-- 
2.25.1



[PATCH v3 0/2] Fix Kernel CI issues

2024-04-26 Thread Anatoliy Klymenko
Fix number of CI reported W=1 build issues.

Patch 1/2: Fix function arguments description.
Closes: 
https://lore.kernel.org/oe-kbuild-all/202404260616.kfgdpcdn-...@intel.com/

Patch 2/2: Fix clang compilation error.
Closes: 
https://lore.kernel.org/oe-kbuild-all/202404260946.4ozxvhd2-...@intel.com/

Signed-off-by: Anatoliy Klymenko 
---
Changes in v3:
- Add Signed-off-by tag.

- Link to v2: 
https://lore.kernel.org/r/20240425-dp-live-fmt-fix-v2-0-6048e8121...@amd.com

Changes in v2:
- Compilation error fix added.

- Link to v1: 
https://lore.kernel.org/r/20240425-dp-live-fmt-fix-v1-1-405f352d3...@amd.com

---
Anatoliy Klymenko (2):
  drm: xlnx: zynqmp_dpsub: Fix few function comments
  drm: xlnx: zynqmp_dpsub: Fix compilation error

 drivers/gpu/drm/xlnx/zynqmp_disp.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
---
base-commit: 2bdb481bf7a93c22b9fea8daefa2834aab23a70f
change-id: 20240425-dp-live-fmt-fix-a10bf7973596

Best regards,
-- 
Anatoliy Klymenko 



[PATCH v2 0/2] Fix Kernel CI issues

2024-04-25 Thread Anatoliy Klymenko
Fix number of CI reported W=1 build issues.

Patch 1/2: Fix function arguments description.
Closes: 
https://lore.kernel.org/oe-kbuild-all/202404260616.kfgdpcdn-...@intel.com/

Patch 2/2: Fix clang compilation error.
Closes: 
https://lore.kernel.org/oe-kbuild-all/202404260946.4ozxvhd2-...@intel.com/

Signed-off-by: Anatoliy Klymenko 
---
Changes in v2:
- Compilation error fix added.

- Link to v1: 
https://lore.kernel.org/r/20240425-dp-live-fmt-fix-v1-1-405f352d3...@amd.com

---
Anatoliy Klymenko (2):
  drm: xlnx: zynqmp_dpsub: Fix few function comments
  drm: xlnx: zynqmp_dpsub: Fix compilation error

 drivers/gpu/drm/xlnx/zynqmp_disp.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
---
base-commit: 2bdb481bf7a93c22b9fea8daefa2834aab23a70f
change-id: 20240425-dp-live-fmt-fix-a10bf7973596

Best regards,
-- 
Anatoliy Klymenko 



[PATCH v2 2/2] drm: xlnx: zynqmp_dpsub: Fix compilation error

2024-04-25 Thread Anatoliy Klymenko
Fix W=1 clang 19 compilation error in zynqmp_disp_layer_drm_formats().

Reported-by: kernel test robot 
Closes: 
https://lore.kernel.org/oe-kbuild-all/202404260946.4ozxvhd2-...@intel.com/
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 423f5f4943cc..c9fb432d4cbd 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -981,7 +981,7 @@ u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer 
*layer,
unsigned int i;
u32 *formats;
 
-   if (WARN_ON(!layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE)) {
+   if (WARN_ON(layer->mode != ZYNQMP_DPSUB_LAYER_NONLIVE)) {
*num_formats = 0;
return NULL;
}

-- 
2.25.1



[PATCH v2 1/2] drm: xlnx: zynqmp_dpsub: Fix few function comments

2024-04-25 Thread Anatoliy Klymenko
Fix arguments description for zynqmp_disp_layer_find_live_format() and
zynqmp_disp_layer_set_live_format().

Reported-by: kernel test robot 
Closes: 
https://lore.kernel.org/oe-kbuild-all/202404260616.kfgdpcdn-...@intel.com/

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 13157da0089e..423f5f4943cc 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -940,7 +940,7 @@ zynqmp_disp_layer_find_format(struct zynqmp_disp_layer 
*layer,
  * zynqmp_disp_layer_find_live_format - Find format information for given
  * media bus format
  * @layer: The layer
- * @drm_fmt: Media bus format to search
+ * @media_bus_format: Media bus format to search
  *
  * Search display subsystem format information corresponding to the given media
  * bus format @media_bus_format for the @layer, and return a pointer to the
@@ -1117,7 +1117,7 @@ void zynqmp_disp_layer_set_format(struct 
zynqmp_disp_layer *layer,
 /**
  * zynqmp_disp_layer_set_live_format - Set the live video layer format
  * @layer: The layer
- * @info: The format info
+ * @media_bus_format: Media bus format to set
  *
  * NOTE: This function should not be used to set format for non-live video
  * layer. Use zynqmp_disp_layer_set_format() instead.

-- 
2.25.1



[PATCH] drm: xlnx: zynqmp_dpsub: Fix few function comments

2024-04-25 Thread Anatoliy Klymenko
Fix arguments description for zynqmp_disp_layer_find_live_format() and
zynqmp_disp_layer_set_live_format().

Reported-by: kernel test robot 
Closes: 
https://lore.kernel.org/oe-kbuild-all/202404260616.kfgdpcdn-...@intel.com/

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 13157da0089e..423f5f4943cc 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -940,7 +940,7 @@ zynqmp_disp_layer_find_format(struct zynqmp_disp_layer 
*layer,
  * zynqmp_disp_layer_find_live_format - Find format information for given
  * media bus format
  * @layer: The layer
- * @drm_fmt: Media bus format to search
+ * @media_bus_format: Media bus format to search
  *
  * Search display subsystem format information corresponding to the given media
  * bus format @media_bus_format for the @layer, and return a pointer to the
@@ -1117,7 +1117,7 @@ void zynqmp_disp_layer_set_format(struct 
zynqmp_disp_layer *layer,
 /**
  * zynqmp_disp_layer_set_live_format - Set the live video layer format
  * @layer: The layer
- * @info: The format info
+ * @media_bus_format: Media bus format to set
  *
  * NOTE: This function should not be used to set format for non-live video
  * layer. Use zynqmp_disp_layer_set_format() instead.

---
base-commit: 2bdb481bf7a93c22b9fea8daefa2834aab23a70f
change-id: 20240425-dp-live-fmt-fix-a10bf7973596

Best regards,
-- 
Anatoliy Klymenko 



[PATCH v4 6/7] drm: xlnx: zynqmp_dpsub: Set input live format

2024-04-16 Thread Anatoliy Klymenko
Program live video input format according to selected media bus format.

In the bridge mode of operation, DPSUB is connected to FPGA CRTC which
almost certainly supports a single media bus format as its output. Expect
this to be delivered via the new bridge atomic state. Program DPSUB
registers accordingly.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 92 --
 drivers/gpu/drm/xlnx/zynqmp_disp.h |  2 +
 drivers/gpu/drm/xlnx/zynqmp_dp.c   | 13 --
 3 files changed, 90 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 8cdd74a9b772..13157da0089e 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -436,19 +436,29 @@ static void zynqmp_disp_avbuf_set_format(struct 
zynqmp_disp *disp,
 const struct zynqmp_disp_format *fmt)
 {
unsigned int i;
-   u32 val;
+   u32 val, reg;
 
-   val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_FMT);
-   val &= zynqmp_disp_layer_is_video(layer)
-   ? ~ZYNQMP_DISP_AV_BUF_FMT_NL_VID_MASK
-   : ~ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_MASK;
-   val |= fmt->buf_fmt;
-   zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_FMT, val);
+   layer->disp_fmt = fmt;
+   if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE) {
+   reg = ZYNQMP_DISP_AV_BUF_FMT;
+   val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_FMT);
+   val &= zynqmp_disp_layer_is_video(layer)
+   ? ~ZYNQMP_DISP_AV_BUF_FMT_NL_VID_MASK
+   : ~ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_MASK;
+   val |= fmt->buf_fmt;
+   zynqmp_disp_avbuf_write(disp, reg, val);
+   } else {
+   reg = zynqmp_disp_layer_is_video(layer)
+   ? ZYNQMP_DISP_AV_BUF_LIVE_VID_CONFIG
+   : ZYNQMP_DISP_AV_BUF_LIVE_GFX_CONFIG;
+   val = fmt->buf_fmt;
+   zynqmp_disp_avbuf_write(disp, reg, val);
+   }
 
for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_SF; i++) {
-   unsigned int reg = zynqmp_disp_layer_is_video(layer)
-? ZYNQMP_DISP_AV_BUF_VID_COMP_SF(i)
-: ZYNQMP_DISP_AV_BUF_GFX_COMP_SF(i);
+   reg = zynqmp_disp_layer_is_video(layer)
+   ? ZYNQMP_DISP_AV_BUF_VID_COMP_SF(i)
+   : ZYNQMP_DISP_AV_BUF_GFX_COMP_SF(i);
 
zynqmp_disp_avbuf_write(disp, reg, fmt->sf[i]);
}
@@ -926,6 +936,31 @@ zynqmp_disp_layer_find_format(struct zynqmp_disp_layer 
*layer,
return NULL;
 }
 
+/**
+ * zynqmp_disp_layer_find_live_format - Find format information for given
+ * media bus format
+ * @layer: The layer
+ * @drm_fmt: Media bus format to search
+ *
+ * Search display subsystem format information corresponding to the given media
+ * bus format @media_bus_format for the @layer, and return a pointer to the
+ * format descriptor.
+ *
+ * Return: A pointer to the format descriptor if found, NULL otherwise
+ */
+static const struct zynqmp_disp_format *
+zynqmp_disp_layer_find_live_format(struct zynqmp_disp_layer *layer,
+  u32 media_bus_format)
+{
+   unsigned int i;
+
+   for (i = 0; i < layer->info->num_formats; i++)
+   if (layer->info->formats[i].bus_fmt == media_bus_format)
+   return >info->formats[i];
+
+   return NULL;
+}
+
 /**
  * zynqmp_disp_layer_drm_formats - Return the DRM formats supported by the 
layer
  * @layer: The layer
@@ -1040,6 +1075,9 @@ void zynqmp_disp_layer_disable(struct zynqmp_disp_layer 
*layer)
  * @layer: The layer
  * @info: The format info
  *
+ * NOTE: Use zynqmp_disp_layer_set_live_format() to set media bus format for
+ * live video layers.
+ *
  * Set the format for @layer to @info. The layer must be disabled.
  */
 void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer,
@@ -1047,14 +1085,16 @@ void zynqmp_disp_layer_set_format(struct 
zynqmp_disp_layer *layer,
 {
unsigned int i;
 
+   if (WARN_ON(layer->mode != ZYNQMP_DPSUB_LAYER_NONLIVE))
+   return;
+
layer->disp_fmt = zynqmp_disp_layer_find_format(layer, info->format);
+   if (WARN_ON(!layer->disp_fmt))
+   return;
layer->drm_fmt = info;
 
zynqmp_disp_avbuf_set_format(layer->disp, layer, layer->disp_fmt);
 
-   if (layer->mode == ZYNQMP_DPSUB_LAYER_LIVE)
-   return;
-
/*
 * Set pconfig for each DMA channel to indicate they're part of a
 * video group.
@@ -1074,6 +1114,32 @@ void zynqmp_disp_layer_set_format(struct 
zynqmp_disp_layer *layer,
}
 }
 
+/**
+ * zynqmp_disp_layer_set_live_format - Set the live video layer format
+ * @layer: The layer
+ * @info: Th

[PATCH v4 7/7] drm/atomic-helper: Add select_output_bus_format callback

2024-04-16 Thread Anatoliy Klymenko
Add optional drm_crtc_helper_funcs.select_output_bus_format callback. This
callback allows to negotiate compatible media bus format on the link
between CRTC and connected DRM encoder or DRM bridge chain. A good usage
example is the CRTC implemented as FPGA soft IP. This kind of CRTC will
most certainly support a single output media bus format, as supporting
multiple runtime options consumes extra FPGA resources. A variety of
options for the FPGA designs are usually achieved by synthesizing IP with
different parameters.

Add drm_helper_crtc_select_output_bus_format that wraps
drm_crtc_helper_funcs.select_output_bus_format.

Incorporate select_output_bus_format callback into the format negotiation
stage to fix the input bus format of the first DRM bridge in the chain.

Save negotiated output media bus format in drm_crtc_state.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/drm_bridge.c | 14 ++--
 drivers/gpu/drm/drm_crtc_helper.c| 38 
 include/drm/drm_crtc.h   | 11 +
 include/drm/drm_crtc_helper.h|  5 +
 include/drm/drm_modeset_helper_vtables.h | 30 +
 5 files changed, 96 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 521a71c61b16..955ca108cd4b 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -28,6 +28,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -879,7 +880,8 @@ static int select_bus_fmt_recursive(struct drm_bridge 
*first_bridge,
unsigned int i, num_in_bus_fmts = 0;
struct drm_bridge_state *cur_state;
struct drm_bridge *prev_bridge;
-   u32 *in_bus_fmts;
+   struct drm_crtc *crtc = crtc_state->crtc;
+   u32 *in_bus_fmts, in_fmt;
int ret;
 
prev_bridge = drm_bridge_get_prev_bridge(cur_bridge);
@@ -933,7 +935,15 @@ static int select_bus_fmt_recursive(struct drm_bridge 
*first_bridge,
return -ENOMEM;
 
if (first_bridge == cur_bridge) {
-   cur_state->input_bus_cfg.format = in_bus_fmts[0];
+   in_fmt = drm_helper_crtc_select_output_bus_format(crtc,
+   crtc_state,
+   in_bus_fmts,
+   num_in_bus_fmts);
+   if (!in_fmt) {
+   kfree(in_bus_fmts);
+   return -ENOTSUPP;
+   }
+   cur_state->input_bus_cfg.format = in_fmt;
cur_state->output_bus_cfg.format = out_bus_fmt;
kfree(in_bus_fmts);
return 0;
diff --git a/drivers/gpu/drm/drm_crtc_helper.c 
b/drivers/gpu/drm/drm_crtc_helper.c
index 2dafc39a27cb..4d3aa39c8a82 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -1055,3 +1055,41 @@ int drm_helper_force_disable_all(struct drm_device *dev)
return ret;
 }
 EXPORT_SYMBOL(drm_helper_force_disable_all);
+
+/**
+ * drm_helper_crtc_select_output_bus_format - Select output media bus format
+ * @crtc: The CRTC to query
+ * @crtc_state: The new CRTC state
+ * @supported_fmts: List of media bus format options to pick from
+ * @num_supported_fmts: Number of media bus formats in @supported_fmts list
+ *
+ * Encoder drivers may call this helper to give the connected CRTC a chance to
+ * select compatible or preffered media bus format to use over the CRTC encoder
+ * link. Encoders should provide list of supported input MEDIA_BUS_FMT_* for
+ * CRTC to pick from. CRTC driver is expected to select preferred media bus
+ * format from the list and, once enabled, generate the signal accordingly.
+ *
+ * Returns:
+ * Selected preferred media bus format or 0 if CRTC does not support any from
+ * @supported_fmts list.
+ */
+u32 drm_helper_crtc_select_output_bus_format(struct drm_crtc *crtc,
+struct drm_crtc_state *crtc_state,
+const u32 *supported_fmts,
+unsigned int num_supported_fmts)
+{
+   if (!crtc || !crtc_state || !supported_fmts || !num_supported_fmts)
+   return 0;
+
+   if (!crtc->helper_private ||
+   !crtc->helper_private->select_output_bus_format)
+   crtc_state->output_bus_format = supported_fmts[0];
+   else
+   crtc_state->output_bus_format =
+   crtc->helper_private->select_output_bus_format(crtc,
+   crtc_state,
+   supported_fmts,
+   num_supported_fmts);
+   return crtc_state->output_bus_format;
+}
+EXPORT_SYMBOL(drm_helper_crtc_select_output_b

[PATCH v4 5/7] drm: xlnx: zynqmp_dpsub: Minimize usage of global flag

2024-04-16 Thread Anatoliy Klymenko
Avoid usage of global zynqmp_dpsub.dma_enabled flag in DPSUB layer
context. This flag signals whether the driver runs in DRM CRTC or DRM
bridge mode, assuming that all display layers share the same live or
non-live mode of operation. Using per-layer mode instead of global flag
will simplify future support of the hybrid scenario.

Remove redundant checks in DMA request/release contexts as
zynqmp_disp_layer.info is well-defined for all layer types, including the
correct number of DMA channels required for each particular layer.

Signed-off-by: Anatoliy Klymenko 
Reviewed-by: Tomi Valkeinen 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 12 +++-
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 24f1f367b1d3..8cdd74a9b772 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -1026,7 +1026,7 @@ void zynqmp_disp_layer_disable(struct zynqmp_disp_layer 
*layer)
 {
unsigned int i;
 
-   if (layer->disp->dpsub->dma_enabled) {
+   if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE) {
for (i = 0; i < layer->drm_fmt->num_planes; i++)
dmaengine_terminate_sync(layer->dmas[i].chan);
}
@@ -1052,7 +1052,7 @@ void zynqmp_disp_layer_set_format(struct 
zynqmp_disp_layer *layer,
 
zynqmp_disp_avbuf_set_format(layer->disp, layer, layer->disp_fmt);
 
-   if (!layer->disp->dpsub->dma_enabled)
+   if (layer->mode == ZYNQMP_DPSUB_LAYER_LIVE)
return;
 
/*
@@ -1090,7 +1090,7 @@ int zynqmp_disp_layer_update(struct zynqmp_disp_layer 
*layer,
const struct drm_format_info *info = layer->drm_fmt;
unsigned int i;
 
-   if (!layer->disp->dpsub->dma_enabled)
+   if (layer->mode == ZYNQMP_DPSUB_LAYER_LIVE)
return 0;
 
for (i = 0; i < info->num_planes; i++) {
@@ -1140,9 +1140,6 @@ static void zynqmp_disp_layer_release_dma(struct 
zynqmp_disp *disp,
 {
unsigned int i;
 
-   if (!layer->info || !disp->dpsub->dma_enabled)
-   return;
-
for (i = 0; i < layer->info->num_channels; i++) {
struct zynqmp_disp_layer_dma *dma = >dmas[i];
 
@@ -1183,9 +1180,6 @@ static int zynqmp_disp_layer_request_dma(struct 
zynqmp_disp *disp,
unsigned int i;
int ret;
 
-   if (!disp->dpsub->dma_enabled)
-   return 0;
-
for (i = 0; i < layer->info->num_channels; i++) {
struct zynqmp_disp_layer_dma *dma = >dmas[i];
char dma_channel_name[16];

-- 
2.25.1



[PATCH v4 4/7] drm: xlnx: zynqmp_dpsub: Anounce supported input formats

2024-04-16 Thread Anatoliy Klymenko
DPSUB in bridge mode supports multiple input media bus formats.

Announce the list of supported input media bus formats via
drm_bridge.atomic_get_input_bus_fmts callback. Introduce a set of live
input formats supported by DPSUB. Add safeguards to format list functions
to prevent their misuse in the different layer modes contexts.

Reviewed-by: Laurent Pinchart 
Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 110 +++--
 drivers/gpu/drm/xlnx/zynqmp_disp.h |   2 +
 drivers/gpu/drm/xlnx/zynqmp_dp.c   |  31 +++
 3 files changed, 139 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 891577475349..24f1f367b1d3 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -77,12 +78,14 @@ enum zynqmp_dpsub_layer_mode {
 /**
  * struct zynqmp_disp_format - Display subsystem format information
  * @drm_fmt: DRM format (4CC)
+ * @bus_fmt: Media bus format
  * @buf_fmt: AV buffer format
  * @swap: Flag to swap R & B for RGB formats, and U & V for YUV formats
  * @sf: Scaling factors for color components
  */
 struct zynqmp_disp_format {
u32 drm_fmt;
+   u32 bus_fmt;
u32 buf_fmt;
bool swap;
const u32 *sf;
@@ -182,6 +185,12 @@ static const u32 scaling_factors_565[] = {
ZYNQMP_DISP_AV_BUF_5BIT_SF,
 };
 
+static const u32 scaling_factors_666[] = {
+   ZYNQMP_DISP_AV_BUF_6BIT_SF,
+   ZYNQMP_DISP_AV_BUF_6BIT_SF,
+   ZYNQMP_DISP_AV_BUF_6BIT_SF,
+};
+
 static const u32 scaling_factors_888[] = {
ZYNQMP_DISP_AV_BUF_8BIT_SF,
ZYNQMP_DISP_AV_BUF_8BIT_SF,
@@ -364,6 +373,41 @@ static const struct zynqmp_disp_format avbuf_gfx_fmts[] = {
},
 };
 
+/* List of live video layer formats */
+static const struct zynqmp_disp_format avbuf_live_fmts[] = {
+   {
+   .drm_fmt= DRM_FORMAT_RGB565,
+   .bus_fmt= MEDIA_BUS_FMT_RGB666_1X18,
+   .buf_fmt= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_6 |
+ ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB,
+   .sf = scaling_factors_666,
+   }, {
+   .drm_fmt= DRM_FORMAT_RGB888,
+   .bus_fmt= MEDIA_BUS_FMT_RGB888_1X24,
+   .buf_fmt= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 |
+ ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB,
+   .sf = scaling_factors_888,
+   }, {
+   .drm_fmt= DRM_FORMAT_YUV422,
+   .bus_fmt= MEDIA_BUS_FMT_UYVY8_1X16,
+   .buf_fmt= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 |
+ ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422,
+   .sf = scaling_factors_888,
+   }, {
+   .drm_fmt= DRM_FORMAT_YUV444,
+   .bus_fmt= MEDIA_BUS_FMT_VUY8_1X24,
+   .buf_fmt= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 |
+ ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV444,
+   .sf = scaling_factors_888,
+   }, {
+   .drm_fmt= DRM_FORMAT_P210,
+   .bus_fmt= MEDIA_BUS_FMT_UYVY10_1X20,
+   .buf_fmt= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_10 |
+ ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422,
+   .sf = scaling_factors_101010,
+   },
+};
+
 static u32 zynqmp_disp_avbuf_read(struct zynqmp_disp *disp, int reg)
 {
return readl(disp->avbuf.base + reg);
@@ -887,6 +931,11 @@ zynqmp_disp_layer_find_format(struct zynqmp_disp_layer 
*layer,
  * @layer: The layer
  * @num_formats: Pointer to the returned number of formats
  *
+ * NOTE: This function doesn't make sense for live video layers and will
+ * always return an empty list in such cases. zynqmp_disp_live_layer_formats()
+ * should be used to query a list of media bus formats supported by the live
+ * video input layer.
+ *
  * Return: A newly allocated u32 array that stores all the DRM formats
  * supported by the layer. The number of formats in the array is returned
  * through the num_formats argument.
@@ -897,10 +946,17 @@ u32 *zynqmp_disp_layer_drm_formats(struct 
zynqmp_disp_layer *layer,
unsigned int i;
u32 *formats;
 
+   if (WARN_ON(!layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE)) {
+   *num_formats = 0;
+   return NULL;
+   }
+
formats = kcalloc(layer->info->num_formats, sizeof(*formats),
  GFP_KERNEL);
-   if (!formats)
+   if (!formats) {
+   *num_formats = 0;
return NULL;
+   }
 
for (i = 0; i < layer->info->num_formats; ++i)
 

[PATCH v4 1/7] drm: xlnx: zynqmp_dpsub: Set layer mode during creation

2024-04-16 Thread Anatoliy Klymenko
Set layer mode of operation (live or dma-based) during layer creation.

Each DPSUB layer mode of operation is defined by corresponding DT node port
connection, so it is possible to assign it during layer object creation.
Previously it was set in layer enable functions, although it is too late
as setting layer format depends on layer mode, and should be done before
given layer enabled.

Signed-off-by: Anatoliy Klymenko 
Reviewed-by: Laurent Pinchart 
Reviewed-by: Tomi Valkeinen 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 21 +
 drivers/gpu/drm/xlnx/zynqmp_disp.h | 13 +
 drivers/gpu/drm/xlnx/zynqmp_dp.c   |  2 +-
 drivers/gpu/drm/xlnx/zynqmp_kms.c  |  2 +-
 4 files changed, 20 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 8a39b3accce5..891577475349 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -64,6 +64,16 @@
 
 #define ZYNQMP_DISP_MAX_NUM_SUB_PLANES 3
 
+/**
+ * enum zynqmp_dpsub_layer_mode - Layer mode
+ * @ZYNQMP_DPSUB_LAYER_NONLIVE: non-live (memory) mode
+ * @ZYNQMP_DPSUB_LAYER_LIVE: live (stream) mode
+ */
+enum zynqmp_dpsub_layer_mode {
+   ZYNQMP_DPSUB_LAYER_NONLIVE,
+   ZYNQMP_DPSUB_LAYER_LIVE,
+};
+
 /**
  * struct zynqmp_disp_format - Display subsystem format information
  * @drm_fmt: DRM format (4CC)
@@ -902,15 +912,12 @@ u32 *zynqmp_disp_layer_drm_formats(struct 
zynqmp_disp_layer *layer,
 /**
  * zynqmp_disp_layer_enable - Enable a layer
  * @layer: The layer
- * @mode: Operating mode of layer
  *
  * Enable the @layer in the audio/video buffer manager and the blender. DMA
  * channels are started separately by zynqmp_disp_layer_update().
  */
-void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer,
- enum zynqmp_dpsub_layer_mode mode)
+void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer)
 {
-   layer->mode = mode;
zynqmp_disp_avbuf_enable_video(layer->disp, layer);
zynqmp_disp_blend_layer_enable(layer->disp, layer);
 }
@@ -1134,6 +1141,12 @@ static int zynqmp_disp_create_layers(struct zynqmp_disp 
*disp)
layer->id = i;
layer->disp = disp;
layer->info = _info[i];
+   /*
+* For now assume dpsub works in either live or non-live mode 
for both layers.
+* Hybrid mode is not supported yet.
+*/
+   layer->mode = disp->dpsub->dma_enabled ? 
ZYNQMP_DPSUB_LAYER_NONLIVE
+  : 
ZYNQMP_DPSUB_LAYER_LIVE;
 
ret = zynqmp_disp_layer_request_dma(disp, layer);
if (ret)
diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.h 
b/drivers/gpu/drm/xlnx/zynqmp_disp.h
index 123cffac08be..9b8b202224d9 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.h
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.h
@@ -42,16 +42,6 @@ enum zynqmp_dpsub_layer_id {
ZYNQMP_DPSUB_LAYER_GFX,
 };
 
-/**
- * enum zynqmp_dpsub_layer_mode - Layer mode
- * @ZYNQMP_DPSUB_LAYER_NONLIVE: non-live (memory) mode
- * @ZYNQMP_DPSUB_LAYER_LIVE: live (stream) mode
- */
-enum zynqmp_dpsub_layer_mode {
-   ZYNQMP_DPSUB_LAYER_NONLIVE,
-   ZYNQMP_DPSUB_LAYER_LIVE,
-};
-
 void zynqmp_disp_enable(struct zynqmp_disp *disp);
 void zynqmp_disp_disable(struct zynqmp_disp *disp);
 int zynqmp_disp_setup_clock(struct zynqmp_disp *disp,
@@ -62,8 +52,7 @@ void zynqmp_disp_blend_set_global_alpha(struct zynqmp_disp 
*disp,
 
 u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer *layer,
   unsigned int *num_formats);
-void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer,
- enum zynqmp_dpsub_layer_mode mode);
+void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer);
 void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer);
 void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer,
  const struct drm_format_info *info);
diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index 1846c4971fd8..04b6bcac3b07 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -1295,7 +1295,7 @@ static void zynqmp_dp_disp_enable(struct zynqmp_dp *dp,
/* TODO: Make the format configurable. */
info = drm_format_info(DRM_FORMAT_YUV422);
zynqmp_disp_layer_set_format(layer, info);
-   zynqmp_disp_layer_enable(layer, ZYNQMP_DPSUB_LAYER_LIVE);
+   zynqmp_disp_layer_enable(layer);
 
if (layer_id == ZYNQMP_DPSUB_LAYER_GFX)
zynqmp_disp_blend_set_global_alpha(dp->dpsub->disp, true, 255);
diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c 
b/drivers/gpu/drm/xlnx/zynqmp_kms.c
index db3bb4afbfc4..43bf416b33d5 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_kms.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_kms.

[PATCH v4 3/7] drm: xlnx: zynqmp_dpsub: Add connected live layer helper

2024-04-16 Thread Anatoliy Klymenko
Add a helper function capturing the first connected live display layer
discovery logic.

Signed-off-by: Anatoliy Klymenko 
Reviewed-by: Tomi Valkeinen 
---
 drivers/gpu/drm/xlnx/zynqmp_dp.c | 37 +++--
 1 file changed, 23 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index 04b6bcac3b07..7faeb010e1ae 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -1276,28 +1276,40 @@ static void zynqmp_dp_encoder_mode_set_stream(struct 
zynqmp_dp *dp,
  * DISP Configuration
  */
 
+/**
+ * zynqmp_dp_disp_connected_live_layer - Return the first connected live layer
+ * @dp: DisplayPort IP core structure
+ *
+ * Return: The first connected live display layer or NULL if none of the live
+ * layers are connected.
+ */
+static struct zynqmp_disp_layer *
+zynqmp_dp_disp_connected_live_layer(struct zynqmp_dp *dp)
+{
+   if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_VIDEO))
+   return dp->dpsub->layers[ZYNQMP_DPSUB_LAYER_VID];
+   else if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_GFX))
+   return dp->dpsub->layers[ZYNQMP_DPSUB_LAYER_GFX];
+   else
+   return NULL;
+}
+
 static void zynqmp_dp_disp_enable(struct zynqmp_dp *dp,
  struct drm_bridge_state *old_bridge_state)
 {
-   enum zynqmp_dpsub_layer_id layer_id;
struct zynqmp_disp_layer *layer;
const struct drm_format_info *info;
 
-   if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_VIDEO))
-   layer_id = ZYNQMP_DPSUB_LAYER_VID;
-   else if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_GFX))
-   layer_id = ZYNQMP_DPSUB_LAYER_GFX;
-   else
+   layer = zynqmp_dp_disp_connected_live_layer(dp);
+   if (!layer)
return;
 
-   layer = dp->dpsub->layers[layer_id];
-
/* TODO: Make the format configurable. */
info = drm_format_info(DRM_FORMAT_YUV422);
zynqmp_disp_layer_set_format(layer, info);
zynqmp_disp_layer_enable(layer);
 
-   if (layer_id == ZYNQMP_DPSUB_LAYER_GFX)
+   if (layer == dp->dpsub->layers[ZYNQMP_DPSUB_LAYER_GFX])
zynqmp_disp_blend_set_global_alpha(dp->dpsub->disp, true, 255);
else
zynqmp_disp_blend_set_global_alpha(dp->dpsub->disp, false, 0);
@@ -1310,11 +1322,8 @@ static void zynqmp_dp_disp_disable(struct zynqmp_dp *dp,
 {
struct zynqmp_disp_layer *layer;
 
-   if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_VIDEO))
-   layer = dp->dpsub->layers[ZYNQMP_DPSUB_LAYER_VID];
-   else if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_GFX))
-   layer = dp->dpsub->layers[ZYNQMP_DPSUB_LAYER_GFX];
-   else
+   layer = zynqmp_dp_disp_connected_live_layer(dp);
+   if (!layer)
return;
 
zynqmp_disp_disable(dp->dpsub->disp);

-- 
2.25.1



[PATCH v4 2/7] drm: xlnx: zynqmp_dpsub: Update live format defines

2024-04-16 Thread Anatoliy Klymenko
Update live format defines to match DPSUB AV_BUF_LIVE_VID_CONFIG register
layout. These defines were never referenced before, so no other changes
required.

Reviewed-by: Laurent Pinchart 
Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp_regs.h | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp_regs.h 
b/drivers/gpu/drm/xlnx/zynqmp_disp_regs.h
index f92a006d5070..fa3935384834 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp_regs.h
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp_regs.h
@@ -165,10 +165,10 @@
 #define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_10  0x2
 #define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_12  0x3
 #define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_MASKGENMASK(2, 0)
-#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB 0x0
-#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV444  0x1
-#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422  0x2
-#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YONLY   0x3
+#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB (0x0 << 4)
+#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV444  (0x1 << 4)
+#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422  (0x2 << 4)
+#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YONLY   (0x3 << 4)
 #define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_MASKGENMASK(5, 4)
 #define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_CB_FIRSTBIT(8)
 #define ZYNQMP_DISP_AV_BUF_PALETTE_MEMORY  0x400

-- 
2.25.1



[PATCH v4 0/7] Managing live video input format for ZynqMP DPSUB

2024-04-16 Thread Anatoliy Klymenko
Implement live video input format setting for ZynqMP DPSUB.

ZynqMP DPSUB can operate in 2 modes: DMA-based and live.

In the live mode, DPSUB receives a live video signal from FPGA-based CRTC.
DPSUB acts as a DRM encoder bridge in such a scenario. To properly tune
into the incoming video signal, DPSUB should be programmed with the proper
media bus format. This patch series addresses this task.

Patch 1/7: Set the DPSUB layer mode of operation prior to enabling the
layer. Allows to use layer operational mode before its enablement.

Patch 2/7: Update some IP register defines.

Patch 3/7: Factor out some code into a helper function.

Patch 4/7: Announce supported input media bus formats via
drm_bridge_funcs.atomic_get_input_bus_fmts callback.

Patch 5/7: Minimize usage of a global flag. Minor improvement.

Patch 6/7: Program DPSUB live video input format based on selected bus
config in the new atomic bridge state.

Patch 7/7: New optional CRTC atomic helper proposal that will allow to
negotiate video signal format between CRTC and connected encoder.
Incorporate this callback into the DRM bridge format negotiation process.
Save negotiated output format in drm_crtc_state. Reference usage of this
API is available here:
https://github.com/onotole/linux/tree/dpsub-live-in

To: Laurent Pinchart 
To: Maarten Lankhorst 
To: Maxime Ripard 
To: Thomas Zimmermann 
To: David Airlie 
To: Daniel Vetter 
To: Michal Simek 
To: Andrzej Hajda 
To: Neil Armstrong 
To: Robert Foss 
To: Jonas Karlman 
To: Jernej Skrabec 
To: Rob Herring 
To: Krzysztof Kozlowski 
To: Conor Dooley 
To: Mauro Carvalho Chehab 
Cc: Tomi Valkeinen 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-arm-ker...@lists.infradead.org
Cc: linux-ker...@vger.kernel.org
Cc: devicet...@vger.kernel.org
Cc: linux-me...@vger.kernel.org
Signed-off-by: Anatoliy Klymenko 

Changes in v4:
- Replace controversial reference driver patches with the private
  repository link.
- Split display layer format manipulation functions into 2 separate cases
  for diferet layer modes.
- Address misc review comments (typos, comments, etc.)

Link to v3: 
https://lore.kernel.org/r/20240321-dp-live-fmt-v3-0-d5090d796...@amd.com

Changes in v3:
- Add connected live layer helper
- Include reference DRM format in zynqmp_disp_format for live layerss.
- Add default bus format list for non-live case.
- Explain removal of redundant checks in the commit message.
- Minor fixes and improvements from review comments.

Link to v2: 
https://lore.kernel.org/r/20240312-dp-live-fmt-v2-0-a9c35dc5c...@amd.com

Changes in v2:
- Factor out register defines update into separate patch.
- Add some improvements minimizing ithe usage of a global flag.
- Reuse existing format setting API instead of introducing new versions.
- Add warning around NULL check on new bridge state within atomic enable
  callback.
- Add drm_helper_crtc_select_output_bus_format() that wraps
  drm_crtc_helper_funcs.select_output_bus_format().
- Update API comments per review recommendations.
- Address some minor review comments.
- Add reference CRTC driver that demonstrates the usage of the proposed
  drm_crtc_helper_funcs.select_output_bus_format() API.

- Link to v1: 
https://lore.kernel.org/r/20240226-dp-live-fmt-v1-0-b78c3f69c...@amd.com

---
Anatoliy Klymenko (7):
  drm: xlnx: zynqmp_dpsub: Set layer mode during creation
  drm: xlnx: zynqmp_dpsub: Update live format defines
  drm: xlnx: zynqmp_dpsub: Add connected live layer helper
  drm: xlnx: zynqmp_dpsub: Anounce supported input formats
  drm: xlnx: zynqmp_dpsub: Minimize usage of global flag
  drm: xlnx: zynqmp_dpsub: Set input live format
  drm/atomic-helper: Add select_output_bus_format callback

 drivers/gpu/drm/drm_bridge.c |  14 +-
 drivers/gpu/drm/drm_crtc_helper.c|  38 +
 drivers/gpu/drm/xlnx/zynqmp_disp.c   | 231 +++
 drivers/gpu/drm/xlnx/zynqmp_disp.h   |  17 +--
 drivers/gpu/drm/xlnx/zynqmp_disp_regs.h  |   8 +-
 drivers/gpu/drm/xlnx/zynqmp_dp.c |  81 ---
 drivers/gpu/drm/xlnx/zynqmp_kms.c|   2 +-
 include/drm/drm_crtc.h   |  11 ++
 include/drm/drm_crtc_helper.h|   5 +
 include/drm/drm_modeset_helper_vtables.h |  30 
 10 files changed, 372 insertions(+), 65 deletions(-)
---
base-commit: bfa4437fd3938ae2e186e7664b2db65bb8775670
change-id: 20240226-dp-live-fmt-6415773b5a68

Best regards,
-- 
Anatoliy Klymenko 



[PATCH v3 9/9] drm: xlnx: Intoduce TPG CRTC driver

2024-03-21 Thread Anatoliy Klymenko
DO NOT MERGE. REFERENCE ONLY.

Add CRTC driver based on AMD/Xilinx Video Test Pattern Generator IP. TPG
based FPGA design represents minimalistic harness useful for testing links
between FPGA based CRTC and external DRM encoders, both FPGA and hardened
IP based.

Add driver for AMD/Xilinx Video Timing Controller. The VTC, working in
generator mode, suplements TPG with video timing signals.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/Kconfig |  21 +
 drivers/gpu/drm/xlnx/Makefile|   4 +
 drivers/gpu/drm/xlnx/xlnx_tpg.c  | 846 +++
 drivers/gpu/drm/xlnx/xlnx_vtc.c  | 452 +++
 drivers/gpu/drm/xlnx/xlnx_vtc.h  | 101 +
 drivers/gpu/drm/xlnx/xlnx_vtc_list.c | 160 +++
 6 files changed, 1584 insertions(+)

diff --git a/drivers/gpu/drm/xlnx/Kconfig b/drivers/gpu/drm/xlnx/Kconfig
index 68ee897de9d7..c40e98c1a5e6 100644
--- a/drivers/gpu/drm/xlnx/Kconfig
+++ b/drivers/gpu/drm/xlnx/Kconfig
@@ -15,3 +15,24 @@ config DRM_ZYNQMP_DPSUB
  This is a DRM/KMS driver for ZynqMP DisplayPort controller. Choose
  this option if you have a Xilinx ZynqMP SoC with DisplayPort
  subsystem.
+
+config DRM_XLNX_BRIDGE_VTC
+   bool "Xilinx DRM VTC Driver"
+   depends on OF
+   help
+ DRM brige driver for Xilinx Video Timing Controller. Choose
+ this option to make VTC a part of the CRTC in display pipeline.
+ Currently the support is added to the Xilinx Video Mixer and
+ Xilinx PL display CRTC drivers. This driver provides ability
+ to generate timings through the bridge layer.
+
+config DRM_XLNX_TPG
+   bool "Xilinx DRM TPG Driver"
+   depends on DRM && OF
+   select DRM_XLNX_BRIDGE_VTC
+   select VIDEOMODE_HELPERS
+   help
+ CRTC driver based on AMD/Xilinx Test Pattern Generator IP. Choose
+ this driver to enable Test Pattern Generator CRTC. This driver
+ implements simplistic CRTC with the single plane and is perfect for
+ testing PL to PS and PL to PL display output pipelines.
diff --git a/drivers/gpu/drm/xlnx/Makefile b/drivers/gpu/drm/xlnx/Makefile
index ea1422a39502..26fb3ad21fa9 100644
--- a/drivers/gpu/drm/xlnx/Makefile
+++ b/drivers/gpu/drm/xlnx/Makefile
@@ -1,2 +1,6 @@
 zynqmp-dpsub-y := zynqmp_disp.o zynqmp_dpsub.o zynqmp_dp.o zynqmp_kms.o
 obj-$(CONFIG_DRM_ZYNQMP_DPSUB) += zynqmp-dpsub.o
+xlnx-tpg-objs := xlnx_tpg.o
+xlnx-tpg-$(CONFIG_DRM_XLNX_BRIDGE_VTC) += xlnx_vtc_list.o
+obj-$(CONFIG_DRM_XLNX_TPG) += xlnx-tpg.o
+obj-$(CONFIG_DRM_XLNX_BRIDGE_VTC) += xlnx_vtc.o
diff --git a/drivers/gpu/drm/xlnx/xlnx_tpg.c b/drivers/gpu/drm/xlnx/xlnx_tpg.c
new file mode 100644
index ..3056bf278414
--- /dev/null
+++ b/drivers/gpu/drm/xlnx/xlnx_tpg.c
@@ -0,0 +1,846 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx logicore test pattern generator driver
+ *
+ * Copyright (C) 2024 Advanced Micro Devices, Inc.
+ *
+ * Author: Anatoliy Klymenko 
+ *
+ * This driver introduces support for the test CRTC based on AMD/Xilinx
+ * Test Pattern Generator IP. The main goal of the driver is to enable
+ * simplistic FPGA design that could be used to test FPGA CRTC to external
+ * encoder IP connectivity.
+ * Reference: https://docs.xilinx.com/r/en-US/pg103-v-tpg
+ */
+
+#include "xlnx_vtc.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define DRIVER_NAME"xlnx-tpg"
+#define DRIVER_DESC"Xilinx TPG DRM KMS Driver"
+#define DRIVER_DATE"20240307"
+#define DRIVER_MAJOR   1
+#define DRIVER_MINOR   0
+
+#define XLNX_TPG_CONTROL   0x
+#define XLNX_TPG_GLOBAL_IRQ_EN 0x0004
+#define XLNX_TPG_IP_IRQ_EN 0x0008
+#define XLNX_TPG_IP_IRQ_STATUS 0x000C
+#define XLNX_TPG_ACTIVE_HEIGHT 0x0010
+#define XLNX_TPG_ACTIVE_WIDTH  0x0018
+#define XLNX_TPG_PATTERN_ID0x0020
+#define XLNX_TPG_COLOR_FORMAT  0x0040
+
+#define XLNX_TPG_IP_IRQ_AP_DONEBIT(0)
+
+#define XLNX_TPG_START BIT(0)
+#define XLNX_TPG_AUTO_RESTART  BIT(7)
+
+enum xlnx_tpg_pattern {
+   XTPG_PAT_HORIZONTAL_RAMP = 0x1,
+   XTPG_PAT_VERTICAL_RAMP,
+   XTPG_PAT_TEMPORAL_RAMP,
+   XTPG_PAT_SOLID_RED,
+   XTPG_PAT_SOLID_GREEN,
+   XTPG_PAT_SOLID_BLUE,
+   XTPG_PAT_SOLID_BLACK,
+   XTPG_PAT_SOLID_WHITE,
+   XTPG_PAT_COLOR_BARS,
+   XTPG_PAT_ZONE_PLATE,
+   XTPG_PAT_TARTAN_COLOR_BARS,
+   XTPG_PAT_CROSS_HATCH,
+   XTPG_PAT_COLOR_SWEEP,
+   XTPG_PAT_COMBO_RAMP,
+   XTPG_PAT_CHECKER_BOARD,
+   XTPG_PAT_DP_COLOR_RAMP,
+   XTPG_PAT_DP_VERTICAL_LINES,
+   XTPG_PAT_DP_COLOR_SQUARE,
+};
+
+static const struct drm_prop_enum_list xtp

[PATCH v3 8/9] dt-bindings: xlnx: Add VTC and TPG bindings

2024-03-21 Thread Anatoliy Klymenko
DO NOT MERGE. REFERENCE ONLY.

Add binding for AMD/Xilinx Video Timing Controller and Test Pattern
Generator.

Copy media-bus-formats.h into dt-bindings/media to suplement TPG DT node.

Signed-off-by: Anatoliy Klymenko 
---
 .../bindings/display/xlnx/xlnx,v-tpg.yaml  |  87 ++
 .../devicetree/bindings/display/xlnx/xlnx,vtc.yaml |  65 
 include/dt-bindings/media/media-bus-format.h   | 177 +
 3 files changed, 329 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/xlnx/xlnx,v-tpg.yaml 
b/Documentation/devicetree/bindings/display/xlnx/xlnx,v-tpg.yaml
new file mode 100644
index ..df5ee5b547cf
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/xlnx/xlnx,v-tpg.yaml
@@ -0,0 +1,87 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/xlnx/xlnx,v-tpg.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Xilinx Video Test Pattern Generator (TPG)
+
+description:
+  AMD/Xilinx Video Test Pattern Generator IP is a soft IP designed to
+  generate test video signal in AXI4-Stream Video format.
+  https://docs.xilinx.com/r/en-US/pg103-v-tpg
+
+maintainers:
+  - Anatoliy Klymenko 
+
+properties:
+  compatible:
+description:
+  TPG versions backward-compatible with previous versions should list all
+  compatible versions in the newer to older order.
+enum: ["xlnx,v-tpg-8.0", "xlnx,v-tpg-8.2"]
+
+  reg:
+maxItems: 1
+
+  interrupts:
+maxItems: 1
+
+  bus-format:
+description: Output media bus format, one of MEDIA_BUS_FMT_*
+maxItems: 1
+
+  xlnx,bridge:
+   description: Reference to Video Timing Controller
+   maxItems: 1
+
+  ports:
+$ref: /schemas/graph.yaml#/properties/ports
+description:
+  Connections from and to external components in the video pipeline.
+
+properties:
+  port@0:
+   $ref: /schemas/graph.yaml#/properties/port
+   description: Sink port connected to downstream video IP.
+
+  port@1:
+   $ref: /schemas/graph.yaml#/properties/port
+   description: Source port to connect to optional video signal source.
+
+required:
+  - port@0
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - bus-format
+  - xlnx,bridge
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+#include 
+
+tpg_0: tpg@4005 {
+  compatible = "xlnx,v-tpg-8.0";
+  reg = <0x4005 0x1>;
+  interrupts = <0 89 4>;
+  xlnx,bridge = <_3>;
+  bus-format = ;
+  ports {
+#address-cells = <1>;
+#size-cells = <0>;
+port@0 {
+  reg = <0>;
+  tpg_out: endpoint {
+remote-endpoint = <_encoder>;
+  };
+};
+  };
+};
+
+...
diff --git a/Documentation/devicetree/bindings/display/xlnx/xlnx,vtc.yaml 
b/Documentation/devicetree/bindings/display/xlnx/xlnx,vtc.yaml
new file mode 100644
index ..51eb12cdcfdc
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/xlnx/xlnx,vtc.yaml
@@ -0,0 +1,65 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/xlnx/xlnx,vtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Device-Tree for Xilinx Video Timing Controller(VTC)
+
+description:
+  Xilinx VTC is a general purpose video timing generator and detector.
+  The input side of this core automatically detects horizontal and
+  vertical synchronization, pulses, polarity, blanking timing and active 
pixels.
+  While on the output, it generates the horizontal and vertical blanking and
+  synchronization pulses used with a standard video system including support
+  for programmable pulse polarity.
+
+  The core is commonly used with Video in to AXI4-Stream core to detect the
+  format and timing of incoming video data or with AXI4-Stream to Video out 
core
+  to generate outgoing video timing for downstream sinks like a video monitor.
+
+  For details please refer to
+  https://docs.xilinx.com/r/en-US/pg016_v_tc
+
+maintainers:
+  - Sagar Vishal 
+
+properties:
+  compatible:
+const: "xlnx,bridge-v-tc-6.1"
+
+  reg:
+maxItems: 1
+
+  xlnx,pixels-per-clock:
+description: Pixels per clock of the stream.
+enum: [1, 2, 4]
+
+  clocks:
+minItems: 2
+
+  clock-names:
+items:
+  - const: clk
+  - const: s_axi_aclk
+
+required:
+  - compatible
+  - reg
+  - xlnx,pixels-per-clock
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+v_tc_0: v_tc@8001 {
+  clock-names = "clk", "s_axi_aclk";
+  clocks = <_wiz_0>, <_clk_0>;
+  compatible = "xlnx,bridge-v-tc-6.1";
+  xlnx,pixels-per-clock = <1>;
+  reg = <0x8001 0x1>;
+};
+
+...
diff --git a/include/dt-bindings/media/medi

[PATCH v3 3/9] drm: xlnx: zynqmp_dpsub: Add connected live layer helper

2024-03-21 Thread Anatoliy Klymenko
Add a helper function capturing the first connected live display layer
discovery logic.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_dp.c | 37 +++--
 1 file changed, 23 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index 04b6bcac3b07..4faafdd76798 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -1276,28 +1276,40 @@ static void zynqmp_dp_encoder_mode_set_stream(struct 
zynqmp_dp *dp,
  * DISP Configuration
  */
 
+/**
+ * zynqmp_dp_disp_connected_live_layer - Return the first connected live layer
+ * @dp: DisplayPort IP core structure
+ *
+ * Return: The first connected live display layer or NULL if none of the live
+ * layer is connected.
+ */
+static struct zynqmp_disp_layer *
+zynqmp_dp_disp_connected_live_layer(struct zynqmp_dp *dp)
+{
+   if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_VIDEO))
+   return dp->dpsub->layers[ZYNQMP_DPSUB_LAYER_VID];
+   else if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_GFX))
+   return dp->dpsub->layers[ZYNQMP_DPSUB_LAYER_GFX];
+   else
+   return NULL;
+}
+
 static void zynqmp_dp_disp_enable(struct zynqmp_dp *dp,
  struct drm_bridge_state *old_bridge_state)
 {
-   enum zynqmp_dpsub_layer_id layer_id;
struct zynqmp_disp_layer *layer;
const struct drm_format_info *info;
 
-   if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_VIDEO))
-   layer_id = ZYNQMP_DPSUB_LAYER_VID;
-   else if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_GFX))
-   layer_id = ZYNQMP_DPSUB_LAYER_GFX;
-   else
+   layer = zynqmp_dp_disp_connected_live_layer(dp);
+   if (!layer)
return;
 
-   layer = dp->dpsub->layers[layer_id];
-
/* TODO: Make the format configurable. */
info = drm_format_info(DRM_FORMAT_YUV422);
zynqmp_disp_layer_set_format(layer, info);
zynqmp_disp_layer_enable(layer);
 
-   if (layer_id == ZYNQMP_DPSUB_LAYER_GFX)
+   if (layer == dp->dpsub->layers[ZYNQMP_DPSUB_LAYER_GFX])
zynqmp_disp_blend_set_global_alpha(dp->dpsub->disp, true, 255);
else
zynqmp_disp_blend_set_global_alpha(dp->dpsub->disp, false, 0);
@@ -1310,11 +1322,8 @@ static void zynqmp_dp_disp_disable(struct zynqmp_dp *dp,
 {
struct zynqmp_disp_layer *layer;
 
-   if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_VIDEO))
-   layer = dp->dpsub->layers[ZYNQMP_DPSUB_LAYER_VID];
-   else if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_GFX))
-   layer = dp->dpsub->layers[ZYNQMP_DPSUB_LAYER_GFX];
-   else
+   layer = zynqmp_dp_disp_connected_live_layer(dp);
+   if (!layer)
return;
 
zynqmp_disp_disable(dp->dpsub->disp);

-- 
2.25.1



[PATCH v3 7/9] drm/atomic-helper: Add select_output_bus_format callback

2024-03-21 Thread Anatoliy Klymenko
Add optional drm_crtc_helper_funcs.select_output_bus_format callback. This
callback allows to negotiate compatible media bus format on the link
between CRTC and connected DRM encoder or DRM bridge chain. A good usage
example is the CRTC implemented as FPGA soft IP. This kind of CRTC will
most certainly support a single output media bus format, as supporting
multiple runtime options consumes extra FPGA resources. A variety of
options for the FPGA designs are usually achieved by synthesizing IP with
different parameters.

Add drm_helper_crtc_select_output_bus_format that wraps
drm_crtc_helper_funcs.select_output_bus_format.

Incorporate select_output_bus_format callback into the format negotiation
stage to fix the input bus format of the first DRM bridge in the chain.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/drm_bridge.c | 14 +++--
 drivers/gpu/drm/drm_crtc_helper.c| 36 
 include/drm/drm_crtc_helper.h|  5 +
 include/drm/drm_modeset_helper_vtables.h | 30 ++
 4 files changed, 83 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 521a71c61b16..955ca108cd4b 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -28,6 +28,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -879,7 +880,8 @@ static int select_bus_fmt_recursive(struct drm_bridge 
*first_bridge,
unsigned int i, num_in_bus_fmts = 0;
struct drm_bridge_state *cur_state;
struct drm_bridge *prev_bridge;
-   u32 *in_bus_fmts;
+   struct drm_crtc *crtc = crtc_state->crtc;
+   u32 *in_bus_fmts, in_fmt;
int ret;
 
prev_bridge = drm_bridge_get_prev_bridge(cur_bridge);
@@ -933,7 +935,15 @@ static int select_bus_fmt_recursive(struct drm_bridge 
*first_bridge,
return -ENOMEM;
 
if (first_bridge == cur_bridge) {
-   cur_state->input_bus_cfg.format = in_bus_fmts[0];
+   in_fmt = drm_helper_crtc_select_output_bus_format(crtc,
+   crtc_state,
+   in_bus_fmts,
+   num_in_bus_fmts);
+   if (!in_fmt) {
+   kfree(in_bus_fmts);
+   return -ENOTSUPP;
+   }
+   cur_state->input_bus_cfg.format = in_fmt;
cur_state->output_bus_cfg.format = out_bus_fmt;
kfree(in_bus_fmts);
return 0;
diff --git a/drivers/gpu/drm/drm_crtc_helper.c 
b/drivers/gpu/drm/drm_crtc_helper.c
index 2dafc39a27cb..f2e12a3c4e5f 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -1055,3 +1055,39 @@ int drm_helper_force_disable_all(struct drm_device *dev)
return ret;
 }
 EXPORT_SYMBOL(drm_helper_force_disable_all);
+
+/**
+ * drm_helper_crtc_select_output_bus_format - Select output media bus format
+ * @crtc: The CRTC to query
+ * @crtc_state: The new CRTC state
+ * @supported_fmts: List of media bus format options to pick from
+ * @num_supported_fmts: Number of media bus formats in @supported_fmts list
+ *
+ * Encoder drivers may call this helper to give the connected CRTC a chance to
+ * select compatible or preffered media bus format to use over the CRTC encoder
+ * link. Encoders should provide list of supported input MEDIA_BUS_FMT_* for
+ * CRTC to pick from. CRTC driver is expected to select preferred media bus
+ * format from the list and, once enabled, generate the signal accordingly.
+ *
+ * Returns:
+ * Selected preferred media bus format or 0 if CRTC does not support any from
+ * @supported_fmts list.
+ */
+u32 drm_helper_crtc_select_output_bus_format(struct drm_crtc *crtc,
+struct drm_crtc_state *crtc_state,
+const u32 *supported_fmts,
+unsigned int num_supported_fmts)
+{
+   if (!crtc || !supported_fmts || !num_supported_fmts)
+   return 0;
+
+   if (!crtc->helper_private ||
+   !crtc->helper_private->select_output_bus_format)
+   return supported_fmts[0];
+
+   return crtc->helper_private->select_output_bus_format(crtc,
+   crtc_state,
+   supported_fmts,
+   num_supported_fmts);
+}
+EXPORT_SYMBOL(drm_helper_crtc_select_output_bus_format);
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index 8c886fc46ef2..b7eb52f3ce41 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -38,6 +38,7 @@
 struct drm_atomic_state;
 struct drm_connector;
 struct drm_c

[PATCH v3 6/9] drm: xlnx: zynqmp_dpsub: Set input live format

2024-03-21 Thread Anatoliy Klymenko
Program live video input format according to selected media bus format.

In the bridge mode of operation, DPSUB is connected to FPGA CRTC which
almost certainly supports a single media bus format as its output. Expect
this to be delivered via the new bridge atomic state. Program DPSUB
registers accordingly. Update zynqmp_disp_layer_set_format() API to fit
both live and non-live layer types.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 66 +-
 drivers/gpu/drm/xlnx/zynqmp_disp.h |  2 +-
 drivers/gpu/drm/xlnx/zynqmp_dp.c   | 13 +---
 drivers/gpu/drm/xlnx/zynqmp_kms.c  |  2 +-
 4 files changed, 55 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 0c2b3f4bffa6..a385d22d428e 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -436,19 +436,28 @@ static void zynqmp_disp_avbuf_set_format(struct 
zynqmp_disp *disp,
 const struct zynqmp_disp_format *fmt)
 {
unsigned int i;
-   u32 val;
+   u32 val, reg;
 
-   val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_FMT);
-   val &= zynqmp_disp_layer_is_video(layer)
-   ? ~ZYNQMP_DISP_AV_BUF_FMT_NL_VID_MASK
-   : ~ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_MASK;
-   val |= fmt->buf_fmt;
-   zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_FMT, val);
+   layer->disp_fmt = fmt;
+   if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE) {
+   reg = ZYNQMP_DISP_AV_BUF_FMT;
+   val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_FMT);
+   val &= zynqmp_disp_layer_is_video(layer)
+   ? ~ZYNQMP_DISP_AV_BUF_FMT_NL_VID_MASK
+   : ~ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_MASK;
+   val |= fmt->buf_fmt;
+   } else {
+   reg = zynqmp_disp_layer_is_video(layer)
+   ? ZYNQMP_DISP_AV_BUF_LIVE_VID_CONFIG
+   : ZYNQMP_DISP_AV_BUF_LIVE_GFX_CONFIG;
+   val = fmt->buf_fmt;
+   }
+   zynqmp_disp_avbuf_write(disp, reg, val);
 
for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_SF; i++) {
-   unsigned int reg = zynqmp_disp_layer_is_video(layer)
-? ZYNQMP_DISP_AV_BUF_VID_COMP_SF(i)
-: ZYNQMP_DISP_AV_BUF_GFX_COMP_SF(i);
+   reg = zynqmp_disp_layer_is_video(layer)
+   ? ZYNQMP_DISP_AV_BUF_VID_COMP_SF(i)
+   : ZYNQMP_DISP_AV_BUF_GFX_COMP_SF(i);
 
zynqmp_disp_avbuf_write(disp, reg, fmt->sf[i]);
}
@@ -902,25 +911,33 @@ static void zynqmp_disp_audio_disable(struct zynqmp_disp 
*disp)
  */
 
 /**
- * zynqmp_disp_layer_find_format - Find format information for a DRM format
+ * zynqmp_disp_layer_find_format - Find format information for a DRM or media
+ * bus format
  * @layer: The layer
- * @drm_fmt: DRM format to search
+ * @drm_or_bus_format: DRM or media bus format
  *
  * Search display subsystem format information corresponding to the given DRM
- * format @drm_fmt for the @layer, and return a pointer to the format
- * descriptor.
+ * or media bus format @drm_or_bus_format for the @layer, and return a pointer
+ * to the format descriptor. Search key choice depends on @layer mode, for live
+ * layers search is done by zynqmp_disp_format.bus_fmt, and for non-live layers
+ * zynqmp_disp_format.drm_fmt is used.
  *
  * Return: A pointer to the format descriptor if found, NULL otherwise
  */
 static const struct zynqmp_disp_format *
 zynqmp_disp_layer_find_format(struct zynqmp_disp_layer *layer,
- u32 drm_fmt)
+ u32 drm_or_bus_format)
 {
unsigned int i;
+   const struct zynqmp_disp_format *disp_format;
 
for (i = 0; i < layer->info->num_formats; i++) {
-   if (layer->info->formats[i].drm_fmt == drm_fmt)
-   return >info->formats[i];
+   disp_format = >info->formats[i];
+   if ((layer->mode == ZYNQMP_DPSUB_LAYER_LIVE &&
+disp_format->bus_fmt == drm_or_bus_format) ||
+   (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE &&
+disp_format->drm_fmt == drm_or_bus_format))
+   return disp_format;
}
 
return NULL;
@@ -992,20 +1009,25 @@ void zynqmp_disp_layer_disable(struct zynqmp_disp_layer 
*layer)
 /**
  * zynqmp_disp_layer_set_format - Set the layer format
  * @layer: The layer
- * @info: The format info
+ * @drm_or_bus_format: DRM or media bus format
  *
  * Set the format for @layer to @info. The layer must be disabled.
  */
 void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer,
- const struct drm_format_info *info)
+  

[PATCH v3 5/9] drm: xlnx: zynqmp_dpsub: Minimize usage of global flag

2024-03-21 Thread Anatoliy Klymenko
Avoid usage of global zynqmp_dpsub.dma_enabled flag in DPSUB layer
context. This flag signals whether the driver runs in DRM CRTC or DRM
bridge mode, assuming that all display layers share the same live or
non-live mode of operation. Using per-layer mode instead of global flag
will simplify future support of the hybrid scenario.

Remove redundant checks in DMA request/release contexts as
zynqmp_disp_layer.info is well-defined for all layer types, including the
correct number of DMA channels required for each particular layer.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 12 +++-
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index abdc3971b193..0c2b3f4bffa6 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -980,7 +980,7 @@ void zynqmp_disp_layer_disable(struct zynqmp_disp_layer 
*layer)
 {
unsigned int i;
 
-   if (layer->disp->dpsub->dma_enabled) {
+   if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE) {
for (i = 0; i < layer->drm_fmt->num_planes; i++)
dmaengine_terminate_sync(layer->dmas[i].chan);
}
@@ -1006,7 +1006,7 @@ void zynqmp_disp_layer_set_format(struct 
zynqmp_disp_layer *layer,
 
zynqmp_disp_avbuf_set_format(layer->disp, layer, layer->disp_fmt);
 
-   if (!layer->disp->dpsub->dma_enabled)
+   if (layer->mode == ZYNQMP_DPSUB_LAYER_LIVE)
return;
 
/*
@@ -1044,7 +1044,7 @@ int zynqmp_disp_layer_update(struct zynqmp_disp_layer 
*layer,
const struct drm_format_info *info = layer->drm_fmt;
unsigned int i;
 
-   if (!layer->disp->dpsub->dma_enabled)
+   if (layer->mode == ZYNQMP_DPSUB_LAYER_LIVE)
return 0;
 
for (i = 0; i < info->num_planes; i++) {
@@ -1094,9 +1094,6 @@ static void zynqmp_disp_layer_release_dma(struct 
zynqmp_disp *disp,
 {
unsigned int i;
 
-   if (!layer->info || !disp->dpsub->dma_enabled)
-   return;
-
for (i = 0; i < layer->info->num_channels; i++) {
struct zynqmp_disp_layer_dma *dma = >dmas[i];
 
@@ -1137,9 +1134,6 @@ static int zynqmp_disp_layer_request_dma(struct 
zynqmp_disp *disp,
unsigned int i;
int ret;
 
-   if (!disp->dpsub->dma_enabled)
-   return 0;
-
for (i = 0; i < layer->info->num_channels; i++) {
struct zynqmp_disp_layer_dma *dma = >dmas[i];
char dma_channel_name[16];

-- 
2.25.1



[PATCH v3 4/9] drm: xlnx: zynqmp_dpsub: Anounce supported input formats

2024-03-21 Thread Anatoliy Klymenko
DPSUB in bridge mode supports multiple input media bus formats.

Announce the list of supported input media bus formats via
drm_bridge.atomic_get_input_bus_fmts callback.
Introduce a set of live input formats, supported by DPSUB.
Rename zynqmp_disp_layer_drm_formats() to zynqmp_disp_layer_formats() to
reflect semantics for both live and non-live layer format lists.

Reviewed-by: Laurent Pinchart 
Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 76 +-
 drivers/gpu/drm/xlnx/zynqmp_disp.h |  4 +-
 drivers/gpu/drm/xlnx/zynqmp_dp.c   | 31 
 drivers/gpu/drm/xlnx/zynqmp_kms.c  |  2 +-
 4 files changed, 101 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index e6d26ef60e89..abdc3971b193 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -77,12 +78,14 @@ enum zynqmp_dpsub_layer_mode {
 /**
  * struct zynqmp_disp_format - Display subsystem format information
  * @drm_fmt: DRM format (4CC)
+ * @bus_fmt: Media bus format
  * @buf_fmt: AV buffer format
  * @swap: Flag to swap R & B for RGB formats, and U & V for YUV formats
  * @sf: Scaling factors for color components
  */
 struct zynqmp_disp_format {
u32 drm_fmt;
+   u32 bus_fmt;
u32 buf_fmt;
bool swap;
const u32 *sf;
@@ -182,6 +185,12 @@ static const u32 scaling_factors_565[] = {
ZYNQMP_DISP_AV_BUF_5BIT_SF,
 };
 
+static const u32 scaling_factors_666[] = {
+   ZYNQMP_DISP_AV_BUF_6BIT_SF,
+   ZYNQMP_DISP_AV_BUF_6BIT_SF,
+   ZYNQMP_DISP_AV_BUF_6BIT_SF,
+};
+
 static const u32 scaling_factors_888[] = {
ZYNQMP_DISP_AV_BUF_8BIT_SF,
ZYNQMP_DISP_AV_BUF_8BIT_SF,
@@ -364,6 +373,41 @@ static const struct zynqmp_disp_format avbuf_gfx_fmts[] = {
},
 };
 
+/* List of live video layer formats */
+static const struct zynqmp_disp_format avbuf_live_fmts[] = {
+   {
+   .drm_fmt= DRM_FORMAT_RGB565,
+   .bus_fmt= MEDIA_BUS_FMT_RGB666_1X18,
+   .buf_fmt= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_6 |
+ ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB,
+   .sf = scaling_factors_666,
+   }, {
+   .drm_fmt= DRM_FORMAT_RGB888,
+   .bus_fmt= MEDIA_BUS_FMT_RGB888_1X24,
+   .buf_fmt= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 |
+ ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB,
+   .sf = scaling_factors_888,
+   }, {
+   .drm_fmt= DRM_FORMAT_YUV422,
+   .bus_fmt= MEDIA_BUS_FMT_UYVY8_1X16,
+   .buf_fmt= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 |
+ ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422,
+   .sf = scaling_factors_888,
+   }, {
+   .drm_fmt= DRM_FORMAT_YUV444,
+   .bus_fmt= MEDIA_BUS_FMT_VUY8_1X24,
+   .buf_fmt= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 |
+ ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV444,
+   .sf = scaling_factors_888,
+   }, {
+   .drm_fmt= DRM_FORMAT_P210,
+   .bus_fmt= MEDIA_BUS_FMT_UYVY10_1X20,
+   .buf_fmt= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_10 |
+ ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422,
+   .sf = scaling_factors_101010,
+   },
+};
+
 static u32 zynqmp_disp_avbuf_read(struct zynqmp_disp *disp, int reg)
 {
return readl(disp->avbuf.base + reg);
@@ -883,16 +927,17 @@ zynqmp_disp_layer_find_format(struct zynqmp_disp_layer 
*layer,
 }
 
 /**
- * zynqmp_disp_layer_drm_formats - Return the DRM formats supported by the 
layer
+ * zynqmp_disp_layer_formats - Return DRM or media bus formats supported by
+ * the layer
  * @layer: The layer
  * @num_formats: Pointer to the returned number of formats
  *
- * Return: A newly allocated u32 array that stores all the DRM formats
+ * Return: A newly allocated u32 array that stores all DRM or media bus formats
  * supported by the layer. The number of formats in the array is returned
  * through the num_formats argument.
  */
-u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer *layer,
-  unsigned int *num_formats)
+u32 *zynqmp_disp_layer_formats(struct zynqmp_disp_layer *layer,
+  unsigned int *num_formats)
 {
unsigned int i;
u32 *formats;
@@ -903,7 +948,9 @@ u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer 
*layer,
return NULL;
 
for (i = 0; i < layer->info->num_formats; ++i)
-

[PATCH v3 2/9] drm: xlnx: zynqmp_dpsub: Update live format defines

2024-03-21 Thread Anatoliy Klymenko
Update live format defines to match DPSUB AV_BUF_LIVE_VID_CONFIG register
layout.

Reviewed-by: Laurent Pinchart 
Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp_regs.h | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp_regs.h 
b/drivers/gpu/drm/xlnx/zynqmp_disp_regs.h
index f92a006d5070..fa3935384834 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp_regs.h
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp_regs.h
@@ -165,10 +165,10 @@
 #define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_10  0x2
 #define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_12  0x3
 #define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_MASKGENMASK(2, 0)
-#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB 0x0
-#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV444  0x1
-#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422  0x2
-#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YONLY   0x3
+#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB (0x0 << 4)
+#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV444  (0x1 << 4)
+#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422  (0x2 << 4)
+#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YONLY   (0x3 << 4)
 #define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_MASKGENMASK(5, 4)
 #define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_CB_FIRSTBIT(8)
 #define ZYNQMP_DISP_AV_BUF_PALETTE_MEMORY  0x400

-- 
2.25.1



[PATCH v3 1/9] drm: xlnx: zynqmp_dpsub: Set layer mode during creation

2024-03-21 Thread Anatoliy Klymenko
Set layer mode of operation (live or dma-based) during layer creation.

Each DPSUB layer mode of operation is defined by corresponding DT node port
connection, so it is possible to assign it during layer object creation.
Previously it was set in layer enable functions, although it is too late
as setting layer format depends on layer mode, and should be done before
given layer enabled.

Signed-off-by: Anatoliy Klymenko 
Reviewed-by: Laurent Pinchart 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 20 
 drivers/gpu/drm/xlnx/zynqmp_disp.h | 13 +
 drivers/gpu/drm/xlnx/zynqmp_dp.c   |  2 +-
 drivers/gpu/drm/xlnx/zynqmp_kms.c  |  2 +-
 4 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 8a39b3accce5..e6d26ef60e89 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -64,6 +64,16 @@
 
 #define ZYNQMP_DISP_MAX_NUM_SUB_PLANES 3
 
+/**
+ * enum zynqmp_dpsub_layer_mode - Layer mode
+ * @ZYNQMP_DPSUB_LAYER_NONLIVE: non-live (memory) mode
+ * @ZYNQMP_DPSUB_LAYER_LIVE: live (stream) mode
+ */
+enum zynqmp_dpsub_layer_mode {
+   ZYNQMP_DPSUB_LAYER_NONLIVE,
+   ZYNQMP_DPSUB_LAYER_LIVE,
+};
+
 /**
  * struct zynqmp_disp_format - Display subsystem format information
  * @drm_fmt: DRM format (4CC)
@@ -902,15 +912,12 @@ u32 *zynqmp_disp_layer_drm_formats(struct 
zynqmp_disp_layer *layer,
 /**
  * zynqmp_disp_layer_enable - Enable a layer
  * @layer: The layer
- * @mode: Operating mode of layer
  *
  * Enable the @layer in the audio/video buffer manager and the blender. DMA
  * channels are started separately by zynqmp_disp_layer_update().
  */
-void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer,
- enum zynqmp_dpsub_layer_mode mode)
+void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer)
 {
-   layer->mode = mode;
zynqmp_disp_avbuf_enable_video(layer->disp, layer);
zynqmp_disp_blend_layer_enable(layer->disp, layer);
 }
@@ -1134,6 +1141,11 @@ static int zynqmp_disp_create_layers(struct zynqmp_disp 
*disp)
layer->id = i;
layer->disp = disp;
layer->info = _info[i];
+   /* For now assume dpsub works in either live or non-live mode 
for both layers.
+* Hybrid mode is not supported yet.
+*/
+   layer->mode = disp->dpsub->dma_enabled ? 
ZYNQMP_DPSUB_LAYER_NONLIVE
+  : 
ZYNQMP_DPSUB_LAYER_LIVE;
 
ret = zynqmp_disp_layer_request_dma(disp, layer);
if (ret)
diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.h 
b/drivers/gpu/drm/xlnx/zynqmp_disp.h
index 123cffac08be..9b8b202224d9 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.h
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.h
@@ -42,16 +42,6 @@ enum zynqmp_dpsub_layer_id {
ZYNQMP_DPSUB_LAYER_GFX,
 };
 
-/**
- * enum zynqmp_dpsub_layer_mode - Layer mode
- * @ZYNQMP_DPSUB_LAYER_NONLIVE: non-live (memory) mode
- * @ZYNQMP_DPSUB_LAYER_LIVE: live (stream) mode
- */
-enum zynqmp_dpsub_layer_mode {
-   ZYNQMP_DPSUB_LAYER_NONLIVE,
-   ZYNQMP_DPSUB_LAYER_LIVE,
-};
-
 void zynqmp_disp_enable(struct zynqmp_disp *disp);
 void zynqmp_disp_disable(struct zynqmp_disp *disp);
 int zynqmp_disp_setup_clock(struct zynqmp_disp *disp,
@@ -62,8 +52,7 @@ void zynqmp_disp_blend_set_global_alpha(struct zynqmp_disp 
*disp,
 
 u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer *layer,
   unsigned int *num_formats);
-void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer,
- enum zynqmp_dpsub_layer_mode mode);
+void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer);
 void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer);
 void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer,
  const struct drm_format_info *info);
diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index 1846c4971fd8..04b6bcac3b07 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -1295,7 +1295,7 @@ static void zynqmp_dp_disp_enable(struct zynqmp_dp *dp,
/* TODO: Make the format configurable. */
info = drm_format_info(DRM_FORMAT_YUV422);
zynqmp_disp_layer_set_format(layer, info);
-   zynqmp_disp_layer_enable(layer, ZYNQMP_DPSUB_LAYER_LIVE);
+   zynqmp_disp_layer_enable(layer);
 
if (layer_id == ZYNQMP_DPSUB_LAYER_GFX)
zynqmp_disp_blend_set_global_alpha(dp->dpsub->disp, true, 255);
diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c 
b/drivers/gpu/drm/xlnx/zynqmp_kms.c
index db3bb4afbfc4..43bf416b33d5 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_kms.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c
@@ -122,7 +122,7 @@ static void zynqmp_dpsub_plan

[PATCH v3 0/9] Setting live video input format for ZynqMP DPSUB

2024-03-21 Thread Anatoliy Klymenko
Implement live video input format setting for ZynqMP DPSUB.

ZynqMP DPSUB can operate in 2 modes: DMA-based and live.

In the live mode, DPSUB receives a live video signal from FPGA-based CRTC.
DPSUB acts as a DRM encoder bridge in such a scenario. To properly tune
into the incoming video signal, DPSUB should be programmed with the proper
media bus format. This patch series addresses this task.

Patch 1/9: Set the DPSUB layer mode of operation prior to enabling the
layer. Allows to use layer operational mode before its enablement.

Patch 2/9: Update some IP register defines.

Patch 3/9: Factor out some code into a helper function.

Patch 4/9: Announce supported input media bus formats via
drm_bridge_funcs.atomic_get_input_bus_fmts callback.

Patch 5/9: Minimize usage of a global flag. Minor improvement.

Patch 6/9: Program DPSUB live video input format based on selected bus
config in the new atomic bridge state.

Patch 7/9: New optional CRTC atomic helper proposal that will allow CRTC
to participate in DRM bridge chain format negotiation and impose format
restrictions. Incorporate this callback into the DRM bridge format
negotiation process.

Patch 8/9: DT bindings documentation for Video Timing Controller and Test
Pattern Generator IPs.

Patch 9/9: Reference FPGA CRTC driver based on AMD/Xilinx Test Pattern
Generator (TPG) IP. Add driver for the AMD/Xilinx Video Timing Controller
(VTC), which supplements TPG.

To: Laurent Pinchart 
To: Maarten Lankhorst 
To: Maxime Ripard 
To: Thomas Zimmermann 
To: David Airlie 
To: Daniel Vetter 
To: Michal Simek 
To: Andrzej Hajda 
To: Neil Armstrong 
To: Robert Foss 
To: Jonas Karlman 
To: Jernej Skrabec 
To: Rob Herring 
To: Krzysztof Kozlowski 
To: Conor Dooley 
To: Mauro Carvalho Chehab 
Cc: Tomi Valkeinen 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-arm-ker...@lists.infradead.org
Cc: linux-ker...@vger.kernel.org
Cc: devicet...@vger.kernel.org
Cc: linux-me...@vger.kernel.org
Signed-off-by: Anatoliy Klymenko 

Changes in v3:
- Add connected live layer helper
- Include reference DRM format in zynqmp_disp_format for live layerss.
- Add default bus format list for non-live case.
- Explain removal of redundant checks in the commit message.
- Minor fixes and improvements from review comments.

Link to v2: 
https://lore.kernel.org/r/20240312-dp-live-fmt-v2-0-a9c35dc5c...@amd.com

Changes in v2:
- Factor out register defines update into separate patch.
- Add some improvements minimizing ithe usage of a global flag.
- Reuse existing format setting API instead of introducing new versions.
- Add warning around NULL check on new bridge state within atomic enable
  callback.
- Add drm_helper_crtc_select_output_bus_format() that wraps
  drm_crtc_helper_funcs.select_output_bus_format().
- Update API comments per review recommendations.
- Address some minor review comments.
- Add reference CRTC driver that demonstrates the usage of the proposed
  drm_crtc_helper_funcs.select_output_bus_format() API.

- Link to v1: 
https://lore.kernel.org/r/20240226-dp-live-fmt-v1-0-b78c3f69c...@amd.com

---
Anatoliy Klymenko (9):
  drm: xlnx: zynqmp_dpsub: Set layer mode during creation
  drm: xlnx: zynqmp_dpsub: Update live format defines
  drm: xlnx: zynqmp_dpsub: Add connected live layer helper
  drm: xlnx: zynqmp_dpsub: Anounce supported input formats
  drm: xlnx: zynqmp_dpsub: Minimize usage of global flag
  drm: xlnx: zynqmp_dpsub: Set input live format
  drm/atomic-helper: Add select_output_bus_format callback
  dt-bindings: xlnx: Add VTC and TPG bindings
  drm: xlnx: Intoduce TPG CRTC driver

 .../bindings/display/xlnx/xlnx,v-tpg.yaml  |  87 +++
 .../devicetree/bindings/display/xlnx/xlnx,vtc.yaml |  65 ++
 drivers/gpu/drm/drm_bridge.c   |  14 +-
 drivers/gpu/drm/drm_crtc_helper.c  |  36 +
 drivers/gpu/drm/xlnx/Kconfig   |  21 +
 drivers/gpu/drm/xlnx/Makefile  |   4 +
 drivers/gpu/drm/xlnx/xlnx_tpg.c| 846 +
 drivers/gpu/drm/xlnx/xlnx_vtc.c| 452 +++
 drivers/gpu/drm/xlnx/xlnx_vtc.h| 101 +++
 drivers/gpu/drm/xlnx/xlnx_vtc_list.c   | 160 
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 170 -
 drivers/gpu/drm/xlnx/zynqmp_disp.h |  19 +-
 drivers/gpu/drm/xlnx/zynqmp_disp_regs.h|   8 +-
 drivers/gpu/drm/xlnx/zynqmp_dp.c   |  81 +-
 drivers/gpu/drm/xlnx/zynqmp_kms.c  |   6 +-
 include/drm/drm_crtc_helper.h  |   5 +
 include/drm/drm_modeset_helper_vtables.h   |  30 +
 include/dt-bindings/media/media-bus-format.h   | 177 +
 18 files changed, 2198 insertions(+), 84 deletions(-)
---
base-commit: bfa4437fd3938ae2e186e7664b2db65bb8775670
change-id: 20240226-dp-live-fmt-6415773b5a68

Best regards,
-- 
Anatoliy Klymenko 



[PATCH v2 2/8] drm: xlnx: zynqmp_dpsub: Update live format defines

2024-03-12 Thread Anatoliy Klymenko
Update live format defines to match DPSUB AV_BUF_LIVE_VID_CONFIG register
layout.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp_regs.h | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp_regs.h 
b/drivers/gpu/drm/xlnx/zynqmp_disp_regs.h
index f92a006d5070..fa3935384834 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp_regs.h
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp_regs.h
@@ -165,10 +165,10 @@
 #define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_10  0x2
 #define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_12  0x3
 #define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_MASKGENMASK(2, 0)
-#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB 0x0
-#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV444  0x1
-#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422  0x2
-#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YONLY   0x3
+#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB (0x0 << 4)
+#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV444  (0x1 << 4)
+#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422  (0x2 << 4)
+#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YONLY   (0x3 << 4)
 #define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_MASKGENMASK(5, 4)
 #define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_CB_FIRSTBIT(8)
 #define ZYNQMP_DISP_AV_BUF_PALETTE_MEMORY  0x400

-- 
2.25.1



[PATCH v2 8/8] drm: xlnx: Intoduce TPG CRTC driver

2024-03-12 Thread Anatoliy Klymenko
DO NOT MERGE. REFERENCE ONLY.

Add CRTC driver based on AMD/Xilinx Video Test Pattern Generator IP. TPG
based FPGA design represents minimalistic harness useful for testing links
between FPGA based CRTC and external DRM encoders, both FPGA and hardened
IP based.

Add driver for AMD/Xilinx Video Timing Controller. The VTC, working in
generator mode, suplements TPG with video timing signals.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/Kconfig |  21 +
 drivers/gpu/drm/xlnx/Makefile|   4 +
 drivers/gpu/drm/xlnx/xlnx_tpg.c  | 854 +++
 drivers/gpu/drm/xlnx/xlnx_vtc.c  | 452 ++
 drivers/gpu/drm/xlnx/xlnx_vtc.h  | 101 +
 drivers/gpu/drm/xlnx/xlnx_vtc_list.c | 160 +++
 6 files changed, 1592 insertions(+)

diff --git a/drivers/gpu/drm/xlnx/Kconfig b/drivers/gpu/drm/xlnx/Kconfig
index 68ee897de9d7..c40e98c1a5e6 100644
--- a/drivers/gpu/drm/xlnx/Kconfig
+++ b/drivers/gpu/drm/xlnx/Kconfig
@@ -15,3 +15,24 @@ config DRM_ZYNQMP_DPSUB
  This is a DRM/KMS driver for ZynqMP DisplayPort controller. Choose
  this option if you have a Xilinx ZynqMP SoC with DisplayPort
  subsystem.
+
+config DRM_XLNX_BRIDGE_VTC
+   bool "Xilinx DRM VTC Driver"
+   depends on OF
+   help
+ DRM brige driver for Xilinx Video Timing Controller. Choose
+ this option to make VTC a part of the CRTC in display pipeline.
+ Currently the support is added to the Xilinx Video Mixer and
+ Xilinx PL display CRTC drivers. This driver provides ability
+ to generate timings through the bridge layer.
+
+config DRM_XLNX_TPG
+   bool "Xilinx DRM TPG Driver"
+   depends on DRM && OF
+   select DRM_XLNX_BRIDGE_VTC
+   select VIDEOMODE_HELPERS
+   help
+ CRTC driver based on AMD/Xilinx Test Pattern Generator IP. Choose
+ this driver to enable Test Pattern Generator CRTC. This driver
+ implements simplistic CRTC with the single plane and is perfect for
+ testing PL to PS and PL to PL display output pipelines.
diff --git a/drivers/gpu/drm/xlnx/Makefile b/drivers/gpu/drm/xlnx/Makefile
index ea1422a39502..26fb3ad21fa9 100644
--- a/drivers/gpu/drm/xlnx/Makefile
+++ b/drivers/gpu/drm/xlnx/Makefile
@@ -1,2 +1,6 @@
 zynqmp-dpsub-y := zynqmp_disp.o zynqmp_dpsub.o zynqmp_dp.o zynqmp_kms.o
 obj-$(CONFIG_DRM_ZYNQMP_DPSUB) += zynqmp-dpsub.o
+xlnx-tpg-objs := xlnx_tpg.o
+xlnx-tpg-$(CONFIG_DRM_XLNX_BRIDGE_VTC) += xlnx_vtc_list.o
+obj-$(CONFIG_DRM_XLNX_TPG) += xlnx-tpg.o
+obj-$(CONFIG_DRM_XLNX_BRIDGE_VTC) += xlnx_vtc.o
diff --git a/drivers/gpu/drm/xlnx/xlnx_tpg.c b/drivers/gpu/drm/xlnx/xlnx_tpg.c
new file mode 100644
index ..297a65fdb289
--- /dev/null
+++ b/drivers/gpu/drm/xlnx/xlnx_tpg.c
@@ -0,0 +1,854 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx logicore test pattern generator driver
+ *
+ * Copyright (C) 2024 Advanced Micro Devices, Inc.
+ *
+ * Author: Anatoliy Klymenko 
+ *
+ * This driver introduces support for the test CRTC based on AMD/Xilinx
+ * Test Pattern Generator IP. The main goal of the driver is to enable
+ * simplistic FPGA design that could be used to test FPGA CRTC to external
+ * encoder IP connectivity.
+ * Reference: https://docs.xilinx.com/r/en-US/pg103-v-tpg
+ */
+
+#include "xlnx_vtc.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define DRIVER_NAME"xlnx-tpg"
+#define DRIVER_DESC"Xilinx TPG DRM KMS Driver"
+#define DRIVER_DATE"20240307"
+#define DRIVER_MAJOR   1
+#define DRIVER_MINOR   0
+
+#define XLNX_TPG_CONTROL   0x
+#define XLNX_TPG_GLOBAL_IRQ_EN 0x0004
+#define XLNX_TPG_IP_IRQ_EN 0x0008
+#define XLNX_TPG_IP_IRQ_STATUS 0x000C
+#define XLNX_TPG_ACTIVE_HEIGHT 0x0010
+#define XLNX_TPG_ACTIVE_WIDTH  0x0018
+#define XLNX_TPG_PATTERN_ID0x0020
+#define XLNX_TPG_COLOR_FORMAT  0x0040
+
+#define XLNX_TPG_IP_IRQ_AP_DONEBIT(0)
+
+#define XLNX_TPG_START BIT(0)
+#define XLNX_TPG_AUTO_RESTART  BIT(7)
+
+enum xlnx_tpg_pattern {
+   XTPG_PAT_HORIZONTAL_RAMP = 0x1,
+   XTPG_PAT_VERTICAL_RAMP,
+   XTPG_PAT_TEMPORAL_RAMP,
+   XTPG_PAT_SOLID_RED,
+   XTPG_PAT_SOLID_GREEN,
+   XTPG_PAT_SOLID_BLUE,
+   XTPG_PAT_SOLID_BLACK,
+   XTPG_PAT_SOLID_WHITE,
+   XTPG_PAT_COLOR_BARS,
+   XTPG_PAT_ZONE_PLATE,
+   XTPG_PAT_TARTAN_COLOR_BARS,
+   XTPG_PAT_CROSS_HATCH,
+   XTPG_PAT_COLOR_SWEEP,
+   XTPG_PAT_COMBO_RAMP,
+   XTPG_PAT_CHECKER_BOARD,
+   XTPG_PAT_DP_COLOR_RAMP,
+   XTPG_PAT_DP_VERTICAL_LINES,
+   XTPG_PAT_DP_COLOR_SQUARE,
+};
+
+static const struct drm_prop_enum_list xtp

[PATCH v2 7/8] dt-bindings: xlnx: Add VTC and TPG bindings

2024-03-12 Thread Anatoliy Klymenko
DO NOT MERGE. REFERENCE ONLY.

Add binding for AMD/Xilinx Video Timing Controller and Test Pattern
Generator.

Copy media-bus-formats.h into dt-bindings/media to suplement TPG DT node.

Signed-off-by: Anatoliy Klymenko 
---
 .../bindings/display/xlnx/xlnx,v-tpg.yaml  |  87 ++
 .../devicetree/bindings/display/xlnx/xlnx,vtc.yaml |  65 
 include/dt-bindings/media/media-bus-format.h   | 177 +
 3 files changed, 329 insertions(+)

diff --git a/Documentation/devicetree/bindings/display/xlnx/xlnx,v-tpg.yaml 
b/Documentation/devicetree/bindings/display/xlnx/xlnx,v-tpg.yaml
new file mode 100644
index ..df5ee5b547cf
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/xlnx/xlnx,v-tpg.yaml
@@ -0,0 +1,87 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/xlnx/xlnx,v-tpg.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Xilinx Video Test Pattern Generator (TPG)
+
+description:
+  AMD/Xilinx Video Test Pattern Generator IP is a soft IP designed to
+  generate test video signal in AXI4-Stream Video format.
+  https://docs.xilinx.com/r/en-US/pg103-v-tpg
+
+maintainers:
+  - Anatoliy Klymenko 
+
+properties:
+  compatible:
+description:
+  TPG versions backward-compatible with previous versions should list all
+  compatible versions in the newer to older order.
+enum: ["xlnx,v-tpg-8.0", "xlnx,v-tpg-8.2"]
+
+  reg:
+maxItems: 1
+
+  interrupts:
+maxItems: 1
+
+  bus-format:
+description: Output media bus format, one of MEDIA_BUS_FMT_*
+maxItems: 1
+
+  xlnx,bridge:
+   description: Reference to Video Timing Controller
+   maxItems: 1
+
+  ports:
+$ref: /schemas/graph.yaml#/properties/ports
+description:
+  Connections from and to external components in the video pipeline.
+
+properties:
+  port@0:
+   $ref: /schemas/graph.yaml#/properties/port
+   description: Sink port connected to downstream video IP.
+
+  port@1:
+   $ref: /schemas/graph.yaml#/properties/port
+   description: Source port to connect to optional video signal source.
+
+required:
+  - port@0
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - bus-format
+  - xlnx,bridge
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+#include 
+
+tpg_0: tpg@4005 {
+  compatible = "xlnx,v-tpg-8.0";
+  reg = <0x4005 0x1>;
+  interrupts = <0 89 4>;
+  xlnx,bridge = <_3>;
+  bus-format = ;
+  ports {
+#address-cells = <1>;
+#size-cells = <0>;
+port@0 {
+  reg = <0>;
+  tpg_out: endpoint {
+remote-endpoint = <_encoder>;
+  };
+};
+  };
+};
+
+...
diff --git a/Documentation/devicetree/bindings/display/xlnx/xlnx,vtc.yaml 
b/Documentation/devicetree/bindings/display/xlnx/xlnx,vtc.yaml
new file mode 100644
index ..51eb12cdcfdc
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/xlnx/xlnx,vtc.yaml
@@ -0,0 +1,65 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/xlnx/xlnx,vtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Device-Tree for Xilinx Video Timing Controller(VTC)
+
+description:
+  Xilinx VTC is a general purpose video timing generator and detector.
+  The input side of this core automatically detects horizontal and
+  vertical synchronization, pulses, polarity, blanking timing and active 
pixels.
+  While on the output, it generates the horizontal and vertical blanking and
+  synchronization pulses used with a standard video system including support
+  for programmable pulse polarity.
+
+  The core is commonly used with Video in to AXI4-Stream core to detect the
+  format and timing of incoming video data or with AXI4-Stream to Video out 
core
+  to generate outgoing video timing for downstream sinks like a video monitor.
+
+  For details please refer to
+  https://docs.xilinx.com/r/en-US/pg016_v_tc
+
+maintainers:
+  - Sagar Vishal 
+
+properties:
+  compatible:
+const: "xlnx,bridge-v-tc-6.1"
+
+  reg:
+maxItems: 1
+
+  xlnx,pixels-per-clock:
+description: Pixels per clock of the stream.
+enum: [1, 2, 4]
+
+  clocks:
+minItems: 2
+
+  clock-names:
+items:
+  - const: clk
+  - const: s_axi_aclk
+
+required:
+  - compatible
+  - reg
+  - xlnx,pixels-per-clock
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+v_tc_0: v_tc@8001 {
+  clock-names = "clk", "s_axi_aclk";
+  clocks = <_wiz_0>, <_clk_0>;
+  compatible = "xlnx,bridge-v-tc-6.1";
+  xlnx,pixels-per-clock = <1>;
+  reg = <0x8001 0x1>;
+};
+
+...
diff --git a/include/dt-bindings/media/medi

[PATCH v2 4/8] drm: xlnx: zynqmp_dpsub: Minimize usage of global flag

2024-03-12 Thread Anatoliy Klymenko
Avoid usage of global zynqmp_dpsub.dma_enabled flag in DPSUB layer
context. This flag signals whether the driver runs in DRM CRTC or DRM
bridge mode, assuming that all display layers share the same live or
non-live mode of operation. Using per-layer mode instead of global flag
will siplify future support of the hybrid scenario.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 11 ---
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index af851190f447..dd48fa60fa9a 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -975,7 +975,7 @@ void zynqmp_disp_layer_disable(struct zynqmp_disp_layer 
*layer)
 {
unsigned int i;
 
-   if (layer->disp->dpsub->dma_enabled) {
+   if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE) {
for (i = 0; i < layer->drm_fmt->num_planes; i++)
dmaengine_terminate_sync(layer->dmas[i].chan);
}
@@ -1001,7 +1001,7 @@ void zynqmp_disp_layer_set_format(struct 
zynqmp_disp_layer *layer,
 
zynqmp_disp_avbuf_set_format(layer->disp, layer, layer->disp_fmt);
 
-   if (!layer->disp->dpsub->dma_enabled)
+   if (layer->mode == ZYNQMP_DPSUB_LAYER_LIVE)
return;
 
/*
@@ -1039,7 +1039,7 @@ int zynqmp_disp_layer_update(struct zynqmp_disp_layer 
*layer,
const struct drm_format_info *info = layer->drm_fmt;
unsigned int i;
 
-   if (!layer->disp->dpsub->dma_enabled)
+   if (layer->mode == ZYNQMP_DPSUB_LAYER_LIVE)
return 0;
 
for (i = 0; i < info->num_planes; i++) {
@@ -1089,7 +1089,7 @@ static void zynqmp_disp_layer_release_dma(struct 
zynqmp_disp *disp,
 {
unsigned int i;
 
-   if (!layer->info || !disp->dpsub->dma_enabled)
+   if (!layer->info)
return;
 
for (i = 0; i < layer->info->num_channels; i++) {
@@ -1132,9 +1132,6 @@ static int zynqmp_disp_layer_request_dma(struct 
zynqmp_disp *disp,
unsigned int i;
int ret;
 
-   if (!disp->dpsub->dma_enabled)
-   return 0;
-
for (i = 0; i < layer->info->num_channels; i++) {
struct zynqmp_disp_layer_dma *dma = >dmas[i];
char dma_channel_name[16];

-- 
2.25.1



[PATCH v2 6/8] drm/atomic-helper: Add select_output_bus_format callback

2024-03-12 Thread Anatoliy Klymenko
Add optional drm_crtc_helper_funcs.select_output_bus_format callback. This
callback allows to negotiate compatible media bus format on the link
between CRTC and connected DRM encoder or DRM bridge chain. A good usage
example is the CRTC implemented as FPGA soft IP. This kind of CRTC will
most certainly support a single output media bus format, as supporting
multiple runtime options consumes extra FPGA resources. A variety of
options for the FPGA designs are usually achieved by synthesizing IP with
different parameters.

Add drm_helper_crtc_select_output_bus_format that wraps
drm_crtc_helper_funcs.select_output_bus_format.

Incorporate select_output_bus_format callback into the format negotiation
stage to fix the input bus format of the first DRM bridge in the chain.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/drm_bridge.c | 14 +++--
 drivers/gpu/drm/drm_crtc_helper.c| 36 
 include/drm/drm_crtc_helper.h|  5 +
 include/drm/drm_modeset_helper_vtables.h | 30 ++
 4 files changed, 83 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 521a71c61b16..955ca108cd4b 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -28,6 +28,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -879,7 +880,8 @@ static int select_bus_fmt_recursive(struct drm_bridge 
*first_bridge,
unsigned int i, num_in_bus_fmts = 0;
struct drm_bridge_state *cur_state;
struct drm_bridge *prev_bridge;
-   u32 *in_bus_fmts;
+   struct drm_crtc *crtc = crtc_state->crtc;
+   u32 *in_bus_fmts, in_fmt;
int ret;
 
prev_bridge = drm_bridge_get_prev_bridge(cur_bridge);
@@ -933,7 +935,15 @@ static int select_bus_fmt_recursive(struct drm_bridge 
*first_bridge,
return -ENOMEM;
 
if (first_bridge == cur_bridge) {
-   cur_state->input_bus_cfg.format = in_bus_fmts[0];
+   in_fmt = drm_helper_crtc_select_output_bus_format(crtc,
+   crtc_state,
+   in_bus_fmts,
+   num_in_bus_fmts);
+   if (!in_fmt) {
+   kfree(in_bus_fmts);
+   return -ENOTSUPP;
+   }
+   cur_state->input_bus_cfg.format = in_fmt;
cur_state->output_bus_cfg.format = out_bus_fmt;
kfree(in_bus_fmts);
return 0;
diff --git a/drivers/gpu/drm/drm_crtc_helper.c 
b/drivers/gpu/drm/drm_crtc_helper.c
index 2dafc39a27cb..f2e12a3c4e5f 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -1055,3 +1055,39 @@ int drm_helper_force_disable_all(struct drm_device *dev)
return ret;
 }
 EXPORT_SYMBOL(drm_helper_force_disable_all);
+
+/**
+ * drm_helper_crtc_select_output_bus_format - Select output media bus format
+ * @crtc: The CRTC to query
+ * @crtc_state: The new CRTC state
+ * @supported_fmts: List of media bus format options to pick from
+ * @num_supported_fmts: Number of media bus formats in @supported_fmts list
+ *
+ * Encoder drivers may call this helper to give the connected CRTC a chance to
+ * select compatible or preffered media bus format to use over the CRTC encoder
+ * link. Encoders should provide list of supported input MEDIA_BUS_FMT_* for
+ * CRTC to pick from. CRTC driver is expected to select preferred media bus
+ * format from the list and, once enabled, generate the signal accordingly.
+ *
+ * Returns:
+ * Selected preferred media bus format or 0 if CRTC does not support any from
+ * @supported_fmts list.
+ */
+u32 drm_helper_crtc_select_output_bus_format(struct drm_crtc *crtc,
+struct drm_crtc_state *crtc_state,
+const u32 *supported_fmts,
+unsigned int num_supported_fmts)
+{
+   if (!crtc || !supported_fmts || !num_supported_fmts)
+   return 0;
+
+   if (!crtc->helper_private ||
+   !crtc->helper_private->select_output_bus_format)
+   return supported_fmts[0];
+
+   return crtc->helper_private->select_output_bus_format(crtc,
+   crtc_state,
+   supported_fmts,
+   num_supported_fmts);
+}
+EXPORT_SYMBOL(drm_helper_crtc_select_output_bus_format);
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index 8c886fc46ef2..b7eb52f3ce41 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -38,6 +38,7 @@
 struct drm_atomic_state;
 struct drm_connector;
 struct drm_c

[PATCH v2 3/8] drm: xlnx: zynqmp_dpsub: Anounce supported input formats

2024-03-12 Thread Anatoliy Klymenko
DPSUB in bridge mode supports multiple input media bus formats.

Announce the list of supported input media bus formats via
drm_bridge.atomic_get_input_bus_fmts callback.
Introduce a set of live input formats, supported by DPSUB.
Rename zynqmp_disp_layer_drm_formats() to zynqmp_disp_layer_formats() to
reflect semantics for both live and non-live layer format lists.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 67 +-
 drivers/gpu/drm/xlnx/zynqmp_disp.h |  4 +--
 drivers/gpu/drm/xlnx/zynqmp_dp.c   | 26 +++
 drivers/gpu/drm/xlnx/zynqmp_kms.c  |  2 +-
 4 files changed, 88 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index e6d26ef60e89..af851190f447 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -77,12 +78,16 @@ enum zynqmp_dpsub_layer_mode {
 /**
  * struct zynqmp_disp_format - Display subsystem format information
  * @drm_fmt: DRM format (4CC)
+ * @bus_fmt: Media bus format
  * @buf_fmt: AV buffer format
  * @swap: Flag to swap R & B for RGB formats, and U & V for YUV formats
  * @sf: Scaling factors for color components
  */
 struct zynqmp_disp_format {
-   u32 drm_fmt;
+   union {
+   u32 drm_fmt;
+   u32 bus_fmt;
+   };
u32 buf_fmt;
bool swap;
const u32 *sf;
@@ -182,6 +187,12 @@ static const u32 scaling_factors_565[] = {
ZYNQMP_DISP_AV_BUF_5BIT_SF,
 };
 
+static const u32 scaling_factors_666[] = {
+   ZYNQMP_DISP_AV_BUF_6BIT_SF,
+   ZYNQMP_DISP_AV_BUF_6BIT_SF,
+   ZYNQMP_DISP_AV_BUF_6BIT_SF,
+};
+
 static const u32 scaling_factors_888[] = {
ZYNQMP_DISP_AV_BUF_8BIT_SF,
ZYNQMP_DISP_AV_BUF_8BIT_SF,
@@ -364,6 +375,36 @@ static const struct zynqmp_disp_format avbuf_gfx_fmts[] = {
},
 };
 
+/* List of live video layer formats */
+static const struct zynqmp_disp_format avbuf_live_fmts[] = {
+   {
+   .bus_fmt= MEDIA_BUS_FMT_RGB666_1X18,
+   .buf_fmt= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_6 |
+ ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB,
+   .sf = scaling_factors_666,
+   }, {
+   .bus_fmt= MEDIA_BUS_FMT_UYVY8_1X24,
+   .buf_fmt= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 |
+ ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB,
+   .sf = scaling_factors_888,
+   }, {
+   .bus_fmt= MEDIA_BUS_FMT_UYVY8_1X16,
+   .buf_fmt= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 |
+ ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422,
+   .sf = scaling_factors_888,
+   }, {
+   .bus_fmt= MEDIA_BUS_FMT_VUY8_1X24,
+   .buf_fmt= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 |
+ ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV444,
+   .sf = scaling_factors_888,
+   }, {
+   .bus_fmt= MEDIA_BUS_FMT_UYVY10_1X20,
+   .buf_fmt= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_10 |
+ ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422,
+   .sf = scaling_factors_101010,
+   },
+};
+
 static u32 zynqmp_disp_avbuf_read(struct zynqmp_disp *disp, int reg)
 {
return readl(disp->avbuf.base + reg);
@@ -883,16 +924,17 @@ zynqmp_disp_layer_find_format(struct zynqmp_disp_layer 
*layer,
 }
 
 /**
- * zynqmp_disp_layer_drm_formats - Return the DRM formats supported by the 
layer
+ * zynqmp_disp_layer_formats - Return DRM or media bus formats supported by
+ * the layer
  * @layer: The layer
  * @num_formats: Pointer to the returned number of formats
  *
- * Return: A newly allocated u32 array that stores all the DRM formats
+ * Return: A newly allocated u32 array that stores all DRM or media bus formats
  * supported by the layer. The number of formats in the array is returned
  * through the num_formats argument.
  */
-u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer *layer,
-  unsigned int *num_formats)
+u32 *zynqmp_disp_layer_formats(struct zynqmp_disp_layer *layer,
+  unsigned int *num_formats)
 {
unsigned int i;
u32 *formats;
@@ -1131,6 +1173,11 @@ static int zynqmp_disp_create_layers(struct zynqmp_disp 
*disp)
.num_channels = 1,
},
};
+   static const struct zynqmp_disp_layer_info live_layer_info = {
+   .formats = avbuf_live_fmts,
+   .num_formats = ARRAY_SIZE(avbuf_live_fmts),
+   .num_channels = 0,
+   };
 
unsigned int i;
int ret;

[PATCH v2 5/8] drm: xlnx: zynqmp_dpsub: Set input live format

2024-03-12 Thread Anatoliy Klymenko
Program live video input format according to selected media bus format.

In the bridge mode of operation, DPSUB is connected to FPGA CRTC which
almost certainly supports a single media bus format as its output. Expect
this to be delivered via the new bridge atomic state. Program DPSUB
registers accordingly.
Update zynqmp_disp_layer_set_format() API to fit both live and non-live
layer types.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 93 +++---
 drivers/gpu/drm/xlnx/zynqmp_disp.h |  2 +-
 drivers/gpu/drm/xlnx/zynqmp_dp.c   | 13 --
 drivers/gpu/drm/xlnx/zynqmp_kms.c  |  2 +-
 4 files changed, 87 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index dd48fa60fa9a..0cacd597f4b8 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -383,7 +383,7 @@ static const struct zynqmp_disp_format avbuf_live_fmts[] = {
  ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB,
.sf = scaling_factors_666,
}, {
-   .bus_fmt= MEDIA_BUS_FMT_UYVY8_1X24,
+   .bus_fmt= MEDIA_BUS_FMT_RBG888_1X24,
.buf_fmt= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 |
  ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB,
.sf = scaling_factors_888,
@@ -433,19 +433,28 @@ static void zynqmp_disp_avbuf_set_format(struct 
zynqmp_disp *disp,
 const struct zynqmp_disp_format *fmt)
 {
unsigned int i;
-   u32 val;
+   u32 val, reg;
 
-   val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_FMT);
-   val &= zynqmp_disp_layer_is_video(layer)
-   ? ~ZYNQMP_DISP_AV_BUF_FMT_NL_VID_MASK
-   : ~ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_MASK;
-   val |= fmt->buf_fmt;
-   zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_FMT, val);
+   layer->disp_fmt = fmt;
+   if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE) {
+   reg = ZYNQMP_DISP_AV_BUF_FMT;
+   val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_FMT);
+   val &= zynqmp_disp_layer_is_video(layer)
+   ? ~ZYNQMP_DISP_AV_BUF_FMT_NL_VID_MASK
+   : ~ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_MASK;
+   val |= fmt->buf_fmt;
+   } else {
+   reg = zynqmp_disp_layer_is_video(layer)
+   ? ZYNQMP_DISP_AV_BUF_LIVE_VID_CONFIG
+   : ZYNQMP_DISP_AV_BUF_LIVE_GFX_CONFIG;
+   val = fmt->buf_fmt;
+   }
+   zynqmp_disp_avbuf_write(disp, reg, val);
 
for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_SF; i++) {
-   unsigned int reg = zynqmp_disp_layer_is_video(layer)
-? ZYNQMP_DISP_AV_BUF_VID_COMP_SF(i)
-: ZYNQMP_DISP_AV_BUF_GFX_COMP_SF(i);
+   reg = zynqmp_disp_layer_is_video(layer)
+   ? ZYNQMP_DISP_AV_BUF_VID_COMP_SF(i)
+   : ZYNQMP_DISP_AV_BUF_GFX_COMP_SF(i);
 
zynqmp_disp_avbuf_write(disp, reg, fmt->sf[i]);
}
@@ -984,23 +993,73 @@ void zynqmp_disp_layer_disable(struct zynqmp_disp_layer 
*layer)
zynqmp_disp_blend_layer_disable(layer->disp, layer);
 }
 
+struct zynqmp_disp_bus_to_drm {
+   u32 bus_fmt;
+   u32 drm_fmt;
+};
+
+/**
+ * zynqmp_disp_reference_drm_format - Get reference DRM format corresponding
+ * to the given media bus format.
+ * @bus_format: Media bus format
+ *
+ * Map media bus format to some DRM format that represents the same color space
+ * and chroma subsampling as the @bus_format video signal. These DRM format
+ * properties are required to program the blender.
+ *
+ * Return: DRM format code corresponding to @bus_format
+ */
+static u32 zynqmp_disp_reference_drm_format(u32 bus_format)
+{
+   static const struct zynqmp_disp_bus_to_drm format_map[] = {
+   {
+   .bus_fmt = MEDIA_BUS_FMT_RGB666_1X18,
+   .drm_fmt = DRM_FORMAT_RGB565,
+   }, {
+   .bus_fmt = MEDIA_BUS_FMT_RBG888_1X24,
+   .drm_fmt = DRM_FORMAT_RGB888,
+   }, {
+   .bus_fmt = MEDIA_BUS_FMT_UYVY8_1X16,
+   .drm_fmt = DRM_FORMAT_YUV422,
+   }, {
+   .bus_fmt = MEDIA_BUS_FMT_VUY8_1X24,
+   .drm_fmt = DRM_FORMAT_YUV444,
+   }, {
+   .bus_fmt = MEDIA_BUS_FMT_UYVY10_1X20,
+   .drm_fmt = DRM_FORMAT_P210,
+   },
+   };
+   unsigned int i;
+
+   for (i = 0; i < ARRAY_SIZE(format_map); ++i)
+   if (format_map[i].bus_fmt == bus_format)
+   return format_map[i].drm_fmt;

[PATCH v2 1/8] drm: xlnx: zynqmp_dpsub: Set layer mode during creation

2024-03-12 Thread Anatoliy Klymenko
Set layer mode of operation (live or dma-based) during layer creation.

Each DPSUB layer mode of operation is defined by corresponding DT node port
connection, so it is possible to assign it during layer object creation.
Previously it was set in layer enable functions, although it is too late
as setting layer format depends on layer mode, and should be done before
given layer enabled.

Signed-off-by: Anatoliy Klymenko 
Reviewed-by: Laurent Pinchart 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 20 
 drivers/gpu/drm/xlnx/zynqmp_disp.h | 13 +
 drivers/gpu/drm/xlnx/zynqmp_dp.c   |  2 +-
 drivers/gpu/drm/xlnx/zynqmp_kms.c  |  2 +-
 4 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 8a39b3accce5..e6d26ef60e89 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -64,6 +64,16 @@
 
 #define ZYNQMP_DISP_MAX_NUM_SUB_PLANES 3
 
+/**
+ * enum zynqmp_dpsub_layer_mode - Layer mode
+ * @ZYNQMP_DPSUB_LAYER_NONLIVE: non-live (memory) mode
+ * @ZYNQMP_DPSUB_LAYER_LIVE: live (stream) mode
+ */
+enum zynqmp_dpsub_layer_mode {
+   ZYNQMP_DPSUB_LAYER_NONLIVE,
+   ZYNQMP_DPSUB_LAYER_LIVE,
+};
+
 /**
  * struct zynqmp_disp_format - Display subsystem format information
  * @drm_fmt: DRM format (4CC)
@@ -902,15 +912,12 @@ u32 *zynqmp_disp_layer_drm_formats(struct 
zynqmp_disp_layer *layer,
 /**
  * zynqmp_disp_layer_enable - Enable a layer
  * @layer: The layer
- * @mode: Operating mode of layer
  *
  * Enable the @layer in the audio/video buffer manager and the blender. DMA
  * channels are started separately by zynqmp_disp_layer_update().
  */
-void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer,
- enum zynqmp_dpsub_layer_mode mode)
+void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer)
 {
-   layer->mode = mode;
zynqmp_disp_avbuf_enable_video(layer->disp, layer);
zynqmp_disp_blend_layer_enable(layer->disp, layer);
 }
@@ -1134,6 +1141,11 @@ static int zynqmp_disp_create_layers(struct zynqmp_disp 
*disp)
layer->id = i;
layer->disp = disp;
layer->info = _info[i];
+   /* For now assume dpsub works in either live or non-live mode 
for both layers.
+* Hybrid mode is not supported yet.
+*/
+   layer->mode = disp->dpsub->dma_enabled ? 
ZYNQMP_DPSUB_LAYER_NONLIVE
+  : 
ZYNQMP_DPSUB_LAYER_LIVE;
 
ret = zynqmp_disp_layer_request_dma(disp, layer);
if (ret)
diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.h 
b/drivers/gpu/drm/xlnx/zynqmp_disp.h
index 123cffac08be..9b8b202224d9 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.h
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.h
@@ -42,16 +42,6 @@ enum zynqmp_dpsub_layer_id {
ZYNQMP_DPSUB_LAYER_GFX,
 };
 
-/**
- * enum zynqmp_dpsub_layer_mode - Layer mode
- * @ZYNQMP_DPSUB_LAYER_NONLIVE: non-live (memory) mode
- * @ZYNQMP_DPSUB_LAYER_LIVE: live (stream) mode
- */
-enum zynqmp_dpsub_layer_mode {
-   ZYNQMP_DPSUB_LAYER_NONLIVE,
-   ZYNQMP_DPSUB_LAYER_LIVE,
-};
-
 void zynqmp_disp_enable(struct zynqmp_disp *disp);
 void zynqmp_disp_disable(struct zynqmp_disp *disp);
 int zynqmp_disp_setup_clock(struct zynqmp_disp *disp,
@@ -62,8 +52,7 @@ void zynqmp_disp_blend_set_global_alpha(struct zynqmp_disp 
*disp,
 
 u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer *layer,
   unsigned int *num_formats);
-void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer,
- enum zynqmp_dpsub_layer_mode mode);
+void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer);
 void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer);
 void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer,
  const struct drm_format_info *info);
diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index 1846c4971fd8..04b6bcac3b07 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -1295,7 +1295,7 @@ static void zynqmp_dp_disp_enable(struct zynqmp_dp *dp,
/* TODO: Make the format configurable. */
info = drm_format_info(DRM_FORMAT_YUV422);
zynqmp_disp_layer_set_format(layer, info);
-   zynqmp_disp_layer_enable(layer, ZYNQMP_DPSUB_LAYER_LIVE);
+   zynqmp_disp_layer_enable(layer);
 
if (layer_id == ZYNQMP_DPSUB_LAYER_GFX)
zynqmp_disp_blend_set_global_alpha(dp->dpsub->disp, true, 255);
diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c 
b/drivers/gpu/drm/xlnx/zynqmp_kms.c
index db3bb4afbfc4..43bf416b33d5 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_kms.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c
@@ -122,7 +122,7 @@ static void zynqmp_dpsub_plan

[PATCH v2 0/8] Setting live video input format for ZynqMP DPSUB

2024-03-12 Thread Anatoliy Klymenko
Implement live video input format setting for ZynqMP DPSUB.

ZynqMP DPSUB can operate in 2 modes: DMA-based and live.

In the live mode, DPSUB receives a live video signal from FPGA-based CRTC.
DPSUB acts as a DRM encoder bridge in such a scenario. To properly tune
into the incoming video signal, DPSUB should be programmed with the proper
media bus format. This patch series addresses this task.

Patch 1/8: Set the DPSUB layer mode of operation prior to enabling the
layer. Allows to use layer operational mode before its enablement.

Patch 2/8: Update some IP register defines.

Patch 3/8: Announce supported input media bus formats via
drm_bridge_funcs.atomic_get_input_bus_fmts callback.

Patch 4/8: Minimize usage of a global flag. Minor improvement.

Patch 5/8: Program DPSUB live video input format based on selected bus
config in the new atomic bridge state.

Patch 6/8: New optional CRTC atomic helper proposal that will allow CRTC
to participate in DRM bridge chain format negotiation and impose format
restrictions. Incorporate this callback into the DRM bridge format
negotiation process.

Patch 7/8: DT bindings documentation for Video Timing Controller and Test
Pattern Generator IPs.

Patch 8/8: Reference FPGA CRTC driver based on AMD/Xilinx Test Pattern
Generator (TPG) IP. Add driver for the AMD/Xilinx Video Timing Controller
(VTC), which supplements TPG.

To: Laurent Pinchart 
To: Maarten Lankhorst 
To: Maxime Ripard 
To: Thomas Zimmermann 
To: David Airlie 
To: Daniel Vetter 
To: Michal Simek 
To: Andrzej Hajda 
To: Neil Armstrong 
To: Robert Foss 
To: Jonas Karlman 
To: Jernej Skrabec 
To: Rob Herring 
To: Krzysztof Kozlowski 
To: Conor Dooley 
To: Mauro Carvalho Chehab 
Cc: dri-devel@lists.freedesktop.org
Cc: linux-arm-ker...@lists.infradead.org
Cc: linux-ker...@vger.kernel.org
Cc: devicet...@vger.kernel.org
Cc: linux-me...@vger.kernel.org
Signed-off-by: Anatoliy Klymenko 

Changes in v2:
- Factor out register defines update into separate patch.
- Add some improvements minimizing ithe usage of a global flag.
- Reuse existing format setting API instead of introducing new versions.
- Add warning around NULL check on new bridge state within atomic enable
  callback.
- Add drm_helper_crtc_select_output_bus_format() that wraps
  drm_crtc_helper_funcs.select_output_bus_format().
- Update API comments per review recommendations.
- Address some minor review comments.
- Add reference CRTC driver that demonstrates the usage of the proposed
  drm_crtc_helper_funcs.select_output_bus_format() API.

- Link to v1: 
https://lore.kernel.org/r/20240226-dp-live-fmt-v1-0-b78c3f69c...@amd.com

---
Anatoliy Klymenko (8):
  drm: xlnx: zynqmp_dpsub: Set layer mode during creation
  drm: xlnx: zynqmp_dpsub: Update live format defines
  drm: xlnx: zynqmp_dpsub: Anounce supported input formats
  drm: xlnx: zynqmp_dpsub: Minimize usage of global flag
  drm: xlnx: zynqmp_dpsub: Set input live format
  drm/atomic-helper: Add select_output_bus_format callback
  dt-bindings: xlnx: Add VTC and TPG bindings
  drm: xlnx: Intoduce TPG CRTC driver

 .../bindings/display/xlnx/xlnx,v-tpg.yaml  |  87 +++
 .../devicetree/bindings/display/xlnx/xlnx,vtc.yaml |  65 ++
 drivers/gpu/drm/drm_bridge.c   |  14 +-
 drivers/gpu/drm/drm_crtc_helper.c  |  36 +
 drivers/gpu/drm/xlnx/Kconfig   |  21 +
 drivers/gpu/drm/xlnx/Makefile  |   4 +
 drivers/gpu/drm/xlnx/xlnx_tpg.c| 854 +
 drivers/gpu/drm/xlnx/xlnx_vtc.c| 452 +++
 drivers/gpu/drm/xlnx/xlnx_vtc.h| 101 +++
 drivers/gpu/drm/xlnx/xlnx_vtc_list.c   | 160 
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 187 -
 drivers/gpu/drm/xlnx/zynqmp_disp.h |  19 +-
 drivers/gpu/drm/xlnx/zynqmp_disp_regs.h|   8 +-
 drivers/gpu/drm/xlnx/zynqmp_dp.c   |  41 +-
 drivers/gpu/drm/xlnx/zynqmp_kms.c  |   6 +-
 include/drm/drm_crtc_helper.h  |   5 +
 include/drm/drm_modeset_helper_vtables.h   |  30 +
 include/dt-bindings/media/media-bus-format.h   | 177 +
 18 files changed, 2204 insertions(+), 63 deletions(-)
---
base-commit: bfa4437fd3938ae2e186e7664b2db65bb8775670
change-id: 20240226-dp-live-fmt-6415773b5a68

Best regards,
-- 
Anatoliy Klymenko 



[PATCH 2/4] drm: xlnx: zynqmp_dpsub: Anounce supported input formats

2024-02-26 Thread Anatoliy Klymenko
DPSUB in bridge mode supports multiple input media bus formats.

Announce the list of supported input media bus formats via
drm_bridge.atomic_get_input_bus_fmts callback.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 37 +
 drivers/gpu/drm/xlnx/zynqmp_disp.h | 10 ++
 drivers/gpu/drm/xlnx/zynqmp_dp.c   |  1 +
 3 files changed, 48 insertions(+)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index e6d26ef60e89..ee99aad915ba 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -77,12 +78,14 @@ enum zynqmp_dpsub_layer_mode {
 /**
  * struct zynqmp_disp_format - Display subsystem format information
  * @drm_fmt: DRM format (4CC)
+ * @bus_fmt: Media bus format
  * @buf_fmt: AV buffer format
  * @swap: Flag to swap R & B for RGB formats, and U & V for YUV formats
  * @sf: Scaling factors for color components
  */
 struct zynqmp_disp_format {
u32 drm_fmt;
+   u32 bus_fmt;
u32 buf_fmt;
bool swap;
const u32 *sf;
@@ -364,6 +367,40 @@ static const struct zynqmp_disp_format avbuf_gfx_fmts[] = {
},
 };
 
+/* List of live video layer formats */
+static const struct zynqmp_disp_format avbuf_live_fmts[] = {
+   {
+   .drm_fmt= DRM_FORMAT_VYUY,
+   .bus_fmt= MEDIA_BUS_FMT_VYUY8_1X16,
+   .buf_fmt= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 |
+ ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422,
+   .sf = scaling_factors_888,
+   },
+};
+
+u32 *zynqmp_disp_get_input_bus_fmts(struct drm_bridge *bridge,
+   struct drm_bridge_state *bridge_state,
+   struct drm_crtc_state *crtc_state,
+   struct drm_connector_state *conn_state,
+   u32 output_fmt,
+   unsigned int *num_input_fmts)
+{
+   int i;
+   u32 *input_fmts;
+
+   input_fmts = kcalloc(ARRAY_SIZE(avbuf_live_fmts), sizeof(*input_fmts), 
GFP_KERNEL);
+   if (!input_fmts) {
+   *num_input_fmts = 0;
+   return input_fmts;
+   }
+
+   for (i = 0; i < ARRAY_SIZE(avbuf_live_fmts); ++i)
+   input_fmts[i] =  avbuf_live_fmts[i].bus_fmt;
+   *num_input_fmts = ARRAY_SIZE(avbuf_live_fmts);
+
+   return input_fmts;
+}
+
 static u32 zynqmp_disp_avbuf_read(struct zynqmp_disp *disp, int reg)
 {
return readl(disp->avbuf.base + reg);
diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.h 
b/drivers/gpu/drm/xlnx/zynqmp_disp.h
index 9b8b202224d9..c2c8dd4896ba 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.h
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.h
@@ -27,6 +27,10 @@
 struct device;
 struct drm_format_info;
 struct drm_plane_state;
+struct drm_bridge;
+struct drm_bridge_state;
+struct drm_connector_state;
+struct drm_crtc_state;
 struct platform_device;
 struct zynqmp_disp;
 struct zynqmp_disp_layer;
@@ -52,6 +56,12 @@ void zynqmp_disp_blend_set_global_alpha(struct zynqmp_disp 
*disp,
 
 u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer *layer,
   unsigned int *num_formats);
+u32 *zynqmp_disp_get_input_bus_fmts(struct drm_bridge *bridge,
+   struct drm_bridge_state *bridge_state,
+   struct drm_crtc_state *crtc_state,
+   struct drm_connector_state *conn_state,
+   u32 output_fmt,
+   unsigned int *num_input_fmts);
 void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer);
 void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer);
 void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer,
diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index 04b6bcac3b07..9cb7ac9f3097 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -1580,6 +1580,7 @@ static const struct drm_bridge_funcs 
zynqmp_dp_bridge_funcs = {
.atomic_check = zynqmp_dp_bridge_atomic_check,
.detect = zynqmp_dp_bridge_detect,
.edid_read = zynqmp_dp_bridge_edid_read,
+   .atomic_get_input_bus_fmts = zynqmp_disp_get_input_bus_fmts,
 };
 
 /* 
-

-- 
2.25.1



[PATCH 1/4] drm: xlnx: zynqmp_dpsub: Set layer mode during creation

2024-02-26 Thread Anatoliy Klymenko
Set layer mode of operation (live or dma-based) during layer creation.

Each DPSUB layer mode of operation is defined by corresponding DT node port
connection, so it is possible to assign it during layer object creation.
Previously it was set in layer enable functions, although it is too late
as setting layer format depends on layer mode, and should be done before
given layer enabled.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 20 
 drivers/gpu/drm/xlnx/zynqmp_disp.h | 13 +
 drivers/gpu/drm/xlnx/zynqmp_dp.c   |  2 +-
 drivers/gpu/drm/xlnx/zynqmp_kms.c  |  2 +-
 4 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 8a39b3accce5..e6d26ef60e89 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -64,6 +64,16 @@
 
 #define ZYNQMP_DISP_MAX_NUM_SUB_PLANES 3
 
+/**
+ * enum zynqmp_dpsub_layer_mode - Layer mode
+ * @ZYNQMP_DPSUB_LAYER_NONLIVE: non-live (memory) mode
+ * @ZYNQMP_DPSUB_LAYER_LIVE: live (stream) mode
+ */
+enum zynqmp_dpsub_layer_mode {
+   ZYNQMP_DPSUB_LAYER_NONLIVE,
+   ZYNQMP_DPSUB_LAYER_LIVE,
+};
+
 /**
  * struct zynqmp_disp_format - Display subsystem format information
  * @drm_fmt: DRM format (4CC)
@@ -902,15 +912,12 @@ u32 *zynqmp_disp_layer_drm_formats(struct 
zynqmp_disp_layer *layer,
 /**
  * zynqmp_disp_layer_enable - Enable a layer
  * @layer: The layer
- * @mode: Operating mode of layer
  *
  * Enable the @layer in the audio/video buffer manager and the blender. DMA
  * channels are started separately by zynqmp_disp_layer_update().
  */
-void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer,
- enum zynqmp_dpsub_layer_mode mode)
+void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer)
 {
-   layer->mode = mode;
zynqmp_disp_avbuf_enable_video(layer->disp, layer);
zynqmp_disp_blend_layer_enable(layer->disp, layer);
 }
@@ -1134,6 +1141,11 @@ static int zynqmp_disp_create_layers(struct zynqmp_disp 
*disp)
layer->id = i;
layer->disp = disp;
layer->info = _info[i];
+   /* For now assume dpsub works in either live or non-live mode 
for both layers.
+* Hybrid mode is not supported yet.
+*/
+   layer->mode = disp->dpsub->dma_enabled ? 
ZYNQMP_DPSUB_LAYER_NONLIVE
+  : 
ZYNQMP_DPSUB_LAYER_LIVE;
 
ret = zynqmp_disp_layer_request_dma(disp, layer);
if (ret)
diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.h 
b/drivers/gpu/drm/xlnx/zynqmp_disp.h
index 123cffac08be..9b8b202224d9 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.h
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.h
@@ -42,16 +42,6 @@ enum zynqmp_dpsub_layer_id {
ZYNQMP_DPSUB_LAYER_GFX,
 };
 
-/**
- * enum zynqmp_dpsub_layer_mode - Layer mode
- * @ZYNQMP_DPSUB_LAYER_NONLIVE: non-live (memory) mode
- * @ZYNQMP_DPSUB_LAYER_LIVE: live (stream) mode
- */
-enum zynqmp_dpsub_layer_mode {
-   ZYNQMP_DPSUB_LAYER_NONLIVE,
-   ZYNQMP_DPSUB_LAYER_LIVE,
-};
-
 void zynqmp_disp_enable(struct zynqmp_disp *disp);
 void zynqmp_disp_disable(struct zynqmp_disp *disp);
 int zynqmp_disp_setup_clock(struct zynqmp_disp *disp,
@@ -62,8 +52,7 @@ void zynqmp_disp_blend_set_global_alpha(struct zynqmp_disp 
*disp,
 
 u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer *layer,
   unsigned int *num_formats);
-void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer,
- enum zynqmp_dpsub_layer_mode mode);
+void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer);
 void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer);
 void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer,
  const struct drm_format_info *info);
diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index 1846c4971fd8..04b6bcac3b07 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -1295,7 +1295,7 @@ static void zynqmp_dp_disp_enable(struct zynqmp_dp *dp,
/* TODO: Make the format configurable. */
info = drm_format_info(DRM_FORMAT_YUV422);
zynqmp_disp_layer_set_format(layer, info);
-   zynqmp_disp_layer_enable(layer, ZYNQMP_DPSUB_LAYER_LIVE);
+   zynqmp_disp_layer_enable(layer);
 
if (layer_id == ZYNQMP_DPSUB_LAYER_GFX)
zynqmp_disp_blend_set_global_alpha(dp->dpsub->disp, true, 255);
diff --git a/drivers/gpu/drm/xlnx/zynqmp_kms.c 
b/drivers/gpu/drm/xlnx/zynqmp_kms.c
index db3bb4afbfc4..43bf416b33d5 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_kms.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_kms.c
@@ -122,7 +122,7 @@ static void zynqmp_dpsub_plane_atomic_update(struct 
drm_plane 

[PATCH 3/4] drm: xlnx: zynqmp_dpsub: Set input live format

2024-02-26 Thread Anatoliy Klymenko
Program live video input format according to selected media bus format.

In the bridge mode of operation, DPSUB is connected to FPGA CRTC which
almost certainly supports a single media bus format as its output. Expect
this to be delivered via the new bridge atomic state. Program DPSUB
registers accordingly.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c  | 52 +
 drivers/gpu/drm/xlnx/zynqmp_disp.h  |  2 ++
 drivers/gpu/drm/xlnx/zynqmp_disp_regs.h |  8 ++---
 drivers/gpu/drm/xlnx/zynqmp_dp.c| 13 ++---
 4 files changed, 67 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index ee99aad915ba..1c3ffdee6b8e 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -416,6 +416,34 @@ static bool zynqmp_disp_layer_is_video(const struct 
zynqmp_disp_layer *layer)
return layer->id == ZYNQMP_DPSUB_LAYER_VID;
 }
 
+/**
+ * zynqmp_disp_avbuf_set_live_format - Set live input format for a layer
+ * @disp: Display controller
+ * @layer: The layer
+ * @fmt: The format information
+ *
+ * Set the live video input format for @layer to @fmt.
+ */
+static void zynqmp_disp_avbuf_set_live_format(struct zynqmp_disp *disp,
+ struct zynqmp_disp_layer *layer,
+ const struct zynqmp_disp_format 
*fmt)
+{
+   u32 reg, i;
+
+   reg = zynqmp_disp_layer_is_video(layer)
+   ? ZYNQMP_DISP_AV_BUF_LIVE_VID_CONFIG
+   : ZYNQMP_DISP_AV_BUF_LIVE_GFX_CONFIG;
+   zynqmp_disp_avbuf_write(disp, reg, fmt->buf_fmt);
+
+   for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_SF; ++i) {
+   reg = zynqmp_disp_layer_is_video(layer)
+   ? ZYNQMP_DISP_AV_BUF_LIVD_VID_COMP_SF(i)
+   : ZYNQMP_DISP_AV_BUF_LIVD_GFX_COMP_SF(i);
+   zynqmp_disp_avbuf_write(disp, reg, fmt->sf[i]);
+   }
+   layer->disp_fmt = fmt;
+}
+
 /**
  * zynqmp_disp_avbuf_set_format - Set the input format for a layer
  * @disp: Display controller
@@ -979,6 +1007,30 @@ void zynqmp_disp_layer_disable(struct zynqmp_disp_layer 
*layer)
zynqmp_disp_blend_layer_disable(layer->disp, layer);
 }
 
+/**
+ * zynqmp_disp_layer_set_live_format - Set live layer input format
+ * @layer: The layer
+ * @info: Input media bus format
+ *
+ * Set the live @layer input bus format. The layer must be disabled.
+ */
+void zynqmp_disp_layer_set_live_format(struct zynqmp_disp_layer *layer,
+  u32 bus_format)
+{
+   int i;
+   const struct zynqmp_disp_format *fmt;
+
+   for (i = 0; i < ARRAY_SIZE(avbuf_live_fmts); ++i) {
+   fmt = _live_fmts[i];
+   if (fmt->bus_fmt == bus_format) {
+   layer->disp_fmt = fmt;
+   layer->drm_fmt = drm_format_info(fmt->drm_fmt);
+   zynqmp_disp_avbuf_set_live_format(layer->disp, layer, 
fmt);
+   return;
+   }
+   }
+}
+
 /**
  * zynqmp_disp_layer_set_format - Set the layer format
  * @layer: The layer
diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.h 
b/drivers/gpu/drm/xlnx/zynqmp_disp.h
index c2c8dd4896ba..f244b7d2346a 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.h
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.h
@@ -66,6 +66,8 @@ void zynqmp_disp_layer_enable(struct zynqmp_disp_layer 
*layer);
 void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer);
 void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer,
  const struct drm_format_info *info);
+void zynqmp_disp_layer_set_live_format(struct zynqmp_disp_layer *layer,
+  u32 bus_format);
 int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer,
 struct drm_plane_state *state);
 
diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp_regs.h 
b/drivers/gpu/drm/xlnx/zynqmp_disp_regs.h
index f92a006d5070..fa3935384834 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp_regs.h
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp_regs.h
@@ -165,10 +165,10 @@
 #define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_10  0x2
 #define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_12  0x3
 #define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_MASKGENMASK(2, 0)
-#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB 0x0
-#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV444  0x1
-#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422  0x2
-#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YONLY   0x3
+#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB (0x0 << 4)
+#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV444  (0x1 << 4)
+#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422  (0x2 << 4)
+#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YONLY   (0x3 << 4)
 #define ZYNQMP_DISP_AV_BU

[PATCH 4/4] drm/atomic-helper: Add select_output_bus_format callback

2024-02-26 Thread Anatoliy Klymenko
Add select_output_bus_format to CRTC atomic helpers callbacks. This
callback Will allow CRTC to participate in media bus format negotiation
over connected DRM bridge chain and impose CRTC-specific restrictions.
A good example is CRTC implemented as FPGA soft IP. This kind of CRTC will
most certainly support a single output media bus format, as supporting
multiple runtime options consumes extra FPGA resources. A variety of
options for FPGA are usually achieved by synthesizing IP with different
parameters.

Incorporate select_output_bus_format callback into the format negotiation
stage to fix the input bus format of the first DRM bridge in the chain.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/drm_bridge.c | 19 +--
 include/drm/drm_modeset_helper_vtables.h | 31 +++
 2 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 521a71c61b16..453ae3d174b4 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -32,6 +32,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -879,7 +880,8 @@ static int select_bus_fmt_recursive(struct drm_bridge 
*first_bridge,
unsigned int i, num_in_bus_fmts = 0;
struct drm_bridge_state *cur_state;
struct drm_bridge *prev_bridge;
-   u32 *in_bus_fmts;
+   struct drm_crtc *crtc = crtc_state->crtc;
+   u32 *in_bus_fmts, in_fmt;
int ret;
 
prev_bridge = drm_bridge_get_prev_bridge(cur_bridge);
@@ -933,7 +935,20 @@ static int select_bus_fmt_recursive(struct drm_bridge 
*first_bridge,
return -ENOMEM;
 
if (first_bridge == cur_bridge) {
-   cur_state->input_bus_cfg.format = in_bus_fmts[0];
+   in_fmt = in_bus_fmts[0];
+   if (crtc->helper_private &&
+   crtc->helper_private->select_output_bus_format) {
+   in_fmt = crtc->helper_private->select_output_bus_format(
+   crtc,
+   crtc->state,
+   in_bus_fmts,
+   num_in_bus_fmts);
+   if (!in_fmt) {
+   kfree(in_bus_fmts);
+   return -ENOTSUPP;
+   }
+   }
+   cur_state->input_bus_cfg.format = in_fmt;
cur_state->output_bus_cfg.format = out_bus_fmt;
kfree(in_bus_fmts);
return 0;
diff --git a/include/drm/drm_modeset_helper_vtables.h 
b/include/drm/drm_modeset_helper_vtables.h
index 881b03e4dc28..7c21ae1fe3ad 100644
--- a/include/drm/drm_modeset_helper_vtables.h
+++ b/include/drm/drm_modeset_helper_vtables.h
@@ -489,6 +489,37 @@ struct drm_crtc_helper_funcs {
 bool in_vblank_irq, int *vpos, int *hpos,
 ktime_t *stime, ktime_t *etime,
 const struct drm_display_mode *mode);
+
+   /**
+* @select_output_bus_format
+*
+* Called by the first connected DRM bridge to negotiate input media
+* bus format. CRTC is expected to pick preferable media formats from
+* the list supported by the DRM bridge chain.
+*
+* This callback is optional.
+*
+* Parameters:
+*
+* crtc:
+* The CRTC.
+* crcs_state:
+* New CRTC state.
+* supported_fmts:
+* List of input bus formats supported by the bridge.
+* num_supported_fmts:
+* Number of formats in the list.
+*
+* Returns:
+*
+* Preferred bus format from the list or 0 if CRTC doesn't support any
+* from the provided list.
+*
+*/
+   u32 (*select_output_bus_format)(struct drm_crtc *crtc,
+   struct drm_crtc_state *crtc_state,
+   const u32 *supported_fmts,
+   int num_supported_fmts);
 };
 
 /**

-- 
2.25.1



[PATCH 0/4] Setting live video input format for ZynqMP DPSUB

2024-02-26 Thread Anatoliy Klymenko
Implement live video input format setting for ZynqMP DPSUB.

ZynqMP DPSUB can operate in 2 modes: DMA-based and live.

In the live mode, DPSUB receives a live video signal from FPGA-based CRTC.
DPSUB acts as a DRM encoder bridge in such a scenario. To properly tune
into the incoming video signal, DPSUB should be programmed with the proper
media bus format. This patch series addresses this task.

Patch 1/4: Set the DPSUB layer mode of operation prior to enabling the
layer. Allows to use layer operational mode before its enablement.

Patch 2/4: Announce supported input media bus formats via
drm_bridge_funcs.atomic_get_input_bus_fmts callback.

Patch 3/4: Program DPSUB live video input format based on selected bus
config in the new atomic bridge state.

Patch 4/4: New optional CRTC atomic helper proposal that will allow CRTC
to participate in DRM bridge chain format negotiation and impose format
restrictions. Incorporate this callback into the DRM bridge format
negotiation process.

Signed-off-by: Anatoliy Klymenko 
---
Anatoliy Klymenko (4):
  drm: xlnx: zynqmp_dpsub: Set layer mode during creation
  drm: xlnx: zynqmp_dpsub: Anounce supported input formats
  drm: xlnx: zynqmp_dpsub: Set input live format
  drm/atomic-helper: Add select_output_bus_format callback

 drivers/gpu/drm/drm_bridge.c |  19 +-
 drivers/gpu/drm/xlnx/zynqmp_disp.c   | 109 +--
 drivers/gpu/drm/xlnx/zynqmp_disp.h   |  25 +++
 drivers/gpu/drm/xlnx/zynqmp_disp_regs.h  |   8 +--
 drivers/gpu/drm/xlnx/zynqmp_dp.c |  16 +++--
 drivers/gpu/drm/xlnx/zynqmp_kms.c|   2 +-
 include/drm/drm_modeset_helper_vtables.h |  31 +
 7 files changed, 182 insertions(+), 28 deletions(-)
---
base-commit: bfa4437fd3938ae2e186e7664b2db65bb8775670
change-id: 20240226-dp-live-fmt-6415773b5a68

Best regards,
-- 
Anatoliy Klymenko 



[PATCH v3 5/5] drm: xlnx: zynqmp_dpsub: Set live video in format

2024-01-23 Thread Anatoliy Klymenko
ZynqMP DPSUB supports 2 modes of operations in regard to video data
input.

In the first mode, DPSUB uses DMA engine to pull video data from memory
buffers. To support this the driver implements CRTC and DRM bridge
representing DP encoder.

In the second mode, DPSUB acquires video data pushed from FPGA and
passes it downstream to DP output. This mode of operation is modeled in
the driver as a DRM bridge that should be attached to some external
CRTC. DPSUB supports multiple input data formats. In order to properly
operate exact media bus format should be negotiated between external
CRTC and DPSUB bridge. DRM framework provides a mechanism to negotiate
media bus formats between bridges connected into a chain, but not
between CRTC and encoder (first bridge in the chain). This change
mitigates the issue for FPGA based CRTC, which would typically have a
single fixed media bus format.

Expect live video input format to be set as "bus-format" property in
connected remote endpoint.

Set display layer mode in the layer creation context.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c  | 109 ++--
 drivers/gpu/drm/xlnx/zynqmp_disp.h  |   3 +-
 drivers/gpu/drm/xlnx/zynqmp_disp_regs.h |   8 +-
 drivers/gpu/drm/xlnx/zynqmp_dp.c|   2 +-
 drivers/gpu/drm/xlnx/zynqmp_kms.c   |   2 +-
 5 files changed, 107 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 8a39b3accce5..a7115321b3fb 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -18,8 +18,10 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -67,12 +69,16 @@
 /**
  * struct zynqmp_disp_format - Display subsystem format information
  * @drm_fmt: DRM format (4CC)
+ * @bus_fmt: Live video media bus format
  * @buf_fmt: AV buffer format
  * @swap: Flag to swap R & B for RGB formats, and U & V for YUV formats
  * @sf: Scaling factors for color components
  */
 struct zynqmp_disp_format {
-   u32 drm_fmt;
+   union {
+   u32 drm_fmt;
+   u32 bus_fmt;
+   };
u32 buf_fmt;
bool swap;
const u32 *sf;
@@ -354,6 +360,16 @@ static const struct zynqmp_disp_format avbuf_gfx_fmts[] = {
},
 };
 
+/* TODO: add support for different formats */
+static const struct zynqmp_disp_format avbuf_live_vid_fmts[] = {
+   {
+   .bus_fmt= MEDIA_BUS_FMT_UYVY8_1X16,
+   .buf_fmt= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 |
+ ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422,
+   .sf = scaling_factors_888,
+   }
+};
+
 static u32 zynqmp_disp_avbuf_read(struct zynqmp_disp *disp, int reg)
 {
return readl(disp->avbuf.base + reg);
@@ -369,6 +385,34 @@ static bool zynqmp_disp_layer_is_video(const struct 
zynqmp_disp_layer *layer)
return layer->id == ZYNQMP_DPSUB_LAYER_VID;
 }
 
+/**
+ * zynqmp_disp_avbuf_set_live_format - Set live input format for a layer
+ * @disp: Display controller
+ * @layer: The layer
+ * @fmt: The format information
+ *
+ * Set the live video input format for @layer to @fmt.
+ */
+static void zynqmp_disp_avbuf_set_live_format(struct zynqmp_disp *disp,
+ struct zynqmp_disp_layer *layer,
+ const struct zynqmp_disp_format 
*fmt)
+{
+   u32 reg, i;
+
+   reg = zynqmp_disp_layer_is_video(layer)
+   ? ZYNQMP_DISP_AV_BUF_LIVE_VID_CONFIG
+   : ZYNQMP_DISP_AV_BUF_LIVE_GFX_CONFIG;
+   zynqmp_disp_avbuf_write(disp, reg, fmt->buf_fmt);
+
+   for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_SF; ++i) {
+   reg = zynqmp_disp_layer_is_video(layer)
+   ? ZYNQMP_DISP_AV_BUF_LIVD_VID_COMP_SF(i)
+   : ZYNQMP_DISP_AV_BUF_LIVD_GFX_COMP_SF(i);
+   zynqmp_disp_avbuf_write(disp, reg, fmt->sf[i]);
+   }
+   layer->disp_fmt = fmt;
+}
+
 /**
  * zynqmp_disp_avbuf_set_format - Set the input format for a layer
  * @disp: Display controller
@@ -902,15 +946,12 @@ u32 *zynqmp_disp_layer_drm_formats(struct 
zynqmp_disp_layer *layer,
 /**
  * zynqmp_disp_layer_enable - Enable a layer
  * @layer: The layer
- * @mode: Operating mode of layer
  *
  * Enable the @layer in the audio/video buffer manager and the blender. DMA
  * channels are started separately by zynqmp_disp_layer_update().
  */
-void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer,
- enum zynqmp_dpsub_layer_mode mode)
+void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer)
 {
-   layer->mode = mode;
zynqmp_disp_avbuf_enable_video(layer->disp, layer);
zynqmp_disp_blend_layer_enable(layer->disp, layer);
 }
@@ -950,11 +991,12 @@ void zynqmp_disp_layer_set_format(struct 
zynq

[PATCH v3 3/5] drm: xlnx: zynqmp_dpsub: Clear status register ASAP

2024-01-23 Thread Anatoliy Klymenko
Clear status register as soon as we read it.

Addressing comments from
https://lore.kernel.org/dri-devel/beb551c7-bb7e-4cd0-b166-e9aad90c4...@ideasonboard.com/

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_dp.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index d60b7431603f..5a3335e1fffa 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -1624,6 +1624,8 @@ static irqreturn_t zynqmp_dp_irq_handler(int irq, void 
*data)
u32 status, mask;
 
status = zynqmp_dp_read(dp, ZYNQMP_DP_INT_STATUS);
+   /* clear status register as soon as we read it */
+   zynqmp_dp_write(dp, ZYNQMP_DP_INT_STATUS, status);
mask = zynqmp_dp_read(dp, ZYNQMP_DP_INT_MASK);
if (!(status & ~mask))
return IRQ_NONE;
@@ -1634,8 +1636,6 @@ static irqreturn_t zynqmp_dp_irq_handler(int irq, void 
*data)
if (status & ZYNQMP_DP_INT_CHBUF_OVERFLW_MASK)
dev_dbg_ratelimited(dp->dev, "overflow interrupt\n");
 
-   zynqmp_dp_write(dp, ZYNQMP_DP_INT_STATUS, status);
-
if (status & ZYNQMP_DP_INT_VBLANK_START)
zynqmp_dpsub_drm_handle_vblank(dp->dpsub);
 
-- 
2.25.1



[PATCH v3 2/5] drm: xlnx: zynqmp_dpsub: Fix timing for live mode

2024-01-23 Thread Anatoliy Klymenko
Expect external video timing in live video input mode, program
DPSUB acordingly.

Reviewed-by: Tomi Valkeinen 

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 407bc07cec69..8a39b3accce5 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -1166,7 +1166,7 @@ void zynqmp_disp_enable(struct zynqmp_disp *disp)
/* Choose clock source based on the DT clock handle. */
zynqmp_disp_avbuf_set_clocks_sources(disp, disp->dpsub->vid_clk_from_ps,
 disp->dpsub->aud_clk_from_ps,
-true);
+disp->dpsub->vid_clk_from_ps);
zynqmp_disp_avbuf_enable_channels(disp);
zynqmp_disp_avbuf_enable_audio(disp);
 
-- 
2.25.1



[PATCH v3 0/5] Fixing live video input in ZynqMP DPSUB

2024-01-23 Thread Anatoliy Klymenko
Add few missing pieces to support ZynqMP DPSUB live video in mode.

ZynqMP DPSUB supports 2 modes of operations in regard to video data
input.

In the first mode, DPSUB uses DMA engine to pull video data from memory
buffers. To support this the driver implements CRTC and DRM bridge
representing DP encoder.

In the second mode, DPSUB acquires video data pushed from FPGA and 
passes it downstream to DP output. This mode of operation is modeled in
the driver as a DRM bridge that should be attached to some external
CRTC.

Patches 1/5,2/5,3/5,4/5 are minor fixes.

DPSUB requires input live video format to be configured.
Patch 5/5: The DP Subsystem requires the input live video format to be
configured. In this patch, we are assuming that the CRTC's bus format is
fixed (typical for FPGA CRTC) and comes from the device tree. This is a
proposed solution, as there is no API to query CRTC output bus format
or negotiate it in any other way.

Changes in v2: 
- Address reviewers' comments:
  - More elaborate and consistent comments / commit messages
  - Fix includes' order
  - Replace of_property_read_u32_index() with of_property_read_u32()

Changes in v3:
- Split patch #3 into 3) moving status register clear immediately after
  read; 4) masking status against interrupts' mask

Link to v1: 
https://lore.kernel.org/all/20240112234222.913138-1-anatoliy.klyme...@amd.com/
Link to v2: 
https://lore.kernel.org/all/20240119055437.2549149-1-anatoliy.klyme...@amd.com/

Anatoliy Klymenko (5):
  drm: xlnx: zynqmp_dpsub: Make drm bridge discoverable
  drm: xlnx: zynqmp_dpsub: Fix timing for live mode
  drm: xlnx: zynqmp_dpsub: Clear status register ASAP
  drm: xlnx: zynqmp_dpsub: Filter interrupts against mask
  drm: xlnx: zynqmp_dpsub: Set live video in format

 drivers/gpu/drm/xlnx/zynqmp_disp.c  | 111 +---
 drivers/gpu/drm/xlnx/zynqmp_disp.h  |   3 +-
 drivers/gpu/drm/xlnx/zynqmp_disp_regs.h |   8 +-
 drivers/gpu/drm/xlnx/zynqmp_dp.c|  16 +++-
 drivers/gpu/drm/xlnx/zynqmp_kms.c   |   2 +-
 5 files changed, 119 insertions(+), 21 deletions(-)

-- 
2.25.1



[PATCH v3 1/5] drm: xlnx: zynqmp_dpsub: Make drm bridge discoverable

2024-01-23 Thread Anatoliy Klymenko
ZynqMP DPSUB supports 2 input modes: DMA based and live video.

In the first mode, the driver implements CRTC and DP encoder DRM bridge
to model the complete display pipeline. In this case, DRM bridge is
being directly instantiated within the driver, not using any bridge
discovery mechanisms.

In the live video input mode video signal is generated by FPGA fabric
and passed into DPSUB over the connected bus. In this mode driver
exposes the DP encoder as a DRM bridge, expecting external CRTC to
discover it via drm_of_find_panel_or_bridge() or a similar call. This
discovery relies on drm_bridge.of_node being properly set.

Assign device OF node to the bridge prior to registering it. This will
make said bridge discoverable by an external CRTC driver.

Reviewed-by: Tomi Valkeinen 
Reviewed-by: Laurent Pinchart 

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_dp.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index a0606fab0e22..d60b7431603f 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -1721,6 +1721,7 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub)
bridge->ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID
| DRM_BRIDGE_OP_HPD;
bridge->type = DRM_MODE_CONNECTOR_DisplayPort;
+   bridge->of_node = dp->dev->of_node;
dpsub->bridge = bridge;
 
/*
-- 
2.25.1



[PATCH v3 4/5] drm: xlnx: zynqmp_dpsub: Filter interrupts against mask

2024-01-23 Thread Anatoliy Klymenko
Filter out status register against the interrupts' mask.

Some events are being reported via DP status register, even if
corresponding interrupts have been disabled. One instance of such event
leads to generation of VBLANK when the driver is in DRM bridge mode,
which in turn results in NULL pointer dereferencing. We should avoid
processing such events in an interrupt handler context.

This problem is less noticeable when the driver operates in DMA mode, as
in this case we have DRM CRTC object instantiated and DRM framework
simply discards unwanted VBLANKs in drm_handle_vblank().

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_dp.c | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index 5a3335e1fffa..9f48e5bbcdec 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -1627,7 +1627,14 @@ static irqreturn_t zynqmp_dp_irq_handler(int irq, void 
*data)
/* clear status register as soon as we read it */
zynqmp_dp_write(dp, ZYNQMP_DP_INT_STATUS, status);
mask = zynqmp_dp_read(dp, ZYNQMP_DP_INT_MASK);
-   if (!(status & ~mask))
+
+   /*
+* Status register may report some events, which corresponding 
interrupts
+* have been disabled. Filter out those events against interrupts' mask.
+*/
+   status &= ~mask;
+
+   if (!status)
return IRQ_NONE;
 
/* dbg for diagnostic, but not much that the driver can do */
-- 
2.25.1



[PATCH v2 2/4] drm: xlnx: zynqmp_dpsub: Fix timing for live mode

2024-01-18 Thread Anatoliy Klymenko
Expect external video timing in live video input mode, program
DPSUB acordingly.

Reviewed-by: Tomi Valkeinen 

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 407bc07cec69..8a39b3accce5 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -1166,7 +1166,7 @@ void zynqmp_disp_enable(struct zynqmp_disp *disp)
/* Choose clock source based on the DT clock handle. */
zynqmp_disp_avbuf_set_clocks_sources(disp, disp->dpsub->vid_clk_from_ps,
 disp->dpsub->aud_clk_from_ps,
-true);
+disp->dpsub->vid_clk_from_ps);
zynqmp_disp_avbuf_enable_channels(disp);
zynqmp_disp_avbuf_enable_audio(disp);
 
-- 
2.25.1



[PATCH v2 4/4] drm: xlnx: zynqmp_dpsub: Set live video in format

2024-01-18 Thread Anatoliy Klymenko
ZynqMP DPSUB supports 2 modes of operations in regard to video data
input.

In the first mode, DPSUB uses DMA engine to pull video data from memory
buffers. To support this the driver implements CRTC and DRM bridge
representing DP encoder.

In the second mode, DPSUB acquires video data pushed from FPGA and
passes it downstream to DP output. This mode of operation is modeled in
the driver as a DRM bridge that should be attached to some external
CRTC. DPSUB supports multiple input data formats. In order to properly
operate exact media bus format should be negotiated between external
CRTC and DPSUB bridge. DRM framework provides a mechanism to negotiate
media bus formats between bridges connected into a chain, but not
between CRTC and encoder (first bridge in the chain). This change
mitigates the issue for FPGA based CRTC, which would typically have a
single fixed media bus format.

Expect live video input format to be set as "bus-format" property in
connected remote endpoint.

Set display layer mode in the layer creation context.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c  | 109 ++--
 drivers/gpu/drm/xlnx/zynqmp_disp.h  |   3 +-
 drivers/gpu/drm/xlnx/zynqmp_disp_regs.h |   8 +-
 drivers/gpu/drm/xlnx/zynqmp_dp.c|   2 +-
 drivers/gpu/drm/xlnx/zynqmp_kms.c   |   2 +-
 5 files changed, 107 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 8a39b3accce5..a7115321b3fb 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -18,8 +18,10 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -67,12 +69,16 @@
 /**
  * struct zynqmp_disp_format - Display subsystem format information
  * @drm_fmt: DRM format (4CC)
+ * @bus_fmt: Live video media bus format
  * @buf_fmt: AV buffer format
  * @swap: Flag to swap R & B for RGB formats, and U & V for YUV formats
  * @sf: Scaling factors for color components
  */
 struct zynqmp_disp_format {
-   u32 drm_fmt;
+   union {
+   u32 drm_fmt;
+   u32 bus_fmt;
+   };
u32 buf_fmt;
bool swap;
const u32 *sf;
@@ -354,6 +360,16 @@ static const struct zynqmp_disp_format avbuf_gfx_fmts[] = {
},
 };
 
+/* TODO: add support for different formats */
+static const struct zynqmp_disp_format avbuf_live_vid_fmts[] = {
+   {
+   .bus_fmt= MEDIA_BUS_FMT_UYVY8_1X16,
+   .buf_fmt= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 |
+ ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422,
+   .sf = scaling_factors_888,
+   }
+};
+
 static u32 zynqmp_disp_avbuf_read(struct zynqmp_disp *disp, int reg)
 {
return readl(disp->avbuf.base + reg);
@@ -369,6 +385,34 @@ static bool zynqmp_disp_layer_is_video(const struct 
zynqmp_disp_layer *layer)
return layer->id == ZYNQMP_DPSUB_LAYER_VID;
 }
 
+/**
+ * zynqmp_disp_avbuf_set_live_format - Set live input format for a layer
+ * @disp: Display controller
+ * @layer: The layer
+ * @fmt: The format information
+ *
+ * Set the live video input format for @layer to @fmt.
+ */
+static void zynqmp_disp_avbuf_set_live_format(struct zynqmp_disp *disp,
+ struct zynqmp_disp_layer *layer,
+ const struct zynqmp_disp_format 
*fmt)
+{
+   u32 reg, i;
+
+   reg = zynqmp_disp_layer_is_video(layer)
+   ? ZYNQMP_DISP_AV_BUF_LIVE_VID_CONFIG
+   : ZYNQMP_DISP_AV_BUF_LIVE_GFX_CONFIG;
+   zynqmp_disp_avbuf_write(disp, reg, fmt->buf_fmt);
+
+   for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_SF; ++i) {
+   reg = zynqmp_disp_layer_is_video(layer)
+   ? ZYNQMP_DISP_AV_BUF_LIVD_VID_COMP_SF(i)
+   : ZYNQMP_DISP_AV_BUF_LIVD_GFX_COMP_SF(i);
+   zynqmp_disp_avbuf_write(disp, reg, fmt->sf[i]);
+   }
+   layer->disp_fmt = fmt;
+}
+
 /**
  * zynqmp_disp_avbuf_set_format - Set the input format for a layer
  * @disp: Display controller
@@ -902,15 +946,12 @@ u32 *zynqmp_disp_layer_drm_formats(struct 
zynqmp_disp_layer *layer,
 /**
  * zynqmp_disp_layer_enable - Enable a layer
  * @layer: The layer
- * @mode: Operating mode of layer
  *
  * Enable the @layer in the audio/video buffer manager and the blender. DMA
  * channels are started separately by zynqmp_disp_layer_update().
  */
-void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer,
- enum zynqmp_dpsub_layer_mode mode)
+void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer)
 {
-   layer->mode = mode;
zynqmp_disp_avbuf_enable_video(layer->disp, layer);
zynqmp_disp_blend_layer_enable(layer->disp, layer);
 }
@@ -950,11 +991,12 @@ void zynqmp_disp_layer_set_format(struct 
zynq

[PATCH v2 3/4] drm: xlnx: zynqmp_dpsub: Filter interrupts against mask

2024-01-18 Thread Anatoliy Klymenko
Filter out status register against the interrupts' mask.

Some events are being reported via DP status register, even if
corresponding interrupts have been disabled. One instance of such event
leads to generation of VBLANK when the driver is in DRM bridge mode,
which in turn results in NULL pointer dereferencing. We should avoid
processing such events in an interrupt handler context.

This problem is less noticeable when the driver operates in DMA mode, as
in this case we have DRM CRTC object instantiated and DRM framework
simply discards unwanted VBLANKs in drm_handle_vblank().

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_dp.c | 12 ++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index d60b7431603f..9ed12244a429 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -1624,8 +1624,17 @@ static irqreturn_t zynqmp_dp_irq_handler(int irq, void 
*data)
u32 status, mask;
 
status = zynqmp_dp_read(dp, ZYNQMP_DP_INT_STATUS);
+   /* clear status register as soon as we read its content */
+   zynqmp_dp_write(dp, ZYNQMP_DP_INT_STATUS, status);
mask = zynqmp_dp_read(dp, ZYNQMP_DP_INT_MASK);
-   if (!(status & ~mask))
+
+   /*
+* Status register may report some events, which corresponding 
interrupts
+* have been disabled. Filter out those events against interrupts' mask.
+*/
+   status &= ~mask;
+
+   if (!status)
return IRQ_NONE;
 
/* dbg for diagnostic, but not much that the driver can do */
@@ -1634,7 +1643,6 @@ static irqreturn_t zynqmp_dp_irq_handler(int irq, void 
*data)
if (status & ZYNQMP_DP_INT_CHBUF_OVERFLW_MASK)
dev_dbg_ratelimited(dp->dev, "overflow interrupt\n");
 
-   zynqmp_dp_write(dp, ZYNQMP_DP_INT_STATUS, status);
 
if (status & ZYNQMP_DP_INT_VBLANK_START)
zynqmp_dpsub_drm_handle_vblank(dp->dpsub);
-- 
2.25.1



[PATCH v2 1/4] drm: xlnx: zynqmp_dpsub: Make drm bridge discoverable

2024-01-18 Thread Anatoliy Klymenko
ZynqMP DPSUB supports 2 input modes: DMA based and live video.

In the first mode, the driver implements CRTC and DP encoder DRM bridge
to model the complete display pipeline. In this case, DRM bridge is
being directly instantiated within the driver, not using any bridge
discovery mechanisms.

In the live video input mode video signal is generated by FPGA fabric
and passed into DPSUB over the connected bus. In this mode driver
exposes the DP encoder as a DRM bridge, expecting external CRTC to
discover it via drm_of_find_panel_or_bridge() or a similar call. This
discovery relies on drm_bridge.of_node being properly set.

Assign device OF node to the bridge prior to registering it. This will
make said bridge discoverable by an external CRTC driver.

Reviewed-by: Tomi Valkeinen 
Reviewed-by: Laurent Pinchart 

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_dp.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index a0606fab0e22..d60b7431603f 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -1721,6 +1721,7 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub)
bridge->ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID
| DRM_BRIDGE_OP_HPD;
bridge->type = DRM_MODE_CONNECTOR_DisplayPort;
+   bridge->of_node = dp->dev->of_node;
dpsub->bridge = bridge;
 
/*
-- 
2.25.1



[PATCH v2 0/4] Fixing live video input in ZynqMP DPSUB

2024-01-18 Thread Anatoliy Klymenko
Add few missing pieces to support ZynqMP DPSUB live video in mode.

ZynqMP DPSUB supports 2 modes of operations in regard to video data
input.

In the first mode, DPSUB uses DMA engine to pull video data from memory
buffers. To support this the driver implements CRTC and DRM bridge
representing DP encoder.

In the second mode, DPSUB acquires video data pushed from FPGA and
passes it downstream to DP output. This mode of operation is modeled in
the driver as a DRM bridge that should be attached to some external
CRTC.

Patches 1/4,2/4,3/4 are minor fixes.

DPSUB requires input live video format to be configured.
Patch 4/4: The DP Subsystem requires the input live video format to be
configured. In this patch, we are assuming that the CRTC's bus format is
fixed (typical for FPGA CRTC) and comes from the device tree. This is a
proposed solution, as there is no API to query CRTC output bus format
or negotiate it in any other way.

Changes in v2:
- Address reviewers' comments:
  - More elaborate and consistent comments / commit messages
  - Fix includes' order
  - Replace of_property_read_u32_index() with of_property_read_u32()

Link to v1: 
https://lore.kernel.org/all/20240112234222.913138-1-anatoliy.klyme...@amd.com/

Anatoliy Klymenko (4):
  drm: xlnx: zynqmp_dpsub: Make drm bridge discoverable
  drm: xlnx: zynqmp_dpsub: Fix timing for live mode
  drm: xlnx: zynqmp_dpsub: Filter interrupts against mask
  drm: xlnx: zynqmp_dpsub: Set live video in format

 drivers/gpu/drm/xlnx/zynqmp_disp.c  | 111 +---
 drivers/gpu/drm/xlnx/zynqmp_disp.h  |   3 +-
 drivers/gpu/drm/xlnx/zynqmp_disp_regs.h |   8 +-
 drivers/gpu/drm/xlnx/zynqmp_dp.c|  15 +++-
 drivers/gpu/drm/xlnx/zynqmp_kms.c   |   2 +-
 5 files changed, 119 insertions(+), 20 deletions(-)

-- 
2.25.1



[PATCH 4/4] drm: xlnx: zynqmp_dpsub: Set live video in format

2024-01-12 Thread Anatoliy Klymenko
Live video input format is expected to be set as
"bus-format" property in connected remote endpoint.
Program live video input format DPSUB registers.
Set display layer mode in layer creation context.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c  | 109 ++--
 drivers/gpu/drm/xlnx/zynqmp_disp.h  |   3 +-
 drivers/gpu/drm/xlnx/zynqmp_disp_regs.h |   8 +-
 drivers/gpu/drm/xlnx/zynqmp_dp.c|   2 +-
 drivers/gpu/drm/xlnx/zynqmp_kms.c   |   2 +-
 5 files changed, 107 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 8a39b3accce5..83af3ad9cdb5 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -20,8 +20,10 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
+#include 
 
 #include "zynqmp_disp.h"
 #include "zynqmp_disp_regs.h"
@@ -67,12 +69,16 @@
 /**
  * struct zynqmp_disp_format - Display subsystem format information
  * @drm_fmt: DRM format (4CC)
+ * @bus_fmt: Live video media bus format
  * @buf_fmt: AV buffer format
  * @swap: Flag to swap R & B for RGB formats, and U & V for YUV formats
  * @sf: Scaling factors for color components
  */
 struct zynqmp_disp_format {
-   u32 drm_fmt;
+   union {
+   u32 drm_fmt;
+   u32 bus_fmt;
+   };
u32 buf_fmt;
bool swap;
const u32 *sf;
@@ -354,6 +360,16 @@ static const struct zynqmp_disp_format avbuf_gfx_fmts[] = {
},
 };
 
+/* TODO: add support for different formats */
+static const struct zynqmp_disp_format avbuf_live_vid_fmts[] = {
+   {
+   .bus_fmt= MEDIA_BUS_FMT_UYVY8_1X16,
+   .buf_fmt= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 |
+ ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422,
+   .sf = scaling_factors_888,
+   }
+};
+
 static u32 zynqmp_disp_avbuf_read(struct zynqmp_disp *disp, int reg)
 {
return readl(disp->avbuf.base + reg);
@@ -369,6 +385,34 @@ static bool zynqmp_disp_layer_is_video(const struct 
zynqmp_disp_layer *layer)
return layer->id == ZYNQMP_DPSUB_LAYER_VID;
 }
 
+/**
+ * zynqmp_disp_avbuf_set_live_format - Set live input format for a layer
+ * @disp: Display controller
+ * @layer: The layer
+ * @fmt: The format information
+ *
+ * Set the live video input format for @layer to @fmt.
+ */
+static void zynqmp_disp_avbuf_set_live_format(struct zynqmp_disp *disp,
+ struct zynqmp_disp_layer *layer,
+ const struct zynqmp_disp_format 
*fmt)
+{
+   u32 reg, i;
+
+   reg = zynqmp_disp_layer_is_video(layer)
+   ? ZYNQMP_DISP_AV_BUF_LIVE_VID_CONFIG
+   : ZYNQMP_DISP_AV_BUF_LIVE_GFX_CONFIG;
+   zynqmp_disp_avbuf_write(disp, reg, fmt->buf_fmt);
+
+   for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_SF; ++i) {
+   reg = zynqmp_disp_layer_is_video(layer)
+   ? ZYNQMP_DISP_AV_BUF_LIVD_VID_COMP_SF(i)
+   : ZYNQMP_DISP_AV_BUF_LIVD_GFX_COMP_SF(i);
+   zynqmp_disp_avbuf_write(disp, reg, fmt->sf[i]);
+   }
+   layer->disp_fmt = fmt;
+}
+
 /**
  * zynqmp_disp_avbuf_set_format - Set the input format for a layer
  * @disp: Display controller
@@ -902,15 +946,12 @@ u32 *zynqmp_disp_layer_drm_formats(struct 
zynqmp_disp_layer *layer,
 /**
  * zynqmp_disp_layer_enable - Enable a layer
  * @layer: The layer
- * @mode: Operating mode of layer
  *
  * Enable the @layer in the audio/video buffer manager and the blender. DMA
  * channels are started separately by zynqmp_disp_layer_update().
  */
-void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer,
- enum zynqmp_dpsub_layer_mode mode)
+void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer)
 {
-   layer->mode = mode;
zynqmp_disp_avbuf_enable_video(layer->disp, layer);
zynqmp_disp_blend_layer_enable(layer->disp, layer);
 }
@@ -950,11 +991,12 @@ void zynqmp_disp_layer_set_format(struct 
zynqmp_disp_layer *layer,
layer->disp_fmt = zynqmp_disp_layer_find_format(layer, info->format);
layer->drm_fmt = info;
 
-   zynqmp_disp_avbuf_set_format(layer->disp, layer, layer->disp_fmt);
-
-   if (!layer->disp->dpsub->dma_enabled)
+   /* Live format set during layer creation */
+   if (layer->mode == ZYNQMP_DPSUB_LAYER_LIVE)
return;
 
+   zynqmp_disp_avbuf_set_format(layer->disp, layer, layer->disp_fmt);
+
/*
 * Set pconfig for each DMA channel to indicate they're part of a
 * video group.
@@ -1083,7 +1125,7 @@ static int zynqmp_disp_layer_request_dma(struct 
zynqmp_disp *disp,
unsigned int i;
int ret;
 
-   if (!disp->dpsub->dma_enabled)
+

[PATCH 2/4] drm: xlnx: zynqmp_dpsub: Fix timing for live mode

2024-01-12 Thread Anatoliy Klymenko
Expect external video timing in live video input mode, program
DPSUB accordingly.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_disp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.c 
b/drivers/gpu/drm/xlnx/zynqmp_disp.c
index 407bc07cec69..8a39b3accce5 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.c
@@ -1166,7 +1166,7 @@ void zynqmp_disp_enable(struct zynqmp_disp *disp)
/* Choose clock source based on the DT clock handle. */
zynqmp_disp_avbuf_set_clocks_sources(disp, disp->dpsub->vid_clk_from_ps,
 disp->dpsub->aud_clk_from_ps,
-true);
+disp->dpsub->vid_clk_from_ps);
zynqmp_disp_avbuf_enable_channels(disp);
zynqmp_disp_avbuf_enable_audio(disp);
 
-- 
2.25.1



[PATCH 3/4] drm: xlnx: zynqmp_dpsub: Don't generate vblank in live mode

2024-01-12 Thread Anatoliy Klymenko
Filter out status register against interrupts' mask.
Some events are being reported via DP status register, even if
corresponding interrupts have been disabled. Avoid processing
of such events in interrupt handler context.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_dp.c | 11 +--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index d60b7431603f..571c5dbc97e5 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -1624,8 +1624,16 @@ static irqreturn_t zynqmp_dp_irq_handler(int irq, void 
*data)
u32 status, mask;
 
status = zynqmp_dp_read(dp, ZYNQMP_DP_INT_STATUS);
+   zynqmp_dp_write(dp, ZYNQMP_DP_INT_STATUS, status);
mask = zynqmp_dp_read(dp, ZYNQMP_DP_INT_MASK);
-   if (!(status & ~mask))
+
+   /*
+* Status register may report some events, which corresponding 
interrupts
+* have been disabled. Filter out those events against interrupts' mask.
+*/
+   status &= ~mask;
+
+   if (!status)
return IRQ_NONE;
 
/* dbg for diagnostic, but not much that the driver can do */
@@ -1634,7 +1642,6 @@ static irqreturn_t zynqmp_dp_irq_handler(int irq, void 
*data)
if (status & ZYNQMP_DP_INT_CHBUF_OVERFLW_MASK)
dev_dbg_ratelimited(dp->dev, "overflow interrupt\n");
 
-   zynqmp_dp_write(dp, ZYNQMP_DP_INT_STATUS, status);
 
if (status & ZYNQMP_DP_INT_VBLANK_START)
zynqmp_dpsub_drm_handle_vblank(dp->dpsub);
-- 
2.25.1



[PATCH 0/4] Fixing live video input in ZynqMP DPSUB

2024-01-12 Thread Anatoliy Klymenko
Patches 1/4,2/4,3/4 are minor fixes.

DPSUB requires input live video format to be configured.
Patch 4/4: The DP Subsystem requires the input live video format to be
configured. In this patch we are assuming that the CRTC's bus format is fixed
and comes from the device tree. This is a proposed solution, as there are no api
to query CRTC output bus format.

Is this a good approach to go with?

Anatoliy Klymenko (4):
  drm: xlnx: zynqmp_dpsub: Make drm bridge discoverable
  drm: xlnx: zynqmp_dpsub: Fix timing for live mode
  drm: xlnx: zynqmp_dpsub: Don't generate vblank in live mode
  drm: xlnx: zynqmp_dpsub: Set live video in format

 drivers/gpu/drm/xlnx/zynqmp_disp.c  | 111 +---
 drivers/gpu/drm/xlnx/zynqmp_disp.h  |   3 +-
 drivers/gpu/drm/xlnx/zynqmp_disp_regs.h |   8 +-
 drivers/gpu/drm/xlnx/zynqmp_dp.c|  14 ++-
 drivers/gpu/drm/xlnx/zynqmp_kms.c   |   2 +-
 5 files changed, 118 insertions(+), 20 deletions(-)

-- 
2.25.1



[PATCH 1/4] drm: xlnx: zynqmp_dpsub: Make drm bridge discoverable

2024-01-12 Thread Anatoliy Klymenko
Assign device of node to bridge prior registering it. This will
make said bridge discoverable by separate crtc driver.

Signed-off-by: Anatoliy Klymenko 
---
 drivers/gpu/drm/xlnx/zynqmp_dp.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index a0606fab0e22..d60b7431603f 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -1721,6 +1721,7 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub)
bridge->ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID
| DRM_BRIDGE_OP_HPD;
bridge->type = DRM_MODE_CONNECTOR_DisplayPort;
+   bridge->of_node = dp->dev->of_node;
dpsub->bridge = bridge;
 
/*
-- 
2.25.1