Re: [PATCH v2 1/4] drm/bridge: dw-hdmi: Add Dynamic Range and Mastering InfoFrame support

From: Andrzej Hajda
Date: Thu Oct 10 2019 - 06:12:54 EST


On 07.10.2019 21:21, Jonas Karlman wrote:
> Add support for configuring Dynamic Range and Mastering InfoFrame from
> the hdr_output_metadata connector property.
>
> This patch adds a use_drm_infoframe flag to dw_hdmi_plat_data that platform
> drivers use to signal when Dynamic Range and Mastering infoframes is supported.
> This flag is needed because Amlogic GXBB and GXL report same DW-HDMI version,
> and only GXL support DRM InfoFrame.
>
> These changes were based on work done by Zheng Yang <zhengyang@xxxxxxxxxxxxxx>
> to support DRM InfoFrame on the Rockchip 4.4 BSP kernel at [1] and [2]
>
> [1] https://github.com/rockchip-linux/kernel/tree/develop-4.4
> [2] https://github.com/rockchip-linux/kernel/commit/d1943fde81ff41d7cca87f4a42f03992e90bddd5
>
> Cc: Zheng Yang <zhengyang@xxxxxxxxxxxxxx>
> Signed-off-by: Jonas Karlman <jonas@xxxxxxxxx>
> Reviewed-by: Neil Armstrong <narmstrong@xxxxxxxxxxxx>


Reviewed-by: Andrzej Hajda <a.hajda@xxxxxxxxxxx>


Neil, since you want to take care of patch3/4, will you take care of the
whole patchset?


Â--
Regards
Andrzej


> ---
> drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 81 +++++++++++++++++++++++
> drivers/gpu/drm/bridge/synopsys/dw-hdmi.h | 37 +++++++++++
> include/drm/bridge/dw_hdmi.h | 1 +
> 3 files changed, 119 insertions(+)
>
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index a15fbf71b9d7..fdc29869d75a 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -25,6 +25,7 @@
> #include <uapi/linux/videodev2.h>
>
> #include <drm/bridge/dw_hdmi.h>
> +#include <drm/drm_atomic.h>
> #include <drm/drm_atomic_helper.h>
> #include <drm/drm_bridge.h>
> #include <drm/drm_edid.h>
> @@ -1743,6 +1744,41 @@ static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi,
> HDMI_FC_DATAUTO0_VSD_MASK);
> }
>
> +static void hdmi_config_drm_infoframe(struct dw_hdmi *hdmi)
> +{
> + const struct drm_connector_state *conn_state = hdmi->connector.state;
> + struct hdmi_drm_infoframe frame;
> + u8 buffer[30];
> + ssize_t err;
> + int i;
> +
> + if (!hdmi->plat_data->use_drm_infoframe)
> + return;
> +
> + hdmi_modb(hdmi, HDMI_FC_PACKET_TX_EN_DRM_DISABLE,
> + HDMI_FC_PACKET_TX_EN_DRM_MASK, HDMI_FC_PACKET_TX_EN);
> +
> + err = drm_hdmi_infoframe_set_hdr_metadata(&frame, conn_state);
> + if (err < 0)
> + return;
> +
> + err = hdmi_drm_infoframe_pack(&frame, buffer, sizeof(buffer));
> + if (err < 0) {
> + dev_err(hdmi->dev, "Failed to pack drm infoframe: %zd\n", err);
> + return;
> + }
> +
> + hdmi_writeb(hdmi, frame.version, HDMI_FC_DRM_HB0);
> + hdmi_writeb(hdmi, frame.length, HDMI_FC_DRM_HB1);
> +
> + for (i = 0; i < frame.length; i++)
> + hdmi_writeb(hdmi, buffer[4 + i], HDMI_FC_DRM_PB0 + i);
> +
> + hdmi_writeb(hdmi, 1, HDMI_FC_DRM_UP);
> + hdmi_modb(hdmi, HDMI_FC_PACKET_TX_EN_DRM_ENABLE,
> + HDMI_FC_PACKET_TX_EN_DRM_MASK, HDMI_FC_PACKET_TX_EN);
> +}
> +
> static void hdmi_av_composer(struct dw_hdmi *hdmi,
> const struct drm_display_mode *mode)
> {
> @@ -2064,6 +2100,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
> /* HDMI Initialization Step F - Configure AVI InfoFrame */
> hdmi_config_AVI(hdmi, mode);
> hdmi_config_vendor_specific_infoframe(hdmi, mode);
> + hdmi_config_drm_infoframe(hdmi);
> } else {
> dev_dbg(hdmi->dev, "%s DVI mode\n", __func__);
> }
> @@ -2230,6 +2267,45 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
> return ret;
> }
>
> +static bool hdr_metadata_equal(const struct drm_connector_state *old_state,
> + const struct drm_connector_state *new_state)
> +{
> + struct drm_property_blob *old_blob = old_state->hdr_output_metadata;
> + struct drm_property_blob *new_blob = new_state->hdr_output_metadata;
> +
> + if (!old_blob || !new_blob)
> + return old_blob == new_blob;
> +
> + if (old_blob->length != new_blob->length)
> + return false;
> +
> + return !memcmp(old_blob->data, new_blob->data, old_blob->length);
> +}
> +
> +static int dw_hdmi_connector_atomic_check(struct drm_connector *connector,
> + struct drm_atomic_state *state)
> +{
> + struct drm_connector_state *old_state =
> + drm_atomic_get_old_connector_state(state, connector);
> + struct drm_connector_state *new_state =
> + drm_atomic_get_new_connector_state(state, connector);
> + struct drm_crtc *crtc = new_state->crtc;
> + struct drm_crtc_state *crtc_state;
> +
> + if (!crtc)
> + return 0;
> +
> + if (!hdr_metadata_equal(old_state, new_state)) {
> + crtc_state = drm_atomic_get_crtc_state(state, crtc);
> + if (IS_ERR(crtc_state))
> + return PTR_ERR(crtc_state);
> +
> + crtc_state->mode_changed = true;
> + }
> +
> + return 0;
> +}
> +
> static void dw_hdmi_connector_force(struct drm_connector *connector)
> {
> struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
> @@ -2254,6 +2330,7 @@ static const struct drm_connector_funcs dw_hdmi_connector_funcs = {
>
> static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
> .get_modes = dw_hdmi_connector_get_modes,
> + .atomic_check = dw_hdmi_connector_atomic_check,
> };
>
> static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
> @@ -2274,6 +2351,10 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
> DRM_MODE_CONNECTOR_HDMIA,
> hdmi->ddc);
>
> + if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe)
> + drm_object_attach_property(&connector->base,
> + connector->dev->mode_config.hdr_output_metadata_property, 0);
> +
> drm_connector_attach_encoder(connector, encoder);
>
> cec_fill_conn_info_from_drm(&conn_info, connector);
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
> index fcff5059db24..1999db05bc3b 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
> @@ -254,6 +254,7 @@
> #define HDMI_FC_POL2 0x10DB
> #define HDMI_FC_PRCONF 0x10E0
> #define HDMI_FC_SCRAMBLER_CTRL 0x10E1
> +#define HDMI_FC_PACKET_TX_EN 0x10E3
>
> #define HDMI_FC_GMD_STAT 0x1100
> #define HDMI_FC_GMD_EN 0x1101
> @@ -289,6 +290,37 @@
> #define HDMI_FC_GMD_PB26 0x111F
> #define HDMI_FC_GMD_PB27 0x1120
>
> +#define HDMI_FC_DRM_UP 0x1167
> +#define HDMI_FC_DRM_HB0 0x1168
> +#define HDMI_FC_DRM_HB1 0x1169
> +#define HDMI_FC_DRM_PB0 0x116A
> +#define HDMI_FC_DRM_PB1 0x116B
> +#define HDMI_FC_DRM_PB2 0x116C
> +#define HDMI_FC_DRM_PB3 0x116D
> +#define HDMI_FC_DRM_PB4 0x116E
> +#define HDMI_FC_DRM_PB5 0x116F
> +#define HDMI_FC_DRM_PB6 0x1170
> +#define HDMI_FC_DRM_PB7 0x1171
> +#define HDMI_FC_DRM_PB8 0x1172
> +#define HDMI_FC_DRM_PB9 0x1173
> +#define HDMI_FC_DRM_PB10 0x1174
> +#define HDMI_FC_DRM_PB11 0x1175
> +#define HDMI_FC_DRM_PB12 0x1176
> +#define HDMI_FC_DRM_PB13 0x1177
> +#define HDMI_FC_DRM_PB14 0x1178
> +#define HDMI_FC_DRM_PB15 0x1179
> +#define HDMI_FC_DRM_PB16 0x117A
> +#define HDMI_FC_DRM_PB17 0x117B
> +#define HDMI_FC_DRM_PB18 0x117C
> +#define HDMI_FC_DRM_PB19 0x117D
> +#define HDMI_FC_DRM_PB20 0x117E
> +#define HDMI_FC_DRM_PB21 0x117F
> +#define HDMI_FC_DRM_PB22 0x1180
> +#define HDMI_FC_DRM_PB23 0x1181
> +#define HDMI_FC_DRM_PB24 0x1182
> +#define HDMI_FC_DRM_PB25 0x1183
> +#define HDMI_FC_DRM_PB26 0x1184
> +
> #define HDMI_FC_DBGFORCE 0x1200
> #define HDMI_FC_DBGAUD0CH0 0x1201
> #define HDMI_FC_DBGAUD1CH0 0x1202
> @@ -744,6 +776,11 @@ enum {
> HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK = 0x0F,
> HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET = 0,
>
> +/* FC_PACKET_TX_EN field values */
> + HDMI_FC_PACKET_TX_EN_DRM_MASK = 0x80,
> + HDMI_FC_PACKET_TX_EN_DRM_ENABLE = 0x80,
> + HDMI_FC_PACKET_TX_EN_DRM_DISABLE = 0x00,
> +
> /* FC_AVICONF0-FC_AVICONF3 field values */
> HDMI_FC_AVICONF0_PIX_FMT_MASK = 0x03,
> HDMI_FC_AVICONF0_PIX_FMT_RGB = 0x00,
> diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
> index 4b3e863c4f8a..fbf3812c4326 100644
> --- a/include/drm/bridge/dw_hdmi.h
> +++ b/include/drm/bridge/dw_hdmi.h
> @@ -126,6 +126,7 @@ struct dw_hdmi_plat_data {
> const struct drm_display_mode *mode);
> unsigned long input_bus_format;
> unsigned long input_bus_encoding;
> + bool use_drm_infoframe;
>
> /* Vendor PHY support */
> const struct dw_hdmi_phy_ops *phy_ops;