Message ID | 20221207-rpi-hdmi-improvements-v1-3-6b15f774c13a@cerno.tech (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | drm/vc4: hdmi: Broadcast RGB, BT601, BT2020 | expand |
Hi Am 07.12.22 um 17:07 schrieb Maxime Ripard: > From: Dave Stevenson <dave.stevenson@raspberrypi.com> > > Copy Intel's "Broadcast RGB" property semantics to add manual override > of the HDMI pixel range for monitors that don't abide by the content > of the AVI Infoframe. > > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com> > Signed-off-by: Maxime Ripard <maxime@cerno.tech> > --- > drivers/gpu/drm/vc4/vc4_hdmi.c | 87 ++++++++++++++++++++++++++++++++++++++++++ > drivers/gpu/drm/vc4/vc4_hdmi.h | 15 ++++++++ > 2 files changed, 102 insertions(+) > > diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c > index 0eafaf0b76e5..488a4012d422 100644 > --- a/drivers/gpu/drm/vc4/vc4_hdmi.c > +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c > @@ -154,6 +154,11 @@ static bool vc4_hdmi_is_full_range_rgb(struct vc4_hdmi *vc4_hdmi, > { > struct drm_display_info *display = &vc4_hdmi->connector.display_info; > > + if (vc4_hdmi->broadcast_rgb == VC4_HDMI_BROADCAST_RGB_LIMITED) > + return false; > + else if (vc4_hdmi->broadcast_rgb == VC4_HDMI_BROADCAST_RGB_FULL) > + return true; > + > return !display->is_hdmi || > drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_FULL; The existing code is now the branch for VC4_HDMI_BROADCAST_RGB_AUTO, AFAIU. > } > @@ -515,8 +520,12 @@ static int vc4_hdmi_connector_atomic_check(struct drm_connector *connector, > { > struct drm_connector_state *old_state = > drm_atomic_get_old_connector_state(state, connector); > + struct vc4_hdmi_connector_state *old_vc4_state = > + conn_state_to_vc4_hdmi_conn_state(old_state); > struct drm_connector_state *new_state = > drm_atomic_get_new_connector_state(state, connector); > + struct vc4_hdmi_connector_state *new_vc4_state = > + conn_state_to_vc4_hdmi_conn_state(new_state); > struct drm_crtc *crtc = new_state->crtc; > > if (!crtc) > @@ -539,6 +548,7 @@ static int vc4_hdmi_connector_atomic_check(struct drm_connector *connector, > } > > if (old_state->colorspace != new_state->colorspace || > + old_vc4_state->broadcast_rgb != new_vc4_state->broadcast_rgb || > !drm_connector_atomic_hdr_metadata_equal(old_state, new_state)) { > struct drm_crtc_state *crtc_state; > > @@ -552,6 +562,49 @@ static int vc4_hdmi_connector_atomic_check(struct drm_connector *connector, > return 0; > } > > +static int vc4_hdmi_connector_get_property(struct drm_connector *connector, > + const struct drm_connector_state *state, > + struct drm_property *property, > + uint64_t *val) > +{ > + struct drm_device *drm = connector->dev; > + struct vc4_hdmi *vc4_hdmi = > + connector_to_vc4_hdmi(connector); > + struct vc4_hdmi_connector_state *vc4_conn_state = > + conn_state_to_vc4_hdmi_conn_state(state); > + > + if (property == vc4_hdmi->broadcast_rgb_property) { > + *val = vc4_conn_state->broadcast_rgb; > + } else { > + drm_dbg(drm, "Unknown property [PROP:%d:%s]\n", > + property->base.id, property->name); > + return -EINVAL; > + } > + > + return 0; > +} > + > +static int vc4_hdmi_connector_set_property(struct drm_connector *connector, > + struct drm_connector_state *state, > + struct drm_property *property, > + uint64_t val) > +{ > + struct drm_device *drm = connector->dev; > + struct vc4_hdmi *vc4_hdmi = > + connector_to_vc4_hdmi(connector); > + struct vc4_hdmi_connector_state *vc4_conn_state = > + conn_state_to_vc4_hdmi_conn_state(state); > + > + if (property == vc4_hdmi->broadcast_rgb_property) { > + vc4_conn_state->broadcast_rgb = val; > + return 0; > + } > + > + drm_dbg(drm, "Unknown property [PROP:%d:%s]\n", > + property->base.id, property->name); > + return -EINVAL; > +} > + > static void vc4_hdmi_connector_reset(struct drm_connector *connector) > { > struct vc4_hdmi_connector_state *old_state = > @@ -571,6 +624,7 @@ static void vc4_hdmi_connector_reset(struct drm_connector *connector) > new_state->base.max_bpc = 8; > new_state->base.max_requested_bpc = 8; > new_state->output_format = VC4_HDMI_OUTPUT_RGB; > + new_state->broadcast_rgb = VC4_HDMI_BROADCAST_RGB_AUTO; > drm_atomic_helper_connector_tv_margins_reset(connector); > } > > @@ -588,6 +642,7 @@ vc4_hdmi_connector_duplicate_state(struct drm_connector *connector) > new_state->tmds_char_rate = vc4_state->tmds_char_rate; > new_state->output_bpc = vc4_state->output_bpc; > new_state->output_format = vc4_state->output_format; > + new_state->broadcast_rgb = vc4_state->broadcast_rgb; > __drm_atomic_helper_connector_duplicate_state(connector, &new_state->base); > > return &new_state->base; > @@ -598,6 +653,8 @@ static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { > .reset = vc4_hdmi_connector_reset, > .atomic_duplicate_state = vc4_hdmi_connector_duplicate_state, > .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, > + .atomic_get_property = vc4_hdmi_connector_get_property, > + .atomic_set_property = vc4_hdmi_connector_set_property, > }; > > static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = { > @@ -606,6 +663,33 @@ static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = > .atomic_check = vc4_hdmi_connector_atomic_check, > }; > > +static const struct drm_prop_enum_list broadcast_rgb_names[] = { > + { VC4_HDMI_BROADCAST_RGB_AUTO, "Automatic" }, > + { VC4_HDMI_BROADCAST_RGB_FULL, "Full" }, > + { VC4_HDMI_BROADCAST_RGB_LIMITED, "Limited 16:235" }, > +}; > + > +static void > +vc4_hdmi_attach_broadcast_rgb_property(struct drm_device *dev, > + struct vc4_hdmi *vc4_hdmi) > +{ > + struct drm_property *prop = vc4_hdmi->broadcast_rgb_property; > + > + if (!prop) { > + prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, > + "Broadcast RGB", > + broadcast_rgb_names, > + ARRAY_SIZE(broadcast_rgb_names)); > + if (!prop) > + return; > + > + vc4_hdmi->broadcast_rgb_property = prop; > + } > + > + drm_object_attach_property(&vc4_hdmi->connector.base, prop, > + VC4_HDMI_BROADCAST_RGB_AUTO); > +} > + > static int vc4_hdmi_connector_init(struct drm_device *dev, > struct vc4_hdmi *vc4_hdmi) > { > @@ -652,6 +736,8 @@ static int vc4_hdmi_connector_init(struct drm_device *dev, > if (vc4_hdmi->variant->supports_hdr) > drm_connector_attach_hdr_output_metadata_property(connector); > > + vc4_hdmi_attach_broadcast_rgb_property(dev, vc4_hdmi); > + > drm_connector_attach_encoder(connector, encoder); > > return 0; > @@ -1690,6 +1776,7 @@ static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder, > mutex_lock(&vc4_hdmi->mutex); > drm_mode_copy(&vc4_hdmi->saved_adjusted_mode, > &crtc_state->adjusted_mode); > + vc4_hdmi->broadcast_rgb = vc4_state->broadcast_rgb; > vc4_hdmi->output_bpc = vc4_state->output_bpc; > vc4_hdmi->output_format = vc4_state->output_format; > mutex_unlock(&vc4_hdmi->mutex); > diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h > index 023ea64ef006..d423f175339f 100644 > --- a/drivers/gpu/drm/vc4/vc4_hdmi.h > +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h > @@ -117,6 +117,12 @@ enum vc4_hdmi_output_format { > VC4_HDMI_OUTPUT_YUV420, > }; > > +enum vc4_hdmi_broadcast_rgb { > + VC4_HDMI_BROADCAST_RGB_AUTO, > + VC4_HDMI_BROADCAST_RGB_FULL, > + VC4_HDMI_BROADCAST_RGB_LIMITED, > +}; > + > /* General HDMI hardware state. */ > struct vc4_hdmi { > struct vc4_hdmi_audio audio; > @@ -129,6 +135,8 @@ struct vc4_hdmi { > > struct delayed_work scrambling_work; > > + struct drm_property *broadcast_rgb_property; > + > struct i2c_adapter *ddc; > void __iomem *hdmicore_regs; > void __iomem *hd_regs; > @@ -221,6 +229,12 @@ struct vc4_hdmi { > * for use outside of KMS hooks. Protected by @mutex. > */ > enum vc4_hdmi_output_format output_format; > + > + /** > + * @broadcast_rgb: Copy of @vc4_connector_state.broadcast_rgb > + * for use outside of KMS hooks. Protected by @mutex. > + */ > + enum vc4_hdmi_broadcast_rgb broadcast_rgb; I cannot seem to find any users of this field. If this is not used, please remove it from the patch. It seems questionable to have this outside if the connector state anyway. > }; > > static inline struct vc4_hdmi * > @@ -241,6 +255,7 @@ struct vc4_hdmi_connector_state { > unsigned long long tmds_char_rate; > unsigned int output_bpc; > enum vc4_hdmi_output_format output_format; > + int broadcast_rgb; Maybe 'enum vc4_hdmi_broadcast_rgb'. Best regards Thomas > }; > > static inline struct vc4_hdmi_connector_state * >
Hi, Thanks for your review On Wed, Jan 11, 2023 at 03:11:51PM +0100, Thomas Zimmermann wrote: > Am 07.12.22 um 17:07 schrieb Maxime Ripard: > > From: Dave Stevenson <dave.stevenson@raspberrypi.com> > > > > Copy Intel's "Broadcast RGB" property semantics to add manual override > > of the HDMI pixel range for monitors that don't abide by the content > > of the AVI Infoframe. > > > > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com> > > Signed-off-by: Maxime Ripard <maxime@cerno.tech> > > --- > > drivers/gpu/drm/vc4/vc4_hdmi.c | 87 ++++++++++++++++++++++++++++++++++++++++++ > > drivers/gpu/drm/vc4/vc4_hdmi.h | 15 ++++++++ > > 2 files changed, 102 insertions(+) > > > > diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c > > index 0eafaf0b76e5..488a4012d422 100644 > > --- a/drivers/gpu/drm/vc4/vc4_hdmi.c > > +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c > > @@ -154,6 +154,11 @@ static bool vc4_hdmi_is_full_range_rgb(struct vc4_hdmi *vc4_hdmi, > > { > > struct drm_display_info *display = &vc4_hdmi->connector.display_info; > > + if (vc4_hdmi->broadcast_rgb == VC4_HDMI_BROADCAST_RGB_LIMITED) > > + return false; > > + else if (vc4_hdmi->broadcast_rgb == VC4_HDMI_BROADCAST_RGB_FULL) > > + return true; > > + > > return !display->is_hdmi || > > drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_FULL; > > The existing code is now the branch for VC4_HDMI_BROADCAST_RGB_AUTO, AFAIU. I'm not entirely sure what you meant here sorry. The existing code path is indeed the VC4_HDMI_BROADCAST_RGB_AUTO case, which is the property default so the current behaviour should remain by default. Is there anything you want me to clarify? Maxime
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 0eafaf0b76e5..488a4012d422 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -154,6 +154,11 @@ static bool vc4_hdmi_is_full_range_rgb(struct vc4_hdmi *vc4_hdmi, { struct drm_display_info *display = &vc4_hdmi->connector.display_info; + if (vc4_hdmi->broadcast_rgb == VC4_HDMI_BROADCAST_RGB_LIMITED) + return false; + else if (vc4_hdmi->broadcast_rgb == VC4_HDMI_BROADCAST_RGB_FULL) + return true; + return !display->is_hdmi || drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_FULL; } @@ -515,8 +520,12 @@ static int vc4_hdmi_connector_atomic_check(struct drm_connector *connector, { struct drm_connector_state *old_state = drm_atomic_get_old_connector_state(state, connector); + struct vc4_hdmi_connector_state *old_vc4_state = + conn_state_to_vc4_hdmi_conn_state(old_state); struct drm_connector_state *new_state = drm_atomic_get_new_connector_state(state, connector); + struct vc4_hdmi_connector_state *new_vc4_state = + conn_state_to_vc4_hdmi_conn_state(new_state); struct drm_crtc *crtc = new_state->crtc; if (!crtc) @@ -539,6 +548,7 @@ static int vc4_hdmi_connector_atomic_check(struct drm_connector *connector, } if (old_state->colorspace != new_state->colorspace || + old_vc4_state->broadcast_rgb != new_vc4_state->broadcast_rgb || !drm_connector_atomic_hdr_metadata_equal(old_state, new_state)) { struct drm_crtc_state *crtc_state; @@ -552,6 +562,49 @@ static int vc4_hdmi_connector_atomic_check(struct drm_connector *connector, return 0; } +static int vc4_hdmi_connector_get_property(struct drm_connector *connector, + const struct drm_connector_state *state, + struct drm_property *property, + uint64_t *val) +{ + struct drm_device *drm = connector->dev; + struct vc4_hdmi *vc4_hdmi = + connector_to_vc4_hdmi(connector); + struct vc4_hdmi_connector_state *vc4_conn_state = + conn_state_to_vc4_hdmi_conn_state(state); + + if (property == vc4_hdmi->broadcast_rgb_property) { + *val = vc4_conn_state->broadcast_rgb; + } else { + drm_dbg(drm, "Unknown property [PROP:%d:%s]\n", + property->base.id, property->name); + return -EINVAL; + } + + return 0; +} + +static int vc4_hdmi_connector_set_property(struct drm_connector *connector, + struct drm_connector_state *state, + struct drm_property *property, + uint64_t val) +{ + struct drm_device *drm = connector->dev; + struct vc4_hdmi *vc4_hdmi = + connector_to_vc4_hdmi(connector); + struct vc4_hdmi_connector_state *vc4_conn_state = + conn_state_to_vc4_hdmi_conn_state(state); + + if (property == vc4_hdmi->broadcast_rgb_property) { + vc4_conn_state->broadcast_rgb = val; + return 0; + } + + drm_dbg(drm, "Unknown property [PROP:%d:%s]\n", + property->base.id, property->name); + return -EINVAL; +} + static void vc4_hdmi_connector_reset(struct drm_connector *connector) { struct vc4_hdmi_connector_state *old_state = @@ -571,6 +624,7 @@ static void vc4_hdmi_connector_reset(struct drm_connector *connector) new_state->base.max_bpc = 8; new_state->base.max_requested_bpc = 8; new_state->output_format = VC4_HDMI_OUTPUT_RGB; + new_state->broadcast_rgb = VC4_HDMI_BROADCAST_RGB_AUTO; drm_atomic_helper_connector_tv_margins_reset(connector); } @@ -588,6 +642,7 @@ vc4_hdmi_connector_duplicate_state(struct drm_connector *connector) new_state->tmds_char_rate = vc4_state->tmds_char_rate; new_state->output_bpc = vc4_state->output_bpc; new_state->output_format = vc4_state->output_format; + new_state->broadcast_rgb = vc4_state->broadcast_rgb; __drm_atomic_helper_connector_duplicate_state(connector, &new_state->base); return &new_state->base; @@ -598,6 +653,8 @@ static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { .reset = vc4_hdmi_connector_reset, .atomic_duplicate_state = vc4_hdmi_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + .atomic_get_property = vc4_hdmi_connector_get_property, + .atomic_set_property = vc4_hdmi_connector_set_property, }; static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = { @@ -606,6 +663,33 @@ static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = .atomic_check = vc4_hdmi_connector_atomic_check, }; +static const struct drm_prop_enum_list broadcast_rgb_names[] = { + { VC4_HDMI_BROADCAST_RGB_AUTO, "Automatic" }, + { VC4_HDMI_BROADCAST_RGB_FULL, "Full" }, + { VC4_HDMI_BROADCAST_RGB_LIMITED, "Limited 16:235" }, +}; + +static void +vc4_hdmi_attach_broadcast_rgb_property(struct drm_device *dev, + struct vc4_hdmi *vc4_hdmi) +{ + struct drm_property *prop = vc4_hdmi->broadcast_rgb_property; + + if (!prop) { + prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, + "Broadcast RGB", + broadcast_rgb_names, + ARRAY_SIZE(broadcast_rgb_names)); + if (!prop) + return; + + vc4_hdmi->broadcast_rgb_property = prop; + } + + drm_object_attach_property(&vc4_hdmi->connector.base, prop, + VC4_HDMI_BROADCAST_RGB_AUTO); +} + static int vc4_hdmi_connector_init(struct drm_device *dev, struct vc4_hdmi *vc4_hdmi) { @@ -652,6 +736,8 @@ static int vc4_hdmi_connector_init(struct drm_device *dev, if (vc4_hdmi->variant->supports_hdr) drm_connector_attach_hdr_output_metadata_property(connector); + vc4_hdmi_attach_broadcast_rgb_property(dev, vc4_hdmi); + drm_connector_attach_encoder(connector, encoder); return 0; @@ -1690,6 +1776,7 @@ static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder, mutex_lock(&vc4_hdmi->mutex); drm_mode_copy(&vc4_hdmi->saved_adjusted_mode, &crtc_state->adjusted_mode); + vc4_hdmi->broadcast_rgb = vc4_state->broadcast_rgb; vc4_hdmi->output_bpc = vc4_state->output_bpc; vc4_hdmi->output_format = vc4_state->output_format; mutex_unlock(&vc4_hdmi->mutex); diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 023ea64ef006..d423f175339f 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -117,6 +117,12 @@ enum vc4_hdmi_output_format { VC4_HDMI_OUTPUT_YUV420, }; +enum vc4_hdmi_broadcast_rgb { + VC4_HDMI_BROADCAST_RGB_AUTO, + VC4_HDMI_BROADCAST_RGB_FULL, + VC4_HDMI_BROADCAST_RGB_LIMITED, +}; + /* General HDMI hardware state. */ struct vc4_hdmi { struct vc4_hdmi_audio audio; @@ -129,6 +135,8 @@ struct vc4_hdmi { struct delayed_work scrambling_work; + struct drm_property *broadcast_rgb_property; + struct i2c_adapter *ddc; void __iomem *hdmicore_regs; void __iomem *hd_regs; @@ -221,6 +229,12 @@ struct vc4_hdmi { * for use outside of KMS hooks. Protected by @mutex. */ enum vc4_hdmi_output_format output_format; + + /** + * @broadcast_rgb: Copy of @vc4_connector_state.broadcast_rgb + * for use outside of KMS hooks. Protected by @mutex. + */ + enum vc4_hdmi_broadcast_rgb broadcast_rgb; }; static inline struct vc4_hdmi * @@ -241,6 +255,7 @@ struct vc4_hdmi_connector_state { unsigned long long tmds_char_rate; unsigned int output_bpc; enum vc4_hdmi_output_format output_format; + int broadcast_rgb; }; static inline struct vc4_hdmi_connector_state *