Skip to content

Commit b300319

Browse files
6by9popcornmix
authored andcommitted
drm/vc4_hdmi: Add Broadcast RGB property to allow override of RGB range
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 <[email protected]>
1 parent 3cfc7aa commit b300319

File tree

2 files changed

+118
-0
lines changed

2 files changed

+118
-0
lines changed

drivers/gpu/drm/vc4/vc4_hdmi.c

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@
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+
344415
static 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

394468
static 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+
399499
static 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));

drivers/gpu/drm/vc4/vc4_hdmi.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ struct vc4_hdmi {
140140

141141
struct delayed_work scrambling_work;
142142

143+
struct drm_property *broadcast_rgb_property;
144+
143145
struct i2c_adapter *ddc;
144146
void __iomem *hdmicore_regs;
145147
void __iomem *hd_regs;
@@ -240,6 +242,12 @@ struct vc4_hdmi {
240242
*/
241243
enum vc4_hdmi_output_format output_format;
242244

245+
/**
246+
* @broadcast_rgb: Copy of @vc4_connector_state.broadcast_rgb
247+
* for use outside of KMS hooks. Protected by @mutex.
248+
*/
249+
int broadcast_rgb;
250+
243251
/* VC5 debugfs regset */
244252
struct debugfs_regset32 cec_regset;
245253
struct debugfs_regset32 csc_regset;
@@ -268,6 +276,7 @@ struct vc4_hdmi_connector_state {
268276
unsigned long long pixel_rate;
269277
unsigned int output_bpc;
270278
enum vc4_hdmi_output_format output_format;
279+
int broadcast_rgb;
271280
};
272281

273282
static inline struct vc4_hdmi_connector_state *
@@ -276,6 +285,12 @@ conn_state_to_vc4_hdmi_conn_state(struct drm_connector_state *conn_state)
276285
return container_of(conn_state, struct vc4_hdmi_connector_state, base);
277286
}
278287

288+
static inline const struct vc4_hdmi_connector_state *
289+
const_conn_state_to_vc4_hdmi_conn_state(const struct drm_connector_state *conn_state)
290+
{
291+
return container_of(conn_state, struct vc4_hdmi_connector_state, base);
292+
}
293+
279294
void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi,
280295
struct vc4_hdmi_connector_state *vc4_conn_state);
281296
void vc4_hdmi_phy_disable(struct vc4_hdmi *vc4_hdmi);

0 commit comments

Comments
 (0)