drm/i915: Add support for limited color range of broadcast outputs
In order to prevent "crushed blacks" on TVs, the range of the RGB output may be limited to 16-235. This used to be available through Xorg under the "Broadcast RGB" option, so reintroduce support for KMS. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=34543 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
parent
ce453d81cb
commit
e953fd7bb3
|
@ -707,6 +707,8 @@ typedef struct drm_i915_private {
|
||||||
|
|
||||||
/* list of fbdev register on this device */
|
/* list of fbdev register on this device */
|
||||||
struct intel_fbdev *fbdev;
|
struct intel_fbdev *fbdev;
|
||||||
|
|
||||||
|
struct drm_property *broadcast_rgb_property;
|
||||||
} drm_i915_private_t;
|
} drm_i915_private_t;
|
||||||
|
|
||||||
struct drm_i915_gem_object {
|
struct drm_i915_gem_object {
|
||||||
|
|
|
@ -1387,6 +1387,7 @@
|
||||||
#define SDVO_ENCODING_HDMI (0x2 << 10)
|
#define SDVO_ENCODING_HDMI (0x2 << 10)
|
||||||
/** Requird for HDMI operation */
|
/** Requird for HDMI operation */
|
||||||
#define SDVO_NULL_PACKETS_DURING_VSYNC (1 << 9)
|
#define SDVO_NULL_PACKETS_DURING_VSYNC (1 << 9)
|
||||||
|
#define SDVO_COLOR_RANGE_16_235 (1 << 8)
|
||||||
#define SDVO_BORDER_ENABLE (1 << 7)
|
#define SDVO_BORDER_ENABLE (1 << 7)
|
||||||
#define SDVO_AUDIO_ENABLE (1 << 6)
|
#define SDVO_AUDIO_ENABLE (1 << 6)
|
||||||
/** New with 965, default is to be set */
|
/** New with 965, default is to be set */
|
||||||
|
|
|
@ -49,6 +49,7 @@ struct intel_dp {
|
||||||
uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE];
|
uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE];
|
||||||
bool has_audio;
|
bool has_audio;
|
||||||
int force_audio;
|
int force_audio;
|
||||||
|
uint32_t color_range;
|
||||||
int dpms_mode;
|
int dpms_mode;
|
||||||
uint8_t link_bw;
|
uint8_t link_bw;
|
||||||
uint8_t lane_count;
|
uint8_t lane_count;
|
||||||
|
@ -741,8 +742,8 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
||||||
struct drm_crtc *crtc = intel_dp->base.base.crtc;
|
struct drm_crtc *crtc = intel_dp->base.base.crtc;
|
||||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||||
|
|
||||||
intel_dp->DP = (DP_VOLTAGE_0_4 |
|
intel_dp->DP = DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
|
||||||
DP_PRE_EMPHASIS_0);
|
intel_dp->DP |= intel_dp->color_range;
|
||||||
|
|
||||||
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
|
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
|
||||||
intel_dp->DP |= DP_SYNC_HS_HIGH;
|
intel_dp->DP |= DP_SYNC_HS_HIGH;
|
||||||
|
@ -1680,6 +1681,7 @@ intel_dp_set_property(struct drm_connector *connector,
|
||||||
struct drm_property *property,
|
struct drm_property *property,
|
||||||
uint64_t val)
|
uint64_t val)
|
||||||
{
|
{
|
||||||
|
struct drm_i915_private *dev_priv = connector->dev->dev_private;
|
||||||
struct intel_dp *intel_dp = intel_attached_dp(connector);
|
struct intel_dp *intel_dp = intel_attached_dp(connector);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -1708,6 +1710,14 @@ intel_dp_set_property(struct drm_connector *connector,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (property == dev_priv->broadcast_rgb_property) {
|
||||||
|
if (val == !!intel_dp->color_range)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
intel_dp->color_range = val ? DP_COLOR_RANGE_16_235 : 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
@ -1827,6 +1837,8 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
|
||||||
intel_dp->force_audio_property->values[1] = 1;
|
intel_dp->force_audio_property->values[1] = 1;
|
||||||
drm_connector_attach_property(connector, intel_dp->force_audio_property, 0);
|
drm_connector_attach_property(connector, intel_dp->force_audio_property, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
intel_attach_broadcast_rgb_property(connector);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -237,6 +237,8 @@ struct intel_unpin_work {
|
||||||
int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
|
int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
|
||||||
extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus);
|
extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus);
|
||||||
|
|
||||||
|
extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector);
|
||||||
|
|
||||||
extern void intel_crt_init(struct drm_device *dev);
|
extern void intel_crt_init(struct drm_device *dev);
|
||||||
extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
|
extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
|
||||||
void intel_dip_infoframe_csum(struct dip_infoframe *avi_if);
|
void intel_dip_infoframe_csum(struct dip_infoframe *avi_if);
|
||||||
|
|
|
@ -41,6 +41,7 @@ struct intel_hdmi {
|
||||||
struct intel_encoder base;
|
struct intel_encoder base;
|
||||||
u32 sdvox_reg;
|
u32 sdvox_reg;
|
||||||
int ddc_bus;
|
int ddc_bus;
|
||||||
|
uint32_t color_range;
|
||||||
bool has_hdmi_sink;
|
bool has_hdmi_sink;
|
||||||
bool has_audio;
|
bool has_audio;
|
||||||
int force_audio;
|
int force_audio;
|
||||||
|
@ -124,6 +125,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
|
||||||
u32 sdvox;
|
u32 sdvox;
|
||||||
|
|
||||||
sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE;
|
sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE;
|
||||||
|
sdvox |= intel_hdmi->color_range;
|
||||||
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
|
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
|
||||||
sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
|
sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
|
||||||
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
|
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
|
||||||
|
@ -278,6 +280,7 @@ intel_hdmi_set_property(struct drm_connector *connector,
|
||||||
uint64_t val)
|
uint64_t val)
|
||||||
{
|
{
|
||||||
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
|
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
|
||||||
|
struct drm_i915_private *dev_priv = connector->dev->dev_private;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = drm_connector_property_set_value(connector, property, val);
|
ret = drm_connector_property_set_value(connector, property, val);
|
||||||
|
@ -305,6 +308,14 @@ intel_hdmi_set_property(struct drm_connector *connector,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (property == dev_priv->broadcast_rgb_property) {
|
||||||
|
if (val == !!intel_hdmi->color_range)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
intel_hdmi->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
@ -363,6 +374,8 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c
|
||||||
intel_hdmi->force_audio_property->values[1] = 1;
|
intel_hdmi->force_audio_property->values[1] = 1;
|
||||||
drm_connector_attach_property(connector, intel_hdmi->force_audio_property, 0);
|
drm_connector_attach_property(connector, intel_hdmi->force_audio_property, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
intel_attach_broadcast_rgb_property(connector);
|
||||||
}
|
}
|
||||||
|
|
||||||
void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
|
void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
|
||||||
|
|
|
@ -80,3 +80,33 @@ int intel_ddc_get_modes(struct drm_connector *connector,
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *broadcast_rgb_names[] = {
|
||||||
|
"Full",
|
||||||
|
"Limited 16:235",
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
intel_attach_broadcast_rgb_property(struct drm_connector *connector)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = connector->dev;
|
||||||
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||||
|
struct drm_property *prop;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
prop = dev_priv->broadcast_rgb_property;
|
||||||
|
if (prop == NULL) {
|
||||||
|
prop = drm_property_create(dev, DRM_MODE_PROP_ENUM,
|
||||||
|
"Broadcast RGB",
|
||||||
|
ARRAY_SIZE(broadcast_rgb_names));
|
||||||
|
if (prop == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(broadcast_rgb_names); i++)
|
||||||
|
drm_property_add_enum(prop, i, i, broadcast_rgb_names[i]);
|
||||||
|
|
||||||
|
dev_priv->broadcast_rgb_property = prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_connector_attach_property(connector, prop, 0);
|
||||||
|
}
|
||||||
|
|
|
@ -92,6 +92,12 @@ struct intel_sdvo {
|
||||||
*/
|
*/
|
||||||
uint16_t attached_output;
|
uint16_t attached_output;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is used to select the color range of RBG outputs in HDMI mode.
|
||||||
|
* It is only valid when using TMDS encoding and 8 bit per color mode.
|
||||||
|
*/
|
||||||
|
uint32_t color_range;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is set if we're going to treat the device as TV-out.
|
* This is set if we're going to treat the device as TV-out.
|
||||||
*
|
*
|
||||||
|
@ -1056,6 +1062,8 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
|
||||||
/* Set the SDVO control regs. */
|
/* Set the SDVO control regs. */
|
||||||
if (INTEL_INFO(dev)->gen >= 4) {
|
if (INTEL_INFO(dev)->gen >= 4) {
|
||||||
sdvox = 0;
|
sdvox = 0;
|
||||||
|
if (intel_sdvo->is_hdmi)
|
||||||
|
sdvox |= intel_sdvo->color_range;
|
||||||
if (INTEL_INFO(dev)->gen < 5)
|
if (INTEL_INFO(dev)->gen < 5)
|
||||||
sdvox |= SDVO_BORDER_ENABLE;
|
sdvox |= SDVO_BORDER_ENABLE;
|
||||||
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
|
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
|
||||||
|
@ -1695,6 +1703,7 @@ intel_sdvo_set_property(struct drm_connector *connector,
|
||||||
{
|
{
|
||||||
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
|
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
|
||||||
struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
|
struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
|
||||||
|
struct drm_i915_private *dev_priv = connector->dev->dev_private;
|
||||||
uint16_t temp_value;
|
uint16_t temp_value;
|
||||||
uint8_t cmd;
|
uint8_t cmd;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -1724,6 +1733,14 @@ intel_sdvo_set_property(struct drm_connector *connector,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (property == dev_priv->broadcast_rgb_property) {
|
||||||
|
if (val == !!intel_sdvo->color_range)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
intel_sdvo->color_range = val ? SDVO_COLOR_RANGE_16_235 : 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
#define CHECK_PROPERTY(name, NAME) \
|
#define CHECK_PROPERTY(name, NAME) \
|
||||||
if (intel_sdvo_connector->name == property) { \
|
if (intel_sdvo_connector->name == property) { \
|
||||||
if (intel_sdvo_connector->cur_##name == temp_value) return 0; \
|
if (intel_sdvo_connector->cur_##name == temp_value) return 0; \
|
||||||
|
@ -2028,6 +2045,9 @@ intel_sdvo_add_hdmi_properties(struct intel_sdvo_connector *connector)
|
||||||
drm_connector_attach_property(&connector->base.base,
|
drm_connector_attach_property(&connector->base.base,
|
||||||
connector->force_audio_property, 0);
|
connector->force_audio_property, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev))
|
||||||
|
intel_attach_broadcast_rgb_property(&connector->base.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
|
Reference in New Issue