5656#include "vc4_hdmi_regs.h"
5757#include "vc4_regs.h"
5858
59+ /*
60+ * "Broadcast RGB" property.
61+ * Allows overriding of HDMI full or limited range RGB
62+ */
63+ #define VC4_BROADCAST_RGB_AUTO 0
64+ #define VC4_BROADCAST_RGB_FULL 1
65+ #define VC4_BROADCAST_RGB_LIMITED 2
66+
5967#define VC5_HDMI_HORZA_HFP_SHIFT 16
6068#define VC5_HDMI_HORZA_HFP_MASK VC4_MASK(28, 16)
6169#define VC5_HDMI_HORZA_VPOS BIT(15)
@@ -135,6 +143,10 @@ static bool vc4_hdmi_is_full_range_rgb(struct vc4_hdmi *vc4_hdmi,
135143{
136144 struct vc4_hdmi_encoder * vc4_encoder = & vc4_hdmi -> encoder ;
137145
146+ if (vc4_hdmi -> broadcast_rgb == VC4_BROADCAST_RGB_LIMITED )
147+ return false;
148+ else if (vc4_hdmi -> broadcast_rgb == VC4_BROADCAST_RGB_FULL )
149+ return true;
138150 return !vc4_encoder -> hdmi_monitor ||
139151 drm_default_rgb_quant_range (mode ) == HDMI_QUANTIZATION_RANGE_FULL ;
140152}
@@ -341,6 +353,65 @@ static int vc4_hdmi_connector_atomic_check(struct drm_connector *connector,
341353 return 0 ;
342354}
343355
356+ /**
357+ * vc4_hdmi_connector_atomic_get_property - hook for
358+ * connector->atomic_get_property.
359+ * @connector: Connector to get the property for.
360+ * @state: Connector state to retrieve the property from.
361+ * @property: Property to retrieve.
362+ * @val: Return value for the property.
363+ *
364+ * Returns the atomic property value for a digital connector.
365+ */
366+ int vc4_hdmi_connector_get_property (struct drm_connector * connector ,
367+ const struct drm_connector_state * state ,
368+ struct drm_property * property ,
369+ uint64_t * val )
370+ {
371+ struct vc4_hdmi * vc4_hdmi = connector_to_vc4_hdmi (connector );
372+ const struct vc4_hdmi_connector_state * vc4_conn_state =
373+ const_conn_state_to_vc4_hdmi_conn_state (state );
374+
375+ if (property == vc4_hdmi -> broadcast_rgb_property ) {
376+ * val = vc4_conn_state -> broadcast_rgb ;
377+ } else {
378+ DRM_DEBUG_ATOMIC ("Unknown property [PROP:%d:%s]\n" ,
379+ property -> base .id , property -> name );
380+ return - EINVAL ;
381+ }
382+
383+ return 0 ;
384+ }
385+
386+ /**
387+ * vc4_hdmi_connector_atomic_set_property - hook for
388+ * connector->atomic_set_property.
389+ * @connector: Connector to set the property for.
390+ * @state: Connector state to set the property on.
391+ * @property: Property to set.
392+ * @val: New value for the property.
393+ *
394+ * Sets the atomic property value for a digital connector.
395+ */
396+ int vc4_hdmi_connector_set_property (struct drm_connector * connector ,
397+ struct drm_connector_state * state ,
398+ struct drm_property * property ,
399+ uint64_t val )
400+ {
401+ struct vc4_hdmi * vc4_hdmi = connector_to_vc4_hdmi (connector );
402+ struct vc4_hdmi_connector_state * vc4_conn_state =
403+ conn_state_to_vc4_hdmi_conn_state (state );
404+
405+ if (property == vc4_hdmi -> broadcast_rgb_property ) {
406+ vc4_conn_state -> broadcast_rgb = val ;
407+ return 0 ;
408+ }
409+
410+ DRM_DEBUG_ATOMIC ("Unknown property [PROP:%d:%s]\n" ,
411+ property -> base .id , property -> name );
412+ return - EINVAL ;
413+ }
414+
344415static void vc4_hdmi_connector_reset (struct drm_connector * connector )
345416{
346417 struct vc4_hdmi_connector_state * old_state =
@@ -377,6 +448,7 @@ vc4_hdmi_connector_duplicate_state(struct drm_connector *connector)
377448 new_state -> pixel_rate = vc4_state -> pixel_rate ;
378449 new_state -> output_bpc = vc4_state -> output_bpc ;
379450 new_state -> output_format = vc4_state -> output_format ;
451+ new_state -> broadcast_rgb = vc4_state -> broadcast_rgb ;
380452 __drm_atomic_helper_connector_duplicate_state (connector , & new_state -> base );
381453
382454 return & new_state -> base ;
@@ -389,13 +461,41 @@ static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
389461 .reset = vc4_hdmi_connector_reset ,
390462 .atomic_duplicate_state = vc4_hdmi_connector_duplicate_state ,
391463 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state ,
464+ .atomic_get_property = vc4_hdmi_connector_get_property ,
465+ .atomic_set_property = vc4_hdmi_connector_set_property ,
392466};
393467
394468static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = {
395469 .get_modes = vc4_hdmi_connector_get_modes ,
396470 .atomic_check = vc4_hdmi_connector_atomic_check ,
397471};
398472
473+ static const struct drm_prop_enum_list broadcast_rgb_names [] = {
474+ { VC4_BROADCAST_RGB_AUTO , "Automatic" },
475+ { VC4_BROADCAST_RGB_FULL , "Full" },
476+ { VC4_BROADCAST_RGB_LIMITED , "Limited 16:235" },
477+ };
478+
479+ static void
480+ vc4_hdmi_attach_broadcast_rgb_property (struct drm_device * dev ,
481+ struct vc4_hdmi * vc4_hdmi )
482+ {
483+ struct drm_property * prop = vc4_hdmi -> broadcast_rgb_property ;
484+
485+ if (!prop ) {
486+ prop = drm_property_create_enum (dev , DRM_MODE_PROP_ENUM ,
487+ "Broadcast RGB" ,
488+ broadcast_rgb_names ,
489+ ARRAY_SIZE (broadcast_rgb_names ));
490+ if (!prop )
491+ return ;
492+
493+ vc4_hdmi -> broadcast_rgb_property = prop ;
494+ }
495+
496+ drm_object_attach_property (& vc4_hdmi -> connector .base , prop , 0 );
497+ }
498+
399499static int vc4_hdmi_connector_init (struct drm_device * dev ,
400500 struct vc4_hdmi * vc4_hdmi )
401501{
@@ -439,6 +539,8 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
439539 if (vc4_hdmi -> variant -> supports_hdr )
440540 drm_connector_attach_hdr_output_metadata_property (connector );
441541
542+ vc4_hdmi_attach_broadcast_rgb_property (dev , vc4_hdmi );
543+
442544 drm_connector_attach_encoder (connector , encoder );
443545
444546 return 0 ;
@@ -1384,6 +1486,7 @@ static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder,
13841486 mutex_lock (& vc4_hdmi -> mutex );
13851487 vc4_hdmi -> output_bpc = vc4_state -> output_bpc ;
13861488 vc4_hdmi -> output_format = vc4_state -> output_format ;
1489+ vc4_hdmi -> broadcast_rgb = vc4_state -> broadcast_rgb ;
13871490 memcpy (& vc4_hdmi -> saved_adjusted_mode ,
13881491 & crtc_state -> adjusted_mode ,
13891492 sizeof (vc4_hdmi -> saved_adjusted_mode ));
0 commit comments