From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Wed, 6 Oct 2021 23:34:04 +0200 Subject: drm/meson: Update the HDMI encoder for Meson8/8b/8m2 Meson8/8b/8m2 uses VPU_HDMI_OUTPUT_YCBCR for YUV444 while newer SoCs use VPU_HDMI_OUTPUT_CBYCR. Also the 32-bit SoCs use VPU_HDMI_OUTPUT_CRYCB for RGB. These are the only two known mappings for the 32-bit SoCs. The VPU_HDMI_FMT_CTRL register with it's YUV444 to YUV422/YUV420 converter is not present on these older SoCs. Avoid writing this reserved register on these 32-bit SoCs. MEDIA_BUS_FMT_RGB888_1X24 cannot be exposed as output format because the RGB to YUV converter is always enabled in meson_plane_atomic_update() (so there's currently no way to configure it). Signed-off-by: Martin Blumenstingl --- drivers/gpu/drm/meson/meson_encoder_hdmi.c | 66 +++++++--- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/meson/meson_encoder_hdmi.c index 111111111111..222222222222 100644 --- a/drivers/gpu/drm/meson/meson_encoder_hdmi.c +++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c @@ -190,13 +190,13 @@ static void meson_encoder_hdmi_atomic_enable(struct drm_bridge *bridge, { struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge); struct drm_atomic_state *state = bridge_state->base.state; - unsigned int ycrcb_map = VPU_HDMI_OUTPUT_CBYCR; struct meson_drm *priv = encoder_hdmi->priv; struct drm_connector_state *conn_state; const struct drm_display_mode *mode; struct drm_crtc_state *crtc_state; struct drm_connector *connector; bool yuv420_mode = false; + unsigned int ycrcb_map; int vic; connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); @@ -217,11 +217,21 @@ static void meson_encoder_hdmi_atomic_enable(struct drm_bridge *bridge, dev_dbg(priv->dev, "\"%s\" vic %d\n", mode->name, vic); - if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) { + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8) || + meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8B) || + meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8M2)) { + if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_RGB888_1X24) + ycrcb_map = VPU_HDMI_OUTPUT_YCBCR; + else + ycrcb_map = VPU_HDMI_OUTPUT_CRYCB; + } else if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) { ycrcb_map = VPU_HDMI_OUTPUT_CRYCB; yuv420_mode = true; - } else if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYVY8_1X16) + } else if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYVY8_1X16) { ycrcb_map = VPU_HDMI_OUTPUT_CRYCB; + } else { + ycrcb_map = VPU_HDMI_OUTPUT_CBYCR; + } /* VENC + VENC-DVI Mode setup */ meson_venc_hdmi_mode_set(priv, vic, ycrcb_map, yuv420_mode, mode); @@ -229,17 +239,21 @@ static void meson_encoder_hdmi_atomic_enable(struct drm_bridge *bridge, /* VCLK Set clock */ meson_encoder_hdmi_set_vclk(encoder_hdmi, mode); - if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) - /* Setup YUV420 to HDMI-TX, no 10bit diphering */ - writel_relaxed(2 | (2 << 2), - priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); - else if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYVY8_1X16) - /* Setup YUV422 to HDMI-TX, no 10bit diphering */ - writel_relaxed(1 | (2 << 2), - priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); - else - /* Setup YUV444 to HDMI-TX, no 10bit diphering */ - writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); + if (!meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8) && + !meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8B) && + !meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8M2)) { + if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) + /* Setup YUV420 to HDMI-TX, no 10bit diphering */ + writel_relaxed(2 | (2 << 2), + priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); + else if (encoder_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYVY8_1X16) + /* Setup YUV422 to HDMI-TX, no 10bit diphering */ + writel_relaxed(1 | (2 << 2), + priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); + else + /* Setup YUV444 to HDMI-TX, no 10bit diphering */ + writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); + } dev_dbg(priv->dev, "%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP"); @@ -262,7 +276,11 @@ static void meson_encoder_hdmi_atomic_disable(struct drm_bridge *bridge, writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN)); } -static const u32 meson_encoder_hdmi_out_bus_fmts[] = { +static const u32 meson8_encoder_hdmi_out_bus_fmts[] = { + MEDIA_BUS_FMT_YUV8_1X24, +}; + +static const u32 meson_gx_encoder_hdmi_out_bus_fmts[] = { MEDIA_BUS_FMT_YUV8_1X24, MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_UYYVYY8_0_5X24, @@ -276,13 +294,27 @@ meson_encoder_hdmi_get_inp_bus_fmts(struct drm_bridge *bridge, u32 output_fmt, unsigned int *num_input_fmts) { + struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge); + struct meson_drm *priv = encoder_hdmi->priv; + unsigned int num_out_bus_fmts; + const u32 *out_bus_fmts; u32 *input_fmts = NULL; int i; + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8) || + meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8B) || + meson_vpu_is_compatible(priv, VPU_COMPATIBLE_M8M2)) { + num_out_bus_fmts = ARRAY_SIZE(meson8_encoder_hdmi_out_bus_fmts); + out_bus_fmts = meson8_encoder_hdmi_out_bus_fmts; + } else { + num_out_bus_fmts = ARRAY_SIZE(meson_gx_encoder_hdmi_out_bus_fmts); + out_bus_fmts = meson_gx_encoder_hdmi_out_bus_fmts; + } + *num_input_fmts = 0; - for (i = 0 ; i < ARRAY_SIZE(meson_encoder_hdmi_out_bus_fmts) ; ++i) { - if (output_fmt == meson_encoder_hdmi_out_bus_fmts[i]) { + for (i = 0 ; i < num_out_bus_fmts ; ++i) { + if (output_fmt == out_bus_fmts[i]) { *num_input_fmts = 1; input_fmts = kcalloc(*num_input_fmts, sizeof(*input_fmts), -- Armbian