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@xxxxxxx> --- 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 = &avbuf_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_MASK GENMASK(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_MASK GENMASK(5, 4) #define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_CB_FIRST BIT(8) #define ZYNQMP_DISP_AV_BUF_PALETTE_MEMORY 0x400 diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c index 9cb7ac9f3097..0d5dffd20ad1 100644 --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c @@ -1281,7 +1281,8 @@ static void zynqmp_dp_disp_enable(struct zynqmp_dp *dp, { enum zynqmp_dpsub_layer_id layer_id; struct zynqmp_disp_layer *layer; - const struct drm_format_info *info; + struct drm_bridge_state *bridge_state; + u32 bus_fmt; if (dp->dpsub->connected_ports & BIT(ZYNQMP_DPSUB_PORT_LIVE_VIDEO)) layer_id = ZYNQMP_DPSUB_LAYER_VID; @@ -1291,10 +1292,14 @@ static void zynqmp_dp_disp_enable(struct zynqmp_dp *dp, return; layer = dp->dpsub->layers[layer_id]; + bridge_state = drm_atomic_get_new_bridge_state(old_bridge_state->base.state, + old_bridge_state->bridge); + if (bridge_state) { + bus_fmt = bridge_state->input_bus_cfg.format; + zynqmp_disp_layer_set_live_format(layer, bus_fmt); + } else + return; - /* 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) -- 2.25.1