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 <anatoliy.klyme...@amd.com>
---
 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 &layer->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: The format info
+ *
+ * NOTE: This function should not be used to set format for non-live video
+ * layer. Use zynqmp_disp_layer_set_format() instead.
+ *
+ * Set the display format for the live @layer. The layer must be disabled.
+ */
+void zynqmp_disp_layer_set_live_format(struct zynqmp_disp_layer *layer,
+                                      u32 media_bus_format)
+{
+       if (WARN_ON(layer->mode != ZYNQMP_DPSUB_LAYER_LIVE))
+               return;
+
+       layer->disp_fmt = zynqmp_disp_layer_find_live_format(layer,
+                                                            media_bus_format);
+       if (WARN_ON(!layer->disp_fmt))
+               return;
+
+       zynqmp_disp_avbuf_set_format(layer->disp, layer, layer->disp_fmt);
+
+       layer->drm_fmt = drm_format_info(layer->disp_fmt->drm_fmt);
+}
+
 /**
  * zynqmp_disp_layer_update - Update the layer framebuffer
  * @layer: The layer
diff --git a/drivers/gpu/drm/xlnx/zynqmp_disp.h 
b/drivers/gpu/drm/xlnx/zynqmp_disp.h
index efd1c52c2916..fa545533c9d1 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_disp.h
+++ b/drivers/gpu/drm/xlnx/zynqmp_disp.h
@@ -58,6 +58,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 media_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_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index faaeea526970..a7fa5e2abb9b 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -1299,15 +1299,20 @@ static void zynqmp_dp_disp_enable(struct zynqmp_dp *dp,
                                  struct drm_bridge_state *old_bridge_state)
 {
        struct zynqmp_disp_layer *layer;
-       const struct drm_format_info *info;
+       struct drm_bridge_state *bridge_state;
+       u32 bus_fmt;
 
        layer = zynqmp_dp_disp_connected_live_layer(dp);
        if (!layer)
                return;
 
-       /* TODO: Make the format configurable. */
-       info = drm_format_info(DRM_FORMAT_YUV422);
-       zynqmp_disp_layer_set_format(layer, info);
+       bridge_state = 
drm_atomic_get_new_bridge_state(old_bridge_state->base.state,
+                                                      
old_bridge_state->bridge);
+       if (WARN_ON(!bridge_state))
+               return;
+
+       bus_fmt = bridge_state->input_bus_cfg.format;
+       zynqmp_disp_layer_set_live_format(layer, bus_fmt);
        zynqmp_disp_layer_enable(layer);
 
        if (layer == dp->dpsub->layers[ZYNQMP_DPSUB_LAYER_GFX])

-- 
2.25.1

Reply via email to