Commit e953fd7b authored by Chris Wilson's avatar Chris Wilson

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=34543Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
parent ce453d81
...@@ -707,6 +707,8 @@ typedef struct drm_i915_private { ...@@ -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 @@ ...@@ -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 { ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 ...@@ -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 { ...@@ -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 { ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 ...@@ -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, ...@@ -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 { ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment