Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions drivers/gpu/drm/vc4/vc4_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,45 @@ static int vc4_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 vc4_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;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static void vc4_hdmi_connector_reset(struct drm_connector *connector)
{
struct vc4_hdmi_connector_state *old_state =
Expand Down Expand Up @@ -576,6 +615,7 @@ static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {

static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = {
.get_modes = vc4_hdmi_connector_get_modes,
.atomic_check = vc4_hdmi_connector_atomic_check,
};

static int vc4_hdmi_connector_init(struct drm_device *dev,
Expand Down Expand Up @@ -613,6 +653,10 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
connector->doublescan_allowed = 0;
connector->stereo_allowed = 1;

if (vc4_hdmi->variant->supports_hdr)
drm_object_attach_property(&connector->base,
connector->dev->mode_config.hdr_output_metadata_property, 0);

drm_connector_attach_encoder(connector, encoder);

return 0;
Expand Down Expand Up @@ -755,6 +799,25 @@ static void vc4_hdmi_set_audio_infoframe(struct drm_encoder *encoder)
vc4_hdmi_write_infoframe(encoder, &frame);
}

static void vc4_hdmi_set_hdr_infoframe(struct drm_encoder *encoder)
{
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
struct drm_connector *connector = &vc4_hdmi->connector;
struct drm_connector_state *conn_state = connector->state;
union hdmi_infoframe frame;

if (!vc4_hdmi->variant->supports_hdr)
return;

if (!conn_state->hdr_output_metadata)
return;

if (drm_hdmi_infoframe_set_hdr_metadata(&frame.drm, conn_state))
return;

vc4_hdmi_write_infoframe(encoder, &frame);
}

static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder)
{
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
Expand All @@ -767,6 +830,8 @@ static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder)
*/
if (vc4_hdmi->audio.streaming)
vc4_hdmi_set_audio_infoframe(encoder);

vc4_hdmi_set_hdr_infoframe(encoder);
}

static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
Expand Down Expand Up @@ -2672,6 +2737,7 @@ static const struct vc4_hdmi_variant bcm2835_variant = {
.phy_rng_enable = vc4_hdmi_phy_rng_enable,
.phy_rng_disable = vc4_hdmi_phy_rng_disable,
.channel_map = vc4_hdmi_channel_map,
.supports_hdr = false,
};

static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
Expand Down Expand Up @@ -2699,6 +2765,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
.phy_rng_enable = vc5_hdmi_phy_rng_enable,
.phy_rng_disable = vc5_hdmi_phy_rng_disable,
.channel_map = vc5_hdmi_channel_map,
.supports_hdr = true,
};

static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
Expand Down Expand Up @@ -2726,6 +2793,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
.phy_rng_enable = vc5_hdmi_phy_rng_enable,
.phy_rng_disable = vc5_hdmi_phy_rng_disable,
.channel_map = vc5_hdmi_channel_map,
.supports_hdr = true,
};

static const struct of_device_id vc4_hdmi_dt_match[] = {
Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/vc4/vc4_hdmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ struct vc4_hdmi_variant {

/* Callback to get channel map */
u32 (*channel_map)(struct vc4_hdmi *vc4_hdmi, u32 channel_mask);

/* Enables HDR metadata */
bool supports_hdr;
};

/* HDMI audio information */
Expand Down
2 changes: 1 addition & 1 deletion include/linux/hdmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ enum hdmi_content_type {
};

enum hdmi_metadata_type {
HDMI_STATIC_METADATA_TYPE1 = 1,
HDMI_STATIC_METADATA_TYPE1 = 0,
};

enum hdmi_eotf {
Expand Down