Message ID | 20240416-dp-live-fmt-v4-6-c7f379b7168e@amd.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Managing live video input format for ZynqMP DPSUB | expand |
On 16/04/2024 23:31, Anatoliy Klymenko wrote: > 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.klymenko@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(-) > Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> Tomi > 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]) >
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])
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.klymenko@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(-)